
PHP调用FFmpeg实现视频切片
在当今的视频流媒体应用中,HLS(HTTP Live Streaming)协议因其良好的跨平台兼容性和自适应码率特性而被广泛使用。将MP4等主流视频格式转换为M3U8加TS切片文件,是实现HLS播放的核心步骤。通过PHP调用FFmpeg,我们可以实现视频切片的自动化处理,本文将详细介绍如何安全、高效地完成这一操作。
一、环境准备
在开始编写PHP代码之前,需要确保服务器已经安装了FFmpeg,并且PHP环境允许执行外部命令。
1. 安装FFmpeg
在Linux服务器上,可以通过包管理器快速安装:
sudo apt-get update sudo apt-get install ffmpeg
2. PHP环境配置
PHP需要开启exec或shell_exec函数。出于安全考虑,许多生产环境默认会禁用这些函数,你需要在php.ini中的disable_functions列表中将其移除,并在重启PHP服务后生效。
二、核心实现原理
视频切片的本质是利用FFmpeg将源视频重新封装并切分为符合HLS协议的文件。核心FFmpeg命令逻辑如下:
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -f hls -hls_time 10 -hls_list_size 0 -hls_segment_filename output/segment_%03d.ts output/index.m3u8
参数说明:
-c:v libx264:指定视频编码为H.264,确保最大兼容性。-c:a aac:指定音频编码为AAC。-f hls:输出格式为HLS。-hls_time 10:每个TS切片的时长为10秒。-hls_list_size 0:M3U8列表中保存所有切片记录(0表示不限制),便于点播回看。-hls_segment_filename:TS切片文件的命名规则,%03d表示3位数字递增。
三、PHP封装代码实现
下面将FFmpeg命令封装为PHP类,增加目录检测、命令安全转义以及错误捕获机制,确保在生产环境中稳定运行。
<?php
class VideoSlicer
{
private $ffmpegPath = '/usr/bin/ffmpeg';
/**
* 将视频切片为HLS格式
* @param string $inputFile 源视频文件绝对路径
* @param string $outputDir 输出目录绝对路径
* @param int $segmentTime 每个切片的时长(秒)
* @return array 执行结果
*/
public function sliceToHLS($inputFile, $outputDir, $segmentTime = 10)
{
// 检查源文件是否存在
if (!file_exists($inputFile)) {
return ['status' => false, 'message' => '源视频文件不存在'];
}
// 创建输出目录
if (!is_dir($outputDir)) {
mkdir($outputDir, 0755, true);
}
$m3u8File = rtrim($outputDir, '/') . '/index.m3u8';
$tsPattern = rtrim($outputDir, '/') . '/segment_%03d.ts';
// 使用 escapeshellarg 防止命令注入
$command = sprintf(
'%s -i %s -c:v libx264 -c:a aac -strict -2 -f hls -hls_time %d -hls_list_size 0 -hls_segment_filename %s %s',
$this->ffmpegPath,
escapeshellarg($inputFile),
intval($segmentTime),
escapeshellarg($tsPattern),
escapeshellarg($m3u8File)
);
// 执行命令并捕获输出与返回状态
$output = [];
$returnVar = 0;
exec($command . ' 2>&1', $output, $returnVar);
if ($returnVar !== 0) {
return [
'status' => false,
'message' => '切片执行失败',
'error' => implode("n", $output)
];
}
return [
'status' => true,
'message'=> '切片成功',
'm3u8' => $m3u8File
];
}
}
// 使用示例
$slicer = new VideoSlicer();
$result = $slicer->sliceToHLS('/var/www/videos/demo.mp4', '/var/www/videos/output/');
print_r($result);
?>四、注意事项与优化建议
1. 执行超时问题
视频切片属于极其耗时的CPU密集型任务。如果视频文件较大,PHP默认的30秒执行超时将会中断程序。建议在脚本头部设置set_time_limit(0)取消时间限制,或者将切片任务放入消息队列(如Redis、RabbitMQ)由后台常驻进程异步处理。
2. 防止命令注入
所有由客户端或变量传入的文件路径参数,在拼接到exec命令前,务必使用escapeshellarg()进行转义,防止恶意用户通过构造文件名执行系统命令。
3. 前端播放测试
切片生成后,可借助前端播放器(如Video.js、DPlayer等)测试播放。将播放器源指向生成的M3U8文件地址即可,例如:http://www.ipipp.com/videos/output/index.m3u8。
4. 视频编码兼容性
如果源视频本身已经是H.264视频编码和AAC音频编码,可以在FFmpeg命令中加上-c copy参数,表示直接复制流而不重新编码,这样切片速度会提升数十倍。