[FFmpeg-devel] [PATCH v2 1/6] lavc: add new API for iterating codecs and codec parsers

wm4 nfxjfg at googlemail.com
Wed Jan 3 17:25:22 EET 2018


On Wed, 3 Jan 2018 00:42:36 +0000
Josh de Kock <josh at itanimul.li> wrote:

> Also replace linked list with an array.
> ---
>  configure              |   12 +-
>  doc/APIchanges         |    4 +
>  libavcodec/allcodecs.c | 1473 ++++++++++++++++++++++++++++--------------------
>  libavcodec/avcodec.h   |   31 +
>  libavcodec/parser.c    |   87 ++-
>  libavcodec/utils.c     |  105 ----
>  libavcodec/version.h   |    3 +
>  7 files changed, 974 insertions(+), 741 deletions(-)
> 

> +#if CONFIG_ME_CMP
> +#include "me_cmp.h"
> +#endif
> +
> +pthread_once_t av_codec_static_init = PTHREAD_ONCE_INIT;
> +static void av_codec_init_static(void)
> +{
> +#if CONFIG_ME_CMP
> +    ff_me_cmp_init_static();
> +#endif

(This should probably be moved away, since it doesn't really have to do
with any of this - it's just a global init in the wrong place. But I
won't insist that this gets cleaned up now. Someone else can do it
later.)

> +    for (int i = 0; codec_list[i]; i++) {
> +        if (codec_list[i]->init_static_data)
> +            codec_list[i]->init_static_data((AVCodec*)codec_list[i]);
>      }
> +}
> +
> +const AVCodec *av_codec_iterate(void **opaque)
> +{
> +    uintptr_t i = (uintptr_t)*opaque;
> +    const AVCodec *c = codec_list[i];
> +
> +    pthread_once(&av_codec_static_init, av_codec_init_static);

One issue: you need to use ff_thread_once() everywhere (it uses a
different initializer type too). The reason is because if it's built
without threads, pthread_once() will not be defined.

Same for all other uses of this.

>  
> -#define REGISTER_ENCDEC(X, x) REGISTER_ENCODER(X, x); REGISTER_DECODER(X, x)
> +    if (c)
> +        *opaque = (void*)(i + 1);
>  
> -#define REGISTER_PARSER(X, x)                                           \
> -    {                                                                   \
> -        extern AVCodecParser ff_##x##_parser;                           \
> -        if (CONFIG_##X##_PARSER)                                        \
> -            av_register_codec_parser(&ff_##x##_parser);                 \
> +    return c;
> +}
> +
> +#if FF_API_NEXT
> +pthread_once_t av_codec_next_init = PTHREAD_ONCE_INIT;
> +
> +static void av_codec_init_next(void)
> +{
> +    AVCodec *prev = NULL, *p;
> +    void *i = 0;
> +    while ((p = (AVCodec*)av_codec_iterate(&i))) {
> +        if (prev)
> +            prev->next = p;
> +        prev = p;
>      }

> +    if (prev)
> +        prev->next = NULL;

What's this for? Isn't it already initialized to NULL?

> +}
> +
>  
> -static void register_all(void)
> +
> +av_cold void avcodec_register(AVCodec *codec)
>  {
> -    /* video codecs */
> -    REGISTER_ENCODER(A64MULTI,          a64multi);

> +    pthread_once(&av_codec_next_init, av_codec_init_next);
> +}

I don't see much of a point in this call. Could be dropped, so the body
is empty.

> +AVCodec *av_codec_next(const AVCodec *c)
> +{
> +    pthread_once(&av_codec_next_init, av_codec_init_next);
> +
> +    if (c)
> +        return c->next;
> +    else
> +        return (AVCodec*)codec_list[0];
>  }
>  
>  void avcodec_register_all(void)
>  {
> -    static AVOnce control = AV_ONCE_INIT;
> +    pthread_once(&av_codec_next_init, av_codec_init_next);
> +}

So that means if you use the legacy API, you still need to call
the register function. Strange choice, but I'm fine with it.

> +#endif
> +
> +static enum AVCodecID remap_deprecated_codec_id(enum AVCodecID id)
> +{
> +    switch(id){
> +        //This is for future deprecatec codec ids, its empty since
> +        //last major bump but will fill up again over time, please don't remove it
> +        default                                         : return id;
> +    }
> +}
> +
> +static AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
> +{
> +    const AVCodec *p, *experimental = NULL;
> +    void *i = 0;
> +
> +    id = remap_deprecated_codec_id(id);
> +
> +    while ((p = av_codec_iterate(&i))) {
> +        if (!x(p))
> +            continue;
> +        if (p->id == id) {
> +            if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {
> +                experimental = p;
> +            } else
> +                return (AVCodec*)p;
> +        }
> +    }
>  
> -    ff_thread_once(&control, register_all);
> +    return (AVCodec*)experimental;
> +}
> +
> +AVCodec *avcodec_find_encoder(enum AVCodecID id)
> +{
> +    return find_codec(id, av_codec_is_encoder);
> +}
> +
> +AVCodec *avcodec_find_decoder(enum AVCodecID id)
> +{
> +    return find_codec(id, av_codec_is_decoder);
> +}
> +
> +static AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCodec *))
> +{
> +    void *i = 0;
> +    const AVCodec *p;
> +
> +    if (!name)
> +        return NULL;
> +
> +    while ((p = av_codec_iterate(&i))) {
> +        if (!x(p))
> +            continue;
> +        if (strcmp(name, p->name) == 0)
> +            return (AVCodec*)p;
> +    }
> +
> +    return NULL;
> +}
> +
> +AVCodec *avcodec_find_encoder_by_name(const char *name)
> +{
> +    return find_codec_by_name(name, av_codec_is_encoder);
> +}
> +
> +AVCodec *avcodec_find_decoder_by_name(const char *name)
> +{
> +    return find_codec_by_name(name, av_codec_is_decoder);
>  }

Personally I'd argue a bool parameter or so to select encoders vs.
decoders would be less roudnabout (like it was before), but I have no
strong opinion. Could be considered an improvement as well.

> +static void av_parser_init_next(void)
> +{
> +    AVCodecParser *prev = NULL, *p;
> +    int i = 0;
> +    while ((p = (AVCodecParser*)parser_list[i++])) {

(Personally I'd prefer less than 2 side effects in conditional
expressions, but maybe it doesn't matter.)

> +        if (prev)
> +            prev->next = p;
> +        prev = p;
> +    }

> +    if (prev)
> +        prev->next = NULL;

Probably redundant assignment again.

Still missing: APIchanges entry.


More information about the ffmpeg-devel mailing list