diff --git a/ffmpeg.c b/ffmpeg.c index 93e3f04b63..7394e466d5 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -3337,20 +3337,23 @@ static int need_output(void) return 0; } -static int select_input_file(uint8_t *no_packet) +static int input_acceptable(InputStream *ist, uint8_t *no_packet) { - int64_t ipts_min = INT64_MAX; - int i, file_index = -1; - - for (i = 0; i < nb_input_streams; i++) { - InputStream *ist = input_streams[i]; - int64_t ipts = ist->pts; + av_assert1(!ist->discard); + return !no_packet[ist->file_index] && + !input_files[ist->file_index]->eof_reached; +} - if (ist->discard || no_packet[ist->file_index]) - continue; - if (!input_files[ist->file_index]->eof_reached) { - if (ipts < ipts_min) { - ipts_min = ipts; +static int find_graph_input(FilterGraph *graph, uint8_t *no_packet) +{ + int i, nb_req_max = 0, file_index = -1; + + for (i = 0; i < graph->nb_inputs; i++) { + int nb_req = av_buffersrc_get_nb_failed_requests(graph->inputs[i]->filter); + if (nb_req > nb_req_max) { + InputStream *ist = graph->inputs[i]->ist; + if (input_acceptable(ist, no_packet)) { + nb_req_max = nb_req; file_index = ist->file_index; } } @@ -3359,6 +3362,65 @@ static int select_input_file(uint8_t *no_packet) return file_index; } +/** + * Select the input file to read from. + * + * @param no_packet array of booleans, one per input file; + * if set, the input file must not be considered + * @param no_frame array of boolean, one per output stream; + * if set, the stream must not be considered; + * for internal use + * @return >=0 index of the input file to use; + * -1 if no file is acceptable; + * -2 to read from filters without reading from a file + */ +static int select_input_file(uint8_t *no_packet, uint8_t *no_frame) +{ + int i, ret, nb_active_out = nb_output_streams, ost_index = -1; + int64_t opts_min; + OutputStream *ost; + AVFilterBufferRef *dummy; + + memset(no_frame, 0, nb_output_streams); + while (nb_active_out) { + opts_min = INT64_MAX; + ost_index = -1; + for (i = 0; i < nb_output_streams; i++) { + OutputStream *ost = output_streams[i]; + int64_t opts = av_rescale_q(ost->st->cur_dts, ost->st->time_base, + AV_TIME_BASE_Q); + if (!no_frame[i] && !ost->is_past_recording_time && + opts < opts_min) { + opts_min = opts; + ost_index = i; + } + } + if (ost_index < 0) + return -1; + + ost = output_streams[ost_index]; + if (ost->source_index >= 0) { + /* ost is directly connected to an input */ + InputStream *ist = input_streams[ost->source_index]; + if (input_acceptable(ist, no_packet)) + return ist->file_index; + } else { + /* ost is connected to a complex filtergraph */ + av_assert1(ost->filter); + ret = av_buffersink_get_buffer_ref(ost->filter->filter, &dummy, + AV_BUFFERSINK_FLAG_PEEK); + if (ret >= 0) + return -2; + ret = find_graph_input(ost->filter->graph, no_packet); + if (ret >= 0) + return ret; + } + no_frame[ost_index] = 1; + nb_active_out--; + } + return -1; +} + static int check_keyboard_interaction(int64_t cur_time) { int i, ret, key; @@ -3580,12 +3642,13 @@ static int transcode(void) AVFormatContext *is, *os; OutputStream *ost; InputStream *ist; - uint8_t *no_packet; + uint8_t *no_packet, *no_frame; int no_packet_count = 0; int64_t timer_start; - if (!(no_packet = av_mallocz(nb_input_files))) + if (!(no_packet = av_mallocz(nb_input_files + nb_output_streams))) exit_program(1); + no_frame = no_packet + nb_input_files; ret = transcode_init(); if (ret < 0) @@ -3619,8 +3682,12 @@ static int transcode(void) } /* select the stream that we must read now */ - file_index = select_input_file(no_packet); + file_index = select_input_file(no_packet, no_frame); /* if none, if is finished */ + if (file_index == -2) { + poll_filters() ; + continue; + } if (file_index < 0) { if (no_packet_count) { no_packet_count = 0; @@ -3652,6 +3719,7 @@ static int transcode(void) ist = input_streams[input_files[file_index]->ist_index + i]; if (ist->decoding_needed) output_packet(ist, NULL); + poll_filters(); } if (opt_shortest)