ffmpeg源碼分析之數據流
本文主要介紹ffmpeg的數據流,在ffmpeg中主要分有三個主要用途用於媒體流的解碼播放,媒體流的轉換(解碼之後再編碼)和媒體流錄製。
媒體流的解碼播放
在ffmpeg中媒體流的解碼播放流程如下圖:
其主要流程爲從媒體文件中讀取出媒體流,然後送入媒體格式解碼器(demuxer)中去除多餘的外衣--媒體格式。然後送入ffmpeg的codec的decode中進行解碼,最終生成顯示需要的YUV格式的圖片,然後再送入類似SDL中進行渲染。ffmpeg中媒體流的解碼播放流程相對比較來說其最大的難點在於pts的同步,在ffmpeg的ffplay中有很好的例子。例子中是啓動了多個線程來進行同步的。
媒體流的轉換
所謂媒體流的轉換分以下幾種情況:
一種是格式轉換,也相當於我們平時的換衣服一樣,只是換個樣式,換一種組織樣式以適應不同場合的需要。
一種是媒體編碼類型的轉換,例如將codec從mpeg4 to H264相當於不同的人來買同一個衣服,雖然外表(格式)看起來一樣但穿衣服的人已經發生了變化。
一種是媒體編碼類型和格式同時轉換,例如將格式爲flv的轉換爲mpeg4,同時將codec從mpeg4 to H264相當於不同的人穿了不同的衣服。
其流程如下圖:
其數據流前半部分同解碼流程一樣,後半部分則和解碼的流程相反。當解析出YUV圖片之後,然後編碼成另外一種codec,之後再將codec的數據加上一個外殼形成一個媒體文件然後通過byteIocontext寫入目標文件。
媒體流錄製
媒體流的錄製過程相當於媒體流轉換的後半部分流程從YUV文件到media文件。其流程爲:
FFMPEG中的decoder的組織形式:
FFMPEG中codec的數據結構如下:
typedef struct AVCodec {
const char *name;
enum AVMediaType type;
enum CodecID id;
int priv_data_size;
int (*init)(AVCodecContext *);
int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data);
int (*close)(AVCodecContext *);
int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
int capabilities;
struct AVCodec *next;
void (*flush)(AVCodecContext *);
const AVRational *supported_framerates;
const enum PixelFormat *pix_fmts;
const char *long_name;
const int *supported_samplerates;
const enum SampleFormat *sample_fmts;
const int64_t *channel_layouts;
} AVCodec;
這個數據結構分別用於decoder和encoder,當被decoder所用時函數指針encode爲NULL,而當用於encode時其decode爲NULL,在ffmpeg中通過向全局變量
static AVCodec *first_avcodec;
中添加新的codec變量。在查找的過程也是通過遍歷這個鏈表然後通過name來匹配相應的codec這個過程將會在以後的文章中詳細描述。在ffmpeg中formate的組織結構和codec類似。