c++如何解析FLV视频文件的Tag结构与Metadata【深度】

千晨吖_2082

千晨吖_2082

2026-04-14

446人浏览

原创

flv tag header需手动逐字节解析:tagtype(1字节)、datasize(3字节大端)、timestamp(3字节+1字节扩展)、streamid(3字节固定为0),严禁指针强转,须用std::array读取后拼装整数。

c++如何解析flv视频文件的tag结构与metadata【深度】

FLV Tag Header 的字节解析必须手动处理,没有标准库可依赖

FLV 是二进制封装格式,Tag Header 不是文本或 JSON,不能用 std::getline 或 rapidjson 解析。你得从文件头开始逐字节读取、按规范位移解包。关键字段包括:TagType(1 字节)、DataSize(3 字节大端)、Timestamp(3 字节时间戳低 24 位 + 1 字节扩展)、StreamID(3 字节固定为 0)。常见错误是直接用 uint32_t* 强转指针读取 —— 这在非对齐地址或大小端不一致平台(如 ARM macOS)会触发未定义行为或读错值。

实操建议:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • 用 std::ifstream::read() 按字节顺序读入 std::array<uint8_t></uint8_t>,再手动拼装整数:例如 DataSize = (buf[1]
  • Timestamp 要组合低 24 位(buf[4..6])和高 8 位(buf[7]),注意 FLV 时间戳单位是毫秒,但实际值可能溢出,需用 uint32_t 并处理回绕(比如前后帧差 > 10s 则视为重置)
  • 跳过 StreamID(恒为 0)但不能跳过——它占 3 字节,少读会导致后续所有 Tag 偏移错乱

Metadata Tag(AMF0 类型)需实现最小 AMF0 解析器,不能只靠字符串匹配

Metadata 总是第一个 TagType == 18 的 Tag,其 Data 区域以 AMF0 编码(不是 JSON)。常见误判是看到 "onMetaData" 就认为是 Metadata —— 实际上该字符串只是 AMF0 中的一个 String 类型字段值,前面还有 type marker(0x02)、长度(2 字节)、内容;后面还跟着真正的对象键值对(0x03 开头的对象标记 + 多组 String + Value + 0x00 0x00 0x09 结束符)。只用 strstr() 扫描会漏掉嵌套结构,也读不到 duration、width 等数值字段。

实操建议:

  • 先确认 Tag Header 中 TagType == 18 且 DataSize >= 13(AMF0 最小对象开销),再进入 AMF0 解析流程
  • AMF0 type marker 0x02 后紧跟 2 字节 length,然后才是 UTF-8 字符串内容;0x03 后是 object,每对 key/value 中 key 是 0x02 string,value 是任意 type(0x00 number、0x01 boolean、0x08 date 等)
  • 重点处理 0x00(double,8 字节 IEEE 754)、0x01(boolean,1 字节)、0x08(date,8 字节 double + 2 字节 timezone,常被忽略导致 creationDate 解错)

音频/视频 Tag 的 Data 区域需按 CodecID 分支解析,不能统一 memcpy

TagType == 8(音频)或 9(视频)时,Data 区域开头是 Codec-specific header,不是裸流。例如 H.264 视频 Tag 的第一个字节是 AvcPacketType(0x00=SPS/PPS,0x01=NALU),紧接着是 CompositionTime(24 位有符号整数,单位毫秒,用于 B 帧 DTS/PTS 计算);AAC 音频则以 AacPacketType(0x00=sequence header,0x01=raw data)开头,之后才是 ADTS 或原始 AAC 帧。直接把整个 Data 区域当媒体帧传给解码器会失败。

实操建议:

  • 先读 CodecID(音频:buf[0] & 0x0F;视频:buf[0] & 0x0F),再根据值决定后续解析逻辑:如 CodecID == 7 → H.264 → 检查 AvcPacketType;CodecID == 10 → H.265 → 注意 HevcPacketType 定义不同
  • H.264 SPS/PPS 提取后需重组为 Annex-B 格式(添加 0x00 0x00 0x00 0x01 前缀),否则大多数 FFmpeg AVCodecContext 初始化失败
  • AAC sequence header(AacPacketType == 0)包含 AudioSpecificConfig,需提取并 Base64 编码后填入 AVCodecParameters::extradata,不能丢弃

文件级 offset 与 Tag size 易被忽略,导致解析中途崩溃

FLV 文件头后是 4 字节的 PreviousTagSize0(恒为 0),之后每个 Tag 结尾都有一个 PreviousTagSize(4 字节大端,等于本 Tag 的 Header+Data 总长度)。很多实现只读 Tag Header 和 Data,却没读最后这 4 字节 —— 下一个 Tag 的起始位置就错了。更隐蔽的问题是:当 Timestamp 跨越 0x00FFFFFF(约 4.6 小时)时,FLV 规范要求写入扩展字节(TagHeader[7]),但某些生成器会漏写,导致后续所有时间戳偏移 1 字节,整个解析链崩坏。

实操建议:

  • 每次读完一个 Tag(Header + Data)后,必须用 read() 再读 4 字节 PreviousTagSize,并与当前 Tag 实际长度校验(误差 > 1 字节即报 warning)
  • 维护全局 file_offset,每次读操作前检查 file_offset + bytes_to_read ,避免 std::ifstream::eof() 滞后导致越界读
  • 对 Timestamp 做单调性检查:若当前 Timestamp 比前一个突降 > 30000ms(30 秒),大概率是扩展字节错位,应尝试回退 1 字节重新解析该 Tag Header
FLV 解析的坑不在算法,而在对字节序、边界、隐式约定的机械忠实——少一个字节、错一位大小端、漏一次回绕判断,整个时间轴或关键元数据就不可逆损坏。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2023.08.07

2155

5

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.23

3322

1

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

2023.10.13

1116

3

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

2025.09.10

3819

7

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

6499

3

java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

2023.11.13

2130

6

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.30

163

8

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1758

5

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

2744

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习