#include #include #include #include #include #include #include #include namespace flv { #pragma pack(push, 1) struct FLVHeader { FLVHeader() { memcpy(magic, "FLV", 3); version = 1; #ifdef SINGLE_FLAG // flag = 0; #else dataOffset = 9; _reserved = 0; _typeFlagsReserved = 0; typeFlagsVideo = 0; typeFlagsAudio = 0; #endif } char magic[3]; uint8_t version; #ifdef SINGLE_FLAG uint8_t flag; #else uint8_t typeFlagsVideo : 1; uint8_t _typeFlagsReserved : 1; uint8_t typeFlagsAudio : 1; uint8_t _reserved : 5; #endif uint32_t dataOffset; }; struct TagHeader { uint8_t tagType; uint8_t dataSize[3]; uint8_t timestamp[4]; uint8_t streamId[3]; }; #pragma pack(pop) static_assert(sizeof(FLVHeader) == 9, "sizeof(FLVHeader) MUST be 9 bytes"); class Parser { public: Parser(const char *filepath) { if (openFile(filepath)) { _m_flv_hdr = parseHeader(); if (_m_flv_hdr) { parseBody(); } } else { std::cout << "openFile [" << filepath << "] failed." << std::endl; } } bool ok() { return _m_ifs.is_open() && _m_flv_hdr.has_value(); } std::string toString() const { if (!_m_flv_hdr) { return "Invalid FLV"; } std::stringstream ss; ss << "VideoFlag: " << (_m_flv_hdr->typeFlagsVideo ? "yes" : "no") << std::endl; ss << "AudioFlag: " << (_m_flv_hdr->typeFlagsAudio ? "yes" : "no") << std::endl; for (const auto &tag : _m_tag_list) { ss << " Tag:" << std::endl; ss << " >type=" << (int) tag.type << std::endl; ss << " >dataLen=" << tag.dataLen << std::endl; ss << " >timestamp=" << tag.timestamp << std::endl; ss << " >streamId=" << tag.streamId << std::endl; } return ss.str(); } private: bool openFile(const char *filepath) { _m_ifs.open(filepath, std::iostream::binary | std::iostream::in); return _m_ifs.is_open(); } std::optional parseHeader() { FLVHeader hdr; _m_ifs.read(reinterpret_cast(&hdr), sizeof(FLVHeader)); if (_m_ifs.gcount() != sizeof(hdr)) { std::cout << "read FLVHeader failed." << std::endl; return std::nullopt; } if (hdr._reserved || hdr._typeFlagsReserved) { return std::nullopt; } return hdr; } void parseBody() { uint32_t prevTagSize; TagHeader hdr; while (true) { // read prevTagSize _m_ifs.read(reinterpret_cast(&prevTagSize), sizeof(prevTagSize)); if (_m_ifs.gcount() != sizeof(prevTagSize)) { break; } // read tagHeader _m_ifs.read(reinterpret_cast(&hdr), sizeof(hdr)); if (_m_ifs.gcount() != sizeof(hdr)) { break; } Tag tag; tag.type = hdr.tagType; tag.dataLen = (hdr.dataSize[0] << 16) | (hdr.dataSize[1] << 8) | hdr.dataSize[2]; tag.timestamp = (hdr.timestamp[3] << 24) | (hdr.timestamp[0] << 16) | (hdr.timestamp[1] << 8) | hdr.timestamp[2]; tag.streamId = (hdr.streamId[0] << 16) | (hdr.streamId[1] << 8) | hdr.streamId[2]; _m_tag_list.push_back(std::move(tag)); _m_ifs.seekg(static_cast(tag.dataLen), std::ios::cur); } } private: struct Tag { uint8_t type = 0; size_t dataLen = 0; uint32_t timestamp = 0; uint32_t streamId; }; std::ifstream _m_ifs; std::optional _m_flv_hdr; std::vector _m_tag_list; }; }// namespace flv int main(int argc, char *argv[]) { if (argc < 2) { printf("flv_parser \n"); return -1; } flv::Parser parser(argv[1]); if (!parser.ok()) { printf("Invalid flv\n"); return -1; } std::cout << parser.toString() << std::endl; return 0; }