ffmpeg推流
流程詳解
av_register_all()
該方法初始化所有的封裝和解封裝。在使用FFmpeg的時候首先要調用這個方法。
這里面就是進行各種注冊,而REGISTER_MUXER 、REGISTER_DEMUXER 是前面定義的宏。我們看到是靜態方法,說明該方法只能在所在的文件中使用,這也防止被注冊多次。
avformat_network_init()
網絡相關初始化。如果我們使用了網絡拉流和推流等等,要先初始化。
avformat_open_input()
聲明是
定義在libavformat\utils.c中。主要功能
輸入輸出結構體AVIOContext的初始化;
輸入數據的協議URLProtocol,通過函數指針的方式,與FFMPEG關聯,剩下的就是調用該URLProtocol的函數進行open,read等操作了
avformat_find_stream_info
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
可以讀取視音頻數據并且獲得一些相關的信息。定義在libavformat\utils.c下
avformat_alloc_output_context2
int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat,
const char *format_name, const char *filename);
定義在libavformat\mux.c中
ctx:函數調用成功之后創建的AVFormatContext結構體。
oformat:指定AVFormatContext中的AVOutputFormat,用于確定輸出格式。如果指定為NULL,可以設定后兩個參數(format_name或者filename)由FFmpeg猜測輸出格式。
PS:使用該參數需要自己手動獲取AVOutputFormat,相對于使用后兩個參數來說要麻煩一些。
format_name:指定輸出格式的名稱。根據格式名稱,FFmpeg會推測輸出格式。輸出格式可以是“flv”,“mkv”等等。
filename:指定輸出文件的名稱。根據文件名稱,FFmpeg會推測輸出格式。文件名稱可以是“xx.flv”,“yy.mkv”等等。
函數執行成功的話,其返回值大于等于0。
內部流程
調用avformat_alloc_context()初始化一個默認的AVFormatContext。
如果指定了輸入的AVOutputFormat,則直接將輸入的AVOutputFormat賦值給AVOutputFormat的oformat。如果沒有指定輸入的AVOutputFormat,就需要根據文件格式名稱或者文件名推測輸出的AVOutputFormat。無論是通過文件格式名稱還是文件名推測輸出格式,都會調用一個函數av_guess_format()。
avio_open
打開FFmpeg的輸入輸出文件
int avio_open2(AVIOContext **s, const char *url, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options);
s:函數調用成功之后創建的AVIOContext結構體。
url:輸入輸出協議的地址(文件也是一種“廣義”的協議,對于文件來說就是文件的路徑)。
flags:打開地址的方式。可以選擇只讀,只寫,或者讀寫。取值如下。
AVIO_FLAG_READ:只讀。
AVIO_FLAG_WRITE:只寫。
AVIO_FLAG_READ_WRITE:讀寫。
int_cb:不太清楚
options:不太清楚
avformat_write_header
寫視頻文件頭,av_write_trailer()用于寫視頻文件尾
av_read_frame
定義在libavformat\utils.c中
讀取碼流中的音頻若干幀或者視頻一幀。解碼視頻的時候,每解碼一個視頻幀,需要先調用 av_read_frame()獲得一幀視頻的壓縮數據,然后才能對該數據進行解碼(例如H.264中一幀壓縮數據通常對應一個NAL)。
這里我貼上官方的注釋,很詳細:
總結起來每段的核心意思
讀取碼流中的音頻若干幀或者視頻一幀
如果pkt->buf是空,那么就要等待下一次av_read_frame調用。否則無法確定是否有效
pts dts duration通常被設置為正確的值。但如果視頻幀包括Bzh幀,那么pts可以是AV_NOPTS_VALUE。所以最好依賴dts。
av_interleaved_write_frame
輸出一幀視音頻數據
核心類
AVFormatContext
AVFormatContext是一個貫穿始終的數據結構,很多函數都要用到它作為參數。它是FFMPEG解封裝(flv,mp4,rmvb,avi)功能的結構體。
內部的成員變量,大家可以查看頭文件。這里我們列舉下一些常用重要的成員變量:
struct AVInputFormat *iformat:輸入數據的封裝格式
AVIOContext *pb:輸入數據的緩存
unsigned int nb_streams:視音頻流的個數
AVStream **streams:視音頻流
char filename[1024]:文件名
int64_t duration:時長(單位:微秒us,轉換為秒需要除以1000000)
int bit_rate:比特率(單位bps,轉換為kbps需要除以1000)
AVDictionary *metadata:元數據
視頻的原數據(metadata)信息可以通過AVDictionary獲取。元數據存儲在AVDictionaryEntry結構體中
typedef struct AVDictionaryEntry {
char *key;
char *value;
} AVDictionaryEntry;
每一條元數據分為key和value兩個屬性。
在ffmpeg中通過av_dict_get()函數獲得視頻的原數據。
AVStream
AVStream是存儲每一個視頻/音頻流信息的結構體。
int index:標識該視頻/音頻流
AVCodecContext codec:指向該視頻/音頻流的AVCodecContext(它們是一一對應的關系)
AVRational time_base:時基。通過該值可以把PTS,DTS轉化為真正的時間。- FFMPEG其他結構體中也有這個字段,但是根據我的經驗,只有AVStream中的time_base是可用的。PTStime_base=真正的時間
int64_t duration:該視頻/音頻流長度
AVDictionary *metadata:元數據信息
AVRational avg_frame_rate:幀率(注:對視頻來說,這個挺重要的)
AVPacket attached_pic:附帶的圖片。比如說一些MP3,AAC音頻文件附帶的專輯封面。
AVPacket
AVPacket是存儲壓縮編碼數據相關信息的結構體。
uint8_t *data:壓縮編碼的數據。
例如對于H.264來說。1個AVPacket的data通常對應一個NAL。
注意:在這里只是對應,而不是一模一樣。他們之間有微小的差別:使用FFMPEG類庫分離出多媒體文件中的H.264碼流
因此在使用FFMPEG進行視音頻處理的時候,常常可以將得到的AVPacket的data數據直接寫成文件,從而得到視音頻的碼流文件。
int size:data的大小
int64_t pts:顯示時間戳
int64_t dts:解碼時間戳
int stream_index:標識該AVPacket所屬的視頻/音頻流。
總結
- 上一篇: ffmpeg推流及python管道控制f
- 下一篇: 两分钟学会线性同余法产生伪随机数