FFmpeg 如何播放带「图片」的 M3U8 视频,IJKPlyaer 适配非标 TS 文件

1、前言

如果你经常接触音视频,那么对于 M3U8 应该不会陌生, M3U8 简单来说就是 HLS(HTTP Live Streaming) ,指的是苹果开发的基于 HTTP 协议的流媒体解决方案,它可以在普通的 HTTP 的应用上直接提供点播和直播的能力。

在 HLS 里会将视流文件切分成小片(ts)并建立索引文件(M3U8),一般如下图所示,首先会有一个 M3U8 文件,然后对应在 #EXTINF 的 tag 下会有很多 TS 格式切片,这应该是我们认知中的 M3U8 文件的标准。

详细讲解 M3U8 的这里就不详细展开,感兴趣的可以看之前分享过的探索移动端音视频与GSYVideoPlayer之旅 。

「那么,如果在 M3U8 里的不是 TS 链接,而是 png 链接或者 bmp 链接会是什么情况」?今天的主题就是探讨如何适配带有图片的非标准 M3U8 视频。

「我们不鼓励「非标」,而是通过「非标」的适配来做科普」

2、为什么 M3U8 里会有图片?

首先,标准的 HLS 协议里 M3U8 文件内肯定是 TS 的切片链接,「那么为什么会有 png/bmp 之类的图片链接存在?或者说,为什么会是图片链接」

这就不得不说「劳动人民的智慧」,众所周知,如果想让一个视频加载更快,那么最简单的办法就是给视频上 CDN ,但是碍于某些团队或者个人「囊中羞涩」,所以开始有人瞄上了公共图床的 CDN ,然后再结合 M3U8 的特性,一套民间的「免费」 视频 CDN 潜规则就这样悄然流行起来。

如果你想将一个完整视频伪装成图片上传公共图床明显不现实,因为体积太大,很多图床也会对图片的大小做限制,但是如果是 M3U8 ,那么就可以把「视频分解成无数 TS ,再把 TS 伪装成图片分批上传,这样就可以给视频「依附」上 CDN 的能力」

3、TS & 图片

如下图所示,这就是一个「非标」的 M3U8 视频链接,可以看到 #EXTINF tag 下会的链接都是 png格式的后缀,「那么这种 png 后缀,会不会影响视频播放呢」

「答案是不会,因为 FFmpeg 里播放并不是认定后缀」,而是通过读取每个 #EXTINF tag 链接的二进制 Header,最终匹配它们的封装和编解码格式。

所以其实在 M3U8 里 #EXTINF tag 下的链接后缀并不重要,可以是 png 或者 bmp ,甚至你写 txt 也是可以的,重点其实是包本身的编码。

那么如果这个视频链接,真的是一个图片呢?如下图所示,可以看到这个 png 本身就是一个完整的图片,不过这个图片的大小和它本身的质量并不匹配,毕竟这样一个图片不可能高达 1.9 MB 。

如下图所示,我们查看这张图片的二进制,可以看到文件的 Header 确实是 PNG ,但是后面还有类似 FFmpeg Service 这样的描述,可以确实这就是一个伪装成真实 PNG 格式的视频文件。

从二进制字节看可以发现这就是一个 TS 封装的视频文件,因为在它的二进制代码里,有「以 0x47 开头,长度为 188 字节,并且通过 0xFF 进行填充的规律 packet 存在」

后面我们会详细解释。

「那么这个 PNG 可以正常播放吗?答案是可以的」。那为什么明明是 PNG 的 Header ,却可以被解析成视频?

首先 FFmpeg 在播放前,会根据前面提到的 0x47 / 188 这个特征去识别这是一个 TS 封装的视频,之后在 mpegts.c 的对应封装处理逻辑里,会针对识别 0x47 作为包的起始位置去解析,所以 PNG 包部分会被忽略。

0x47 是一个 TS 包的固定 header ,一般一个 TS 包是 188 字节,不够长度一般会用 0xFF 填充」,而 FFmpeg 会针对每个格式去做识别,计算它们的 score ,根据每种格式的 score 决定它可能是什么格式,比如 mpegts.c 里是 mpegts_probe函数,它通过 analyze 函数就会找到 0x47 起始做一系列的判断。

另外还一个叫 mpegts_read_header的函数会读取数据头信息,比如解析出 TS 流当中的数据包大小,节目信息,PMT表,Video PID,Audio PID 等等,这些也是 TS 流播放的重要依据。

而在 mpegts.c 里最重要的 read_packet函数也是,读取的时候会读取 TS_PACKET_SIZE(188)的大小,然后判断包的首字节是不是 0x47 ,如果不是就通过 mpegts_resync重新同步一下去尝试寻找 0x47

「可能这时候细心的你已经发现了「盲点」,前面 PNG 的 Header 二进制里不就是 89 50 4E 47吗?这里不也是有 0x47 ?,这种情况下 mpegts.c 在解包的时候不就会「错乱」了吗」

如下图所示,因为如果从图片的 0x47 开始算, 以 188 的包长度计算,下一个包不就找不到 0x

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值