赞
踩
因为在线看视频时有的会比较卡顿,刚好也有闲置测试用的树莓派搭建的小服务器,本着不浪费的精神,就想着是不是能把视频下到本地,这样就不用担心卡顿了,刚好前面也记录过ffmpeg下载合并视频,以及aria2下载的,于是就有了一个不知道是不是高效安全的方式,记录下。
首先试过使用ffmpeg来直接通过外网的m3u8进行同时下载与合并生成mp4,但是发现速度很慢,只有1~3百K左右,盲猜是在一个个下ts文件,而且不知道什么原因,当到一定程度的时候,会有一定几率出现ffmpeg卡住的问题。
然后试过使用php的file_get_contents和file_put_contents来下载保存,但是一样速度超级慢,只怪Sham不会并发。
然后试了通过aria2下载,发现速度不错,家里300m宽带能到3~7MB/s浮动多。
于是就有了思路:
首先通过php来获取m3u8文件里的ts地址列表,然后生成本地用的m3u8文件,以及部分有加密用的.key文件。
然后就通过aria2c来批量下载ts地址文件中的地址。
最后就是通过ffmpeg来通过本地m3u8,获取本地的ts文件并合并生成mp4,速度明显提升
下面是Sham写的,记录备忘下
执行方法是通过网页访问这个php页,加上参数?name=xxx&m3u8=http://xxx.com/m3u8
- <?php
- if(isset($_GET['m3u8'])){
- //获取url
- $url = $_GET['m3u8'];
- //获取网址域名
- $urlarr = explode('/',$url);
- $domain = $urlarr[0].'//'.$urlarr[2].'/';
-
- //先判断传入的m3u8里面有没有直接包含ts地址,还是套着一个m3u8文件
- $url = Check_m3u8($url);
-
- //定义m3u8名字,用于区分不同的m3u8,用自定义则获取,没有则通过网址里的信息来
- $m3u8_name = $_GET['name']!=null && $_GET['name']!='' ? $_GET['name'] : $urlarr[3]."_".$urlarr[4];
- //判断、新建tslist文件夹,用于存储
- if(!file_exists('tslist/')){
- mkdir('tslist/',0777);
- }
- //通过名称建立不同文件夹
- $dir = 'tslist/'.$m3u8_name.'/';
- $ts_dir = $dir.'ts/';
- if(!file_exists($dir)){
- mkdir($dir,0777);
- }
- if(!file_exists($ts_dir)){
- mkdir($ts_dir,0777);
- }
-
- //获取m3u8文件里面的信息,并生成数组
- $content = explode(chr(10),file_get_contents($url));
- $i = 1;
- //这个是用来单独存储ts文件真实网址的
- $ts_url ='';
- //这个是用来新建本地m3u8文件,保证路径与下载保存的ts文件路径一致
- $m3u8_content = '';
- //通过循环来获取m3u8文件里每一行的信息
- foreach ($content as $v){
- //获取Key,并保存到本地
- if(strstr($v,'.key')){
- $get_key = explode('"',$v);
- $key_url = $get_key[1];
- //如不带域名,则添加,带了就保留
- $key_urls = strstr($key_url,'http') ? $key_url : $domain.$key_url;
- file_put_contents($dir.$m3u8_name.'_key.key',file_get_contents($key_urls));
- //用于本地m3u8文件,key路径与m3u8文件在同一个文件夹
- $m3u8_content .= $get_key[0].'"'.$m3u8_name.'_key.key"'.chr(10);
- }
- //获取正式ts文件网址
- elseif(strstr($v,'.ts')){
- //如不带域名,则添加,带了就保留
- $ts_urls = strstr($v,'http') ? $v : $domain.$v;
- $ts_url .= $ts_urls.chr(10);
- //获取ts文件名
- $ts_name = explode('/',$v);
- $m3u8_content .= 'ts/'.end($ts_name).chr(10);
- }
- else{
- $m3u8_content .= $v.chr(10);
- }
-
- }
- file_put_contents($dir.$m3u8_name.'.m3u8',$m3u8_content);
- file_put_contents($dir.$m3u8_name.'_ts_list.txt',$ts_url);
-
- //通过执行aria2里下载
- $res = shell_exec('aria2c --dir='.dirname(__FILE__).'/'.$ts_dir.' -i '.$dir.$m3u8_name.'_ts_list.txt');
- if($res){
- shell_exec('ffmpeg -allowed_extensions ALL -i '.dirname(__FILE__).'/'.$dir.$m3u8_name.'.m3u8 -c copy '.dirname(__FILE__).'/'.$dir.$m3u8_name.'.mp4');
- }
- }else{
- echo "请传入m3u8地址,以?m3u8=http://xxxx.com/xxx.m3u8的方式";
- }
-
-
- //判断m3u8里面有没有再包含m3u8文件
- function Check_m3u8($url){
- global $domain;
- $m3u8_content = file_get_contents($url);
- if(strstr($m3u8_content,'.m3u8')){
- $m3u8_contents = explode(chr(10),$m3u8_content);
- foreach($m3u8_contents as $m3u8){
- if(strstr($m3u8,'.m3u8')){
- $url = strstr($m3u8,'http') ? $m3u8 : $domain.$m3u8;
- break;
- }
- }
- Check_m3u8($url);
- }
- return $url;
- }
这个方法的缺点就是需要将PHP的最大脚本运行时间调大,不然会报502错误,还有就是需要开放shell_exec函数,不知道对安全性会不会有影响。
当然有个好处就是感觉挺快,对只会点php的人来说是个不错的方法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。