summaryrefslogtreecommitdiff
path: root/fftools
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2021-11-12 17:22:57 +0100
committerAnton Khirnov <anton@khirnov.net>2021-11-16 10:51:32 +0100
commitbd55552d692254b53504357c6987eea976cff4f9 (patch)
tree5f32cb67ed83d8f37606d21339d727b1fcfa833e /fftools
parentd4ae2a20e8783a3658d47bae952ae681c6465a39 (diff)
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.c35
-rw-r--r--fftools/ffmpeg_opt.c72
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;
}