现在要做的就是增加对
HTML5
播放源的下载支持(๑•̀ㅂ•́)و✧
要做的事情
先上图,有个概念
使用HTML5播放的时候,浏览器不断的发了这么多请求(OPTIONS/GET + 视频源/音频源),请求的地址基本上是一样的,只是指向的文件的不同部分,这点从请求和回复的头部可以看出来。
再说说我的理解
- 我先把HTML5的整个视频+音频的m4s文件下下来了,然后尝试了用播放器打开,结果失败。。。这对我造成了极大的困扰
- 我先从一个旁观者的角度,思考这种视频流该怎样实现。
- 首先,这个视频文件应该是可以分成多个片段的,并不一定要全部下载完才能播放,比如文件的600 - 700 字节可以播放2min30s - 2min31s的画面, 701-900 …
- 其次,遵循这种格式的视频文件集合,应该可以支持多种清晰度的切换,比如720p的2min30s - 2min31s的画面对应600 - 700 字节,可能1080p的对应的是另一个文件的1600 - 2100等
- 虽然不是很懂多媒体,但我想这里面有几个问题是显而易见的:
- 一是即使同一清晰度,可能还有帧率啥的因素,导致一段时间(比如1s)所需消耗的文件大小可能也不同
- 二是即使对应区间长度相同,选错对齐位置也播放不出来,还是以文件的600 - 700 字节播放2min30s - 2min31s的画面为例,[509 - 699]、[635 - 735]啥的肯定也播不出来
- 如果换我来,我想把视频的分片计算的映射方法,还有其它一些必要信息写到文件头部,这个空间肯定占用不大,传输也花不了多长时间,嗯,耐撕的解决方案。
- 经过观察,似乎整个播放流程就是这样实现的。下面截取了一部分配置,注意
SegmentBase
。每次播放源的前两个请求果然与这区间一致。{ "duration": 83, "minBufferTime": 1.5, "video": [{ ... "id": 80, "baseUrl": "http://upos-hz-mirrorkodou.acgvideo.com/upgcxcode/...", "backupUrl": null, "bandwidth": 2442010, "mimeType": "video/mp4", "codecs": "avc1.640028", "width": 1920, "height": 1080, "frameRate": "25", "sar": "1:1", "startWithSap": 1, "SegmentBase": { "Initialization": "0-975", "indexRange": "976-1211" }, "codecid": 7 }], "audio": [...] }
然后问题来了
我是谁?我在哪儿?我为什么要想这么多?_( ゚Д゚)ノ
我tm又不是要边下边播,为什么要在意这些。。。φ(≧ω≦*)♪
我把服务器那端的文件整个都挪过来了,怎么可能生不成想要的东西。。。Pia!(o ‵-′)ノ”(ノ﹏<。)
所以,直接ffmpeg处理一下试一试,现在我有一个音频,一个视频
FFmpeg将视频和音频合并
ffmpeg -i /path/to/input-no-audio.mp4 -i input.mp3 -c copy /path/to/output.mp4
搞掂
把HTML5的视频、音频源整个下下来, ffmpeg合并, 然后OK了。。。K了。。
实现
和flash源下载的不同的地方在于:
- 获取下载地址的api参数
//String url = "https://api.bilibili.com/x/player/playurl?fnval=2&fnver=0&player=1&otype=json&avid=%s&cid=%s&qn=%s"; String url = "https://api.bilibili.com/x/player/playurl?fnval=16&fnver=0&type=&otype=json&avid=%s&cid=%s&qn=%s"; url = String.format(url, avIdNum, cid, qn);
- 下载的HTTP请求头部
我这是完全按照浏览器的来,没有测试服务器有没有这方面的判断//FLV headerMap.put("X-Requested-With", "ShockwaveFlash/28.0.0.137"); //M4S headerMap.remove("X-Requested-With");
-
下载的文件 由一个
.flv
变为视频音频两个.m4s
- 是否需要经过ffmpeg处理
flash源下载可以直接食用,HTML5源需要经过处理public static String[] createConvertCmd(String videoName, String audioName, String dstName) { String cmd[] = {"ffmpeg", "-i", Global.savePath +videoName, "-i", Global.savePath +audioName, "-c", "copy", Global.savePath + dstName}; return cmd; }
源代码
- 下载地址: https://github.com/nICEnnnnnnnLee/BilibiliDown/releases
- GitHub: https://github.com/nICEnnnnnnnLee/BilibiliDown
- Gitee码云: https://gitee.com/NiceLeee/BilibiliDown