FFmpeg從入門到出家(FFmpeg簡析)
FFmpeg簡析
FFmpeg從無到有,發展至今,功能日益強大,程式碼也越來越多,很多初學者都被其眾多的原始檔、龐大的結構體和複雜的演算法打消了繼續學習的念頭。本章節將從總體對FFmpeg進行簡單的解析,教您如何閱讀FFmpeg原始碼。
FFmpeg包含如下類庫:
libavformat - 用於各種音視訊封裝格式的生成和解析,包括獲取解碼所需資訊、讀取音視訊資料等功能。各種流媒體協議程式碼(如rtmpproto.c等)以及音視訊格式的(解)複用程式碼(如flvdec.c、flvenc.c等)都位於該目錄下。
libavcodec - 音視訊各種格式的編解碼。各種格式的編解碼程式碼(如aacenc.c、aacdec.c等)都位於該目錄下。
libavutil - 包含一些公共的工具函式的使用庫,包括算數運算,字元操作等。
libswscale - 提供原始視訊的比例縮放、色彩對映轉換、影象顏色空間或格式轉換的功能。
libswresample - 提供音訊重取樣,取樣格式轉換和混合等功能。
libpostproc - 用於後期效果處理,如影象的去塊效應等。
libavdevice - 用於硬體的音視訊採集、加速和顯示。
如果您之前沒有閱讀FFmpeg程式碼的經驗,建議優先閱讀libavformat、libavcodec以及libavutil下面的程式碼,它們提供了音視訊開發的最基本功能,應用範圍也是最廣的。
FFmpeg裡面最常用的資料結構,按功能可大致分為以下幾類(以下程式碼行數,以branch: origin/release/3.4為準):
1. 封裝格式
◦AVFormatContext - 描述了媒體檔案的構成及基本資訊,是統領全域性的基本結構體,貫穿程式始終,很多函式都要用它作為引數;
◦AVInputFormat - 解複用器物件,每種作為輸入的封裝格式(例如FLV、MP4、TS等)對應一個該結構體,如libavformat/flvdec.c的ff_flv_demuxer;
◦AVOutputFormat - 複用器物件,每種作為輸出的封裝格式(例如FLV, MP4、TS等)對應一個該結構體,如libavformat/flvenc.c的
◦AVStream - 用於描述一個視訊/音訊流的相關資料資訊。
2.編解碼
◦AVCodecContext - 描述編解碼器上下文的資料結構,包含了眾多編解碼器需要的引數資訊;
◦AVCodec - 編解碼器物件,每種編解碼格式(例如H.264、AAC等)對應一個該結構體,如libavcodec/aacdec.c的ff_aac_decoder。每個AVCodecContext中含有一個AVCodec;
◦AVCodecParameters - 編解碼引數,每個AVStream中都含有一個AVCodecParameters,用來存放當前流的編解碼引數。
3. 網路協議
◦URLProtocol - 描述了音視訊資料傳輸所使用的協議,每種傳輸協議(例如HTTP、RTMP)等,都會對應一個URLProtocol結構,如libavformat/http.c中的ff_http_protocol;
◦URLContext - 封裝了協議物件及協議操作物件。
[if !supportLists]4. [endif]資料存放
◦AVPacket - 存放編碼後、解碼前的壓縮資料,即ES資料;
◦AVFrame - 存放編碼前、解碼後的原始資料,如YUV格式的視訊資料或PCM格式的音訊資料等;
上述結構體的關係圖如下所示(箭頭表示派生出):
圖2. FFmpeg結構體關係圖下面這段程式碼完成了讀取媒體檔案中音視訊資料的基本功能,本節以此為例,分析FFmpeg內部程式碼的呼叫邏輯。
char *url = "http://192.168.1.105/test.flv";
AVPacket pkt;
int ret = 0;
//註冊複用器、編碼器等
av_register_all();
avformat_network_init();
//開啟檔案
AVFormatContext *fmtCtx = avformat_alloc_context();
ret = avformat_open_input(&fmtCtx, url, NULL, NULL);
ret = avformat_find_stream_info(fmtCtx, NULL);
//讀取音視訊資料
while(ret >= 0)
{
ret = av_read_frame(s, &pkt);
}
av_register_all函式的作用是註冊一系列的(解)複用器、編/解碼器等。它在所有基於FFmpeg的應用程式中幾乎都是第一個被呼叫的,只有呼叫了該函式,才能使用複用器、編碼器等。
static void register_all(void)
{
avcodec_register_all();
/* (de)muxers */
……
REGISTER_MUXDEMUX(FLV, flv);
……
}
編/解碼其註冊過程相同,此處不再贅述。
FFmpeg讀取媒體資料的過程始於avformat_open_input,該方法中完成了媒體檔案的開啟和格式探測的功能。但FFmpeg是如何找到正確的流媒體協議和解複用器呢?可以看到avformat_open_input方法中呼叫了init_input函式,在這裡面完成了查詢流媒體協議和解複用器的工作。
static intinit_input(AVFormatContext *s, const char *filename,
AVDictionary **options)
{
int ret;
……
if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
return ret;
if (s->iformat)
return 0;
return av_probe_input_buffer2(s->pb, &s->iformat, filename,
s, 0, s->format_probesize);
}
[if !supportLists]1. [endif]s->io_open實際上呼叫的就是io_open_default,它最終呼叫到url_find_protocol方法。
static conststructURLProtocol *url_find_protocol(const char *filename)
{
constURLProtocol **protocols;
……
protocols = ffurl_get_protocols(NULL, NULL);
if (!protocols)
return NULL;
for (i = 0; protocols[i]; i++) {
constURLProtocol *up = protocols[i];
if (!strcmp(proto_str, up->name)) {
av_freep(&protocols);
return up;
}
if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
!strcmp(proto_nested, up->name)) {
av_freep(&protocols);
return up;
}
}
av_freep(&protocols);
return NULL;
}
ffurl_get_protocols可以得到當前編譯的FFmpeg支援的所有流媒體協議,通過url的scheme和protocol->name相比較,得到正確的protocol。例如本例中URLProtocol最終指向了libavformat/http.c中的ff_http_protocol。
[if !supportLists]1. [endif]av_probe_input_buffer2最終呼叫到av_probe_input_format3,該方法遍歷所有的解複用器,即first_iformat連結串列中的所有節點,呼叫它們的read_probe()函式計算匹配得分,函式最終返回計算找到的最匹配的解複用器。本例中AVInputFormat最終指向了libavformat/flvdec.c中的ff_flv_demuxer。
av_read_frame作用是讀取媒體資料中的每個音視訊幀,該方法中最關鍵的地方就是呼叫了AVInputFormat的read_packet()方法。AVInputFormat的read_packet()是一個函式指標,指向當前的AVInputFormat的讀取資料的函式。在本例中,AVInputFormat為ff_flv_demuxer,也就是說read_packet最終指向了flv_read_packet。
相關推薦
FFmpeg從入門到出家(FFmpeg簡析)
FFmpeg簡析 FFmpeg從無到有,發展至今,功能日益強大,程式碼也越來越多,很多初學者都被其眾多的原始檔、龐大的結構體和複雜的演算法打消了繼續學習的念頭。本章節將從總體對FFmpeg進行簡單的解析,教您如何閱讀FFmpeg原始碼。 FFmpeg包含如下類庫:
FFmpeg從入門到出家(HEVC在RTMP中的擴展)
log 將在 設置 else 基礎 .com wrong mage 相關 由金山雲視頻雲技術團隊提供:FFmpeg從入門到出家第三季; 為推進HEVC視頻編碼格式在直播方案中的落地,經過CDN聯盟討論,並和主流雲服務廠商達成一致,規範了HEVC在RTMP/FLV中的擴展,具
FFmpeg從入門到精通——進階篇,SEI那些事兒
uid ffffff nco 生成 角色 根據 開發工程師 實踐 流過濾 前言在直播應用的開發過程中,如果把主播端消息事件傳遞到觀眾端,一般會以Instant Messaging(即時通訊)的方式傳遞過去,但因為消息分發通道和直播通道是分開的,因此消息與直播音視頻數據的同步
MyBatis源碼解析之數據源(含數據庫連接池簡析)
概述 myba 源碼 conn java 初始 對象狀態 lis 為什麽 一.概述: 常見的數據源組件都實現了javax.sql.DataSource接口; MyBatis不但要能集成第三方的數據源組件,自身也提供了數據源的實現; 一般情況下,數據源的初始化過程參數較多,比
MyBatis原始碼解析之資料來源(含資料庫連線池簡析)
一.概述: 常見的資料來源元件都實現了javax.sql.DataSource介面; MyBatis不但要能整合第三方的資料來源元件,自身也提供了資料來源的實現; 一般情況下,資料來源的初始化過程引數較多,比較複雜; 二.設計模式: 為什麼要使用工廠模式 資料來
自學自用 = 網易雲課堂(細說Linux-從入門到精通視頻教程)
lin date upd kcon size route zip rep 系統 視頻地址 https://study.163.com/course/courseMain.htm?courseId=983014 介紹 本篇博客,旨在記錄視頻學習的要點,所以格式隨意,且沒有文字
讓react用起來更得心應手——(react-router原理簡析)
讓react用起來更得心應手系列文章: 前端路由和後臺路由 在剛入行的時候一直明白什麼單頁面應用是什麼,說白了就是混淆了前臺路由和後臺路由,現在來縷縷它們: 前臺路由:頁面的顯示由前臺js控制,在url的路徑中輸入雜湊值是不會往後臺傳送請求的,所以前臺可以通過將雜湊和頁
學習Qt之基礎篇——從入門開始(1)
Qt 簡介 Qt是一個跨平臺的C++應用程式開發框架,被廣泛用於開發GUI程式。 Qt有豐富的 API且面向物件。Qt是自由且開放原始碼的軟體,在GNU較寬鬆公共許可證條款下發布。支援廣泛的編譯器,包括GCC的C++編譯器和Visual Studio。 Q
EditText無法獲取焦點 獲取焦點無法編輯(android:descendantFocusability用法簡析 )
android:descendantFocusability用法簡析 開發中很常見的一個問題,專案中的listview不僅僅是簡單的文字,常常需要自己定義listview,自己的Adapter去繼承BaseAdapter,在adapter中按照需求進行編寫,問題就出現了,可
對FFMPEG的小總結(自己看的)
這篇文章是我自己看的,你未必能看懂,當做我自己的備份。 FFmpeg是複雜的開源系統,剛開始玩只知道用命令ffmpeg -i test.mp4 這樣的。其實普通使用者能有用這個命令ffmpeg和FFmpeg框架是有區別的。 其實ffmpeg這個命令是一個程式,程式碼是FF
加速度校準分析(Pixhawk加速度校準演算法簡析)
1. 加速度計上電校準零偏是否可行? 答案是否,以PX4飛控為例,在NED系下,水平放置時,機體測量加速度的資料應該是[0 0 -g],所以,除非你確定你的飛控校準加速度零偏的時候是絕對的水平,否則只會加大誤差,更別談每次上電自動校準,減零偏了,試想一下,如果我就是要飛
input只能輸入數字(正則簡析)
專案中有醬紫一個需求,輸入金額的input,只能輸入數字(正,負,零),最開始我天真的用了h5的新屬性‘type=number’解決,結果呢,,,obviously,,,不相容!!!首先火狐就不相容。只好另擇它路。 既然這樣子以本人愚見,有兩個路子。1、可以在
宋寶華- KVM最初的2小時(KVM從入門到入不了門)
接著《Docker最初的2小時(Docker從入門到入門)》繼續聊,再花10個小時寫出《KVM最初的2小時(KVM從入門到入不了門)》。坦白講,由於KVM遠遠比Docker要複雜,還是要2小時愛上KVM,這絕非難事,所以很可能入不了門。原則上,我們繼續迭代學習,
GAN網路從入門教程(二)之GAN原理
在一篇部落格[GAN網路從入門教程(一)之GAN網路介紹](https://www.cnblogs.com/xiaohuiduan/p/13237486.html)中,簡單的對GAN網路進行了一些介紹,介紹了其是什麼,然後大概的流程是什麼。 在這篇部落格中,主要是介紹其數學公式,以及其演算法流程。當然數學公
SpringBoot入門-1(Hello Word Boot)
eas hand running 頁面 .cn tpm 2.3 src size 1、創建一個Maven項目,添加一個parent,代碼如下 <parent> <groupId>org.springframework.boot
【資源下載】分享個嵌入式開發的入門教程(包含視頻)
gpt water term href jsb sdn ast csdn gravity 基於ARM A17的嵌入式開發的入門開發教程,有興趣的朋友可下載或者在線觀看 開發教程:http://wiki.t-firefly.com 視頻教程:https://pan.baid
JavaScript最佳新手入門系列(大話變量)
left col 新手入門 mcs com cti http href coo 533e讀2歡q侖誥4chttp://www.zcool.com.cn/collection/ZMTgzMjExMTI=.html 726n共4520xhttp://www.zcool.com.
Scala入門3(特質線性化)
相同 object 完成 可能 args scala 結構 放置 mutable 嘗試設計一套特質,靈活的改動整數隊列。隊列有兩種操作:put把整數放入隊列,get從尾部取出它們。隊列是先進先出的,get應該依照入隊列的順序取數據。提示:可以用mutable.Array
小程序入門心得(不談api)
用戶信息 項目 信息 app.js 準備 neu 技術分享 圖片 微信公眾 小程序入門 一、準備 首先先去微信公眾平臺註冊一個小程序賬號,去拿到一個AppID(沒AppID也可以開發,只是有些功能會受限),註冊成功後到開發設置獲取自己的AppID,即使有AppID有些功能還
小程序開發快速入門教程(附源碼)
五分鐘上手-微信小程序 1:用沒有註冊過微信公眾平臺的郵箱註冊一個微信公眾號, 申請帳號 ,點擊 https://mp.weixin.qq.com/wxopen/waregister?action=step1 根據指引填寫信息和提交相應的資料,就可以擁有自己的小程序帳號。註冊完成之後開始登