Video

如何在不依賴 fps 的情況下提取“儲存的幀”?

  • February 14, 2019

我注意到如果我用這個命令提取幀:

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 資訊來提取幀。

因此我的問題是,如何在不依賴 fps 的情況下通過“儲存幀”使 ffmpeg 提取幀?

我希望我可以獲得與 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

據我了解這個問題,您想從影片中提取幀。每個幀都應該儲存一個單獨的文件。所有文件大小的總和應與影片的文件大小相匹配。這僅適用於某些特定影片。我將嘗試廣泛地解釋事情。

TL;博士

從具有相同視覺質量和文件大小的 h264 編碼影片中提取幀是不可能的。

影片容器格式令人困惑

本例中的影片文件是 MP4 文件。MP4 是影片數據的容器。然而,容器的類型並沒有真正說明實際內容。事實上,許多不同類型的影片格式可以駐留在 MP4 文件中——就像 zip 存檔(或 PDF 文件)一樣。

有不同類型的影片

影片是一系列圖像。有很多方法可以將這些圖像儲存到影片流中(編碼)以及之後如何讀取它們(解碼)。這些算法通常稱為編解碼器

請記住,並非所有編解碼器都進行壓縮。在此範例中,h264 是編解碼器。預設情況下,h264 編碼器計算從一幀到下一幀的差異。如果差異很小,編碼器只儲存差異。實際幀被丟棄。只有第一個¹幀被儲存為完整的圖像。這節省了很多空間,是壓縮策略之一。h264 解碼器會將儲存的差異應用於前一幀,重新創建原始幀。

如您所見,影片中的幀相互依賴。如果你想要單個文件,你希望它們是獨立的。這意味著您始終需要儲存每個單幀的完整資訊。這意味著,您不能簡單地將現有數據複製到文件中,而必須重新編碼影片。在此過程中,文件大小的總和必須增加。

您可以閱讀影片壓縮中的各種圖片類型,特別是“基於差異的”幀間一般影片壓縮的概述

h264 不是 JPEG

即使我們談論的是單個圖像。JPEG 使用一種稱為DCT的壓縮方法。 H.264使用類似但改進的版本。這意味著 JPEG 不可能像 h264 那樣有效地壓縮。順便說一句,您可以使用HEIF將 h264 壓縮圖像放入文件中(這本質上就像一幀影片)。


¹這並不完全正確,但我現在想保持簡單。它實際上更像是“場景的第一幀”。如果您想了解細節:

編碼器會注意到各個場景的開始(在電影攝影中,這通常稱為“剪輯”)。從一幀到另一幀的差異非常大,因此不好壓縮。編碼器決定不使用“基於差異的”幀間。相反,它使用完整的圖片(這稱為“幀內”,也稱為“關鍵幀”)。

還有一個技術原因:只有在尋找影片時,您可能會快速跳轉到幀內。因此,幀內幀也會不時地放入流中(不管實際影片內容如何)。通常,

現在我們學到了很多關於影片壓縮的知識。該影片展示了一些事情: 由於文件損壞,該影片失去了幀內。解碼器或多或少地成功地播放了它。失去的幀可能顯示女人在看一邊。現在她轉過頭來,解碼器只有來自幀間的數據,其中包括一些運動資訊。看起來那個女人最終的臉在她的頭側。與此同時,一個人從背景中走過。這個人沒有出現在失去的幀內,因此看起來還不錯。

損壞的影片文件的有趣輸出

引用自:https://unix.stackexchange.com/questions/500649