摘要
最近在给客户开发短视频项目模块中遇到自动获取上传视频的时长并用于外部展示的需求。
刚开始想到用比较笨的方法,就是上传之前手动写入视频文件的大小,无奈嫌麻烦,寻求其它方法。
也是一个比较笨的方法------ ffmpeg
通过下载 ffmpeg,在面板中安装 PHP 5.6,并放开 exec 函数。在建立的新站点中,使用 PHP5.6 版本。
为了安全 PHP 5.6 允许执行外部程序,且其他站点不使用 PHP 5.6 版本,由 PHP 程序执行 ffmpeg,获取时间时长并存储到数据库中。
1、下载 ffmpeg
打开 https://www.gyan.dev/ffmpeg/builds/
点击左侧导航菜单中的 release builds,在右侧,找到,ffmpeg-release-essentials.zip ,点击以下载。
根据需要下载工具,点击左侧导航菜单中的 tools,在右侧,找到,ffmpeg-tools.zip ,点击以下载。
包含的工具有:
aviocat crypto_bench cws2fws ffescape ffeval ffhash fourcc2pixfmt graph2dot ismindex pktdumper probetest qt-faststart seek_print sidxindex venc_data_dump zmqsend
将压缩包中的 bin 目录解压,如存放在 d:\ffmpeg\bin 中。
2、设置环境变量
在"此电脑"中,点击右键,选择"属性",之后选择"高级系统设置"。
在"高级选择卡"中点击"环境变量",在"系统变量"中,找到"Path",双击编辑后,添加新的环境变量值,如 d:\ffmpeg\bin。
3、创建站点
绑定的域名,填写,127.0.0.2(只用于内部访问),PHP 版本设置为 5.6,且在禁用函数中,移除 exec。
编辑 .user.ini,增加站点目录,ffmpeg 程序目录
powershell
open_basedir="d:/wwwroot/syncvideoinfo/;D:/wwwroot/zhandian/;D:/ffmpeg/bin/;C:/Windows/Temp/;C:/Temp/;D:/BtSoft/temp/session/"
4、使用 GetVidoSize.php
因为需要设置 .env 所在目录,及解析视频地址
之后读取数据库中存储的视频地址,并获取时间,然后,写入到数据库中
php
<?php
/**
* 获取视频时间长度
*/
class GetVidoSize
{
/** @var string 锁文件路径 */
private $lockFile;
/** @var string env 配置文件路径 */
private $dbEnvFile;
/** @var string env 待解析视频目录 */
private $parseVideoDir;
function __construct()
{
$this->lockFile = "./sync.lock";
$this->dbEnvFile = "../kaoshi/.env";
$this->parseVideoDir = "../kaoshi/public";
}
public function canSync($write = false, $val = 0)
{
if ($write) {
return file_put_contents($this->lockFile, $val) ? true : false;
}
$data = file_get_contents($this->lockFile);
if ($data) {
return false;
} else {
return true;
}
}
public function getVideoMins($file)
{
$command = "ffmpeg -i " . $file . " 2>&1";
exec($command, $output);
// 从输出中提取视频信息
$line = implode('', $output);
// 提取视频时长
if (preg_match("/Duration: (.*?), /", $line, $matches)) {
$time = explode(':', $matches[1]);
return (intval($time[0]) * 60 * 60) + intval($time[1]) * 60 + intval($time[2]);
}
return 0;
}
/**
* @throws Exception
*/
public function sync()
{
$res = [
'count' => 0,
'list' => [],
];
if (!$this->canSync()) {
throw new Exception("Please hold on ...");
}
$this->canSync(true, date('Y-m-d H:i:s'));
$dbConfig = parse_ini_file($this->dbEnvFile, true);
try {
// 创建连接
$conn = new PDO("mysql:host={$dbConfig['database']['hostname']};dbname={$dbConfig['database']['database']}",
$dbConfig['database']['username'],
$dbConfig['database']['password']);
// 设置 PDO 错误模式为异常
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$list = $conn->query("SELECT id,moive_file FROM fa_exam_course_movie where mins=0");
$res['count'] = count($list->rowCount() > 0 ? $list : []);
foreach ($list as $row) {
$t = time();
$sec = $this->getVideoMins($this->parseVideoDir . $row['moive_file']);
// SQL 更新语句
$sql = "update fa_exam_course_movie set mins=:sec,updatetime=:t where id=:id";
// 预处理 SQL 语句
$stmt = $conn->prepare($sql);
// 绑定参数
$stmt->bindParam(':sec', $sec);
$stmt->bindParam(':t', $t);
$stmt->bindParam(':id', $row['id']);
// 执行更新操作
$stmt->execute();
$res['list'][] = [
'id' => $row['id'],
'moive_file' => $row['moive_file'],
'length' => $sec,
'status' => $stmt->rowCount(),
];
}
} catch (PDOException $e) {
throw new Exception($e->getMessage());
}
// 关闭连接
$conn = null;
$this->canSync(true, 0);
return $res;
}
}
try {
$data = (new SyncVideo())->sync();
echo date('Y-m-d H:i:s'), " count: ", $data['count'], PHP_EOL;
foreach ($data['list'] as $v) {
echo $v['id'], "\t", $v['moive_file'], "\t", $v['length'], "\t", $v['status'], PHP_EOL;
}
} catch (Exception $e) {
echo $e;
}
// 程序正常退出
exit(0);
5、增加计划任务
任务类型为,访问 URL,每1分钟访问一次,地址为 http://127.0.0.1/GetVidoSize.php
OK 到此就完成了,虽然说方法还是有点笨 但是至少可以实现。
版权声明 草邦软件开发 草邦CMS系统 草邦办公管理系统 草邦媒介资源系统
本软件不提供任何形式的明示或暗示担保,包括但不限于对适销性,特定目的的适用性和非侵权性的担保。无论是由于软件,使用或其他方式产生的,与之有关或与之有关的合同,侵权或其他形式的任何索赔,损害或其他责任,作者或版权所有者概不负责。