protonemedia / laravel-ffmpeg

This package provides an integration with FFmpeg for Laravel. Laravel's Filesystem handles the storage of the files.
https://protone.media/en/blog/how-to-use-ffmpeg-in-your-laravel-projects
MIT License
1.62k stars 193 forks source link

fix: Remove EXT-X-ENDLIST from master playlist file #519

Open dave-nicholas opened 6 months ago

dave-nicholas commented 6 months ago

I am a contributor on the shaka project and noticed that playback was broken with this library. This PR fixes a bug in the master playlist and allows playback with shaka (and probably other players where playback previously failed).

Unlike the EXTM3U element which is required at the start every Media Playlist and every Master Playlist. The EXT-X-ENDLIST should only appear in a Media Playlist file.

exxsy commented 2 months ago

Yeah EXT-X-ENDLIST line causes shaka player to throw error

exxsy commented 2 months ago

If you just dont want to wait PR,

Create a PlaylistGenerator for this case, like this one.

namespace App\PlaylistGenerators;

class HLSExtendedGenerator implements PlaylistGenerator
{
    public const PLAYLIST_START = '#EXTM3U';

    private function getStreamInfoLine(Media $segmentPlaylistMedia, string $key): string
    {
        $segmentPlaylist = $segmentPlaylistMedia->getDisk()->get(
            $segmentPlaylistMedia->getDirectory() . HLSExporter::generateTemporarySegmentPlaylistFilename($key)
        );

        $lines = DynamicHLSPlaylist::parseLines($segmentPlaylist)->filter();

        return $lines->get($lines->search($segmentPlaylistMedia->getFilename()) - 1);
    }

    public function get(array $segmentPlaylists, PHPFFMpeg $driver): string
    {
        return Collection::make($segmentPlaylists)->map(function (Media $segmentPlaylist, $key) use ($driver) {
            $streamInfoLine = $this->getStreamInfoLine($segmentPlaylist, $key);

            $media = (new MediaOpener($segmentPlaylist->getDisk(), $driver))
                ->openWithInputOptions($segmentPlaylist->getPath(), ['-allowed_extensions', 'ALL']);

            if ($media->getVideoStream()) {
                if ($frameRate = StreamParser::new($media->getVideoStream())->getFrameRate()) {
                    $streamInfoLine .= ",FRAME-RATE={$frameRate}";
                }
            }

            return [$streamInfoLine, $segmentPlaylist->getFilename()];
        })->collapse()->prepend(self::PLAYLIST_START)->implode(PHP_EOL);
    }
}

Then use it like this,

        FFMpeg::fromDisk("videos")
            ->open("/$this->name.$this->extension")
            ->exportForHLS()
            ->withPlaylistGenerator(new HLSExtendedGenerator)
            ->setSegmentLength(10)->...