FFMpeg分析詳細分析

與其說是分析,不如說是學習,只是看在自己第一次寫系列文章的份上,給足自己面子,取個有"深度"的題目!如有人被題目所蒙騙進來,還望見諒!

? ? ? URLProtocol,URLContext和ByteIOContext是FFMpeg操作文件(即I/O,包括網絡數據流)的結構,這幾個結構現實的功能類似于C++的多態繼承吧,C++的多態是通過子類繼承實現,而FFMpeg的“多態”是通過靜態對像現實。這部分的代碼非常值得C程序借鑒,我是說,如果你要在C里實現類似C++多態性的功能;比如當你要區分你老婆和情人之間的不同功能時。

? ? ?好了,先來看一下這三個struct的定義吧

typedef struct URLProtocol {

?

? ? const char *name; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //Rotocol名稱

? ? int (*url_open)(URLContext *h, const char *url, int flags); ? ? ?//open函數指針對象,以下類似

? ? int (*url_read)(URLContext *h, unsigned char *buf, int size);?

? ? int (*url_write)(URLContext *h, unsigned char *buf, int size);

? ? int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);

? ? int (*url_close)(URLContext *h);

? ? struct URLProtocol *next; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//指向下一個URLProtocol,具體說明見備注1

? ? int (*url_read_pause)(URLContext *h, int pause);

? ? int64_t (*url_read_seek)(URLContext *h, int stream_index,int64_t timestamp, int flags);

? ? int (*url_get_file_handle)(URLContext *h);

} URLProtocol;

?

備注1:FFMpeg所有的Protol類型都用這個變量串成一個鏈表,表頭為avio.c里的URLProtocol *first_protocol = NULL;

每個文件類似都有自己的一個URLProtocol靜態對象,如libavformat/file.c里

?

URLProtocol file_protocol = {

? ? "file",

? ? file_open,

? ? file_read,

? ? file_write,

? ? file_seek,

? ? file_close,

? ? .url_get_file_handle = file_get_handle,

};

再通過av_register_protocol()將他們鏈接成鏈表。在FFMpeg中所有的URLProtocol對像值都在編譯時確定。

?

?

typedef struct URLContext {

#if LIBAVFORMAT_VERSION_MAJOR >= 53

? ? const AVClass *av_class; ///< information for av_log(). Set by url_open().

#endif

? ? struct URLProtocol *prot; ? ? ? ? ?//指向具體的I/0類型,在運行時通過文件URL確定,如是file類型時就是file_protocol?? ? ? ? ?

? ? int flags;

? ? int is_streamed; ?/**< true if streamed (no seek possible), default = false */

? ? int max_packet_size; ?/**< if non zero, the stream is packetized with this max packet size */

? ? void *priv_data; ? ? ? ? ? ? ? ? ? ? ? //指向具體的I/O句柄

? ? char *filename; /**< specified URL */

} URLContext;

不同于URLProtocol對象值在編譯時確定,URLContext對象值是在運行過程中根據輸入的I/O類型動態確定的。這一動一靜組合起到了C++的多態繼承一樣的作用。URLContext像是基類,為大家共同所有,而URLProtocol像是子類部分。

?

typedef struct {

? ? unsigned char *buffer;

? ? int buffer_size;

? ? unsigned char *buf_ptr, *buf_end;

? ? void *opaque;

? ? int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);

? ? int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);

? ? int64_t (*seek)(void *opaque, int64_t offset, int whence);

? ? int64_t pos; /**< position in the file of the current buffer */

? ? int must_flush; /**< true if the next seek should flush */

? ? int eof_reached; /**< true if eof reached */

? ? int write_flag; ?/**< true if open for writing */

? ? int is_streamed;

? ? int max_packet_size;

? ? unsigned long checksum;

? ? unsigned char *checksum_ptr;

? ? unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);

? ? int error; ? ? ? ? ///< contains the error code or 0 if no error happened

? ? int (*read_pause)(void *opaque, int pause);

? ? int64_t (*read_seek)(void *opaque, int stream_index,

? ? ? ? ? ? ? ? ? ? ? ? ?int64_t timestamp, int flags);

} ByteIOContext;

ByteIOContext是URLContext和URLProtocol?一個擴展,也是FFMpeg提供給用戶的接口,URLContext和URLProtocol對用戶是透明,我們所有的操作是通過ByteIOContext現實。這幾個struct的相關的關鍵函數有:

int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,

? ? ? ? ? ? ? ? ? ? ? ?AVInputFormat *fmt,

? ? ? ? ? ? ? ? ? ? ? ?int buf_size,

? ? ? ? ? ? ? ? ? ? ? ?AVFormatParameters *ap)

{

? ??int url_fopen(ByteIOContext **s, const char *filename, int flags)

? ??{

? ?? ????url_open(URLContext **puc, const char *filename, int flags)

? ?? ????{

? ??? ??? ? ???URLProtocol *up;

? ? ?? ???? ? ?//根據filename確定up

? ? ?? ???? ? ?url_open_protocol (URLContext **puc, struct URLProtocol *up,?const char *filename, int flags)

? ? ??? ??? ? ?{

? ? ??? ??? ? ? ? ? //初始化URLContext對像,并通過 up->url_open()將I/O打開將I/O fd賦值給URLContext的priv_data對像

? ? ??? ??? ? ?}

? ??? ???}

? ??? ???url_fdopen(ByteIOContext **s, URLContext *h)

? ??? ???{

? ??? ??? ? ? ?//初始化ByteIOContext 對像

? ? ?? ??}

? ??}

}

我們先看一下音視頻播放器的大概結構(個人想法,不保證正確):1、數據源輸入(Input)->2、文件格式解析器(Demux)->3、音視頻解碼(Decoder)->4、顏色空間轉換(僅視頻)->5、渲染輸出(Render Output)。前一篇介紹的幾個struct是數據源輸入模塊里的內容,哪么這一帖所講的就是第二個模塊即文件格式解析器里用到的內容。

? ? ??AVInputFormat、AVOutputFormat與URLProtocol類似,每一種文件類型都有一個AVInputFormat和AVOutputFormat靜態對像并通過av_register_input_format和av_register_output_format函數鏈成一個表,其表頭在utils.c:

?

/** head of registered input format linked list */

AVInputFormat *first_iformat = NULL;

/** head of registered output format linked list */

AVOutputFormat *first_oformat = NULL;

?

AVInputFormat和AVOutputFormat的定義分別在avformat.h,代碼很長,不貼出來浪費空間了。

當程序運行時,AVInputFormat對像的

?

int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,

? ? ? ? ? ? ? ? ? ? ? ?AVInputFormat *fmt,

? ??? ? ? ? ? ? ? ? ? ?int buf_size,

? ? ? ? ? ? ? ? ? ? ???AVFormatParameters *ap)

{

?

? ???fmt = av_probe_input_format(pd, 0);//返回該文件的AVInputFormat類型

}

至于AVOutputFormat嘛,下次再說吧,晚安!

?? AVFormatContext在FFMpeg里是一個非常重要的的結構,是其它輸入、輸出相關信息的一個容器,需要注意的是其中兩個成員:

struct AVInputFormat *iformat;//數據輸入格式
?struct AVOutputFormat *oformat;//數據輸出格式
這兩個成員不能同時賦值,即AVFormatContext不能同時做為輸入、輸出格式的容器。AVFormatContext和AVIContext、FLVContext等XXXContext之間像前面講的URLContext和URLProtocol的關系一樣,是一種"多態"關系,即AVFormatContext對像記錄著運行時大家共有的信息,而各個XXXContext記錄自己文件格式的信息,如AVIContext、FLVContext等。AVInputFormat->priv_data_size記錄相對應的XXXContext的大小,該值大小在編譯時靜態確定。AVFormatContext的void *priv_data記錄XXXContext指針。
AVFormatContext對像的初始化主要在AVInputFormat的read_header函數中進行,read_header是個函數指針,指向
具體的文件類型的read_header,如flv_read_header(),avi_read_header()等,AVFormatContext、AVInputFormat和XXXContext組成一起共同完成數據輸入模塊,可以出來粗魯的認為,AVFormatContext是一個類容器,AVInputFormat是這個類的操作函數集合,XXXContext代表該類的私有數據對像。AVFormatContext還有個重要的成員?AVStream *streams[MAX_STREAMS];也是在read_header里初始化,這個等會兒再講。
?前幾篇說的都還是數據源文件格式解析部分,哪么解析完后呢,讀出的數據流保存在哪呢?正是現在講的AVStream對像,在AVInputFormat的read_header中初始化AVFormatContext對像時,他會解析出該輸入文件有哪些類型的數據流,并初始化AVFormatContext的AVStream *streams[MAX_STREAMS];一個AVStream代表一個流對像,如音頻流、視頻流,nb_streams記錄流對像個數。主版本號大于53時MAX_STREAMS為100,小于53為20。AVStream也是個容器,其

void *priv_data;//

成員變量指向具體的Stream類型對像,如AVIStream。其

AVCodecContext *actx;//記錄具體的編解容器,這個下面會講

也在這讀頭文件信息里初始化。

主要相關的函數有

int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,

? ? ? ? ? ? ? ? ? ? ? ?AVInputFormat *fmt,

? ? ? ? ? ? ? ? ? ? ? ?int buf_size,

? ? ? ? ? ? ? ? ? ? ? ?AVFormatParameters *ap)

{

?

? ??av_open_input_stream(AVFormatContext **ic_ptr,ByteIOContext *pb, const char *filename,AVInputFormat ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*fmt, AVFormatParameters *ap)

? ??{

? ? ? ? ?fmt.read_header()//調用具體的AVInputFormat的read_header,如avi_read_header

? ?? ????{

? ? ? ? ? ? ? ?//根據文件頭信息初始化AVStream *streams及AVStream里的

? ? ? ? ? ? ? ?//void *priv_data和AVCodecContext *actx;成員對像

? ??? ???}? ? ? ??

? ??}

}

? 他們之間的關系和URLProtocol、URLContext之間是一樣的,AVCodecContext動態的記錄一個解碼器的上下文信息,而AVCodec是每個解碼器都會擁有一個自己的靜態對像,并通過avcodec_register()函數注冊成一個鏈表,表頭在utils.c里定義

static AVCodec *first_avcodec = NULL;

AVCodecContext的enum CodecID codec_id成員記錄者當前數據流的Codec,void *priv_data記錄具體Codec所對應的上下文信息對像的指針,如MsrleContext。這三個結合起來現實數據解碼的作用。我們可以傻逼的認為AVCodecContext是這個解碼模塊的容器類,Codec是操作函數集合,類似MsrleContext的就是操作數據對像。

他們之間關系的確立:

每一個解碼類型都會有自己的Codec靜態對像,Codec的int priv_data_size記錄該解碼器上下文的結構大小,如MsrleContext。這些都是編譯時確定的,程序運行時通過avcodec_register_all()將所有的解碼器注冊成一個鏈表。在av_open_input_stream()函數中調用AVInputFormat的read_header()中讀文件頭信息時,會讀出數據流的CodecID,即確定了他的解碼器Codec。

typedef struct AVPicture {

? ? uint8_t *data[4];

? ? int linesize[4]; ? ? ? ///< number of bytes per line

} AVPicture;

typedef struct AVFrame

{

? ?uint8_t *data[4]; // 有多重意義,其一用NULL 來判斷是否被占用

? ?int linesize[4];

? ?uint8_t *base[4]; // 有多重意義,其一用NULL 來判斷是否分配內存

? ?//......其他的數據

} AVFrame;

從定義上可知,AVPicture是AVFrame的一個子集,他們都是數據流在編解過程中用來保存數據緩存的對像,從int av_read_frame(AVFormatContext *s, AVPacket *pkt)函數看,從數據流讀出的數據首先是保存在AVPacket里,也可以理解為一個AVPacket最多只包含一個AVFrame,而一個AVFrame可能包含好幾個AVPacket,AVPacket是種數據流分包的概念。記錄一些音視頻相關的屬性值,如pts,dts等,定義如下:

typedef struct AVPacket {? ?

? ? int64_t pts;? ?

? ? int64_t dts;

? ? uint8_t *data;

? ? int ? size;

? ? int ? stream_index;

? ? int ? flags;? ?

? ? int ? duration;

? ? void ?(*destruct)(struct AVPacket *);

? ? void ?*priv;

? ? int64_t pos; ? ? ? ? ? ? ? ? ? ? ? ? ? ?///< byte position in stream, -1 if unknown? ?

? ? int64_t convergence_duration;

} AVPacket;


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/454995.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/454995.shtml
英文地址,請注明出處:http://en.pswp.cn/news/454995.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《jQuery基礎》總結

目前&#xff0c;互聯網上最好的jQuery入門教材&#xff0c;是Rebecca Murphey寫的《jQuery基礎》&#xff08;jQuery Fundamentals&#xff09;。這本書雖然是入門教材&#xff0c;但也足足有100多頁。我對它做了一個詳細的筆記&#xff0c;試圖理清jQuery的設計思想&#xff…

邏輯綜合工具DesignCompiler使用教程

邏輯綜合工具Design Compiler使用教程 圖形界面design vision操作示例 邏輯綜合主要是將HDL語言描述的電路轉換為工藝庫器件構成的網表的過程。綜合工具目前比較主流的是synopsys公司Design Compiler&#xff0c;我們在設計實踐過程中采用這一工具。Design compiler有兩種工作…

遍歷結構體_三菱ST語言編程(3)——結構體變量

上篇文章介紹了數組&#xff0c;是一組相同類型數據的列表&#xff0c;那么不同類型的數據能否組合到一起用一個標簽表示呢&#xff1f;答案當然是可以的&#xff0c;而實現這個功能的就是結構體(struct)。建立結構體在三菱結構化編程的界面中左側程序部件里可以找到結構體標簽…

關于微信小程序swiper的問題

關于小程序swiper的問題 代碼 在官方示例上給swiper添加了currentbindchangecircular添加了一個buttonbindtap用于切換下一張 index.wxml <swiper indicator-dots"{{indicatorDots}}"bindchange"swiperChange"current"{{index}}"circular&quo…

PyQt5案例匯總(完整版)

個人博客點這里 PyQt5案例匯總(完整版) 起步 PyQt5是一套綁定Qt5的應用程序框架。他在Python 2.x和3.x中都是可用的。該教程使用的是Python3.x。 Qt庫是一套最有用的GUI庫。 PyQt5是作為一套Python模塊實現的。他已經超過620個類和6000個函數與方法。他是一個運行在所有主…

中的 隱藏鼠標菜單_Mac移動隱藏刪除頂部菜單欄圖標教程

蘋果菜單欄貫穿 Mac 的屏幕頂部。左側是蘋果菜單和應用菜單&#xff0c;應用菜單一般顯示你當前使用的Mac軟件的所有功能菜單。右側通常是以圖標顯示的狀態菜單&#xff0c;幫助你快速查看Mac的狀態以及快速訪問某些Mac軟件。移動圖標位置若想要重新排列狀態菜單欄的圖標&#…

可以用什么代替平面鏡

答案是鏡面 潛望鏡是利用平面鏡來改變光路轉載于:https://www.cnblogs.com/lidepeng/p/7280593.html

[hadoop] kettle spoon 基礎使用 (txt 內容抽取到excel中)

spoon.bat 啟動kettle。 測試數據 1. 新建轉換 輸入中選擇文本文件輸入 雙擊設置文本輸入 字符集、分隔符設置 獲取對應的字段&#xff0c;預覽記錄。 拖入 excel輸出&#xff0c;設置轉換關系 設置輸出路徑 獲取字段 啟動轉換 導入的excel數據&#xff08;設置好格式,圖中ID,A…

ffmpeg提取音頻播放器總結

ffmpeg提取音頻播放器總結&#xff1b; 一&#xff1a;簡介 從編寫音頻播放器代碼到完成播放器編寫&#xff0c;測試&#xff0c;整整5天的時間&#xff0c;這時間還不算之前對 ffmpeg熟悉的時間&#xff0c;可以說是歷經千辛萬苦&#xff0c;終于搞出來了&#xff0c;雖然最…

【BZOJ 4103】 [Thu Summer Camp 2015]異或運算 可持久化01Trie

我們觀察數據&#xff1a;樹套樹 PASS 主席樹 PASS 一層一個Trie PASS 再看&#xff0c;異或&#xff01;我們就把目光暫時定在01Tire然后我們發現&#xff0c;我們可以帶著一堆點在01Trie上行走&#xff0c;因為O(n*q*30m*30)是一個可選復雜度。 我們想一下我們正常的時候…

Docker學習筆記——Java及Tomcat Dockerfile

1、Java Dockerfile創建項目目錄java&#xff0c;目錄下上傳所需java版本壓縮包&#xff0c;并創建Dockerfile文件&#xff0c;項目結構如下&#xff1a;java-Dockerfile-jdk-8u111-linux-x64.gzDockerfile內容&#xff1a;# JAVA # Version 1.8.0_111 # SOURCE_IMAGE FROM cen…

rabbitmq接口異常函數方法_RabbitMQ監控(三):監控隊列狀態

#RabbitMQ 監控(三)驗證RabbitMQ健康運行只是確保消息通信架構可靠性的一部分&#xff0c;同時&#xff0c;你也需要確保消息通信結構配置沒有遭受意外修改&#xff0c;從而避免應用消息丟失。RabbitMQ Management HTTP API提供了一個方法允許你查看任何vhost上的任何隊列&…

FFMpeg語法參數中文參考手冊

要查看你的ff mpeg支持哪些 格式&#xff0c;可以用如下命令&#xff1a;$ ffmpeg -formats | less還可以把 視頻文件導出成jpg序列幀&#xff1a;$ ffmpeg -i bc-cinematic-en.avi example.%d.jpgdebian下安裝ffmpeg很簡單&#xff1a;&#xff03;apt-get install ffmpegffmp…

Java類集框架 —— LinkedHashMap源碼分析

前言 我們知道HashMap底層是采用數組單向線性鏈表/紅黑樹來實現的&#xff0c;HashMap在擴容或者鏈表與紅黑樹轉換過程時可能會改變元素的位置和順序。如果需要保存元素存入或訪問的先后順序&#xff0c;那就需要采用LinkedHashMap了。 LinkedHashMap結構 LinkedHashMap繼承自H…

apache 支持.htaccess重寫url

1. httpd.conf 添加&#xff1a; <Directory />Options Indexes FollowSymLinks MultiviewsAllowOverride allRequire all grantedRewriteEngine On</Directory> 開啟&#xff1a; 在phpinfo里找到&#xff1a; 說明開啟成功。 2.httpd-vhosts.conf &#xff08;開…

oom 如何避免 高并發_【高并發】高并發環境下如何防止Tomcat內存溢出?看完我懂了!!...

【高并發】高并發環境下如何防止Tomcat內存溢出&#xff1f;看完我懂了&#xff01;&#xff01;發布時間&#xff1a;2020-04-19 00:47,瀏覽次數&#xff1a;126, 標簽&#xff1a;Tomcat寫在前面隨著系統并發量越來越高&#xff0c;Tomcat所占用的內存就會越來越大&#xff0…

[JSOI2008]最小生成樹計數

OJ題號&#xff1a;  BZOJ1016 題目大意&#xff1a;   給定一個無向帶權圖&#xff0c;求最小生成樹的個數。 思路&#xff1a;   先跑一遍最小生成樹&#xff0c;統計相同權值的邊出現的個數。   易證不同的最小生成樹&#xff0c;它們不同的那一部分邊的權值實際上是…

vuex webpack 配置_vue+webpack切換環境和打包之后服務器配置

import axios from ‘axios‘import store from ‘../store/index‘const rootUrl process.env.API_ROOT//創建axios實例const service axios.create({timeout:30000 //超時時間})//添加request攔截器service.interceptors.request.use(config >{if (Object.keys(config.hea…

redis基本用法學習(C#調用FreeRedis操作redis)

FreeRedis屬于常用的基于.net的redis客戶端&#xff0c;EasyCaching中也提供適配FreeRedis的包。根據參考文獻4中的說法&#xff0c;FreeRedis和CsRedis算是近親&#xff08;都是GitHub中賬號為2881099下的開源項目&#xff09;&#xff0c;因此其用法特別相似。FreeRedis的主要…

opencv:圖像的基本變換

0.概述 圖像變換的基本原理都是找到原圖和目標圖的像素位置的映射關系&#xff0c;這個可以用坐標系來思考&#xff0c;在opencv中&#xff0c; 圖像的坐標系是從左上角開始(0,0)&#xff0c;向右是x增加方向(cols)&#xff0c;向下時y增加方向(rows)。 普通坐標關系&#xff1…