h264 aac mux flv
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了h264 aac mux flv相关的知识,希望对你有一定的参考价值。
1、目前封装
c++ 封装h264 和 aac 成为flv,里面没有加script,但是可以用,后会把script加上,用在了把rtsp 汇流成flv,数据形式是拷贝进去的,如果有兴趣,可以进行零拷贝方式发送
1 因为传输层是tcp,所以可以把头部和数据分开发送,这样增加了发送的次数
2 可以把码流收入到缓存中,缓存预留 4+11+5 和 4+ 11 +2
视频 4+ 11 +5 + 数据
音频 4+ 11 +2 + 数据
以上两种方法都可以
2、准备一个头文件,包含就能用
/*
author :qianbo
email :418511899@qq.com
听雨堂 丁香结
address https://gitee.com/guanzhi0319/flvmux/
*/
听雨堂 丁香结
*/
#pragma once
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <mutex>
using namespace std;
enum {
FLV_TAG_TYPE_AUDIO = 0x08,
FLV_TAG_TYPE_VIDEO = 0x09,
FLV_TAG_TYPE_META = 0x12,
};
#define FLV_TAG_HEAD_LEN 11
#define FLV_PRE_TAG_LEN 4
//#ifndef _WIN32
//struct FLVTag {
// uint8_t type;
// uint8_t data_size[3];
// uint8_t timestamp[3];
// uint8_t timestamp_ex;
// uint8_t streamid[3];
//} __attribute__((__packed__));
//#else
//#pragma pack(push,1)
//typedef struct FLVTag {
// uint8_t type;
// uint8_t data_size[3];
// uint8_t timestamp[3];
// uint8_t timestamp_ex;
// uint8_t streamid[3];
//}FLVTag;
//#pragma pack(pop)
//#endif
typedef struct PutBitContext
{
unsigned int bit_buf;
int bit_left;
char *buf, *buf_ptr, *buf_end;
int size_in_bits;
} PutBitContext;
static inline void init_put_bits(PutBitContext *s, char *buffer, int buffer_size)
{
if (buffer_size < 0) {
buffer_size = 0;
buffer = 0;
}
s->size_in_bits = 8 * buffer_size;
s->buf = buffer;
s->buf_end = s->buf + buffer_size;
s->buf_ptr = s->buf;
s->bit_left = 32;
s->bit_buf = 0;
}
static inline void put_bits(PutBitContext *s, int n, unsigned int value)
{
unsigned int bit_buf;
int bit_left;
bit_buf = s->bit_buf;
bit_left = s->bit_left;
if (n < bit_left) {
bit_buf = (bit_buf << n) | value;
bit_left -= n;
}
else {
bit_buf <<= bit_left;
bit_buf |= value >> (n - bit_left);
UI32ToBytes((uint8_t*)s->buf_ptr, bit_buf);
//AV_WB32(s->buf_ptr, bit_buf);
//printf("bitbuf = %08x\\n", bit_buf);
s->buf_ptr += 4;
bit_left += 32 - n;
bit_buf = value;
}
s->bit_buf = bit_buf;
s->bit_left = bit_left;
}
static inline void flush_put_bits(PutBitContext *s)
{
s->bit_buf <<= s->bit_left;
while (s->bit_left < 32) {
*s->buf_ptr++ = s->bit_buf >> 24;
s->bit_buf <<= 8;
s->bit_left += 8;
}
s->bit_left = 32;
s->bit_buf = 0;
}
inline char* DoubleToBytes(char* buf, double val)
{
union {
unsigned char dc[8];
double dd;
} d;
unsigned char b[8];
d.dd = val;
b[0] = d.dc[7];
b[1] = d.dc[6];
b[2] = d.dc[5];
b[3] = d.dc[4];
b[4] = d.dc[3];
b[5] = d.dc[2];
b[6] = d.dc[1];
b[7] = d.dc[0];
memcpy(buf, b, 8);
return buf + 8;
}
inline uint8_t* UI08ToBytes(uint8_t* buf, unsigned char val)
{
buf[0] = (uint8_t)(val) & 0xff;
return buf + 1;
}
inline uint8_t* UI16ToBytes(uint8_t* buf, unsigned short val)
{
buf[0] = (uint8_t)(val >> 8) & 0xff;
buf[1] = (uint8_t)(val) & 0xff;
return buf + 2;
}
inline uint8_t* UI24ToBytes(uint8_t* buf, unsigned int val)
{
buf[0] = (uint8_t)(val >> 16) & 0xff;
buf[1] = (uint8_t)(val >> 8) & 0xff;
buf[2] = (uint8_t)(val) & 0xff;
return buf + 3;
}
inline uint8_t* UI32ToBytes(uint8_t* buf, unsigned int val)
{
buf[0] = (uint8_t)(val >> 24) & 0xff;
buf[1] = (uint8_t)(val >> 16) & 0xff;
buf[2] = (uint8_t)(val >> 8) & 0xff;
buf[3] = (uint8_t)(val) & 0xff;
return buf + 4;
}
typedef enum enum_av{
enum_av_a = 0x04,
enum_av_v = 0x01,
enum_av_av = 0x05
}enum_av;
typedef struct s_av_config
{
uint8_t *sps = NULL;
int len_sps = 0;
uint8_t* pps = NULL;
int len_pps = 0;
enum_av flag_av;
int samplerate = 44100;
int channel = 2;
}s_av_config;
class c_flv_mux
{
private:
std::mutex m_mutex;
uint8_t * m_meta_data = NULL;
//9 bytes header + 4 bytes pretag length = 0
char * m_header = "FLV\\x1\\x5\\0\\0\\0\\x9\\0\\0\\0\\0";
public:
class Lock {
private:
std::unique_lock<std::mutex> _lock;
public:
inline Lock(c_flv_mux* parent) : _lock(parent->m_mutex) {}
};
uint8_t* flv_header(uint8_t* header, bool is_have_audio, bool is_have_video)
{
if (is_have_audio && is_have_video)
header[4] = 0x05;
else if (is_have_audio && !is_have_video)
header[4] = 0x04;
else if (!is_have_audio && is_have_video)
header[4] = 0x01;
else
header[4] = 0x00;
return header + 13;
}
uint8_t * connect_meta(const char * connect_url, int len_conurl,
const char * addtion ,int len_add)
{
// /live/userid
//四字节pretag size 11字节头部 +
int len_data = len_conurl + len_add;
//两个空格
int len_frame = 11 + 2 + len_data;
//除去11个字节的头部
int len_body = len_data;
int len_data = len_conurl + len_add;
uint8_t * meta_data = new uint8_t[len_frame + 4];
//
}
protected:
void flv_write_11_header(
uint8_t *buf, uint32_t len_body,
uint32_t timestamp, uint8_t tag_type)
{
uint8_t* pos = buf;
//flvtag 11字节
*pos++= tag_type;// 0x09-> video | 0x08-> audio
*pos++ = (uint8_t)(len_body >> 16); //data len
*pos++ = (uint8_t)(len_body >> 8); //data len
*pos++ = (uint8_t)(len_body); //data len
*pos++ = (uint8_t)(timestamp >> 16); //time stamp
*pos++ = (uint8_t)(timestamp >> 8); //time stamp
*pos++ = (uint8_t)(timestamp); //time stamp
*pos++ = (uint8_t)(timestamp >> 24); //time stamp
*pos++ = 0x00; //stream id 0
*pos++ = 0x00; //stream id 0
*pos = 0x00; //stream id 0
return;
}
void flv_header_v_tag(
uint8_t *buf,
const uint8_t *sps, uint32_t len_sps,
const uint8_t *pps, uint32_t len_pps)
{
int len_data = len_sps + len_pps;
int len_frame = 11 + 16 + len_data;
//除去11个字节的头部
int len_body = 16 + len_data;
flv_write_11_header(buf, len_body, 0, FLV_TAG_TYPE_VIDEO);
//buf's length 11 + len_sps + len_pps + 16 bytes + 4bytes (last pretag lenth)
//int bodylen = 11 + sps_len + pps_len + 16;
//uint8_t *buf = (uint8_t *)malloc(bodylen + 4);
//留出11个字节
uint8_t * pos = buf + 11;
//flv VideoTagHeader
*pos++ = 0x17; //key frame, AVC
*pos++ = 0x00; //avc sequence header
*pos++ = 0x00; //composit time
*pos++ = 0x00; //composit time
*pos++ = 0x00; //composit time
*pos++ = 0x01; //configurationversion
*pos++ = sps[1]; //avcprofileindication
*pos++ = sps[2]; //profilecompatibilty
*pos++ = sps[3]; //avclevelindication
*pos++ = 0xff; //reserved + lengthsizeminusone
*pos++ = 0xe1; //numofsequenceset
*pos++ = (uint8_t)(len_sps >> 8); //sequence parameter set length high 8 bits
*pos++ = (uint8_t)(len_sps); //sequence parameter set length low 8 bits
memcpy(pos, sps, len_sps); //H264 sequence parameter set
pos += len_sps;
*pos++ = 0x01; //numofpictureset
*pos++ = (uint8_t)(len_pps >> 8); //picture parameter set length high 8 bits
*pos++ = (uint8_t)(len_pps); //picture parameter set length low 8 bits
memcpy(pos, pps, len_pps); //H264 picture parameter set
pos += len_pps;
*pos++ = (uint8_t)(len_frame >> 24); //data len
*pos++ = (uint8_t)(len_frame >> 16); //data len
*pos++ = (uint8_t)(len_frame >> 8); //data len
*pos = (uint8_t)(len_frame); //data len
}
void flv_header_a_tag(uint8_t * buf,
int sample_rate, int channels)
{
//11字节的tag ,音频4字节头部,4字节pretag长度
int len_data = 4;
int len_frame = 11 + 4;
//除去11个字节的头部
int len_body = len_data;
flv_write_11_header(buf, len_body, 0, FLV_TAG_TYPE_AUDIO);
uint8_t *pbuf = buf + 11;
/* SoundFormat|SoundRate|SoundSize|SoundType:0xa0|0x0c|0x02|0x01*/
pbuf = UI08ToBytes(pbuf, 0xaf);
//unsigned char flag = 0;
//flag = (10 << 4) | // soundformat "10 == AAC"
// (3 << 2) | // soundrate "3 == 44-kHZ"
// //(0<<1) |
// (1 << 1) | // soundsize "1 == 16bit"
// 1; // soundtype "1 == Stereo"
pbuf = UI08ToBytes(pbuf, 0); // AACPacketType: 0x00 - AAC sequence header
int put_value = 0;
switch (sample_rate)
{
case 44100:
put_value = 0x04;
break;
case 16000:
put_value = 0x08;
break;
case 64000:
put_value = 0x02;
break;
case 22050:
put_value = 0x07;
break;
case 8000:
put_value = 0x0b;
break;
}
// 0: 96000 Hz // 1 : 88200 Hz // 2 : 64000 Hz
// 3 : 48000 Hz // 4 : 44100 Hz // 5 : 32000 Hz
// 6 : 24000 Hz // 7 : 22050 Hz // 8 : 16000 Hz
// 9 : 12000 Hz // 10 : 11025 Hz // 11 : 8000 Hz
// 12 : 7350 Hz // 13 : Reserved // 14 : Reserved
// 15 : frequency is written explictly
PutBitContext pb;
init_put_bits(&pb, (char*)pbuf, 16);
put_bits(&pb, 5, 2); //object type - AAC-LC
//44100HZ 0x1210 --- 16000HZ 0x1410 --- 8000HZ 0x1590 --- 22050HZ 0x1390
put_bits(&pb, 4, put_value); //sample rate index, 44100 or 16000 or other
put_bits(&pb, 4, 2); //channel configuration
//GASpecificConfig
put_bits(&pb, 1, 0); //frame length - 1024 samples
put_bits(&pb, 1, 0); //does not depend on core coder
put_bits(&pb, 1, 0); //is not extension
flush_put_bits(&pb);
pbuf += 2;
UI32ToBytes(pbuf, len_frame);
}
#define Pre_Tag_Len 4
//返回包长度
inline int flv_v_len(int dlen)
{
int bodylen = 11 + 5 + dlen;
return bodylen + Pre_Tag_Len;
}
inline int flv_a_len(int dlen)
{
int bodylen = 11 + 2 + dlen;
return bodylen + Pre_Tag_Len;
}
//获取视频长度
int flv_header_v_tag_len(int spslen, int ppslen)
{
int bodylen = 11 + spslen + ppslen + 16;
return bodylen + Pre_Tag_Len;
}
int flv_header_a_tag_len()
{
int bodylen = 11 + 4;
return bodylen + Pre_Tag_Len;
}
public:
int InitMeta(s_av_config *savconfig)
{
//_meta_data = new char[]
if (savconfig == NULL)
return -1;
int len_total = 0;
int len_video = 0FLV文件(H264 + AAC)格式超详细分析