ffmpeg實戰-音視訊基礎概念

白狼棧發表於2021-06-22

轉發自白狼棧:檢視原文

關於音視訊,相信大家都看過電影(視訊),聽過音樂(音訊),至少應該都知道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,解析度為544x960,視訊流的位元率是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封裝器(又稱之為複用器)完成。

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

相關文章