天天看點

ffmpeg函數介紹

本文對在使用ffmpeg進行音視訊編解碼時使用到的一些函數做一個簡單介紹,我目前使用的ffmpeg版本為:0.8.5,因為本人發現在不同的版本中,有些函數名稱會有點小改動,是以在此有必要說明下ffmpeg的版本号。

ffmpeg本人也是剛接觸,本文将采用累加的方法逐個介紹我使用到的函數,如有不妥之處,還望諒解!

頭檔案引入方法:

extern "C" {

#include "libavcodec/avcodec.h"

#include "libavformat/avformat.h"

#include "libavutil/avutil.h"

#include "libavutil/mem.h"

#include "libavutil/fifo.h"

#include "libswscale/swscale.h"

};

1 avcodec_init()

void avcodec_init(void);

// 初始化libavcodec,一般最先調用該函數

// 引入頭檔案: #include "libavcodec/avcodec.h"

// 實作在: \ffmpeg\libavcodec\utils.c

// 該函數必須在調用libavcodec裡的其它函數前調用,一般在程式啟動或子產品初始化時調用,如果你調用了多次也無所謂,因為後面的調用不會做任何事情.從函數的實作裡你可以發現,代碼中對多次調用進行了控制.

// 該函數是非線程安全的

2 av_register_all()

void av_register_all(void);

// 初始化 libavformat和注冊所有的muxers、demuxers和protocols,

// 一般在調用avcodec_init後調用該方法

// 引入頭檔案:#include "libavformat/avformat.h"

// 實作在:\ffmpeg\libavformat\allformats.c

// 其中會調用avcodec_register_all()注冊多種音視訊格式的編解碼器,并注冊各種檔案的編解複用器

// 當然,你也可以不調用該函數,而通過選擇調用特定的方法來提供支援

3 avformat_alloc_context()

AVFormatContext *avformat_alloc_context(void);

// 配置設定一個AVFormatContext結構

// 引入頭檔案:#include "libavformat/avformat.h"

// 實作在:\ffmpeg\libavformat\options.c

// 其中負責申請一個AVFormatContext結構的記憶體,并進行簡單初始化

// avformat_free_context()可以用來釋放該結構裡的所有東西以及該結構本身

// 也是就說使用 avformat_alloc_context()配置設定的結構,需要使用avformat_free_context()來釋放

// 有些版本中函數名可能為: av_alloc_format_context();

4 avformat_free_context()

void avformat_free_context(AVFormatContext *s);

// 釋放一個AVFormatContext結構

// 引入頭檔案:#include "libavformat/avformat.h"

// 實作在:\ffmpeg\libavformat\utils.c

// 使用 avformat_alloc_context()配置設定的結構,采用該函數進行釋放,除釋放AVFormatContext結構本身記憶體之外,AVFormatContext中指針所指向的記憶體也會一并釋放

// 有些版本中函數名猜測可能為: av_free_format_context();

5 AVFormatContext 結構

typedef struct AVFormatContext {

    struct AVInputFormat *iformat;

    struct AVOutputFormat *oformat;

    AVIOContext *pb;

    unsigned int nb_streams;

    AVStream **streams;

    char filename[1024];

    ....

} AVFormatContext;

// AVFormatContext在FFMpeg裡是一個非常重要的的結構,是其它輸入、輸出相關資訊的一個容器

// 引入頭檔案:#include "libavformat/avformat.h"

// 以上隻列出了其中的部分成員

// 作為輸入容器時 struct AVInputFormat *iformat; 不能為空, 其中包含了輸入檔案的音視訊流資訊,程式從輸入容器從讀出音視訊包進行解碼處理

// 作為輸出容器時 struct AVOutputFormat *oformat; 不能為空, 程式把編碼好的音視訊包寫入到輸出容器中

// AVIOContext *pb: I/O上下文,通過對該變量指派可以改變輸入源或輸出目的

// unsigned int nb_streams; 音視訊流數量

// AVStream **streams; 音視訊流

6 AVIOContext 結構

typedef struct {

    unsigned char *buffer; 

    int buffer_size;       

    unsigned char *buf_ptr;

    unsigned char *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;           

    int must_flush;        

    int eof_reached;       

    int write_flag;        

#if FF_API_OLD_AVIO

    attribute_deprecated int is_streamed;

#endif

    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;             

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

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

                         int64_t timestamp, int flags);

    int seekable;

} AVIOContext;

// 位元組流 I/O 上下文

// 在結構的尾部增加變量可以減少版本沖突

// 移除、排序和修改已經存在的變量将會導緻較大的版本沖突

// sizeof(AVIOContext)在libav*.外部不可使用

// AVIOContext裡的函數指針不能直接調用,通常使用avio_alloc_context()函數來設定其中的函數指針

// unsigned char *buffer: 緩存的起始指針

// int buffer_size: 緩存的最大值

// 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): seek檔案回調方法

7 avio_alloc_context()

AVIOContext *avio_alloc_context(

                  unsigned char *buffer,

                  int buffer_size,

                  int write_flag,

                  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));

// 為I/0緩存申請并初始化一個AVIOContext結構,結束使用時必須使用av_free()進行釋放

// unsigned char *buffer: 輸入/輸出緩存記憶體塊,必須是使用av_malloc()配置設定的

// int buffer_size: 緩存大小是非常重要的

// int write_flag: 如果緩存為可寫則設定為1,否則設定為0

// void *opaque: 指針,用于回調時使用

// int (*read_packet): 讀包函數指針

// int (*write_packet): 寫包函數指針

// int64_t (*seek): seek檔案函數指針

8 av_open_input_file()

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

                       AVInputFormat *fmt,

                       int buf_size,

                       AVFormatParameters *ap);

// 以輸入方式打開一個媒體檔案,也即源檔案,codecs并沒有打開,隻讀取了檔案的頭資訊.

// 引入頭檔案:#include "libavformat/avformat.h"

// AVFormatContext **ic_ptr 輸入檔案容器

// const char *filename 輸入檔案名,全路徑,并且保證檔案存在

// AVInputFormat *fmt 輸入檔案格式,填NULL即可

// int buf_size,緩沖區大小,直接填0即可

// AVFormatParameters *ap, 格式參數,添NULL即可

// 成功傳回0,其它失敗

// 不贊成使用 avformat_open_input 代替

9 av_close_input_file()

void av_close_input_file(AVFormatContext *s);

// 關閉使用avformat_close_input()打開的輸入檔案容器,但并不關系它的codecs

// 引入頭檔案:#include "libavformat/avformat.h"

// 使用av_open_input_file 打開的檔案容器,可以使用該函數關閉

// 使用 av_close_input_file 關閉後,就不再需要使用avformat_free_context 進行釋放了

10 av_find_stream_info()

int av_find_stream_info(AVFormatContext *ic);

// 通過讀取媒體檔案的中的包來擷取媒體檔案中的流資訊,對于沒有頭資訊的檔案如(mpeg)是非常有用的,

// 該函數通常重算類似mpeg-2幀模式的真實幀率,該函數并未改變邏輯檔案的position.

// 引入頭檔案:#include "libavformat/avformat.h"

// 也就是把媒體檔案中的音視訊流等資訊讀出來,儲存在容器中,以便解碼時使用

// 傳回>=0時成功,否則失敗

1 avcodec_find_decoder()

AVCodec *avcodec_find_decoder(enum CodecID id);

// 通過code ID查找一個已經注冊的音視訊解碼器

// 引入 #include "libavcodec/avcodec.h"

// 實作在: \ffmpeg\libavcodec\utils.c

// 查找解碼器之前,必須先調用av_register_all注冊所有支援的解碼器

// 查找成功傳回解碼器指針,否則傳回NULL

// 音視訊解碼器儲存在一個連結清單中,查找過程中,函數從頭到尾周遊連結清單,通過比較解碼器的ID來查找

2 avcodec_find_decoder_by_name()

AVCodec *avcodec_find_decoder_by_name(const char *name);

// 通過一個指定的名稱查找一個已經注冊的音視訊解碼器

// 引入 #include "libavcodec/avcodec.h"

// 實作在: \ffmpeg\libavcodec\utils.c

// 查找解碼器之前,必須先調用av_register_all注冊所有支援的解碼器

// 查找成功傳回解碼器指針,否則傳回NULL

// 音視訊解碼器儲存在一個連結清單中,查找過程中,函數從頭到尾周遊連結清單,通過比較解碼器的name來查找

3 avcodec_find_encoder()

AVCodec *avcodec_find_encoder(enum CodecID id);

// 通過code ID查找一個已經注冊的音視訊編碼器

// 引入 #include "libavcodec/avcodec.h"

// 實作在: \ffmpeg\libavcodec\utils.c

// 查找編碼器之前,必須先調用av_register_all注冊所有支援的編碼器

// 查找成功傳回編碼器指針,否則傳回NULL

// 音視訊編碼器儲存在一個連結清單中,查找過程中,函數從頭到尾周遊連結清單,通過比較編碼器的ID來查找

4 avcodec_find_encoder_by_name()

AVCodec *avcodec_find_encoder_by_name(const char *name);

// 通過一個指定的名稱查找一個已經注冊的音視訊編碼器

// 引入 #include "libavcodec/avcodec.h"

// 實作在: \ffmpeg\libavcodec\utils.c

// 查找編碼器之前,必須先調用av_register_all注冊所有支援的編碼器

// 查找成功傳回編碼器指針,否則傳回NULL

// 音視訊編碼器儲存在一個連結清單中,查找過程中,函數從頭到尾周遊連結清單,通過比較編碼器的名稱來查找

5 avcodec_open()

int avcodec_open(AVCodecContext *avctx, AVCodec *codec);

// 使用給定的AVCodec初始化AVCodecContext

// 引入#include "libavcodec/avcodec.h"

// 方法: avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), avcodec_find_decoder() and avcodec_find_encoder() 提供了快速擷取一個codec的途徑

// 該方法在編碼和解碼時都會用到

// 傳回0時成功,打開作為輸出時,參數設定不對的話,調用會失敗

  6 av_guess_format()

AVOutputFormat *av_guess_format(const char *short_name,

                                const char *filename,

                                const char *mime_type);

// 傳回一個已經注冊的最合适的輸出格式

// 引入#include "libavformat/avformat.h"

// 可以通過 const char *short_name 擷取,如"mpeg"

// 也可以通過 const char *filename 擷取,如"E:\a.mp4"

7 av_new_stream()

AVStream *av_new_stream(AVFormatContext *s, int id);

// 為媒體檔案添加一個流,一般為作為輸出的媒體檔案容器添加音視訊流

// 引入 #include "libavformat/avformat.h"

// 再打開源檔案時使用者一般不需要直接調用該方法

  8 dump_format()

#if FF_API_DUMP_FORMAT

attribute_deprecated void dump_format(AVFormatContext *ic,

                                      int index,

                                      const char *url,

                                      int is_output);

#endif

// 該函數的作用就是檢查下初始化過程中設定的參數是否符合規範 // 有些版本中為 av_ dump_format   9 av_set_parameters()

#if FF_API_FORMAT_PARAMETERS

attribute_deprecated int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap);

#endif // 設定初始化參數 // 不贊成跳過該方法,直接調用 avformat_write_header/av_write_header   10 av_write_header()

#if FF_API_FORMAT_PARAMETERS

attribute_deprecated int av_write_header(AVFormatContext *s);

#endif

// 把流頭資訊寫入到媒體檔案中 // 傳回0成功  

1 AVPacket

typedef struct AVPacket {

    int64_t pts;

    int64_t dts;

    uint8_t *data;

    int   size;

    int   stream_index;

    int   flags;

int   duration;

.

.

.

} AVPacket

// AVPacket是個很重要的結構,該結構在讀媒體源檔案和寫輸出檔案時都需要用到 // int64_t pts; 顯示時間戳 // int64_t dts; 解碼時間戳 // uint8_t *data; 包資料 // int   size; 包資料長度 // int   stream_index; 包所屬流序号 // int   duration; 時長 // 以上資訊,如果是在讀媒體源檔案那麼avcodec會初始化,如果是輸出檔案,使用者需要對以上資訊指派   2 av_init_packet()

void av_init_packet(AVPacket *pkt);

// 使用預設值初始化AVPacket // 定義AVPacket對象後,請使用av_init_packet進行初始化   3 av_free_packet()

void av_free_packet(AVPacket *pkt);

// 釋放AVPacket對象   4 av_read_frame()

int av_read_frame(AVFormatContext *s, AVPacket *pkt);

// 從輸入源檔案容器中讀取一個AVPacket資料包

// 該函數讀出的包并不每次都是有效的,對于讀出的包我們都應該進行相應的解碼(視訊解碼/音頻解碼),

// 在傳回值>=0時,循環調用該函數進行讀取,循環調用之前請調用av_free_packet函數清理AVPacket   5 avcodec_decode_video2()

int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,

                         int *got_picture_ptr,

                         AVPacket *avpkt);

// 解碼視訊流AVPacket // 使用av_read_frame讀取媒體流後需要進行判斷,如果為視訊流則調用該函數解碼 // 傳回結果<0時失敗,此時程式應該退出檢查原因 // 傳回>=0時正常,假設 讀取包為:AVPacket vPacket 傳回值為 int vLen; 每次解碼正常時,對vPacket做 // 如下處理: //   vPacket.size -= vLen;

//   vPacket.data += vLen; // 如果 vPacket.size==0,則繼續讀下一流包,否則繼續排程該方法進行解碼,直到vPacket.size==0 // 傳回 got_picture_ptr > 0 時,表示解碼到了AVFrame *picture,其後可以對picture程序處理   6 avcodec_decode_audio3()

int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,

                         int *frame_size_ptr,

                         AVPacket *avpkt);

// 解碼音頻流AVPacket // 使用av_read_frame讀取媒體流後需要進行判斷,如果為音頻流則調用該函數解碼 // 傳回結果<0時失敗,此時程式應該退出檢查原因 // 傳回>=0時正常,假設 讀取包為:AVPacket vPacket 傳回值為 int vLen; 每次解碼正常時,對vPacket做 // 如下處理: //   vPacket.size -= vLen;

//   vPacket.data += vLen; // 如果 vPacket.size==0,則繼續讀下一流包,否則繼續排程該方法進行解碼,直到vPacket.size==0   轉自:http://blog.chinaunix.net/uid/20718335/frmd/153034.html

繼續閱讀