分析一下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 bodyuint8_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 profilestatic 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;//h264int _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个字节的PreviousTagSizeTag* 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)//不是AACcontinue;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);//流的idheader.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 0char 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);
#elseret = *(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--;}#endifreturn 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;elseboolValue = 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 headerif(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 ADTSWriteU64(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 codememcpy(_pMedia + _nMediaLen, &nH264StartCode, 4);//复制nalu数据memcpy(_pMedia + _nMediaLen + 4, pd + nOffset + pParser->_nNaluUintLength, nNaluLen);_nMediaLen += (4 + nNaluLen);nOffset += (pParser->_nNaluUintLength + nNaluLen);}
}