AI 摘要

文章过长,暂不支持AI总结

📘m3u8云切片转码系统(PHP+FFmpeg)详细配置及排错指南

📌 1、环境要求与准备

环境推荐版本备注
Linux系统Debian/CentOS 推荐不建议Windows平台
Web环境Apache + PHP 7.1 + MySQL 5.6宝塔面板推荐(易操作)
执行权限必须开启exec()权限宝塔面板的禁用函数去掉exec 和shell_exec
  • 具体需求:
    • Apache/Nginx 必须配置支持伪静态(后续播放和访问需要)。
    • PHP需开启exec(),默认宝塔面板会禁用,需取消禁用。
    • 数据库MySQL5.6版本以上。
    • FFmpeg 可使用静态编译版本 (推荐版本 ≥3.0)。

📌 2、遇到的问题与逐步排查过程

(1)🔧 初步问题:转码任务一直不启动

原因:

  • 最开始的exec()函数被PHP禁用,导致系统无法调用FFmpeg进行转码。

解决方式:

  • 宝塔面板 → 软件商店 → PHP管理 → 禁用函数,删除exec和shell_exec,保存并重启PHP。

新建一个php,验证exec是否可用,前端访问这个php文件。

然后到 logs/test_exec.log 看是否有输出:

  • 有内容 ➜ exec() 没问题,问题出在转码命令;
  • 没内容或空文件 ➜ exec() 被彻底限制,宝塔可能还有残余设置没解开。

如果看到“执行结束”说明 PHP 正常运行了 exec()

在 FFmpeg 执行前确保目录存在! 可以手动创建
<?php
$cmd = './packs/ffmpeg -version';
exec($cmd, $out, $status);
file_put_contents('logs/test_exec.log', implode("\n", $out)."\nSTATUS=$status\n", FILE_APPEND);
echo "执行结束";
?>

接下来检查这个test_exec.log文件 如果类似下面的并且最后是STATUS=0 说明一切正常

ffmpeg version N-47099-gdcbd89e000-static https://johnvansickle.com/ffmpeg/
built with gcc ...
...
STATUS=0

完成之后可以在程序根目录下新建并运行下面的php页面验证FFmpeg:

<?php
$output = [];
$return_var = 0;
exec('./packs/ffmpeg -version', $output, $return_var);
echo "<pre>";
print_r($output);
echo "返回状态码:$return_var";
echo "</pre>";
?>

访问这个 PHP 页面,如果返回状态码不是 0,或者没有输出,说明:

  • 可能 PHP 禁用了 exec 函数
  • 或者当前运行环境(例如 Open_basedir 或 safe_mode)不允许

正常情况下 在终端输入./packs/ffmpeg -version 如果ffmpeg正常 应该返回下面的信息

Array
(
[0] => ffmpeg version N-47099-gdcbd89e000-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2018 the FFmpeg developers
[1] => built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516
[2] => configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc-6 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg
[3] => libavutil 56. 19.101 / 56. 19.101
[4] => libavcodec 58. 31.102 / 58. 31.102
[5] => libavformat 58. 18.104 / 58. 18.104
[6] => libavdevice 58. 4.105 / 58. 4.105
[7] => libavfilter 7. 33.100 / 7. 33.100
[8] => libswscale 5. 2.100 / 5. 2.100
[9] => libswresample 3. 2.100 / 3. 2.100
[10] => libpostproc 55. 2.100 / 55. 2.100
)
返回状态码:0

(2)🔧 FFmpeg路径配置错误

问题表现:

  • 转码页面显示ffmpeg未找到或提示ffmpeg error

排查方法:

  • 后台配置路径:设置为绝对路径而非相对路径。

正确路径示例:

./packs/

(路径后必须有斜杠,且不要包含具体ffmpeg文件名)

测试FFmpeg有效性PHP代码:

<?php
exec("/www/wwwroot/你的网站/packs/ffmpeg -version", $output, $status);
print_r($output);
echo "STATUS=$status";
?>

状态码为0且有输出表示成功。


(3)🔧 转码队列一直卡“等待转码”

这个问题可能出现在当前系统的转码调度器上

当前系统的“转码调度器”就是 Ting.php 控制器里的 transcode() 方法,它负责从数据库 queue 表里取任务,并用 ffmpeg 进行转码。

这种情况 你首先可以手动访问 http://你的域名/admin.php/ting/transcode,查看返回的数字(视频编号)

假如返回的是数字 10说明 ID 为 10 的视频任务已经被调度器处理了!

但你观察后台状态仍然是“等待转码”,如果还未生成m3u8文件(你可以查看一下存不存在生成的m3u8和ts文件。我当时确实没有生成)说明问题已经明确是出在 FFmpeg 调用或执行失败阶段。

系统调用 FFmpeg 的地方其实是在 Ting::transcode() 的这段逻辑:

$this->load->library('xyz');
$format = $this->xyz->format($Video_Path.$uploadStr.$newname);

说明系统是通过一个叫 xyz 的类来封装 FFmpeg 的调用!

而这个Xyz.php的transcode() 方法中这句:

$result = exec($make_command,$arr,$log);

没有日志输出 无法定位

所以现在我们只要在 transcode() 方法中加上如下调试代码,就能完全清楚系统是否命令写错、路径不对,还是权限问题。

在下面这句

$result = exec($make_command,$arr,$log);

添加下面的代码:

file_put_contents('/tmp/ffmpeg_command.log', $make_command . "\n", FILE_APPEND);
file_put_contents('/tmp/ffmpeg_output.log', implode("\n", $arr) . "\nEXIT CODE: $log\n", FILE_APPEND);

完成后大概长这样:

$result = exec($make_command,$arr,$log);
file_put_contents('/tmp/ffmpeg_command.log', $make_command . "\n", FILE_APPEND);
file_put_contents('/tmp/ffmpeg_output.log', implode("\n", $arr) . "\nEXIT CODE: $log\n", FILE_APPEND);
if($log == 0){
return defined('KBPS') ? KBPS : 'm3u8ok';
}else{
return '';
}
}

原因:

  • 文件路径问题或队列状态被锁死(转码中断或进程假死)。

解决办法:

  • 检查PHP代码Ting.phpXyz.php的路径正确性;
  • 确认packs目录中存在ffmpegffprobe,并拥有755权限;
  • 杀死已有卡死进程
ps aux | grep "ffmpeg" | awk '{print $2}' | xargs kill -9

(4)🔧 转码执行但未生成M3U8文件

错误表现:

  • 转码队列状态已成功,但实际无m3u8文件生成。

排查方法:

  • 手动执行FFmpeg命令,检查错误:
./packs/ffmpeg -i [源视频] -c:v libx264 -hls_time 10 -hls_list_size 0 -f hls [目标路径]/index.m3u8
  • 错误提示如Could not write header for output file...表明目标文件夹未创建。
  • 需要提前创建目标目录或确保程序的自动创建目录权限正常

📌 最终成功的核心点:

  • 文件夹必须有完整读写权限
  • PHP的mkdir函数有效(mkdirss递归创建);
  • 手动创建测试文件夹确认FFmpeg正常执行后,转码即可顺利完成。

(5)🔧 HTTPS不支持问题

这套程序比较老旧,默认不支持https访问,你需要手动将硬编码部分的http改为https

表现:

  • 代码默认生成http://链接,页面使用HTTPS访问会报错,视频无法播放。

排查发现:

  • 核心函数m3u8_link()内硬编码了http://协议。

修改方案:

找到定义 m3u8_link() 的文件(在 /application/helpers/common_helper.php )

这部分已经写死了

$link = 'http://'.Web_Url.$webpath.'m3u8/'.sys_auth($path).'.'.$ac;

所以需要将http://改为https://

修改后应该长这样

function m3u8_link($path,$ac='m3u8',$xu=1){
$Mu_Path = substr(Mu_Path,0,2) == './' ? substr(Mu_Path,2) : Mu_Path;
$webpath = CS_Web_Wjt == 1 ? Web_Path : Web_Path.'index.php/';
$protocol = 'https://'; // 强制使用 HTTPS
//多图模式
if($ac != 'm3u8'){
if($xu > 1 && strpos($path, '[xu]') === false){
$name = end(explode('/', $path));
$path = str_replace($name, $xu.'_'.$name, $path);
}else{
$path = str_replace('[xu]', $xu, $path);
}
if($ac == 'gif') $path = str_replace('.jpg', '.gif', $path);
}else{
if(Mu_Type == 1 && $xu != '1'){
$ext = end(explode('/', $path));
$path = str_replace($ext, $xu.'/'.$ext, $path);
}
}
if(Web_Play == ''){
if(Web_M3u8On == 1){
if($ac == 'm3u8'){
$link = $protocol.Web_Url.$webpath.'m3u8/'.sys_auth($path).'.'.$ac;
}else{
$link = $protocol.Web_Url.$webpath.'m3u8/pic/'.sys_auth($path).'.'.$ac;
}
}else{
$link = $protocol.Web_Url.Web_Path.$Mu_Path.$path;
}
}else{
if(Web_M3u8On == 1){
if($ac == 'm3u8'){
$link = $protocol.Web_Play.$webpath.'m3u8/'.sys_auth($path).'.'.$ac;
}else{
$link = $protocol.Web_Play.$webpath.'m3u8/pic/'.sys_auth($path).'.'.$ac;
}
}else{
$link = $protocol.Web_Play.'/'.$path;
}
}
return $link;
}

这样就可顺利兼容HTTPS,视频播放正常。


📌 3、配置参数完整说明

以下是涉及到的核心配置参数的完整注释说明(config.phpapplication/config中的配置):

参数解释推荐设置
Mu_PathM3U8输出路径./video/m3u8/
Video_Path视频源路径./video/data/
Mu_FfpathFFmpeg的安装路径/www/wwwroot/v.iob.lol/packs/
Mu_Type是否启用双码率0(否) 或 1(是)
Mu_Kbps默认码率(kbps)800(根据需求调整)
Mu_Kbps2第二码率(kbps)400(根据需求调整)
Mu_Size视频转码分辨率1280x720 (可自定)
Mu_Time每个TS切片长度(秒)推荐10
Mp_On是否处理音频1 (启用音频处理)
Web_CrossOn防盗链功能根据需求,默认关闭(0)
Web_M3u8On是否启用M3U8加密根据需求

📌 4、推荐的标准操作流程(未来使用时)

  1. 部署环境,安装PHP 7.1 + MySQL 5.6 + Apache/Nginx,开放exec()
  2. 上传完整代码,设置文件夹权限(755);
  3. 配置ffmpeg路径,使用绝对路径;
  4. 测试exec()执行ffmpeg -version
  5. 配置HTTPS,修改函数m3u8_link()协议为https://
  6. 确认目标路径存在且可写,后台创建队列;
  7. 转码成功后,在前台播放,观察视频播放状态。

📌 5、排错核心要点(再出现问题时的核心步骤)

步骤检测项操作方法
1PHP函数权限exec()必须可用
2路径权限文件夹必须755以上权限,允许PHP创建
3FFmpeg命令测试使用shell直接执行ffmpeg命令测试
4m3u8链接协议HTTPS需强制为https协议
5日志与监控查看logs/内生成的日志文件

通过以上操作和详细的排查过程总结,这套老旧的PHP云转码系统即可稳定、有效地投入日常使用。