为掌握ffmpeg的工作流程,现以libavcodec下的ffmpeg/doc/examples/decoding_encoding.c中实现视频编码为例展示其工作过程。
libavcodec库是实现音频或视频的编码或解码,所有编解码CODEC的调用均有统一的格式,ffmpeg以公共的函数指针注册、调用和销毁
CODEC。
video_encode_example例程实现给定视频数据的编码,将编码后的码流写文件。所有avcodec的调用均使用统一的过程,首先是初始化avcodec_init(),所有CODEC库在使用前均需要调用该函数;然后是注册所有的CODEC,包括注册编码器REGISTER_ENCODER、解码器REGISTER_DECODER、编解码器REGISTER_ENCDEC等;最后使用CODEC,如video_encode_example。
1 初始化CODEC
调用ffmpeg的函数avcodec_init实现CODEC的初始化。
static av_cold void avcodec_init(void)
{
static int initialized = 0; //静态变量标注初始化,只调用一次
if (initialized != 0)
return;
initialized = 1;
if (CONFIG_ME_CMP)
ff_me_cmp_init_static();
}
为确保该初始化仅被调用一次,因此使用局部静态变量,记录以前的动作。初始化的任务是将“数字信号处理应用”中的静态表格初始化。其实就是一个数组,初始化其为0。
初始化的函数会在这里被调用:
av_cold void avcodec_register(AVCodec *codec)
{
AVCodec **p;
avcodec_init();
p = last_avcodec;
codec->next = NULL;
while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec))
p = &(*p)->next;
last_avcodec = &codec->next;
if (codec->init_static_data)
codec->init_static_data(codec);
}
2 注册CODEC
由于有诸多的CODEC,所以ffmpeg以公共的函数指针的方式,以统一的接口操作CODEC。首先AVCodec结构体定义了函数指针,某一个CODEC实例填充AVCodec结构的字段,然后用REGISTER_ENCODER注册该CODEC。
struct AVSubtitle;
/**
* AVCodec.
*/
typedef struct AVCodec {
/**
* Name of the codec implementation.
* The name is globally unique among encoders and among decoders (but an
* encoder and a decoder can share the same name).
* This is the primary way to find a codec from the user perspective.
*/
const char *name;
/**
* Descriptive name for the codec, meant to be more human readable than name.
* You should use the NULL_IF_CONFIG_SMALL() macro to define it.
*/
const char *long_name;
enum AVMediaType type;
enum AVCodecID id;
/**
* Codec capabilities.
* see AV_CODEC_CAP_*
*/
int capabilities;
const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0}
const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1
const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is