ffmpeg 从 WebM 转换为 MP4 – 如何保持文件大小?

ffmpeg 从 WebM 转换为 MP4 – 如何保持文件大小?

我正在尝试将 WebM 文件转换为 MP4,使用以下参数:

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    

问题是输出文件比源文件大得多。我该如何调整大小以使两个文件具有相同的大小/定义?此外,我看到这个警告,我不知道是否应该害怕它:

未知侧数据类型 10(24 字节)。

答案1

使用-crf,您无法真正实现相同的大小。CRF 表示“恒定速率因子” - 它是一个无单位(意味着没有 %,没有 kb/s,...)值,介于 0(无损)和 51(最差质量)之间(x264 的默认值:23)。CRF 的目的是实现一定的视觉质量无需定义比特率FFmpeg 的 H.264 指南状态:

[...] 主观上合理的范围是 18-28。认为 18 在视觉上无损或接近无损:它应该看起来与输入相同 [...] 但从技术上讲它不是无损的。范围是指数级的,因此将 CRF 值增加 +6 大约是比特率的一半,而 -6 大约是比特率的两倍。

(请注意,不同的编码器可能具有不同的 CRF 值范围:例如,x265 的默认 CRF 值为 28, 哪个应该视觉上与 x264 的 23 相同。)

当然,您可以随意摆弄,-crf直到获得所需的文件大小 - 但这通常意味着大量的反复试验。


现在有人可能会问“但如果质量相同,并且 x264 应该是一个很好的编码器,那么为什么CRF不会使文件变小?

这个问题的答案很简单:x264(就像市场上几乎所有其他编码器一样)无法检测输入文件的编码效率。它可能知道它的 ABR(平均比特率)为 2 Mb/s,但这并不能说明质量。如果您的输入文件编码不佳(低比特率和/或非常快的编码器设置),那么它可能会有瑕疵(块,...)。您可以看到它们,但 x264 不能(真的)这样做[1] - 因此通过声明-crf,它假设您希望在新文件中的所有瑕疵保留到您的值(0-51)能够保留的程度,这会导致更高的比特率,因为瑕疵(如噪音)不易预测。

[1] 想象一下看到一堵砖墙——虽然你可以根据方形砖块的红色和它们之间的灰色砂浆认出它是砖墙,但编码器看到的都是红色和灰色像素。


因此,实现特定文件大小的方法是通过 ABR,这是-b:vFFmpeg 的 中的 -parameter。ABRlibx264适用于可变比特率 (VBR),但它会尝试在整个文件中实现指定的平均比特率。为了使该原则发挥作用,应该使用两次传递,以便 FFmpeg 可以首先查看文件并计算比特率,然后在第二步对其进行编码。

如果你的目标是得到一个与输入文件大小相同的结果文件,你可以用这种方式计算你的比特率

(<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]

中的注释[brackets],中需要您填写的值,以及作为下划线行的<ANGLE_BRACKETS>结果。___

使用结果语法:

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>

在x264中,CRF和ABR是互斥的- 您可以使用其中一种,因此,使用 x264 时,您的选择始终是保证质量与保证文件大小。据我所知,其他编码器(像 x265) 可以结合使用 ABR 和 CRF,因此您可以指定编码器试图实现的比特率和质量范围。但您始终只能有一个最高优先级:视觉质量或目标文件大小(或编码速度)。凭借丰富的经验,人们可以为任何给定的工作实现“完美平衡”,但这仍然是一种妥协。


关于 ffmpeg 中的参数的最后一条评论:

如果你不需要参数(有很多场合都需要它们),不要指定它们。-loglevel info是默认值,那么为什么要指定它呢?它能做的最好的事情就是,如果您的代码中有拼写错误,它就会破坏您的代码(同样适用于-trellis)。此外,libx264在指定 GOP 方面做得很好,所以-g除非您需要它用于特定的播放引擎/...(同样适用于-cmp-csubcmp)。

编码器的开发人员通常会尝试使其产品的使用变得简单,因此,大多数情况下,默认值比盲目输入 10 年前某人在互联网上找到的第一个文档中的随机参数要好得多。

当然,如果你已经做过研究,而且有经验(或者只是想尝试一下),我绝不会阻止你使用 ffmpeg 进入命令控制台的字符限制!

答案2

最简单、最快捷的解决方案,不需要重新编码或猜测最终文件大小:只需将音频和视频复制到 matroska 容器即可。

ffmpeg -i 2017-05-01-122851.webm -vcodec 复制 -acodec 复制 2017-05-01-122851.mkv

这样,只有文件大小差异可以是容器开销,这通常是边际的。

相关内容