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.63k stars 194 forks source link

DynamicHLSPlaylist parseLines always return null #450

Open sandyh90 opened 1 year ago

sandyh90 commented 1 year ago

Hi,

I have a problem while starting to encode my video using this package because DynamicHLSPlaylist::parseLines() value always return null did i do something wrong?

and this is my code and debug output.

Code

$withoutFileExt = preg_replace('/\\.[^.\\s]{3,4}$/', '', $getVideoData->video_file);
                        $format = new X264('aac', 'libx264');
                        $format->setAdditionalParameters(['-c:v', 'h264_amf']);
                        $lowBitrate = ($format)->setKiloBitrate(250);
                        $midBitrate = ($format)->setKiloBitrate(500);
                        $highBitrate = ($format)->setKiloBitrate(1000);
                        FFMpeg::fromDisk('public')
                            ->open("video/{$getVideoData->folder_video}/{$getVideoData->video_file}")
                            ->exportForHLS()
                            ->addFormat($lowBitrate)
                            ->addFormat($midBitrate)
                            ->addFormat($highBitrate)
                            ->save("{$withoutFileExt}.m3u8");

Output

TypeError: ProtoneMedia\LaravelFFMpeg\Http\DynamicHLSPlaylist::parseLines(): Argument #1 ($lines) must be of type string, null given, called in D:\Server\VideoEncoder\vendor\pbmedia\laravel-ffmpeg\src\Exporters\HLSPlaylistGenerator.php on line 30 and defined in D:\Server\VideoEncoder\vendor\pbmedia\laravel-ffmpeg\src\Http\DynamicHLSPlaylist.php:157
Stack trace:
#0 D:\Server\VideoEncoder\vendor\pbmedia\laravel-ffmpeg\src\Exporters\HLSPlaylistGenerator.php(30): ProtoneMedia\LaravelFFMpeg\Http\DynamicHLSPlaylist::parseLines(NULL)
#1 D:\Server\VideoEncoder\vendor\pbmedia\laravel-ffmpeg\src\Exporters\HLSPlaylistGenerator.php(47): ProtoneMedia\LaravelFFMpeg\Exporters\HLSPlaylistGenerator->getStreamInfoLine(Object(ProtoneMedia\LaravelFFMpeg\Filesystem\Media), '0')
#2 [internal function]: ProtoneMedia\LaravelFFMpeg\Exporters\HLSPlaylistGenerator->ProtoneMedia\LaravelFFMpeg\Exporters\{closure}(Object(ProtoneMedia\LaravelFFMpeg\Filesystem\Media), 0)
#3 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Collections\Arr.php(560): array_map(Object(Closure), Array, Array)
#4 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Collections\Collection.php(719): Illuminate\Support\Arr::map(Array, Object(Closure))
#5 D:\Server\VideoEncoder\vendor\pbmedia\laravel-ffmpeg\src\Exporters\HLSPlaylistGenerator.php(57): Illuminate\Support\Collection->map(Object(Closure))
#6 D:\Server\VideoEncoder\vendor\pbmedia\laravel-ffmpeg\src\Exporters\HLSExporter.php(309): ProtoneMedia\LaravelFFMpeg\Exporters\HLSPlaylistGenerator->get(Array, Object(ProtoneMedia\LaravelFFMpeg\Drivers\PHPFFMpeg))
#7 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Collections\Traits\EnumeratesValues.php(715): ProtoneMedia\LaravelFFMpeg\Exporters\HLSExporter->ProtoneMedia\LaravelFFMpeg\Exporters\{closure}(Object(Illuminate\Support\Collection))
#8 D:\Server\VideoEncoder\vendor\pbmedia\laravel-ffmpeg\src\Exporters\HLSExporter.php(320): Illuminate\Support\Collection->pipe(Object(Closure))
#9 D:\Server\VideoEncoder\app\Jobs\TranscodingVideoData.php(67): ProtoneMedia\LaravelFFMpeg\Exporters\HLSExporter->save('mediaData/b6fea...')
#10 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php(36): App\Jobs\TranscodingVideoData->handle()
#11 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\Util.php(41): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#12 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php(93): Illuminate\Container\Util::unwrapIfClosure(Object(Closure))
#13 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php(37): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#14 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\Container.php(651): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#15 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Bus\Dispatcher.php(128): Illuminate\Container\Container->call(Array)
#16 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(141): Illuminate\Bus\Dispatcher->Illuminate\Bus\{closure}(Object(App\Jobs\TranscodingVideoData))
#17 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(116): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(App\Jobs\TranscodingVideoData))
#18 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Bus\Dispatcher.php(132): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#19 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\CallQueuedHandler.php(124): Illuminate\Bus\Dispatcher->dispatchNow(Object(App\Jobs\TranscodingVideoData), false)
#20 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(141): Illuminate\Queue\CallQueuedHandler->Illuminate\Queue\{closure}(Object(App\Jobs\TranscodingVideoData))
#21 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(116): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(App\Jobs\TranscodingVideoData))
#22 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\CallQueuedHandler.php(126): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#23 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\CallQueuedHandler.php(70): Illuminate\Queue\CallQueuedHandler->dispatchThroughMiddleware(Object(Illuminate\Queue\Jobs\DatabaseJob), Object(App\Jobs\TranscodingVideoData))
#24 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\Jobs\Job.php(98): Illuminate\Queue\CallQueuedHandler->call(Object(Illuminate\Queue\Jobs\DatabaseJob), Array)
#25 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\Worker.php(425): Illuminate\Queue\Jobs\Job->fire()
#26 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\Worker.php(375): Illuminate\Queue\Worker->process('database', Object(Illuminate\Queue\Jobs\DatabaseJob), Object(Illuminate\Queue\WorkerOptions))
#27 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\Worker.php(173): Illuminate\Queue\Worker->runJob(Object(Illuminate\Queue\Jobs\DatabaseJob), 'database', Object(Illuminate\Queue\WorkerOptions))
#28 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\Console\WorkCommand.php(150): Illuminate\Queue\Worker->daemon('database', 'transcode-video', Object(Illuminate\Queue\WorkerOptions))
#29 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Queue\Console\WorkCommand.php(134): Illuminate\Queue\Console\WorkCommand->runWorker('database', 'transcode-video')
#30 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php(36): Illuminate\Queue\Console\WorkCommand->handle()
#31 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\Util.php(41): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#32 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php(93): Illuminate\Container\Util::unwrapIfClosure(Object(Closure))
#33 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php(37): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#34 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Container\Container.php(651): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#35 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Console\Command.php(144): Illuminate\Container\Container->call(Array)
#36 D:\Server\VideoEncoder\vendor\symfony\console\Command\Command.php(291): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#37 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Console\Command.php(126): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#38 D:\Server\VideoEncoder\vendor\symfony\console\Application.php(1014): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#39 D:\Server\VideoEncoder\vendor\symfony\console\Application.php(301): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Queue\Console\WorkCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#40 D:\Server\VideoEncoder\vendor\symfony\console\Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#41 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Console\Application.php(102): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#42 D:\Server\VideoEncoder\vendor\laravel\framework\src\Illuminate\Foundation\Console\Kernel.php(155): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#43 D:\Server\VideoEncoder\artisan(37): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#44 {main}

while i trace the error where caught in this method

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);
    }
SadeghPM commented 1 year ago

Please post your code that involve DynamicHLSPlaylist class. Maybe this solve https://github.com/protonemedia/laravel-ffmpeg/pull/466

sandyh90 commented 1 year ago

@SadeghPM i don't have any other code that involve with DynamicHLSPlaylist class only this basic code have relation with that class.

$withoutFileExt = preg_replace('/\\.[^.\\s]{3,4}$/', '', $getVideoData->video_file);
                        $format = new X264('aac', 'libx264');
                        $format->setAdditionalParameters(['-c:v', 'h264_amf']);
                        $lowBitrate = ($format)->setKiloBitrate(250);
                        $midBitrate = ($format)->setKiloBitrate(500);
                        $highBitrate = ($format)->setKiloBitrate(1000);
                        FFMpeg::fromDisk('public')
                            ->open("video/{$getVideoData->folder_video}/{$getVideoData->video_file}")
                            ->exportForHLS()
                            ->addFormat($lowBitrate)
                            ->addFormat($midBitrate)
                            ->addFormat($highBitrate)
                            ->save("{$withoutFileExt}.m3u8");

Ok I will try your pull request code hopefully it will work normally, thanks for letting me know.

aronquiray commented 1 year ago

@sandyh90 make sure the the video is residing in your storage folder if you're using local, it's on storage/app/public/video/{$getVideoData->folder_video}/{$getVideoData->video_file} make sure that it's existing there. if not, then try to run the command php artisan storage:link as I can see you're using the public key

Nothing is wrong with the current setup

$storageLocation = $this->isLocalStorage ? 'public/'.$location : $location;

        $toLocation = $this->isLocalStorage ? "public/temp/collections/$track->uuid/".$track->uuid.'.m3u8' : "collections/$track->uuid/$track->uuid.m3u8";

        $low = (new X264)->setAudioKiloBitrate(96);
        $med = (new X264)->setAudioKiloBitrate(128);
        $high = (new X264)->setAudioKiloBitrate(256);
        $ultra = (new X264)->setAudioKiloBitrate(320);

        FFMpeg::fromDisk(config('filesystems.default'))
            ->open($storageLocation) // MP3 file
            ->exportForHLS()
            ->addFormat($low)
            ->addFormat($med)
            ->addFormat($high)
            ->addFormat($ultra)
            ->setSegmentLength(10)
            ->save($toLocation); //m3u8

this is what I have on my setup.

sandyh90 commented 1 year ago

@aronquiray yup but i have tried thing others like run php artisan storage:link command and check if the folder exists or not but nothing worked it just failed to save master playlist but to save playlist for quality selector works fine without problem