Search code examples
phplaravellaravel-5ffmpegffmpeg-php

PHP-FFMpeg: How to properly concatenate two videos?


THE SITUATION:

I need it to concatenate multiple videos into one single video.
I am using the library PHP-FFMpeg.
But I don't manage to make it working.

THE VIDEOS:

The videos are recordings made with the MediaRecorder Web API.
The video format is: video/webm;codecs=h264 The audio format is opus.

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

CONCAT USING PHP-FFMPEG (using saveFromSameCodecs):

This is how I try to concat them using saveFromSameCodecs:
(I have checked the paths and are correct)

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

But it failed with the following error message:

ffmpeg failed to execute command '/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 USING FFMPEG COMMAND LINE:

On suggestion on @RolandStarke and @LordNeckbeard I have tried using the ffmpeg command line to get a better insight on what is going on.

If I use the following command line:

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

I get the following error, related to the audio opus codec.

enter image description here

If I use the following command line, converting the audio coded to acc:

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

The final video is properly created, as a concatenation of the other videos.

CONCAT USING PHP-FFMPEG: (using saveFromDifferentCodecs)

It seems the problem is ONLY related to the codec. So I have tried using saveFromDifferentCodecs:

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

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

But I still get an error:

ffmpeg failed to execute command '/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 USING PHPFFMPEG (but with different videos):

If the problem is only related to the codec, then using two different videos with
video codec: h264 and audio codec aac,
it should work, but it doesn't:

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'

But using the command line it works smoothly: ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

CONCAT USING shell_exec:

I have tried using shell_exec, with the first two videos (opus codec):

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");

And it works smoothly. The final output is created, and with the acc audio codec.

TESTING THE LIBRARY:

To see if php-mpeg was actually working, I test it by making a basic resize of a video and it worked correctly.

RESUME:

  • Using ffmpeg command lines everything works fine
  • Using shell_exec everything works fine
  • Using php-ffmpeg I always get the error ffmpeg failed to execute command

QUESTION:

How can I concat videos using php-ffmpeg?

Is the issue caused by wrong encoding?

Thanks!


Solution

  • When encountering issues with php-ffmpeg the best approach is to copy the command from the error message and paste it in terminal. This will give you a better error message.

    In your case the the error is

    ffmpeg failed to execute command '/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

    Debugging this is a bit harder as the temp file /private/var/[...]/ffmpeg-concath1kHiX is deleted when you try to execute the ffmpeg command in the terminal. To test it you can create the temp file yourself like:

    $vidoes = [__DIR__ . '/small.mp4', __DIR__ . '/small.mp4'];
    
    file_put_contents('videolist.txt', implode("\n", array_map(function ($path) {
        return 'file ' . addslashes($path);
    }, $vidoes)));
    

    Now you can run the ffmpeg command in the terminal

    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
    

    So you your case the error is that the output file already existed. The solution is to use an other non-existing output file or delete it before concatenating your videos.

    Here an example how to concatenate files (small.mp4 taken from 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);