NiceLeeのBlog 用爱发电 bilibili~

Java FLV文件结构分析 与 直播流录制问题处理

2019-05-16
nIceLee

阅读:


最近做了一下B站的直播录制,发现下载的flv文件播放时视频时长有点问题,于是深入了解了一下,在此做些记录。

问题

  • 不想调用ffmpeg直接拉流,自己直接通过保存二进制视频流的方式录制成FLV文件。
    下下来之后发现视频的确可以播放,但是长度明显不对。

前期思考

想来想去,应该有两个地方的问题:

  1. 停止下载后,最后一帧不够完整,导致播放器解析有点问题
  2. 直播的时候,时长是不可预知的,所以FLV文件里面包含所有信息的文件头可能出问题

FLV格式

参考https://blog.csdn.net/chgaowei/article/details/51243345

遇到的坑与解决方案

  • 如何遍历每一个Tag?
    整体结构如下:
    头部(9字节) + 上一个Tag长度(4字节) + 若干个 [ Tag + 上一个Tag长度(4字节) ]
    按道理,一个完整的FLV文件,既可以直接从头开始解析,也可以从末尾开始解析

  • 如何确保直播录制的FLV是完整的?
    参考上一要点,从头开始解析,不管最后一个[Tag + 长度]是不是完整,将它删除即可。

  • 如何计算直播录制的FLV的视频时长?
    最后一个Tag的时间戳 - 第一个Tag的时间戳(具体获得见每个tag的通用结构

  • 如何修改FLV的duration字段?
    1. 在找到文件中找到duration对应的位置,特征为0x08, 0x64 , 0x75 , 0x72 , 0x61 , 0x74 , 0x69 , 0x6f , 0x6e
      0x08 表示后面有8个字节,后面的是duration对应的ascii码
    2. duration的值紧跟在后面,用9个字节来表示。
      第一个字节为0x00,表示后面跟着double类型,后八个字节为double的值
  • 每个tag的通用结构?
结构 长度(字节) 备注
tag 类型 1 8:audio, 9:video, 18:scripts
data长度 3 从streamd id 后算起, Tag长度 = data长度 + 11
timestamp 时间戳 3 时间戳
timestampex 1 默认0x00
stream id 3 默认0x00 00 00
data data长度 长度为data长度
  • 修改FLV的duration字段后,播放器显示的时长仍然不一致?
    • 通过ffmpeg处理了以后,对比发现,原始的每个tag的timestamp 时间戳都比较大,而最后一个tag的时间戳正好对应的就是播放器显示的时长
    • 也就是说,现在要将第一个tag的时间戳置零, 以后每一帧分别前移 第一个tag的时间戳 的时间
  • 尽管播放似乎没问题,ffmpeg转码会提示:
    Non-monotonous DTS in output stream 0:0; previous: 0, current: 0; changing to 1. This may result in incorrect timestamps in the output file.
    • 似乎同一类型的tag的时间戳需要严格递增,前面处理直播录制的文件的时候开头没有弄好,设置了过多的0时间戳,导致该错误
    • 参考上一点,做些处理,确保时间戳严格递增即可

源代码


内容
隐藏