ffmpeg實戰-音影片基礎概念

轉發自白狼棧:查看原文

關於音影片,相信大家都看過電影(影片),聽過音樂(音頻),至少應該都知道mp4是影片文件,mp3是音頻文件。

對於一個音影片文件,都有哪些屬性呢?以影片為例,我們可以通過 ffmpeg -i 命令查看媒體文件的資訊。

» ffmpeg -i r1ori.mp4                                                                                                                       
ffmpeg version 4.1 Copyright (c) 2000-2018 the FFmpeg developers
  built with Apple LLVM version 10.0.0 (clang-1000.10.44.4)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.1 --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags='-I/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/include/darwin' --host-ldflags= --enable-ffplay --enable-gpl --enable-libmp3lame --enable-libopus --enable-libsnappy --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxvid --enable-lzma --enable-chromaprint --enable-frei0r --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfdk-aac --enable-libfontconfig --enable-libfreetype --enable-libgme --enable-libgsm --enable-libmodplug --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-librsvg --enable-librtmp --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtesseract --enable-libtwolame --enable-libvidstab --enable-libwavpack --enable-libwebp --enable-libzmq --enable-opencl --enable-openssl --enable-videotoolbox --enable-libopenjpeg --disable-decoder=jpeg2000 --extra-cflags=-I/usr/local/Cellar/openjpeg/2.3.0/include/openjpeg-2.3 --enable-nonfree
  libavutil      56\. 22.100 / 56\. 22.100
  libavcodec     58\. 35.100 / 58\. 35.100
  libavformat    58\. 20.100 / 58\. 20.100
  libavdevice    58\.  5.100 / 58\.  5.100
  libavfilter     7\. 40.101 /  7\. 40.101
  libavresample   4\.  0\.  0 /  4\.  0\.  0
  libswscale      5\.  3.100 /  5\.  3.100
  libswresample   3\.  3.100 /  3\.  3.100
  libpostproc    55\.  3.100 / 55\.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'r1ori.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.20.100
  Duration: 00:00:58.53, start: 0.000000, bitrate: 1870 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 544x960, 1732 kb/s, 29.83 fps, 29.83 tbr, 11456 tbn, 59.67 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 129 kb/s (default)
    Metadata:
      handler_name    : SoundHandler

  

除了影片的元資訊,還包括了更多我們當初編譯的配置,你可以選擇 -hide_banner 參數來隱藏這些資訊,完整的命令如下

»ffmpeg -i r1ori.mp4 -hide_banner   
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'r1ori.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.20.100
  Duration: 00:00:58.53, start: 0.000000, bitrate: 1870 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 544x960, 1732 kb/s, 29.83 fps, 29.83 tbr, 11456 tbn, 59.67 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 129 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
At least one output file must be specified

  

我們主要看幾個數據

  1. Input #0, mov,mp4,m4a,3gp,3g2,mj2, from ‘r1ori.mp4’: # Input #0 表示我們通過ffmpeg -i 參數輸入的第一個文件,下標從0開始,也就是說我們可以輸入多個文件,實際上ffmpeg還支援輸出多個文件
  2. Metadata 表示影片元資訊
  3. Duration 這行包含了影片的播放時長是58.53秒,開始播放時間是0,整個文件的比特率是1870kbit/s
  4. Stream #0:0(und): Video: h264,這行表示該文件的第一個流是影片流,編碼格式是H264格式(封裝格式為AVC1),每一幀的數據表示為yuv420p,解析度為544×960,影片流的比特率是1732kbit/s,幀率為每秒鐘29.83幀。
  5. Stream #0:1(und): Audio: aac,這行表示該文件的第二個流是音頻流,編碼格式為ACC(封裝格式為MP4A),並且採用的Profile是LC規格,取樣率是44.1KHz,聲道是立體聲(stereo),碼率是129kbit/s

開始出現了一些陌生的名詞,我們依次介紹下。

容器

像上面這個影片文件一樣,把不同的數據流(影片流、音頻流,有的還有字幕流等)封裝在一個文件中,我們稱之為容器。像我們熟悉的mp4、avi、rmvb等等都是多媒體容器格式,一般情況下,多媒體文件的後綴就是它的容器格式。

我們可以把容器理解為一個瓶子、罐子之類的東西。

編碼和解碼(codec)

編碼:將影片、音頻用某種格式或規範記錄下來並存儲,稱為編碼(codec)。編碼可以理解成是對容器內的東西的加工處理。

常見的影片編碼格式有 h264、h265等,常見的音頻編碼格式有 mp3、aac等。

解碼:就是將影片、音頻壓縮的編碼數據,解碼成為非壓縮的影片、音頻原始數據。比如我們要對一段音頻增加回聲,就需要先對音頻文件先解碼再編碼。

軟解:即軟體解碼,通過軟體讓CPU對影片文件進行解碼操作。

硬解:即硬體解碼,為了減輕CPU的壓力,採用GPU來處理原來全部讓CPU處理的部分影片數據。

軟解需要對大量的影片資訊進行處理,所以軟解非常吃CPU,一條FFmpeg的命令都有可能把CPU干趴下了。

相比而言,硬解的效率非常高,但是硬解的缺點也顯而易見,它不能像軟解那樣,對字幕、畫質等的處理效果都不是很好。如果我沒記錯的話,七牛雲平台(一個相對專業的音影片平台)現在還不支援硬解。

ffmpeg是最常見的軟解碼開源庫,它實際是通過比如 H264、H265、MPEG-4等編解碼演算法進行軟解。

在現如今的音影片領域,ffmpeg 幾乎支援所有音影片的編解碼,非常強大。

轉碼:即編碼轉換,是將影片從一種格式轉換為另一種格式。比如將一個flv文件轉換為mp4文件。

ffmpeg -i input.flv output.mp4

比特率

比特率又稱碼率,表示編碼器每秒輸出的位元組數,單位是 Kbps,b 為 比特(bit) 這個就是電腦文件大小的計量單位,1KB=8Kb,區分大小寫,s 為 秒(second) p 為 每(per) 。

比如

在相同的壓縮演算法下(後面我們會介紹若干不同的壓縮演算法),碼率越高,影片的品質也就越高。

對於壓縮文件,按照上面的理解,碼率的粗略計算方式=文件大小/時長。

比如 r1ori.mp4 的大小是 13.7兆,時長約59秒,那麼它的碼率大約等於 (13.7 x 1024 x 8) / 59 = 1900 kb/s

公式:1MB=8Mb=1024KB=8192Kb

因為還有一些參數的影響,所以這個碼率我們也只能得到一個大約的數值。

固定碼率和可變碼率

早些年的時候,音頻編碼的時候選擇的都是固定碼率(Constant Bitrate, CBR),後面出現了可變碼率(Variable Bitrate, VBR),固定碼率指的是編碼器輸出的碼率固定,這樣就很難均衡「平靜的畫面」和「劇烈的畫面」,相對而言,可變碼率就可以很好的控制編碼器,在細節比較多,畫面相對劇烈的時候使用更多的比特位,對於相對平靜的畫面,使用更低的比特位。如此一來,在輸出品質一定的情況下,VBR更具優勢,存儲的話我們也會優先選擇可變碼率。

幀和幀率

幀指的是一個畫面。

幀率(frames per second, fps),即每秒輸出多少幀,你也可以理解畫面每秒輸出多少次。

大家在玩遊戲的時候一定深有體驗,遊戲卡頓的時候,畫面都是幀與幀之間跳動的,非常的不順暢。

幀率影響畫面的流暢度,幀率越高,畫面也就越流暢。

由於視覺暫留現象(即當物體在快速運動時, 人眼所看到的影像消失後,人眼仍能繼續保留其影像1/24秒左右的影像)的存在,所以對於一般的電影影片,要求最低幀率是24,也就是每幀曝光1/24 = 0.042秒。

解析度

解析度大家應該都不陌生,比如某影片網站常見的藍光1080P,超清720P,高清540P。

解析度可以理解為影片畫面的大小,即影片的寬度和高度。720P指的就是高度是720像素。

了解過碼率和幀率我們發現,不能絕對的說解析度越高影片越清晰,更重要的是如何平衡好碼率、幀率以及解析度三者的關係。

總的來說,我們更願意接受影片體積越小,清晰度越高的影片,一來是存儲方便,二來是看起來爽。

有損和無損

首先我們說一下什麼是音影片的原始數據?原始數據指的是通過音影片設備採集的、沒有經過任何加工的數據。音頻的原始數據是pcm格式,影片的原始數據是yuv格式。

有損和無損,即有沒有損失,這裡針對的是多媒體數據壓縮的一種說法。有損壓縮又稱之為破壞性壓縮,當然並不是說壓縮之後無法解壓的那種破壞。比如我們常見的mp3、mp4文件都是有損壓縮。

以音頻編碼為例,音頻裡面的聲音來源於自然界,我們通過技術方案捕獲到聲音,然後根據一定的演算法進行存儲。

在現階段,我們存儲下來的聲音不能完全還原為自然界的聲音,任何音頻編碼都是有損的。

有同學可能要提出疑問了,我看有文章介紹,音頻的原始數據不是pcm格式的嗎?

其實pcm編碼也只是無限接近於無損,它能夠達到訊號的最高保真,因此,pcm編碼才被約定為無損壓縮。

好好的音頻,我想聽最真實的從自然界採集的聲音,為什麼要壓縮呢?

原始數據太大,不方便存儲

即使存儲下來了,也不方便傳輸,需要極大的頻寬

現在影片的壓縮比很高,比如現如今大家耳熟能詳的4k 8k,看起來完全能滿足需要

復用器和解復用器

對於容器而言,注意這裡針對的是容器,我們經常會有兩種頻繁的操作。

取出容器內的音影片數據,我們稱之為解封裝,由demuxer解封裝器(又稱之為解復用器)完成。

把處理好的音影片數據裝進容器內稱之為封裝,由muxer封裝器(又稱之為復用器)完成。

我們會在這邊文章下面持續更新音影片相關的概念,如果你覺得有什麼概念不好理解,可以給我留言,我會再收集並作補充。