Этот пакет обеспечивает интеграцию с FFmpeg для Laravel 10. Файловая система Laravel обеспечивает хранение файлов.
Мы с гордостью поддерживаем сообщество, разрабатывая пакеты Laravel и раздавая их бесплатно. Если этот пакет экономит ваше время или вы полагаетесь на него профессионально, рассмотрите возможность спонсировать поддержку и разработку и ознакомьтесь с нашим последним премиальным пакетом: Inertia Table. Отслеживание проблем и запросов на включение требует времени, но мы будем рады помочь!
Очень простая оболочка PHP-FFMpeg, включая поддержку фильтров и других расширенных функций.
Интеграция с файловой системой Laravel, системой конфигурации и обработкой журналов.
Совместимость с Laravel 10, поддержка обнаружения пакетов.
Встроенная поддержка HLS.
Встроенная поддержка шифрования HLS (AES-128) и ротации ключей (опционально).
Встроенная поддержка конкатенации, нескольких входов/выходов, последовательностей изображений (таймлапс), сложных фильтров (и картографирования), экспорта кадров/миниатюр.
Встроенная поддержка водяных знаков (позиционирование и манипулирование).
Встроенная поддержка создания мозаики/спрайта/тайла из видео.
Встроенная поддержка создания файлов миниатюр предварительного просмотра VTT .
Требуется PHP 8.1 или выше.
Протестировано с FFmpeg 4.4 и 5.0.
Убедитесь, что у вас установлена последняя версия FFmpeg:
ffmpeg -версия
Вы можете установить пакет через композитор:
композитору требуется pbmedia/laravel-ffmpeg
Добавьте поставщика услуг и фасад в файл конфигурации app.php
если вы не используете обнаружение пакетов.
// config/app.php'providers' => [ ...ProtoneMediaLaravelFFMpegSupportServiceProvider::class, ... ];'псевдонимы' => [ ...'FFMpeg' => ProtoneMediaLaravelFFMpegSupportFFMpeg::class ... ];
Опубликуйте файл конфигурации с помощью инструмента CLI artisan:
поставщик php artisan:publish --provider="ProtoneMediaLaravelFFMpegSupportServiceProvider"
Конфигурационный ключ set_command_and_error_output_on_exception
теперь по умолчанию имеет значение true
, что делает исключения более информативными. Подробнее читайте в разделе «Обработка исключений».
Конфигурационный ключ enable_logging
был заменен на log_channel
для выбора канала журнала, используемого при записи сообщений в журналы. Если вы по-прежнему хотите полностью отключить ведение журнала, вы можете установить для нового конфигурационного ключа значение false
.
Длина сегмента и интервал ключевых кадров экспорта HLS должны быть 2
или более; less больше не поддерживается.
Поскольку Laravel 9 перешел с Flysystem 1.x на 3.x, эта версия несовместима с Laravel 8 или более ранними версиями.
Если вы используете функцию манипулирования водяными знаками, обязательно обновите spatie/image
до версии v2.
Пространство имен изменилось на ProtoneMediaLaravelFFMpeg
, фасад был переименован в ProtoneMediaLaravelFFMpegSupportFFMpeg
, а поставщик услуг был переименован в ProtoneMediaLaravelFFMpegSupportServiceProvider
.
Цепной экспорт по-прежнему поддерживается, но вам придется повторно применять фильтры для каждого экспорта.
Списки воспроизведения HLS теперь включают данные о битрейте, частоте кадров и разрешении. Сегменты также используют новый шаблон именования (подробнее). Пожалуйста, убедитесь, что экспорт по-прежнему работает в вашем плеере.
Экспорт HLS теперь выполняется как одно задание вместо экспорта каждого формата/потока отдельно. При этом используются функции map
FFMpeg и filter_complex
. Возможно, будет достаточно заменить все вызовы addFilter
на addLegacyFilter
, но некоторые фильтры следует перенести вручную. Пожалуйста, прочитайте документацию по HLS, чтобы узнать больше о добавлении фильтров.
Конвертируйте аудио или видео файл:
FFMpeg::fromDisk('песни') ->open('вчера.mp3') ->экспорт() ->toDisk('конвертированные_песни') ->inFormat (новый FFMpegFormatAudioAac) -> save('вчера.aac');
Вместо метода fromDisk()
вы также можете использовать метод fromFilesystem()
, где $filesystem
— это экземпляр IlluminateContractsFilesystemFilesystem
.
$media = FFMpeg::fromFilesystem($filesystem)->open('yesterday.mp3');
Вы можете следить за ходом транскодирования. Используйте метод onProgress
для обеспечения обратного вызова, который дает вам процент выполнения. В предыдущих версиях этого пакета вам приходилось передавать обратный вызов объекту формата.
FFMpeg::open('steve_howe.mp4') ->экспорт() ->onProgress(function ($percentage) {echo "{$percentage}% перекодировано"; });
Обратный вызов также может отображать $remaining
(в секундах) и $rate
:
FFMpeg::open('steve_howe.mp4') ->экспорт() ->onProgress(function ($percentage, $remaining, $rate) {echo "Осталось {$remaining} секунд со скоростью: {$rate}"; });
Вы можете открывать загруженные файлы непосредственно из экземпляра Request
. Вероятно, лучше сначала сохранить загруженный файл на случай, если запрос прервется, но если вы хотите, вы можете открыть экземпляр UploadedFile
:
класс UploadVideoController {публичная функция __invoke(Запрос $запрос) { FFMpeg::open($request->file('video')); } }
Вы можете открывать файлы из Интернета с помощью метода openUrl
. Вы можете указать собственные заголовки HTTP с помощью необязательного второго параметра:
FFMpeg::openUrl('https://videocoursebuilder.com/lesson-1.mp4'); FFMpeg::openUrl('https://videocoursebuilder.com/lesson-2.mp4', ['Авторизация' => 'Базовый YWRtaW46MTIzNA==', ]);
В случае сбоя кодирования должно быть выброшено исключение ProtoneMediaLaravelFFMpegExportersEncodingException
, которое расширяет базовый класс FFMpegExceptionRuntimeException
. В этом классе есть два метода, которые могут помочь вам выявить проблему. С помощью метода getCommand
можно получить исполняемую команду со всеми параметрами. Метод getErrorOutput
предоставляет вам полный журнал вывода.
В предыдущих версиях этого пакета сообщение об исключении всегда было Encoding error . Вы можете вернуться к этому сообщению, обновив конфигурационный ключ set_command_and_error_output_on_exception
до false
.
пытаться { FFMpeg::open('вчера.mp3') ->экспорт() ->inFormat(новый AAC) -> save('вчера.aac'); } catch (EncodingException $Exception) {$command = $Exception->getCommand();$errorLog = $Exception->getErrorOutput(); }
Вы можете добавлять фильтры через Closure
или с помощью объектов фильтра PHP-FFMpeg:
используйте FFMpegFiltersVideoVideoFilters; FFMpeg::fromDisk('видео') ->open('steve_howe.mp4') ->addFilter(function (VideoFilters $filters) {$filters->resize(new FFMpegCoordinateDimension(640, 480)); }) ->экспорт() ->toDisk('converted_videos') ->inFormat (новый FFMpegFormatVideoX264) ->save('small_steve.mkv');// или $start = FFMpegCoordinateTimeCode::fromSeconds(5)$clipFilter = new FFMpegFiltersVideoClipFilter($start); FFMpeg::fromDisk('видео') ->open('steve_howe.mp4') ->addFilter($clipFilter) ->экспорт() ->toDisk('converted_videos') ->inFormat (новый FFMpegFormatVideoX264) ->save('short_steve.mkv');
Вы также можете вызвать метод addFilter
после метода export
:
используйте FFMpegFiltersVideoVideoFilters; FFMpeg::fromDisk('видео') ->open('steve_howe.mp4') ->экспорт() ->toDisk('converted_videos') ->inFormat (новый FFMpegFormatVideoX264) ->addFilter(function (VideoFilters $filters) {$filters->resize(new FFMpegCoordinateDimension(640, 480)); }) ->save('small_steve.mkv');
Поскольку изменение размера — распространенная операция, мы добавили для нее специальный метод:
FFMpeg::open('steve_howe.mp4') ->экспорт() ->inFormat (новый FFMpegFormatVideoX264) -> изменить размер (640, 480) ->save('steve_howe_resized.mp4');
Первый аргумент — это ширина, а второй аргумент — высота. Необязательный третий аргумент — это режим. Вы можете выбрать между fit
(по умолчанию), inset
, width
или height
. Необязательный четвертый аргумент — это логическое значение, указывающее, следует ли принудительно использовать стандартные соотношения. Об этих режимах можно узнать в классе FFMpegFiltersVideoResizeFilter
.
Иногда вы не хотите использовать встроенные фильтры. Вы можете применить свой собственный фильтр, предоставив набор опций. Это может быть массив или несколько строк в качестве аргументов:
FFMpeg::fromDisk('видео') ->open('steve_howe.mp4') ->addFilter(['-itsoffset', 1]);// orFFMpeg::fromDisk('videos') ->open('steve_howe.mp4') ->addFilter('-itsoffset', 1);
Вы можете легко добавить водяной знак, используя метод addWatermark
. С помощью WatermarkFactory
вы можете открыть файл водяного знака с определенного диска так же, как открываете аудио- или видеофайл. Когда вы отбрасываете метод fromDisk
, он использует диск по умолчанию, указанный в файле конфигурации filesystems.php
.
После открытия файла водяного знака вы можете расположить его с помощью методов top
, right
, bottom
и left
. Первым параметром этих методов является смещение, которое не является обязательным и может быть отрицательным.
используйте ProtoneMediaLaravelFFMpegFiltersWatermarkFactory; FFMpeg::fromDisk('видео') ->open('steve_howe.mp4') ->addWatermark(function(WatermarkFactory $watermark) {$watermark->fromDisk('local') ->open('logo.png') ->право(25) -> низ (25); });
Вместо использования методов позиционирования вы также можете использовать методы horizontalAlignment
и verticalAlignment
.
Для горизонтального выравнивания вы можете использовать константы WatermarkFactory::LEFT
, WatermarkFactory::CENTER
и WatermarkFactory::RIGHT
. Для вертикального выравнивания вы можете использовать константы WatermarkFactory::TOP
, WatermarkFactory::CENTER
и WatermarkFactory::BOTTOM
. Оба метода принимают необязательный второй параметр — смещение.
FFMpeg::open('steve_howe.mp4') ->addWatermark(function(WatermarkFactory $watermark) {$watermark->open('logo.png') ->horizontalAlignment(WatermarkFactory::LEFT, 25) ->verticalAlignment(WatermarkFactory::TOP, 25); });
WatermarkFactory
также поддерживает открытие файлов из Интернета с помощью метода openUrl
. Он также поддерживает пользовательские заголовки HTTP.
FFMpeg::open('steve_howe.mp4') ->addWatermark(function(WatermarkFactory $watermark) {$watermark->openUrl('https://videocoursebuilder.com/logo.png');// или $watermark->openUrl('https://videocoursebuilder.com/ logo.png', ['Авторизация' => 'Базовый YWRtaW46MTIzNA==', ]); });
Если вам нужен больший контроль над запросом GET, вы можете передать необязательный третий параметр, который предоставит вам ресурс Curl.
$watermark->openUrl('https://videocoursebuilder.com/logo.png', ['Авторизация' => 'Базовый YWRtaW46MTIzNA==', ], function($curl) {curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); });
Этот пакет может управлять водяными знаками с помощью пакета изображений Spatie. Для начала установите пакет с помощью Composer:
композитору требуется Spatie/изображение
Теперь вы можете связать еще один метод манипуляции с экземпляром WatermarkFactory
:
FFMpeg::open('steve_howe.mp4') ->addWatermark(function(WatermarkFactory $watermark) {$watermark->open('logo.png') ->право(25) ->низ(25) ->ширина(100) ->высота(100) -> оттенки серого(); });
Ознакомьтесь с документацией по всем доступным методам.
В этот пакет входит класс ProtoneMediaLaravelFFMpegFFMpegCopyFormat
, который позволяет экспортировать файл без перекодирования потоков. Возможно, вы захотите использовать это для использования другого контейнера:
используйте ProtoneMediaLaravelFFMpegFFMpegCopyFormat; FFMpeg::open('video.mp4') ->экспорт() ->inFormat(новый CopyFormat) -> сохранить('video.mkv');
// Метод fromDisk() не требуется, файл теперь // будет открыт с «диска» по умолчанию, как указано в // файле конфигурации.FFMpeg::open('my_movie.mov')// экспорт на FTP, конвертированный в WMV->export() ->toDisk('ftp') ->inFormat (новый FFMpegFormatVideoWMV) ->save('my_movie.wmv')// экспорт в Amazon S3, преобразованный в X264->export() ->toDisk('s3') ->inFormat (новый FFMpegFormatVideoX264) ->save('my_movie.mkv');// можно даже отказаться от метода 'toDisk()', // теперь преобразованный файл будет сохранен // на том же диске, что и исходный!->export() ->inFormat (новый FFMpegFormatVideoWebM) ->save('my_movie.webm')// опционально вы можете установить видимость// экспортируемого файла->export() ->inFormat (новый FFMpegFormatVideoWebM) ->withVisibility('публичный') -> сохранить('my_movie.webm')
FFMpeg::fromDisk('видео') ->open('steve_howe.mp4') ->getFrameFromSeconds(10) ->экспорт() ->toDisk('миниатюры') ->save('FrameAt10sec.png');// Вместо метода 'getFrameFromSeconds()' вы можете// также использовать методы 'getFrameFromString()' или// 'getFrameFromTimecode()':$media = FFMpeg ::open('steve_howe.mp4');$frame = $media->getFrameFromString('00:00:13.37');// или $timecode = new FFMpegCoordinateTimeCode(...);$frame = $media->getFrameFromTimecode($timecode);
Вы также можете получить необработанное содержимое кадра вместо сохранения его в файловой системе:
$contents = FFMpeg::open('video.mp4') ->getFrameFromSeconds(2) ->экспорт() ->getFrameContents();
Существует TileFilter
, который поддерживает функцию Tile. Чтобы ускорить и упростить экспорт нескольких кадров, мы использовали эту функцию, добавив несколько вспомогательных методов. Например, вы можете использовать метод exportFramesByInterval
для экспорта кадров через фиксированный интервал. Альтернативно вы можете передать количество кадров, которые хотите экспортировать, методу exportFramesByAmount
, который затем рассчитает интервал на основе продолжительности видео.
FFMpeg::open('video.mp4') ->exportFramesByInterval(2) ->save('thumb_%05d.jpg');
Оба метода принимают необязательный второй и третий аргумент для указания ширины и высоты фреймов. Вместо передачи ширины и высоты вы также можете передать только один из них. FFmpeg будет учитывать соотношение сторон источника.
FFMpeg::open('video.mp4') ->exportFramesByAmount(10, 320, 180) ->save('thumb_%05d.png');
Оба метода принимают необязательный четвертый аргумент, определяющий качество изображения при экспорте в формат с потерями, например JPEG. Диапазон JPEG составляет 2-31
, где 2
— лучшее качество, а 31
— худшее.
FFMpeg::open('video.mp4') ->exportFramesByInterval(2, 640, 360, 5) ->save('thumb_%05d.jpg');
Вы можете создавать плитки из видео. Вы можете вызвать метод exportTile
, чтобы указать, как должны создаваться ваши плитки. В приведенном ниже примере каждое сгенерированное изображение состоит из сетки 3x5 (таким образом, содержащей 15 кадров), а размер каждого кадра составляет 160x90 пикселей. Каждые 5 секунд из видео будет сниматься кадр. Вместо передачи ширины и высоты вы также можете передать только один из них. FFmpeg будет учитывать соотношение сторон источника.
используйте ProtoneMediaLaravelFFMpegFiltersTileFactory; FFMpeg::open('steve_howe.mp4') ->exportTile(function (TileFactory $factory) {$factory->interval(5) ->масштаб(160, 90) -> сетка (3, 5); }) ->save('tile_%05d.jpg');
Вместо того, чтобы передавать ширину и высоту, вы также можете передать только один из них, например scale(160)
или scale(null, 90)
. Соотношение сторон будет соблюдено. TileFactory
также имеет методы margin
, padding
, width
и height
. Существует также метод quality
, позволяющий указать качество при экспорте в формат с потерями, например JPEG. Диапазон JPEG составляет 2-31
, где 2
— лучшее качество, а 31
— худшее.
Этот пакет также может создать файл WebVTT для добавления миниатюр предварительного просмотра в ваш видеоплеер. Это поддерживается проигрывателем JW «из коробки», а также доступны плагины для Video.js, созданные сообществом. Вы можете вызвать generateVTT
в TileFactory
с нужным именем файла:
FFMpeg::open('steve_howe.mp4') ->exportTile(function (TileFactory $factory) {$factory->interval(10) ->масштаб(320, 180) -> сетка (5, 5) ->generateVTT('thumbnails.vtt'); }) ->save('tile_%05d.jpg');
Объединение нескольких преобразований работает, поскольку метод save
MediaExporter
возвращает новый экземпляр MediaOpener
. Вы можете использовать это для циклического перемещения по элементам, например, для экспорта нескольких кадров из одного видео:
$mediaOpener = FFMpeg::open('video.mp4');foreach ([5, 15, 25] as $key => $секунды) {$mediaOpener = $mediaOpener->getFrameFromSeconds($секунды) ->экспорт() ->save("thumb_{$key}.png"); }
MediaOpener
также включает в себя each
метод. Приведенный выше пример можно было бы реорганизовать следующим образом:
FFMpeg::open('video.mp4')->each([5, 15, 25], function ($ffmpeg, $секунды, $key) {$ffmpeg->getFrameFromSeconds($секунды)->export()- >save("thumb_{$key}.png"); });
Вы можете создать таймлапс из последовательности изображений, используя метод asTimelapseWithFramerate
в средстве экспорта.
FFMpeg::open('feature_%04d.png') ->экспорт() ->asTimelapseWithFramerate(1) ->inFormat(новый X264) ->сохранить('timelapse.mp4');
Вы можете открыть несколько входов, даже с разных дисков. При этом используются функции map
FFMpeg и filter_complex
. Вы можете открыть несколько файлов, связав метод open
с использованием массива. Вы можете смешивать входы с разных дисков.
FFMpeg::open('video1.mp4')->open('video2.mp4'); FFMpeg::open(['video1.mp4', 'video2.mp4']); FFMpeg::fromDisk('загрузки') ->open('video1.mp4') ->fromDisk('архив') ->open('video2.mp4');
Когда вы открываете несколько входов, вам необходимо добавить сопоставления, чтобы FFMpeg знал, как их маршрутизировать. Этот пакет предоставляет метод addFormatOutputMapping
, который принимает три параметра: формат, выходные данные и выходные метки части -filter_complex
.
Выходные данные (второй аргумент) должны быть экземпляром ProtoneMediaLaravelFFMpegFilesystemMedia
. Вы можете создать экземпляр с помощью метода make
, вызвать его с именем диска и путем (см. пример).
Посмотрите этот пример, в котором отдельные видео- и аудиовходы сопоставляются с одним выходом.
FFMpeg::fromDisk('локальный') ->open(['video.mp4', 'audio.m4a']) ->экспорт() ->addFormatOutputMapping(new X264, Media::make('local', 'new_video.mp4'), ['0:v', '1:a']) -> сохранить();
Это пример из базовой библиотеки:
// Этот код берет 2 входных видео, складывает их горизонтально в 1 выходное видео и // добавляет к этому новому видео звук из первого видео. (Это невозможно// с простым графом фильтров, имеющим только 1 вход и только 1 выход).FFMpeg::fromDisk('local') ->open(['video.mp4', 'video2.mp4']) ->экспорт() ->addFilter('[0:v][1:v]', 'hstack', '[v]') // $in, $parameters, $out->addFormatOutputMapping(new X264, Media::make(' local', 'stacked_video.mp4'), ['0:a', '[v]']) -> сохранить();
Как и в случае с отдельными входными данными, вы также можете передать обратный вызов методу addFilter
. Это даст вам экземпляр FFMpegFiltersAdvancedMediaComplexFilters
:
используйте FFMpegFiltersAdvancedMediaComplexFilters; FFMpeg::open(['video.mp4', 'video2.mp4']) ->экспорт() ->addFilter(function(ComplexFilters $filters) {// $filters->watermark(...);});
Открытие файлов из Интернета работает аналогично. Вы можете передать массив URL-адресов методу openUrl
, при необходимости с настраиваемыми заголовками HTTP.
FFMpeg::openUrl(['https://videocoursebuilder.com/lesson-3.mp4','https://videocoursebuilder.com/lesson-4.mp4', ]); FFMpeg::openUrl(['https://videocoursebuilder.com/lesson-3.mp4','https://videocoursebuilder.com/lesson-4.mp4', ], ['Авторизация' => 'Базовый YWRtaW46MTIzNA==', ]);
Если вы хотите использовать другой набор HTTP-заголовков для каждого URL-адреса, вы можете связать метод openUrl
:
FFMpeg::openUrl('https://videocoursebuilder.com/lesson-5.mp4', ['Авторизация' => 'Базовый YWRtaW46MTIzNA==', ])->openUrl('https://videocoursebuilder.com/lesson-6.mp4', ['Авторизация' => 'Базовый bmltZGE6NDMyMQ==', ]);
FFMpeg::fromDisk('локальный') ->open(['video.mp4', 'video2.mp4']) ->экспорт() ->concatWithoutTranscoding() -> сохранить('concat.mp4');
FFMpeg::fromDisk('локальный') ->open(['video.mp4', 'video2.mp4']) ->экспорт() ->inFormat(новый X264) ->concatWithTranscoding($hasVideo = true, $hasAudio = true) -> сохранить('concat.mp4');
С помощью класса Media
вы можете определить продолжительность файла:
$media = FFMpeg::open('wwdc_2006.mp4');$durationInSeconds = $media->getDurationInSeconds(); // возвращает int$durationInMiliсекунды = $media->getDurationInMiliсекунды(); // возвращает число с плавающей запятой
При открытии или сохранении файлов с или на удаленный диск на вашем сервере будут создаваться временные файлы. После того, как вы закончите экспортировать или обработать эти файлы, вы можете очистить их, вызвав метод cleanupTemporaryFiles()
:
FFMpeg::cleanupTemporaryFiles();
По умолчанию корень временных каталогов оценивается методом PHP sys_get_temp_dir()
, но вы можете изменить его, установив для конфигурационного ключа temporary_files_root
собственный путь.
Вы можете создать список воспроизведения M3U8 для использования HLS.
$lowBitrate = (новый X264)->setKiloBitrate(250);$midBitrate = (новый X264)->setKiloBitrate(500);$highBitrate = (новый X264)->setKiloBitrate(1000); FFMpeg::fromDisk('видео') ->open('steve_howe.mp4') ->экспортДляHLS() ->setSegmentLength(10) // необязательно->setKeyFrameInterval(48) // необязательно->addFormat($lowBitrate) ->addFormat($midBitrate) ->addFormat($highBitrate) ->save('adaptive_steve.m3u8');
Метод addFormat
экспортера HLS принимает необязательный второй параметр, который может быть методом обратного вызова. Это позволяет добавлять разные фильтры для каждого формата. Сначала ознакомьтесь с разделом «Несколько входов», чтобы понять, как обрабатываются сложные фильтры.
Вы можете использовать метод addFilter
для добавления сложного фильтра (см. пример $lowBitrate
). Поскольку фильтр scale
используется часто, существует вспомогательный метод (см. пример $midBitrate
). Вы также можете использовать вызываемый объект для получения доступа к экземпляру ComplexFilters
. Пакет предоставляет аргументы $in
и $out
поэтому вам не придется об этом беспокоиться (см. пример $highBitrate
).
Экспорт HLS построен с использованием функций map
и filter_complex
FFMpeg. Это кардинальное изменение по сравнению с более ранними версиями (1.x–6.x), в которых для каждого формата выполнялся один экспорт. При обновлении замените вызовы addFilter
вызовами addLegacyFilter
и проверьте результат (см. пример $superBitrate
). Не все фильтры будут работать таким образом, а некоторые необходимо обновлять вручную.
$lowBitrate = (новый X264)->setKiloBitrate(250);$midBitrate = (новый X264)->setKiloBitrate(500);$highBitrate = (новый X264)->setKiloBitrate(1000);$superBitrate = (новый X264)- >setKiloBitrate(1500); FFMpeg::open('steve_howe.mp4') ->экспортДляHLS() ->addFormat($lowBitrate, function($media) {$media->addFilter('scale=640:480'); }) ->addFormat($midBitrate, function($media) {$media->scale(960, 720); }) ->addFormat($highBitrate, function ($media) {$media->addFilter(function ($filters, $in, $out) {$filters->custom($in, 'scale=1920:1200', $out ); // $in, $parameters, $out}); }) ->addFormat($superBitrate, function($media) {$media->addLegacyFilter(function ($filters) {$filters->resize(new FFMpegCoordinateDimension(2560, 1920)); }); }) ->save('adaptive_steve.m3u8');
Вы можете использовать собственный шаблон для именования сегментов и списков воспроизведения. useSegmentFilenameGenerator
дает вам 5 аргументов. Первый, второй и третий аргумент предоставляют информацию о базовом имени экспорта, формате текущей итерации и ключе текущей итерации. Четвертый аргумент — это обратный вызов, который вы должны вызвать с помощью шаблона сегментов . Пятый аргумент — это обратный вызов, который вы должны вызвать с помощью шаблона списка воспроизведения . Обратите внимание, что это не имя основного плейлиста, а название плейлиста каждого формата.
FFMpeg::fromDisk('видео') ->open('steve_howe.mp4') ->экспортДляHLS() ->useSegmentFilenameGenerator(function ($name, $format, $key, вызываемые $segments, вызываемый $playlist) {$segments("{$name}-{$format->getKiloBitrate()}-{$key}-%03d .ts");$playlist("{$name}-{$format->getKiloBitrate()}-{$key}.m3u8"); });
Вы можете зашифровать каждый сегмент HLS, используя шифрование AES-128. Для этого вызовите метод withEncryptionKey
в экспортере HLS с ключом. Мы предоставляем вспомогательный метод generateEncryptionKey
в классе HLSExporter
для генерации ключа. Убедитесь, что вы правильно храните ключ, поскольку без ключа экспортированный результат бесполезен. По умолчанию имя файла ключа — secret.key
, но вы можете изменить его с помощью необязательного второго параметра метода withEncryptionKey
.
используйте ProtoneMediaLaravelFFMpegExportersHLSExporter;$encryptionKey = HLSExporter::generateEncryptionKey(); FFMpeg::open('steve_howe.mp4') ->экспортДляHLS() ->withEncryptionKey($encryptionKey) ->addFormat($lowBitrate) ->addFormat($midBitrate) ->addFormat($highBitrate) ->save('adaptive_steve.m3u8');
Чтобы еще больше защитить экспорт HLS, вы можете повернуть ключ в каждом экспортируемом сегменте. При этом он сгенерирует несколько ключей, которые вам нужно будет сохранить. Используйте метод withRotatingEncryptionKey
, чтобы включить эту функцию и предоставить обратный вызов, реализующий хранение ключей.
FFMpeg::open('steve_howe.mp4') ->экспортДляHLS() ->withRotatingEncryptionKey(function ($filename, $contents) {$videoId = 1;// используйте этот обратный вызов для хранения ключей шифрованияStorage::disk('secrets')->put($videoId . '/' . $filename, $contents);// или...DB::table('hls_secrets')->insert(['video_id' => $videoId,'filename' => $filename,'contents' => $contents, ]); }) ->addFormat($lowBitrate) ->addFormat($midBitrate) ->addFormat($highBitrate) ->save('adaptive_steve.m3u8');
Метод withRotatingEncryptionKey
имеет необязательный второй аргумент, позволяющий установить количество сегментов, использующих один и тот же ключ. По умолчанию это 1
.
FFMpeg::open('steve_howe.mp4') ->экспортДляHLS() ->withRotatingEncryptionKey($callable, 10);
Некоторые файловые системы, особенно на дешевых и медленных VPS, недостаточно быстры для обработки вращающегося ключа. Это может привести к возникновению исключений кодирования, например, No key URI specified in key info file
. Одним из возможных решений является использование другого хранилища для ключей, которое вы можете указать с помощью конфигурационного ключа temporary_files_encrypted_hls
. В системах на базе UNIX вы можете использовать файловую систему tmpfs
для увеличения скорости чтения/записи:
// config/laravel-ffmpeg.phpreturn ['temporary_files_encrypted_hls' => '/dev/shm'];
Чтобы сделать работу с зашифрованным HLS еще лучше, мы добавили класс DynamicHLSPlaylist
, который изменяет списки воспроизведения «на лету» специально для вашего приложения. Таким образом, вы можете добавить свою логику аутентификации и авторизации. Поскольку мы используем простой контроллер Laravel, вы можете использовать такие функции, как Gates и Middleware.
В этом примере мы сохранили экспорт HLS на public
диск, а ключи шифрования сохранили на secrets
диске, который не является общедоступным. Поскольку браузер не имеет доступа к ключам шифрования, он не будет воспроизводить видео. В каждом списке воспроизведения есть пути к ключам шифрования, и нам нужно изменить эти пути, чтобы они указывали на доступную конечную точку.
Эта реализация состоит из двух маршрутов. Тот, который отвечает ключом шифрования, и тот, который отвечает измененным списком воспроизведения. Первый маршрут ( video.key
) относительно прост, и именно здесь вам следует добавить дополнительную логику.
Второй маршрут ( video.playlist
) использует класс DynamicHLSPlaylist
. Вызовите метод dynamicHLSPlaylist
на фасаде FFMpeg
. Подобно открытию медиафайлов, вы можете открыть список воспроизведения, используя методы fromDisk
и open
. Затем вы должны предоставить три обратных вызова. Каждый из них дает вам относительный путь и ожидает взамен полный путь. Поскольку класс DynamicHLSPlaylist
реализует интерфейс IlluminateContractsSupportResponsable
, вы можете вернуть экземпляр.
Первый обратный вызов (KeyUrlResolver) дает вам относительный путь к ключу шифрования. Второй обратный вызов (MediaUrlResolver) дает вам относительный путь к медиа-сегменту (файлам .ts). Третий обратный вызов (PlaylistUrlResolver) дает вам относительный путь к списку воспроизведения.
Теперь вместо использования Storage::disk('public')->url('adaptive_steve.m3u8')
для получения полного URL-адреса вашего основного плейлиста вы можете использовать route('video.playlist', ['playlist' => 'adaptive_steve.m3u8'])
. Класс DynamicHLSPlaylist
заботится обо всех путях и URL-адресах.
Route::get('/video/secret/{key}', function ($key) {return Storage::disk('secrets')->download($key); })->name('video.key'); Route::get('/video/{playlist}', function ($playlist) {return FFMpeg::dynamicHLSPlaylist() ->fromDisk('публичный') -> открыть ($ плейлист) ->setKeyUrlResolver(function ($key) {обратный маршрут('video.key', ['key' => $key]); }) ->setMediaUrlResolver(function ($mediaFilename) {return Storage::disk('public')->url($mediaFilename); }) ->setPlaylistUrlResolver(function ($playlistFilename) {обратный маршрут('video.playlist', ['playlist' => $playlistFilename]); }); })->name('video.playlist');
Здесь вы можете найти сеанс живого кодирования, посвященный шифрованию HLS:
https://www.youtube.com/watch?v=WlbzWoAcez4
Вы можете получить необработанные выходные данные процесса, вызвав метод getProcessOutput
. Хотя вариант использования ограничен, вы можете использовать его для анализа файла (например, с помощью фильтра volumedetect
). Он возвращает класс ProtoneMediaLaravelFFMpegSupportProcessOutput
, который имеет три метода: all
, errors
и output
. Каждый метод возвращает массив с соответствующими строками.
$processOutput = FFMpeg::open('video.mp4') ->экспорт() ->addFilter(['-filter:a', 'volumedetect', '-f', 'null']) ->getProcessOutput();$processOutput->all();$processOutput->errors();$processOutput->out();
Объект Media, который вы получаете, когда «открываете» файл, на самом деле содержит объект Media, принадлежащий базовому драйверу. Как вы можете видеть здесь, он обрабатывает вызовы динамических методов. Таким образом, вам по-прежнему будут доступны все методы базового драйвера.
// Это дает вам экземпляр ProtoneMediaLaravelFFMpegMediaOpener$media = FFMpeg::fromDisk('videos')->open('video.mp4');// Метод 'getStreams' будет вызываться для базового объекта Media, поскольку// его не существует в этом объекте. $codec = $media->getStreams()->first()->get('codec_name');
Если вам нужен прямой доступ к базовому объекту, вызовите объект как функцию (вызов):
// Это дает вам экземпляр ProtoneMediaLaravelFFMpegMediaOpener$media = FFMpeg::fromDisk('videos')->open('video.mp4');// Это дает вам экземпляр FFMpegMediaMediaTypeInterface$baseMedia = $media();
Прослушиватель прогресса отображает перекодированный процент, но базовый пакет также имеет внутренний AbstractProgressListener
, который предоставляет текущий проход и текущее время. Хотя вариант использования ограничен, вы можете захотеть получить доступ к этому экземпляру прослушивателя. Вы можете сделать это, украсив формат ProgressListenerDecorator
. Эта функция является экспериментальной, поэтому обязательно тщательно протестируйте ее перед использованием в рабочей среде.
используйте FFMpegFormatProgressListenerAbstractProgressListener; используйте ProtoneMediaLaravelFFMpegFFMpegProgressListenerDecorator; $format = новый FFMpegFormatVideoX264; $decoratedFormat = ProgressListenerDecorator::decorate($format); FFMpeg::open('video.mp4') ->экспорт() ->inFormat($decoratedFormat) ->onProgress(function () use ($decoratedFormat) {$listeners = $decoratedFormat->getListeners(); // массив прослушивателей $listener = $listeners[0]; // экземпляр AbstractProgressListener$listener->getCurrentPass() ;$listener->getTotalPass();$listener->getCurrentTime(); }) ->save('new_video.mp4');
Поскольку мы не можем избавиться от некоторых базовых параметров, вы можете взаимодействовать с последней командой FFmpeg, добавив обратный вызов к экспортеру. Вы можете добавить один или несколько обратных вызовов, используя метод beforeSaving
:
FFMpeg::open('video.mp4') ->экспорт() ->inFormat(новый X264) ->beforeSaving(function ($commands) {$commands[] = '-hello'; return $commands; }) -> сохранить('concat.mp4');
Примечание. Это не работает с конкатенацией и экспортом кадров.
Вот сообщение в блоге, которое поможет вам начать работу с этим пакетом:
https://protone.media/en/blog/how-to-use-ffmpeg-in-your-laravel-projects
Вот 20-минутный обзор того, как начать работу с Video.js. В нем рассматривается включение Video.js из CDN, его импорт как модуль ES6 с помощью Laravel Mix (Webpack) и создание повторно используемого компонента Vue.js.
https://www.youtube.com/watch?v=nA1Jy8BPjys
Пользовательские фильтры
FFmpeg не удалось выполнить команду
Получить размеры видеофайла
Мониторинг хода транскодирования
Невозможно загрузить FFProbe
Пожалуйста, посетите CHANGELOG для получения дополнительной информации о том, что изменилось за последнее время.
$ тест композитора
Пожалуйста, смотрите ВКЛАД для получения подробной информации.
Inertia Table
: идеальная таблица для Inertia.js со встроенным построителем запросов.
Laravel Blade On Demand
: пакет Laravel для компиляции шаблонов Blade в памяти.
Laravel Cross Eloquent Search
: пакет Laravel для поиска по нескольким моделям Eloquent.
Laravel Eloquent Scope as Select
: прекратите дублировать области и ограничения запросов Eloquent в PHP. Этот пакет позволяет повторно использовать области и ограничения запроса, добавляя их в качестве подзапроса.
Laravel MinIO Testing Tools
: запускайте тесты на сервере MinIO S3.
Laravel Mixins
: коллекция вкусностей Laravel.
Laravel Paddle
: интеграция API Paddle.com для Laravel с поддержкой веб-перехватчиков/событий.
Laravel Task Runner
: пишите сценарии Shell, такие как Blade Components, и запускайте их локально или на удаленном сервере.
Laravel Verify New Email
: этот пакет добавляет поддержку проверки новых адресов электронной почты: когда пользователь обновляет свой адрес электронной почты, он не заменяет старый, пока не будет проверен новый.
Laravel XSS Protection
: промежуточное программное обеспечение Laravel для защиты вашего приложения от межсайтового скриптинга (XSS). Он очищает ввод запроса и может очищать операторы эха Blade.
Если вы обнаружите какие-либо проблемы, связанные с безопасностью, отправьте электронное письмо по адресу [email protected] вместо использования системы отслеживания проблем. Пожалуйста, не пишите никаких вопросов по электронной почте, откройте проблему, если у вас есть вопрос.
Паскаль Балже
Все участники
Лицензия MIT (MIT). Дополнительную информацию см. в файле лицензии.