总的流程
了解了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.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;
- }