ffmpeg源碼分析五:ffmpeg調用x264編碼器的過程分析 (轉5)


原帖地址:http://blog.csdn.net/austinblog/article/details/25127533

 

該文將以X264編碼器為例,解釋說明FFMPEG是怎么調用第三方編碼器來進行編碼的。

 
 

所有編碼器和解碼器都是在avcodec_register_all()函數中注冊的。從中可以找到視頻的H264解碼器和X264編碼器:

 

REGISTER_DECODER(H264,              h264);

REGISTER_ENCODER(LIBX264,           libx264);

 

他們都是通過一下宏進行相應的注冊的:

 

#define REGISTER_DECODER(X, x)                                          \
     {                                                                   \
         extern AVCodec ff_##x##_decoder;                                \
         if (CONFIG_##X##_DECODER)                                       \
             avcodec_register(&ff_##x##_decoder);                        \
     }





#define REGISTER_ENCODER(X, x)                                          \
     {                                                                   \
         extern AVCodec ff_##x##_encoder;                                \
         if (CONFIG_##X##_ENCODER)                                       \
             avcodec_register(&ff_##x##_encoder);                        \
     }

 

注冊的過程發生在avcodec_register(AVCodec *codec)函數中,實際上就是向全局鏈表last_avcodec中加入libx264_encoder、h264_decoder特定的編解碼器,輸入參數AVCodec是一個結構體,可以理解為編解碼器的基類,其中不僅包含了名稱,id等屬性,而且包含了如下函數指針,讓每個具體的編解碼器擴展類實現。

 

 int (*init)(AVCodecContext *);

    int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size,
                       const struct AVSubtitle *sub);
     /**
      * Encode data to an AVPacket.
      *
      * @param      avctx          codec context
      * @param      avpkt          output AVPacket (may contain a user-provided buffer)
      * @param[in]  frame          AVFrame containing the raw data to be encoded
      * @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a
      *                            non-empty packet was returned in avpkt.
      * @return 0 on success, negative error code on failure
      */
     int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr);
     int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
     int (*close)(AVCodecContext *);
     /**
      * Flush buffers.
      * Will be called when seeking
      */
     void (*flush)(AVCodecContext *);

繼續追蹤libx264,也就是X264的靜態編碼庫,它在FFMPEG編譯的時候被引入作為H.264編碼器。在libx264.c中有如下代碼

 

AVCodec ff_libx264_encoder = {
     .name             = "libx264",
     .long_name        = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
     .type             = AVMEDIA_TYPE_VIDEO,
     .id               = AV_CODEC_ID_H264,
     .priv_data_size   = sizeof(X264Context),
     .init             = X264_init,
     .encode2          = X264_frame,
     .close            = X264_close,
     .capabilities     = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
     .priv_class       = &x264_class,
     .defaults         = x264_defaults,
     .init_static_data = X264_init_static,
 };

這里具體對來自AVCodec的屬性和方法進行賦值。其中

  .init = X264_init,
     .encode2 = X264_frame,
     .close = X264_close,

將函數指針指向了具體函數,這三個函數將使用libx264靜態庫中提供的API,也就是X264的主要接口函數進行具體實現。

上面看到的X264Context封裝了X264所需要的上下文管理數據,

typedef struct X264Context {
     AVClass        *class;
     x264_param_t    params;
     x264_t         *enc;
     x264_picture_t  pic;
     uint8_t        *sei;
     int             sei_size;
     char *preset;
     char *tune;
     char *profile;
     char *level;
     int fastfirstpass;
     char *wpredp;
     char *x264opts;
     float crf;
     float crf_max;
     int cqp;
     int aq_mode;
     float aq_strength;
     char *psy_rd;
     int psy;
     int rc_lookahead;
     int weightp;
     int weightb;
     int ssim;
     int intra_refresh;
     int bluray_compat;
     int b_bias;
     int b_pyramid;
     int mixed_refs;
     int dct8x8;
     int fast_pskip;
     int aud;
     int mbtree;
     char *deblock;
     float cplxblur;
     char *partitions;
     int direct_pred;
     int slice_max_size;
     char *stats;
     int nal_hrd;
     char *x264_params;
 } X264Context;

它屬於結構體AVCodecContext的void *priv_data變量,定義了每種編解碼器私有的上下文屬性,AVCodecContext也類似上下文基類一樣。可以用類圖來表示大概的編解碼器組合。

 

 

編解碼器打開操作是在transcode_init() -> init_input_stream() -> avcodec_open2()完成的,對具體的編解碼器進行初始化。例如X264_init()

 

具體的編碼操作是在transcode() -> transcode_step() -> reap_filters() -> do_video_out() 或 do_audio_out() -> avcodec_encode_video2() 或 avcodec_encode_audio2()。然后通過函數指針調用特定的編解碼器。例如X264_frame()。

 

最后通過avcodec_close()關閉編解碼器。例如X264_close()。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM