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

Nicolas George george at nsup.org
Thu Apr 6 13:27:43 EEST 2017


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);
             }
-- 
2.11.0



More information about the ffmpeg-devel mailing list