avconv: Add loop option.

Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
Alexandra Hájková
2015-10-09 22:11:56 +02:00
committed by Anton Khirnov
parent 11c5f438ff
commit 16b0c92962
4 changed files with 121 additions and 5 deletions

107
avconv.c
View File

@@ -1185,6 +1185,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
decoded_frame->pts = av_rescale_q(decoded_frame->pts,
ist->st->time_base,
(AVRational){1, avctx->sample_rate});
ist->nb_samples = decoded_frame->nb_samples;
for (i = 0; i < ist->nb_filters; i++) {
if (i < ist->nb_filters - 1) {
f = ist->filter_frame;
@@ -1323,7 +1324,7 @@ static int send_filter_eof(InputStream *ist)
}
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static void process_input_packet(InputStream *ist, const AVPacket *pkt)
static void process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
{
int i;
int got_output;
@@ -1402,7 +1403,8 @@ static void process_input_packet(InputStream *ist, const AVPacket *pkt)
}
/* after flushing, send an EOF on all the filter inputs attached to the stream */
if (!pkt && ist->decoding_needed) {
/* except when looping we need to flush but not to send an EOF */
if (!pkt && ist->decoding_needed && !no_eof) {
int ret = send_filter_eof(ist);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
@@ -2270,6 +2272,86 @@ static void reset_eagain(void)
input_files[i]->eagain = 0;
}
// set duration to max(tmp, duration) in a proper time base and return duration's time_base
static AVRational duration_max(int64_t tmp, int64_t *duration, AVRational tmp_time_base,
AVRational time_base)
{
int ret;
if (!*duration) {
*duration = tmp;
return tmp_time_base;
}
ret = av_compare_ts(*duration, time_base, tmp, tmp_time_base);
if (ret < 0) {
*duration = tmp;
return tmp_time_base;
}
return time_base;
}
static int seek_to_start(InputFile *ifile, AVFormatContext *is)
{
InputStream *ist;
AVCodecContext *avctx;
int i, ret, has_audio = 0;
int64_t duration = 0;
ret = av_seek_frame(is, -1, is->start_time, 0);
if (ret < 0)
return ret;
for (i = 0; i < ifile->nb_streams; i++) {
ist = input_streams[ifile->ist_index + i];
avctx = ist->dec_ctx;
// flush decoders
if (ist->decoding_needed) {
process_input_packet(ist, NULL, 1);
avcodec_flush_buffers(avctx);
}
/* duration is the length of the last frame in a stream
* when audio stream is present we don't care about
* last video frame length because it's not defined exactly */
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && ist->nb_samples)
has_audio = 1;
}
for (i = 0; i < ifile->nb_streams; i++) {
ist = input_streams[ifile->ist_index + i];
avctx = ist->dec_ctx;
if (has_audio) {
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && ist->nb_samples) {
AVRational sample_rate = {1, avctx->sample_rate};
duration = av_rescale_q(ist->nb_samples, sample_rate, ist->st->time_base);
} else
continue;
} else {
if (ist->framerate.num) {
duration = av_rescale_q(1, ist->framerate, ist->st->time_base);
} else if (ist->st->avg_frame_rate.num) {
duration = av_rescale_q(1, ist->st->avg_frame_rate, ist->st->time_base);
} else duration = 1;
}
if (!ifile->duration)
ifile->time_base = ist->st->time_base;
/* the total duration of the stream, max_pts - min_pts is
* the duration of the stream without the last frame */
duration += ist->max_pts - ist->min_pts;
ifile->time_base = duration_max(duration, &ifile->duration, ist->st->time_base,
ifile->time_base);
}
ifile->loop--;
return ret;
}
/*
* Read one packet from an input file and send it for
* - decoding -> lavfi (audio/video)
@@ -2289,6 +2371,7 @@ static int process_input(void)
InputStream *ist;
AVPacket pkt;
int ret, i, j;
int64_t duration;
/* select the stream that we must read now */
ifile = select_input_file();
@@ -2310,6 +2393,11 @@ static int process_input(void)
ifile->eagain = 1;
return ret;
}
if ((ret < 0) && (ifile->loop > 1)) {
if ((ret = seek_to_start(ifile, is)) < 0)
return ret;
ret = get_input_packet(ifile, &pkt);
}
if (ret < 0) {
if (ret != AVERROR_EOF) {
print_error(is->filename, ret);
@@ -2321,7 +2409,7 @@ static int process_input(void)
for (i = 0; i < ifile->nb_streams; i++) {
ist = input_streams[ifile->ist_index + i];
if (ist->decoding_needed)
process_input_packet(ist, NULL);
process_input_packet(ist, NULL, 0);
/* mark all outputs that don't go through lavfi as finished */
for (j = 0; j < nb_output_streams; j++) {
@@ -2400,8 +2488,17 @@ static int process_input(void)
pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
}
}
duration = av_rescale_q(ifile->duration, ifile->time_base, ist->st->time_base);
if (pkt.pts != AV_NOPTS_VALUE) {
pkt.pts += duration;
ist->max_pts = FFMAX(pkt.pts, ist->max_pts);
ist->min_pts = FFMIN(pkt.pts, ist->min_pts);
}
process_input_packet(ist, &pkt);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts += duration;
process_input_packet(ist, &pkt, 0);
discard_packet:
av_free_packet(&pkt);
@@ -2472,7 +2569,7 @@ static int transcode(void)
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
process_input_packet(ist, NULL);
process_input_packet(ist, NULL, 0);
}
}
poll_filters();