商品视频封面
约 1690 字大约 6 分钟
2026-02-03
概述
本文档规定了在 ShopXO 系统中商品视频封面自动生成功能的开发流程、环境配置和使用规范。
功能说明
视频封面处理功能自动从商品视频中提取智能封面,通过亮度检测算法避免黑屏封面问题,提升商品展示效果。
核心特性
- 智能封面提取: 自动扫描视频前N秒,跳过黑屏画面
- 亮度检测算法: 使用 ITU-R BT.601 标准加权计算亮度 (Y = 0.299R + 0.587G + 0.114*B)
- 批量处理: 支持命令行批量处理已有商品视频
- 附件记录管理: 自动将生成的封面记录到附件表
技术架构
Service 层: app/service/VideoCoverService.php
├── ExtractCover() # 单个视频封面提取
├── BatchExtractCover() # 批量处理
├── CalculateBrightness() # 亮度计算
└── SaveAttachmentRecord() # 附件记录保存
Command 层: app/command/VideoCover.php
├── video:cover # 处理所有商品
└── video:cover --goods_id=N # 处理指定商品
配置文件: config/ueditor.php
└── ffmpeg 配置段
数据存储:
├── sxo_goods # 商品表 (video 字段)
└── sxo_goods_videos # 商品视频表 (cover 字段)环境依赖
1. PHP 扩展要求
| 扩展名 | 用途 | 是否必需 |
|---|---|---|
| GD 库 | 图像处理(亮度计算、缩放) | 是 |
| json | JSON 数据处理 | 是 |
| mbstring | 多字节字符串处理 | 是 |
检查 GD 库:
php -m //查看该命令下是否有gd库2. Composer 依赖
在 composer.json(在新窗口打开) 中已包含:
{
"require": {
"php-ffmpeg/php-ffmpeg": "^1.3"
}
}安装依赖:
composer install3. FFmpeg 可执行文件
FFmpeg 是视频处理的核心工具,需要单独安装。
Windows 环境配置
FFmpeg 安装
方式一:使用 Chocolatey(推荐)
# 安装 Chocolatey(如果未安装)
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# 安装 FFmpeg
choco install ffmpeg方式二:手动下载
- 访问 https://www.gyan.dev/ffmpeg/builds/
- 下载
ffmpeg-release-essentials.zip - 解压到目录,如
C:\ffmpeg - 添加到系统 PATH 环境变量:
C:\ffmpeg\bin
验证安装:
ffmpeg -version
ffprobe -version配置文件修改
编辑 config/ueditor.php(在新窗口打开):
'ffmpeg' => [
// Windows: FFmpeg 安装目录的 bin 路径
'bin_path' => 'C:\\ffmpeg\\bin\\',
// 或使用绝对路径
// 'bin_path' => 'C:\\ffmpeg\\bin\\ffmpeg.exe',
'timeout' => 3600,
'cover_width' => 150,
'brightness_threshold' => 20,
'max_scan_duration' => 10,
'cover_save_dir' => 'upload/video/goods/',
],注意事项:
- 路径中的反斜杠需要转义:
C:\\ffmpeg\\bin\\ - 或使用单引号字符串:
'C:/ffmpeg/bin/' - 如果已添加到 PATH,可留空让系统自动查找
Linux 环境配置
FFmpeg 安装
Ubuntu/Debian
# 更新包列表
sudo apt update
# 安装 FFmpeg
sudo apt install ffmpeg
# 验证安装
ffmpeg -version
ffprobe -versionCentOS/RHEL/Rocky
# CentOS 7
sudo yum install epel-release
sudo yum install ffmpeg ffmpeg-devel
# CentOS 8 / Rocky Linux / AlmaLinux
sudo dnf install epel-release
sudo dnf install ffmpeg ffmpeg-devel
# 验证安装
ffmpeg -version配置文件修改
编辑 config/ueditor.php(在新窗口打开):
'ffmpeg' => [
// Linux: FFmpeg 安装目录(通常是 /usr/bin/)
'bin_path' => '/usr/bin/',
// 或留空,通过 PATH 环境变量查找
// 'bin_path' => '',
'timeout' => 3600,
'cover_width' => 150,
'brightness_threshold' => 20,
'max_scan_duration' => 10,
'cover_save_dir' => 'upload/video/goods/',
],验证路径:
which ffmpeg
# 输出: /usr/bin/ffmpeg平台差异对比
| 配置项 | Windows | Linux |
|---|---|---|
| 可执行文件 | ffmpeg.exe, ffprobe.exe | ffmpeg, ffprobe |
| 默认路径 | C:\ffmpeg\bin\ | /usr/bin/ |
| 路径分隔符 | ; (PATH 环境变量) | : (PATH 环境变量) |
| 目录分隔符 | \ (需转义为 \\) | / |
| 权限 | 需读取权限 | 需执行权限 (chmod +x) |
| 配置示例 | 'C:\\ffmpeg\\bin\\' 或 '' | '/usr/bin/' 或 '' |
注意
注意,在代码中涉及 linux 目录下文件写入操作,确保赋予写权限。
自动检测逻辑:
系统在 VideoCoverService.php(在新窗口打开) 中实现了自动路径检测:
private static function DetectFFmpegPath($configuredPath, $command)
{
$isWindows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
$executable = $isWindows ? $command . '.exe' : $command;
if (empty($configuredPath)) {
return $executable; // 依赖 PATH 环境变量
}
if (is_dir($configuredPath)) {
$separator = $isWindows ? '\\' : '/';
return rtrim($configuredPath, '/\\') . $separator . $executable;
}
return $configuredPath;
}配置参数说明
在 config/ueditor.php(在新窗口打开) 中的 FFmpeg 配置段:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
bin_path | string | /usr/bin/ | FFmpeg 可执行文件目录 |
timeout | int | 3600 | 处理超时时间(秒) |
cover_width | int | 150 | 封面缩放宽度(用于亮度检测) |
brightness_threshold | int | 20 | 黑屏判定阈值(0-255) |
max_scan_duration | int | 10 | 最大扫描时长(秒) |
cover_save_dir | string | upload/video/goods/ | 封面存储目录 |
使用方式
1. 命令行批量处理
# 处理所有视频列表(goods_videos 表中 cover 为空的记录)
php think video:cover
# 处理指定商品的视频
php think video:cover --goods_id=123
# 处理推荐视频(goods 表中 video 字段)
php think video:cover --type=22. 代码调用
use app\service\VideoCoverService;
// 单个视频处理
$videoPath = 'D:/project/public/static/upload/video/goods/2025/01/31/video.mp4';
$result = VideoCoverService::ExtractCover($videoPath);
if ($result['success']) {
$coverPath = $result['data'];
echo "封面生成成功: {$coverPath}";
} else {
echo "错误: {$result['msg']}";
}
// 批量处理
$videoPaths = [
'/path/to/video1.mp4',
'/path/to/video2.mp4',
];
$batchResult = VideoCoverService::BatchExtractCover($videoPaths);核心算法说明
亮度计算算法
使用 ITU-R BT.601 标准的加权平均法:
Y = 0.299 × R + 0.587 × G + 0.114 × B- Y: 亮度值 (0-255)
- R/G/B: 红/绿/蓝分量 (0-255)
- 阈值: 默认 20,低于此值视为黑屏
封面提取流程
1. 获取视频时长
2. 从第0秒开始,每隔1秒提取一帧
3. 计算帧画面平均亮度
4. 如果亮度 > 阈值,保存为封面
5. 如果扫描完仍无有效画面,使用第1秒作为兜底
6. 保存封面文件和附件记录封面文件命名规则
封面文件保存在与视频相同的目录下:
视频路径: static/upload/video/goods/2025/01/31/1234567890.mp4
封面路径: static/upload/video/goods/2025/01/31/video_cover_1234567890.jpg命名格式: video_cover_{视频文件名}.jpg
数据库结构
sxo_goods 表
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 商品ID |
video | varchar(255) | 推荐视频路径 |
sxo_goods_videos 表
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 视频ID |
goods_id | int | 商品ID |
video | varchar(255) | 视频文件路径 |
cover | varchar(255) | 封面文件路径 |
is_show | tinyint | 是否显示 |
sxo_attachment 表
封面生成后自动记录到附件表:
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 附件ID |
title | varchar(255) | 文件名 (video_cover_xxx) |
url | varchar(255) | 相对路径 |
type | varchar(20) | 类型 (image) |
ext | varchar(10) | 扩展名 (jpg) |
size | int | 文件大小(字节) |
hash | varchar(32) | MD5 哈希值 |
故障排查
常见问题
1. FFmpeg 未找到
错误信息:
Failed to execute FFmpeg: sh: ffmpeg: not found解决方案:
- Linux:
sudo apt install ffmpeg - Windows: 安装 FFmpeg 并添加到 PATH
- 或在配置文件中指定完整路径
2. GD 库未安装
错误信息:
GD库未安装或不支持JPEG解决方案:
# Ubuntu/Debian
sudo apt install php-gd
# CentOS/RHEL
sudo yum install php-gd
# Windows
取消注释 php.ini 中的: extension=gd3. 权限问题(Linux)
错误信息:
Permission denied: /path/to/cover.jpg解决方案:
# 确保上传目录可写
sudo chmod -R 755 public/static/upload/
sudo chown -R www-data:www-data public/static/upload/4. 处理超时
错误信息:
FFmpeg process timeout exceeded解决方案: 在 config/ueditor.php(在新窗口打开) 中增加超时时间:
'ffmpeg' => [
'timeout' => 7200, // 增加到2小时
],相关文件清单
| 文件路径 | 类型 | 说明 |
|---|---|---|
app/service/VideoCoverService.php(在新窗口打开) | Service | 视频封面服务 |
app/command/VideoCover.php(在新窗口打开) | Command | 命令行工具 |
config/ueditor.php(在新窗口打开) | Config | FFmpeg 配置 |
composer.json(在新窗口打开) | Config | Composer 依赖 |
app/admin/controller/Goods.php | Controller | 商品管理后台 |
app/api/controller/Goods.php | Controller | 商品 API |
