PHP 和 FFMPEG - 执行智能视频转换

2023-12-11

我有一项异常困难的任务要执行。我以为这很容易,但我的所有努力都没有结果。

我正在将上传到 php 脚本的视频从各种格式(.avi、.mpg、.wmv、.mov 等)转换为单一 .flv 格式。转换效果很好,但我遇到的问题是视频的分辨率。

这是我当前正在运行的命令(使用 PHP 变量):

ffmpeg -i $original -ab 96k -b 700k -ar 44100 -s 640x480 -acodec mp3 $converted

$original 和 $converted 都包含这些文件的完整路径。我的问题是,即使源较小,它也总是会转换为 640x480(就像我告诉它的那样)。显然,这在下载视频时浪费了磁盘空间和带宽。此外,这并没有考虑到输入视频的宽高比不是 4:3,如果我上传 16:9 视频,会导致“压缩”转换。

我需要做三件事:

  1. 确定原始视频的宽高比。
  2. 如果不是 4:3,则用黑条填充顶部和底部。
  3. 如果原件尺寸较大或与原件宽度/高度相关的 4:3 纵横比(以更接近 640x480 为准),则转换为 640x480。

我已经跑了ffmpeg -i在一些视频上,但我没有看到一致的格式或位置来查找原始分辨率。一旦我能够弄清楚这一点,我知道我可以“进行数学计算”来计算出正确的尺寸并指定填充以使用 -padttop、-padbottom 等来固定纵横比。


好的。我有一个功能齐全的解决方案。这适用于任何发现这个问题并想做同样事情的人。我的代码可能不是很优雅,但它可以完成工作。


获取 FFMPEG 的输出

首先,我必须获得 ffmpeg -i 的输出,这本身就是一个挑战。感谢霸主的回答我的另一个问题,我终于能够让它工作了2>&1在我的命令结束时。感谢埃弗特对这个问题的回答,我能够用以下命令解析输出preg_match找到原始文件的高度和宽度。

function get_vid_dim($file)
{
    $command = '/usr/bin/ffmpeg -i ' . escapeshellarg($file) . ' 2>&1';
    $dimensions = array();
    exec($command,$output,$status);
    if (!preg_match('/Stream #(?:[0-9\.]+)(?:.*)\: Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)/',implode('\n',$output),$matches))
    {
        preg_match('/Could not find codec parameters \(Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)\)/',implode('\n',$output),$matches);
    }
    if(!empty($matches['width']) && !empty($matches['height']))
    {
        $dimensions['width'] = $matches['width'];
        $dimensions['height'] = $matches['height'];
    }
    return $dimensions;
}

确定最佳尺寸

我编写此函数是为了确定用于转换的最佳尺寸。它采用原始尺寸、目标尺寸以及是否强制转换为目标纵横比(根据其宽度/高度确定)。目标尺寸始终是该函数可以返回的最大结果。

function get_dimensions($original_width,$original_height,$target_width,$target_height,$force_aspect = true)
{
    // Array to be returned by this function
    $target = array();
    // Target aspect ratio (width / height)
    $aspect = $target_width / $target_height;
    // Target reciprocal aspect ratio (height / width)
    $raspect = $target_height / $target_width;

    if($original_width/$original_height !== $aspect)
    {
        // Aspect ratio is different
        if($original_width/$original_height > $aspect)
        {
            // Width is the greater of the two dimensions relative to the target dimensions
            if($original_width < $target_width)
            {
                // Original video is smaller.  Scale down dimensions for conversion
                $target_width = $original_width;
                $target_height = round($raspect * $target_width);
            }
            // Calculate height from width
            $original_height = round($original_height / $original_width * $target_width);
            $original_width = $target_width;
            if($force_aspect)
            {
                // Pad top and bottom
                $dif = round(($target_height - $original_height) / 2);
                $target['padtop'] = $dif;
                $target['padbottom'] = $dif;
            }
        }
        else
        {
            // Height is the greater of the two dimensions relative to the target dimensions
            if($original_height < $target_height)
            {
                // Original video is smaller.  Scale down dimensions for conversion
                $target_height = $original_height;
                $target_width = round($aspect * $target_height);
            }
            //Calculate width from height
            $original_width = round($original_width / $original_height * $target_height);
            $original_height = $target_height;
            if($force_aspect)
            {
                // Pad left and right
                $dif = round(($target_width - $original_width) / 2);
                $target['padleft'] = $dif;
                $target['padright'] = $dif;
            }
        }
    }
    else
    {
        // The aspect ratio is the same
        if($original_width !== $target_width)
        {
            if($original_width < $target_width)
            {
                // The original video is smaller.  Use its resolution for conversion
                $target_width = $original_width;
                $target_height = $original_height;
            }
            else
            {
                // The original video is larger,  Use the target dimensions for conversion
                $original_width = $target_width;
                $original_height = $target_height;
            }
        }
    }
    if($force_aspect)
    {
        // Use the target_ vars because they contain dimensions relative to the target aspect ratio
        $target['width'] = $target_width;
        $target['height'] = $target_height;
    }
    else
    {
        // Use the original_ vars because they contain dimensions relative to the original's aspect ratio
        $target['width'] = $original_width;
        $target['height'] = $original_height;
    }
    return $target;
}

Usage

以下是您将从中获得的一些示例get_dimensions()为了让事情更清楚:

get_dimensions(480,360,640,480,true);
-returns: Array([width] => 480, [height] => 360)

get_dimensions(480,182,640,480,true);
-returns: Array([padtop] => 89, [padbottom] => 89, [width] => 480, [height] => 360)

get_dimensions(480,182,640,480,false);
-returns: Array([width] => 480, [height] => 182)

get_dimensions(640,480,480,182,true);
-returns: Array([padleft] => 119, [padright] => 119, [width] => 480, [height] => 182)

get_dimensions(720,480,640,480,true);
-returns: Array([padtop] => 27, [padbottom] => 27, [width] => 640, [height] => 480)

get_dimensions(720,480,640,480,false);
-returns: Array([width] => 640, [height] => 427)

成品

现在,把它们放在一起:

$src = '/var/videos/originals/original.mpg';
$original = get_vid_dim($src);
if(!empty($original['width']) && !empty($original['height']))
{
    $target = get_dimensions($original['width'],$original['height'],640,480,true);
    $command = '/usr/bin/ffmpeg -i ' . $src . ' -ab 96k -b 700k -ar 44100 -s ' . $target['width'] . 'x' . $target['height'];
    $command .= (!empty($target['padtop']) ? ' -padtop ' . $target['padtop'] : '');
    $command .= (!empty($target['padbottom']) ? ' -padbottom ' . $target['padbottom'] : '');
    $command .= (!empty($target['padleft']) ? ' -padleft ' . $target['padleft'] : '');
    $command .= (!empty($target['padright']) ? ' -padright ' . $target['padright'] : '');
    $command .= ' -acodec mp3 /var/videos/converted/target.flv 2>&1';

    exec($command,$output,$status);

    if($status == 0)
    {
        // Success
        echo 'Woohoo!';
    }
    else
    {
        // Error.  $output has the details
        echo '<pre>',join('\n',$output),'</pre>';
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PHP 和 FFMPEG - 执行智能视频转换 的相关文章

  • 从浏览器中删除cookie?

    有什么方法可以指示网络浏览器完全delete一个人的cookie是用PHP设置的吗 我不想expiry或者等待浏览器closed 对于删除 我的意思是实际上不再将其列在 cookie 列表中 尝试这样删除所有 cookie foreach
  • PHP 如何使用比较运算符比较字符串?

    我正在使用比较运算符来比较字符串 我需要对以下两个比较及其结果进行某种解释 if ai gt i echo Yes else echo No output No 为什么这些会这样输出 if ia gt i echo Yes else ech
  • fputcsv 和记事本

    我使用 fputcsv 生成 csv 文件 它工作得很好 但是当我在记事本 Windows 中查看 csv 文件时 没有新行 所有行都在 1 行中 并且在应该换行的地方有一个正方形 损坏的字符 例如 Mac 上的其他编辑器可以正确显示带有中
  • 更改laravel视图页面中的日期格式[重复]

    这个问题在这里已经有答案了 我想更改从数据库获取的日期格式 现在我得到了 2016 10 01 user gt from date 我想更改 laravel 5 3 中的格式 d m y user gt from date gt forma
  • Laravel中间件获取路由参数

    我正在编写诸如 学校俱乐部管理系统 之类的东西 并遇到一些资源授权问题 假设有club and club有经理 我想检查用户是否是经理club在他可以使用中间件管理它之前 使用 Laravel 5 2 My router看起来像这样 Rou
  • 多个提交按钮

    我在 HTML 和 PHP 中遇到多个提交按钮时遇到问题 我尝试为基于 Web 的计算器编写 GUI 代码 这确实很容易 但是 php 中的函数并不那么容易 所以我有这个简单的 GUI 有 6 个提交按钮
  • 从 Magento 产品视图中的可配置产品中获取所有简单产品

    如何获取与可配置产品关联的所有简单产品 我找到了如何做相反的事情 从简单的产品获得可配置的产品 但这不是我需要的 我想显示所选产品的库存数量 可配置属性 我最初的想法是打印所有数量的库存并用 jQuery 控制显示 任何想法 使用下面的代码
  • php 验证十进制格式的纬度/经度字符串

    好吧 我有一个巨大的经度和纬度坐标列表 也就是说 我还有一些来源来提取这些坐标 其中一些来自 get post 方法 这可能会导致我的网站 服务中存在潜在的安全漏洞 所以我想弄清楚如何通过 PHP 验证经度和纬度 我正在考虑通过 preg
  • 让 PHPUnit 忽略一些事情?

    我有一个 PHPUnit 测试类 我希望在测试运行中忽略它 我知道我可以通过重命名它来做到这一点 以便它的文件名中不包含 测试 一词 但我不想这样做 因为它比我想要的更混乱了源代码控制水域 有人有建议吗 有几个选项phpunit命令可以帮助
  • Sphinx错误:搜索请求中未知的本地索引“INDEX_NAME”[已关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我使用 Sphinx 0 9 9 r
  • PHP Define() 似乎不能与 include() 一起使用

    我一直在尝试 OO PHP 目前拥有三个文件 我有一个 class lib php 目前它只有一个databaseServer 类 一个index php 文件和一个definitions php 文件 我想将所有敏感数据库信息放入定义文件
  • PHP:CURL 可以遵循元重定向吗

    CURL 可以使用 CURLOPT FOLLOWLOCATION 遵循标头重定向 但是否可以遵循元刷新重定向 Thanks 是的 但您必须自己解析响应并查找类似以下内容 Obeying 刷新请求是浏览器端的事情 使用DOM解析来查找cURL
  • 如何限制注册用户尝试投票两次[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 php 编码和网站设计非常陌生 我正在尝试开发一个在线投票系统 只允许注册用户投票 已完成所有操作并且工作正常 但我需要的帮助是
  • 如何跨页面播放背景音乐

    我已经读过这个问题 我知道它只能用框架来完成 我真的不想要全站点 AJAX 如何在多个 HTML 页面上播放背景音频 https stackoverflow com questions 4210370 how to play a backg
  • PHP 中的依赖注入

    我一直在研究依赖注入 我是在关注某件事还是完全没有关注 代码是好是坏 依赖注入与否 下面的代码是CMS系统的基础 现在有一个名为 page details 的表 其中存储了所有网页 目录 文件结构 htaccess index php cl
  • 使用PHP将大文件上传到谷歌云存储

    我正在尝试将大文件从服务器上传到云存储 文件超过 500mb 但 PHP 超时 我尝试查看 Google 客户端库文档 并在 stackoverflow 中进行爬行 但找不到任何可以帮助我的内容 还有有什么办法可以跟踪上传进度吗 这是我目前
  • Laravel 自定义授权

    我在这里进行登录验证 LoginData Input except array token if Auth attempt LoginData return success 我的表不同 所以这里我更改表名称auth php table gt
  • 限制在WhereHas内

    所以我想获取最后状态等于给定状态的请求 我尝试过first 但它给了我一个错误并且限制不起作用 requests Request whereHas requestStatus function query use status return
  • print_r 的替代方案(仅显示最多 2 3 个键)

    我有一个multi dimensional array有 200 个键 每个键有 3 到 5 个数组 我想知道有什么方法可以只看到有限的部分 即最多 3 或 4 个键 因为如果我使用print r desiredArray 然后花费了太多时
  • 如何使用 PHP 读取/显示 XML

    有没有办法使用 PHP 读取 external xml 来自不同网站的 xml 文件 我知道有一种方法可以使用 JavaScript 读取 XML 但前提是它们都位于同一根目录中 您能否提供有关如何获取 xml 文件的示例 然后阅读以下内容

随机推荐