[FFmpeg-devel] [PATCH] ffmpeg_opt: remove the stats metadata added by mkvmerge.

wm4 nfxjfg at googlemail.com
Thu Apr 6 14:01:21 EEST 2017


On Thu,  6 Apr 2017 12:27:43 +0200
Nicolas George <george at nsup.org> wrote:

> They are probably not valid for the resulting file.
> They look like this:
>       BPS             : 40665
>       BPS-eng         : 40665
>       DURATION        : 00:00:20.000000000
>       DURATION-eng    : 00:00:20.000000000
>       NUMBER_OF_FRAMES: 10
>       NUMBER_OF_FRAMES-eng: 10
>       NUMBER_OF_BYTES : 101664
>       NUMBER_OF_BYTES-eng: 101664
>       _STATISTICS_WRITING_APP: mkvmerge v9.8.0 ('Kuglblids') 64bit
>       _STATISTICS_WRITING_APP-eng: mkvmerge v9.8.0 ('Kuglblids') 64bit
>       _STATISTICS_WRITING_DATE_UTC: 2017-04-06 08:22:08
>       _STATISTICS_WRITING_DATE_UTC-eng: 2017-04-06 08:22:08
>       _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
>       _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
> 
> Signed-off-by: Nicolas George <george at nsup.org>
> ---
>  ffmpeg_opt.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 48 insertions(+), 1 deletion(-)
> 
> 
> Note: as written in a comment, this code ignores the return value of
> av_dict_set(), because the surrounding code ignores the return value of
> av_dict_copy(). A lot of unchecked errors happen in this function, but I am
> not reworking a 2700-lines function today.
> 
> 
> diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
> index d1fe8742ff..f72f38796a 100644
> --- a/ffmpeg_opt.c
> +++ b/ffmpeg_opt.c
> @@ -497,6 +497,53 @@ static void parse_meta_type(char *arg, char *type, int *index, const char **stre
>          *type = 'g';
>  }
>  
> +/**
> + * Copy a dictionary except the stats metadata added by mkvmerge.
> + * They are probably not valid for the resulting file.
> + *
> + * FIXME Return values are ignored by the surrounding code and here.
> + */
> +static void dict_copy_nostats(AVDictionary **dst, const AVDictionary *src)
> +{
> +    AVDictionaryEntry *t;
> +    const char *tags = NULL, *p, *q;
> +    size_t len;
> +
> +    t = av_dict_get(src, "_STATISTICS_TAGS", NULL, AV_DICT_MATCH_CASE);
> +    if (t)
> +        tags = t->value;
> +    t = NULL;
> +    while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX))) {
> +        if (av_strstart(t->key, "_STATISTICS_", NULL))
> +            continue;
> +        if (tags) {
> +            /* tags is a space-separated list of stats tags */
> +            p = tags;
> +            while (*p) {
> +                q = strchr(p, ' ');
> +                len = q ? q - p : strlen(p);
> +                if (!q)
> +                    q = p + strlen(p);
> +#define ff_islower(c) ((unsigned)((c) - 'a') < 26)
> +                if (!memcmp(t->key, p, len) &&
> +                    (!t->key[len] ||
> +                     /* also remove TAG-lng */
> +                     (t->key[len] == '-' &&
> +                      ff_islower(t->key[len + 1]) &&
> +                      ff_islower(t->key[len + 2]) &&
> +                      ff_islower(t->key[len + 3]) &&
> +                      !t->key[len + 4])))
> +                    break;
> +#undef ff_islower
> +                for (p += len; *p == ' '; p++);
> +            }
> +            if (*p) /* match found => do not copy */
> +                continue;
> +        }
> +        av_dict_set(dst, t->key, t->value, AV_DICT_DONT_OVERWRITE);
> +    }
> +}
> +
>  static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
>  {
>      AVDictionary **meta_in = NULL;
> @@ -2546,7 +2593,7 @@ loop_end:
>              if (output_streams[i]->source_index < 0)         /* this is true e.g. for attached files */
>                  continue;
>              ist = input_streams[output_streams[i]->source_index];
> -            av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
> +            dict_copy_nostats(&output_streams[i]->st->metadata, ist->st->metadata);
>              if (!output_streams[i]->stream_copy) {
>                  av_dict_set(&output_streams[i]->st->metadata, "encoder", NULL, 0);
>              }

I sure love format-specific hacks in ffmpeg CLI!

I don't think this patch is acceptable.

I went on trying to find out how Matroska readers are supposed to
handle this:

<wm4> mosu: what's the correct way to discard _STATISTICS tags if you want only "actual" tags the user added?
<wm4> matching by name doesn't work, because there are many names to be considered and they don't all start with _ or _STATISTICS
<mosu> You mean in the context of programs other than mkvmerge?
<wm4> yes
<mosu> mkvmerge adds one tag called _STATISTICS_TAGS which includes the a space-separated list of names of "normal" tags it has added. Additionally it adds _STATISTICS_WRITING_APP and _STATISTICS_WRITING_DATE.
<wm4> that's... painful
<mosu> There's nothing in the specs about this, though; it's a convention created by/invented for mkvmerge

So that's what you have to implement in the demuxer.


More information about the ffmpeg-devel mailing list