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

wm4 nfxjfg at googlemail.com
Sat Dec 23 17:50:26 EET 2017


On Sat, 23 Dec 2017 13:27:53 +0000
Josh de Kock <josh at itanimul.li> wrote:

> From 1d84641556eea563b82b17a6ffe54226e0e31c4e Mon Sep 17 00:00:00 2001
> From: Josh de Kock <josh at itanimul.li>
> Date: Fri, 22 Dec 2017 22:17:00 +0000
> Subject: [PATCH] lavc: add new API for iterating codecs and codec parsers
> 
> Also replace linked list with an array.
> ---

I generally agree with this patch.

>  configure              |   14 +-
>  libavcodec/allcodecs.c | 1472 ++++++++++++++++++++++++++++--------------------
>  libavcodec/avcodec.h   |   25 +
>  libavcodec/parser.c    |   86 ++-
>  libavcodec/utils.c     |  105 ----
>  5 files changed, 962 insertions(+), 740 deletions(-)
> 
> diff --git a/configure b/configure
> index d09eec4..681fe10 100755
> --- a/configure
> +++ b/configure
> @@ -3517,9 +3517,6 @@ find_things(){
>      sed -n "s/^[^#]*$pattern.*([^,]*, *\([^,]*\)\(,.*\)*).*/\1_$thing/p" "$file"
>  }
>  
> -ENCODER_LIST=$(find_things  encoder  ENC      libavcodec/allcodecs.c)
> -DECODER_LIST=$(find_things  decoder  DEC      libavcodec/allcodecs.c)
> -PARSER_LIST=$(find_things   parser   PARSER   libavcodec/allcodecs.c)
>  MUXER_LIST=$(find_things    muxer    _MUX     libavformat/allformats.c)
>  DEMUXER_LIST=$(find_things  demuxer  DEMUX    libavformat/allformats.c)
>  OUTDEV_LIST=$(find_things   outdev   OUTDEV   libavdevice/alldevices.c)
> @@ -3533,6 +3530,13 @@ find_things_extern(){
>      sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$thing/p" "$file"
>  }
>  
> +ENCODER_LIST=$(find_things_extern encoder AVCodec libavcodec/allcodecs.c)
> +DECODER_LIST=$(find_things_extern decoder AVCodec libavcodec/allcodecs.c)
> +CODEC_LIST="
> +    $ENCODER_LIST
> +    $DECODER_LIST
> +"
> +PARSER_LIST=$(find_things_extern parser AVCodecParser libavcodec/parser.c)
>  BSF_LIST=$(find_things_extern bsf AVBitStreamFilter libavcodec/bitstream_filters.c)
>  HWACCEL_LIST=$(find_things_extern hwaccel AVHWAccel libavcodec/hwaccels.h)
>  PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c)
> @@ -7020,6 +7024,10 @@ print_enabled_components(){
>      cp_if_changed $TMPH $file
>  }
>  
> +print_enabled_components libavcodec/codec_list.c AVCodec codec_list $CODEC_LIST
> +#print_enabled_components libavcodec/encoder_list.c AVCodec encoder_list $ENCODER_LIST
> +#print_enabled_components libavcodec/decoder_list.c AVCodec decoder_list $DECODER_LIST

Commented leftover crap?

> +print_enabled_components libavcodec/parser_list.c AVCodecParser parser_list $PARSER_LIST
>  print_enabled_components libavcodec/bsf_list.c AVBitStreamFilter bitstream_filters $BSF_LIST
>  print_enabled_components libavformat/protocol_list.c URLProtocol url_protocols $PROTOCOL_LIST
>  
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index ed1e7ab..cea2bf3 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -29,641 +29,865 @@
>  #include "avcodec.h"
>  #include "version.h"
>  
> -#define REGISTER_ENCODER(X, x)                                          \
> -    {                                                                   \
> -        extern AVCodec ff_##x##_encoder;                                \
> -        if (CONFIG_##X##_ENCODER)                                       \
> -            avcodec_register(&ff_##x##_encoder);                        \
> +extern AVCodec ff_a64multi_encoder;
> [...] 
>
> +#include "codec_list.c"
> +
> +#if CONFIG_ME_CMP
> +#include "me_cmp.h"
> +pthread_once_t ff_me_cmp_static_init = PTHREAD_ONCE_INIT;
> +#endif
> +
> +pthread_once_t av_codec_next_init = PTHREAD_ONCE_INIT;
> +
> +const AVCodec *av_codec_iterate(void **opaque)
> +{
> +    uintptr_t i = (uintptr_t)*opaque;
> +    const AVCodec *c = codec_list[i];
> +
> +    if (c)
> +        *opaque = (void*)(i + 1);
> +
> +    return c;
> +}
> +
> +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;
>      }
> +    prev->next = NULL;
> +}
>  
> -#define REGISTER_DECODER(X, x)                                          \
> -    {                                                                   \
> -        extern AVCodec ff_##x##_decoder;                                \
> -        if (CONFIG_##X##_DECODER)                                       \
> -            avcodec_register(&ff_##x##_decoder);                        \
> +av_cold void avcodec_register(AVCodec *codec)
> +{

This function, together with av_codec_next(), should be deprecated.
Just adding attribute_deprecated isn't enough. You also need to add
that FF_API_ ifdeffery soup (unfortunately).

> +#if CONFIG_ME_CMP
> +    pthread_once(&ff_me_cmp_static_init, ff_me_cmp_init_static);
> +#endif
> +
> +    pthread_once(&av_codec_next_init, av_codec_init_next);
> +    
> +    if (codec->init_static_data)
> +        codec->init_static_data(codec);
> +}

As I stated below, this stuff should go away. The me_cmp thing can
probably be (very carefully) be moved to codecs which need it. The
init_static_data thing will have to stay for a while, because wrappers
like libx264 modify a public field of AVCodec in it.

> +
> +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];
> +}
> +
> +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;
>  
> -#define REGISTER_ENCDEC(X, x) REGISTER_ENCODER(X, x); REGISTER_DECODER(X, x)
> +    id = remap_deprecated_codec_id(id);
>  
> -#define REGISTER_PARSER(X, x)                                           \
> -    {                                                                   \
> -        extern AVCodecParser ff_##x##_parser;                           \
> -        if (CONFIG_##X##_PARSER)                                        \
> -            av_register_codec_parser(&ff_##x##_parser);                 \
> +    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;
> +        }
>      }
>  
> -static void register_all(void)
> +    return (AVCodec*)experimental;
> +}
> +
> +AVCodec *avcodec_find_encoder(enum AVCodecID id)
>  {
> -    /* video codecs */
> -    REGISTER_ENCODER(A64MULTI,          a64multi);
> [...]
> +    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);
>  }
>  
>  void avcodec_register_all(void)
>  {
> -    static AVOnce control = AV_ONCE_INIT;
> +	const AVCodec *codec;
> +    void *i = 0;
>  
> -    ff_thread_once(&control, register_all);
> +#if CONFIG_ME_CMP
> +    pthread_once(&ff_me_cmp_static_init, ff_me_cmp_init_static);
> +#endif
> +
> +    pthread_once(&av_codec_next_init, av_codec_init_next);
> +
> +    while ((codec = av_codec_iterate(&i))) {
> +        if (codec->init_static_data)
> +        	codec->init_static_data((AVCodec*)codec);
> +    }
>  }

I think this function should be deprecated, and not be required to be
called. This requires init_static_data and the me_cmp thing to be moved
somewhere else. Also, init_static_data should somehow be synchronized
too.

> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index ce089b7..2300974 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -3979,10 +3979,22 @@ typedef struct AVCodecParameters {
>  } AVCodecParameters;
>  
>  /**
> + * Iterate over all registered codecs.
> + *
> + * @param opaque a pointer where libavcodec will store the iteration state. Must
> + *               point to NULL to start the iteration.
> + *
> + * @return the next registered codec or NULL when the iteration is
> + *         finished
> + */
> +const AVCodec *av_codec_iterate(void **opaque);
> +
> +/**
>   * If c is NULL, returns the first registered codec,
>   * if c is non-NULL, returns the next registered codec after c,
>   * or NULL if c is the last one.
>   */
> +attribute_deprecated
>  AVCodec *av_codec_next(const AVCodec *c);
>  
>  /**
> @@ -5120,8 +5132,21 @@ typedef struct AVCodecParser {
>      struct AVCodecParser *next;
>  } AVCodecParser;
>  
> +/**
> + * Iterate over all registered codec parsers.
> + *
> + * @param opaque a pointer where libavcodec will store the iteration state. Must
> + *               point to NULL to start the iteration.
> + *
> + * @return the next registered codec parser or NULL when the iteration is
> + *         finished
> + */
> +const AVCodecParser *av_parser_iterate(void **opaque);

Such additions need doc/APIchanges entries. Deprecations receive an
entry in that file too.

> +
> +attribute_deprecated
>  AVCodecParser *av_parser_next(const AVCodecParser *c);
>  
> +attribute_deprecated
>  void av_register_codec_parser(AVCodecParser *parser);
>  AVCodecParserContext *av_parser_init(int codec_id);
>  
> diff --git a/libavcodec/parser.c b/libavcodec/parser.c
> index 670680e..4e4c22d 100644
> --- a/libavcodec/parser.c
> +++ b/libavcodec/parser.c
> @@ -32,33 +32,103 @@
>  #include "internal.h"
>  #include "parser.h"
>  
> -static AVCodecParser *av_first_parser = NULL;
> +#include "pthread.h"
> +
> +/* Parsers */
> +extern AVCodecParser ff_aac_parser;
> +extern AVCodecParser ff_aac_latm_parser;
> +extern AVCodecParser ff_ac3_parser;
> +extern AVCodecParser ff_adx_parser;
> +extern AVCodecParser ff_bmp_parser;
> +extern AVCodecParser ff_cavsvideo_parser;
> +extern AVCodecParser ff_cook_parser;
> +extern AVCodecParser ff_dca_parser;
> +extern AVCodecParser ff_dirac_parser;
> +extern AVCodecParser ff_dnxhd_parser;
> +extern AVCodecParser ff_dpx_parser;
> +extern AVCodecParser ff_dvaudio_parser;
> +extern AVCodecParser ff_dvbsub_parser;
> +extern AVCodecParser ff_dvdsub_parser;
> +extern AVCodecParser ff_dvd_nav_parser;
> +extern AVCodecParser ff_flac_parser;
> +extern AVCodecParser ff_g729_parser;
> +extern AVCodecParser ff_gsm_parser;
> +extern AVCodecParser ff_h261_parser;
> +extern AVCodecParser ff_h263_parser;
> +extern AVCodecParser ff_h264_parser;
> +extern AVCodecParser ff_hevc_parser;
> +extern AVCodecParser ff_mjpeg_parser;
> +extern AVCodecParser ff_mlp_parser;
> +extern AVCodecParser ff_mpeg4video_parser;
> +extern AVCodecParser ff_mpegaudio_parser;
> +extern AVCodecParser ff_mpegvideo_parser;
> +extern AVCodecParser ff_opus_parser;
> +extern AVCodecParser ff_png_parser;
> +extern AVCodecParser ff_pnm_parser;
> +extern AVCodecParser ff_rv30_parser;
> +extern AVCodecParser ff_rv40_parser;
> +extern AVCodecParser ff_sipr_parser;
> +extern AVCodecParser ff_tak_parser;
> +extern AVCodecParser ff_vc1_parser;
> +extern AVCodecParser ff_vorbis_parser;
> +extern AVCodecParser ff_vp3_parser;
> +extern AVCodecParser ff_vp8_parser;
> +extern AVCodecParser ff_vp9_parser;
> +extern AVCodecParser ff_xma_parser;
> +
> +#include "parser_list.c"
> +
> +pthread_once_t av_parser_next_init = PTHREAD_ONCE_INIT;
> +
> +static void av_parser_init_next(void)
> +{
> +    AVCodecParser *prev = NULL, *p;
> +    int i = 0;
> +    while ((p = (AVCodecParser*)parser_list[i++])) {
> +        if (prev)
> +            prev->next = p;
> +        prev = p;
> +    }
> +    prev->next = NULL;
> +}
>  
>  AVCodecParser *av_parser_next(const AVCodecParser *p)
>  {
> +    pthread_once(&av_parser_next_init, av_parser_init_next);
> +
>      if (p)
>          return p->next;
>      else
> -        return av_first_parser;
> +        return (AVCodecParser*)parser_list[0];
> +}
> +
> +const AVCodecParser *av_parser_iterate(void **opaque)
> +{
> +    uintptr_t i = (uintptr_t)*opaque;
> +    const AVCodecParser *p = parser_list[i];
> +
> +    if (p)
> +        *opaque = (void*)(i + 1);
> +
> +    return p;
>  }
>  
>  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));
> +    pthread_once(&av_parser_next_init, av_parser_init_next);
>  }
>  
>  AVCodecParserContext *av_parser_init(int codec_id)
>  {
>      AVCodecParserContext *s = NULL;
> -    AVCodecParser *parser;
> +    const AVCodecParser *parser;
> +    void *i = 0;
>      int ret;
>  
>      if (codec_id == AV_CODEC_ID_NONE)
>          return NULL;
>  
> -    for (parser = av_first_parser; parser; parser = parser->next) {
> +    while ((parser = av_parser_iterate(&i))) {
>          if (parser->codec_ids[0] == codec_id ||
>              parser->codec_ids[1] == codec_id ||
>              parser->codec_ids[2] == codec_id ||
> @@ -72,7 +142,7 @@ found:
>      s = av_mallocz(sizeof(AVCodecParserContext));
>      if (!s)
>          goto err_out;
> -    s->parser = parser;
> +    s->parser = (AVCodecParser*)parser;
>      s->priv_data = av_mallocz(parser->priv_data_size);
>      if (!s->priv_data)
>          goto err_out;
> diff --git a/libavcodec/utils.c b/libavcodec/utils.c
> index 873f39f..ff1422e 100644
> --- a/libavcodec/utils.c
> +++ b/libavcodec/utils.c
> @@ -47,7 +47,6 @@
>  #include "decode.h"
>  #include "hwaccel.h"
>  #include "libavutil/opt.h"
> -#include "me_cmp.h"
>  #include "mpegvideo.h"
>  #include "thread.h"
>  #include "frame_thread_encoder.h"
> @@ -144,30 +143,6 @@ void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size)
>          memset(*p, 0, min_size + AV_INPUT_BUFFER_PADDING_SIZE);
>  }
>  
> -/* encoder management */
> -static AVCodec *first_avcodec = NULL;
> -static AVCodec **last_avcodec = &first_avcodec;
> -
> -AVCodec *av_codec_next(const AVCodec *c)
> -{
> -    if (c)
> -        return c->next;
> -    else
> -        return first_avcodec;
> -}
> -
> -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();
> -}
> -
>  int av_codec_is_encoder(const AVCodec *codec)
>  {
>      return codec && (codec->encode_sub || codec->encode2 ||codec->send_frame);
> @@ -178,21 +153,6 @@ int av_codec_is_decoder(const AVCodec *codec)
>      return codec && (codec->decode || codec->receive_frame);
>  }
>  
> -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);
> -}
> -
>  int ff_set_dimensions(AVCodecContext *s, int width, int height)
>  {
>      int ret = av_image_check_size2(width, height, s->max_pixels, AV_PIX_FMT_NONE, 0, s);
> @@ -1202,71 +1162,6 @@ FF_ENABLE_DEPRECATION_WARNINGS
>      return 0;
>  }
>  
> -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_encdec(enum AVCodecID id, int encoder)
> -{
> -    AVCodec *p, *experimental = NULL;
> -    p = first_avcodec;
> -    id= remap_deprecated_codec_id(id);
> -    while (p) {
> -        if ((encoder ? av_codec_is_encoder(p) : av_codec_is_decoder(p)) &&
> -            p->id == id) {
> -            if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {
> -                experimental = p;
> -            } else
> -                return p;
> -        }
> -        p = p->next;
> -    }
> -    return experimental;
> -}
> -
> -AVCodec *avcodec_find_encoder(enum AVCodecID id)
> -{
> -    return find_encdec(id, 1);
> -}
> -
> -AVCodec *avcodec_find_encoder_by_name(const char *name)
> -{
> -    AVCodec *p;
> -    if (!name)
> -        return NULL;
> -    p = first_avcodec;
> -    while (p) {
> -        if (av_codec_is_encoder(p) && strcmp(name, p->name) == 0)
> -            return p;
> -        p = p->next;
> -    }
> -    return NULL;
> -}
> -
> -AVCodec *avcodec_find_decoder(enum AVCodecID id)
> -{
> -    return find_encdec(id, 0);
> -}
> -
> -AVCodec *avcodec_find_decoder_by_name(const char *name)
> -{
> -    AVCodec *p;
> -    if (!name)
> -        return NULL;
> -    p = first_avcodec;
> -    while (p) {
> -        if (av_codec_is_decoder(p) && strcmp(name, p->name) == 0)
> -            return p;
> -        p = p->next;
> -    }
> -    return NULL;
> -}
> -
>  const char *avcodec_get_name(enum AVCodecID id)
>  {
>      const AVCodecDescriptor *cd;

I think it'd be slightly more readable if you did the move in a
separate patch before this one, but I'm not insisting on it.


More information about the ffmpeg-devel mailing list