I'm Sham
一个在通往码农道路上走走停停的行政文员

php+aira2+ffmpeg下载m3u8文件并保存成mp4

因为在线看视频时有的会比较卡顿,刚好也有闲置测试用的树莓派搭建的小服务器,本着不浪费的精神,就想着是不是能把视频下到本地,这样就不用担心卡顿了,刚好前面也记录过ffmpeg下载合并视频,以及aria2下载的,于是就有了一个不知道是不是高效安全的方式,记录下。

首先试过使用ffmpeg来直接通过外网的m3u8进行同时下载与合并生成mp4,但是发现速度很慢,只有1~3百K左右,盲猜是在一个个下ts文件,而且不知道什么原因,当到一定程度的时候,会有一定几率出现ffmpeg卡住的问题。

然后试过使用php的file_get_contents和file_put_contents来下载保存,但是一样速度超级慢,只怪Sham不会并发。

然后试了通过aria2下载,发现速度不错,能到1m多。

于是就有了思路:

首先通过php来获取m3u8文件里的ts地址列表,然后生成本地用的m3u8文件,以及部分有加密用的.key文件。

然后就通过aria2c来批量下载ts地址文件中的地址。

最后就是通过ffmpeg来通过本地m3u8,获取本地的ts文件并合并生成mp4,速度明显提升

下面是Sham写的,记录备忘下

<?php
if(isset($_POST['m3u8'])){
    //获取url
    $url = $_POST['m3u8'];
    //获取网址域名
    $urlarr = explode('/',$url);
    $domain = $urlarr[0].'//'.$urlarr[2].'/';
    
    //先判断传入的m3u8里面有没有直接包含ts地址,还是套着一个m3u8文件
    $url = Check_m3u8($url);
    
    
    //定义m3u8名字,用于区分不同的m3u8,用自定义则获取,没有则通过网址里的信息来
    $m3u8_name = $_POST['name']!=null && $_POST['name']!='' ? $_POST['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的人来说是个不错的方法。

赞(0) 赏杯咖啡!
未经允许不得转载:Sham@双目瞿 » php+aira2+ffmpeg下载m3u8文件并保存成mp4

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

如果你觉得文章好,请赏1杯速溶咖啡给Sham吧!

微信扫一扫打赏