Laravel FFMpeg

repository·main·Indexed 23 days ago

https://github.com/protonemedia/laravel-ffmpeg

A wrapper around PHP-FFMpeg that integrates with Laravel's Filesystem, configuration, and logging systems for video processing. It supports audio/video conversion, HLS adaptive bitrate streaming with AES-128 encryption, frame extraction, watermarking, and video tiling. The library provides tools for monitoring transcoding progress, handling encoding exceptions, and managing temporary files from remote disks.

Tokens
11.6K
Snippets
28
Records
72
Agent score
81%

What's inside laravel-ffmpeg

  1. Access the underlying Media object

    main

    The object returned by open() is a ProtoneMedia\LaravelFFMpeg\MediaOpener. It uses dynamic method calls to proxy requests to the underlying driver (e.g., PHP-FFMpeg).

    • Proxying: You can call methods that exist on the underlying driver directly on the MediaOpener instance.
    • Direct Access: To get the actual underlying driver instance, call the object as a function (invoke it).
  2. Encrypt HLS segments with AES-128

    main

    To secure HLS exports, use withEncryptionKey() on the HLS exporter.

    • Generate a key: Use ProtoneMedia\LaravelFFMpeg\Exporters\HLSExporter::generateEncryptionKey().
    • Custom filename: The default filename is secret.key, but you can pass a second argument to withEncryptionKey() to change it.

    Warning: You must store the generated key securely; the exported video cannot be played without it.

    use ProtoneMedia\LaravelFFMpeg\Exporters\HLSExporter;
    
    $encryptionKey = HLSExporter::generateEncryptionKey();
    
    FFMpeg::open('steve_howe.mp4')
        ->exportForHLS()
        ->withEncryptionKey($encryptionKey)
        ->addFormat($lowBitrate)
        ->addFormat($midBitrate)
        ->addFormat($highBitrate)
        ->save('adaptive_steve.m3u8');
  3. Convert audio or video files

    main

    You can convert files by specifying a source disk, opening a file, defining an export format, and choosing a destination disk and filename. Use fromDisk($disk) to specify the source disk, or fromFilesystem($filesystem) to use an instance of Illuminate\\Contracts\\Filesystem\\Filesystem.

    FFMpeg::fromDisk('songs')
        ->open('yesterday.mp3')
        ->export()
        ->toDisk('converted_songs')
        ->inFormat(new \FFMpeg\Format\Audio\Aac)
        ->save('yesterday.aac');
  4. Create an HLS (M3U8) playlist

    main

    You can export videos to HLS format to enable adaptive bitrate streaming. Use exportForHLS() on an opened media file. You can define multiple bitrates using addFormat() to create an adaptive stream.

    Key methods:

    • setSegmentLength(int): Set the duration of each segment (optional).
    • setKeyFrameInterval(int): Set the keyframe interval (optional).
    • keepAllAudioStreams(): By default, HLS exports only include the first audio stream (0:a:0). Call this to include all audio streams.
    $lowBitrate = (new X264)->setKiloBitrate(250);
    $midBitrate = (new X264)->setKiloBitrate(500);
    $highBitrate = (new X264)->setKiloBitrate(1000);
    
    FFMpeg::fromDisk('videos')
        ->open('steve_howe.mp4')
        ->exportForHLS()
        ->setSegmentLength(10)
        ->setKeyFrameInterval(48)
        ->addFormat($lowBitrate)
        ->addFormat($midBitrate)
        ->addFormat($highBitrate)
        ->save('adaptive_steve.m3u8');
  5. Install Laravel FFMpeg

    main

    To use Laravel FFMpeg, ensure you have the latest version of FFmpeg installed on your system by running ffmpeg -version. Then, install the package via Composer.

    If you are not using Laravel's Package Discovery, you must manually register the Service Provider and the Facade in your config/app.php file. Finally, publish the configuration file to your application using the Artisan CLI.

  6. Upgrade to v8

    main

    When upgrading to version 8, note the following breaking changes and configuration updates:

    • Exceptions: The set_command_and_error_output_on_exception config key now defaults to true, providing more informative error messages.
    • Logging: The enable_logging key has been replaced by log_channel. To disable logging entirely, set log_channel to false.
    • HLS Exports: The segment length and keyframe interval for HLS exports must now be 2 or greater.
    • Compatibility: This version requires Laravel 9+ due to the migration from Flysystem 1.x to 3.x. It is not compatible with Laravel 8 or earlier.
    • Watermarks: If using watermark manipulation, ensure spatie/image is upgraded to v2.
  7. Rotate encryption keys for HLS

    main

    For higher security, you can rotate the encryption key for every segment using withRotatingEncryptionKey().

    • Callback: The method accepts a callback that receives the $filename and $contents of the key. Use this to save keys to your database or storage.
    • Rotation Interval: You can specify how many segments should share the same key by passing a second integer argument. The default is 1 (one key per segment).

    Performance Tip: On slow filesystems, rotating keys might cause encoding exceptions like No key URI specified in key info file. To mitigate this, you can set a tmpfs filesystem (like /dev/shm on Linux) in the temporary_files_encrypted_hls config key.

    FFMpeg::open('steve_howe.mp4')
        ->exportForHLS()
        ->withRotatingEncryptionKey(function ($filename, $contents) {
            $videoId = 1;
            // Store the encryption keys (e.g., in DB or Storage)
            Storage::disk('secrets')->put($videoId . '/' . $filename, $contents);
        })
        ->addFormat($lowBitrate)
        ->addFormat($midBitrate)
        ->addFormat($highBitrate)
        ->save('adaptive_steve.m3u8');
    
    // To rotate every 10 segments:
    // ->withRotatingEncryptionKey($callable, 10);
  8. Upgrade to v7

    main

    When upgrading to version 7, note the following major changes:

    • Namespacing: The namespace has changed to ProtoneMedia\LaravelFFMpeg. The Facade is now ProtoneMedia\LaravelFFMpeg\Support\FFMpeg and the Service Provider is ProtoneMedia\LaravelFFMpeg\Support\ServiceProvider.
    • Filters: While chaining exports is still supported, you must reapply filters for each export.
    • HLS Changes:
      • Playlists now include bitrate, framerate, and resolution data.
      • Segments use a new naming pattern.
      • HLS export is now executed as a single job using FFmpeg's map and filter_complex features instead of separate jobs. You may need to replace addFilter with addLegacyFilter or migrate filters manually.
  9. Protect HLS keys using DynamicHLSPlaylist

    main

    To prevent unauthorized access to HLS segments and keys, use the DynamicHLSPlaylist class. This allows you to serve playlists through Laravel routes where you can implement authentication/authorization (e.g., via Gates or Middleware).

    Instead of linking directly to a file on a public disk, you use FFMpeg::dynamicHLSPlaylist() to resolve paths dynamically via three resolvers:

    1. setKeyUrlResolver: Maps a relative key path to a secure route/URL.
    2. setMediaUrlResolver: Maps a relative media segment path to a public URL.
    3. setPlaylistUrlResolver: Maps a relative playlist path to a route/URL.

    The DynamicHLSPlaylist instance implements Illuminate\Contracts\Support\Responsable, so it can be returned directly from a controller.

    // Route to serve the actual key file securely
    Route::get('/video/secret/{key}', function ($key) {
        return Storage::disk('secrets')->download($key);
    })->name('video.key');
    
    // Route to serve the dynamic playlist
    Route::get('/video/{playlist}', function ($playlist) {
        return FFMpeg::dynamicHLSPlaylist()
            ->fromDisk('public')
            ->open($playlist)
            ->setKeyUrlResolver(function ($key) {
                return route('video.key', ['key' => $key]);
            })
            ->setMediaUrlResolver(function ($mediaFilename) {
                return Storage::disk('public')->url($mediaFilename);
            })
            ->setPlaylistUrlResolver(function ($playlistFilename) {
                return route('video.playlist', ['playlist' => $playlistFilename]);
            });
    })->name('video.playlist');
  10. Configure Service Provider and Facade manually

    main

    If Package Discovery is disabled, add the following to your config/app.php file:

    'providers' => [
        ...
        ProtoneMedia\LaravelFFMpeg\Support\ServiceProvider::class,
        ...
    ],
    
    'aliases' => [
        ...
        'FFMpeg' => ProtoneMedia\LaravelFFMpeg\Support\FFMpeg::class
        ...
    ];
    // config/app.php
    
    'providers' => [
        ...
        ProtoneMedia\LaravelFFMpeg\Support\ServiceProvider::class,
        ...
    ];
    
    'aliases' => [
        ...
        'FFMpeg' => ProtoneMedia\LaravelFFMpeg\Support\FFMpeg::class
        ...
    ];
  11. Manage media with the PHPFFMpeg driver

    main

    The PHPFFMpeg class is the primary driver used to interact with media files via the underlying PHP-FFMpeg library. It acts as a wrapper that provides Laravel-friendly methods for opening media collections, handling video/audio types, and managing complex operations like concatenation or frame extraction.

    Key capabilities include:

    • Opening Media: You can open a single file or a MediaCollection (which can trigger 'Advanced' mode for multiple files).
    • Type Checking: Determine if the currently opened media is a Video, Audio, Frame, or Concat object.
    • Fluent Interface: Most methods return $this to allow chaining, or return a new media object when the state changes (e.g., extracting a frame).
    • Event & Listener Support: Attach listeners or event handlers to the underlying driver to monitor progress or lifecycle events.