diff options
author | Anton Khirnov <anton@khirnov.net> | 2011-07-29 08:36:13 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2011-08-12 19:10:22 +0200 |
commit | 3d4f0dab79ccc8b1a662de440a789ec00b428963 (patch) | |
tree | d1dced445d0ac8ab89d212d2f443753ba2cce848 | |
parent | d4863fc1a83ceab1d75469b406a2c67e5659b2a0 (diff) | |
download | ffmpeg-3d4f0dab79ccc8b1a662de440a789ec00b428963.tar.gz |
avconv: get rid of new* options.
They are confusing, irregular and redundant -- -map already contains all
the information. Stream maps can now be parsed in opt_output_file().
Add a more user-friendly default behavior in case no maps are present.
Breaks -programid for now, but it never worked properly anyway. A better
solution will be written soon.
-rw-r--r-- | avconv.c | 311 | ||||
-rw-r--r-- | doc/avconv.texi | 59 |
2 files changed, 125 insertions, 245 deletions
@@ -464,7 +464,6 @@ static int exit_program(int ret) av_free(vstats_filename); av_free(streamid_map); - av_free(stream_maps); av_free(meta_data_maps); av_freep(&input_streams); @@ -1946,8 +1945,7 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost, static int transcode(AVFormatContext **output_files, int nb_output_files, InputFile *input_files, - int nb_input_files, - StreamMap *stream_maps, int nb_stream_maps) + int nb_input_files) { int ret = 0, i, j, k, n, nb_ostreams = 0; AVFormatContext *is, *os; @@ -1975,32 +1973,6 @@ static int transcode(AVFormatContext **output_files, } nb_ostreams += os->nb_streams; } - if (nb_stream_maps > 0 && nb_stream_maps != nb_ostreams) { - fprintf(stderr, "Number of stream maps must match number of output streams\n"); - ret = AVERROR(EINVAL); - goto fail; - } - - /* Sanity check the mapping args -- do the input files & streams exist? */ - for(i=0;i<nb_stream_maps;i++) { - int fi = stream_maps[i].file_index; - int si = stream_maps[i].stream_index; - - if (fi < 0 || fi > nb_input_files - 1 || - si < 0 || si > input_files[fi].ctx->nb_streams - 1) { - fprintf(stderr,"Could not find input stream #%d.%d\n", fi, si); - ret = AVERROR(EINVAL); - goto fail; - } - fi = stream_maps[i].sync_file_index; - si = stream_maps[i].sync_stream_index; - if (fi < 0 || fi > nb_input_files - 1 || - si < 0 || si > input_files[fi].ctx->nb_streams - 1) { - fprintf(stderr,"Could not find sync stream #%d.%d\n", fi, si); - ret = AVERROR(EINVAL); - goto fail; - } - } ost_table = av_mallocz(sizeof(OutputStream *) * nb_ostreams); if (!ost_table) @@ -2008,80 +1980,8 @@ static int transcode(AVFormatContext **output_files, n = 0; for(k=0;k<nb_output_files;k++) { os = output_files[k]; - for(i=0;i<os->nb_streams;i++,n++) { - int found; - ost = ost_table[n] = output_streams_for_file[k][i]; - if (nb_stream_maps > 0) { - ost->source_index = input_files[stream_maps[n].file_index].ist_index + - stream_maps[n].stream_index; - - /* Sanity check that the stream types match */ - if (input_streams[ost->source_index].st->codec->codec_type != ost->st->codec->codec_type) { - int i= ost->file_index; - av_dump_format(output_files[i], i, output_files[i]->filename, 1); - fprintf(stderr, "Codec type mismatch for mapping #%d.%d -> #%d.%d\n", - stream_maps[n].file_index, stream_maps[n].stream_index, - ost->file_index, ost->index); - exit_program(1); - } - - } else { - int best_nb_frames=-1; - /* get corresponding input stream index : we select the first one with the right type */ - found = 0; - for (j = 0; j < nb_input_streams; j++) { - int skip=0; - ist = &input_streams[j]; - if(opt_programid){ - int pi,si; - AVFormatContext *f = input_files[ist->file_index].ctx; - skip=1; - for(pi=0; pi<f->nb_programs; pi++){ - AVProgram *p= f->programs[pi]; - if(p->id == opt_programid) - for(si=0; si<p->nb_stream_indexes; si++){ - if(f->streams[ p->stream_index[si] ] == ist->st) - skip=0; - } - } - } - if (ist->discard && ist->st->discard != AVDISCARD_ALL && !skip && - ist->st->codec->codec_type == ost->st->codec->codec_type) { - if(best_nb_frames < ist->st->codec_info_nb_frames){ - best_nb_frames= ist->st->codec_info_nb_frames; - ost->source_index = j; - found = 1; - } - } - } - - if (!found) { - if(! opt_programid) { - /* try again and reuse existing stream */ - for (j = 0; j < nb_input_streams; j++) { - ist = &input_streams[j]; - if ( ist->st->codec->codec_type == ost->st->codec->codec_type - && ist->st->discard != AVDISCARD_ALL) { - ost->source_index = j; - found = 1; - } - } - } - if (!found) { - int i= ost->file_index; - av_dump_format(output_files[i], i, output_files[i]->filename, 1); - fprintf(stderr, "Could not find input stream matching output stream #%d.%d\n", - ost->file_index, ost->index); - exit_program(1); - } - } - } - ist = &input_streams[ost->source_index]; - ist->discard = 0; - ost->sync_ist = (nb_stream_maps > 0) ? - &input_streams[input_files[stream_maps[n].sync_file_index].ist_index + - stream_maps[n].sync_stream_index] : ist; - } + for (i = 0; i < os->nb_streams; i++, n++) + ost_table[n] = output_streams_for_file[k][i]; } /* for each output stream, we compute the right encoding parameters */ @@ -3221,50 +3121,7 @@ static int opt_input_file(const char *opt, const char *filename) return 0; } -static void check_inputs(int *has_video_ptr, - int *has_audio_ptr, - int *has_subtitle_ptr, - int *has_data_ptr) -{ - int has_video, has_audio, has_subtitle, has_data, i, j; - AVFormatContext *ic; - - has_video = 0; - has_audio = 0; - has_subtitle = 0; - has_data = 0; - - for(j=0;j<nb_input_files;j++) { - ic = input_files[j].ctx; - for(i=0;i<ic->nb_streams;i++) { - AVCodecContext *enc = ic->streams[i]->codec; - switch(enc->codec_type) { - case AVMEDIA_TYPE_AUDIO: - has_audio = 1; - break; - case AVMEDIA_TYPE_VIDEO: - has_video = 1; - break; - case AVMEDIA_TYPE_SUBTITLE: - has_subtitle = 1; - break; - case AVMEDIA_TYPE_DATA: - case AVMEDIA_TYPE_ATTACHMENT: - case AVMEDIA_TYPE_UNKNOWN: - has_data = 1; - break; - default: - abort(); - } - } - } - *has_video_ptr = has_video; - *has_audio_ptr = has_audio; - *has_subtitle_ptr = has_subtitle; - *has_data_ptr = has_data; -} - -static void new_video_stream(AVFormatContext *oc, int file_idx) +static OutputStream *new_video_stream(AVFormatContext *oc, int file_idx) { AVStream *st; OutputStream *ost; @@ -3393,9 +3250,10 @@ static void new_video_stream(AVFormatContext *oc, int file_idx) av_freep(&forced_key_frames); video_stream_copy = 0; frame_pix_fmt = PIX_FMT_NONE; + return ost; } -static void new_audio_stream(AVFormatContext *oc, int file_idx) +static OutputStream *new_audio_stream(AVFormatContext *oc, int file_idx) { AVStream *st; OutputStream *ost; @@ -3454,9 +3312,11 @@ static void new_audio_stream(AVFormatContext *oc, int file_idx) audio_disable = 0; av_freep(&audio_codec_name); audio_stream_copy = 0; + + return ost; } -static void new_data_stream(AVFormatContext *oc, int file_idx) +static OutputStream *new_data_stream(AVFormatContext *oc, int file_idx) { AVStream *st; OutputStream *ost; @@ -3485,9 +3345,10 @@ static void new_data_stream(AVFormatContext *oc, int file_idx) data_disable = 0; av_freep(&data_codec_name); data_stream_copy = 0; + return ost; } -static void new_subtitle_stream(AVFormatContext *oc, int file_idx) +static OutputStream *new_subtitle_stream(AVFormatContext *oc, int file_idx) { AVStream *st; OutputStream *ost; @@ -3533,24 +3394,7 @@ static void new_subtitle_stream(AVFormatContext *oc, int file_idx) subtitle_disable = 0; av_freep(&subtitle_codec_name); subtitle_stream_copy = 0; -} - -static int opt_new_stream(const char *opt, const char *arg) -{ - AVFormatContext *oc; - int file_idx = nb_output_files - 1; - if (nb_output_files <= 0) { - fprintf(stderr, "At least one output file must be specified\n"); - exit_program(1); - } - oc = output_files[file_idx]; - - if (!strcmp(opt, "newvideo" )) new_video_stream (oc, file_idx); - else if (!strcmp(opt, "newaudio" )) new_audio_stream (oc, file_idx); - else if (!strcmp(opt, "newsubtitle")) new_subtitle_stream(oc, file_idx); - else if (!strcmp(opt, "newdata" )) new_data_stream (oc, file_idx); - else av_assert0(0); - return 0; + return ost; } /* arg format is "output-stream-index:streamid-value". */ @@ -3578,9 +3422,10 @@ static int opt_streamid(const char *opt, const char *arg) static void opt_output_file(const char *filename) { AVFormatContext *oc; - int i, err, use_video, use_audio, use_subtitle, use_data; - int input_has_video, input_has_audio, input_has_subtitle, input_has_data; + int i, err; AVOutputFormat *file_oformat; + OutputStream *ost; + InputStream *ist; if (!strcmp(filename, "-")) filename = "pipe:"; @@ -3619,42 +3464,94 @@ static void opt_output_file(const char *filename) print_error(filename, err); exit_program(1); } + } else if (!nb_stream_maps) { + /* pick the "best" stream of each type */ +#define NEW_STREAM(type, index)\ + if (index >= 0) {\ + ost = new_ ## type ## _stream(oc, nb_output_files);\ + ost->source_index = index;\ + ost->sync_ist = &input_streams[index];\ + input_streams[index].discard = 0;\ + } + + /* video: highest resolution */ + if (!video_disable && oc->oformat->video_codec != CODEC_ID_NONE) { + int area = 0, idx = -1; + for (i = 0; i < nb_input_streams; i++) { + ist = &input_streams[i]; + if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && + ist->st->codec->width * ist->st->codec->height > area) { + area = ist->st->codec->width * ist->st->codec->height; + idx = i; + } + } + NEW_STREAM(video, idx); + } + + /* audio: most channels */ + if (!audio_disable && oc->oformat->audio_codec != CODEC_ID_NONE) { + int channels = 0, idx = -1; + for (i = 0; i < nb_input_streams; i++) { + ist = &input_streams[i]; + if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && + ist->st->codec->channels > channels) { + channels = ist->st->codec->channels; + idx = i; + } + } + NEW_STREAM(audio, idx); + } + + /* subtitles: pick first */ + if (!subtitle_disable && oc->oformat->subtitle_codec != CODEC_ID_NONE) { + for (i = 0; i < nb_input_streams; i++) + if (input_streams[i].st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + NEW_STREAM(subtitle, i); + break; + } + } + /* do something with data? */ } else { - use_video = file_oformat->video_codec != CODEC_ID_NONE || video_stream_copy || video_codec_name; - use_audio = file_oformat->audio_codec != CODEC_ID_NONE || audio_stream_copy || audio_codec_name; - use_subtitle = file_oformat->subtitle_codec != CODEC_ID_NONE || subtitle_stream_copy || subtitle_codec_name; - use_data = data_stream_copy || data_codec_name; /* XXX once generic data codec will be available add a ->data_codec reference and use it here */ - - /* disable if no corresponding type found */ - check_inputs(&input_has_video, - &input_has_audio, - &input_has_subtitle, - &input_has_data); - - if (!input_has_video) - use_video = 0; - if (!input_has_audio) - use_audio = 0; - if (!input_has_subtitle) - use_subtitle = 0; - if (!input_has_data) - use_data = 0; - - /* manual disable */ - if (audio_disable) use_audio = 0; - if (video_disable) use_video = 0; - if (subtitle_disable) use_subtitle = 0; - if (data_disable) use_data = 0; - - if (use_video) new_video_stream(oc, nb_output_files); - if (use_audio) new_audio_stream(oc, nb_output_files); - if (use_subtitle) new_subtitle_stream(oc, nb_output_files); - if (use_data) new_data_stream(oc, nb_output_files); - - av_dict_copy(&oc->metadata, metadata, 0); - av_dict_free(&metadata); + for (i = 0; i < nb_stream_maps; i++) { + StreamMap *map = &stream_maps[i]; + int fi = map->file_index; + int si = map->stream_index; + + if (fi < 0 || fi >= nb_input_files || + si < 0 || si >= input_files[fi].ctx->nb_streams) { + av_log(NULL, AV_LOG_ERROR, "Input stream #%d.%d does not exist.\n", fi, si); + exit_program(1); + } + fi = map->sync_file_index; + si = map->sync_stream_index; + if (fi < 0 || fi >= nb_input_files || + si < 0 || si >= input_files[fi].ctx->nb_streams) { + av_log(NULL, AV_LOG_ERROR, "Sync stream #%d.%d does not exist.\n", fi, si); + exit_program(1); + } + + ist = &input_streams[input_files[map->file_index].ist_index + map->stream_index]; + switch (ist->st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(oc, nb_output_files); break; + case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(oc, nb_output_files); break; + case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(oc, nb_output_files); break; + case AVMEDIA_TYPE_DATA: ost = new_data_stream(oc, nb_output_files); break; + default: + av_log(NULL, AV_LOG_ERROR, "Cannot map stream #%d.%d - unsupported type.\n", + map->file_index, map->stream_index); + exit_program(1); + } + + ost->source_index = input_files[map->file_index].ist_index + map->stream_index; + ost->sync_ist = &input_streams[input_files[map->sync_file_index].ist_index + + map->sync_stream_index]; + ist->discard = 0; + } } + av_dict_copy(&oc->metadata, metadata, 0); + av_dict_free(&metadata); + av_dict_copy(&output_opts[nb_output_files], format_opts, 0); output_files[nb_output_files++] = oc; @@ -3787,6 +3684,8 @@ static void opt_output_file(const char *filename) metadata_global_autocopy = 1; metadata_streams_autocopy = 1; metadata_chapters_autocopy = 1; + av_freep(&stream_maps); + nb_stream_maps = 0; av_freep(&forced_key_frames); uninit_opts(); @@ -4241,7 +4140,6 @@ static const OptionDef options[] = { { "top", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_top_field_first}, "top=1/bottom=0/auto=-1 field first", "" }, { "dc", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)&intra_dc_precision}, "intra_dc_precision", "precision" }, { "vtag", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_codec_tag}, "force video tag/fourcc", "fourcc/tag" }, - { "newvideo", OPT_VIDEO, {(void*)opt_new_stream}, "add a new video stream to the current output stream" }, { "vlang", HAS_ARG | OPT_STRING | OPT_VIDEO, {(void *)&video_language}, "set the ISO 639 language code (3 letters) of the current video stream" , "code" }, { "qphist", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, { (void *)&qp_hist }, "show QP histogram" }, { "force_fps", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&force_fps}, "force the selected framerate, disable the best supported framerate selection" }, @@ -4257,14 +4155,12 @@ static const OptionDef options[] = { { "acodec", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" }, { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO, {(void*)opt_codec_tag}, "force audio tag/fourcc", "fourcc/tag" }, { "vol", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&audio_volume}, "change audio volume (256=normal)" , "volume" }, // - { "newaudio", OPT_AUDIO, {(void*)opt_new_stream}, "add a new audio stream to the current output stream" }, { "alang", HAS_ARG | OPT_STRING | OPT_AUDIO, {(void *)&audio_language}, "set the ISO 639 language code (3 letters) of the current audio stream" , "code" }, { "sample_fmt", HAS_ARG | OPT_EXPERT | OPT_AUDIO, {(void*)opt_audio_sample_fmt}, "set sample format, 'list' as argument shows all the sample formats supported", "format" }, /* subtitle options */ { "sn", OPT_BOOL | OPT_SUBTITLE, {(void*)&subtitle_disable}, "disable subtitle" }, { "scodec", HAS_ARG | OPT_SUBTITLE, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" }, - { "newsubtitle", OPT_SUBTITLE, {(void*)opt_new_stream}, "add a new subtitle stream to the current output stream" }, { "slang", HAS_ARG | OPT_STRING | OPT_SUBTITLE, {(void *)&subtitle_language}, "set the ISO 639 language code (3 letters) of the current subtitle stream" , "code" }, { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE, {(void*)opt_codec_tag}, "force subtitle tag/fourcc", "fourcc/tag" }, @@ -4332,8 +4228,7 @@ int main(int argc, char **argv) } ti = getutime(); - if (transcode(output_files, nb_output_files, input_files, nb_input_files, - stream_maps, nb_stream_maps) < 0) + if (transcode(output_files, nb_output_files, input_files, nb_input_files) < 0) exit_program(1); ti = getutime() - ti; if (do_benchmark) { diff --git a/doc/avconv.texi b/doc/avconv.texi index ab1df09fb3..d325b1d14f 100644 --- a/doc/avconv.texi +++ b/doc/avconv.texi @@ -65,6 +65,20 @@ specified for the inputs. @c man end DESCRIPTION +@chapter Stream selection +@c man begin STREAM SELECTION + +By default av tries to pick the "best" stream of each type present in input +files and add them to each output file. For video, this means the highest +resolution, for audio the highest channel count. For subtitle it's simply the +first subtitle stream. + +You can disable some of those defaults by using @code{-vn/-an/-sn} options. For +full manual control, use the @code{-map} option, which disables the defaults just +described. + +@c man end STREAM SELECTION + @chapter Options @c man begin OPTIONS @@ -148,9 +162,6 @@ Set the number of data frames to record. @item -scodec @var{codec} Force subtitle codec ('copy' to copy stream). -@item -newsubtitle -Add a new subtitle stream to the current output stream. - @item -slang @var{code} Set the ISO 639 language code (3 letters) of the current subtitle stream. @@ -295,9 +306,6 @@ prefix is ``av2pass''. The complete file name will be @file{PREFIX-N.log}, where N is a number specific to the output stream. -@item -newvideo -Add a new video stream to the current output stream. - @item -vlang @var{code} Set the ISO 639 language code (3 letters) of the current video stream. @@ -565,18 +573,6 @@ Disable audio recording. @item -acodec @var{codec} Force audio codec to @var{codec}. Use the @code{copy} special value to specify that the raw codec data must be copied as is. -@item -newaudio -Add a new audio track to the output file. If you want to specify parameters, -do so before @code{-newaudio} (@code{-acodec}, @code{-ab}, etc..). - -Mapping will be done automatically, if the number of output streams is equal to -the number of input streams, else it will pick the first one that matches. You -can override the mapping using @code{-map} as usual. - -Example: -@example -avconv -i file.mpg -vcodec copy -acodec ac3 -ab 384k test.mpg -acodec mp2 -ab 192k -newaudio -@end example @item -alang @var{code} Set the ISO 639 language code (3 letters) of the current audio stream. @end table @@ -617,8 +613,6 @@ Bitstream filters available are "dump_extra", "remove_extra", "noise", "mp3comp" @table @option @item -scodec @var{codec} Force subtitle codec ('copy' to copy stream). -@item -newsubtitle -Add a new subtitle stream to the current output stream. @item -slang @var{code} Set the ISO 639 language code (3 letters) of the current subtitle stream. @item -sn @@ -649,19 +643,16 @@ file. Both indexes start at 0. If specified, @var{sync_file_id}.@var{sync_stream_id} sets which input stream is used as a presentation sync reference. -The @code{-map} options must be specified just after the output file. -If any @code{-map} options are used, the number of @code{-map} options -on the command line must match the number of streams in the output -file. The first @code{-map} option on the command line specifies the +The first @code{-map} option on the command line specifies the source for output stream 0, the second @code{-map} option specifies the source for output stream 1, etc. For example, if you have two audio streams in the first input file, these streams are identified by "0.0" and "0.1". You can use -@code{-map} to select which stream to place in an output file. For +@code{-map} to select which streams to place in an output file. For example: @example -avconv -i INPUT out.wav -map 0.1 +avconv -i INPUT -map 0.1 out.wav @end example will map the input stream in @file{INPUT} identified by "0.1" to the (single) output stream in @file{out.wav}. @@ -671,11 +662,10 @@ For example, to select the stream with index 2 from input file index 6 from input @file{b.mov} (specified by the identifier "1.6"), and copy them to the output file @file{out.mov}: @example -avconv -i a.mov -i b.mov -vcodec copy -acodec copy out.mov -map 0.2 -map 1.6 +avconv -i a.mov -i b.mov -vcodec copy -acodec copy -map 0.2 -map 1.6 out.mov @end example -To add more streams to the output file, you can use the -@code{-newaudio}, @code{-newvideo}, @code{-newsubtitle} options. +Note that using this option disables the default mappings for this output file. @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 @@ -1008,16 +998,11 @@ only formats accepting a normal integer are suitable. You can put many streams of the same type in the output: @example -avconv -i test1.avi -i test2.avi -vcodec copy -acodec copy -vcodec copy -acodec copy test12.avi -newvideo -newaudio +avconv -i test1.avi -i test2.avi -map 0.3 -map 0.2 -map 0.1 -map 0.0 -vcodec copy -acodec copy -vcodec copy -acodec copy test12.nut @end example -In addition to the first video and audio streams, the resulting -output file @file{test12.avi} will contain the second video -and the second audio stream found in the input streams list. - -The @code{-newvideo}, @code{-newaudio} and @code{-newsubtitle} -options have to be specified immediately after the name of the output -file to which you want to add them. +The resulting output file @file{test12.avi} will contain first four streams from +the input file in reverse order. @end itemize @c man end EXAMPLES |