avconv: make -map_metadata work consistently with the other options
authorAnton Khirnov <anton@khirnov.net>
Fri, 29 Jul 2011 11:07:27 +0000 (13:07 +0200)
committerAnton Khirnov <anton@khirnov.net>
Fri, 12 Aug 2011 11:50:36 +0000 (13:50 +0200)
Before, it took an input and output file index, now it only takes an
input file and applies to the next output file.

Stream/chapter/program specification is now part of the option name and
the delimiter was changed from ',' to ':' to be consistent with the
similar feature for AVOptions.

avconv.c
doc/avconv.texi

index b72b26d..f5ca05a 100644 (file)
--- a/avconv.c
+++ b/avconv.c
@@ -2091,10 +2091,6 @@ static int transcode(AVFormatContext **output_files,
         codec = ost->st->codec;
         icodec = ist->st->codec;
 
-        if (metadata_streams_autocopy)
-            av_dict_copy(&ost->st->metadata, ist->st->metadata,
-                         AV_DICT_DONT_OVERWRITE);
-
         ost->st->disposition = ist->st->disposition;
         codec->bits_per_raw_sample= icodec->bits_per_raw_sample;
         codec->chroma_sample_location = icodec->chroma_sample_location;
@@ -2399,63 +2395,6 @@ static int transcode(AVFormatContext **output_files,
         ist->is_start = 1;
     }
 
-    /* set meta data information from input file if required */
-    for (i=0;i<nb_meta_data_maps;i++) {
-        AVFormatContext *files[2];
-        AVDictionary    **meta[2];
-        int j;
-
-#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
-        if ((index) < 0 || (index) >= (nb_elems)) {\
-            snprintf(error, sizeof(error), "Invalid %s index %d while processing metadata maps\n",\
-                     (desc), (index));\
-            ret = AVERROR(EINVAL);\
-            goto dump_format;\
-        }
-
-        int out_file_index = meta_data_maps[i][0].file;
-        int in_file_index = meta_data_maps[i][1].file;
-        if (in_file_index < 0 || out_file_index < 0)
-            continue;
-        METADATA_CHECK_INDEX(out_file_index, nb_output_files, "output file")
-        METADATA_CHECK_INDEX(in_file_index, nb_input_files, "input file")
-
-        files[0] = output_files[out_file_index];
-        files[1] = input_files[in_file_index].ctx;
-
-        for (j = 0; j < 2; j++) {
-            MetadataMap *map = &meta_data_maps[i][j];
-
-            switch (map->type) {
-            case 'g':
-                meta[j] = &files[j]->metadata;
-                break;
-            case 's':
-                METADATA_CHECK_INDEX(map->index, files[j]->nb_streams, "stream")
-                meta[j] = &files[j]->streams[map->index]->metadata;
-                break;
-            case 'c':
-                METADATA_CHECK_INDEX(map->index, files[j]->nb_chapters, "chapter")
-                meta[j] = &files[j]->chapters[map->index]->metadata;
-                break;
-            case 'p':
-                METADATA_CHECK_INDEX(map->index, files[j]->nb_programs, "program")
-                meta[j] = &files[j]->programs[map->index]->metadata;
-                break;
-            }
-        }
-
-        av_dict_copy(meta[0], *meta[1], AV_DICT_DONT_OVERWRITE);
-    }
-
-    /* copy global metadata by default */
-    if (metadata_global_autocopy) {
-
-        for (i = 0; i < nb_output_files; i++)
-            av_dict_copy(&output_files[i]->metadata, input_files[0].ctx->metadata,
-                         AV_DICT_DONT_OVERWRITE);
-    }
-
     /* open files and write file headers */
     for(i=0;i<nb_output_files;i++) {
         os = output_files[i];
@@ -2963,10 +2902,9 @@ static int opt_map(const char *opt, const char *arg)
     return 0;
 }
 
-static void parse_meta_type(char *arg, char *type, int *index, char **endptr)
+static void parse_meta_type(char *arg, char *type, int *index)
 {
-    *endptr = arg;
-    if (*arg == ',') {
+    if (*arg == ':') {
         *type = *(++arg);
         switch (*arg) {
         case 'g':
@@ -2974,7 +2912,8 @@ static void parse_meta_type(char *arg, char *type, int *index, char **endptr)
         case 's':
         case 'c':
         case 'p':
-            *index = strtol(++arg, endptr, 0);
+            if (*(++arg) == ':')
+                *index = strtol(++arg, NULL, 0);
             break;
         default:
             fprintf(stderr, "Invalid metadata type %c.\n", *arg);
@@ -2992,15 +2931,15 @@ static int opt_map_metadata(const char *opt, const char *arg)
     meta_data_maps = grow_array(meta_data_maps, sizeof(*meta_data_maps),
                                 &nb_meta_data_maps, nb_meta_data_maps + 1);
 
-    m = &meta_data_maps[nb_meta_data_maps - 1][0];
+    m = &meta_data_maps[nb_meta_data_maps - 1][1];
     m->file = strtol(arg, &p, 0);
-    parse_meta_type(p, &m->type, &m->index, &p);
-    if (*p)
-        p++;
+    parse_meta_type(p, &m->type, &m->index);
 
-    m1 = &meta_data_maps[nb_meta_data_maps - 1][1];
-    m1->file = strtol(p, &p, 0);
-    parse_meta_type(p, &m1->type, &m1->index, &p);
+    m1 = &meta_data_maps[nb_meta_data_maps - 1][0];
+    if (p = strchr(opt, ':'))
+        parse_meta_type(p, &m1->type, &m1->index);
+    else
+        m1->type = 'g';
 
     if (m->type == 'g' || m1->type == 'g')
         metadata_global_autocopy = 0;
@@ -3777,6 +3716,62 @@ static void opt_output_file(const char *filename)
     if (chapters_input_file >= 0)
         copy_chapters(chapters_input_file, nb_output_files - 1);
 
+    /* copy metadata */
+    for (i = 0; i < nb_meta_data_maps; i++) {
+        AVFormatContext *files[2];
+        AVDictionary    **meta[2];
+        int j;
+
+#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
+        if ((index) < 0 || (index) >= (nb_elems)) {\
+            av_log(NULL, AV_LOG_ERROR, "Invalid %s index %d while processing metadata maps\n",\
+                     (desc), (index));\
+            exit_program(1);\
+        }
+
+        int in_file_index = meta_data_maps[i][1].file;
+        if (in_file_index < 0)
+            continue;
+        METADATA_CHECK_INDEX(in_file_index, nb_input_files, "input file")
+
+        files[0] = oc;
+        files[1] = input_files[in_file_index].ctx;
+
+        for (j = 0; j < 2; j++) {
+            MetadataMap *map = &meta_data_maps[i][j];
+
+            switch (map->type) {
+            case 'g':
+                meta[j] = &files[j]->metadata;
+                break;
+            case 's':
+                METADATA_CHECK_INDEX(map->index, files[j]->nb_streams, "stream")
+                meta[j] = &files[j]->streams[map->index]->metadata;
+                break;
+            case 'c':
+                METADATA_CHECK_INDEX(map->index, files[j]->nb_chapters, "chapter")
+                meta[j] = &files[j]->chapters[map->index]->metadata;
+                break;
+            case 'p':
+                METADATA_CHECK_INDEX(map->index, files[j]->nb_programs, "program")
+                meta[j] = &files[j]->programs[map->index]->metadata;
+                break;
+            }
+        }
+
+        av_dict_copy(meta[0], *meta[1], AV_DICT_DONT_OVERWRITE);
+    }
+
+    /* copy global metadata by default */
+    if (metadata_global_autocopy)
+        av_dict_copy(&oc->metadata, input_files[0].ctx->metadata,
+                     AV_DICT_DONT_OVERWRITE);
+    if (metadata_streams_autocopy)
+        for (i = 0; i < oc->nb_streams; i++) {
+            InputStream *ist = &input_streams[output_streams_for_file[nb_output_files-1][i]->source_index];
+            av_dict_copy(&oc->streams[i]->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
+        }
+
     frame_rate    = (AVRational){0, 0};
     frame_width   = 0;
     frame_height  = 0;
@@ -3785,6 +3780,12 @@ static void opt_output_file(const char *filename)
     audio_sample_fmt  = AV_SAMPLE_FMT_NONE;
     chapters_input_file = INT_MAX;
 
+    av_freep(&meta_data_maps);
+    nb_meta_data_maps = 0;
+    metadata_global_autocopy   = 1;
+    metadata_streams_autocopy  = 1;
+    metadata_chapters_autocopy = 1;
+
     av_freep(&forced_key_frames);
     uninit_opts();
     init_opts();
index 32808fd..ab1df09 100644 (file)
@@ -677,16 +677,16 @@ avconv -i a.mov -i b.mov -vcodec copy -acodec copy out.mov -map 0.2 -map 1.6
 To add more streams to the output file, you can use the
 @code{-newaudio}, @code{-newvideo}, @code{-newsubtitle} options.
 
-@item -map_metadata @var{outfile}[,@var{metadata}]:@var{infile}[,@var{metadata}]
-Set metadata information of @var{outfile} from @var{infile}. Note that those
-are file indices (zero-based), not filenames.
-Optional @var{metadata} parameters specify, which metadata to copy - (g)lobal
+@item -map_metadata[:@var{metadata_type}][:@var{index}] @var{infile}[:@var{metadata_type}][:@var{index}]
+Set metadata information of the next output file from @var{infile}. Note that
+those are file indices (zero-based), not filenames.
+Optional @var{metadata_type} parameters specify, which metadata to copy - (g)lobal
 (i.e. metadata that applies to the whole file), per-(s)tream, per-(c)hapter or
 per-(p)rogram. All metadata specifiers other than global must be followed by the
-stream/chapter/program number. If metadata specifier is omitted, it defaults to
+stream/chapter/program index. If metadata specifier is omitted, it defaults to
 global.
 
-By default, global metadata is copied from the first input file to all output files,
+By default, global metadata is copied from the first input file,
 per-stream and per-chapter metadata is copied along with streams/chapters. These
 default mappings are disabled by creating any mapping of the relevant type. A negative
 file index can be used to create a dummy mapping that just disables automatic copying.
@@ -694,7 +694,7 @@ file index can be used to create a dummy mapping that just disables automatic co
 For example to copy metadata from the first stream of the input file to global metadata
 of the output file:
 @example
-avconv -i in.ogg -map_metadata 0:0,s0 out.mp3
+avconv -i in.ogg -map_metadata 0:s:0 out.mp3
 @end example
 @item -map_chapters @var{input_file_index}
 Copy chapters from input file with index @var{input_file_index} to the next