Este pacote fornece uma integração com FFmpeg para Laravel 10. O sistema de arquivos do Laravel cuida do armazenamento dos arquivos.
Temos orgulho de apoiar a comunidade desenvolvendo pacotes Laravel e distribuindo-os gratuitamente. Se este pacote economiza seu tempo ou se você confia nele profissionalmente, considere patrocinar a manutenção e o desenvolvimento e confira nosso pacote premium mais recente: Mesa de Inércia. Acompanhar problemas e solicitações pull leva tempo, mas ficaremos felizes em ajudar!
Wrapper super fácil em torno do PHP-FFMpeg, incluindo suporte para filtros e outros recursos avançados.
Integração com sistema de arquivos do Laravel, sistema de configuração e tratamento de logs.
Compatível com Laravel 10, suporte para Package Discovery.
Suporte integrado para HLS.
Suporte integrado para HLS criptografado (AES-128) e chaves rotativas (opcional).
Suporte integrado para concatenação, múltiplas entradas/saídas, sequências de imagens (timelapse), filtros complexos (e mapeamento), exportações de quadros/miniaturas.
Suporte integrado para marcas d’água (posicionamento e manipulação).
Suporte integrado para criar um mosaico/sprite/tile a partir de um vídeo.
Suporte integrado para geração de arquivos de miniatura de visualização VTT .
Requer PHP 8.1 ou superior.
Testado com FFmpeg 4.4 e 5.0.
Verifique se você tem a versão mais recente do FFmpeg instalada:
ffmpeg -versão
Você pode instalar o pacote via compositor:
compositor requer pbmedia/laravel-ffmpeg
Adicione o provedor de serviços e o Façade ao arquivo de configuração app.php
se você não estiver usando o Package Discovery.
//config/app.php'providers' => [ ...ProtoneMediaLaravelFFMpegSupportServiceProvider::class, ... ];'aliases' => [ ...'FFMpeg' => ProtoneMediaLaravelFFMpegSupportFFMpeg::class ... ];
Publique o arquivo de configuração usando a ferramenta CLI do artesão:
fornecedor de artesão php:publish --provider="ProtoneMediaLaravelFFMpegSupportServiceProvider"
A chave de configuração set_command_and_error_output_on_exception
agora é padronizada como true
, tornando as exceções mais informativas. Leia mais na seção Tratamento de exceções.
A chave de configuração enable_logging
foi substituída por log_channel
para escolher o canal de log usado ao gravar mensagens nos logs. Se ainda quiser desabilitar totalmente o log, você pode definir a nova chave de configuração como false
.
O comprimento do segmento e o intervalo do quadro-chave das exportações HLS devem ser 2
ou mais; less não é mais suportado.
Como o Laravel 9 migrou do Flysystem 1.x para 3.x, esta versão não é compatível com o Laravel 8 ou anterior.
Se você estiver usando o recurso de manipulação de marca d’água, certifique-se de atualizar spatie/image
para v2.
O namespace foi alterado para ProtoneMediaLaravelFFMpeg
, a fachada foi renomeada para ProtoneMediaLaravelFFMpegSupportFFMpeg
e o provedor de serviços foi renomeado para ProtoneMediaLaravelFFMpegSupportServiceProvider
.
As exportações em encadeamento ainda são suportadas, mas é necessário reaplicar filtros para cada exportação.
As listas de reprodução HLS agora incluem dados de taxa de bits, taxa de quadros e resolução. Os segmentos também utilizam um novo padrão de nomenclatura (leia mais). Verifique se suas exportações ainda funcionam no seu player.
A exportação HLS agora é executada como uma tarefa em vez de exportar cada formato/stream separadamente. Isso usa os recursos map
e filter_complex
do FFMpeg. Pode ser suficiente substituir todas as chamadas para addFilter
por addLegacyFilter
, mas alguns filtros devem ser migrados manualmente. Leia a documentação do HLS para saber mais sobre como adicionar filtros.
Converta um arquivo de áudio ou vídeo:
FFMpeg::fromDisk('músicas') ->abrir('ontem.mp3') ->exportar() ->toDisk('converted_songs') ->inFormat(novo FFMpegFormatAudioAac) ->salvar('ontem.aac');
Em vez do método fromDisk()
você também pode usar o método fromFilesystem()
, onde $filesystem
é uma instância de IlluminateContractsFilesystemFilesystem
.
$media = FFMpeg::fromFilesystem($filesystem)->open('ontem.mp3');
Você pode monitorar o progresso da transcodificação. Use o método onProgress
para fornecer um retorno de chamada, que fornece a porcentagem concluída. Nas versões anteriores deste pacote você tinha que passar o retorno de chamada para o objeto de formato.
FFMpeg::open('steve_howe.mp4') ->exportar() ->onProgress(function ($percentage) {echo "{$percentage}% transcodificado"; });
O retorno de chamada também pode expor $remaining
(em segundos) e $rate
:
FFMpeg::open('steve_howe.mp4') ->exportar() ->onProgress(function ($percentage, $remaining, $rate) {echo "{$remaining} segundos restantes na taxa: {$rate}"; });
Você pode abrir arquivos carregados diretamente da instância Request
. Provavelmente é melhor salvar primeiro o arquivo enviado, caso a solicitação seja abortada, mas se desejar, você pode abrir uma instância UploadedFile
:
classe UploadVideoController {função pública __invoke(Solicitação $solicitação) { FFMpeg::open($request->file('vídeo')); } }
Você pode abrir arquivos da web usando o método openUrl
. Você pode especificar cabeçalhos HTTP personalizados com o segundo parâmetro opcional:
FFMpeg::openUrl('https://videocoursebuilder.com/lesson-1.mp4'); FFMpeg::openUrl('https://videocoursebuilder.com/lesson-2.mp4', ['Autorização' => 'YWRtaW46MTIzNA==' básico, ]);
Quando a codificação falha, uma ProtoneMediaLaravelFFMpegExportersEncodingException
deve ser lançada, o que estende a classe FFMpegExceptionRuntimeException
subjacente. Esta classe possui dois métodos que podem ajudá-lo a identificar o problema. Usando o método getCommand
, você pode obter o comando executado com todos os parâmetros. O método getErrorOutput
fornece um log de saída completo.
Nas versões anteriores deste pacote, a mensagem da exceção era sempre Encoding failed . Você pode fazer downgrade para esta mensagem atualizando a chave de configuração set_command_and_error_output_on_exception
para false
.
tentar { FFMpeg::open('ontem.mp3') ->exportar() ->inFormat(novo Aac) ->salvar('ontem.aac'); } catch (EncodingException $exception) {$command = $exception->getCommand();$errorLog = $exception->getErrorOutput(); }
Você pode adicionar filtros através de um Closure
ou usando objetos Filter do PHP-FFMpeg:
use FFMpegFiltersVideoVideoFilters; FFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->addFilter(function (VideoFilters $filters) {$filters->resize(new FFMpegCoordenDimension(640, 480)); }) ->exportar() ->toDisk('converted_videos') ->inFormat(novo FFMpegFormatVideoX264) ->save('small_steve.mkv');// ou$start = FFMpegCoordinateTimeCode::fromSeconds(5)$clipFilter = new FFMpegFiltersVideoClipFilter($start); FFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->addFilter($clipFilter) ->exportar() ->toDisk('converted_videos') ->inFormat(novo FFMpegFormatVideoX264) ->salvar('short_steve.mkv');
Você também pode chamar o método addFilter
após o método export
:
use FFMpegFiltersVideoVideoFilters; FFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->exportar() ->toDisk('converted_videos') ->inFormat(novo FFMpegFormatVideoX264) ->addFilter(function (VideoFilters $filters) {$filters->resize(new FFMpegCoordenDimension(640, 480)); }) ->salvar('small_steve.mkv');
Como o redimensionamento é uma operação comum, adicionamos um método dedicado para isso:
FFMpeg::open('steve_howe.mp4') ->exportar() ->inFormat(novo FFMpegFormatVideoX264) -> redimensionar (640, 480) ->salvar('steve_howe_resized.mp4');
O primeiro argumento é a largura e o segundo argumento é a altura. O terceiro argumento opcional é o modo. Você pode escolher entre fit
(padrão), inset
, width
ou height
. O quarto argumento opcional é um booleano para forçar ou não o uso de proporções padrão. Você pode encontrar mais informações sobre esses modos na classe FFMpegFiltersVideoResizeFilter
.
Às vezes você não deseja usar os filtros integrados. Você pode aplicar seu próprio filtro fornecendo um conjunto de opções. Pode ser um array ou múltiplas strings como argumentos:
FFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->addFilter(['-itsoffset', 1]);// orFFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->addFilter('-itsoffset', 1);
Você pode adicionar facilmente uma marca d'água usando o método addWatermark
. Com o WatermarkFactory
, você pode abrir seu arquivo de marca d'água de um disco específico, da mesma forma que abre um arquivo de áudio ou vídeo. Quando você descarta o método fromDisk
, ele usa o disco padrão especificado no arquivo de configuração filesystems.php
.
Depois de abrir seu arquivo de marca d’água, você pode posicioná-lo com os métodos top
, right
, bottom
e left
. O primeiro parâmetro desses métodos é o deslocamento, que é opcional e pode ser negativo.
usar ProtoneMediaLaravelFFMpegFiltersWatermarkFactory; FFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->addWatermark(function(WatermarkFactory $watermark) {$watermark->fromDisk('local') ->abrir('logotipo.png') ->certo(25) ->fundo(25); });
Em vez de usar os métodos de posição, você também pode usar os métodos horizontalAlignment
e verticalAlignment
.
Para alinhamento horizontal, você pode usar as constantes WatermarkFactory::LEFT
, WatermarkFactory::CENTER
e WatermarkFactory::RIGHT
. Para alinhamento vertical, você pode usar as constantes WatermarkFactory::TOP
, WatermarkFactory::CENTER
e WatermarkFactory::BOTTOM
. Ambos os métodos utilizam um segundo parâmetro opcional, que é o deslocamento.
FFMpeg::open('steve_howe.mp4') ->addWatermark(function(WatermarkFactory $watermark) {$watermark->open('logo.png') ->horizontalAlignment(WatermarkFactory::LEFT, 25) ->verticalAlignment(WatermarkFactory::TOP, 25); });
O WatermarkFactory
também suporta a abertura de arquivos da web com o método openUrl
. Ele também oferece suporte a cabeçalhos HTTP personalizados.
FFMpeg::open('steve_howe.mp4') ->addWatermark(function(WatermarkFactory $watermark) {$watermark->openUrl('https://videocoursebuilder.com/logo.png');// ou$watermark->openUrl('https://videocoursebuilder.com/ logo.png', ['Autorização' => 'Básico YWRtaW46MTIzNA==', ]); });
Se quiser mais controle sobre a solicitação GET, você pode passar um terceiro parâmetro opcional, que fornece o recurso Curl.
$watermark->openUrl('https://videocoursebuilder.com/logo.png', ['Autorização' => 'YWRtaW46MTIzNA==', ], função($curl) {curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); });
Este pacote pode manipular marcas d’água usando o pacote Image do Spatie. Para começar, instale o pacote com o Composer:
compositor requer espaço/imagem
Agora você pode encadear mais um método de manipulação na instância WatermarkFactory
:
FFMpeg::open('steve_howe.mp4') ->addWatermark(function(WatermarkFactory $watermark) {$watermark->open('logo.png') ->certo(25) ->inferior(25) ->largura(100) ->altura(100) ->escala de cinza(); });
Confira a documentação para todos os métodos disponíveis.
Este pacote vem com uma classe ProtoneMediaLaravelFFMpegFFMpegCopyFormat
que permite exportar um arquivo sem transcodificar os fluxos. Você pode querer usar isso para usar outro contêiner:
usar ProtoneMediaLaravelFFMpegFFMpegCopyFormat; FFMpeg::open('video.mp4') ->exportar() ->inFormat(novo CopyFormat) ->salvar('vídeo.mkv');
// O método 'fromDisk()' não é necessário, o arquivo agora // será aberto a partir do 'disco' padrão, conforme especificado // no arquivo de configuração.FFMpeg::open('my_movie.mov')// exportar para FTP, convertido em WMV->export() ->toDisk('ftp') ->inFormat(novo FFMpegFormatVideoWMV) ->save('my_movie.wmv')// exporta para Amazon S3, convertido em X264->export() ->toDisk('s3') ->inFormat(novo FFMpegFormatVideoX264) ->save('my_movie.mkv');// você pode até descartar o método 'toDisk()',// agora o arquivo convertido será salvo // no mesmo disco da fonte!->export() ->inFormat(novo FFMpegFormatVideoWebM) ->save('my_movie.webm')// opcionalmente você pode definir a visibilidade // do arquivo exportado->export() ->inFormat(novo FFMpegFormatVideoWebM) ->withVisibility('público') -> salvar('meu_filme.webm')
FFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->getFrameFromSeconds(10) ->exportar() ->toDisk('miniaturas') ->save('FrameAt10sec.png');// Em vez do método 'getFrameFromSeconds()', você poderia// também usar os métodos 'getFrameFromString()' ou // 'getFrameFromTimecode()':$media = FFMpeg ::open('steve_howe.mp4');$frame = $media->getFrameFromString('00:00:13.37');// ou$timecode = new FFMpegCoordenTimeCode(...);$frame = $media->getFrameFromTimecode($timecode);
Você também pode obter o conteúdo bruto do quadro em vez de salvá-lo no sistema de arquivos:
$conteúdo = FFMpeg::open('video.mp4') ->getFrameFromSeconds(2) ->exportar() ->getFrameContents();
Existe um TileFilter
que alimenta o recurso Tile. Para tornar a exportação de vários quadros mais rápida e simples, aproveitamos esse recurso para adicionar alguns métodos auxiliares. Por exemplo, você pode usar o método exportFramesByInterval
para exportar quadros em um intervalo fixo. Alternativamente, você pode passar o número de frames que deseja exportar para o método exportFramesByAmount
, que calculará o intervalo com base na duração do vídeo.
FFMpeg::open('video.mp4') ->exportFramesByInterval(2) ->salvar('thumb_%05d.jpg');
Ambos os métodos aceitam um segundo e terceiro argumentos opcionais para especificar a largura e a altura dos quadros. Em vez de passar a largura e a altura, você também pode passar apenas uma delas. O FFmpeg respeitará a proporção da fonte.
FFMpeg::open('video.mp4') ->exportFramesByAmount(10, 320, 180) ->salvar('thumb_%05d.png');
Ambos os métodos aceitam um quarto argumento opcional para especificar a qualidade da imagem quando você exporta para um formato com perdas como JPEG. O intervalo para JPEG é 2-31
, sendo 2
a melhor qualidade e 31
a pior.
FFMpeg::open('video.mp4') ->exportFramesByInterval(2, 640, 360, 5) ->salvar('thumb_%05d.jpg');
Você pode criar blocos a partir de um vídeo. Você pode chamar o método exportTile
para especificar como seus blocos devem ser gerados. No exemplo abaixo, cada imagem gerada consiste em uma grade 3x5 (contendo, portanto, 15 quadros) e cada quadro tem 160x90 pixels. Um quadro será tirado a cada 5 segundos do vídeo. Em vez de passar a largura e a altura, você também pode passar apenas uma delas. O FFmpeg respeitará a proporção da fonte.
usar ProtoneMediaLaravelFFMpegFiltersTileFactory; FFMpeg::open('steve_howe.mp4') ->exportTile(função (TileFactory $fábrica) {$fábrica->intervalo(5) ->escala(160, 90) ->grade(3, 5); }) ->salvar('tile_%05d.jpg');
Em vez de passar a largura e a altura, você também pode passar apenas um deles, como scale(160)
ou scale(null, 90)
. A proporção será respeitada. O TileFactory
também possui métodos margin
, padding
, width
e height
. Também existe um método quality
para especificar a qualidade ao exportar para um formato com perdas como JPEG. O intervalo para JPEG é 2-31
, sendo 2
a melhor qualidade e 31
a pior.
Este pacote também pode gerar um arquivo WebVTT para adicionar miniaturas de visualização ao seu reprodutor de vídeo. Isso é compatível imediatamente com o JW player e também há plug-ins da comunidade para Video.js disponíveis. Você pode chamar o método generateVTT
no TileFactory
com o nome de arquivo desejado:
FFMpeg::open('steve_howe.mp4') ->exportTile(função (TileFactory $fábrica) {$fábrica->intervalo(10) ->escala(320, 180) -> grade (5, 5) ->generateVTT('thumbnails.vtt'); }) ->salvar('tile_%05d.jpg');
Encadear múltiplas conversões funciona porque o método save
do MediaExporter
retorna uma nova instância do MediaOpener
. Você pode usar isso para percorrer itens, por exemplo, para exportar vários quadros de um vídeo:
$mediaOpener = FFMpeg::open('video.mp4');foreach ([5, 15, 25] as $key => $seconds) {$mediaOpener = $mediaOpener->getFrameFromSeconds($seconds) ->exportar() ->save("thumb_{$key}.png"); }
O MediaOpener
também vem com each
método. O exemplo acima poderia ser refatorado assim:
FFMpeg::open('video.mp4')->each([5, 15, 25], function ($ffmpeg, $seconds, $key) {$ffmpeg->getFrameFromSeconds($seconds)->export()- >save("thumb_{$key}.png"); });
Você pode criar um timelapse a partir de uma sequência de imagens usando o método asTimelapseWithFramerate
no exportador
FFMpeg::open('feature_%04d.png') ->exportar() ->asTimelapseWithFramerate(1) ->inFormat(novo X264) ->salvar('timelapse.mp4');
Você pode abrir múltiplas entradas, até mesmo de discos diferentes. Isso usa os recursos map
e filter_complex
do FFMpeg. Você pode abrir vários arquivos encadeando o método open
usando um array. Você pode misturar entradas de discos diferentes.
FFMpeg::open('video1.mp4')->open('video2.mp4'); FFMpeg::open(['video1.mp4', 'video2.mp4']); FFMpeg::fromDisk('uploads') ->abrir('vídeo1.mp4') ->fromDisk('arquivo') ->abrir('video2.mp4');
Ao abrir múltiplas entradas, você deve adicionar mapeamentos para que o FFMpeg saiba como roteá-los. Este pacote fornece um método addFormatOutputMapping
, que usa três parâmetros: o formato, a saída e os rótulos de saída da parte -filter_complex
.
A saída (2º argumento) deve ser uma instância de ProtoneMediaLaravelFFMpegFilesystemMedia
. Você pode instanciar com o método make
, chamá-lo com o nome do disco e o caminho (ver exemplo).
Confira este exemplo, que mapeia entradas separadas de vídeo e áudio em uma saída.
FFMpeg::fromDisk('local') ->abrir(['vídeo.mp4', 'áudio.m4a']) ->exportar() ->addFormatOutputMapping(new X264, Media::make('local', 'new_video.mp4'), ['0:v', '1:a']) ->salvar();
Este é um exemplo da biblioteca subjacente:
// Este código pega 2 vídeos de entrada, empilha-os horizontalmente em 1 vídeo de saída e // adiciona a este novo vídeo o áudio do primeiro vídeo. (É impossível // com um gráfico de filtro simples que tenha apenas 1 entrada e apenas 1 saída).FFMpeg::fromDisk('local') ->abrir(['video.mp4', 'video2.mp4']) ->exportar() ->addFilter('[0:v][1:v]', 'hstack', '[v]') // $in, $parameters, $out->addFormatOutputMapping(new X264, Media::make(' local', 'stacked_video.mp4'), ['0:a', '[v]']) ->salvar();
Assim como nas entradas únicas, você também pode passar um retorno de chamada para o método addFilter
. Isso lhe dará uma instância de FFMpegFiltersAdvancedMediaComplexFilters
:
use FFMpegFiltersAdvancedMediaComplexFilters; FFMpeg::open(['video.mp4', 'video2.mp4']) ->exportar() ->addFilter(function(ComplexFilters $filters) {// $filters->watermark(...);});
Abrir arquivos da web funciona de forma semelhante. Você pode passar uma série de URLs para o método openUrl
, opcionalmente com cabeçalhos HTTP personalizados.
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', ], ['Autorização' => 'YWRtaW46MTIzNA==' básico, ]);
Se quiser usar outro conjunto de cabeçalhos HTTP para cada URL, você pode encadear o método openUrl
:
FFMpeg::openUrl('https://videocoursebuilder.com/lesson-5.mp4', ['Autorização' => 'YWRtaW46MTIzNA==' básico, ])->openUrl('https://videocoursebuilder.com/lesson-6.mp4', ['Autorização' => 'Básico bmltZGE6NDMyMQ==', ]);
FFMpeg::fromDisk('local') ->abrir(['video.mp4', 'video2.mp4']) ->exportar() ->concatSemTranscodificação() ->salvar('concat.mp4');
FFMpeg::fromDisk('local') ->abrir(['video.mp4', 'video2.mp4']) ->exportar() ->inFormat(novo X264) ->concatWithTranscoding($hasVideo = true, $hasAudio = true) ->salvar('concat.mp4');
Com a classe Media
você pode determinar a duração de um arquivo:
$media = FFMpeg::open('wwdc_2006.mp4');$durationInSeconds = $media->getDurationInSeconds(); // retorna um int$durationInMiliseconds = $media->getDurationInMiliseconds(); //retorna um float
Ao abrir ou salvar arquivos de ou para um disco remoto, arquivos temporários serão criados em seu servidor. Depois de exportar ou processar esses arquivos, você pode limpá-los chamando o método cleanupTemporaryFiles()
:
FFMpeg::cleanupTemporaryFiles();
Por padrão, a raiz dos diretórios temporários é avaliada pelo método sys_get_temp_dir()
do PHP, mas você pode modificá-la definindo a chave de configuração temporary_files_root
para um caminho personalizado.
Você pode criar uma lista de reprodução M3U8 para fazer HLS.
$lowBitrate = (novo X264)->setKiloBitrate(250);$midBitrate = (novo X264)->setKiloBitrate(500);$highBitrate = (novo X264)->setKiloBitrate(1000); FFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->exportForHLS() ->setSegmentLength(10) // opcional->setKeyFrameInterval(48) // opcional->addFormat($lowBitrate) ->addFormat($midBitrate) ->addFormat($highBitrate) ->salvar('adaptive_steve.m3u8');
O método addFormat
do exportador HLS utiliza um segundo parâmetro opcional que pode ser um método de retorno de chamada. Isso permite adicionar diferentes filtros por formato. Primeiro, verifique a seção Múltiplas entradas para entender como os filtros complexos são tratados.
Você pode usar o método addFilter
para adicionar um filtro complexo (veja o exemplo $lowBitrate
). Como o filtro scale
é muito usado, existe um método auxiliar (veja o exemplo $midBitrate
). Você também pode usar um callable para obter acesso à instância ComplexFilters
. O pacote fornece os argumentos $in
e $out
para que você não precise se preocupar com isso (veja o exemplo $highBitrate
).
A exportação HLS é construída usando os recursos map
e filter_complex
do FFMpeg. Esta é uma alteração significativa em relação às versões anteriores (1.x - 6.x), que realizavam uma única exportação para cada formato. Se você estiver atualizando, substitua as chamadas addFilter
por chamadas addLegacyFilter
e verifique o resultado (veja o exemplo $superBitrate
). Nem todos os filtros funcionarão desta forma e alguns precisam ser atualizados manualmente.
$lowBitrate = (novo X264)->setKiloBitrate(250);$midBitrate = (novo X264)->setKiloBitrate(500);$highBitrate = (novo X264)->setKiloBitrate(1000);$superBitrate = (novo X264)- >setKiloBitrate(1500); FFMpeg::open('steve_howe.mp4') ->exportForHLS() ->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, $parâmetros, $out}); }) ->addFormat($superBitrate, function($media) {$media->addLegacyFilter(function ($filters) {$filters->resize(new FFMpegCoordenDimension(2560, 1920)); }); }) ->salvar('adaptive_steve.m3u8');
Você pode usar um padrão personalizado para nomear os segmentos e playlists. O useSegmentFilenameGenerator
fornece 5 argumentos. O primeiro, segundo e terceiro argumentos fornecem informações sobre o nome base da exportação, o formato da iteração atual e a chave da iteração atual. O quarto argumento é um retorno de chamada que você deve chamar com seu padrão de segmentos . O quinto argumento é um retorno de chamada que você deve chamar com o padrão da sua lista de reprodução . Observe que este não é o nome da playlist principal, mas sim o nome da playlist de cada formato.
FFMpeg::fromDisk('vídeos') ->abrir('steve_howe.mp4') ->exportForHLS() ->useSegmentFilenameGenerator(function ($name, $format, $key, $segments chamáveis, $playlist chamável) {$segments("{$name}-{$format->getKiloBitrate()}-{$key}-%03d .ts");$playlist("{$name}-{$format->getKiloBitrate()}-{$key}.m3u8"); });
Você pode criptografar cada segmento HLS usando criptografia AES-128. Para fazer isso, chame o método withEncryptionKey
no exportador HLS com uma chave. Fornecemos um método auxiliar generateEncryptionKey
na classe HLSExporter
para gerar uma chave. Certifique-se de armazenar bem a chave, pois o resultado exportado não vale nada sem a chave. Por padrão, o nome do arquivo da chave é secret.key
, mas você pode alterar isso com o segundo parâmetro opcional do método withEncryptionKey
.
use ProtoneMediaLaravelFFMpegExportersHLSExporter;$encryptionKey = HLSExporter::generateEncryptionKey(); FFMpeg::open('steve_howe.mp4') ->exportForHLS() ->withEncryptionKey($encryptionKey) ->addFormat($lowBitrate) ->addFormat($midBitrate) ->addFormat($highBitrate) ->salvar('adaptive_steve.m3u8');
Para proteger ainda mais sua exportação HLS, você pode girar a chave em cada segmento exportado. Ao fazer isso, serão geradas várias chaves que você precisará armazenar. Use o método withRotatingEncryptionKey
para habilitar esse recurso e fornecer um retorno de chamada que implemente o armazenamento das chaves.
FFMpeg::open('steve_howe.mp4') ->exportForHLS() ->withRotatingEncryptionKey(function ($filename, $contents) {$videoId = 1;// use este retorno de chamada para armazenar as chaves de criptografiaStorage::disk('secrets')->put($videoId . '/' . $filename, $contents);// ou...DB::table('hls_secrets')->insert(['video_id' => $videoId,'filename' => $nomedoarquivo,'conteúdo' => $conteúdo, ]); }) ->addFormat($lowBitrate) ->addFormat($midBitrate) ->addFormat($highBitrate) ->salvar('adaptive_steve.m3u8');
O método withRotatingEncryptionKey
possui um segundo argumento opcional para definir o número de segmentos que usam a mesma chave. O padrão é 1
.
FFMpeg::open('steve_howe.mp4') ->exportForHLS() ->withRotatingEncryptionKey($callable, 10);
Alguns sistemas de arquivos, especialmente em VPSs baratos e lentos, não são rápidos o suficiente para lidar com a chave rotativa. Isso pode levar a exceções de codificação, como No key URI specified in key info file
. Uma solução possível é usar um armazenamento diferente para as chaves, que você pode especificar usando a chave de configuração temporary_files_encrypted_hls
. Em sistemas baseados em UNIX, você pode usar um sistema de arquivos tmpfs
para aumentar as velocidades de leitura/gravação:
//config/laravel-ffmpeg.phpreturn ['temporary_files_encrypted_hls' => '/dev/shm'];
Para tornar o trabalho com HLS criptografado ainda melhor, adicionamos uma classe DynamicHLSPlaylist
que modifica listas de reprodução dinamicamente e especificamente para seu aplicativo. Dessa forma, você pode adicionar sua lógica de autenticação e autorização. Como estamos usando um controlador Laravel simples, você pode usar recursos como Gates e Middleware.
Neste exemplo, salvamos a exportação HLS no disco public
e armazenamos as chaves de criptografia no disco secrets
, que não está disponível publicamente. Como o navegador não consegue acessar as chaves de criptografia, ele não reproduz o vídeo. Cada lista de reprodução possui caminhos para as chaves de criptografia e precisamos modificar esses caminhos para apontar para um terminal acessível.
Esta implementação consiste em duas rotas. Um que responda com uma chave de criptografia e outro que responda com uma lista de reprodução modificada. A primeira rota ( video.key
) é relativamente simples e é aqui que você deve adicionar sua lógica adicional.
A segunda rota ( video.playlist
) usa a classe DynamicHLSPlaylist
. Chame o método dynamicHLSPlaylist
na fachada FFMpeg
e, semelhante à abertura de arquivos de mídia, você pode abrir uma lista de reprodução utilizando os métodos fromDisk
e open
. Então você deve fornecer três retornos de chamada. Cada um deles fornece um caminho relativo e espera um caminho completo em troca. Como a classe DynamicHLSPlaylist
implementa a interface IlluminateContractsSupportResponsable
, você pode retornar a instância.
O primeiro retorno de chamada (KeyUrlResolver) fornece o caminho relativo para uma chave de criptografia. O segundo retorno de chamada (MediaUrlResolver) fornece o caminho relativo para um segmento de mídia (arquivos .ts). O terceiro retorno de chamada (PlaylistUrlResolver) fornece o caminho relativo para uma lista de reprodução.
Agora, em vez de usar Storage::disk('public')->url('adaptive_steve.m3u8')
para obter o URL completo da sua playlist principal, você pode usar route('video.playlist', ['playlist' => 'adaptive_steve.m3u8'])
. A classe DynamicHLSPlaylist
cuida de todos os caminhos e URLs.
Route::get('/video/secret/{key}', function ($key) {return Storage::disk('secrets')->download($key); })->nome('video.key'); Route::get('/video/{playlist}', function ($playlist) {return FFMpeg::dynamicHLSPlaylist() ->fromDisk('público') ->abrir($lista de reprodução) ->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]); }); })->nome('video.playlist');
Aqui você pode encontrar uma sessão de codificação ao vivo sobre criptografia HLS:
https://www.youtube.com/watch?v=WlbzWoAcez4
Você pode obter a saída bruta do processo chamando o método getProcessOutput
. Embora o caso de uso seja limitado, você pode usá-lo para analisar um arquivo (por exemplo, com o filtro volumedetect
). Ele retorna uma classe ProtoneMediaLaravelFFMpegSupportProcessOutput
que possui três métodos: all
, errors
e output
. Cada método retorna um array com as linhas correspondentes.
$processOutput = FFMpeg::open('video.mp4') ->exportar() ->addFilter(['-filter:a', 'volumedetect', '-f', 'null']) ->getProcessOutput();$processOutput->all();$processOutput->errors();$processOutput->out();
O objeto Media que você obtém quando 'abre' um arquivo, na verdade contém o objeto Media que pertence ao driver subjacente. Ele lida com chamadas de métodos dinâmicos, como você pode ver aqui. Dessa forma, todos os métodos do driver subjacente ainda estarão disponíveis para você.
// Isso fornece uma instância de ProtoneMediaLaravelFFMpegMediaOpener$media = FFMpeg::fromDisk('videos')->open('video.mp4');// O método 'getStreams' será chamado no objeto Media subjacente já que // ele não existe neste objeto.$codec = $media->getStreams()->first()->get('codec_name');
Se você quiser acesso direto ao objeto subjacente, chame o objeto como uma função (invoque):
// Isso fornece uma instância de ProtoneMediaLaravelFFMpegMediaOpener$media = FFMpeg::fromDisk('videos')->open('video.mp4'); // Isso fornece uma instância de FFMpegMediaMediaTypeInterface$baseMedia = $media();
O ouvinte de progresso expõe a porcentagem transcodificada, mas o pacote subjacente também possui um AbstractProgressListener
interno que expõe a passagem atual e a hora atual. Embora o caso de uso seja limitado, talvez você queira obter acesso a esta instância do ouvinte. Você pode fazer isso decorando o formato com ProgressListenerDecorator
. Esse recurso é altamente experimental, portanto, teste-o completamente antes de usá-lo na produção.
use FFMpegFormatProgressListenerAbstractProgressListener;use ProtoneMediaLaravelFFMpegFFMpegProgressListenerDecorator;$format = new FFMpegFormatVideoX264;$decoratedFormat = ProgressListenerDecorator::decorate($format); FFMpeg::open('video.mp4') ->exportar() ->inFormat($decoradoFormat) ->onProgress(function () use ($decoratedFormat) {$listeners = $decoratedFormat->getListeners(); // array de ouvintes$listener = $listeners[0]; // instância de AbstractProgressListener$listener->getCurrentPass() ;$listener->getTotalPass();$listener->getCurrentTime(); }) ->salvar('novo_vídeo.mp4');
Como não podemos nos livrar de algumas das opções subjacentes, você pode interagir com o comando final do FFmpeg adicionando um retorno de chamada ao exportador. Você pode adicionar um ou mais retornos de chamada usando o método beforeSaving
:
FFMpeg::open('video.mp4') ->exportar() ->inFormat(novo X264) ->beforeSaving(function ($commands) {$commands[] = '-hello';return $commands; }) ->salvar('concat.mp4');
Nota: isso não funciona com concatenação e exportações de quadros
Aqui está uma postagem no blog que ajudará você a começar com este pacote:
https://protone.media/en/blog/how-to-use-ffmpeg-in-your-laravel-projects
Aqui está uma visão geral de 20 minutos sobre como começar a usar Video.js. Abrange a inclusão de Video.js de um CDN, sua importação como um módulo ES6 com Laravel Mix (Webpack) e a construção de um componente Vue.js reutilizável.
https://www.youtube.com/watch?v=nA1Jy8BPjys
Filtros personalizados
FFmpeg falhou ao executar o comando
Obtenha as dimensões de um arquivo de vídeo
Monitorando o progresso da transcodificação
Não foi possível carregar o FFProbe
Consulte CHANGELOG para obter mais informações sobre o que mudou recentemente.
$ teste do compositor
Consulte CONTRIBUINDO para obter detalhes.
Inertia Table
: a tabela definitiva para Inertia.js com Query Builder integrado.
Laravel Blade On Demand
: pacote Laravel para compilar templates Blade na memória.
Laravel Cross Eloquent Search
: pacote Laravel para pesquisar vários modelos do Eloquent.
Laravel Eloquent Scope as Select
: Pare de duplicar seus escopos e restrições de consulta Eloquent em PHP. Este pacote permite reutilizar escopos e restrições de consulta adicionando-os como uma subconsulta.
Laravel MinIO Testing Tools
: execute seus testes em um servidor MinIO S3.
Laravel Mixins
: Uma coleção de guloseimas do Laravel.
Laravel Paddle
: integração API Paddle.com para Laravel com suporte para webhooks/eventos.
Laravel Task Runner
: Escreva scripts Shell como componentes Blade e execute-os localmente ou em um servidor remoto.
Laravel Verify New Email
: Este pacote adiciona suporte para verificação de novos endereços de email: quando um usuário atualiza seu endereço de email, ele não substituirá o antigo até que o novo seja verificado.
Laravel XSS Protection
: Laravel Middleware para proteger seu aplicativo contra scripts entre sites (XSS). Ele limpa a entrada de solicitação e pode limpar instruções de eco do Blade.
Se você descobrir algum problema relacionado à segurança, envie um e-mail para [email protected] em vez de usar o rastreador de problemas. Por favor, não envie nenhuma pergunta por e-mail, abra um problema se tiver alguma dúvida.
Pascal Baljet
Todos os colaboradores
A licença MIT (MIT). Consulte Arquivo de licença para obter mais informações.