FFmpg音视频入门教程
FFmpeg
FFmpg是音視頻領域的瑞士軍刀,由C語言進行編寫,廣泛的支持C++, python,java,go等語言的調用,繼承了幾乎所有的編解碼庫和流協議,并能任意的添加圖片水印和問題,能解決音視頻開發領域幾乎所有的問題, FFmpeg的開源協議為LGPL何GPL協議,也就是說他能在一定程度上允許閉源商用,前提是不要使用它的GPL開源的功能。
本文經過裁剪
參考:https://ffmpeg.org/documentation.html
原文地址:https://www.fawdlstty.com/ffmpeg/docs/03_ffmpeg_beginning.html#%E5%90%84%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F
音視頻基礎
顏色空間
計算機中的任意圖形都要遵循一定的數據描述方式,圖像的描述方式被稱為顏色空間
RGB顏色空間
RGB是我們最為熟悉的顏色空間,最初通過物理學家發現,通過紅綠藍的不同強弱的組合幾乎能表現出任意的類型的光的顏色,所以后來計算機屏幕上每個像素點都是由這三種顏色的小燈組合成,通過控制等的強弱即可實現對顏色的控制,紅色Red、綠色Green、藍色Blue。
經過計算每個像素點從沒有光到最亮,每個顏色定義256種亮度,可以表達16777216種顏色,已經達到人類能識別的極限,所以現在屏幕及亮度采用RGB24的方式來表達顏色,24代表24位,也就是每個顏色8位,分別取值0-255.
YUV顏色空間
YUV顏色空間是視頻格式主要的顏色空間,與RGB一樣,這種顏色空間也能表示任意顏色。這種顏色空間有很多標準,但是無一例外都可以通過RGB運算獲得。
以YCbCr Rec.601來說, Y(luma代表亮度),U(Chroma Blue, Cb代表藍色色度), V(Chroma Red, Cr,代表紅色色度)三個份量描述一個顏色,這種描述方式將綠色給去掉了,藍色和紅色分別表示冷色色調和暖色色調。
從圖中能看到,左邊的圖最為清晰,因為人眼對細節敏感對冷暖色調反應比較遲緩。
于是科學家想到一種肉眼很難分辨出的壓縮方式,也就是原本Y,U,V分別一個值代表一個像素,現在兩個Y或者4個Y共用一個U和V。
目前常用的壓縮編碼方式是四個Y共用一個U和V,這種編碼方式相對于RGB來說節省了一半的存儲空間。如下:
RGB排列:RGBRGBRGBRGB YUV排列:YYYYUVRGB轉YUV
Y = 0.299 * R + 0.587 * G + 0.114 * B U = - 0.168736 * R - 0.331264 * G + 0.5 * B V = 0.5 * R - 0.418688 * G - 0.081312 * BYUV轉RGB
R = Y + 1.402 * V G = Y - 0.344 * U - 0.714 * V B = Y + 1.772 * U音頻的說明
音頻簡而言之就是聲音在介質中的震動。以S16格式為存儲的聲音來看,聲音的取值范圍為-32768~32767,代表某個時間點聲音的強度,越高代表強度越大,越接近0代表聲音越下,直至沒有。
音頻采樣率
現在任何的超級計算機都沒有辦法把聲音完整的給錄制下來,聲音采樣的含義就是將聲音某個時間點的輕度存儲下來,需要進行播放時,就用相同的輕度和頻率震動空氣,即可還原出聲音信息。但是采樣并不是連續的,而是離散的,比如使用最為廣泛的44100Hz采樣率,含義就i事將聲音的振動輕度每秒種采樣44100次,這種采樣從大多數人角度來說依然足夠,人類能夠分辨采樣的極限是48000HZ采樣率,這種采樣在很多場合都在使用。
其次對于強度來說,最常用的是S16,通常電話的采樣是s8部分特殊領域也有進行S32位采樣的,目前采樣幾乎沒有S64的
聲音的黑科技
聲音兩種高級處理方式,一種是去噪,一種是消音
聲音同時也是一種波,通過傅立葉函數濾波也可以很容易的去除聲音中的噪音。原理是聲音是很多高頻和低頻的波的組合,通常低頻為實際需要的聲音,高頻為無用的噪音,此時通過低通濾波,過濾高頻的噪音,即可實現聲音去噪。
消音通常是一種嵌入式微型設備,比如去噪耳機或去噪器,大概效果就是這樣;帶上去噪耳機后就能消除環境聲音,更方便聽歌,去噪器是手機大小的設備,開啟后能消除環境噪音,方便私密談話或者喜歡安靜的人使用。這兩種設備的原理是這樣的:首先開啟特制麥克風采集聲音,然后輸出反向震動聲波,這個時候新的聲波就和原聲波中和掉了。
容器及編碼
容器
容器通常是一種文件格式或流媒體格式,用來描述純視頻、純音頻或音視頻的存儲格式。
純音頻容器格式有mp3、aac、wma等,通常你放的歌均使用這種容器來存儲。
純視頻容器格式我暫時沒見過,可能有。
混合容器格式有mp4、flv、vob、rmvb等,通??吹囊曨l,音視頻都有的格式就使用這種存儲格式,它們除了能混合存儲,還能僅存放音頻或視頻。比如一首mp3的歌轉為flv格式來播放完全是沒問題的。
圖像編碼
未壓縮編碼格式有rgb/bgr、hsl/hsv/hsb、yuv等等系列,因體積因素,使用最廣泛的是yuv系列。這類編碼方式有一個共同的特點,也就是抽取其中任意一幀都能表述整個圖像。
壓縮編碼格式有h263/h264/h265、vp8/vp9/av1、flv1等等,這類圖像均經過壓縮,只有I幀能完整還原整個畫面(前提是知道metadata信息),其他類型的幀可能是在I幀基礎上做一些改動的描述,比如有了I幀后,新的幀可以對其做出一定的修改;也可能壓根不存儲畫面信息,只存放metadata或SEI信息(h264/h265)等。
音頻編碼
未壓縮的音頻編碼有兩個主要概念,一個是格式,一個是采樣率。通常格式是使用16位有符號數字作為采樣,取值范圍-32768~32767,網上看到的很多音頻處理軟件的聲音波形圖就是這個值;除了這個外,還能用8位整數、32位整數、32位float來表示,存儲容量越大,聲音也就越保真。通常16位能滿足絕大多數人對聲音需求,所以很少有場景使用32位無損音質。同時32位也是人類對聲音分辨的極限,超過32位的比如64位音質,一方面沒任何優勢,另一方面浪費存儲空間。
采樣率的意思是每秒鐘存儲多少個聲音的值,主流使用44.1KHz,也就是每秒鐘有44100個采樣點,能滿足絕大多數人的需求了。同時人類對采樣率識別的極限是48KHz,也就是每秒鐘有48000個采樣點。超過這個頻率的音質對人類來說沒有任何區別,除非特殊場合,否則48KHz完全足夠,主流依然是44.1KHz。
各種數據結構的生命周期
FFmpeg對象的生命周期管理也是非常重要的內容,這一塊如果不處理好非常容易導致內存泄露等情況。
AVCodec
編碼對象,通常通過 avcodec_find_decoder 函數,傳入編碼ID獲得,可以直接拋棄,不用關心泄露。
AVFormatContext
最重要的對象之一,用于維護一個輸入流或輸出流,通常通過 avformat_alloc_output_context2 函數打開,由 avformat_close_input 函數釋放。對于文件對象,生命周期類似文件句柄;對于網絡IO對象,生命周期類似C語言網絡函數中的SOCKET句柄。
AVStream
這個類的作用就是指定具體的流的類型,比如一個MP4文件有音視頻數據,那么處理這個文件就由一個 AVFormatContext 對象來維護,可以通過這個對象訪問兩個 AVStream 對象,一個用于視頻的處理(讀或寫),一個用于音頻的處理(讀或寫)
在讀流的情況下,使用 avformat_find_stream_info 找出所有流的信息同時打開所有流,生命周期此時將交于 AVFormatContext 對象托管,不用再關心泄露。
在寫流的情況下,使用 avformat_new_stream 創建新的流并關聯至 AVFormatContext,生命周期此時將交于 AVFormatContext 對象托管,不用再關心泄露。
AVCodecContext
用于將數據進行編解碼,比如將yuv420p編碼為h264數據,或者將aac數據解碼為fltp格式數據,音視頻編解碼全靠這個類。
它可以獨立存在,也能與 AVStream 相關聯;通常一個 AVStream 對象就有一個 AVCodecContext。當它與 AVStream 關聯后,生命周期與 AVStream 一樣,交給 AVFormatContext 對象管理。
通常寫流時通過制定參數,然后通過 avcodec_open2 打開編碼;讀流時在通過 avcodec_find_decoder 找到 AVCodec* 后,通過 avcodec_open2 打開編碼。
如果它沒有與 AVStream 相關聯,那么需要手動關閉,先 avcodec_close,再 avcodec_free_context。
AVInputFormat
用于查找輸入流的對象,在通過 avformat_open_input 使用后,生命周期將交于 AVFormatContext 對象托管,不用再關心泄露。
AVDictionary
通常用于打開前指定參數,使用 av_dict_set 函數設置;使用完畢后通過 av_dict_free 函數釋放。
AVPacket
一個這個結構代表一個數據包,用于存儲編碼后的數據,比如h264 raw數據或aac raw數據。這個數據結構由兩部分組成,結構本身和數據部分。
結構本身通過 av_packet_alloc 與 av_packet_free 分配及釋放;數據部分通常通過 avcodec_receive_packet 或 av_read_frame 也就是編碼后或者從流管道獲取一幀數據,由于可能有多個 AVPacket 引用同一塊數據,所以不能直接釋放,需使用 av_packet_unref 結束引用這一塊數據,如果沒有結構再引用數據后,數據內存區域將自動釋放。
AVFrame
用于儲存音視頻的一幀數據,可以儲存視頻圖像的rgb或yuv像素格式數據,也可以儲存音頻的s16或fltp采樣格式數據,其中音頻一幀的采樣數與時長是不定的,一幀可能有幾十毫秒時長的數據,也可能有半秒時長的數據。
結構本身通過 av_frame_alloc 與 av_frame_free 分配及釋放;數據部分通常通過 avcodec_receive_frame 或 av_frame_get_buffer 解碼 AVPacket 或者自己分配。同ACPacket一樣,由于可能有多個 AVFrame 引用同一塊數據,所以不能直接釋放,需使用 av_frame_unref 結束引用這一塊數據,如果沒有結構再引用數據后,數據內存區域將自動釋放。
總結
以上是生活随笔為你收集整理的FFmpg音视频入门教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++——容器小整理
- 下一篇: 【计算机科学基础】计算机概述