参考链接: 1. FLV科普12 FLV脚本数据解析-Metadata Tag解析 https://blog.csdn.net/cabbage2008/article/details/50500021
     2. FLV科普9 FLV音频信息 https://blog.csdn.net/cabbage2008/article/details/50445023
     3. FLV科普6 FLV Tag以及Tag头信息解析 https://blog.csdn.net/cabbage2008/article/details/50374083
     4. FLV科普11 FLV视频信息 https://blog.csdn.net/cabbage2008/article/details/50449857

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h> #define TAB44 " "
#define PRINTF_DEBUG #define MAX_SIGNATURE_LEN 3
#define MAX_PRE_TAG_SIZE_LEN 4
#define MIN_FLV_HEADER_LEN 9
#define MAX_TAG_HEADER_LEN 11
#define MAX_PARSE_TAG_NUM 15
#define MAX_AMF_STR_SIZE 255 /************************************************************************************************************
** flv header: 记录了flv的类型, 版本等信息, 是flv的开头, 一般都差不多, 占9bytes
**
-------------------------------------------------------------------------------------------------------------
** 字段名称    | 长度(bytes) | 有关描述
-------------------------------------------------------------------------------------------------------------
** signature | 3 | 文件标识, 总是为"FLV", 0x46 0x4c 0x56
** version | 1 | 版本(目前为0x01)
** flag | 3 | 文件的标志位说明. 前5位保留, 必须为0;
第6位为音频Tag: 1表示有音频; 第七位保留, 为0; 第8位为视频Tag: 1表示有视频
** headersize | 4 | 整个header的长度, 一般为9(版本为0x01时); 大于9表示下面还有扩展信息
************************************************************************************************************/
/*
1. unsigned char reserved5: 5, flags_audio: 1, reserved1: 1, flags_video: 1;
2. unsigned char : 5, flags_audio: 1, : 1, flags_video: 1; (无名说明无法使用, 仅占位)
3. 下面结构体位域的另外两种写法.
*/
typedef struct t_flv_header
{
unsigned char signature[MAX_SIGNATURE_LEN+];
unsigned char version;
unsigned char : ;
unsigned char flags_audio: ;
unsigned char : ;
unsigned char flags_video: ; int headersize;
} T_FLV_HEADER; /************************************************************************************************************
** tag header
**
-------------------------------------------------------------------------------------------------------------
** 字段名称    | 长度(bytes) | 有关描述
-------------------------------------------------------------------------------------------------------------
** type | 1 | 数据类型, (0x12)为脚本类型; (0x08)为音频类型; (0x09)为视频类型
** data_size | 3 | 数据区长度
** timestamp | 3 | 时间戳, 类型为(0x12)的tag时间戳一直为0, (0xFFFFFF)可以表示长度为4小时, 单位为毫秒.
** timestamp_extended | 1 | 将时间戳扩展为4bytes, 代表高8位, 一般都为0, 长度为4小时的flv一般很少见了
** streamid | 3 | 总为0
************************************************************************************************************/
typedef struct t_flv_tag_header
{
int type;
int data_size;
int timestamp;
int timestamp_extended;
int streamid;
} T_FLV_TAG_HEADER; /************************************************************************************************************
** video tag header
**
-------------------------------------------------------------------------------------------------------------
** 字段名称    | 长度(bytes) | 有关描述
-------------------------------------------------------------------------------------------------------------
** FreameType | 4(bits) | FrameType为数据类型, 1为关键帧, 2为非关键帧, 3为h263的非关键帧,
4为服务器生成关键帧, 5为视频信息或命令帧.
** CodecId | 4(bits) | CodecID为包装类型, 1为JPEG, 2为H263, 3为Screen video,
4为On2 VP6, 5为On2 VP6, 6为Screen videoversion 2, 7为AVC CodecID=2, 为H263VideoPacket;
CodecID=3, 为ScreenVideopacket;
CodecID=4, 为VP6FLVVideoPacket;
CodecID=5, 为VP6FLVAlphaVideoPacket;
CodecID=6, 为ScreenV2VideoPacket;
CodecID=7, 为AVCVideoPacket. ** AVCVideoPacket Format: | AVCPacketType(8)| CompostionTime(24) | Data |
如果AVCPacketType=0x00, 为AVCSequence Header;--描述了SPS以及PPS的信息;
如果AVCPacketType=0x01, 为AVC NALU;
如果AVCPacketType=0x02, 为AVC end ofsequence;
CompositionTime为相对时间戳: 如果AVCPacketType=0x01, 为相对时间戳; 其它, 均为0; Data为负载数据:
如果AVCPacketType=0x00, 为AVCDecorderConfigurationRecord;
如果AVCPacketType=0x01, 为NALUs;
如果AVCPacketType=0x02, 为空. AVCDecorderConfigurationRecord格式, 包括文件的信息:
| cfgVersion(8) | avcProfile(8) | profileCompatibility(8) |avcLevel(8) | reserved(6) | lengthSizeMinusOne(2) | reserved(3) | numOfSPS(5) |spsLength(16) | sps(n) | numOfPPS(8) | ppsLength(16) | pps(n) |
************************************************************************************************************/
typedef struct t_flv_tag_video_header
{
unsigned char freameType:, codecId:;
} T_FLV_TAG_VIDEO_HEADER; /************************************************************************************************************
** AVCDecoderConfigurationRecord
**
-------------------------------------------------------------------------------------------------------------
** 字段名称    | 长度(bytes) | 有关描述
-------------------------------------------------------------------------------------------------------------
** configurationVersion  | 1 | 配置版本占用8位, 一定为1
** AVCProfileIndication  | 1 | profile_idc占用8位, 从H.264标准SPS第一个字段profile_idc拷贝而来, 指明所用profile
** profile_compatibility  | 1 | 占用8位, 从H.264标准SPS拷贝的冗余字
** AVCLevelIndication  | 1 | level_idc占用8位, 从H.264标准SPS第一个字段level_idc拷贝而来, 指明所用 level
** reserved | 6b | 保留位占6位, 值一定为'111111'
** lengthSizeMinusOne | 2b | 占用2位, 表示NAL单元头的长度, 0表示1字节, 1表示2字节, 2表示3字节, 3表示4字节
** reserved | 3b | 保留位占3位, 值一定为'111'
** numOfSPS | 5b | numOfSequenceParameterSets占用5位, 表示当前SPS的个数
** SPSLength | 2 | sequenceParameterSetLength占用16位, SPS占用的长度
** SPSData | * |
** numOfPPS | 5b | numOfPictureParameterSets占用8位, 表示当前PPS的个数
** PPSLength | 2 | pictureParameterSetLength占用16位, PPS占用的长度
** PPSData | * | numOfPictureParameterSets占用8位, 表示当前PPS的个数 AVCProfileIndication, profile_compatibility, AVCLevelIndication就是拷贝SPS的前3个字节
************************************************************************************************************/
typedef struct t_flv_tag_avc_dec_cfg
{
unsigned char configurationVersion;
unsigned char AVCProfileIndication;
unsigned char profile_compatibility;
unsigned char AVCLevelIndication;
unsigned char :, lengthSizeMinusOne:; unsigned char :, numOfSequenceParameterSets:;
unsigned short spsLen;
unsigned char *spsData; unsigned char numOfPictureParameterSets;
unsigned short ppsLen;
unsigned char *ppsData;
} T_FLV_TAG_AVC_DEC_CFG; /************************************************************************************************************
** avc video packet header
**
-------------------------------------------------------------------------------------------------------------
** 字段名称    | 长度(bytes) | 有关描述
-------------------------------------------------------------------------------------------------------------
** AVCPacketType占用1字节 | 1 |
** CompositionTime | 3 | AVCVideoPacket同样包括Packet Header和Packet Body两部分:
Packet Header:
AVCPacketType占用1字节, 仅在AVC时有此字段
               0, AVC sequence header (SPS、PPS信息等)
               1, AVC NALU
               2, AVC end of sequence (lower level NALU sequence ender is not required or supported) CompositionTime占用24位, 相对时间戳, 如果AVCPacketType=0x01为相对时间戳; 其它, 均为0;
该值表示当前帧的显示时间, tag的时间为解码时间, 显示时间等于 解码时间+CompositionTime.
************************************************************************************************************/
typedef struct t_flv_tag_avc_video_packet
{
unsigned char avcPacketType; int compositionTime; union videoPacket
{
T_FLV_TAG_AVC_DEC_CFG avcDecCfg;
} vp;
} T_FLV_TAG_AVC_VIDEO_PACKET; typedef struct t_flv_tag_audio_header
{
unsigned char soundFormat:, soundRate:, soundSize:, soundType:;
} T_FLV_TAG_AUDIO_HEADER; typedef struct t_flv_tag_aac_spec_cfg
{
unsigned char audioObjectType:;
unsigned char samplingFreqIndex:, channelCfg:;
} T_FLV_TAG_AAC_SPEC_CFG; typedef struct t_flv_tag_aac_audio_packet
{
unsigned char aacPacketType; union audioPacket
{
T_FLV_TAG_AAC_SPEC_CFG aacSpecCfg;
} ap;
} T_FLV_TAG_AAC_AUDIO_PACKET; typedef struct t_flv_tag
{
} T_FLV_TAG; /* 小端转double */
static double dealAmfNumber(unsigned char *amfNum)
{
double d = ; unsigned char *dp = (unsigned char *)&d; dp[] = amfNum[];
dp[] = amfNum[];
dp[] = amfNum[];
dp[] = amfNum[];
dp[] = amfNum[];
dp[] = amfNum[];
dp[] = amfNum[];
dp[] = amfNum[]; return d;
} /*
1. DealHeader(const unsigned char* headerData);
这样定义会报warning: assignment discards 'const' qualifier from pointer target type,
大意是指针丢掉"const"限定符.
2. 原因是: data = headerData; 这一句存在丢掉的风险(可通过给*data赋予不同的值, 使得headerData的数据也被修改, 失去const的作用)
3. const int *p; //这种情况表示*p是const无法进行修改, 而p是可以进行修改的;
int* const p; //这种情况表示p是const无法进行修改, 而*p是可以进行修改的;
const int* const p; //这种情况表示*p与p都无法进行修改.
*/
static void DealFlvHeader(unsigned char* const headerData)
{
unsigned char *data = NULL; T_FLV_HEADER flvHeader = {}; data = headerData; memset(&flvHeader, 0x0, sizeof(T_FLV_HEADER)); memcpy(flvHeader.signature, data, MAX_SIGNATURE_LEN); flvHeader.signature[MAX_SIGNATURE_LEN] = '\0'; data += MAX_SIGNATURE_LEN; flvHeader.version = data[]; data += ; flvHeader.flags_audio = data[] >> & 0x1;
flvHeader.flags_video = data[] & 0x1; data += ; flvHeader.headersize = (data[] << ) | (data[] << ) | (data[] << ) | data[]; if (0x1 != flvHeader.version)
{
printf("version is not 1, todo...\n");
} #ifdef PRINTF_DEBUG
printf("+FLV Header\n");
printf("%ssignature: %s, version: %d, flags_audio: %d, flags_video: %d, headersize: %d\n",
TAB44, flvHeader.signature, flvHeader.version, flvHeader.flags_audio, flvHeader.flags_video, flvHeader.headersize);
#endif
} static void DealTagHeader(unsigned char* const headerData, T_FLV_TAG_HEADER *tagHeader)
{
static int videoTagNum = ;
static int audioTagNum = ; unsigned char *data = NULL; T_FLV_TAG_HEADER header = {}; data = headerData; memset(&header, 0x0, sizeof(T_FLV_TAG_HEADER)); header.type = data[]; data += ; header.data_size = (data[] << ) | (data[] << ) | data[]; data += ; header.timestamp = (data[] << ) | (data[] << ) | data[]; data += ; header.timestamp_extended = data[]; data += ; header.streamid = (data[] << ) | (data[] << ) | data[]; memcpy(tagHeader, &header, sizeof(T_FLV_TAG_HEADER)); #ifdef PRINTF_DEBUG
switch (tagHeader->type)
{
case 0x12:
printf("%s+Script Tag\n", TAB44); break; case 0x9:
videoTagNum++; printf("%s+Video Tag[%d]\n", TAB44, videoTagNum); break; case 0x8:
audioTagNum++; printf("%s+Audio Tag[%d]\n", TAB44, audioTagNum); break; default:
break;
} printf("%s%s+Tag Header\n", TAB44, TAB44);
printf("%s%s%stype: %d, data_size: %d, timestamp: %d, timestamp_extended: %d, streamid: %d\n",
TAB44, TAB44, TAB44, tagHeader->type, tagHeader->data_size, tagHeader->timestamp, tagHeader->timestamp_extended, tagHeader->streamid);
#endif
} /*
第一个AMF包:
       第1个字节表示AMF包类型, 一般总是0x02, 表示字符串, 其他值表示意义请查阅文档.
       第2-3个字节为UI16类型值, 表示字符串的长度, 一般总是0x000A("onMetaData"长度).
       后面字节为字符串数据, 一般总为"onMetaData".
 
第二个AMF包:
       第1个字节表示AMF包类型, 一般总是0x08, 表示数组.
       第2-5个字节为UI32类型值, 表示数组元素的个数.
       后面即为各数组元素的封装, 数组元素为元素名称和值组成的对. 表示方法如下:
       第1-2个字节表示元素名称的长度, 假设为L. 后面跟着为长度为L的字符串. 第L+3个字节表示元素值的类型.
       后面跟着为对应值, 占用字节数取决于值的类型. 0 = Number type (double, 8)
1 = Boolean type
2 = String type
3 = Object type
4 = MovieClip type
5 = Null type
6 = Undefined type
7 = Reference type
8 = ECMA array type
10 = Strict array type
11 = Date type
12 = Long string type 1. 不要频繁的malloc小内存(内存碎片, 代价);
2. 如该函数中arrayKey, arrayValue, amfStrData设置成指针, 然后malloc就有问题(字符串后残留上述三个最大长度中的字符);
3. 可能的解释: 当用free释放的你用malloc分配的存储空间, 释放的存储空间并没有从进程的地址空间中删除, 而是保留在可用存储区池中,
当再次用malloc时只要可用存储区池中有足够的地址空间, 都不会再向内可申请内存了, 而是在可用存储区池中分配了. 实际分析时: 8的数组后还有一串 00 00 09, 暂时不清楚, 先跳过if (tagDataSize <= 3)
*/
static void DealScriptTagData(unsigned char* const tagData, unsigned int tagDataSize)
{
int i = ;
int amfType = ;
int amfIndex = ;
int valueType = ;
int valueSize = ;
int keySize = ;
int arrayCount = ;
int amfStringSize = ; double amfNum = ; unsigned char amfStr[MAX_AMF_STR_SIZE+] = {}; unsigned char *data = NULL; data = tagData; for (;;)
{
if (tagDataSize <= )
{
break;
} amfType = data[]; amfIndex += ; data += ;
tagDataSize -= ; #ifdef PRINTF_DEBUG
printf("%s%s%sAMF%d type: %d\n", TAB44, TAB44, TAB44, amfIndex, amfType);
#endif switch (amfType)
{
case :
amfStringSize = (data[] << ) | data[]; #ifdef PRINTF_DEBUG
printf("%s%s%sAMF%d String size: %d\n", TAB44, TAB44, TAB44, amfIndex, amfStringSize);
#endif data += ;
tagDataSize -= ; memset(amfStr, 0x0, sizeof(amfStr)); memcpy(amfStr, data, amfStringSize); amfStr[amfStringSize] = '\0'; #ifdef PRINTF_DEBUG
printf("%s%s%sAMF%d String: %s\n", TAB44, TAB44, TAB44, amfIndex, amfStr);
#endif data += amfStringSize;
tagDataSize -= amfStringSize; break; case :
arrayCount = (data[] << ) | (data[] << ) | (data[] << ) | data[]; #ifdef PRINTF_DEBUG
printf("%s%s%sAMF%d Metadata count: %d\n", TAB44, TAB44, TAB44, amfIndex, arrayCount);
printf("%s%s%s+Metadata\n", TAB44, TAB44, TAB44);
#endif data += ;
tagDataSize -= ; for (i=; i<arrayCount; i++)
{
keySize = (data[] << ) | data[]; data += ;
tagDataSize -= ; memset(amfStr, 0x0, sizeof(amfStr)); memcpy(amfStr, data, keySize); amfStr[keySize] = '\0'; #ifdef PRINTF_DEBUG
printf("%s%s%s%s%s: ", TAB44, TAB44, TAB44, TAB44, amfStr);
#endif data += keySize;
tagDataSize -= keySize; valueType = data[]; data += ;
tagDataSize -= ; if ( == valueType)
{
amfNum = dealAmfNumber(data);
#ifdef PRINTF_DEBUG
printf("%lf\n", amfNum);
#endif data += ;
tagDataSize -= ;
}
else if ( == valueType)
{
#ifdef PRINTF_DEBUG
printf("%d\n", data[]);
#endif
data += ;
tagDataSize -= ;
}
else if ( == valueType)
{
valueSize = (data[] << ) | data[]; data += ;
tagDataSize -= ; memset(amfStr, 0x0, sizeof(amfStr)); memcpy(amfStr, data, valueSize); amfStr[valueSize] = '\0'; #ifdef PRINTF_DEBUG
printf("%s\n", amfStr);
#endif data += valueSize;
tagDataSize -= valueSize;
}
else
{
//printf("now can not parse value type: %d\n", valueType); return;
}
} break; default:
break;
}
}
} /*
Video Header = | FrameType(4) | CodecID(4) |
VideoData = | FrameType(4) | CodecID(4) | VideoData(n) |
*/
static void DealVideoTagData(unsigned char* const tagData)
{
unsigned char *data = NULL; data = tagData; T_FLV_TAG_VIDEO_HEADER vTagHeader = {};
T_FLV_TAG_AVC_VIDEO_PACKET avcVideoPacket = {}; memset(&vTagHeader, 0x0, sizeof(vTagHeader)); vTagHeader.freameType = data[] >> & 0xf;
vTagHeader.codecId = data[] & 0xf; data++; #ifdef PRINTF_DEBUG
printf("%s%s%sFrameType: %d\n", TAB44, TAB44, TAB44, vTagHeader.freameType);
printf("%s%s%sCodecId: %d\n", TAB44, TAB44, TAB44, vTagHeader.codecId);
#endif /* now just avc(h264) */
switch (vTagHeader.codecId)
{
case 0x07:
memset(&avcVideoPacket, 0x0, sizeof(avcVideoPacket)); avcVideoPacket.avcPacketType = data[];
avcVideoPacket.compositionTime = (data[] << ) | (data[] << ) | data[]; data += ; if ( == avcVideoPacket.avcPacketType)
{
#ifdef PRINTF_DEBUG
printf("%s%s%s+AVCVideoPacket\n", TAB44, TAB44, TAB44);
printf("%s%s%s%sAVCPacketType: %d\n", TAB44, TAB44, TAB44, TAB44, avcVideoPacket.avcPacketType);
printf("%s%s%s%sCompositionTime Offset: %d\n", TAB44, TAB44, TAB44, TAB44, avcVideoPacket.compositionTime);
#endif
printf("%s%s%s%s+AVCDecoderConfigurationRecord\n", TAB44, TAB44, TAB44, TAB44); avcVideoPacket.vp.avcDecCfg.configurationVersion = data[];
avcVideoPacket.vp.avcDecCfg.AVCProfileIndication = data[];
avcVideoPacket.vp.avcDecCfg.profile_compatibility = data[];
avcVideoPacket.vp.avcDecCfg.AVCLevelIndication = data[];
avcVideoPacket.vp.avcDecCfg.lengthSizeMinusOne = data[] & 0x3;
avcVideoPacket.vp.avcDecCfg.numOfSequenceParameterSets = data[] & 0x1f;
avcVideoPacket.vp.avcDecCfg.spsLen = (data[] << ) | data[]; // todo, parse sps data += (+avcVideoPacket.vp.avcDecCfg.spsLen); avcVideoPacket.vp.avcDecCfg.numOfPictureParameterSets = data[];
avcVideoPacket.vp.avcDecCfg.ppsLen = (data[] << ) | data[]; // todo, parse pps #ifdef PRINTF_DEBUG
printf("%s%s%s%s%sconfigurationVersion: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.configurationVersion);
printf("%s%s%s%s%sAVCProfileIndication: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.AVCProfileIndication);
printf("%s%s%s%s%sprofile_compatibility: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.profile_compatibility);
printf("%s%s%s%s%sAVCLevelIndication: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.AVCLevelIndication);
printf("%s%s%s%s%slengthSizeMinusOne: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.lengthSizeMinusOne);
printf("%s%s%s%s%snumOfSequenceParameterSets: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.numOfSequenceParameterSets);
printf("%s%s%s%s%ssequenceParameterSetLength: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.spsLen);
printf("%s%s%s%s%snumOfPictureParameterSets: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.numOfPictureParameterSets);
printf("%s%s%s%s%spictureParameterSetLength: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, avcVideoPacket.vp.avcDecCfg.ppsLen);
#endif
}
else
{
#ifdef PRINTF_DEBUG
printf("%s%s%s+Video Data\n", TAB44, TAB44, TAB44);
printf("%s%s%s%sAVCPacketType: %d\n", TAB44, TAB44, TAB44, TAB44, avcVideoPacket.avcPacketType);
printf("%s%s%s%sCompositionTime Offset: %d\n", TAB44, TAB44, TAB44, TAB44, avcVideoPacket.compositionTime);
printf("%s%s%s%sData\n", TAB44, TAB44, TAB44, TAB44);
#endif
} break; default:
break;
}
} static void DealAudioTagData(unsigned char* const tagData)
{
unsigned char *data = NULL; data = tagData; T_FLV_TAG_AUDIO_HEADER audioHeader = {};
T_FLV_TAG_AAC_AUDIO_PACKET aPacket = {}; memset(&audioHeader, 0x0, sizeof(T_FLV_TAG_AUDIO_HEADER)); audioHeader.soundFormat = (data[] >> ) & 0xf;
audioHeader.soundRate = (data[] >> ) & 0x3;
audioHeader.soundSize = (data[] >> ) & 0x1;
audioHeader.soundType = data[] & 0x1; #ifdef PRINTF_DEBUG
printf("%s%s%sSoundFormat: %d\n", TAB44, TAB44, TAB44, audioHeader.soundFormat); switch (audioHeader.soundRate)
{
case :
printf("%s%s%sSoundRate: 5.5-KHz\n", TAB44, TAB44, TAB44);
break; case :
printf("%s%s%sSoundRate: 11-KHz\n", TAB44, TAB44, TAB44);
break; case :
printf("%s%s%sSoundRate: 22-KHz\n", TAB44, TAB44, TAB44);
break; case :
printf("%s%s%sSoundRate: 44-KHz\n", TAB44, TAB44, TAB44);
break; default:
printf("%s%s%sSoundRate: %d\n", TAB44, TAB44, TAB44, audioHeader.soundRate);
} switch (audioHeader.soundSize)
{
case :
printf("%s%s%sSoundSize: snd8bit\n", TAB44, TAB44, TAB44);
break; case :
printf("%s%s%sSoundSize: snd16bit\n", TAB44, TAB44, TAB44);
break; default:
printf("%s%s%sSoundSize: %d\n", TAB44, TAB44, TAB44, audioHeader.soundSize);
} switch (audioHeader.soundType)
{
case :
printf("%s%s%sSoundType: sndMono\n", TAB44, TAB44, TAB44);
break; case :
printf("%s%s%sSoundType: sndStereo\n", TAB44, TAB44, TAB44);
break; default:
printf("%s%s%sSoundSize: %d\n", TAB44, TAB44, TAB44, audioHeader.soundSize);
}
#endif data++; /* now just for aac */
switch (audioHeader.soundFormat)
{
case 0xa:
memset(&aPacket, 0x0, sizeof(T_FLV_TAG_AAC_AUDIO_PACKET)); aPacket.aacPacketType = data[]; if ( == aPacket.aacPacketType)
{
#ifdef PRINTF_DEBUG
printf("%s%s%s+AACAudioData\n", TAB44, TAB44, TAB44);
printf("%s%s%s%sAACPacketType: %d\n", TAB44, TAB44, TAB44, TAB44, aPacket.aacPacketType);
#endif
aPacket.ap.aacSpecCfg.audioObjectType = (data[] >> ) & 0x1f;
aPacket.ap.aacSpecCfg.samplingFreqIndex = ((data[] & 0x7) << ) | ((data[] >> ) & 0x1);
aPacket.ap.aacSpecCfg.channelCfg = (data[] >> ) & 0xf; #ifdef PRINTF_DEBUG
printf("%s%s%s%s+AudioSpecificConfig\n", TAB44, TAB44, TAB44, TAB44); printf("%s%s%s%s%sAudioObjectType: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, aPacket.ap.aacSpecCfg.audioObjectType);
printf("%s%s%s%s%sSamplingFrequencyIndex: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, aPacket.ap.aacSpecCfg.samplingFreqIndex);
printf("%s%s%s%s%sChannelConfiguration: %d\n", TAB44, TAB44, TAB44, TAB44, TAB44, aPacket.ap.aacSpecCfg.channelCfg);
#endif
}
else
{
#ifdef PRINTF_DEBUG
printf("%s%s%s+AACAudioData\n", TAB44, TAB44, TAB44);
printf("%s%s%s%sAACPacketType: %d\n", TAB44, TAB44, TAB44, TAB44, aPacket.aacPacketType);
printf("%s%s%s%sData(Raw AAC frame data)\n", TAB44, TAB44, TAB44, TAB44);
#endif
} break; default:
break;
}
} static void DealTagData(unsigned char* const tagData, const int tagType, const unsigned int tagSize)
{
#ifdef PRINTF_DEBUG
printf("%s%s%s\n", TAB44, TAB44, "+Tag Data");
#endif switch (tagType)
{
case 0x12:
DealScriptTagData(tagData, tagSize); break; case 0x9:
DealVideoTagData(tagData); break; case 0x8:
DealAudioTagData(tagData); break; default:
break;
}
} int main(int argc, char *argv[])
{
int dataLen = ;
int previousTagSize = ; FILE *fp = NULL; unsigned char *tagData = NULL; unsigned char flvHeaderData[MIN_FLV_HEADER_LEN+] = {};
unsigned char preTagSizeData[MAX_PRE_TAG_SIZE_LEN+] = {};
unsigned char tagHeaderData[MAX_TAG_HEADER_LEN+] = {}; T_FLV_TAG_HEADER tagHeader = {}; if ( != argc)
{
printf("Usage: flvparse **.flv\n"); return -;
} fp = fopen(argv[], "rb");
if (!fp)
{
printf("open file[%s] error!\n", argv[]); return -;
} memset(flvHeaderData, 0x0, sizeof(flvHeaderData)); dataLen = fread(flvHeaderData, , MIN_FLV_HEADER_LEN, fp);
if (dataLen != MIN_FLV_HEADER_LEN)
{
printf("read flv header error!\n"); fclose(fp); return -;
} flvHeaderData[MIN_FLV_HEADER_LEN] = '\0'; DealFlvHeader(flvHeaderData); #ifdef PRINTF_DEBUG
printf("+FLV Body\n");
#endif while ()
{
memset(preTagSizeData, 0x0, sizeof(preTagSizeData)); dataLen = fread(preTagSizeData, , MAX_PRE_TAG_SIZE_LEN, fp);
if (dataLen != MAX_PRE_TAG_SIZE_LEN)
{
break;
} preTagSizeData[MAX_PRE_TAG_SIZE_LEN] = '\0'; #ifdef PRINTF_DEBUG
printf("%spreviousTagSize: %d\n", TAB44, (preTagSizeData[]<<) | (preTagSizeData[]<<) | (preTagSizeData[]<<) | preTagSizeData[]);
#endif memset(tagHeaderData, 0x0, sizeof(tagHeaderData)); dataLen = fread(tagHeaderData, , MAX_TAG_HEADER_LEN, fp);
if (dataLen != MAX_TAG_HEADER_LEN)
{
continue;
} memset(&tagHeader, 0x0, sizeof(T_FLV_TAG_HEADER)); DealTagHeader(tagHeaderData, &tagHeader); tagData = (unsigned char*)malloc(tagHeader.data_size);
if (!tagData)
{
continue;
} memset(tagData, 0x0, tagHeader.data_size); dataLen = fread(tagData, , tagHeader.data_size, fp);
if (dataLen != tagHeader.data_size)
{
continue;
} DealTagData(tagData, tagHeader.type, tagHeader.data_size); free(tagData);
tagData = NULL;
} fclose(fp); return ;
}

   最后如果您觉得本篇对您有帮助,可以打赏下,谢谢!!!

 

flv文件解析(纯c解析代码)的更多相关文章

  1. h264文件分析(纯c解析代码)

    参考链接:1. 解析H264的SPS信息 https://blog.csdn.net/lizhijian21/article/details/80982403               2. h.2 ...

  2. h265文件分析(纯c解析代码)

    参考链接: 1. HEVC码流解析 https://blog.csdn.net/CrystalShaw/article/details/80624804   2. HEVC编码结构:序列参数集SPS. ...

  3. mpeg4文件分析(纯c解析代码)

    参考链接: 1. MPEG4码流的帧率计算 https://blog.csdn.net/littlebee90/article/details/68924690                2. M ...

  4. ts文件分析(纯c解析代码)

    参考链接: 1. MPEG-2 TS码流分析 https://blog.csdn.net/zhubin215130/article/details/8958567 TS Header PAT PMT ...

  5. mpeg2文件分析(纯c解析代码)

    参考链接: 1. MPEG-2码流结构分析 https://www.cnblogs.com/CoderTian/p/9246225.html(本文语法采用这里的截图,代码原创) 1. mpeg2的码流 ...

  6. ps文件解析(纯c解析代码)

    参考链接:1. PS流的格式和解析总结 http://www.cnblogs.com/lihaiping/p/4181607.html  2. TS科普5 PES包解析 https://blog.cs ...

  7. mp4文件解析(纯c解析代码)

     参考链接:1. mp4文件格式解析 https://www.cnblogs.com/ranson7zop/p/7889272.html   2. MP4文件格式分析及分割实现(附源码) https: ...

  8. (转)rtmp协议简单解析以及用其发送h264的flv文件

    Adobe公司太坑人了,官方文档公布的信息根本就不全,如果只按照他上面的写的话,是没法用的.按照文档上面的流程,server和client连接之后首先要进行握手,握手成功之后进行一些交互,其实就是交互 ...

  9. 【转】使用JavaParser获得Java代码中的类名、方法形参列表中的参数名以及统计总的文件个数与不能解析的文件个数

    遍历目录查找Java文件: public static void ergodicDir(File dir, HashSet<String> argNameSet, HashSet<S ...

随机推荐

  1. list,tuple,dict,set的增删改查

    数据结构 list tuple dict set 增 append insert    d['key']=value  add 删 pop pop(0)    d.pop('name') pop re ...

  2. CentOS7攻克日记(二) —— 配置初始化及网络配置

    reboot之后到达这个页面,点击第一个进去同意一下协议之后Done,然后点击右下角的FINISH

  3. Java中的集合类,集合类有哪些,如何增添删除元素,如何遍历

    http://www.cnblogs.com/LittleHann/p/3690187.html import java.util.*; public class TestCollection { p ...

  4. POJ 1061 青蛙的约会(拓展欧几里得)

    #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #i ...

  5. inline temp 内联临时变量

    double basePrice = order.getPrice(); return basePrice; 改成 return  order.getPrice(); 去掉临时无用的临时变量

  6. 另类AOP设计

    常见的AOP设计都基于Remoting的RealProxy,或者基于Emit实现的动态代理,或者基于反射的Attribute扫描拦截.但是我们还有另类的拦截方案DynamicObject,只要我们继承 ...

  7. textarea跟随内容自动伸缩高度实现方案

    监听input事件,然后将textarea的style.height设置为最低高度(19px),进而获取到元素的scrollHeight,然后将scroolHeight设置为style.height

  8. widerface---VOC

    import os, h5py, cv2, sys, shutil import numpy as np from xml.dom.minidom import Document rootdir = ...

  9. linux-基础命令篇-02

    基本命令:--LS 关于显示的颜色含义: 白色:表示普通文件 蓝色:表示目录 绿色:表示可执行文件 红色:表示压缩文件 浅蓝色:链接文件 红色闪烁:表示链接的文件有问题 黄色:表示设备文件 灰色:表示 ...

  10. font——文字属性大全

    一.字体风格(font-style) <style type="text/css"> /*默认值.浏览器显示一个标准的字体样式.*/ p.normal {font-st ...