1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-11-23 21:54:53 +02:00

fftools/ffmpeg_mux_init: allow creating streams from filtergraphs created out of stream groups

Several formats are being designed where more than one independent video or
audio stream within a container are part of what should be a single combined
output. This is the case for HEIF (Defining a grid where the decoded output
of several separate video streams are to be placed to generate a single output
image) and IAMF (Defining audio streams where channels are present in separate
coded stream).

AVStreamGroup was designed and implemented in libavformat to convey this
information, but the actual merging is left to the caller.
This change allows the FFmpeg CLI to take said information, parse it, and
create filtergraphs to merge the streams, making the combined output be usable
automatically further in the process.

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer
2025-10-18 21:02:21 -03:00
parent 99ec0752d7
commit c751ad2c36
2 changed files with 48 additions and 0 deletions

View File

@@ -1598,6 +1598,7 @@ fail:
static int map_auto_video(Muxer *mux, const OptionsContext *o)
{
AVFormatContext *oc = mux->fc;
InputStreamGroup *best_istg = NULL;
InputStream *best_ist = NULL;
int64_t best_score = 0;
int qcr;
@@ -1609,8 +1610,35 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
for (int j = 0; j < nb_input_files; j++) {
InputFile *ifile = input_files[j];
InputStreamGroup *file_best_istg = NULL;
InputStream *file_best_ist = NULL;
int64_t file_best_score = 0;
for (int i = 0; i < ifile->nb_stream_groups; i++) {
InputStreamGroup *istg = ifile->stream_groups[i];
int64_t score = 0;
if (!istg->fg)
continue;
for (int j = 0; j < istg->stg->nb_streams; j++) {
AVStream *st = istg->stg->streams[j];
if (st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) {
score = 100000000;
break;
}
}
switch (istg->stg->type) {
default:
continue;
}
if (score > file_best_score) {
file_best_score = score;
file_best_istg = istg;
}
}
for (int i = 0; i < ifile->nb_streams; i++) {
InputStream *ist = ifile->streams[i];
int64_t score;
@@ -1630,6 +1658,15 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
continue;
file_best_score = score;
file_best_ist = ist;
file_best_istg = NULL;
}
}
if (file_best_istg) {
file_best_score -= 5000000*!!(file_best_istg->stg->disposition & AV_DISPOSITION_DEFAULT);
if (file_best_score > best_score) {
best_score = file_best_score;
best_istg = file_best_istg;
best_ist = NULL;
}
}
if (file_best_ist) {
@@ -1639,9 +1676,19 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
if (file_best_score > best_score) {
best_score = file_best_score;
best_ist = file_best_ist;
best_istg = NULL;
}
}
}
if (best_istg) {
FilterGraph *fg = best_istg->fg;
OutputFilter *ofilter = fg->outputs[0];
av_assert0(fg->nb_outputs == 1);
av_log(mux, AV_LOG_VERBOSE, "Creating output stream from stream group derived complex filtergraph %d.\n", fg->index);
return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, NULL, ofilter, NULL, NULL);
}
if (best_ist)
return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, best_ist, NULL, NULL, NULL);