如何在不依赖fps的情况下提取“存储的帧”?

如何在不依赖fps的情况下提取“存储的帧”?

我注意到如果我用这个命令提取帧:

ffmpeg -i sample_nosound.mp4 $filename%03d.jpg

默认情况下,它会根据 fps 进行提取。ffmpeg -i sample_nosound.mp4显示该视频的帧率为 6 fps,因此它提取了 1630 个 jpg 帧文件,其中 1630/6 = 271.6 秒相当于 4:32 的视频总时长。

但 1630 jpg 帧的总大小为 13 MB:

$ du -h extracted_jpg_folder
13M      extracted_jpg_folder

,而 mp4 的文件大小为 1.8 MB,远低于总帧大小:

$ ls -la sample_nosound.mp4
-rw-rw-r-- 1 xiaobai xiaobai 1814889 Feb  13 15:42 'sample_nosound.mp4'

这意味着 ffmpeg 通过引用重复帧的 fps 信息来提取帧。

因此我的问题是,如何使 ffmpeg 通过“存储的帧”提取帧而不依赖 fps ?

我希望我可以获得几乎与 mp4 文件大小相同的总帧大小。

我不期望完全匹配文件大小,因为 mp4 可以包含一些元数据。

输出ffprobe -i sample_nosound.mp4

ffprobe version 3.4.4-0ubuntu0.18.04.1 Copyright (c) 2007-2018 the FFmpeg developers
  built with gcc 7 (Ubuntu 7.3.0-16ubuntu3)
  configuration: --prefix=/usr --extra-version=0ubuntu0.18.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --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-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --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-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
  WARNING: library configuration mismatch
  avcodec     configuration: --prefix=/usr --extra-version=0ubuntu0.18.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --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-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --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-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared --enable-version3 --disable-doc --disable-programs --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libtesseract --enable-libvo_amrwbenc
  libavutil      55. 78.100 / 55. 78.100
  libavcodec     57.107.100 / 57.107.100
  libavformat    57. 83.100 / 57. 83.100
  libavdevice    57. 10.100 / 57. 10.100
  libavfilter     6.107.100 /  6.107.100
  libavresample   3.  7.  0 /  3.  7.  0
  libswscale      4.  8.100 /  4.  8.100
  libswresample   2.  9.100 /  2.  9.100
  libpostproc    54.  7.100 / 54.  7.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'sample_nosound.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf57.83.100
  Duration: 00:04:32.00, start: 0.000000, bitrate: 53 kb/s
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, bt470bg/bt709/bt709), 640x330 [SAR 1:1 DAR 64:33], 53 kb/s, 6 fps, 6 tbr, 12288 tbn, 12 tbc (default)
    Metadata:
      handler_name    : VideoHandler

答案1

据我了解这个问题,你想从视频中提取帧。每个帧都应该存储一个单独的文件。所有文件大小的总和应与视频的文件大小相匹配。这仅适用于某些特定视频。我将尝试广泛地解释事情。

长话短说

从 h264 编码视频中提取具有相同视觉质量和文件大小的帧是不可能的。

视频容器格式令人困惑

本例中的视频文件是 MP4 文件。 MP4 是视频数据的容器。然而,容器的类型并没有真正说明实际内容。事实上,有很多不同种类的视频格式可以驻留在 MP4 文件中 – 就像 zip 存档(或 PDF 文件)一样。

有不同类型的视频

视频是图像序列。有很多方法可以将这些图像存储到视频流中(编码)以及如何随后读取它们(解码)。这些算法通常被称为编解码器

请记住,并非所有编解码器都会进行压缩。在此示例中,h264 是编解码器。默认情况下,h264 编码器计算一帧与下一帧的差异。如果差异很小,编码器仅存储差异。实际帧被丢弃。仅第一帧存储为完整图像。这节省了很多空间,是压缩策略之一。 h264 解码器会将存储的差异应用于前一帧,重新创建原始帧。

如您所见,视频中的帧相互依赖。如果您想要单个文件,您希望它们是独立的。这意味着您始终需要存储每个单帧的完整信息。这意味着,您不能简单地获取现有数据并将其复制到文件中,而是必须重新编码视频。在此过程中,文件大小的总和必须增加。

您可以阅读各种视频压缩中的图片类型,特别是“基于差异”帧间或一个视频压缩的一般概述

h264 不是 JPEG

即使我们谈论的是个体图像。 JPEG 使用称为离散余弦变换H.264使用类似但改进的版本。这意味着 JPEG 不可能像 h264 那样高效压缩。顺便说一句,您可以使用以下命令将 h264 压缩图像放入文件中海伊夫(这本质上就像一个单帧视频)。


``这并不完全正确,但我现在想保持简单。它实际上更像是“场景的第一帧”。如果您想了解细节:
编码器会注意到各个场景的开始(在电影摄影中,这通常称为“剪辑”)。一帧与另一帧的差异非常大,因此不利于压缩。编码器决定不使用“基于差异的”帧间。相反,它使用完整的图片(这称为“帧内”,也称为“关键帧”)。
还有一个技术原因:只有在帧内,您在搜索视频时才能快速跳转。因此,帧内帧也会时不时地放入流中(无论实际视频内容如何)。通常,视频每秒有一个帧内帧。

现在我们了解了很多有关视频压缩的知识。该视频演示了一些内容:
损坏的视频文件的有趣输出
由于文件损坏,该视频丢失了一个帧内帧。解码器或多或少成功地播放了它。丢失的画面可能显示该女子正在向侧面看。现在她转过头来,解码器只有来自帧间的数据,其中包括一些运动信息。看起来这个女人最终把脸放在了头的一侧。与此同时,一个人走过背景。这个人没有出现在丢失的帧内,因此看起来还不错。

相关内容