本文目录导读:

我来详细介绍在PHP项目中实现视频转码的几种方法:
使用FFmpeg(推荐方案)
安装FFmpeg
# Ubuntu/Debian sudo apt-get install ffmpeg # CentOS/RHEL sudo yum install ffmpeg # macOS brew install ffmpeg
PHP代码实现
<?php
class VideoTranscoder {
private $ffmpegPath;
public function __construct($ffmpegPath = '/usr/bin/ffmpeg') {
$this->ffmpegPath = $ffmpegPath;
}
/**
* 转码视频
*/
public function transcode($inputFile, $outputFile, $format = 'mp4') {
$command = sprintf(
'%s -i %s -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k %s 2>&1',
$this->ffmpegPath,
escapeshellarg($inputFile),
escapeshellarg($outputFile)
);
exec($command, $output, $returnCode);
return [
'success' => $returnCode === 0,
'output' => $output
];
}
/**
* 调整视频尺寸
*/
public function resize($inputFile, $outputFile, $width, $height) {
$command = sprintf(
'%s -i %s -vf scale=%d:%d -c:v libx264 -preset medium %s 2>&1',
$this->ffmpegPath,
escapeshellarg($inputFile),
$width,
$height,
escapeshellarg($outputFile)
);
exec($command, $output, $returnCode);
return $returnCode === 0;
}
/**
* 压缩视频
*/
public function compress($inputFile, $outputFile, $bitrate = '1M') {
$command = sprintf(
'%s -i %s -b:v %s -b:a 128k %s 2>&1',
$this->ffmpegPath,
escapeshellarg($inputFile),
$bitrate,
escapeshellarg($outputFile)
);
exec($command, $output, $returnCode);
return $returnCode === 0;
}
}
使用PHP-FFMpeg库
安装
composer require php-ffmpeg/php-ffmpeg
使用示例
<?php
require 'vendor/autoload.php';
use FFMpeg\FFMpeg;
use FFMpeg\Format\Video\X264;
class VideoConverter {
private $ffmpeg;
public function __construct() {
$this->ffmpeg = FFMpeg::create([
'ffmpeg.binaries' => '/usr/bin/ffmpeg',
'ffprobe.binaries' => '/usr/bin/ffprobe',
'timeout' => 3600,
'ffmpeg.threads' => 4,
]);
}
public function convert($inputPath, $outputPath) {
try {
$video = $this->ffmpeg->open($inputPath);
$format = new X264('aac', 'libx264');
$format->setKiloBitrate(1000)
->setAudioKiloBitrate(128);
$video->save($format, $outputPath);
return ['success' => true];
} catch (Exception $e) {
return ['success' => false, 'error' => $e->getMessage()];
}
}
}
异步处理方案(适合大文件)
<?php
class AsyncVideoTranscoder {
private $queueFile = '/tmp/video_queue.json';
public function addToQueue($inputFile, $outputFile, $settings = []) {
$queue = $this->getQueue();
$job = [
'id' => uniqid(),
'input' => $inputFile,
'output' => $outputFile,
'settings' => $settings,
'status' => 'pending',
'created_at' => date('Y-m-d H:i:s')
];
$queue[] = $job;
file_put_contents($this->queueFile, json_encode($queue));
return $job['id'];
}
private function getQueue() {
if (!file_exists($this->queueFile)) {
return [];
}
return json_decode(file_get_contents($this->queueFile), true) ?? [];
}
public function processQueue() {
$queue = $this->getQueue();
foreach ($queue as &$job) {
if ($job['status'] === 'pending') {
$job['status'] = 'processing';
file_put_contents($this->queueFile, json_encode($queue));
// 执行转码
$result = $this->executeTranscode($job);
$job['status'] = $result ? 'completed' : 'failed';
$job['completed_at'] = date('Y-m-d H:i:s');
file_put_contents($this->queueFile, json_encode($queue));
// 处理下一项
break;
}
}
}
private function executeTranscode($job) {
$command = sprintf(
'ffmpeg -i %s -c:v libx264 -preset medium %s -y > /dev/null 2>&1 &',
escapeshellarg($job['input']),
escapeshellarg($job['output'])
);
exec($command, $output, $returnCode);
return $returnCode === 0;
}
}
使用消息队列(高性能方案)
<?php
// 使用 Redis 作为队列
class RedisVideoTranscoder {
private $redis;
private $queueKey = 'video:transcode:queue';
public function __construct() {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public function pushJob($inputFile, $outputFile, $options = []) {
$job = [
'input' => $inputFile,
'output' => $outputFile,
'options' => $options,
'created_at' => time()
];
$this->redis->lPush($this->queueKey, json_encode($job));
return true;
}
public function processJobs() {
while (true) {
$job = $this->redis->rPop($this->queueKey);
if ($job) {
$jobData = json_decode($job, true);
$this->transcodeVideo($jobData);
}
// 短暂暂停避免CPU过载
usleep(100000);
}
}
private function transcodeVideo($job) {
$command = sprintf(
'ffmpeg -i %s -c:v libx264 -preset fast %s -y',
escapeshellarg($job['input']),
escapeshellarg($job['output'])
);
exec($command, $output, $returnCode);
// 记录转码结果
$this->logResult($job, $returnCode);
}
}
Web界面管理
<?php
// 上传和转码控制器
class VideoController {
public function upload() {
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['video'])) {
$file = $_FILES['video'];
// 验证文件
$allowedTypes = ['video/mp4', 'video/avi', 'video/mov'];
if (!in_array($file['type'], $allowedTypes)) {
return ['error' => '不支持的文件格式'];
}
$uploadPath = '/uploads/' . uniqid() . '_' . $file['name'];
move_uploaded_file($file['tmp_name'], $uploadPath);
// 开始转码
$transcoder = new VideoTranscoder();
$outputPath = '/converted/' . uniqid() . '.mp4';
$result = $transcoder->transcode($uploadPath, $outputPath);
if ($result['success']) {
return [
'success' => true,
'original' => $uploadPath,
'converted' => $outputPath,
'url' => '/download/' . basename($outputPath)
];
}
}
}
}
配置建议
<?php
// config.php
return [
'ffmpeg' => [
'path' => '/usr/bin/ffmpeg',
'timeout' => 3600, // 1小时超时
'threads' => 4, // CPU线程数
// 预设配置
'presets' => [
'high_quality' => [
'video' => 'libx264',
'bitrate' => '2000k',
'audio' => 'aac',
'audio_bitrate' => '192k'
],
'web_optimized' => [
'video' => 'libx264',
'bitrate' => '800k',
'audio' => 'aac',
'audio_bitrate' => '128k'
]
]
]
];
错误处理和日志
<?php
class VideoTranscoderErrorHandler {
private $logFile = '/var/log/video_transcoder.log';
public function logError($message, $context = []) {
$log = sprintf(
"[%s] ERROR: %s | Context: %s\n",
date('Y-m-d H:i:s'),
$message,
json_encode($context)
);
file_put_contents($this->logFile, $log, FILE_APPEND);
}
public function getStatus($jobId) {
$statusFile = "/tmp/transcoder_{$jobId}.status";
if (file_exists($statusFile)) {
return json_decode(file_get_contents($statusFile), true);
}
return ['status' => 'unknown'];
}
}
注意事项
- 性能优化:大文件转码建议使用异步队列
- 资源限制:设置适当的超时和内存限制
- 安全考虑:严格验证上传文件,防止命令注入
- 监控报警:记录转码失败并发送通知
- 进度反馈:对长时间转码提供进度反馈
选择哪种方案取决于你的项目需求:简单转码用FFmpeg命令,复杂需求用PHP-FFMpeg库,高并发用消息队列方案。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播