因为在线看视频时有的会比较卡顿,刚好也有闲置测试用的树莓派搭建的小服务器,本着不浪费的精神,就想着是不是能把视频下到本地,这样就不用担心卡顿了,刚好前面也记录过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的人来说是个不错的方法。
最新评论
感谢大佬,非常棒的自学资料,向大佬学习!
您的行政服务小程序V2正好我们有需求,能否给个联系方式沟通下呢?谢谢!
想咨询楼主
牛逼的楼主 感谢分享 学习学习
public function UpdateDomainRecord($ip)这里会报错
学习学习
新生进来学习
目前正在找食堂报餐的小程序,看了下评论发现楼主真的是行政文员,真的太牛逼,让我不得不敬佩!我会一直关注着您的