PHP-FFMpeg:如何正确连接两个视频?

PHP-FFMpeg: How to properly concatenate two videos?

情况:

我需要它将多个视频连接成一个视频。
我正在使用库 PHP-FFMpeg
但我无法让它工作。

视频:

这些视频是用 MediaRecorder Web API 录制的。
视频格式为:video/webm;codecs=h264 音频格式为 opus.

recorder = new MediaRecorder(this.stream, {
  mimeType: 'video/webm;codecs=h264'
})

CONCAT 使用 PHP-FFMPEG(使用 saveFromSameCodecs):

这就是我尝试使用 saveFromSameCodecs 连接它们的方式:
(我已经检查过路径并且是正确的)

$video = $ffmpeg->open( $path1 );
$video
    ->concat([$path1, $path2])
    ->saveFromSameCodecs($path_output, TRUE);

但失败并显示以下错误消息:

ffmpeg 执行命令失败 '/usr/local/bin/ffmpeg' '-f' 'concat' '-safe' '0' '-i' '/private/var/folders/dw/919v2nds7s78pz_qhp7z9rcm0000gn/T/ffmpeg-concath1kHiX' ' -c' 'copy' '/Users/francescomussi/Desktop/Apps/cameraProject/back-end/camera-laravel/storage/app/public/videos/output.mp4'

CONCAT 使用 FFMPEG 命令行:

关于@RolandStarke 和@LordNeckbeard 的建议,我尝试使用 ffmpeg command line 来更好地了解正在发生的事情。

如果我使用以下命令行:

ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

我收到以下错误,与 audio opus 编解码器有关。

如果我使用以下命令行,将音频编码转换为acc:

ffmpeg -f concat -safe 0 -i mylist.txt -c:v copy -c:a aac output.mp4

最终视频已正确创建,作为其他视频的串联。

CONCAT 使用 PHP-FFMPEG:(使用 saveFromDifferentCodecs)

看来问题只与编解码器有关。 所以我尝试使用 saveFromDifferentCodecs:

$format = new FFMpeg\Format\Video\X264('libfdk_aac', 'libx264');

$result = $video1
    ->concat([$path1, $path2])
    ->saveFromDifferentCodecs($format, $output_path);

但我仍然得到一个错误:

ffmpeg 执行命令失败 '/usr/local/bin/ffmpeg' '-i' '/Users/francescomussi/Desktop/Apps/cameraProject/back-end/camera-laravel/storage/app/public/videos/test1.mp4' '-i' '/Users/francescomussi/Desktop/Apps/cameraProject/back-end/camera-laravel/storage/app/public/videos/test2.mp4' '-filter_complex' '[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]' '-map' '[v]' '-map' '[a]' '-b:a' '128k' '/Users/francescomussi/Desktop/Apps/cameraProject/back-end/camera-laravel/storage/app/public/videos/output.mp4'

CONCAT 使用 PHPFFMPEG(但视频不同):

如果问题仅与编解码器有关,则使用两个不同的视频与
视频编解码器:h264 和音频编解码器 aac
它应该工作,但它没有:

ffmpeg failed to execute command '/usr/local/bin/ffmpeg' '-f' 'concat' '-safe' '0' '-i' '/private/var/folders/dw/919v2nds7s78pz_qhp7z9rcm0000gn/T/ffmpeg-concatoJGhLt' '-c' 'copy' '/Users/francescomussi/Desktop/Apps/cameraProject/back-end/camera-laravel/storage/app/public/videos/output.mp4'

但是使用命令行它工作顺利:ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

CONCAT 使用 shell_exec:

我已经尝试使用 shell_exec,前两个视频(opus 编解码器):

echo shell_exec("/usr/local/bin/ffmpeg -f concat -safe 0 -i /Users/francescomussi/Desktop/Apps/cameraProject/back-end/camera-laravel/mylist.txt -c:v copy -c:a aac /Users/francescomussi/Desktop/Apps/cameraProject/back-end/camera-laravel/output.mp4 2>&1");

并且运行顺利。 最终输出已创建,并带有 acc 音频编解码器。

正在测试库:

为了查看 php-mpeg 是否实际工作,我通过对视频进行基本调整大小来测试它并且它工作正常。

简历:

问题:

如何使用 php-ffmpeg 连接视频?

是否编码错误导致的问题?

谢谢!

当遇到 php-ffmpeg 问题时,最好的方法是从错误消息中复制命令并将其粘贴到终端中。这会给你一个更好的错误信息。

在你的情况下,错误是

ffmpeg 执行命令失败 '/usr/local/bin/ffmpeg' '-f' 'concat' '-safe' '0' '-i' '/private/var/folders/dw/919v2nds7s78pz_qhp7z9rcm0000gn/T/ffmpeg-concath1kHiX' ' -c' 'copy' '/Users/francescomussi/Desktop/Apps/cameraProject/back-end/camera-laravel/storage/app/public/videos/output.mp4

调试这有点困难,因为临时文件 /private/var/[...]/ffmpeg-concath1kHiX 在您尝试执行 ffmpeg 命令时被删除在终端。要测试它,您可以自己创建临时文件,例如:

$vidoes = [__DIR__ . '/small.mp4', __DIR__ . '/small.mp4'];

file_put_contents('videolist.txt', implode("\n", array_map(function ($path) {
    return 'file ' . addslashes($path);
}, $vidoes)));

现在你可以运行终端中的ffmpeg命令

ffmpeg -f concat -safe 0 -i videolist.txt -c copy /Users/[...]/videos/output.mp4
#[...]
#File '/Users/[...]/videos/output.mp4' already exists. Overwrite ? [y/N] 
#Not overwriting - exiting

所以你的情况错误是输出文件已经存在。解决方案是使用其他不存在的输出文件或在连接视频之前将其删除。

这里是一个如何连接文件的例子(small.mp4 取自http://techslides.com/sample-webm-ogg-and-mp4-video-files-for-html5

<?php

require 'vendor/autoload.php';

$ffmpeg = FFMpeg\FFMpeg::create();
$video = $ffmpeg->open(__DIR__ . '/small.mp4'); 
$video
    ->concat([__DIR__ . '/small.mp4', __DIR__ . '/small.mp4'])
    ->saveFromSameCodecs(__DIR__ . '/out-'.  time() . '.mp4', true);

正确答案来自@RolandStarke。
在这里我只是想整理一个建议列表,这些建议可能对调试处理 ffmpeg 的其他类似问题有用:

  1. 重新安装 ffmpeg。它可能是缺少选项或缺少编解码器。以下是安装方法(针对 mac),包括所有可能的选项(2018 年 9 月)。我花了 30 分钟所以请耐心等待。

    brew install ffmpeg --with-chromaprint --with-fdk-aac --with-fontconfig --with-freetype --with-frei0r --with-game-music-emu --with-libass --with-libbluray --with-libbs2b --with-libcaca --with-libgsm --with-libmodplug --with-librsvg --with-libsoxr --with-libssh --with-libvidstab --with-libvorbis --with-libvpx --with-opencore-amr --with-openh264 --with-openjpeg --with-openssl --with-opus --with-rtmpdump --with-rubberband --with-sdl2 --with-snappy --with-speex --with-srt --with-tesseract --with-theora --with-tools --with-two-lame --with-wavpack --with-webp --with-x265 --with-xz --with-zeromqlibzeromq --with-zimg

    要获得更新的选项列表,您可以 运行: brew options ffmpeg 或 google 它。

  2. 尝试做你正在尝试做的同样的事情,但只使用 ffmpeg 命令行。它将更有洞察力和更好的错误报告。例如对于连接:

    ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

  3. 检查 PHP-FFMpeg 是否正常工作。 Concat 是有点难度的操作。您可以尝试使用更简单的一个,看看它是否正常工作以及库是否已正确安装。例如你可以尝试一个简单的转换:

    FFMpeg::fromDisk('local') ->open('public/videos/test.mp4') ->export() ->toDisk('local') ->inFormat(new FFMpeg\Format\Video\X264('libmp3lame', 'libx264')) ->save('public/videos/converted_test.mp4');

  4. 仔细检查每条路径。在 concat 的情况下,确保输出文件不存在。

  5. 可能是编码问题。尝试使用不同编解码器的其他类型的文件,看看这是否真的是问题所在。如果您可以事先转换为正确的编解码器。

  6. 在源代码中添加换行符。在我的例子中,我得到了一般错误:Unable to save concatenated video。这是源代码:

    try { $this->driver->command($commands); } catch (ExecutionFailureException $e) { $this->cleanupTemporaryFile($outputPathfile); $this->cleanupTemporaryFile($sourcesFile); throw new RuntimeException('Unable to save concatenated video', $e->getCode(), $e); }

    但如果我转储执行然后将其终止,就在该块之前:

    dd($this->driver->command($commands));

    它给了我更详细的错误信息。

    您还可以转储命令数组:dd($commands);

  7. 最后这里有一个与 PHP-FFMpeg 类似的问题列表,您可以查看是否已经给出了解决方案:https://github.com/pascalbaljetmedia/laravel-ffmpeg/wiki/FFmpeg-failed-to-execute-command

如果您有其他建议,请随时发表评论或编辑答案。