您当前的位置: 首页 > 慢生活 > 程序人生 网站首页程序人生
解决ffmpeg下载远程m3u8视频大量ts分片失败重试成本高的问题
发布时间:2023-08-30 11:36:26编辑:雪饮阅读()
-
对于一些短视频来说,那么ts分片再能分,基本上ffmpeg下载成功率都是极高的,即便失败了,那么重新下载的成本也会很低。
但是有一种情况就是某些长一些的视频,比如一个标准的电影,再加上比如你要下载的这个目标网站的带宽之类问题或者说你自身网络也挺慢,那么ffmpeg下载成功率是很低的。
此时由于一个标准电影分片又非常多,那么在这种情况下重新下载的时间成本会是很高的。
目前我是没有发现ffmpeg有支持对已下载分片的缓存的相关参数设置。
所以这里主要是为了解决对已经下载的ts分片,在失败后重新执行下载脚本时候,可以跳过已下载的ts分片的功能。
那么本来想写一个python版本,但是python本人了解的不多,有点偷懒,就直接搞php版了。。。
本来还想写web前端界面的那种,然后和php的websocket进行交互可以看到进度,想了想实现起来颇费时间,也就直接搞纯命令行脚本的了。
这里以长安三万里为例子,现在会发现有好多网站已经是不直接一个m3u8文件了,而是先请求一个m3u8文件,然后在这个m3u8文件里面引入另外一个m3u8文件,这第二个m3u8文件才是实际有包含ts分片的m3u8文件。那么我们的脚本的输入参数必然是这第二个m3u8文件的远程链接了。
最终脚本的表现效果如:
那么实现脚本其实并不难。
m3u8_download.php如:
<?php
/*
*命令参考
* -m:m3u8地址
* -o:输出路径
* D:\phpstudy_pro\Extensions\php\php7.4.3nts\php.exe -c D:\phpstudy_pro\Extensions\php\php7.4.3nts\php.ini C:\Users\Administrator\PhpstormProjects\untitled\m3u8_download.php -m https://hot.qoqkkhy.com/20230720/V4Docige/1000kb/hls/index.m3u8 -o C:\Users\Administrator\PhpstormProjects\untitled\ChangAn.mp4
*
*
* 参考
* ffmpeg -threads 0 -i "https://hot.qoqkkhy.com/20230720/V4Docige/1000kb/hls/index.m3u8" -c copy -y "C:\Users\Administrator\PhpstormProjects\untitled\ChangAn.mp4"
* */
$ffmpegPath='D:\software\ffmpeg-master-latest-win64-gpl\ffmpeg-master-latest-win64-gpl\bin\ffmpeg.exe';
print_r($argv);
$m=null;
$o=null;
if($argv[1]=="-m"){
$m=$argv[2];
}
if($argv[3]=="-o"){
$o=$argv[4];
}
if(!$m){
exit();
}
if(!$o){
exit();
}
//取得m3u8资源根链接
$result22=parse_url($m);
$m3u8_root=$result22["scheme"]."://".$result22["host"];
//创建当前任务目录
print_r("开始创建当前任务目录\r\n");
$dir=md5($m);
if(!is_dir($dir)){
$flag21=mkdir($dir,0777,true);
if($flag21){
print_r("当前任务目录创建成功\r\n");
}
}
else{
print_r("当前任务目录已存在,无需创建\r\n");
}
//下载m3u8文件
print_r("开始下载m3u8原始文件\r\n");
$m3u8_original_file=$dir."/original.m3u8";
if (file_exists($m3u8_original_file)){
print_r("m3u8原始文件已存在,无须下载\r\n");
}
$m3u8_content=file_get_contents($m);
file_put_contents($m3u8_original_file,$m3u8_content);
//提取ts链接集合
print_r("开始提取ts链接集合\r\n");
$ts_list=[];
$m3u8_original_file_handle = fopen($m3u8_original_file,"r");
while(!feof($m3u8_original_file_handle))
{
$pattern="/.ts$/";
$line=fgets($m3u8_original_file_handle);
//可能包含有换行符,这里需要做换行处理
$line=trim($line);
if(preg_match($pattern,$line)){
array_push($ts_list,$line);
}
}
fclose($m3u8_original_file_handle);
print_r("提取到的ts链接集合\r\n");
print_r($ts_list);
//开始创建当前任务ts目录
print_r("开始创建当前任务ts目录\r\n");
$dir_ts=$dir."/ts";
if(!is_dir($dir_ts)){
$flag21=mkdir($dir_ts,0777,true);
if($flag21){
print_r("当前任务ts目录创建成功\r\n");
}
}
else{
print_r("当前任务ts目录已存在,无需创建\r\n");
}
//开始下载ts文件
$ts_complete_count=0;
foreach($ts_list as $val){
$md576=md5($val);
$file77=$dir_ts."/".$md576.".ts";
$c_ts=$m3u8_root.$val;
//需要判断m3u8中ts文件是否使用的绝对路径
$result103=parse_url($val);
if(isset($result103["scheme"])){
$c_ts=$val;
}
print_r("正在下载ts:".$c_ts."\r\n");
//进度
$rate_of_progress=$ts_complete_count/count($ts_list)*100;
print_r("-------------ts下载进度:".$rate_of_progress."%-------------------\r\n");
if (file_exists($file77)){
$ts_complete_count++;
print_r($c_ts."文件已下载,无须下载\r\n");
}
else{
//如果file_get_contents失败,可以通过curl去排查详细错误
$c_ts_content=file_get_contents($c_ts);
if(!$c_ts_content){
print_r("下载ts:".$c_ts."失败(95)\r\n");
exit();
}
$flag85=file_put_contents($file77,$c_ts_content);
if(!$flag85){
$ts_complete_count++;
print_r("下载ts:".$c_ts."失败(101)\r\n");
exit();
}
$ts_complete_count++;
print_r("下载ts:".$c_ts."成功\r\n");
}
}
if($ts_complete_count!=count($ts_list)){
print_r("当前任务ts下载不完整,可重新尝试\r\n");
exit();
}
print_r("当前任务所有ts下载完成\r\n");
//开始替换生成新的本地m3u8文件
print_r("开始替换生成新的本地m3u8文件\r\n");
$m3u8_new_file=$dir."/new.m3u8";
if (file_exists($m3u8_new_file)){
print_r("m3u8本地文件已存在,无须生成\r\n");
}
else{
$m3u8_content_new=$m3u8_content;
foreach($ts_list as $val){
$md576=md5($val);
$file77="ts/".$md576.".ts";
$m3u8_content_new=str_replace($val,$file77,$m3u8_content_new);
}
file_put_contents($m3u8_new_file,$m3u8_content_new);
print_r("m3u8本地文件生成成功\r\n");
}
$command=$ffmpegPath.' -threads 0 -i "'.realpath($m3u8_new_file).'" -c copy -y "'.$o.'"';
print_r("本地合并ts:".$command."\r\n");
$output = exec($command);
echo $output;
关键字词:ffmpeg,m3u8,ts,大量分片,失败,重试