自己动手写一个M3U8下载器

下班买菜

自己动手写一个M3U8下载器

当你用手机或者电脑追剧的时候,有没有想过你眼前的视频是如何从服务器到你的手机上的呢?

其实随着网络技术的发展,在人们的日常生活中,互联网已经无处不在.

不管你是用手机,还是电脑,不管你浏览网页,还是使用APP; 一个按钮的点击,一个页面的刷新,最后都是通过网络请求到服务器,然后再从服务器返回你所需要的数据.

如果你会抓包,或者在浏览器里按F12打开控制台,就能发现信息交互的蛛丝马迹.

现在已经进入了信息化时代,每个人都应该对互联网有个基本的了解.

言归正传, 当你打开APP或者网页,找到要追的剧,点击播放,而这些视频则是通过流的方式一点点从服务器传到你的屏幕上.

FLV

在我的记忆里,刚开始的时候,网上的视频还是flv格式. 这种格式文件小,加载速度快,延时低.

FLV (Flash Video)Adobe 公司推出的一种视频格式,是一种在网络上传输的流媒体数据存储容器格式.支持的协议有RTMPHTTP-FLV.这两个协议也都是Adobe公司推出的.

RTMP基于 TCP 传输,可能会被防火墙拦截.

HTTP-FLV是基于HTTP,虽然可以避免被防火墙拦截,但是数据会在本地缓存,保密性不好.

HLS

下面就是现在最流行的一种协议了: HLS

HLS (HTTP Live Streaming)是苹果公司基于 HTTP 的流媒体传输协议.主要应用于 iOS 设备

相对于常见的流媒体协议,HLS 最大的不同在于它并不是一下请求完整的数据流。它会在服务器端将流媒体数据切割成连续的时长较短的 ts 小文件,并通过 M3U8 索引文件按序访问 ts 文件。客户端只要不停的按序播放从服务器获取到的文件,从而实现播放音视频。

HLS基于HTTP,也不会被防火墙拦截,性能高,自带多码率适应,支持在播放过程中,可以自由选择调整码率,缺点就是延时高,小文件多.

M3U8

当我们看剧的时候,想把这个下载下来怎么办呢?打开浏览器的控制台,可以发现浏览器请求了一个m3u8地址,如下图:

这个地址就是视频资源的索引地址,而返回的ts文件,就是被切割的很小的一个个视频文件.

如果我们可以把这些ts文件都下载下来,然后合并,转码成mp4,那么我们就得到了完整的视频文件.

请求m3u8地址,得到的m3u8文件格式如下:

没有加密:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:4.166667,
5b1adcbb728000000.ts
#EXTINF:4.958333,
5b1adcbb728000001.ts
#EXTINF:2.958333,
5b1adcbb728000002.ts
......
#EXTINF:2.125000,
5b1adcbb728000204.ts
#EXT-X-ENDLIST

有加密:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="/20220415/hq0ifQwb/1000kb/hls/key.key"
#EXTINF:0.189,
/20220415/hq0ifQwb/1000kb/hls/pB625ruF.ts
#EXTINF:0.5,
/20220415/hq0ifQwb/1000kb/hls/SH2VgoEz.ts
#EXTINF:1.25,
/20220415/hq0ifQwb/1000kb/hls/Dv4M2bdG.ts
......
/20220415/hq0ifQwb/1000kb/hls/q7lZX33G.ts
#EXTINF:1,
/20220415/hq0ifQwb/1000kb/hls/9EOUyDBJ.ts
#EXT-X-ENDLIST

下载

说一下核心的代码吧,粘太多代码也不好看.

这里请求m3u8url,得到index.m3u8文件,然后解析文件.有时候可能会出现文件里还有m3u8链接嵌套的情况,这种情况可以使用递归的方式来进行解析,因为这种情况比较少,所以没有使用递归.

解析得到ts文件的url,播放时长,还有序号.

播放时长是用来计算整个视频的长度的,序号是为了最后拼接的时候,文件顺序不会乱.

如果被加密,获取加密key,加密方法,偏移向量等解密需要的信息.

使用并行的方式下载所有的ts文件.

试过使用线程池还有Fork-Join,这种并行的方式底层就是使用的Fork-Join.两种下载速度差不多.

这里并发数设置为4,如果设置太大,怕服务器扛不住.还是善良一点吧.由于是并行下载,所以下载顺序是乱序的,所以最后合并的时候序号还是很重要的.

解密

接下来就是解密了,因为不是所有的m3u8都加密了,所以这里要先判断一下是否需要解密,不需要直接返回即可.


合并

因为ts片段可以无缝拼接,所以合并比较简单,使用文件流的方式写到一起就可以了.

格式转换 FFmpeg

想要用Java转换视频格式,那就少不了这个工具: FFmpeg

FFmpeg是一款开源软件,提供了强大的音视频编解码工具.也是音视频编解码开发套件,为开发者提供了丰富的音视频的调用接口。

FFmpeg 提供了多种媒体格式的封装和解封装,包括多种音视频编码、多种协议的流媒体、多种色彩格式转换、多种采样率转换、多种码率转换等;FFmpeg 框架提供了多种丰富的插件模块,包含封装与解封装的插件、编码与解码的插件等。

使用 FFmpeg 作为内核视频播放器:

使用 FFmpeg 作为内核的 Directshow Filter

使用 FFmpeg 作为内核的转码工具:

Mac可以使用HomeBrew安装:

brew install ffmpeg



到这里就完成了.

全部下载完之后,调用这个方法,就可以把ts格式的转为mp4.







刚开始的时候,我想过用多线程的方式,把ts片段转为mp4后,再进行合并,这样可以省去最后转换的时间.

后来发现,如果都转为mp4之后,就不能使用文件流读取,然后写到一个文件的方式来进行合并了.

因为每个mp4文件有自己的文件头,不能这样合并.

FFmpeg的用法很多,功能很强大,感兴趣的可以看一下.

好啦,就这样吧, 如需合作,请私信。

最后欢迎大家关注我的公众号,共同学习,一起进步。加油🤣