Revision 1829e195

View differences:

doc/ffmpeg-doc.texi
586 586
Just enumerate the input streams in the order you want them in the output.
587 587
@var{sync_stream_id} if specified sets the input stream to sync
588 588
against.
589
@item -map_meta_data @var{outfile}:@var{infile}
589
@item -map_meta_data @var{outfile}[,@var{metadata}]:@var{infile}[,@var{metadata}]
590 590
Set meta data information of @var{outfile} from @var{infile}. Note that those
591 591
are file indices (zero-based), not filenames.
592
Optional @var{metadata} parameters specify, which metadata to copy - (g)lobal
593
(i.e. metadata that applies to the whole file), per-(s)tream, per-(c)hapter or
594
per-(p)rogram. All metadata specifiers other than global must be followed by the
595
stream/chapter/program number. If metadata specifier is omitted, it defaults to
596
global.
597
For example to copy metadata from the first stream of the input file to global metadata
598
of the output file:
599
@example
600
ffmpeg -i in.ogg -map_meta_data 0:0,s0 out.mp3
601
@end example
592 602
@item -debug
593 603
Print specific debug info.
594 604
@item -benchmark
ffmpeg.c
97 97
 * select an input file for an output file
98 98
 */
99 99
typedef struct AVMetaDataMap {
100
    int out_file;
101
    int in_file;
100
    int  file;      //< file index
101
    char type;      //< type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram
102
    int  index;     //< stream/chapter/program number
102 103
} AVMetaDataMap;
103 104

  
104 105
static const OptionDef options[];
......
125 126
static AVStreamMap *stream_maps = NULL;
126 127
static int nb_stream_maps;
127 128

  
128
static AVMetaDataMap *meta_data_maps = NULL;
129
/* first item specifies output metadata, second is input */
130
static AVMetaDataMap (*meta_data_maps)[2] = NULL;
129 131
static int nb_meta_data_maps;
130 132

  
131 133
/* indexed by output file stream index */
......
2326 2328

  
2327 2329
    /* set meta data information from input file if required */
2328 2330
    for (i=0;i<nb_meta_data_maps;i++) {
2329
        AVFormatContext *out_file;
2330
        AVFormatContext *in_file;
2331
        AVFormatContext *files[2];
2332
        AVMetadata      **meta[2];
2331 2333
        AVMetadataTag *mtag;
2334
        int j;
2332 2335

  
2333
        int out_file_index = meta_data_maps[i].out_file;
2334
        int in_file_index = meta_data_maps[i].in_file;
2335
        if (out_file_index < 0 || out_file_index >= nb_output_files) {
2336
            snprintf(error, sizeof(error), "Invalid output file index %d map_meta_data(%d,%d)",
2337
                     out_file_index, out_file_index, in_file_index);
2338
            ret = AVERROR(EINVAL);
2339
            goto dump_format;
2340
        }
2341
        if (in_file_index < 0 || in_file_index >= nb_input_files) {
2342
            snprintf(error, sizeof(error), "Invalid input file index %d map_meta_data(%d,%d)",
2343
                     in_file_index, out_file_index, in_file_index);
2344
            ret = AVERROR(EINVAL);
2345
            goto dump_format;
2336
#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
2337
        if ((index) < 0 || (index) >= (nb_elems)) {\
2338
            snprintf(error, sizeof(error), "Invalid %s index %d while processing metadata maps\n",\
2339
                     (desc), (index));\
2340
            ret = AVERROR(EINVAL);\
2341
            goto dump_format;\
2346 2342
        }
2347 2343

  
2348
        out_file = output_files[out_file_index];
2349
        in_file = input_files[in_file_index];
2344
        int out_file_index = meta_data_maps[i][0].file;
2345
        int in_file_index = meta_data_maps[i][1].file;
2346
        METADATA_CHECK_INDEX(out_file_index, nb_output_files, "output file")
2347
        METADATA_CHECK_INDEX(in_file_index, nb_input_files, "input file")
2350 2348

  
2349
        files[0] = output_files[out_file_index];
2350
        files[1] = input_files[in_file_index];
2351

  
2352
        for (j = 0; j < 2; j++) {
2353
            AVMetaDataMap *map = &meta_data_maps[i][j];
2354

  
2355
            switch (map->type) {
2356
            case 'g':
2357
                meta[j] = &files[j]->metadata;
2358
                break;
2359
            case 's':
2360
                METADATA_CHECK_INDEX(map->index, files[j]->nb_streams, "stream")
2361
                meta[j] = &files[j]->streams[map->index]->metadata;
2362
                break;
2363
            case 'c':
2364
                METADATA_CHECK_INDEX(map->index, files[j]->nb_chapters, "chapter")
2365
                meta[j] = &files[j]->chapters[map->index]->metadata;
2366
                break;
2367
            case 'p':
2368
                METADATA_CHECK_INDEX(map->index, files[j]->nb_programs, "program")
2369
                meta[j] = &files[j]->programs[map->index]->metadata;
2370
                break;
2371
            }
2372
        }
2351 2373

  
2352 2374
        mtag=NULL;
2353
        while((mtag=av_metadata_get(in_file->metadata, "", mtag, AV_METADATA_IGNORE_SUFFIX)))
2354
            av_metadata_set2(&out_file->metadata, mtag->key, mtag->value, AV_METADATA_DONT_OVERWRITE);
2375
        while((mtag=av_metadata_get(*meta[1], "", mtag, AV_METADATA_IGNORE_SUFFIX)))
2376
            av_metadata_set2(meta[0], mtag->key, mtag->value, AV_METADATA_DONT_OVERWRITE);
2355 2377
    }
2356 2378

  
2357 2379
    /* copy chapters from the first input file that has them*/
......
2890 2912
    }
2891 2913
}
2892 2914

  
2915
static void parse_meta_type(const char *arg, char *type, int *index, char **endptr)
2916
{
2917
    *endptr = arg;
2918
    if (*arg == ',') {
2919
        *type = *(++arg);
2920
        switch (*arg) {
2921
        case 'g':
2922
            break;
2923
        case 's':
2924
        case 'c':
2925
        case 'p':
2926
            *index = strtol(++arg, endptr, 0);
2927
            break;
2928
        default:
2929
            fprintf(stderr, "Invalid metadata type %c.\n", *arg);
2930
            ffmpeg_exit(1);
2931
        }
2932
    } else
2933
        *type = 'g';
2934
}
2935

  
2893 2936
static void opt_map_meta_data(const char *arg)
2894 2937
{
2895
    AVMetaDataMap *m;
2938
    AVMetaDataMap *m, *m1;
2896 2939
    char *p;
2897 2940

  
2898 2941
    meta_data_maps = grow_array(meta_data_maps, sizeof(*meta_data_maps),
2899 2942
                                &nb_meta_data_maps, nb_meta_data_maps + 1);
2900 2943

  
2901
    m = &meta_data_maps[nb_meta_data_maps - 1];
2902
    m->out_file = strtol(arg, &p, 0);
2944
    m = &meta_data_maps[nb_meta_data_maps - 1][0];
2945
    m->file = strtol(arg, &p, 0);
2946
    parse_meta_type(p, &m->type, &m->index, &p);
2903 2947
    if (*p)
2904 2948
        p++;
2905 2949

  
2906
    m->in_file = strtol(p, &p, 0);
2950
    m1 = &meta_data_maps[nb_meta_data_maps - 1][1];
2951
    m1->file = strtol(p, &p, 0);
2952
    parse_meta_type(p, &m1->type, &m1->index, &p);
2907 2953
}
2908 2954

  
2909 2955
static void opt_input_ts_scale(const char *arg)
......
4038 4084
    { "i", HAS_ARG, {(void*)opt_input_file}, "input file name", "filename" },
4039 4085
    { "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" },
4040 4086
    { "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file:stream[:syncfile:syncstream]" },
4041
    { "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "set meta data information of outfile from infile", "outfile:infile" },
4087
    { "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "set meta data information of outfile from infile", "outfile[,metadata]:infile[,metadata]" },
4042 4088
    { "t", OPT_FUNC2 | HAS_ARG, {(void*)opt_recording_time}, "record or transcode \"duration\" seconds of audio/video", "duration" },
4043 4089
    { "fs", HAS_ARG | OPT_INT64, {(void*)&limit_filesize}, "set the limit file size in bytes", "limit_size" }, //
4044 4090
    { "ss", OPT_FUNC2 | HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" },

Also available in: Unified diff