ffmpeg conversão de WebM para MP4 - como manter o tamanho do arquivo?

0

Eu estou tentando converter um arquivo WebM para MP4, usando os seguintes parâmetros:

ffmpeg -loglevel info -i 2017-05-01-122851.webm -c:v libx264 -preset slower -crf 20 -bf 2 -trellis 2 -cmp 2 -subcmp 2 -g 45 -c:a aac -strict experimental -ab 32k ../renamed-video/2017-05-01-122851.mp4

ffmpeg version 3.0.7-0ubuntu0.16.10.1 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 6.2.0 (Ubuntu 6.2.0-5ubuntu12) 20161005
  configuration: --prefix=/usr --extra-version=0ubuntu0.16.10.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --cc=cc --cxx=g++ --enable-gpl --enable-shared --disable-stripping --disable-decoder=libopenjpeg --disable-decoder=libschroedinger --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librubberband --enable-librtmp --enable-libschroedinger --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzvbi --enable-openal --enable-opengl --enable-x11grab --enable-libdc1394 --enable-libiec61883 --enable-libzmq --enable-frei0r --enable-chromaprint --enable-libx264
  libavutil      55. 17.103 / 55. 17.103
  libavcodec     57. 24.102 / 57. 24.102
  libavformat    57. 25.100 / 57. 25.100
  libavdevice    57.  0.101 / 57.  0.101
  libavfilter     6. 31.100 /  6. 31.100
  libavresample   3.  0.  0 /  3.  0.  0
  libswscale      4.  0.100 /  4.  0.100
  libswresample   2.  0.101 /  2.  0.101
  libpostproc    54.  0.100 / 54.  0.100
Input #0, matroska,webm, from '2017-05-01-122851.webm':
  Metadata:
    encoder         : GStreamer matroskamux version 1.8.3
    creation_time   : 2017-05-01 10:28:51
  Duration: 00:04:32.88, start: 0.000000, bitrate: 3160 kb/s
    Stream #0:0(eng): Video: vp8, yuv420p, 1280x720, SAR 1:1 DAR 16:9, 250 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      title           : Video
    Stream #0:1(eng): Audio: vorbis, 44100 Hz, mono, fltp (default)
    Metadata:
      title           : Audio
File '../renamed-video/2017-05-01-122851.mp4' already exists. Overwrite ? [y/N] y
[libx264 @ 0x55d5e57dde80] using SAR=1/1
[libx264 @ 0x55d5e57dde80] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2
[libx264 @ 0x55d5e57dde80] profile High, level 5.1
[libx264 @ 0x55d5e57dde80] 264 - core 148 r2699 a5e06b9 - H.264/MPEG-4 AVC codec - Copyleft 2003-2016 - http://www.videolan.org/x264.html - options: cabac=1 ref=8 deblock=1:0:0 analyse=0x3:0x133 me=umh subme=9 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=0 trellis=2 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=2 b_pyramid=2 b_adapt=2 b_bias=0 direct=3 weightb=1 open_gop=0 weightp=2 keyint=45 keyint_min=4 scenecut=40 intra_refresh=0 rc_lookahead=45 rc=crf mbtree=1 crf=20.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to '../renamed-video/2017-05-01-122851.mp4':
  Metadata:
    encoder         : Lavf57.25.100
    Stream #0:0(eng): Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], q=-1--1, 250 fps, 16k tbn, 250 tbc (default)
    Metadata:
      title           : Video
      encoder         : Lavc57.24.102 libx264
    Side data:
      unknown side data type 10 (24 bytes)
    Stream #0:1(eng): Audio: aac (LC) ([64][0][0][0] / 0x0040), 44100 Hz, mono, fltp, 32 kb/s (default)
    Metadata:
      title           : Audio
      encoder         : Lavc57.24.102 aac
Stream mapping:
  Stream #0:0 -> #0:0 (vp8 (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (vorbis (native) -> aac (native))
Press [q] to stop, [?] for help
frame=  768 fps= 32 q=-1.0 Lsize=    2573kB time=00:00:03.20 bitrate=6576.7kbits/s dup=676 drop=0 speed=0.136x    

O problema é que o arquivo de saída é muito maior que o arquivo de origem. Como posso ajustar o tamanho para que os dois arquivos tenham o mesmo tamanho / definição? Além disso, vejo esse aviso, e não sei se tenho que ter medo dele:

tipo de dados do lado desconhecido 10 (24 bytes).

liv913
fonte
2
Se você quiser atingir o mesmo tamanho, use dois passes e ABR -c:v libx264 -preset slower -b:v <YOUR_BITRATE>k -pass <PASS_#> . O CRF (Fator de Taxa Constante) é usado para obter uma certa qualidade visual de forma alguma (além de experiência ou tentativa e erro) para saber a taxa de bits média antes.
flolilo
1
@ liv913 -loglevel infoé o padrão, por isso não faz nada. Qual é o motivo para adicionar -bf 2 -trellis 2 -cmp 2 -subcmp 2? Essas opções são cobertas pela predefinição.
llogan
@flolilolilo Você deve postar isso (com um pouco mais de explicação) como resposta.
slhck
@slhck done - Espero não ter esquecido nada. @ liv913 afirma algo além unknown side data type 10 (24 bytes)? como [libx264 0x123456] unknown side data type 10 (24 bytes)(isto é claro, é um exemplo inventado).
flolilo
Obrigado rapazes. @ LordNeckbeard: como posso ver a lista de opções abrangidas pela predefinição slower? Usando o comando help, ffmpeg -hide_banner -f lavfi -i nullsrc -c:v libx264 -preset help -f mp4 -só posso ver a lista de presets, não o que eles devem fazer.
liv913

Respostas:

3

Com -crf, você não pode realmente atingir o mesmo tamanho. CRF significa "Fator de Taxa Constante" - é um valor sem unidade (ou seja, sem%, sem kb / s, ...) entre 0 (sem perda) e 51 (pior qualidade) (valor padrão para x264: 23). O propósito do CRF é alcançar uma certa qualidade visual sem ter que definir taxas de bits . Os estados do Guia H.264 do FFmpeg :

[...] um intervalo subjetivamente são 18-28. Considere 18 como sendo visualmente sem perda ou quase: deve ter a mesma aparência [...] que a entrada, mas não é tecnicamente sem perdas. O intervalo é exponencial, portanto, aumentar o valor de CRF +6 é aproximadamente metade da taxa de bits, enquanto -6 é aproximadamente o dobro da taxa de bits.

(Observe que diferentes codificadores podem ter diferentes faixas de valores de CRF: por exemplo, o valor de CRF padrão de x265 é 28 , que deve ser visualmente igual a 23 de x264).

É claro que você pode mexer -crfaté obter o tamanho de arquivo desejado - mas isso geralmente significa muito teste e erro.


Agora pode-se perguntar "mas se a qualidade é a mesma e x264 é supostamente um bom codificador, então por que o CRF não tornará o arquivo menor? "

A resposta para essa pergunta é fácil: o x264 (como virtualmente todos os outros codificadores no mercado) não tem como detectar a eficiência do arquivo de entrada codificado. Pode saber que tem um ABR (Average Bit Rate) de 2 Mb / s, mas isso não diz nada sobre a qualidade. E se o seu arquivo de entrada foi codificado de forma insatisfatória (baixa taxa de bits e / ou configurações de codificador muito rápidas), então ele pode ter artefatos (blocos, ...). Você pode vê-los, mas o x264 não pode (realmente) fazê-lo [1] - então, afirmando -crf, ele pressupõe que você deseja conservar todos os artefatos em seu novo arquivo na medida em que seu valor (0-51) for capaz de , o que leva a taxas de bits mais altas porque os artefatos (como o ruído) não são fáceis de prever.

[1] Imagine como ver uma parede de tijolos - enquanto você pode reconhecê-la como tal por causa da cor vermelha dos tijolos em forma de quadrado e da argamassa cinza entre eles, tudo o que o codificador vê são os pixels vermelho e cinza.


Então, o caminho para alcançar um certo tamanho de arquivo é via ABR , que é o -b:vparâmetro no FFmpeg libx264. A ABR trabalha com taxas de bits variáveis ​​(VBR), mas tenta alcançar uma taxa de bits média conforme especificado em todo o arquivo. Para fazer com que esse princípio funcione bem, deve-se usar dois passos para que o FFmpeg possa primeiro olhar para o arquivo e calcular as taxas de bits e depois codificá-lo em uma segunda etapa.

Se o seu objetivo é ter um arquivo resultante com o mesmo tamanho do arquivo de entrada, você pode calcular sua taxa de bits da seguinte maneira :

(<FILESIZE_INPUT-FILE> [MiB] * 8192) / <DURATION_INPUT-FILE> [seconds] = ~XYZ [kBit/s total bitrate]
XYZ [kBit/s total bitrate] - <DESIRED_AUDIO_BITRATE> [kBit/s] = ___ [kBit/s video bitrate]

Anotações [brackets], valores para você preencher <ANGLE_BRACKETS>e seu resultado como ___linha de sublinhados.

Com a sintaxe resultante:

ffmpeg -y -i <INPUT-FILE-PATH> -c:v libx264 -b:v ___k -preset slower <OTHER_COMMANDS_LIKE_AUDIO> -pass 1 -f <OUTPUT-FILE-FORMAT> /dev/null && \
ffmpeg -y -i <INPUT-FILE-PATH> -c:v libx264 -b:v ___k -preset slower <OTHER_COMMANDS_LIKE_AUDIO> -pass 2 <OUTPUT-FILE-PATH>

Em x264, CRF e ABR são mutuamente exclusivos - você pode usar um ou outro, então sua escolha com x264 sempre terá qualidade garantida versus tamanho de arquivo garantido. Até onde eu sei, outros codificadores ( como x265 ) podem usar uma combinação de ABR e CRF, então você pode especificar uma taxa de bits e uma faixa de qualidade que o codificador tenta alcançar. Mas você sempre pode ter apenas uma prioridade mais alta: qualidade visual ou tamanho do arquivo de destino (ou velocidade de codificação). Com muita experiência, pode-se alcançar "o equilíbrio perfeito" para qualquer trabalho, mas ainda assim seria um compromisso.


Um último comentário sobre os parâmetros no ffmpeg:

Se você não precisa de parâmetros ( e há muitas ocasiões em que alguém precisaria deles ), não os especifique. -loglevel infoé o padrão, então por que você especificou? O melhor que pode fazer é quebrar seu código se você tiver um erro de digitação (o mesmo vale para -trellis). Além disso, libx264faz um bom trabalho ao especificar GOPs, portanto, -gpode não ser necessário, a menos que você precise de um mecanismo específico de reprodução / ... (o mesmo vale para -cmpe -csubcmp).

Os desenvolvedores dos codificadores geralmente tentam facilitar o uso de seus produtos e, portanto, valores padrão na maioria das vezes são muito melhores do que digitar cegamente em parâmetros aleatórios que alguém na internet encontrou há 10 anos na primeira documentação disponível.

Embora, é claro, se você fez sua pesquisa e você tenha a experiência (ou simplesmente deseja experimentá-la), não há como eu impedir que você vá para o limite de caracteres do console de comando com o ffmpeg!

flolilo
fonte