分析一下GitHub上一份FLV文件分析和解析器的开源代码
GitHub源码地址:功能强大的 FLV 文件分析和解析器
:可以将flv文件的视频tag中的h264类型数据和音频tag中的aac类型数据导出
(只限h264和aac)
(这个代码不太适合用于大文件的分析,因为所有数据都会一直存在内存中)
main.cpp
#include <iostream>
#include <fstream>
#include "FlvParser.h"
using namespace std;
void Pro(fstream &fin);
int main()
{
cout << "Hello World!" << endl;
string infilename("test.flv");
if(!infilename.length())
{
cout<<"!infilename.length() "<<endl;
}
fstream fin;
fin.open(infilename, ios_base::in | ios_base::binary);
if(!fin)
{
cout<<"fin.open failed!"<<endl;
return 0;
}
Pro(fin);
fin.close();
return 0;
}
void Pro(fstream& fin)
{
FlvParser parser;
int nBufSize = 2 * 1024 * 1024;
int nFlvPos = 0;
uint8_t *pBuf, *pBak;
pBuf = new uint8_t[nBufSize];
pBak = new uint8_t[nBufSize];
while (1)
{
int nReadNum = 0;
int nUsedLen = 0;
fin.read((char*)pBuf + nFlvPos, nBufSize - nFlvPos);
//获取上次读取的字符数
nReadNum = fin.gcount();
//结束读取
if(nReadNum == 0)
break;
nFlvPos += nReadNum;
parser.Parse(pBuf, nFlvPos, nUsedLen);
//判断没有处理nFlvPos长度,就前移剩下的数据到前面
if(nFlvPos != nUsedLen)
{
memcpy(pBak, pBuf + nUsedLen, nFlvPos - nUsedLen);
memcpy(pBuf, pBak, nFlvPos - nUsedLen);
}
nFlvPos -= nUsedLen;
}
//输出文件信息
parser.PrintInfo();
//输出h264数据
parser.DumpH264("parser.h264");
//输出aac数据
parser.DumpAAC("parser.aac");
delete[] pBak;
delete[] pBuf;
}
FlvParser.h
#ifndef FLVPARSER_H
#define FLVPARSER_H
#include <vector>
#include <stdint.h>
#include <string>
using namespace std;
class FlvParser
{
public:
FlvParser();
virtual ~FlvParser();
int Parse(uint8_t *pBuf, int nBufSize,int& nUsedLen);
int PrintInfo();
int DumpH264(const std::string& path);
int DumpAAC(const std::string& path);
private:
//flv头部信息
typedef struct _FlvHeader
{
int nVersion; //版本
int bHaveVideo;//是否有音频
int bHaveAudio;//是否有视频
int nHeadSize;//FLV头部长度
//头部数据
uint8_t *pFlvHeader;
}FlvHeader;
//Tag头部
struct TagHeader
{
int nType;//类型
int nDataSize;//body的大小
int nTimeStamp;//时间戳
int nTSEx; //时间戳的扩展字节
int nStreamID;//流的ID,总是0
//完整的时间戳nTimeStamp和nTSEx拼装
uint32_t nTotalTS;
TagHeader():nType(0), nDataSize(0), nTimeStamp(0), nTSEx(0), nStreamID(0), nTotalTS(0){}
~TagHeader(){}
};
class Tag
{
public:
TagHeader _header;
uint8_t* _pTagHeader;//tag头部
uint8_t* _pTagData;//tag body
uint8_t* _pMedia;//tag 元数据,改造后的数据
int _nMediaLen;//数据长度
public:
Tag():_pTagHeader(0), _pTagData(0), _pMedia(0), _nMediaLen(0){}
void Init(TagHeader* pHeader, uint8_t* pBuf, int nLeftLen);
};
class VideoTag: public Tag
{
public:
int _nFrameType;//帧类型
int _nCodecID;//视频编解码类型
public:
VideoTag(TagHeader* pHeader, uint8_t* pBuf, int nLeftLen, FlvParser* pParser);
int ParseH264Tag(FlvParser *pParser);
int ParseH264Configuration(FlvParser* pParser, uint8_t* pTagData);
int ParseNalu(FlvParser* pParser, uint8_t* pTagData);
};
class AudioTag:public Tag
{
public:
int _nSoundFormat; //编码类型
int _nSoundRate;//采样率
int _nSoundSize;//精度
int _nSoundType;//类型
static int _aacProfile;//AAC profile
static int _sampleRateIndex;//采样率索引
static int _channelConfig;//通道设置
public:
AudioTag(TagHeader* pHeader, uint8_t* pBuf, int nLeftLen, FlvParser* pParser);
int ParseAACTag(FlvParser *pParser);
int ParseAudioSpecificConfig(FlvParser* pParser, uint8_t *pTagData);
int ParserRawAAC(FlvParser* pParser, uint8_t* pTagData);
};
class MetaDataTag: public Tag
{
public:
uint8_t m_amf1_type;
uint32_t m_amf1_size;
uint8_t m_amf2_type;
unsigned char* m_meta;
unsigned int m_length;
double m_duration;
double m_width;
double m_height;
double m_videodatarate;
double m_framerate;
double m_videocodecid;
double m_audiodatarate;
double m_audiosamplerate;
double m_audiosamplesize;
bool m_stereo;
double m_audiocodecid;
string m_major_brand;
string m_minor_version;
string m_compatible_brands;
string m_encoder;
double m_filesize;
public:
MetaDataTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen, FlvParser *pParser);
double hexStr2double(const unsigned char* hex, const unsigned int length);
int parseMeta(FlvParser* pParser);
void printMeta();
};
struct FlvStat
{
int nMetaNum, nVideoNum, nAudioNum;
int nMaxTimeStamp;
int nLengthSize;
FlvStat(): nMetaNum(0), nVideoNum(0), nAudioNum(0), nMaxTimeStamp(0), nLengthSize(0){}
~FlvStat(){}
};
//取4字节数值
static uint32_t ShowU32(uint8_t* pBuf)
{
return (pBuf[0] << 24) | (pBuf[1] << 16) | (pBuf[2] << 8) | pBuf[3];
}
//取3字节数值
static uint32_t ShowU24(uint8_t* pBuf)
{
return (pBuf[0] << 16) | (pBuf[1] << 8) | pBuf[2];
}
//取2字节数值
static uint32_t ShowU16(uint8_t* pBuf)
{
return (pBuf[0] << 8) | pBuf[1];
}
//取1字节数值
static uint32_t ShowU8(uint8_t* pBuf)
{
return pBuf[0];
}
//按位的数据写入到64位中,x 本来的值会往左移(高位移)
//length : 多少位数据
//value : 实际的值
static void WriteU64(uint64_t& x, int length, int value)
{
uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - length);
x = (x << length) | ((uint64_t)value & mask);
}
//字节序替换
static uint32_t WriteU32(uint32_t n)
{
uint32_t nn = 0;
uint8_t *p = (uint8_t*)&n;
uint8_t *pp= (uint8_t*)&nn;
pp[0] = p[3];
pp[1] = p[2];
pp[2] = p[1];
pp[3] = p[0];
return nn;
}
friend class Tag;
private:
FlvHeader* CreateFlvHeader(uint8_t* pBuf);
int DestroyFlvHeader(FlvHeader* pHeader);
Tag* CreateTag(uint8_t* pBuf, int nLeftLen);
int DestroyTag(Tag* pTag);
int Stat();
int StatVideo(Tag* pTag);
int IsUserDataTag(Tag* pTag);
private:
FlvHeader* _pFlvHeader;
vector<Tag*> _vpTag;
FlvStat _sStat;
//Videojj* _vjj;
//h264
int _nNaluUintLength;
};
#endif // FLVPARSER_H
FlvParser.cpp
#include "FlvParser.h"
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
#define CheckBuffer(x) { if((nBufSize - nOffset) < (x)){ nUsedLen = nOffset; return 0;} }
int FlvParser::AudioTag::_aacProfile;
int FlvParser::AudioTag::_sampleRateIndex;
int FlvParser::AudioTag::_channelConfig;
static const uint32_t nH264StartCode = 0x01000000;
FlvParser::FlvParser()
{
_pFlvHeader = NULL;
}
FlvParser::~FlvParser()
{
for(int i = 0; i < _vpTag.size(); i++)
{
DestroyTag(_vpTag[i]);
delete _vpTag[i];
}
}
int FlvParser::Parse(uint8_t *pBuf, int nBufSize,int& nUsedLen)
{
int nOffset = 0;
//初始化flv解析器
if(_pFlvHeader == 0)
{
//CheckBuffer(9);
//如果不够flv header长度就返回
if((nBufSize - nOffset) < 9)
{
nUsedLen = nOffset;
return 0;
}
_pFlvHeader = CreateFlvHeader(pBuf + nOffset);
nOffset += _pFlvHeader->nHeadSize;
}
while (1)
{
//CheckBuffer(15);
if((nBufSize - nOffset) < 15)
{
nUsedLen = nOffset;
return 0;
}
int nPrevSize = ShowU32(pBuf + nOffset);
nOffset += 4;//移过4个字节的PreviousTagSize
Tag* pTag = CreateTag(pBuf + nOffset, nBufSize - nOffset);
if(pTag == NULL)
{
nOffset -= 4;
break;
}
nOffset += (11 + pTag->_header.nDataSize);
_vpTag.push_back(pTag);
}
nUsedLen = nOffset;
return 0;
}
int FlvParser::PrintInfo()
{
Stat();
cout << "vnum: " << _sStat.nVideoNum << " , anum: " << _sStat.nAudioNum << " , mnum: " << _sStat.nMetaNum << endl;
cout << "maxTimeStamp: " << _sStat.nMaxTimeStamp << " ,nLengthSize: " << _sStat.nLengthSize << endl;
return 0;
}
//输出h264文件
int FlvParser::DumpH264(const std::string& path)
{
fstream f;
f.open(path.c_str(), ios_base::out | ios_base::binary);
vector<Tag*>::iterator it_tag;
for(it_tag = _vpTag.begin(); it_tag != _vpTag.end(); it_tag++)
{
if((*it_tag)->_header.nType != 0x09)
continue;
f.write((char*)(*it_tag)->_pMedia, (*it_tag)->_nMediaLen);
}
f.close();
return 1;
}
//输出AAC文件
int FlvParser::DumpAAC(const std::string& path)
{
fstream f;
f.open(path.c_str(), ios_base::out | ios_base::binary);
vector<Tag*>::iterator it_tag;
for(it_tag = _vpTag.begin(); it_tag != _vpTag.end(); it_tag ++)
{
if((*it_tag)->_header.nType != 0x08)
{
continue;
}
AudioTag* pAudioTag = (AudioTag*)(*it_tag);
if(pAudioTag->_nSoundFormat != 10)//不是AAC
continue;
if(pAudioTag->_nMediaLen != 0)
{
f.write((char*)(*it_tag)->_pMedia, (*it_tag)->_nMediaLen);
}
}
f.close();
return 1;
}
//创建保存Flv Header信息
FlvParser::FlvHeader* FlvParser::CreateFlvHeader(uint8_t *pBuf)
{
FlvHeader* pHeader = new FlvHeader;
pHeader->nVersion = pBuf[3]; //版本号
pHeader->bHaveAudio = (pBuf[4] >> 2) & 0x01;//是否有音频
pHeader->bHaveVideo = (pBuf[4] >> 0) & 0x01;//是否有视频
pHeader->nHeadSize = ShowU32(pBuf + 5);// 头部长度
//将原来的flv header 数据保存一份
pHeader->pFlvHeader = new uint8_t[pHeader->nHeadSize];
memcpy(pHeader->pFlvHeader, pBuf, pHeader->nHeadSize);
return pHeader;
}
//释放Flv Header信息相关内存
int FlvParser::DestroyFlvHeader(FlvHeader *pHeader)
{
if(pHeader == NULL)
return 0;
delete pHeader->pFlvHeader;
delete pHeader;
pHeader = NULL;
return 1;
}
int FlvParser::Stat()
{
for(int i = 0; i< _vpTag.size(); i++)
{
switch (_vpTag[i]->_header.nType)
{
case 0x08:
_sStat.nAudioNum++;
break;
case 0x09:
StatVideo(_vpTag[i]);
break;
case 0x12:
_sStat.nMetaNum++;
break;
default:
break;
}
}
return 1;
}
int FlvParser::StatVideo(Tag *pTag)
{
_sStat.nVideoNum++;
_sStat.nMaxTimeStamp = pTag->_header.nTimeStamp;
//0x17 = 帧类型为 1 (h264的IDR 关键帧标识)
// 7 (avc)
//0x00 = AVC 包类型为 0 (AVC sequence header)
if(pTag->_pTagData[0] == 0x17 && pTag->_pTagData[1] == 0x00)
{
//获取nalu 长度使用多少个字节表示
//注意:根据上面知道AVC sequence header包(包含SPS 、PPS)时,
//帧类型是 1 ,是使用h264的IDR 关键帧相同标识的)
_sStat.nLengthSize = (pTag->_pTagData[9] & 0x03) + 1;
}
return 1;
}
//创建Tag
FlvParser::Tag* FlvParser::CreateTag(uint8_t *pBuf, int nLeftLen)
{
//开始解析tag头部
TagHeader header;
header.nType = ShowU8(pBuf + 0);//类型
header.nDataSize = ShowU24(pBuf + 1);//tag body的长度
header.nTimeStamp = ShowU24(pBuf + 4);//时间戳,低24位
header.nTSEx = ShowU8(pBuf + 7);//时间戳扩展字段,高8位
header.nStreamID = ShowU24(pBuf + 8);//流的id
header.nTotalTS = (uint32_t)((header.nTSEx << 24)) + header.nTimeStamp;//合成完整的时间戳
//如果这次数据不够整个tag长度(包括tag header 和 tag body)就不处理
if((header.nDataSize + 11) > nLeftLen)
{
return NULL;
}
Tag* pTag;
switch (header.nType) {
case 0x09://视频类型
pTag = new VideoTag(&header, pBuf, nLeftLen, this);
break;
case 0x08://音频类型
pTag = new AudioTag(&header, pBuf, nLeftLen, this);
break;
case 0x12://script 类型
pTag = new MetaDataTag(&header, pBuf, nLeftLen, this);
break;
default:
pTag = new Tag();
pTag->Init(&header, pBuf, nLeftLen);
break;
}
return pTag;
}
//释放Tag相应的内存
int FlvParser::DestroyTag(Tag* pTag)
{
if(pTag->_pMedia != NULL)
delete[] pTag->_pMedia;
if(pTag->_pTagData != NULL)
delete[] pTag->_pTagData;
if(pTag->_pTagHeader != NULL)
delete[] pTag->_pTagHeader;
return 1;
}
//tag 初始化
void FlvParser::Tag::Init(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen)
{
//复制tag头部信息(解析好的)
memcpy(&_header, pHeader, sizeof(TagHeader));
//复制tag头部信息(原数据)
_pTagHeader = new uint8_t[11];
memcpy(_pTagHeader, pBuf, 11);
//复制tag body
_pTagData = new uint8_t[_header.nDataSize];
memcpy(_pTagData, pBuf + 11, _header.nDataSize);
}
FlvParser::MetaDataTag::MetaDataTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen, FlvParser *pParser)
{
Init(pHeader, pBuf, nLeftLen);
uint8_t* pd = _pTagData;
m_amf1_type = ShowU8(pd);//第一个AMF 包类型一般为2(字符串)
m_amf1_size = ShowU16(pd + 1);//字符串数据的长度
//不是字符串就返回,不处理
if(m_amf1_type != 2)
{
printf("no metadata\n");
return;
}
//判断字符串是否等于onMetaData就进行处理
if(strncmp((const char*)"onMetaData", (const char*)(pd + 3), 10) == 0)
{
parseMeta(pParser);
}
}
//使用字符串的方式提取double类型值,直接将原来的double8个字节,字节序调转一下也一样的
double FlvParser::MetaDataTag::hexStr2double(const unsigned char* hex, const unsigned int length)
{
double ret = 0;
#if 0
char hexstr[length * 2];
memset(hexstr, 0, sizeof(hexstr));
for(uint32_t i = 0; i < length; i++)
{
sprintf(hexstr + i * 2, "%02x", hex[i]);
}
sscanf(hexstr, "%llx", (unsigned long long*)&ret);
#else
ret = *(double*)hex;
uint8_t* ret_begin = (uint8_t*)&ret;
uint8_t* ret_end = ret_begin + 7;
for(int i = 0; i<4; i++)
{
uint8_t temp = *ret_begin;
*ret_begin = *ret_end;
*ret_end = temp;
ret_begin++;
ret_end--;
}
#endif
return ret;
}
int FlvParser::MetaDataTag::parseMeta(FlvParser* pParser)
{
uint8_t* pd = _pTagData;
int dataSize = _header.nDataSize;
uint32_t arrayLen = 0;
//跨过第一个AMF结构,到第二个AFM结构
uint32_t offset = 13;
uint32_t nameLen = 0;
double doubleValue = 0;
string strValue = "";
bool boolValue = false;
uint32_t valueLen =0;
uint8_t u8Value = 0;
//判断类型是否等于8(数组)
if(pd[offset++] == 0x08)
{
//数组元素长度
arrayLen = ShowU32(pd + offset);
offset += 4;//跨过数组长度占用的4个字节
cout<<"MetaData ArrayLen = " << arrayLen << endl;
}
else
{
cout<<"MetaData format error!" <<endl;
return -1;
}
for(uint32_t i = 0; i < arrayLen; i++)
{
doubleValue = 0;
boolValue = false;
strValue = "";
//读取字段名称的长度
nameLen = ShowU16(pd + offset);
offset += 2;
char name[nameLen + 1];//字段存储
memset(name, 0, sizeof(name));
//复制字段名称
memcpy(name, &pd[offset], nameLen);
offset += nameLen;
//获取AFM类型
uint8_t amfType = pd[offset++];
switch (amfType) {
case 0x0://double 8字节
doubleValue = hexStr2double(&pd[offset], 8);
offset += 8;
break;
case 0x1: //bool 1个字节
u8Value = ShowU8(pd + offset);
offset += 1;
if(u8Value != 0)
boolValue = true;
else
boolValue = false;
break;
case 0x2://字符串
valueLen = ShowU16(pd + offset);
offset += 2;
strValue.append(pd + offset, pd + offset + valueLen);
strValue.append("");
offset += valueLen;
break;
default:
printf("un handle amfType:%d\n", amfType);
break;
}
//保存相应的参数值
if(strncmp(name, "duration", 8) == 0)
{
m_duration = doubleValue;
}
else if(strncmp(name, "width", 5) == 0)
{
m_width = doubleValue;
}
else if(strncmp(name, "height", 6) == 0)
{
m_height = doubleValue;
}
else if(strncmp(name, "videodatarate", 13) == 0)
{
m_videodatarate = doubleValue;
}
else if(strncmp(name, "framerate", 9) == 0)
{
m_framerate = doubleValue;
}
else if(strncmp(name, "videocodecid", 12) == 0)
{
m_videocodecid = doubleValue;
}
else if(strncmp(name, "audiodatarate", 13) == 0)
{
m_audiodatarate = doubleValue;
}
else if(strncmp(name, "audiosamplerate", 15) == 0)
{
m_audiosamplerate = doubleValue;
}
else if(strncmp(name, "audiosamplesize", 15) == 0)
{
m_audiosamplesize = doubleValue;
}
else if(strncmp(name, "stereo", 6) == 0)
{
m_stereo = boolValue;
}
else if(strncmp(name, "audiocodecid", 12) == 0)
{
m_audiocodecid = doubleValue;
}
else if(strncmp(name, "major_brand", 11) == 0)
{
m_major_brand = strValue;
}
else if(strncmp(name, "minor_version", 13) == 0)
{
m_minor_version = strValue;
}
else if(strncmp(name, "compatible_brands", 17) == 0)
{
m_compatible_brands = strValue;
}
else if(strncmp(name, "encoder", 7) == 0)
{
m_encoder = strValue;
}
else if(strncmp(name, "filesize", 8) == 0)
{
m_filesize = doubleValue;
}
}
printMeta();
return 1;
}
void FlvParser::MetaDataTag::printMeta()
{
printf("\nduration: %0.2lfs, filesize: %.0lfbytes\n", m_duration, m_filesize);
printf("width: %0.0lf, height: %0.0lf\n", m_width, m_height);
printf("videodatarate: %0.2lfkbps, framerate: %0.0lffps\n", m_videodatarate, m_framerate);
printf("videocodecid: %0.0lf\n", m_videocodecid);
printf("audiodatarate: %0.2lfkbps, audiosamplerate: %0.0lfKhz\n",
m_audiodatarate, m_audiosamplerate);
printf("audiosamplesize: %0.0lfbit, stereo: %d\n", m_audiosamplesize, m_stereo);
printf("audiocodecid: %0.0lf\n", m_audiocodecid);
printf("major_brand: %s, minor_version: %s\n", m_major_brand.c_str(), m_minor_version.c_str());
printf("compatible_brands: %s, encoder: %s\n\n", m_compatible_brands.c_str(), m_encoder.c_str());
}
FlvParser::AudioTag::AudioTag(TagHeader* pHeader, uint8_t* pBuf, int nLeftLen, FlvParser* pParser)
{
Init(pHeader, pBuf, nLeftLen);
uint8_t *pd = _pTagData;
_nSoundFormat = (pd[0] & 0xf0) >> 4;//音频格式 如:AAC
_nSoundRate = (pd[0] & 0x0c) >> 2;//采样率
_nSoundSize = (pd[0] & 0x02) >> 1;//采样精度
_nSoundType = (pd[0] & 0x01);//是否立体声
if(_nSoundFormat == 10)//AAC
{
ParseAACTag(pParser);
}
}
int FlvParser::AudioTag::ParseAACTag(FlvParser *pParser)
{
uint8_t* pd = _pTagData;
//数据包的类型:音频配置信息,音频数据
int nAACPacketType = pd[1];
//AAC sequence header
if(nAACPacketType == 0)
{
ParseAudioSpecificConfig(pParser, pd);
}
//AAC 数据(AAC RAW)
else if(nAACPacketType == 1)
{
ParserRawAAC(pParser, pd);
}
else
{
cout<<"ParseAACTag nAACPacketType = "<< nAACPacketType << endl;
}
return 1;
}
int FlvParser::AudioTag::ParseAudioSpecificConfig(FlvParser* pParser, uint8_t *pTagData)
{
uint8_t* pd = _pTagData;
_aacProfile = ((pd[2] & 0xf8) >> 3);//5位 AAC 编码级别
_sampleRateIndex = ((pd[2] & 0x07) << 1) | (pd[3] >> 7);//4bit 真正采样率索引
_channelConfig = (pd[3] >> 3) & 0x0f; //4bit 通道数量
printf("----- AAC info------\n");
printf("profile:%d\n", _aacProfile);
printf("sample rate index:%d\n", _sampleRateIndex);
printf("channel config:%d\n", _channelConfig);
_pMedia = NULL;
_nMediaLen = 0;
return 0;
}
int FlvParser::AudioTag::ParserRawAAC(FlvParser* pParser, uint8_t* pTagData)
{
uint64_t bits = 0;
//数据长度,跳过tag data的第一个第二个字节
int dataSize = _header.nDataSize - 2;
//制作 AAC ADTS
WriteU64(bits, 12, 0xFFF);
WriteU64(bits, 1, 0);
WriteU64(bits, 2, 0);
WriteU64(bits, 1, 1);
WriteU64(bits, 2, _aacProfile - 1);
WriteU64(bits, 4, _sampleRateIndex);
WriteU64(bits, 1, 0);
WriteU64(bits, 3, _channelConfig);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 13, 7 + dataSize);
WriteU64(bits, 11, 0x7FF);
WriteU64(bits, 2, 0);
//
_nMediaLen = 7 + dataSize;
_pMedia = new uint8_t[_nMediaLen];
uint8_t p64[8];
//调转字节序
p64[0] = (uint8_t)(bits >> 56);//0,没用数据
p64[1] = (uint8_t)(bits >> 48);//ADTS 头的0xfff开始位置
p64[2] = (uint8_t)(bits >> 40);
p64[3] = (uint8_t)(bits >> 32);
p64[4] = (uint8_t)(bits >> 24);
p64[5] = (uint8_t)(bits >> 16);
p64[6] = (uint8_t)(bits >> 8);
p64[7] = (uint8_t)(bits);
//ADTS header,从p64 + 1 开始的
memcpy(_pMedia, p64 + 1, 7);
//AAC RAW 从 audio tag data的第3个字节开始的
memcpy(_pMedia + 7, pTagData + 2, dataSize);
return 1;
}
//VideoTag构造
FlvParser::VideoTag::VideoTag(TagHeader* pHeader, uint8_t* pBuf, int nLeftLen, FlvParser* pParser)
{
//初始化
Init(pHeader, pBuf, nLeftLen);
uint8_t *pd = _pTagData;
_nFrameType = (pd[0] & 0xf0) >> 4;//帧类型 (HDR / 普通帧)
_nCodecID = pd[0] & 0x0f;//视频编码类型(avc)
//开始解析 (视频类型 的tag 、 avc 编码类型)
if(_header.nType == 0x09 && _nCodecID == 7)
{
ParseH264Tag(pParser);
}
}
//解析h264
FlvParser::VideoTag::ParseH264Tag(FlvParser *pParser)
{
uint8_t* pd = _pTagData;
int nAVCPacketType = pd[1];
int nCompositionTime = FlvParser::ShowU24(pd + 2);
//视频配置信息(sps、pps)
if(nAVCPacketType == 0)
{
ParseH264Configuration(pParser, pd);
}
//视频数据
else if(nAVCPacketType == 1)
{
ParseNalu(pParser, pd);
}
else
{
cout<<"Unknow ParseH264Tag nAVCPacketType = "<< nAVCPacketType << endl;
}
return 1;
}
FlvParser::VideoTag::ParseH264Configuration(FlvParser *pParser, uint8_t *pTagData)
{
uint8_t* pd = pTagData;
//获取nalu长度使用多少个字节进行存储
pParser->_nNaluUintLength = (pd[9] & 0x03) + 1;
int sps_size, pps_size;
//sps(序列参数集)的长度
sps_size = FlvParser::ShowU16(pd + 11);
//pps(图像参数集)的长度
pps_size = FlvParser::ShowU16(pd + 11 + (2 + sps_size) + 1);
//制作元数据(4表示start code)
_nMediaLen = 4 + sps_size + 4 + pps_size;
_pMedia = new uint8_t[_nMediaLen];
memcpy(_pMedia, &nH264StartCode, 4);
memcpy(_pMedia + 4, pd + 11 + 2, sps_size);
memcpy(_pMedia + 4 + sps_size, &nH264StartCode, 4);
memcpy(_pMedia + 4 + sps_size + 4, pd + 11 + 2 + sps_size + 2 + 1, pps_size);
return 1;
}
FlvParser::VideoTag::ParseNalu(FlvParser *pParser, uint8_t *pTagData)
{
uint8_t* pd = pTagData;
int nOffset = 0;
_pMedia = new uint8_t[_header.nDataSize + 10];
_nMediaLen = 0;
nOffset = 5;
while (1)
{
//如果解析完了一个TAG,就跳出循环
if(nOffset >= _header.nDataSize)
break;
//计算nalu的长度
//一个tag可能包含多个nalu,每个nalu前面都有NalUnitLength字节表示每个nalu的长度
int nNaluLen;
switch (pParser->_nNaluUintLength)
{
case 4:
nNaluLen = FlvParser::ShowU32(pd + nOffset);
break;
case 3:
nNaluLen = FlvParser::ShowU24(pd + nOffset);
break;
case 2:
nNaluLen = FlvParser::ShowU16(pd + nOffset);
break;
default:
nNaluLen = FlvParser::ShowU8(pd + nOffset);
break;
}
//添加nalu start code
memcpy(_pMedia + _nMediaLen, &nH264StartCode, 4);
//复制nalu数据
memcpy(_pMedia + _nMediaLen + 4, pd + nOffset + pParser->_nNaluUintLength, nNaluLen);
_nMediaLen += (4 + nNaluLen);
nOffset += (pParser->_nNaluUintLength + nNaluLen);
}
}