音视频开发---文件格式转换---h264转flv过程详解

将H.264封装为FLV格式 C源码CSDN下载:https://download.csdn.net/download/weixin_42462202/11037715
参考上面博文提供的c代码项目,整理一下h264转flv的流程

h264文件分析:


信息整理并用于后续: 有无音视频流

生成flv文件:
1、准备好flv文件头的buf(包含flv文件头信息+4字节 previous tag size)并写入目标flv文件   	getFlvHeader + 写入flvFlushData
2、Script Tag Data结构 填充2个AFM包的元素(部分直接填/部分不填但记录下值的位置offfset) 	getVideoScriptParam(只有Script Tag Data数据) + buildTag(tagdate加个头变成tag) + 写入flvFlushData
3、读取最前面2个nalu(即sps和pps)→→  getAVCSequenceHeader(将spspps数据打包成一个video tag date) +打包 + 写入  //有其特定格式 from文档
4while循环读取nalu并打包成tag写入目标文件 (如果遇到sps则要做成一个spspps的tag写入)		getvideoTagData将普通nalu打包成tag.date
																							//按照标准格式 依次写入对应的参数
5、补上前面缺少的数据 																		rewrite_amf_double

/*
自定义函数
写入AMF包的类型or元素个数(即写入一个enum int):	ui8/16/24/32_to_bytes(uint8_t *buf, uint16_t val) 将一个8/16/24/32位数据按照大端格式存放/写入到buf 

写入AMF包的元素名长度+元素名:			amf_string_to_bytes(uint8_t *buf, const char *str)  
写入AMF包的元素的值:					*amf_double_to_bytes(uint8_t *buf, double d)

为3种tag封装一个tag头:   buildTag		

int getNALU(PT_NALU pNalu, FILE *pFile) 读去start_code后读取nalu_date(每读一个字节就检查是否读完本nalu)
rewrite_amf_double(FILE *fp, uint64_t position, double value)在文件的position位置填上数据value
*/

typedef struct FlvContext {
    T_FlvTag flvTag;
	{
		unsigned char *pBuf;		//	到目前位置已经准备好了的内容的buf(每次准备以tag为单位准备,且以previous tag size结尾)
		unsigned int bufLen;		//=FLV_HEAD_SIZE(头9字节)+FLV_TAG_PRE_SIZE(previous tag size 4字节)   
		unsigned char *pBufHelp;    // 给本次tag(第一次:视频Script Tag Data 使用 4096足够用了)
		unsigned int bufHelpLen;
		unsigned int timeStamp; /* 时间戳 */
		unsigned int tagType; /* 数据类型 */   // = FLV_TAG_TYPE_META;
		unsigned long frameNum;
		unsigned long frameRatePos;
		unsigned long durationPos;
		unsigned long fileSizePos;
		unsigned long bitratePos;
	}
    T_AVParam avParam;
    {
    	T_AudioParam audioParam;
    	T_VideoParam videoParam;
    	{
			int frameType;		/* 视频帧类型( I帧,P帧 ) */  //=15
			unsigned int imageType;		/* 图像分辨率类型 */
			unsigned int form;				/* 制式(PAL或N制) */
			unsigned int width;			/* 宽度 */ 			//= 320;
			unsigned int height;			/* 高度 */ 		//=240
			unsigned int pitch;
			unsigned int fieldFlag;	    /* 分场标志 */
			unsigned int frameRate;        //帧率
			unsigned int codecType;		//视频编码类型 = FLV_CODECID_H264;
    	}
    	int bHasAudio; /* 是否有音频数据 */
    	int bHasVideo =1; /* 是否有视频数据 */
    }
    unsigned int curTimeStamp;   //=0
    unsigned int aduioTimeInterval;  //= 20;
    unsigned int videoTimeInterval;	//= 66; /* 一秒15帧,帧间隔15ms */
    FILE *pSrcFile;
    FILE *pDstFile;
} T_FlvContext, *PT_FlvContext;



T_NALU nalu[2];//分别为sps pps准备

//向*buf按照大端模式写入32bit
static uint8_t *ui32_to_bytes(uint8_t *buf, uint32_t val) {
    buf[0] = (val >> 24) & 0xff;
    buf[1] = (val >> 16) & 0xff;
    buf[2] = (val >> 8) & 0xff;
    buf[3] = (val) & 0xff;

    return buf + 4;
}

//buf按照字节转int
static uint8_t bytes_to_ui32(const uint8_t *buf) {
    return (((buf[0]) << 24) & 0xff000000)
            | (((buf[1]) << 16) & 0xff0000)
            | (((buf[2]) << 8) & 0xff00)
            | (((buf[3])) & 0xff);
}

//union实现格式转换
static uint64_t dbl2int(double value)
{
	union
	{
		double f;
		uint64_t i;
	}_val;

	_val.f = value;

	return _val.i;
}
发布了81 篇原创文章 · 获赞 1 · 访问量 2897

猜你喜欢

转载自blog.csdn.net/qq_42024067/article/details/104311162