[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