本文目录导读:

在 PHP 中实现视频截帧,主要有以下几种方法:
使用 FFmpeg(推荐)
这是最常用和强大的方法:
安装 FFmpeg
# Ubuntu/Debian sudo apt-get install ffmpeg # CentOS/RHEL sudo yum install ffmpeg # macOS brew install ffmpeg
基本截帧示例
<?php
function getVideoFrame($videoPath, $outputPath, $time = '00:00:01') {
// 基础命令
$cmd = sprintf(
'ffmpeg -i %s -ss %s -vframes 1 -q:v 2 %s 2>&1',
escapeshellarg($videoPath),
$time,
escapeshellarg($outputPath)
);
exec($cmd, $output, $returnCode);
return $returnCode === 0;
}
// 使用示例
$videoFile = 'video.mp4';
$frameFile = 'frame.jpg';
$result = getVideoFrame($videoFile, $frameFile, '00:00:05');
if ($result) {
echo "截帧成功!";
} else {
echo "截帧失败!";
}
?>
高级用法
<?php
class VideoFrameExtractor {
private $ffmpegPath = 'ffmpeg';
/**
* 截取指定时间的帧
*/
public function getFrameAtTime($videoPath, $time, $outputPath, $options = []) {
$defaultOptions = [
'quality' => 2, // 质量(1-31,越小越好)
'size' => null, // 尺寸,如 '320x240'
'framerate' => 1, // 帧率
'format' => 'jpg' // 输出格式
];
$options = array_merge($defaultOptions, $options);
$cmd = $this->ffmpegPath;
// 添加输入文件
$cmd .= ' -i ' . escapeshellarg($videoPath);
// 添加时间参数
$cmd .= ' -ss ' . $time;
// 添加质量参数
$cmd .= ' -vframes 1 -q:v ' . $options['quality'];
// 添加尺寸参数
if ($options['size']) {
$cmd .= ' -s ' . $options['size'];
}
// 添加输出文件
$cmd .= ' ' . escapeshellarg($outputPath);
// 执行命令
exec($cmd . ' 2>&1', $output, $returnCode);
return [
'success' => $returnCode === 0,
'output' => $output,
'path' => $outputPath
];
}
/**
* 提取视频中的所有帧
*/
public function extractAllFrames($videoPath, $outputDir, $format = 'jpg') {
if (!is_dir($outputDir)) {
mkdir($outputDir, 0777, true);
}
$cmd = sprintf(
'%s -i %s -vf fps=1 %s/frame_%%d.%s 2>&1',
$this->ffmpegPath,
escapeshellarg($videoPath),
escapeshellarg($outputDir),
$format
);
exec($cmd, $output, $returnCode);
return $returnCode === 0;
}
/**
* 获取视频信息
*/
public function getVideoInfo($videoPath) {
$cmd = sprintf(
'%s -i %s 2>&1',
$this->ffmpegPath,
escapeshellarg($videoPath)
);
exec($cmd, $output);
$info = [
'duration' => null,
'width' => null,
'height' => null
];
foreach ($output as $line) {
// 获取时长
if (preg_match('/Duration: (\d{2}):(\d{2}):(\d{2}\.\d{2})/', $line, $matches)) {
$info['duration'] = $matches[1] . ':' . $matches[2] . ':' . $matches[3];
}
// 获取分辨率
if (preg_match('/Stream.*Video:.*(\d{3,4})x(\d{3,4})/', $line, $matches)) {
$info['width'] = $matches[1];
$info['height'] = $matches[2];
}
}
return $info;
}
}
// 使用示例
$extractor = new VideoFrameExtractor();
// 单帧截取
$result = $extractor->getFrameAtTime(
'video.mp4',
'00:00:10',
'output/frame.jpg',
['size' => '640x360']
);
// 提取所有帧(每秒1帧)
$result = $extractor->extractAllFrames('video.mp4', 'frames/');
// 获取视频信息
$info = $extractor->getVideoInfo('video.mp4');
echo "视频时长:" . $info['duration'];
echo "分辨率:" . $info['width'] . 'x' . $info['height'];
?>
使用 PHP 扩展
GD 库 + FFmpeg(结合使用)
<?php
function getFrameWithGD($videoPath, $time, $outputPath) {
// 先使用ffmpeg截帧
$tempFile = tempnam(sys_get_temp_dir(), 'frame');
$cmd = sprintf(
'ffmpeg -i %s -ss %s -vframes 1 %s 2>&1',
escapeshellarg($videoPath),
$time,
escapeshellarg($tempFile)
);
exec($cmd, $output, $returnCode);
if ($returnCode !== 0) {
return false;
}
// 使用GD进行图像处理
$image = imagecreatefromjpeg($tempFile);
// 调整大小
$newWidth = 800;
$newHeight = 450;
$resizedImage = imagecreatetruecolor($newWidth, $newHeight);
imagecopyresampled(
$resizedImage, $image,
0, 0, 0, 0,
$newWidth, $newHeight,
imagesx($image), imagesy($image)
);
// 添加水印
$watermark = imagecreatetruecolor(100, 50);
$color = imagecolorallocate($watermark, 255, 255, 255);
imagestring($watermark, 5, 5, 5, 'Watermark', $color);
imagecopy($resizedImage, $watermark, 10, 10, 0, 0, 100, 50);
// 保存图片
imagejpeg($resizedImage, $outputPath, 90);
// 清理资源
imagedestroy($image);
imagedestroy($resizedImage);
unlink($tempFile);
return true;
}
?>
使用第三方库
PHP-FFI(通过 FFI 调用)
<?php
// 使用 FFI 调用 FFmpeg 库(需要 FFI 扩展)
$ffi = FFI::cdef(
"int avformat_open_input(void **ps, const char *url, void *fmt, void *options);",
"libavformat.so"
);
// 具体实现较为复杂,推荐使用命令行方式
?>
完整的实用示例
<?php
class VideoProcessor {
private $ffmpeg;
public function __construct($ffmpegPath = 'ffmpeg') {
$this->ffmpeg = $ffmpegPath;
}
/**
* 生成视频缩略图(多个时间点)
*/
public function generateThumbnails($videoPath, $outputDir, $count = 4) {
// 获取视频信息
$info = $this->getVideoInfo($videoPath);
if (!$info || !$info['duration']) {
return false;
}
// 解析时长
list($h, $m, $s) = explode(':', $info['duration']);
$totalSeconds = $h * 3600 + $m * 60 + $s;
// 计算截取时间点
$thumbnails = [];
for ($i = 0; $i < $count; $i++) {
$timePoint = $totalSeconds * ($i + 1) / ($count + 1);
$thumbPath = $outputDir . '/thumb_' . ($i + 1) . '.jpg';
// 格式化时间
$timeStr = sprintf(
'%02d:%02d:%02d',
floor($timePoint / 3600),
floor(($timePoint % 3600) / 60),
floor($timePoint % 60)
);
// 执行截帧
$cmd = sprintf(
'%s -i %s -ss %s -vframes 1 -vf "thumbnail=50,scale=320:240" %s 2>&1',
$this->ffmpeg,
escapeshellarg($videoPath),
$timeStr,
escapeshellarg($thumbPath)
);
exec($cmd, $output, $returnCode);
if ($returnCode === 0) {
$thumbnails[] = $thumbPath;
}
}
return $thumbnails;
}
/**
* 创建视频网格预览
*/
public function createPreviewGrid($videoPath, $outputPath, $gridWidth = 3, $gridHeight = 3) {
$cmd = sprintf(
'%s -i %s -vf "fps=1,scale=320:180,tile=%dx%d" -frames:v 1 %s 2>&1',
$this->ffmpeg,
escapeshellarg($videoPath),
$gridWidth,
$gridHeight,
escapeshellarg($outputPath)
);
exec($cmd, $output, $returnCode);
return $returnCode === 0;
}
private function getVideoInfo($videoPath) {
$cmd = sprintf('%s -i %s 2>&1', $this->ffmpeg, escapeshellarg($videoPath));
exec($cmd, $output);
$info = [];
foreach ($output as $line) {
if (preg_match('/Duration: (\d{2}:\d{2}:\d{2}\.\d+)/', $line, $m)) {
$info['duration'] = $m[1];
}
}
return $info;
}
}
// 使用示例
$processor = new VideoProcessor();
$thumbnails = $processor->generateThumbnails('video.mp4', 'thumbs/', 4);
$result = $processor->createPreviewGrid('video.mp4', 'preview.jpg');
?>
注意事项
- 安全性:始终使用
escapeshellarg()处理用户输入 - 性能:对于大视频文件,考虑异步处理
- 错误处理:始终检查返回码和输出
- 内存管理:处理大量帧时注意内存使用
- 格式支持:确保 FFmpeg 已安装所需编解码器
这些方法中,使用 FFmpeg 命令行是最稳定和功能最全面的方案,建议优先使用。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播