summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2022-08-22 14:53:40 +0200
committerThilo Borgmann <thilo.borgmann@mail.de>2023-03-30 23:48:36 +0200
commit6e9d6a1d501ff74ce10da4e0e9dcfd72976d662d (patch)
tree694f098103c90a4d201166fc939bae9508441f86
parent3980415627a187d188dc25669cea6b12912eb178 (diff)
encode -> decode WIP
-rw-r--r--fftools/ffmpeg.c170
-rw-r--r--fftools/ffmpeg.h15
-rw-r--r--fftools/ffmpeg_demux.c23
-rw-r--r--fftools/ffmpeg_filter.c58
-rw-r--r--fftools/ffmpeg_mux.c22
-rw-r--r--fftools/ffmpeg_opt.c53
6 files changed, 234 insertions, 107 deletions
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index d721a5e721..0d60ca1fe3 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -668,6 +668,8 @@ static void close_output_stream(OutputStream *ost)
if (ost->sq_idx_encode >= 0)
sq_send(of->sq_encode, ost->sq_idx_encode, SQFRAME(NULL));
+ if (ost->dec)
+ av_thread_message_queue_set_err_recv(ost->dec, AVERROR_EOF);
}
static int check_recording_time(OutputStream *ost, int64_t ts, AVRational tb)
@@ -1352,6 +1354,74 @@ static void do_video_out(OutputFile *of,
av_frame_move_ref(ost->last_frame, next_picture);
}
+static int ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par)
+{
+ int ret;
+
+ // We never got any input. Set a fake format, which will
+ // come from libavformat.
+ ifilter->format = par->format;
+ ifilter->sample_rate = par->sample_rate;
+ ifilter->width = par->width;
+ ifilter->height = par->height;
+ ifilter->sample_aspect_ratio = par->sample_aspect_ratio;
+ ret = av_channel_layout_copy(&ifilter->ch_layout, &par->ch_layout);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void flush_encoder(OutputStream *ost)
+{
+ AVCodecContext *enc = ost->enc_ctx;
+ OutputFile *of = output_files[ost->file_index];
+ int ret;
+
+
+ // Try to enable encoding with no input frames.
+ // Maybe we should just let encoding fail instead.
+ if (!ost->initialized) {
+ FilterGraph *fg = ost->filter->graph;
+
+ av_log(NULL, AV_LOG_WARNING,
+ "Finishing stream %d:%d without any data written to it.\n",
+ ost->file_index, ost->st->index);
+
+ if (ost->filter && !fg->graph) {
+ int x;
+ for (x = 0; x < fg->nb_inputs; x++) {
+ InputFilter *ifilter = fg->inputs[x];
+ if (ifilter->format < 0 &&
+ ifilter_parameters_from_codecpar(ifilter, ifilter->ist->par) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error copying paramerets from input stream\n");
+ exit_program(1);
+ }
+ }
+
+ if (!ifilter_has_all_input_formats(fg))
+ return;
+
+ ret = configure_filtergraph(fg);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error configuring filter graph\n");
+ exit_program(1);
+ }
+
+ of_output_packet(of, ost->pkt, ost, 1);
+ }
+
+ init_output_stream_wrapper(ost, NULL, 1);
+ }
+
+ if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO)
+ return;
+
+ ret = submit_encode_frame(of, ost, NULL);
+ if (ret != AVERROR_EOF)
+ exit_program(1);
+}
+
/**
* Get and encode new output from any of the filtergraphs, without causing
* activity.
@@ -1397,6 +1467,7 @@ static int reap_filters(int flush)
} else if (flush && ret == AVERROR_EOF) {
if (av_buffersink_get_type(filter) == AVMEDIA_TYPE_VIDEO)
do_video_out(of, ost, NULL);
+ flush_encoder(ost);
}
break;
}
@@ -1763,24 +1834,6 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
print_final_stats(total_size);
}
-static int ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par)
-{
- int ret;
-
- // We never got any input. Set a fake format, which will
- // come from libavformat.
- ifilter->format = par->format;
- ifilter->sample_rate = par->sample_rate;
- ifilter->width = par->width;
- ifilter->height = par->height;
- ifilter->sample_aspect_ratio = par->sample_aspect_ratio;
- ret = av_channel_layout_copy(&ifilter->ch_layout, &par->ch_layout);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
static void flush_encoders(void)
{
int ret;
@@ -1792,52 +1845,8 @@ static void flush_encoders(void)
}
for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
- AVCodecContext *enc = ost->enc_ctx;
- OutputFile *of = output_files[ost->file_index];
-
- if (!enc)
- continue;
-
- // Try to enable encoding with no input frames.
- // Maybe we should just let encoding fail instead.
- if (!ost->initialized) {
- FilterGraph *fg = ost->filter->graph;
-
- av_log(ost, AV_LOG_WARNING,
- "Finishing stream without any data written to it.\n");
-
- if (ost->filter && !fg->graph) {
- int x;
- for (x = 0; x < fg->nb_inputs; x++) {
- InputFilter *ifilter = fg->inputs[x];
- if (ifilter->format < 0 &&
- ifilter_parameters_from_codecpar(ifilter, ifilter->ist->par) < 0) {
- av_log(ost, AV_LOG_ERROR, "Error copying paramerets from input stream\n");
- exit_program(1);
- }
- }
-
- if (!ifilter_has_all_input_formats(fg))
- continue;
-
- ret = configure_filtergraph(fg);
- if (ret < 0) {
- av_log(ost, AV_LOG_ERROR, "Error configuring filter graph\n");
- exit_program(1);
- }
-
- of_output_packet(of, ost->pkt, ost, 1);
- }
-
- init_output_stream_wrapper(ost, NULL, 1);
- }
-
- if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO)
- continue;
-
- ret = submit_encode_frame(of, ost, NULL);
- if (ret != AVERROR_EOF)
- exit_program(1);
+ if (ost->enc_ctx)
+ flush_encoder(ost);
}
}
@@ -2130,6 +2139,8 @@ static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
av_assert1(ist->nb_filters > 0); /* ensure ret is initialized */
for (i = 0; i < ist->nb_filters; i++) {
+ //fprintf(stderr, "send frame to filters %d:%d %g\n", ist->file_index, ist->st->index,
+ // decoded_frame->pts * av_q2d(ist->st->time_base));
ret = ifilter_send_frame(ist->filters[i], decoded_frame, i < ist->nb_filters - 1);
if (ret == AVERROR_EOF)
ret = 0; /* ignore */
@@ -2216,6 +2227,8 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_
if (ist->dts != AV_NOPTS_VALUE)
dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
if (pkt) {
+ //fprintf(stderr, "decode %d:%d %g\n", ist->file_index, ist->st->index,
+ // pkt->pts * av_q2d(ist->st->time_base));
pkt->dts = dts; // ffmpeg.c probably shouldn't do this
}
@@ -3488,15 +3501,24 @@ static OutputStream *choose_output(void)
ost->initialized, ost->inputs_done, ost->finished);
}
- if (!ost->initialized && !ost->inputs_done)
- return ost->unavailable ? NULL : ost;
+ if (!ost->initialized && !ost->inputs_done) {
+ if (ost->unavailable)
+ break;
+ return ost;
+ }
if (!ost->finished && opts < opts_min) {
opts_min = opts;
ost_min = ost->unavailable ? NULL : ost;
}
}
- return ost_min;
+ if (ost_min)
+ return ost_min;
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ if (!ost->finished)
+ return ost;
+ }
+ return NULL;
}
static void set_tty_echo(int on)
@@ -3769,8 +3791,10 @@ static int process_input(int file_index)
is = ifile->ctx;
ret = ifile_get_packet(ifile, &pkt);
+ //fprintf(stderr, "get input packet %d: %d\n", file_index, ret);
if (ret == AVERROR(EAGAIN)) {
+ //fprintf(stderr, "eagain\n");
ifile->eagain = 1;
return ret;
}
@@ -3931,6 +3955,7 @@ static int transcode_step(void)
av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from, finishing.\n");
return AVERROR_EOF;
}
+ //fprintf(stderr, "choose output %d:%d\n", ost->file_index, ost->index);
if (ost->filter && !ost->filter->graph->graph) {
if (ifilter_has_all_input_formats(ost->filter->graph)) {
@@ -3969,8 +3994,10 @@ static int transcode_step(void)
if ((ret = transcode_from_filter(ost->filter->graph, &ist)) < 0)
return ret;
- if (!ist)
+ if (!ist) {
+ reset_eagain();
return 0;
+ }
} else if (ost->filter) {
int i;
for (i = 0; i < ost->filter->graph->nb_inputs; i++) {
@@ -3989,10 +4016,13 @@ static int transcode_step(void)
av_assert0(ist);
}
+ //fprintf(stderr, "process input %d\n", ist->file_index);
ret = process_input(ist->file_index);
if (ret == AVERROR(EAGAIN)) {
- if (input_files[ist->file_index]->eagain)
+ if (input_files[ist->file_index]->eagain) {
+ //fprintf(stderr, "unavailable %d:%d->%d:%d", ist->file_index, ist->st->index, ost->file_index, ost->index);
ost->unavailable = 1;
+ }
return 0;
}
@@ -4052,7 +4082,7 @@ static int transcode(void)
process_input_packet(ist, NULL, 0);
}
}
- flush_encoders();
+ //flush_encoders();
term_exit();
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index f1412f6446..53c055d273 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -81,6 +81,7 @@ typedef struct HWDevice {
/* select an input stream for an output stream */
typedef struct StreamMap {
int disabled; /* 1 is this mapping is disabled by a negative map */
+ int decoder;
int file_index;
int stream_index;
char *linklabel; /* name of an output link, for mapping lavfi outputs */
@@ -266,6 +267,8 @@ typedef struct OptionsContext {
int nb_enc_stats_post_fmt;
SpecifierOpt *mux_stats_fmt;
int nb_mux_stats_fmt;
+
+ int open_pass;
} OptionsContext;
typedef struct InputFilter {
@@ -447,6 +450,12 @@ typedef struct LastFrameDuration {
int64_t duration;
} LastFrameDuration;
+typedef struct Decoder {
+ AVThreadMessageQueue *fifo;
+ struct OutputFile *of;
+ struct OutputStream *ost;
+} Decoder;
+
typedef struct InputFile {
int index;
@@ -482,6 +491,8 @@ typedef struct InputFile {
* the last frame duration back to the demuxer thread */
AVThreadMessageQueue *audio_duration_queue;
int audio_duration_queue_size;
+
+ Decoder *dec;
} InputFile;
enum forced_keyframes_const {
@@ -687,6 +698,8 @@ typedef struct OutputStream {
* subtitles utilizing fix_sub_duration at random access points.
*/
unsigned int fix_sub_duration_heartbeat;
+
+ AVThreadMessageQueue *dec;
} OutputStream;
typedef struct OutputFile {
@@ -785,7 +798,7 @@ int configure_filtergraph(FilterGraph *fg);
void check_filter_outputs(void);
int filtergraph_is_simple(FilterGraph *fg);
int init_simple_filtergraph(InputStream *ist, OutputStream *ost);
-int init_complex_filtergraph(FilterGraph *fg);
+int init_complex_filtergraph(FilterGraph *fg, int pass);
void sub2video_update(InputStream *ist, int64_t heartbeat_pts, AVSubtitle *sub);
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index ffece60720..56ba0dd7c4 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -72,6 +72,8 @@ typedef struct Demuxer {
int non_blocking;
} Demuxer;
+//#include <sys/prctl.h>
+
typedef struct DemuxMsg {
AVPacket *pkt;
int looping;
@@ -241,6 +243,10 @@ static void *input_thread(void *arg)
AVPacket *pkt;
unsigned flags = d->non_blocking ? AV_THREAD_MESSAGE_NONBLOCK : 0;
int ret = 0;
+ char thread_name[16];
+
+ //snprintf(thread_name, sizeof(thread_name), "demux%d", f->index);
+ //prctl(PR_SET_NAME, (unsigned long)thread_name, 0, 0, 0);
pkt = av_packet_alloc();
if (!pkt) {
@@ -253,7 +259,19 @@ static void *input_thread(void *arg)
while (1) {
DemuxMsg msg = { NULL };
- ret = av_read_frame(f->ctx, pkt);
+ if (f->dec) {
+ AVPacket *pkt1;
+ ret = av_thread_message_queue_recv(f->dec->fifo, &pkt1, 0);
+ if (ret >= 0) {
+ av_packet_move_ref(pkt, pkt1);
+ av_packet_free(&pkt1);
+ pkt->flags |= AV_PKT_FLAG_TRUSTED;
+ pkt->stream_index = 0;
+ //fprintf(stderr, "dec received %ld\n", pkt->pts);
+ f->streams[f->index]->st->time_base = f->dec->ost->mux_timebase;
+ }
+ } else
+ ret = av_read_frame(f->ctx, pkt);
if (ret == AVERROR(EAGAIN)) {
av_usleep(10000);
@@ -372,6 +390,9 @@ static int thread_start(Demuxer *d)
(f->ctx->pb ? !f->ctx->pb->seekable :
strcmp(f->ctx->iformat->name, "lavfi")))
d->non_blocking = 1;
+ if (nb_input_files > 1 &&
+ f->dec)
+ d->non_blocking = 1;
ret = av_thread_message_queue_alloc(&d->in_thread_queue,
d->thread_queue_size, sizeof(DemuxMsg));
if (ret < 0)
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 1f5bbf6c4d..02ce6f8000 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -228,19 +228,10 @@ static char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)
return res;
}
-static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
+static InputStream *ifilter_get_ist(FilterGraph *fg, AVFilterInOut *in)
{
- InputStream *ist = NULL;
enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
- InputFilter *ifilter;
- int i;
-
- // TODO: support other filter types
- if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
- av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
- "currently.\n");
- exit_program(1);
- }
+ InputStream *ist;
if (in->name) {
AVFormatContext *s;
@@ -251,11 +242,11 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
if (file_idx < 0 || file_idx >= nb_input_files) {
av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
file_idx, fg->graph_desc);
- exit_program(1);
+ return NULL;
}
s = input_files[file_idx]->ctx;
- for (i = 0; i < s->nb_streams; i++) {
+ for (int i = 0; i < s->nb_streams; i++) {
enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type;
if (stream_type != type &&
!(stream_type == AVMEDIA_TYPE_SUBTITLE &&
@@ -278,6 +269,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
exit_program(1);
}
} else {
+ int i;
/* find the first unused stream of corresponding type */
for (ist = ist_iter(NULL); ist; ist = ist_iter(ist)) {
if (ist->user_set_discard == AVDISCARD_ALL)
@@ -292,6 +284,24 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
exit_program(1);
}
}
+
+ return ist;
+}
+
+static int init_input_filter(FilterGraph *fg, AVFilterInOut *in)
+{
+ InputStream *ist = NULL;
+ enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
+ InputFilter *ifilter;
+
+ // TODO: support other filter types
+ if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
+ av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
+ "currently.\n");
+ exit_program(1);
+ }
+
+ ist = ifilter_get_ist(fg, in);
av_assert0(ist);
ist->discard = 0;
@@ -312,6 +322,8 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
GROW_ARRAY(ist->filters, ist->nb_filters);
ist->filters[ist->nb_filters - 1] = ifilter;
+
+ return 0;
}
static int read_binary(const char *path, uint8_t **data, int *len)
@@ -464,12 +476,15 @@ fail:
return ret;
}
-int init_complex_filtergraph(FilterGraph *fg)
+int init_complex_filtergraph(FilterGraph *fg, int pass)
{
AVFilterInOut *inputs, *outputs, *cur;
AVFilterGraph *graph;
int ret = 0;
+ if (fg->nb_inputs || fg->nb_outputs)
+ return 0;
+
/* this graph is only used for determining the kinds of inputs
* and outputs we have, and is discarded on exit from this function */
graph = avfilter_graph_alloc();
@@ -481,8 +496,19 @@ int init_complex_filtergraph(FilterGraph *fg)
if (ret < 0)
goto fail;
- for (cur = inputs; cur; cur = cur->next)
- init_input_filter(fg, cur);
+ for (cur = inputs; cur; cur = cur->next) {
+ if (!ifilter_get_ist(fg, cur)) {
+ if (pass == 0)
+ return 0;
+ exit_program(1);
+ }
+ }
+
+ for (cur = inputs; cur; cur = cur->next) {
+ ret = init_input_filter(fg, cur);
+ if (ret < 0)
+ return ret;
+ }
for (cur = outputs; cur;) {
OutputFilter *const ofilter = ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);
diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
index cf58051949..5d433d5af4 100644
--- a/fftools/ffmpeg_mux.c
+++ b/fftools/ffmpeg_mux.c
@@ -26,6 +26,7 @@
#include "sync_queue.h"
#include "thread_queue.h"
+#include "libavutil/avassert.h"
#include "libavutil/fifo.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
@@ -38,6 +39,8 @@
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
+//#include <sys/prctl.h>
+
int want_sdp = 1;
static Muxer *mux_from_of(OutputFile *of)
@@ -201,6 +204,10 @@ static void *muxer_thread(void *arg)
OutputFile *of = &mux->of;
AVPacket *pkt = NULL;
int ret = 0;
+ //char thread_name[16];
+
+ //snprintf(thread_name, sizeof(thread_name), "mux%d", of->index);
+ //prctl(PR_SET_NAME, (unsigned long)thread_name, 0, 0, 0);
pkt = av_packet_alloc();
if (!pkt) {
@@ -222,6 +229,17 @@ static void *muxer_thread(void *arg)
}
ost = of->streams[stream_idx];
+
+ if (ost->dec) {
+ if (ret < 0) {
+ av_thread_message_queue_set_err_recv(ost->dec, AVERROR_EOF);
+ } else {
+ AVPacket *pkt1 = av_packet_clone(pkt);
+ ret = av_thread_message_queue_send(ost->dec, &pkt1, 0);
+ av_assert0(ret >= 0);
+ }
+ }
+
ret = sync_queue_process(mux, ost, ret < 0 ? NULL : pkt, &stream_eof);
av_packet_unref(pkt);
if (ret == AVERROR_EOF && stream_eof)
@@ -430,8 +448,8 @@ static int thread_start(Muxer *mux)
AVPacket *pkt;
/* try to improve muxing time_base (only possible if nothing has been written yet) */
- if (!av_fifo_can_read(ms->muxing_queue))
- ost->mux_timebase = ost->st->time_base;
+ //if (!av_fifo_can_read(ms->muxing_queue))
+ // ost->mux_timebase = ost->st->time_base;
while (av_fifo_read(ms->muxing_queue, &pkt, 1) >= 0) {
ret = thread_submit_packet(mux, ost, pkt);
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 055275d813..51f2fcaf31 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -394,6 +394,12 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
exit_program(1);
}
+ } else if (map[0] == 'd' && map[1] == ':') {
+ GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
+ m = &o->stream_maps[o->nb_stream_maps - 1];
+ m->decoder = 1;
+ m->file_index = strtol(map + 2, &p, 0);
+ m->stream_index = strtol(p + 1, &p, 0);
} else {
if (allow_unused = strchr(map, '?'))
*allow_unused = 0;
@@ -745,12 +751,12 @@ static int opt_streamid(void *optctx, const char *opt, const char *arg)
return 0;
}
-static int init_complex_filters(void)
+static int init_complex_filters(int pass)
{
int i, ret = 0;
for (i = 0; i < nb_filtergraphs; i++) {
- ret = init_complex_filtergraph(filtergraphs[i]);
+ ret = init_complex_filtergraph(filtergraphs[i], pass);
if (ret < 0)
return ret;
}
@@ -1213,15 +1219,17 @@ void show_usage(void)
enum OptGroup {
GROUP_OUTFILE,
GROUP_INFILE,
+ GROUP_DECODER,
};
static const OptionGroupDef groups[] = {
[GROUP_OUTFILE] = { "output url", NULL, OPT_OUTPUT },
[GROUP_INFILE] = { "input url", "i", OPT_INPUT },
+ [GROUP_DECODER] = { "decoding process", "dec", OPT_INPUT },
};
-static int open_files(OptionGroupList *l, const char *inout,
- int (*open_file)(const OptionsContext*, const char*))
+static int open_files(OptionGroupList *l, const char *inout, int pass,
+ int (*open_file)(OptionsContext*, const char*, int, int))
{
int i, ret;
@@ -1241,7 +1249,7 @@ static int open_files(OptionGroupList *l, const char *inout,
}
av_log(NULL, AV_LOG_DEBUG, "Opening an %s file: %s.\n", inout, g->arg);
- ret = open_file(&o, g->arg);
+ ret = open_file(&o, g->arg, pass, i);
uninit_options(&o);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error opening %s file %s.\n",
@@ -1280,24 +1288,34 @@ int ffmpeg_parse_options(int argc, char **argv)
term_init();
/* open input files */
- ret = open_files(&octx.groups[GROUP_INFILE], "input", ifile_open);
+ ret = open_files(&octx.groups[GROUP_INFILE], "input", 0, ifile_open);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");
goto fail;
}
- /* create the complex filtergraphs */
- ret = init_complex_filters();
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error initializing complex filters.\n");
- goto fail;
- }
+ apply_sync_offsets();
- /* open output files */
- ret = open_files(&octx.groups[GROUP_OUTFILE], "output", of_open);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
- goto fail;
+ for (int pass = 0; pass < 2; pass++) {
+ /* create the complex filtergraphs */
+ ret = init_complex_filters(pass);
+ if (ret < 0 && pass == 1) {
+ av_log(NULL, AV_LOG_FATAL, "Error initializing complex filters.\n");
+ goto fail;
+ }
+
+ /* open output files */
+ ret = open_files(&octx.groups[GROUP_OUTFILE], "output", pass, of_open);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
+ goto fail;
+ }
+
+ ret = open_files(&octx.groups[GROUP_DECODER], "decoder", pass, open_decoder);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error opening decoders: ");
+ goto fail;
+ }
}
correct_input_start_times();
@@ -1770,6 +1788,7 @@ const OptionDef options[] = {
"initialise hardware device", "args" },
{ "filter_hw_device", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_hw_device },
"set hardware device used when filtering", "device" },
+ { "open_pass", HAS_ARG | OPT_EXPERT | OPT_OUTPUT | OPT_INT | OPT_OFFSET, { .off = OFFSET(open_pass) } },
{ NULL, },
};