[9]【ffmpeg原始碼分析 1】av_register_all()和avcodec_register_all()
阿新 • • 發佈:2018-12-29
日期:2016.10.18
作者:isshe
github:github.com/isshe
郵箱:[email protected]
前言
接下來打算學習一下編解碼,不過好像很難的樣子, 希望能看懂。
1. av_register_all()
- 所在檔案:allformats.c
- 主要程式碼:(每個巨集只列舉一個)
void av_register_all(void)
{
static int initialized;
if (initialized)
return;
//註冊編解碼器
avcodec_register_all();
/* (de)muxers */
//註冊複用器
REGISTER_MUXER (A64, a64);
//註冊解複用器
REGISTER_DEMUXER (AA, aa);
//兩個同時註冊
REGISTER_MUXDEMUX(AC3, ac3);
1.1 REGISTER_MUXER巨集
- 程式碼:
#define REGISTER_MUXER(X, x) \
{ \
extern AVOutputFormat ff_##x##_muxer; \
if (CONFIG_##X##_MUXER) \
av_register_output_format(&ff_##x##_muxer); \
}
- “##”號起連線作用,例如:a##b = ab.
- ff_##x##_muxer, 一個與x對應的AVOutputFormat.
- 其實這些外部變數,一般定義的時候就賦了初值。(限於篇幅,具體的示例在下面編解碼相關的地方)
1.1.1 av_register_output_format()
- 註冊一個與該格式相應的AVFormat結構
- 相關程式碼:
//head of registered output format linked list
static AVOutputFormat *first_oformat = NULL;
static AVOutputFormat **last_oformat = &first_oformat;
void av_register_output_format(AVOutputFormat *format)
{
AVOutputFormat **p = last_oformat;
// Note, format could be added after the first 2 checks but that implies that *p is no longer NULL
//檢查連結串列中有無指定的format,沒有就加入。
//在前面兩個條件成立後才把format連線到p連結串列中。
while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
p = &(*p)->next;
if (!format->next)
last_oformat = &format->next;
}
- last_oformat是一個二次指標。
- avpriv_atomic_ptr_cas把format放到p連結串列中。
- 遍歷連結串列,把指定format加到連結串列後面。
1.2 REGISTER_DEMUXER 巨集
- 和REGISTER_MUXER()類似。
1.3 REGISTER_MUXDEMUX 巨集
- #define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)
2. avcodec_register_all()
- 所在檔案:allcodecs.c
- 主要程式碼:(每種情況列舉一個)
void avcodec_register_all(void)
{
static int initialized;
if (initialized)
return;
initialized = 1;
//硬體加速器
/* hardware accelerators */
REGISTER_HWACCEL(H263_CUVID, h263_cuvid);
//注意以下函式適用於視訊和音訊
//註冊編碼器
REGISTER_ENCODER(A64MULTI, a64multi);
//註冊解碼器
REGISTER_DECODER(AASC, aasc);
//兩個同時註冊
REGISTER_ENCDEC (ALIAS_PIX, alias_pix);
//註冊分析器???不懂
REGISTER_PARSER(AAC, aac);
2.1 REGISTER_HWACCEL 巨集
- 註冊硬體加速器巨集
- 程式碼:
#define REGISTER_HWACCEL(X, x) \
{ \
extern AVHWAccel ff_##x##_hwaccel; \
if (CONFIG_##X##_HWACCEL) \
av_register_hwaccel(&ff_##x##_hwaccel); \
}
- extern的那個變數在原始碼中沒找著…
2.1.1 av_register_hwaccel()
- 註冊硬體加速器的函式
- 程式碼:和前面的muter類似。
void av_register_hwaccel(AVHWAccel *hwaccel)
{
AVHWAccel **p = last_hwaccel;
hwaccel->next = NULL;
while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel))
p = &(*p)->next;
last_hwaccel = &hwaccel->next;
}
2.2 REGISTER_ENCODER巨集
- 註冊編碼器的巨集
- 程式碼:
#define REGISTER_ENCODER(X, x) \
{ \
extern AVCodec ff_##x##_encoder; \
if (CONFIG_##X##_ENCODER) \
avcodec_register(&ff_##x##_encoder); \
}
2.2.1 ff_##x##_encoder變數
- 用aac示例:ff_aac_encoder變數
AVCodec ff_aac_encoder = {
.name = "aac",
.long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_AAC,
.priv_data_size = sizeof(AACEncContext),
.init = aac_encode_init, //初始化
.encode2 = aac_encode_frame, //編碼函式
.close = aac_encode_end, //
.defaults = aac_encode_defaults,
.supported_samplerates = mpeg4audio_sample_rates,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
.capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
.priv_class = &aacenc_class,
};
- 可見,這些外部變數都是已經賦值好的,解碼的【或其他】也類似。
- 下面呼叫的註冊函式就是把這麼一個結構放到連結串列中。
2.2.2 avcodec_register
- 註冊編碼器的函式
- 程式碼:
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.3 REGISTER_DECODER 巨集
- 和編碼類似
2.4 REGISTER_ENCDEC 巨集
- 同時註冊解碼和編碼器
2.5 REGISTER_PARSER 巨集
- 程式碼:
#define REGISTER_PARSER(X, x) \
{ \
extern AVCodecParser ff_##x##_parser; \
if (CONFIG_##X##_PARSER) \
av_register_codec_parser(&ff_##x##_parser); \
}
av_register_codec_parser()
- 程式碼:
void av_register_codec_parser(AVCodecParser *parser)
{
do {
parser->next = av_first_parser;
} while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser));
}