LION-jiejie преди 1 седмица
ревизия
ac0ac394af
променени са 5 файла, в които са добавени 792 реда и са изтрити 0 реда
  1. 2 0
      .gitignore
  2. 11 0
      CMakeLists.txt
  3. 532 0
      FlvParser.cc
  4. 182 0
      FlvParser.h
  5. 65 0
      main.cc

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+build/
+.cache/

+ 11 - 0
CMakeLists.txt

@@ -0,0 +1,11 @@
+
+cmake_minimum_required(VERSION 3.10)
+project(flvparser)
+
+set(CMAKE_CXX_STANDARD 17)
+
+# 添加你的源码
+add_executable(flvparser main.cc FlvParser.cc)
+
+# 如果有头文件路径,添加 include
+# target_include_directories(my_app PRIVATE ${CMAKE_SOURCE_DIR}/)

+ 532 - 0
FlvParser.cc

@@ -0,0 +1,532 @@
+#include "FlvParser.h"
+
+#include <stdlib.h>
+
+#include <fstream>
+#include <iostream>
+
+int FlvParser::AudioTag::_aacProfile;
+int FlvParser::AudioTag::_sampleRateIndex;
+int FlvParser::AudioTag::_channelConfig;
+
+static int nH264StartCode = 0x01000000;
+#define CheckBuf(x)                  \
+    {                                \
+        if (nBufLen - nOffset < x) { \
+            nUsedLen = nOffset;      \
+            return 0;                \
+        }                            \
+    }
+
+FlvParser::FlvParser() { _pFlvHeader = nullptr; }
+
+FlvParser::~FlvParser() {
+    for (int i = 0; i < _vpTag.size(); i++) {
+        DestroyTag(_vpTag[i]);
+        delete _vpTag[i];
+    }
+}
+
+int FlvParser::Parse(uint8_t* pBuf, int nBufLen, int& nUsedLen) {
+    int nOffset = 0;
+
+    if (_pFlvHeader == nullptr) {
+        CheckBuf(9);
+        _pFlvHeader = CreateHeader(pBuf + nOffset);
+        nOffset += _pFlvHeader->nHeaderSize;
+    }
+
+    while (1) {
+        CheckBuf(15);
+
+        int nPrevSize = SolveU32(pBuf + nOffset);
+        nOffset += 4;
+        Tag* tag = CreateTag(pBuf + nOffset, nBufLen - nOffset);
+
+        if (tag == nullptr) {
+            nOffset -= 4;
+            break;
+        }
+
+        nOffset += (11 + tag->_header.nDataSize);
+        _vpTag.push_back(tag);
+    }
+
+    nUsedLen = nOffset;
+
+    return 0;
+}
+
+FlvParser::FlvHeader* FlvParser::CreateHeader(uint8_t* pBuf) {
+    FlvHeader* pHeader = new FlvHeader;
+
+    pHeader->nVersion = pBuf[3];
+    pHeader->bHaveAudio = (pBuf[4] >> 2) & 0x01;
+    pHeader->bHaveVideo = (pBuf[4] >> 0) & 0x01;
+    pHeader->nHeaderSize = SolveU32(pBuf + 5);
+    pHeader->pFlvHeader = new uint8_t[pHeader->nHeaderSize];
+
+    memset(pHeader->pFlvHeader, 0, pHeader->nHeaderSize);
+    memcpy(pHeader->pFlvHeader, pBuf, pHeader->nHeaderSize);
+
+    return pHeader;
+}
+
+void FlvParser::DestroyHeader(FlvParser::FlvHeader* pHeader) {
+    if (pHeader) {
+        if (pHeader->pFlvHeader) {
+            delete pHeader->pFlvHeader;
+        }
+    }
+}
+
+void FlvParser::Tag::Init(TagHeader* pHeader, uint8_t* pBuf, int nLeftLen) {
+    memcpy(&_header, pHeader, sizeof(TagHeader));
+    _pTagHeader = new uint8_t[11];
+    memcpy(_pTagHeader, pBuf, 11);
+
+    _pTagData = new uint8_t[pHeader->nDataSize];
+    memcpy(_pTagData, pBuf + 11, pHeader->nDataSize);
+}
+
+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;
+    _nCodecType = (pd[0] & 0x0f) >> 0;
+
+    if (_header.nTagType == 0x09 && _nCodecType == 7) {
+        ParseH264Tag(pParser);
+    }
+}
+
+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;
+    _nSoundRate = (pd[0] & 0x0c) >> 2;
+    _nSoundSize = (pd[0] & 0x02) >> 1;
+    _nSoundType = (pd[0] & 0x01) >> 0;
+
+    if (_nSoundFormat == 10) {
+        ParseAACTag(pParser);
+    }
+}
+
+int FlvParser::AudioTag::ParseAACTag(FlvParser* pParser) {
+    uint8_t* pd = _pTagData;
+
+    int nAACPacketType = pd[1];
+
+    if (nAACPacketType == 0) {
+        ParseAudioSpecificConfig(pParser, pd);
+    } else if (nAACPacketType == 1) {
+        ParseAACRaw(pParser, pd);
+    } else {
+    }
+
+    return 0;
+}
+
+int FlvParser::AudioTag::ParseAudioSpecificConfig(FlvParser* pParser,
+                                                  uint8_t* pTagData) {
+    uint8_t* pd = pTagData;
+
+    _aacProfile = (pd[2] & 0xf8) >> 3;
+    _sampleRateIndex = ((pd[2] & 0x07) << 1 | (pd[3] >> 7));
+    _channelConfig = (pd[3] >> 3) & 0x0f;
+
+    printf("-----AAC-----\n");
+    printf("aacProfile:%d\n", _aacProfile);
+    printf("sampleRateIndex:%d\n", _sampleRateIndex);
+    printf("channelConfig:%d\n", _channelConfig);
+
+    _pMedia = nullptr;
+    _nMediaLen = 0;
+
+    return 0;
+}
+
+int FlvParser::AudioTag::ParseAACRaw(FlvParser* pParser, uint8_t* pTagData) {
+    uint64_t bits = 0;
+    int datasize = _header.nDataSize - 2;
+
+    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, datasize + 7);
+    WriteU64(bits, 11, 0x7FF);
+    WriteU64(bits, 2, 0);
+
+    _nMediaLen = datasize + 7;
+    _pMedia = new uint8_t[_nMediaLen];
+
+    uint8_t p64[8] = {0};
+
+    for (size_t i = 0; i < 8; i++) {
+        p64[i] = bits >> (64 - 8 * (i + 1));
+    }
+
+    memcpy(_pMedia, p64 + 1, 7);
+    memcpy(_pMedia + 7, pTagData + 2, datasize);
+}
+
+FlvParser::Tag* FlvParser::CreateTag(uint8_t* pBuf, int nLeftLen) {
+    TagHeader* header;
+    header->nTagType = SolveU8(pBuf);
+    header->nDataSize = SolveU24(pBuf + 1);
+    header->nTimeSamp = SolveU24(pBuf + 4);
+    header->nTimeSampExt = SolveU8(pBuf + 7);
+    header->nStreamID = SolveU24(pBuf + 8);
+    header->nTotalTS =
+        (uint32_t)(header->nTimeSampExt << 24) + header->nTimeSamp;
+
+    if ((header->nDataSize + 11) < nLeftLen) {
+        return nullptr;
+    }
+
+    Tag* pTag;
+
+    switch (header->nTagType) {
+        case 0x08:
+            // video
+            pTag = new VideoTag(header, pBuf, nLeftLen, this);
+            break;
+        case 0x09:
+            // audio
+            pTag = new AudioTag(header, pBuf, nLeftLen, this);
+            break;
+        case 0x12:
+            // script
+        default:
+            pTag = new Tag();
+            pTag->Init(header, pBuf, nLeftLen);
+            break;
+    }
+
+    return pTag;
+}
+
+void FlvParser::DestroyTag(Tag* pTag) {
+    if (pTag->_pTagHeader) delete[] pTag->_pTagHeader;
+    if (pTag->_pMedia) delete[] pTag->_pMedia;
+    if (pTag->_pTagData) delete[] pTag->_pTagData;
+}
+
+int FlvParser::VideoTag::ParseH264Tag(FlvParser* pParser) {
+    uint8_t* pd = _pTagData;
+
+    int nAVCPacketType = pd[1];
+
+    int nCompositionTime = SolveU24(pd + 2);
+
+    if (nAVCPacketType == 0) {
+        ParseH264Configuration(pParser, pd);
+    } else if (nAVCPacketType == 1) {
+        ParseNalu(pParser, pd);
+    }
+
+    return 0;
+}
+
+int FlvParser::VideoTag::ParseH264Configuration(FlvParser* pParser,
+                                                uint8_t* pTagData) {
+    uint8_t* pd = pTagData;
+
+    pParser->_nNaluUnitLength = (pd[9] & 0x03) + 1;
+
+    int pps_size, sps_size;
+
+    sps_size = SolveU16(pd + 11);
+
+    pps_size = SolveU16(pd + 11 + 2 + (1 + sps_size) + 1);
+
+    _nMediaLen = 4 + sps_size + 4 + pps_size;
+    _pMedia = new uint8_t[_nMediaLen];
+
+    memset(_pMedia, 0, _nMediaLen);
+
+    memcpy(_pMedia, &nH264StartCode, 4);
+    memcpy(_pMedia + 4, pd + 11 + 2, sps_size);
+    memcpy(_pMedia + 4 + sps_size, &nH264StartCode, 4);
+    memcpy(_pMedia + 8 + sps_size, pd + 11 + 2 + sps_size + 1 + 2, pps_size);
+
+    return 0;
+}
+
+int FlvParser::VideoTag::ParseNalu(FlvParser* pParser, uint8_t* pTagData) {
+    uint8_t* pd = pTagData;
+
+    int nOffset = 0;
+
+    _nMediaLen = 0;
+    _pMedia = new uint8_t[_header.nDataSize + 10];
+
+    nOffset = 5;
+
+    while (1) {
+        if (nOffset >= _header.nDataSize) break;
+
+        int nNaluLen = 0;
+
+        switch (pParser->_nNaluUnitLength) {
+            case 4:
+                nNaluLen = SolveU32(pd + nOffset);
+                break;
+            case 3:
+                nNaluLen = SolveU24(pd + nOffset);
+                break;
+            case 2:
+                nNaluLen = SolveU16(pd + nOffset);
+                break;
+            default:
+                nNaluLen = SolveU8(pd + nOffset);
+                break;
+        }
+
+        memcpy(_pMedia + _nMediaLen, &nH264StartCode, 4);
+        memcpy(_pMedia + _nMediaLen + 4,
+               pd + nOffset + pParser->_nNaluUnitLength, nNaluLen);
+        nOffset += (nNaluLen + pParser->_nNaluUnitLength);
+        _nMediaLen += (4 + nNaluLen);
+    }
+
+    return 0;
+}
+
+int FlvParser::DumpH264(const std::string filepath) {
+    std::fstream fout;
+    fout.open(filepath.c_str(), std::ios_base::out | std::ios_base::binary);
+
+    if (fout) {
+        std::vector<Tag*>::iterator it_tag;
+        it_tag = _vpTag.begin();
+
+        for (it_tag; it_tag != _vpTag.end(); it_tag++) {
+            if ((*it_tag)->_header.nTagType != 0x09) continue;
+
+            fout.write((char*)(*it_tag)->_pMedia, (*it_tag)->_nMediaLen);
+        }
+    }
+
+    fout.close();
+
+    return 0;
+}
+
+int FlvParser::DumpAAC(const std::string filepath) {
+    std::fstream fout;
+    fout.open(filepath.c_str(), std::ios_base::out | std::ios_base::binary);
+
+    if (fout) {
+        std::vector<Tag*>::iterator it_tag;
+        it_tag = _vpTag.begin();
+
+        for (it_tag; it_tag != _vpTag.end(); it_tag++) {
+            if ((*it_tag)->_header.nTagType != 0x08) continue;
+
+            AudioTag* ad_tag = (AudioTag*)(*it_tag);
+            if (ad_tag->_nSoundFormat != 10) continue;
+
+            if (ad_tag->_nMediaLen == 0) continue;
+
+            fout.write((char*)(*it_tag)->_pMedia, (*it_tag)->_nMediaLen);
+        }
+    }
+
+    fout.close();
+
+    return 0;
+}
+
+int FlvParser::DumpFlv(const std::string filepath) {}
+
+void FlvParser::SetStat() {
+    for (size_t i = 0; i < _vpTag.size(); i++) {
+        switch (_vpTag[i]->_header.nTagType) {
+            case 0x08:
+                _sStat.nAudioNum++;
+                break;
+            case 0x09:
+                SetVideoStat(_vpTag[i]);
+                break;
+            case 0x12:
+                _sStat.nMetaNum++;
+                break;
+        }
+    }
+}
+
+void FlvParser::SetVideoStat(Tag* pTag) {
+    _sStat.nVideoNum++;
+    _sStat.nMaxTimeStamp = pTag->_header.nTimeSamp;
+
+    if (pTag->_pTagData[0] == 0x17 && pTag->_pTagData[1] == 0x00) {
+        _sStat.nLengthSize = (pTag->_pTagData[9] & 0x03) + 1;
+    }
+}
+
+int FlvParser::MetaTag::parseMeta(FlvParser* pParser) {
+    uint8_t* pd = _pTagData;
+    int dataSize = _header.nDataSize;
+
+    uint32_t arrayLen = 0;
+    uint32_t offset = 13;  // Type + Value_Size + Value占用13字节
+
+    uint32_t nameLen = 0;
+    double doubleValue = 0;
+    std::string strValue = "";
+    bool boolValue = false;
+    uint32_t valueLen = 0;
+    uint8_t u8Value = 0;
+    if (pd[offset++] == 0x08)  // 0x8 onMetaData
+    {
+        arrayLen = SolveU32(pd + offset);
+        offset += 4;  // 跳过 [ECMAArrayLength]占用的字节
+        printf("ArrayLen = %d\n", arrayLen);
+    } else {
+        printf("metadata format error!!!");
+        return -1;
+    }
+
+    for (uint32_t i = 0; i < arrayLen; i++) {
+        doubleValue = 0;
+        boolValue = false;
+        strValue = "";
+        // 读取字段长度
+        nameLen = SolveU16(pd + offset);
+        offset += 2;  // 跳过2字节字段长度
+
+        char name[nameLen + 1];  // 获取字段名称
+
+        memset(name, 0, sizeof(name));
+        memcpy(name, &pd[offset], nameLen);
+        name[nameLen + 1] = '\0';
+        offset += nameLen;  // 跳过字段名占用的长度
+
+        uint8_t amfType = pd[offset++];
+        switch (amfType)  // 判别值的类型
+        {
+            case 0x0:  // Number type, 就是double类型, 占用8字节
+                doubleValue = hexStr2Double(&pd[offset], 8);
+                offset += 8;  // 跳过8字节
+                break;
+
+            case 0x1:  // Boolean type, 占用1字节
+                u8Value = SolveU8(pd + offset);
+                offset += 1;  // 跳过1字节
+                if (u8Value != 0x00)
+                    boolValue = true;
+                else
+                    boolValue = false;
+                break;
+
+            case 0x2:  // String type
+                valueLen = SolveU16(pd + offset);
+                offset += 2;  // 跳过2字节 length
+                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_brand = 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::MetaTag::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_brand.c_str(),
+           m_encoder.c_str());
+}
+
+double FlvParser::MetaTag::hexStr2Double(const unsigned char* hex,
+                                         const unsigned int length) {
+    double ret = 0;
+    char hexstr[length * 2];
+    memset(hexstr, 0, length * 2);
+
+    for (int i = 0; i < length; i++) {
+        std::sprintf(hexstr + i * 2, "%02x", hex[i]);
+    }
+
+    sscanf(hexstr, "%llx", (unsigned long long*)&ret);
+
+    return ret;
+}
+
+void FlvParser::PrintInfo() {
+    SetStat();
+
+    std::cout << "vnum:" << _sStat.nVideoNum << ",anum:" << _sStat.nAudioNum
+              << std::endl;
+    std::cout << "maxTimeStamp:" << _sStat.nMaxTimeStamp
+              << ",nLengthSize:" << _sStat.nLengthSize << std::endl;
+}

+ 182 - 0
FlvParser.h

@@ -0,0 +1,182 @@
+#ifndef FLVPARSER_H
+#define FLVPARSER_H
+#include <stdint.h>
+#include <stdio.h>
+
+#include <cstdint>
+#include <iostream>
+
+class FlvParser {
+   public:
+    FlvParser();
+    virtual ~FlvParser();
+
+    int Parse(uint8_t *pBuf, int nBufLen, int &nUsedLen);
+    int DumpH264(const std::string filepath);
+    int DumpAAC(const std::string filepath);
+    int DumpFlv(const std::string filepath);
+
+   private:
+    struct FlvHeader {
+        int nVersion;
+        int bHaveAudio;
+        int bHaveVideo;
+        int nHeaderSize;
+
+        uint8_t *pFlvHeader;
+    };
+    typedef struct FlvHeader *pFlvHeader;
+
+    struct TagHeader {
+        int nTagType;
+        int nDataSize;
+        int nTimeSamp;
+        int nTimeSampExt;
+        int nStreamID;
+
+        uint32_t nTotalTS;
+
+        TagHeader()
+            : nTagType(0),
+              nDataSize(0),
+              nTimeSamp(0),
+              nTimeSampExt(0),
+              nStreamID(0) {};
+        ~TagHeader() {};
+    };
+    class Tag {
+       public:
+        Tag() : _pTagData(nullptr), _pTagHeader(nullptr), _pMedia(nullptr) {}
+        void Init(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen);
+
+        TagHeader _header;
+        uint8_t *_pTagHeader;
+        uint8_t *_pTagData;
+        uint8_t *_pMedia;
+        int _nMediaLen;
+    };
+
+    class VideoTag : public Tag {
+       public:
+        VideoTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen,
+                 FlvParser *pParser);
+        int _nFrameType;
+        int _nCodecType;
+        int ParseH264Tag(FlvParser *pParser);
+        int ParseH264Configuration(FlvParser *pParser, uint8_t *pTagData);
+        int ParseNalu(FlvParser *pParser, uint8_t *pTagData);
+    };
+    class AudioTag : public Tag {
+       public:
+        AudioTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen,
+                 FlvParser *pParser);
+
+        int _nSoundType;
+        int _nSoundRate;
+        int _nSoundSize;
+        int _nSoundFormat;
+
+        static int _aacProfile;
+        static int _sampleRateIndex;
+        static int _channelConfig;
+
+        int ParseAACTag(FlvParser *pParser);
+        int ParseAudioSpecificConfig(FlvParser *pParser, uint8_t *pTagData);
+        int ParseAACRaw(FlvParser *pParser, uint8_t *pTagData);
+    };
+    class MetaTag : public Tag {
+       public:
+        MetaTag(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();
+
+        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;  // 视频码率(kbps)
+        double m_framerate;      // 视频帧率
+        double m_videocodecid;   // 视频编码格式编号
+
+        double m_audiodatarate;    // 音频码率
+        double m_audiosamplerate;  // 音频采样率
+        double m_audiosamplesize;  // 音频采样位数(通常是16bit)
+        bool m_stereo;             // 是否立体声(多声道)
+        double m_audiocodecid;     // 音频编码格式
+                                   //
+        std::string m_major_brand;
+        std::string m_minor_version;
+        std::string m_compatible_brand;
+        std::string m_encoder;
+
+        double m_filesize;
+    };
+    struct FlvStat {
+        int nMetaNum;
+        int nVideoNum;
+        int nAudioNum;
+        int nMaxTimeStamp;
+        int nLengthSize;
+
+        FlvStat()
+            : nMetaNum(0),
+              nVideoNum(0),
+              nAudioNum(0),
+              nMaxTimeStamp(0),
+              nLengthSize(0) {}
+        ~FlvStat() {};
+    };
+
+    void SetStat();
+    void SetVideoStat(Tag *pTag);
+
+    friend class Tag;
+
+   public:
+    static uint32_t SolveU32(uint8_t *pBuf) {
+        return (pBuf[0] << 24 | pBuf[1] << 16 | pBuf[2] << 8 | pBuf[3]);
+    }
+
+    static uint32_t SolveU24(uint8_t *pBuf) {
+        return (pBuf[0] << 16 | pBuf[1] << 8 | pBuf[0]);
+    }
+
+    static u_int32_t SolveU16(uint8_t *pBuf) {
+        return (pBuf[0] << 8 | pBuf[1]);
+    }
+
+    static uint32_t SolveU8(uint8_t *pBuf) { return (pBuf[0]); }
+
+    static void WriteU64(uint64_t &x, int length, int value) {
+        uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - length);
+        x = (x << length) | ((uint64_t)value & mask);
+    }
+
+    void PrintInfo();
+
+   private:
+    FlvParser::FlvHeader *CreateHeader(uint8_t *pBuf);
+    void DestroyHeader(FlvHeader *pHeader);
+    Tag *CreateTag(uint8_t *pBuf, int nLeftSize);
+    void DestroyTag(Tag *pTag);
+
+   private:
+    FlvHeader *_pFlvHeader;
+    std::vector<Tag *> _vpTag;
+    FlvStat _sStat;
+
+    int _nNaluUnitLength;
+};
+
+#endif  // !FLVPARSER_H

+ 65 - 0
main.cc

@@ -0,0 +1,65 @@
+#include <fstream>
+#include <iostream>
+
+#include "FlvParser.h"
+
+void Process(std::fstream &fin, char *filename);
+
+int main(int argc, char *argv[]) {
+    if (argc < 3) {
+        printf("flvparser [input file] [output file]\n");
+
+        return -1;
+    }
+
+    std::fstream fin;
+    fin.open(argv[1], std::ios_base::in | std::ios_base::binary);
+
+    if (!fin) {
+        std::cout << "fstream init error" << std::endl;
+        return -1;
+    }
+
+    Process(fin, argv[1]);
+
+    fin.close();
+
+    return 0;
+}
+
+void Process(std::fstream &fin, char *filename) {
+    FlvParser pParser;
+
+    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;
+
+        pParser.Parse(pBuf + nFlvPos, nReadNum, nUsedLen);
+        nFlvPos += nReadNum;
+
+        if (nUsedLen != nFlvPos) {
+            memcpy(pBak, pBuf + nUsedLen, nFlvPos - nUsedLen);
+            memcpy(pBuf, pBak, nFlvPos - nUsedLen);
+        }
+
+        nFlvPos -= nUsedLen;
+    }
+
+    pParser.DumpH264("parser.h264");
+    pParser.DumpAAC("parser.aac");
+    pParser.DumpFlv("parser.flv");
+
+    delete[] pBuf;
+    delete[] pBak;
+}