Manipulating Videos in PHP

Handling video is something that I have been avoiding for several years. And now in order to save some server space, I am forced to learn how this thing works.

So if you want you can come along for the ride.

To start we need FFmpeg which is "A complete, cross-platform solution to record, convert and stream audio and video".

I'm on a Mac so I will use Homebrew.

brew install ffmpeg

Now let's use Lambo to create a test Laravel project to mess around with.

lambo ffmpeg-test

Now we could use some fancy shell interaction to handle resizing and transcoding some videos but instead, we will use PHP-FFMpeg a library written specifically for interacting with FFmpeg through PHP.

composer require php-ffmpeg/php-ffmpeg

Now let's go into our web.php route file and create a new instance.

Route::get('/', function () {

    $ffmpeg = FFMpeg\FFMpeg::create([
        // We need to pass in the path to our ffmpeg binary
        // You can find this by running `which ffmpeg`
        'ffmpeg.binaries'  => '/usr/local/bin/ffmpeg',

        // We also need to pass in the path to our ffprobe binary
        // You can find this by running `which ffprobe`
        'ffprobe.binaries' => '/usr/local/bin/ffprobe',

        // Set the number of threads ffmpeg can use
        'ffmpeg.threads'  => 12,
    ]);

});

Next, let's have some fun with some videos!

Converting a Video

So one of the most important things one would want to do with videos is transcoding or converting to a different format.

This is how we can do that with FFmpeg:

// inside the "/" route closure

// Use the Storage Facade to get the path to an .mov file
$video = $ffmpeg->open(Storage::disk('local')->path('test.mov'));

// Create a Format to convert to. This is an mp4 format with an mp3 audio codec
$format = (new FFMpeg\Format\Video\X264())->setAudioCodec("libmp3lame");

// Save the video using the created format
$video->save($format, Storage::disk('local')->path('small.mp4'));

And that's all there is to it. You can find all the different video formats here.

Resizing

We can also resize videos like this:

// get the $video and create the $format

$video->filters()
    ->resize(new FFMpeg\Coordinate\Dimension(1280, 720));

// Save the video using the created format
$video->save($format, Storage::disk('local')->path('small.mp4'));

This will resize the video without retaining the aspect ratio. If your video might not already be a 16:9 aspect ratio you would want to use the pad() method:

$video->filters()
    ->pad(new FFMpeg\Coordinate\Dimension(1280, 720));

Which will just add either vertical or horizontal padding based on what the video needs to fit the size you passed.

How about thumbnails?

So if we were building something like Vimeo or Youtube we need video thumbnails. FFmpeg can get a frame of a video and return it as an image.

We can do this in PHP-FFmpeg using the frame() method on the Video class. Let's give it a try:

$video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(1))
    ->save(Storage::disk('local')->path('frame.jpg'));

It's that easy!

Now there are a lot of other things you can do with FFmpeg and the PHP-FFmpeg library like:

And a whole lot of others that I will not be covering in this post.

In Closing

Editing video using php may seem hard, at least it did to me. But there are libraries out there (like PHP-FFmpeg) made by amazing people that make it super easy.