diff options
author | Anton Khirnov <anton@khirnov.net> | 2021-11-12 17:22:57 +0100 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2021-11-16 10:51:32 +0100 |
commit | bd55552d692254b53504357c6987eea976cff4f9 (patch) | |
tree | 5f32cb67ed83d8f37606d21339d727b1fcfa833e /fftools | |
parent | d4ae2a20e8783a3658d47bae952ae681c6465a39 (diff) | |
download | ffmpeg-bd55552d692254b53504357c6987eea976cff4f9.tar.gz |
ffmpeg: rewrite setting the stream disposition
Currently, the code doing this is spread over several places and may
behave in unexpected ways. E.g. automatic 'default' marking is only done
for streams fed by complex filtergraphs. It is also applied in the order
in which the output streams are initialized, which is effectively
random.
Move processing the dispositions at the end of open_output_file(), when
we already have all the necessary information.
Apply the automatic default marking only if no explicit -disposition
options were supplied by the user, and apply it to the first stream of
each type (excluding attached pics) when there is more than one stream
of that type and no default markings were copied from the input streams.
Explicitly document the new behavior.
Changes the results of some tests, where the output file gets a default
disposition, while it previously did not.
Diffstat (limited to 'fftools')
-rw-r--r-- | fftools/ffmpeg.c | 35 | ||||
-rw-r--r-- | fftools/ffmpeg_opt.c | 72 |
2 files changed, 73 insertions, 34 deletions
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 65d6a2668d..7b2dcee838 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3168,9 +3168,6 @@ static int init_output_stream_streamcopy(OutputStream *ost) if (ost->st->duration <= 0 && ist->st->duration > 0) ost->st->duration = av_rescale_q(ist->st->duration, ist->st->time_base, ost->st->time_base); - // copy disposition - ost->st->disposition = ist->st->disposition; - if (ist->st->nb_side_data) { for (i = 0; i < ist->st->nb_side_data; i++) { const AVPacketSideData *sd_src = &ist->st->side_data[i]; @@ -3358,7 +3355,7 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) AVCodecContext *enc_ctx = ost->enc_ctx; AVCodecContext *dec_ctx = NULL; AVFormatContext *oc = output_files[ost->file_index]->ctx; - int j, ret; + int ret; set_encoder_id(output_files[ost->file_index], ost); @@ -3368,21 +3365,9 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) av_dict_set(&ost->st->metadata, "rotate", NULL, 0); if (ist) { - ost->st->disposition = ist->st->disposition; - dec_ctx = ist->dec_ctx; enc_ctx->chroma_sample_location = dec_ctx->chroma_sample_location; - } else { - for (j = 0; j < oc->nb_streams; j++) { - AVStream *st = oc->streams[j]; - if (st != ost->st && st->codecpar->codec_type == ost->st->codecpar->codec_type) - break; - } - if (j == oc->nb_streams) - if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || - ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - ost->st->disposition = AV_DISPOSITION_DEFAULT; } if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -3663,24 +3648,6 @@ static int init_output_stream(OutputStream *ost, AVFrame *frame, return ret; } - // parse user provided disposition, and update stream values - if (ost->disposition) { -#if LIBAVFORMAT_VERSION_MAJOR >= 60 - ret = av_opt_set(ost->st, "disposition", ost->disposition, 0); -#else - { - const AVClass *class = av_stream_get_class(); - const AVOption *o = av_opt_find(&class, "disposition", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ); - - av_assert0(o); - ret = av_opt_eval_flags(&class, o, ost->disposition, &ost->st->disposition); - } -#endif - - if (ret < 0) - return ret; - } - /* initialize bitstream filters for the output stream * needs to be done here, because the codec id for streamcopy is not * known until now */ diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index ab4c63a362..4685cf6435 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2150,6 +2150,72 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) return 0; } +static int set_dispositions(OutputFile *of) +{ + int nb_streams[AVMEDIA_TYPE_NB] = { 0 }; + int have_default[AVMEDIA_TYPE_NB] = { 0 }; + int have_manual = 0; + + // first, copy the input dispositions + for (int i = 0; i< of->ctx->nb_streams; i++) { + OutputStream *ost = output_streams[of->ost_index + i]; + + nb_streams[ost->st->codecpar->codec_type]++; + + have_manual |= !!ost->disposition; + + if (ost->source_index >= 0) { + ost->st->disposition = input_streams[ost->source_index]->st->disposition; + + if (ost->st->disposition & AV_DISPOSITION_DEFAULT) + have_default[ost->st->codecpar->codec_type] = 1; + } + } + + if (have_manual) { + // process manually set dispositions - they override the above copy + for (int i = 0; i< of->ctx->nb_streams; i++) { + OutputStream *ost = output_streams[of->ost_index + i]; + int ret; + + if (!ost->disposition) + continue; + +#if LIBAVFORMAT_VERSION_MAJOR >= 60 + ret = av_opt_set(ost->st, "disposition", ost->disposition, 0); +#else + { + const AVClass *class = av_stream_get_class(); + const AVOption *o = av_opt_find(&class, "disposition", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ); + + av_assert0(o); + ret = av_opt_eval_flags(&class, o, ost->disposition, &ost->st->disposition); + } +#endif + + if (ret < 0) + return ret; + } + } else { + // For each media type with more than one stream, find a suitable stream to + // mark as default, unless one is already marked default. + // "Suitable" means the first of that type, skipping attached pictures. + for (int i = 0; i< of->ctx->nb_streams; i++) { + OutputStream *ost = output_streams[of->ost_index + i]; + enum AVMediaType type = ost->st->codecpar->codec_type; + + if (nb_streams[type] < 2 || have_default[type] || + ost->st->disposition & AV_DISPOSITION_ATTACHED_PIC) + continue; + + ost->st->disposition |= AV_DISPOSITION_DEFAULT; + have_default[type] = 1; + } + } + + return 0; +} + static void init_output_filter(OutputFilter *ofilter, OptionsContext *o, AVFormatContext *oc) { @@ -2857,6 +2923,12 @@ loop_end: } } + err = set_dispositions(of); + if (err < 0) { + av_log(NULL, AV_LOG_FATAL, "Error setting output stream dispositions\n"); + exit_program(1); + } + return 0; } |