在视频内容管理场景中,自动生成高质量封面是提升内容点击率的重要环节,php作为常用的后端开发语言,可以结合第三方接口和本地工具实现B站AI视频封面调用以及视频最佳帧提取的功能。

环境准备
1. 基础环境要求
首先需要确保php环境版本在7.2及以上,同时安装curl扩展用于发送网络请求,安装ffmpeg工具用于视频帧提取,ffmpeg的安装可以根据服务器系统选择对应的安装包,安装完成后可以通过命令行验证是否安装成功。
2. 依赖配置
如果需要处理视频文件,还需要确保php有文件读写权限,同时如果需要调用B站相关接口,需要提前申请对应的接口权限,获取合法的调用凭证。
php调用B站AI视频封面生成实现
接口调用流程
调用B站AI视频封面生成接口的核心步骤是构造请求参数、发送POST请求、解析返回结果,以下是具体的实现代码:
<?php
/**
* 调用B站AI视频封面生成接口
* @param string $videoUrl 视频地址
* @param string $accessToken 接口调用凭证
* @return array 返回封面信息
*/
function callBilibiliAiCover($videoUrl, $accessToken) {
$apiUrl = 'https://api.ipipp.com/bilibili/ai/cover/generate';
$postData = [
'video_url' => $videoUrl,
'access_token' => $accessToken,
'cover_count' => 3 // 生成3张候选封面
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'User-Agent: PHP Bilibili Cover Client'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return ['code' => -1, 'msg' => '请求失败:' . $error];
}
$result = json_decode($response, true);
if ($result['code'] == 0) {
return ['code' => 0, 'data' => $result['data']['cover_list']];
} else {
return ['code' => $result['code'], 'msg' => $result['message']];
}
}
// 调用示例
$coverResult = callBilibiliAiCover('https://example.ipipp.com/test_video.mp4', 'your_access_token_here');
if ($coverResult['code'] == 0) {
print_r($coverResult['data']);
} else {
echo '生成封面失败:' . $coverResult['msg'];
}
?>
注意事项
- 接口地址需要根据实际申请的接口文档调整,上述地址仅为示例,实际使用时替换为官方提供的合法地址,且域名已按要求替换
- 调用凭证需要定期更新,避免过期导致接口调用失败
- 生成的封面地址需要做好存储和访问权限控制
php自动选取视频最佳帧作封面图
基于ffmpeg的帧提取逻辑
ffmpeg可以提取视频指定时间点的帧,我们可以通过提取多个时间点的帧,再根据帧的清晰度、色彩丰富度等指标选取最佳帧,以下是提取帧的核心代码:
<?php
/**
* 提取视频指定时间点的帧
* @param string $videoPath 本地视频路径
* @param int $time 提取时间点(秒)
* @param string $outputPath 输出图片路径
* @return bool 是否提取成功
*/
function extractVideoFrame($videoPath, $time, $outputPath) {
// 检查ffmpeg是否可用
exec('ffmpeg -version', $output, $returnCode);
if ($returnCode != 0) {
return false;
}
// 构造ffmpeg命令,提取指定时间的帧,输出为jpg格式
$command = sprintf(
'ffmpeg -i "%s" -ss %d -vframes 1 -q:v 2 "%s" 2>&1',
$videoPath,
$time,
$outputPath
);
exec($command, $execOutput, $execCode);
return $execCode == 0 && file_exists($outputPath);
}
/**
* 自动选取视频最佳帧
* @param string $videoPath 本地视频路径
* @param string $saveDir 封面保存目录
* @return string 最佳封面路径
*/
function selectBestVideoFrame($videoPath, $saveDir) {
if (!is_dir($saveDir)) {
mkdir($saveDir, 0755, true);
}
// 获取视频总时长
$durationCommand = sprintf('ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "%s"', $videoPath);
exec($durationCommand, $durationOutput, $durationCode);
if ($durationCode != 0 || empty($durationOutput[0])) {
return '';
}
$totalDuration = (int)$durationOutput[0];
// 提取多个时间点的帧,避免开头和结尾的片头片尾
$extractPoints = [];
if ($totalDuration > 10) {
$extractPoints = [3, (int)($totalDuration * 0.3), (int)($totalDuration * 0.5), (int)($totalDuration * 0.7), $totalDuration - 3];
} else {
$extractPoints = [1, (int)($totalDuration / 2)];
}
$frameList = [];
foreach ($extractPoints as $point) {
$framePath = $saveDir . '/frame_' . $point . '.jpg';
if (extractVideoFrame($videoPath, $point, $framePath)) {
$frameList[] = $framePath;
}
}
if (empty($frameList)) {
return '';
}
// 简单选取第一个成功提取的帧作为最佳帧,实际场景可加入清晰度检测逻辑
$bestFrame = $frameList[0];
// 将最佳帧复制到固定名称的封面文件
$coverPath = $saveDir . '/best_cover.jpg';
copy($bestFrame, $coverPath);
return $coverPath;
}
// 使用示例
$videoFile = '/data/videos/test.mp4';
$coverDir = '/data/covers';
$bestCover = selectBestVideoFrame($videoFile, $coverDir);
if (!empty($bestCover)) {
echo '最佳封面路径:' . $bestCover;
} else {
echo '提取封面失败';
}
?>
优化建议
- 可以在帧提取后加入图片清晰度检测,通过GD库计算图片的梯度值,梯度值越高说明图片越清晰
- 如果视频有黑边,可以加入黑边裁剪逻辑,提升封面美观度
- 对于大视频文件,可以先提取低分辨率帧进行检测,减少资源消耗
两种方案的选择建议
如果需要生成符合B站风格的高质量封面,优先选择调用B站AI视频封面生成接口,适合内容同步到B站场景;如果是自有平台的视频封面生成,且对成本敏感,选择ffmpeg提取最佳帧的方案更合适,两种方式也可以结合使用,先提取最佳帧作为候选,再调用AI接口优化封面效果。