总的流程
了解了FLV的封装原理,我们通过一个简单的FLV解析器的例子来看看FLV到底是怎么样封装/解封装的
该FLV的地址:功能强大的 FLV 文件分析和解析器
main函数
流程:
1、读取输入文件(flv类型的视频文件)
2、调用Process进行处理
3、退出
int main(int argc, char *argv[])
{
cout << "Hi, this is FLV parser test program!\n";
if (argc != 3)
{
cout << "FlvParser.exe [input flv] [output flv]" << endl;
return 0;
}
fstream fin;
fin.open(argv[1], ios_base::in | ios_base::binary);
if (!fin)
return 0;
Process(fin, argv[2]);
fin.close();
return 1;
}
处理函数Process
流程:
1、读取文件
2、开始解析
3、打印解析信息
4、把解析之后的数据输出到另外一个文件中
void Process(fstream &fin, const char *filename)
{
CFlvParser parser;
int nBufSize = 2000 * 1024;
int nFlvPos = 0;
unsigned char *pBuf, *pBak;
pBuf = new unsigned char[nBufSize];
pBak = new unsigned char[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);
if (nFlvPos != nUsedLen)
{
memcpy(pBak, pBuf + nUsedLen, nFlvPos - nUsedLen);
memcpy(pBuf, pBak, nFlvPos - nUsedLen);
}
nFlvPos -= nUsedLen;
}
parser.PrintInfo();
/*parser.DumpH264("parser.264");
parser.DumpAAC("parser.aac");*/
//dump into flv
parser.DumpFlv(filename);
delete []pBak;
delete []pBuf;
}
解析函数
流程:
1、解析flv的头部
2、解析flv的Tag
int CFlvParser::Parse(unsigned char *pBuf, int nBufSize, int &nUsedLen)
{
int nOffset = 0;
if (_pFlvHeader == 0)
{
CheckBuffer(9);
_pFlvHeader = CreateFlvHeader(pBuf+nOffset);
nOffset += _pFlvHeader->nHeadSize;
}
while (1)
{
CheckBuffer(15);
int nPrevSize = ShowU32(pBuf + nOffset);
nOffset += 4;
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;
}