ffmpeg.c: extend map_meta_data to allow advanced mappings
i.e. to/from streams/chapters/programs. Originally committed as revision 25635 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
4f9d25ddc8
commit
1829e19528
@ -586,9 +586,19 @@ Set stream mapping from input streams to output streams.
|
||||
Just enumerate the input streams in the order you want them in the output.
|
||||
@var{sync_stream_id} if specified sets the input stream to sync
|
||||
against.
|
||||
@item -map_meta_data @var{outfile}:@var{infile}
|
||||
@item -map_meta_data @var{outfile}[,@var{metadata}]:@var{infile}[,@var{metadata}]
|
||||
Set meta data 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
|
||||
(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
|
||||
global.
|
||||
For example to copy metadata from the first stream of the input file to global metadata
|
||||
of the output file:
|
||||
@example
|
||||
ffmpeg -i in.ogg -map_meta_data 0:0,s0 out.mp3
|
||||
@end example
|
||||
@item -debug
|
||||
Print specific debug info.
|
||||
@item -benchmark
|
||||
|
100
ffmpeg.c
100
ffmpeg.c
@ -97,8 +97,9 @@ typedef struct AVStreamMap {
|
||||
* select an input file for an output file
|
||||
*/
|
||||
typedef struct AVMetaDataMap {
|
||||
int out_file;
|
||||
int in_file;
|
||||
int file; //< file index
|
||||
char type; //< type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram
|
||||
int index; //< stream/chapter/program number
|
||||
} AVMetaDataMap;
|
||||
|
||||
static const OptionDef options[];
|
||||
@ -125,7 +126,8 @@ static int nb_output_codecs = 0;
|
||||
static AVStreamMap *stream_maps = NULL;
|
||||
static int nb_stream_maps;
|
||||
|
||||
static AVMetaDataMap *meta_data_maps = NULL;
|
||||
/* first item specifies output metadata, second is input */
|
||||
static AVMetaDataMap (*meta_data_maps)[2] = NULL;
|
||||
static int nb_meta_data_maps;
|
||||
|
||||
/* indexed by output file stream index */
|
||||
@ -2326,32 +2328,52 @@ static int transcode(AVFormatContext **output_files,
|
||||
|
||||
/* set meta data information from input file if required */
|
||||
for (i=0;i<nb_meta_data_maps;i++) {
|
||||
AVFormatContext *out_file;
|
||||
AVFormatContext *in_file;
|
||||
AVFormatContext *files[2];
|
||||
AVMetadata **meta[2];
|
||||
AVMetadataTag *mtag;
|
||||
int j;
|
||||
|
||||
int out_file_index = meta_data_maps[i].out_file;
|
||||
int in_file_index = meta_data_maps[i].in_file;
|
||||
if (out_file_index < 0 || out_file_index >= nb_output_files) {
|
||||
snprintf(error, sizeof(error), "Invalid output file index %d map_meta_data(%d,%d)",
|
||||
out_file_index, out_file_index, in_file_index);
|
||||
ret = AVERROR(EINVAL);
|
||||
goto dump_format;
|
||||
}
|
||||
if (in_file_index < 0 || in_file_index >= nb_input_files) {
|
||||
snprintf(error, sizeof(error), "Invalid input file index %d map_meta_data(%d,%d)",
|
||||
in_file_index, out_file_index, in_file_index);
|
||||
ret = AVERROR(EINVAL);
|
||||
goto dump_format;
|
||||
#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;\
|
||||
}
|
||||
|
||||
out_file = output_files[out_file_index];
|
||||
in_file = input_files[in_file_index];
|
||||
int out_file_index = meta_data_maps[i][0].file;
|
||||
int in_file_index = meta_data_maps[i][1].file;
|
||||
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];
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
AVMetaDataMap *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;
|
||||
}
|
||||
}
|
||||
|
||||
mtag=NULL;
|
||||
while((mtag=av_metadata_get(in_file->metadata, "", mtag, AV_METADATA_IGNORE_SUFFIX)))
|
||||
av_metadata_set2(&out_file->metadata, mtag->key, mtag->value, AV_METADATA_DONT_OVERWRITE);
|
||||
while((mtag=av_metadata_get(*meta[1], "", mtag, AV_METADATA_IGNORE_SUFFIX)))
|
||||
av_metadata_set2(meta[0], mtag->key, mtag->value, AV_METADATA_DONT_OVERWRITE);
|
||||
}
|
||||
|
||||
/* copy chapters from the first input file that has them*/
|
||||
@ -2890,20 +2912,44 @@ static void opt_map(const char *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_meta_type(const char *arg, char *type, int *index, char **endptr)
|
||||
{
|
||||
*endptr = arg;
|
||||
if (*arg == ',') {
|
||||
*type = *(++arg);
|
||||
switch (*arg) {
|
||||
case 'g':
|
||||
break;
|
||||
case 's':
|
||||
case 'c':
|
||||
case 'p':
|
||||
*index = strtol(++arg, endptr, 0);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid metadata type %c.\n", *arg);
|
||||
ffmpeg_exit(1);
|
||||
}
|
||||
} else
|
||||
*type = 'g';
|
||||
}
|
||||
|
||||
static void opt_map_meta_data(const char *arg)
|
||||
{
|
||||
AVMetaDataMap *m;
|
||||
AVMetaDataMap *m, *m1;
|
||||
char *p;
|
||||
|
||||
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];
|
||||
m->out_file = strtol(arg, &p, 0);
|
||||
m = &meta_data_maps[nb_meta_data_maps - 1][0];
|
||||
m->file = strtol(arg, &p, 0);
|
||||
parse_meta_type(p, &m->type, &m->index, &p);
|
||||
if (*p)
|
||||
p++;
|
||||
|
||||
m->in_file = strtol(p, &p, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
static void opt_input_ts_scale(const char *arg)
|
||||
@ -4038,7 +4084,7 @@ static const OptionDef options[] = {
|
||||
{ "i", HAS_ARG, {(void*)opt_input_file}, "input file name", "filename" },
|
||||
{ "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" },
|
||||
{ "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file:stream[:syncfile:syncstream]" },
|
||||
{ "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "set meta data information of outfile from infile", "outfile:infile" },
|
||||
{ "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "set meta data information of outfile from infile", "outfile[,metadata]:infile[,metadata]" },
|
||||
{ "t", OPT_FUNC2 | HAS_ARG, {(void*)opt_recording_time}, "record or transcode \"duration\" seconds of audio/video", "duration" },
|
||||
{ "fs", HAS_ARG | OPT_INT64, {(void*)&limit_filesize}, "set the limit file size in bytes", "limit_size" }, //
|
||||
{ "ss", OPT_FUNC2 | HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" },
|
||||
|
Loading…
x
Reference in New Issue
Block a user