音视频解封装demo:将FLV文件解封装(demux)得到文件中的H264数据和AAC数据(纯手工,不依赖第三方开源库)

avatar
作者
猴君
阅读量:3

1、README

前言

注意:flv是不支持h.265封装的。目前解封装功能正常,所得到的H.264文件与AAC文件均可正常播放。

a. demo使用
$ make clean && make DEBUG=1 $  $ $ ./flv_demux_h264_aac  Usage:     ./flv_demux_h264_aac avfile/test1.flv    ./flv_demux_h264_aac avfile/test2.flv 
b. 参考链接

【参考文章】

【参考源码】

【工具下载】

c. demo目录架构
$ tree . ├── aac_adts.c ├── aac_adts.h ├── avfile │   ├── test1.aac │   ├── test1.flv │   ├── test1.h264 │   ├── test2.aac │   ├── test2.flv │   └── test2.h264 ├── docs │   ├── FLV封装格式介绍及解析 - 简书.mhtml │   ├── FLV格式详解_JT同学的博客-CSDN博客_flv格式.mhtml │   ├── 笔记---H.264里的SEI - 简书.mhtml │   ├── 音视频封装:FLV格式详解和打包H264、AAC方案(上) - 云+社区 - 腾讯云.mhtml │   └── 音视频封装:FLV格式详解和打包H264、AAC方案(下) - 云+社区 - 腾讯云.mhtml ├── flv.c ├── flv_format.h ├── flv.h ├── h264_nalu.h ├── main.c ├── Makefile ├── README.md ├── reference_code │   └── Flv_to_h264_AAC_Demux.zip └── tools     ├── FlvParse.exe     ├── H264BSAnalyzer.exe     └── SpecialAAAC.exe 

2、主要代码片段

flv_format.h
/***************************************************************  * describe: Flv file format description(Mainly for H.264 & AAC)  * author: linriming  * e-mail: linriming20@163.com  ***************************************************************/  #ifndef __FLV_FORMAT_H__ #define __FLV_FORMAT_H__   #include <stdint.h>   #define AUDIO_SUPPORT(x)    (x << 2)    /* bit[2] in flvheader's type_flag */ #define VIDEO_SUPPORT(x)    (x << 0)    /* bit[0] in flvheader's type_flag */   #define SIZE_FLV_HEADER         sizeof(struct flvHeader)    /* 9 Bytes */ #define SIZE_FLV_TAG_HEADER     sizeof(struct flvTagHeader) /* 11 Bytes */ #define SIZE_PREVIOUS_TAG_SIZE  sizeof(uint32_t)            /* 4 Bytes */   /* FLV tag type */ typedef enum{ 	FLVTAG_TYPE_AUDIO  = 0x08, 	FLVTAG_TYPE_VIDEO  = 0x09, 	FLVTAG_TYPE_SCRIPT = 0x12, }flvTagType;   /* AMF data type in <Script Tag> */ typedef enum{     AMF_DATA_TYPE_NUMBER      = 0x00,     AMF_DATA_TYPE_BOOL        = 0x01,     AMF_DATA_TYPE_STRING      = 0x02,     AMF_DATA_TYPE_OBJECT      = 0x03,     AMF_DATA_TYPE_NULL        = 0x05,     AMF_DATA_TYPE_UNDEFINED   = 0x06,     AMF_DATA_TYPE_REFERENCE   = 0x07,     AMF_DATA_TYPE_MIXEDARRAY  = 0x08,     AMF_DATA_TYPE_OBJECT_END  = 0x09,     AMF_DATA_TYPE_ARRAY       = 0x0a,     AMF_DATA_TYPE_DATE        = 0x0b,     AMF_DATA_TYPE_LONG_STRING = 0x0c,     AMF_DATA_TYPE_UNSUPPORTED = 0x0d, } amfDataType;   /* audio tag */ typedef enum{ 	SFI_LINEAR_PCM_PLATFORM_ENDIAN = 0, 	SFI_ADPCM                      = 1, 	SFI_MP3                        = 2, 	SFI_LINEAR_PCM_LITTLE_ENDIAN   = 3, 	SFI_NELLYMOSER_16KHZ_MONO      = 4, 	SFI_NELLYMOSER_8KHZ_MONO       = 5, 	SFI_NELLYMOSER                 = 6, 	SFI_G711A                      = 7, 	SFI_G711MU                     = 8, 	SFI_RESERVED                   = 9, 	SFI_AAC                        = 10, 	SFI_SPEEX                      = 11, 	SFI_MP3_8KHZ                   = 14, 	SFI_DEVIVE_SPECIFIC_SOUND      = 15, }soundFormatIndex;   typedef enum{ 	SRI_5_5KHZ = 0, 	SRI_11KHZ  = 1, 	SRI_22KHZ  = 2, 	SRI_44KHZ  = 3, }soundSamplerateIndex;   typedef enum{ 	SSI_8BIT  = 0, 	SSI_16BIT = 1, }soundSizeIndex;   typedef enum{ 	STI_MONO   = 0, 	STI_STEREO = 1, }soundTypeIndex;    #define  AAC_PACKET_TYPE_SEQUENCE_HEADER 	(0) #define  AAC_PACKET_TYPE_RAW 				(1)  typedef enum{ 	AAC_MAIN = 1,     AAC_LC   = 2,     AAC_SSR  = 3, }aacProfileIndex;  typedef enum{ 	AAC_96KHz = 0x0,     AAC_88_2KHz = 0x1,     AAC_64KHz = 0x2,    	AAC_48KHz = 0x3,     AAC_44_1KHz = 0x4,     AAC_32KHz = 0x5,    	AAC_24KHz = 0x6,     AAC_22_05KHz = 0x7,     AAC_16KHz  = 0x8,     AAC_12KHz  = 0x9,     AAC_11_025KHz  = 0xa,     AAC_8KHz  = 0xb,     AAC_RESERVED = 0xc, }aacSamplerateIndex;  typedef enum{ 	AAC_CHANNEL_SPECIAL = 0x0,     AAC_CHANNEL_MONO = 0x1,     AAC_CHANNEL_STEREO = 0x2,    	AAC_CHANNEL_3 = 0x3, 	AAC_CHANNEL_4 = 0x4, 	AAC_CHANNEL_5 = 0x5, 	AAC_CHANNEL_5_1 = 0x6, 	AAC_CHANNEL_7_1 = 0x7,     AAC_CHANNELRESERVED = 0x8, }aacChannelIndex;    #define  AVC_PACKET_TYPE_SEQUENCE_HEADER 			 (0) #define  AVC_PACKET_TYPE_NALU 						 (1) #define  AVC_PACKET_TYPE_END_OF_SEQUENCE 			 (2)  /* next for video tag */ #define  VIDEOTAG_FRAMETYPE_KEYFRAME                 (1) #define  VIDEOTAG_FRAMETYPE_INTER_FRAME              (2) #define  VIDEOTAG_FRAMETYPE_DISPOSABLE_INTER_FRAME   (3) #define  VIDEOTAG_FRAMETYPE_GENERATED_KEYFRAME       (4) #define  VIDEOTAG_FRAMETYPE_VIDEO_INFO_FRAME         (5)  #define  VIDEOTAG_CODECID_JPEG                       (1) #define  VIDEOTAG_CODECID_SORENSON_H263              (2) #define  VIDEOTAG_CODECID_SCREEN_VIDEO               (3) #define  VIDEOTAG_CODECID_ON2_VP6                    (4) #define  VIDEOTAG_CODECID_ON2_VP6_WITH_ALPHA_CHANNEL (5) #define  VIDEOTAG_CODECID_SCREEN_VIDEO_VERSION_2     (6) #define  VIDEOTAG_CODECID_AVC                        (7)    #pragma pack(push) #pragma pack(1)   /* 1 bytes align */  typedef struct flvHeader{ 	uint8_t  signature[3]; 		/* signature bytes always 'F' 'L' 'V': 0x46 0x4C 0x56 */ 	uint8_t  version; 			/* file version, always 0x01 */ 	uint8_t  type_flag; 		/* bit[7:3] and bit[1] always 0, bit[2] for aduio, bit[0] for video */ 	uint32_t data_offset; 		/* size of header, 00 00 00 09(big-endian) for version 1 */ }T_FlvHeader, *PT_FlvHeader;   	    /* 9 bytes totally */   typedef struct flvTagHeader{ 	uint8_t TagType; 					/* Type of this tag. Value are 8(audio), 9(video), 18(script), other(reserved). */ 	uint8_t DataSize[3]; 				/* Length of the data in the Data filed. */ 	uint8_t Timestamp[3]; 				/* Time in milliseconds at which the data in this applies. 0 in first tag in the FLV file. */ 	uint8_t TimestampExtended; 			/* Extension of Timestamp field to form a SI32 value, it is upper 8 bits. */ 	uint8_t StreamID[3]; 				/* Always 0 */ }T_FlvTagHeader, *PT_FlvTagHeader; 	/* 11 bytes total */   typedef struct flvTag{ 	T_FlvTagHeader flvheader; 	/* tag header */ 	uint8_t flvdata[0]; 		/* tag data index */ }T_FlvTag, *PT_FlvTag;   typedef struct avcVideoPacket{ 	T_FlvTagHeader flvheader; 	uint8_t flvdata[0]; 		/* flv tag data index */ }T_AvcVideoPacket, *PT_AvcVideoPacket;   #pragma pack(pop)   #endif /* __FLV_FORMAT_H__ */ 
flv.c
#include "h264_nalu.h" #include "aac_adts.h" #include "flv.h"   int flv_demux_h264_aac(const char *flvFileName) { 	FILE *fpH264 = NULL; 	FILE *fpAAC  = NULL; 	FILE *fpFLV  = NULL; 	uint8_t *flvBuf = NULL; 	// note!!!: it maybe happen the 'Segmentation fault', as 1024 is too long for 'sps', but it maybe save the 'sei' or other unused data if first nalu isn't 'sps'. 	uint8_t spsBuf[64] = {0}; 	uint8_t ppsBuf[64] = {0}; 	uint32_t spsLen = 0; 	uint32_t ppsLen = 0; 	int ret = -1; 	uint32_t flvTagDataSize = 0; 	PT_FlvTag ptFlvTag = NULL;  	const char *h264FileName = "out_video.h264"; 	const char *aacFileName = "out_audio.aac";  	/* open file */ 	fpFLV  = fopen(flvFileName,  "rb"); 	if (!fpFLV) 	{ 		printf("open %s error!\n", flvFileName); 	} 	fpH264 = fopen(h264FileName, "wb"); 	if (!fpH264) 	{ 		printf("open %s error!\n", h264FileName); 	} 	fpAAC  = fopen(aacFileName,  "wb"); 	if (!fpAAC) 	{ 		printf("open %s error!\n", aacFileName); 	}  	/* alloc memory */ 	flvBuf = (uint8_t *)malloc(MAX_FLV_BUF_SIZE); 	if (!flvBuf) 	{ 		printf("malloc for 'flvBuf' error!\n"); 	}  	/* parse and save some data first. */ 	fread(flvBuf, SIZE_FLV_HEADER, 1, fpFLV); 	ret = strncmp((const char *)flvBuf, "FLV", 3); 	if(ret != 0) 	{ 		printf("\033[31m It's not a FLV file!\n\033[0m"); 		return -1; 	} 	DEBUG("\033[32m" 		  "=====================================\n" 		  "Signature: '%c' '%c' '%c'\n" 		  "Version  : 0x%02x\n" 		  "Audio    : %s\n" 		  "Video    : %s\n" 		  "=====================================\n" 		  "\033[0m", 		  flvBuf[0], flvBuf[1], flvBuf[2], flvBuf[3], (flvBuf[4] & 0x04) ? "yes" : "no", (flvBuf[4] & 0x01) ? "yes" : "no");  	fread(flvBuf, SIZE_PREVIOUS_TAG_SIZE, 1, fpFLV); 	DEBUG("\033[37m[Pre Tag Size]: %d \033[0m\n", (flvBuf[0] << 24) |\ 												   (flvBuf[1] << 16) |\ 												   (flvBuf[2] <<  8) |\ 												    flvBuf[3]);  	while(1) 	{ 		ret = fread(flvBuf, SIZE_FLV_TAG_HEADER, 1, fpFLV); 		if (ret <= 0) 		{ 			DEBUG(">>> FLV file end! <<<\n"); 			break; 		} 		ptFlvTag = (PT_FlvTag)flvBuf;  		flvTagDataSize = (ptFlvTag->flvheader.DataSize[0] << 16) |\ 						 (ptFlvTag->flvheader.DataSize[1] << 8) |\ 						  ptFlvTag->flvheader.DataSize[2]; 		fread(ptFlvTag->flvdata, flvTagDataSize, 1, fpFLV);  		switch (ptFlvTag->flvheader.TagType) 		{ 			case FLVTAG_TYPE_SCRIPT: { 				DEBUG("\033[34m[Script Tag] \033[0m\n"); 				/* nothing to do! */ 				break; 			} 			case FLVTAG_TYPE_AUDIO: { 				char *packetTypeStr = NULL; 				int aacPacketType = ptFlvTag->flvdata[1];  				switch(aacPacketType) 				{ 					case AAC_PACKET_TYPE_SEQUENCE_HEADER: 						packetTypeStr = "[AAC sequence header]"; 						/* nothing to do! */ 						break; 					case AAC_PACKET_TYPE_RAW: 						packetTypeStr = "[AAC raw]";  						uint8_t headerbuf[AAC_ADTS_HEADER_SIZE] = {0}; 						uint32_t headerbufLen = 0; 						uint32_t datasize = ((ptFlvTag->flvheader.DataSize[0] << 16) |\ 											 (ptFlvTag->flvheader.DataSize[1] << 8) |\ 											 ptFlvTag->flvheader.DataSize[2]); 						generateAdtsHeader(AAC_ADTS_HEADER_SIZE + (datasize - 2), headerbuf, &headerbufLen);  						fwrite(headerbuf, headerbufLen, 1, fpAAC); 						fwrite(&ptFlvTag->flvdata[2], datasize - 2, 1, fpAAC); 						break; 					default: 						printf("[%s:%d] Unknown AAC packet type!", __FUNCTION__, __LINE__); 						goto exit; 				} 				DEBUG("\033[36m[Audio Tag] \t %s\033[0m\n", packetTypeStr); 				break; 			} 			case FLVTAG_TYPE_VIDEO: { 				char *packetTypeStr = NULL; 				char *frameTypeStr = NULL; 				uint8_t startCode[4] = {0x00, 0x00, 0x00, 0x01}; 				int isKeyFrame = 0; 				int type = 0;  				isKeyFrame = (ptFlvTag->flvdata[0] & 0xF0) == 0x10 ? 1 : 0; 				type = ptFlvTag->flvdata[1];  				switch(type) 				{ 					case AVC_PACKET_TYPE_SEQUENCE_HEADER: 						packetTypeStr = "[AVC squence header]"; 						frameTypeStr = "[key frame]";  						spsLen = ((ptFlvTag->flvdata[11] << 8) | ptFlvTag->flvdata[12]); 						memcpy(spsBuf, &ptFlvTag->flvdata[13], spsLen);  						//printf("spsLen: %d\n", spsLen); 						//for(int i = 0; i < spsLen; i++) 						//	printf("0x%02x ", spsBuf[i]); 						//printf("\n");  						ppsLen = ((ptFlvTag->flvdata[13 + spsLen + 1] << 8) | ptFlvTag->flvdata[13+spsLen+2]); 						memcpy(ppsBuf, &ptFlvTag->flvdata[13 + spsLen + 3], ppsLen);  						//printf("ppsLen: %d\n", ppsLen); 						//for(int i = 0; i < ppsLen; i++) 						//	printf("0x%02x ", ppsBuf[i]); 						//printf("\n");  						break; 					case AVC_PACKET_TYPE_NALU: 						packetTypeStr = "[AVC NALU]";  						/* one or more NALU. */ 						uint32_t naluDataSize = 0; 						uint32_t curPos = 0;  						curPos = 5; 						naluDataSize = (ptFlvTag->flvdata[curPos + 0] << 24) |\ 									   (ptFlvTag->flvdata[curPos + 1] << 16) |\ 									   (ptFlvTag->flvdata[curPos + 2] << 8) |\ 										ptFlvTag->flvdata[curPos + 3]; 						if(isKeyFrame) 						{ 							frameTypeStr = "[key frame]";  							if((ptFlvTag->flvdata[curPos + 4] & 0x1f) == NALU_TYPE_SEI &&\ 							   (ptFlvTag->flvdata[curPos + 5] & 0x1f) == 0x05/* SEI: payloadType: user_data_unregistered() */) 							{ 								/* has SEI */ 								/* SEI */ 								fwrite(startCode, sizeof(startCode), 1, fpH264); 								fwrite(&ptFlvTag->flvdata[curPos + 4], naluDataSize, 1, fpH264);  								/* SPS */ 								fwrite(startCode, sizeof(startCode), 1, fpH264); 								fwrite(spsBuf, spsLen, 1, fpH264);  								/* PPS */ 								fwrite(startCode, sizeof(startCode), 1, fpH264); 								fwrite(ppsBuf, ppsLen, 1, fpH264);  								/* update the second NALU data size. */ 								curPos += (4 + naluDataSize); 								naluDataSize = (ptFlvTag->flvdata[curPos + 0] << 24) |\ 											   (ptFlvTag->flvdata[curPos + 1] << 16) |\ 											   (ptFlvTag->flvdata[curPos + 2] << 8) |\ 												ptFlvTag->flvdata[curPos + 3]; 								/* IDR */ 								fwrite(startCode, sizeof(startCode), 1, fpH264); 								fwrite(&ptFlvTag->flvdata[curPos + 4], naluDataSize, 1, fpH264); 							} 							else 							{ 								/* SPS */ 								fwrite(startCode, sizeof(startCode), 1, fpH264); 								fwrite(spsBuf, spsLen, 1, fpH264);  								/* PPS */ 								fwrite(startCode, sizeof(startCode), 1, fpH264); 								fwrite(ppsBuf, ppsLen, 1, fpH264);  								/* IDR */ 								fwrite(startCode, sizeof(startCode), 1, fpH264); 								fwrite(&ptFlvTag->flvdata[curPos + 4], naluDataSize, 1, fpH264); 							}  						} 						else 						{ 							frameTypeStr = "[inter frame]";  							/* SLICE */ 							fwrite(startCode, sizeof(startCode), 1, fpH264); 							fwrite(&ptFlvTag->flvdata[curPos + 4], naluDataSize, 1, fpH264); 						} 						break; 					case AVC_PACKET_TYPE_END_OF_SEQUENCE: 						packetTypeStr = "[AVC end of squence]"; 						frameTypeStr = "[key frame]"; 						break; 					default: 						printf("[%s:%d] Unknown AVC packet type!", __FUNCTION__, __LINE__); 						goto exit; 				} 				DEBUG("\033[35m[Video Tag] \t %s \t %s\033[0m\n", packetTypeStr, frameTypeStr); 				break; 			} 			default: { 				printf("\033[33m[Unknown Tag]\033[0m\n"); 				break; 			} 		}  		fread(flvBuf, SIZE_PREVIOUS_TAG_SIZE, 1, fpFLV); 		DEBUG("\033[37m[PreTagSize] \t %d\033[0m\n", (flvBuf[0] << 24) |\ 													 (flvBuf[1] << 16) |\ 													 (flvBuf[2] <<	8) |\ 													  flvBuf[3]);  	}  exit: 	if(fpFLV) 	fclose(fpFLV); 	if(fpH264) 	{fflush(fpH264); fclose(fpH264);} 	if(fpAAC) 	{fflush(fpAAC); fclose(fpAAC);} 	if(flvBuf)  free(flvBuf);  	return 0; }  
main.c
#include <stdio.h>  #include "flv.h"   int main(int argc, char *argv[]) { 	if(argc == 1) 	{ 		printf("Usage: \n"  			   "   %s avfile/test1.flv\n" 			   "   %s avfile/test2.flv\n", 			   argv[0], argv[0]); 		return -1; 	}  	flv_demux_h264_aac(argv[1]);  	printf("\033[32m""Success!\n""\033[0m");  	return 0; }  

3、demo下载地址(任选一个)

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!