mirror of
https://git.videolan.org/git/ffmpeg.git
synced 2024-09-03 06:53:23 +02:00
ffmpeg: select input file based on output time.
Filters can change the timings, so input files must not necessarily be read at the same rythm. This patch select the input file to read based on the timestamp at output instead of input. With complex filter graphs, finding the input for a given output is done by making a request and checking to what buffer source it has been forwarded.
This commit is contained in:
parent
f4451d2e75
commit
1cadab6023
96
ffmpeg.c
96
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;
|
||||
av_assert1(!ist->discard);
|
||||
return !no_packet[ist->file_index] &&
|
||||
!input_files[ist->file_index]->eof_reached;
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_input_streams; i++) {
|
||||
InputStream *ist = input_streams[i];
|
||||
int64_t ipts = ist->pts;
|
||||
static int find_graph_input(FilterGraph *graph, uint8_t *no_packet)
|
||||
{
|
||||
int i, nb_req_max = 0, file_index = -1;
|
||||
|
||||
if (ist->discard || no_packet[ist->file_index])
|
||||
continue;
|
||||
if (!input_files[ist->file_index]->eof_reached) {
|
||||
if (ipts < ipts_min) {
|
||||
ipts_min = ipts;
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user