Commit 9ccd9062 authored by Hendrik Leppkes's avatar Hendrik Leppkes

Merge commit '16b0c929'

* commit '16b0c929':
  avconv: Add loop option.
Merged-by: 's avatarHendrik Leppkes <h.leppkes@gmail.com>
parents b9947883 16b0c929
...@@ -253,6 +253,9 @@ Overwrite output files without asking. ...@@ -253,6 +253,9 @@ Overwrite output files without asking.
Do not overwrite output files, and exit immediately if a specified Do not overwrite output files, and exit immediately if a specified
output file already exists. output file already exists.
@item -loop @var{number} (@emph{input})
Set number of times input stream shall be looped.
@item -c[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream}) @item -c[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
@itemx -codec[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream}) @itemx -codec[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
Select an encoder (when used before an output file) or a decoder (when used Select an encoder (when used before an output file) or a decoder (when used
......
...@@ -2024,6 +2024,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output) ...@@ -2024,6 +2024,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts, decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts,
(AVRational){1, avctx->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last, (AVRational){1, avctx->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last,
(AVRational){1, avctx->sample_rate}); (AVRational){1, avctx->sample_rate});
ist->nb_samples = decoded_frame->nb_samples;
for (i = 0; i < ist->nb_filters; i++) { for (i = 0; i < ist->nb_filters; i++) {
if (i < ist->nb_filters - 1) { if (i < ist->nb_filters - 1) {
f = ist->filter_frame; f = ist->filter_frame;
...@@ -2261,7 +2262,7 @@ static int send_filter_eof(InputStream *ist) ...@@ -2261,7 +2262,7 @@ static int send_filter_eof(InputStream *ist)
} }
/* pkt = NULL means EOF (needed to flush decoder buffers) */ /* pkt = NULL means EOF (needed to flush decoder buffers) */
static int process_input_packet(InputStream *ist, const AVPacket *pkt) static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
{ {
int ret = 0, i; int ret = 0, i;
int got_output = 0; int got_output = 0;
...@@ -2370,7 +2371,8 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt) ...@@ -2370,7 +2371,8 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt)
} }
/* after flushing, send an EOF on all the filter inputs attached to the stream */ /* after flushing, send an EOF on all the filter inputs attached to the stream */
if (!pkt && ist->decoding_needed && !got_output) { /* except when looping we need to flush but not to send an EOF */
if (!pkt && ist->decoding_needed && !got_output && !no_eof) {
int ret = send_filter_eof(ist); int ret = send_filter_eof(ist);
if (ret < 0) { if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n"); av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
...@@ -3606,6 +3608,86 @@ static void reset_eagain(void) ...@@ -3606,6 +3608,86 @@ static void reset_eagain(void)
output_streams[i]->unavailable = 0; output_streams[i]->unavailable = 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;
}
/* /*
* Return * Return
* - 0 -- one packet was read and processed * - 0 -- one packet was read and processed
...@@ -3620,6 +3702,7 @@ static int process_input(int file_index) ...@@ -3620,6 +3702,7 @@ static int process_input(int file_index)
InputStream *ist; InputStream *ist;
AVPacket pkt; AVPacket pkt;
int ret, i, j; int ret, i, j;
int64_t duration;
is = ifile->ctx; is = ifile->ctx;
ret = get_input_packet(ifile, &pkt); ret = get_input_packet(ifile, &pkt);
...@@ -3628,6 +3711,11 @@ static int process_input(int file_index) ...@@ -3628,6 +3711,11 @@ static int process_input(int file_index)
ifile->eagain = 1; ifile->eagain = 1;
return ret; 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 < 0) {
if (ret != AVERROR_EOF) { if (ret != AVERROR_EOF) {
print_error(is->filename, ret); print_error(is->filename, ret);
...@@ -3638,7 +3726,7 @@ static int process_input(int file_index) ...@@ -3638,7 +3726,7 @@ static int process_input(int file_index)
for (i = 0; i < ifile->nb_streams; i++) { for (i = 0; i < ifile->nb_streams; i++) {
ist = input_streams[ifile->ist_index + i]; ist = input_streams[ifile->ist_index + i];
if (ist->decoding_needed) { if (ist->decoding_needed) {
ret = process_input_packet(ist, NULL); ret = process_input_packet(ist, NULL, 0);
if (ret>0) if (ret>0)
return 0; return 0;
} }
...@@ -3773,6 +3861,16 @@ static int process_input(int file_index) ...@@ -3773,6 +3861,16 @@ static int process_input(int file_index)
pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base); 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);
}
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts += duration;
if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO || if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) && ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
...@@ -3824,7 +3922,7 @@ static int process_input(int file_index) ...@@ -3824,7 +3922,7 @@ static int process_input(int file_index)
sub2video_heartbeat(ist, pkt.pts); sub2video_heartbeat(ist, pkt.pts);
process_input_packet(ist, &pkt); process_input_packet(ist, &pkt, 0);
discard_packet: discard_packet:
av_free_packet(&pkt); av_free_packet(&pkt);
...@@ -3989,7 +4087,7 @@ static int transcode(void) ...@@ -3989,7 +4087,7 @@ static int transcode(void)
for (i = 0; i < nb_input_streams; i++) { for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i]; ist = input_streams[i];
if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) { if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
process_input_packet(ist, NULL); process_input_packet(ist, NULL, 0);
} }
} }
flush_encoders(); flush_encoders();
......
...@@ -112,6 +112,7 @@ typedef struct OptionsContext { ...@@ -112,6 +112,7 @@ typedef struct OptionsContext {
/* input options */ /* input options */
int64_t input_ts_offset; int64_t input_ts_offset;
int loop;
int rate_emu; int rate_emu;
int accurate_seek; int accurate_seek;
int thread_queue_size; int thread_queue_size;
...@@ -272,6 +273,10 @@ typedef struct InputStream { ...@@ -272,6 +273,10 @@ typedef struct InputStream {
int wrap_correction_done; int wrap_correction_done;
int64_t filter_in_rescale_delta_last; int64_t filter_in_rescale_delta_last;
int64_t min_pts; /* pts with the smallest value in a current stream */
int64_t max_pts; /* pts with the higher value in a current stream */
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
double ts_scale; double ts_scale;
int saw_first_ts; int saw_first_ts;
...@@ -342,7 +347,12 @@ typedef struct InputFile { ...@@ -342,7 +347,12 @@ typedef struct InputFile {
int eof_reached; /* true if eof reached */ int eof_reached; /* true if eof reached */
int eagain; /* true if last read attempt returned EAGAIN */ int eagain; /* true if last read attempt returned EAGAIN */
int ist_index; /* index of first stream in input_streams */ int ist_index; /* index of first stream in input_streams */
int loop; /* set number of times input stream should be looped */
int64_t duration; /* actual duration of the longest stream in a file
at the moment when looping happens */
AVRational time_base; /* time base of the duration */
int64_t input_ts_offset; int64_t input_ts_offset;
int64_t ts_offset; int64_t ts_offset;
int64_t last_ts; int64_t last_ts;
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */ int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
......
...@@ -627,6 +627,9 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) ...@@ -627,6 +627,9 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
ist->file_index = nb_input_files; ist->file_index = nb_input_files;
ist->discard = 1; ist->discard = 1;
st->discard = AVDISCARD_ALL; st->discard = AVDISCARD_ALL;
ist->nb_samples = 0;
ist->min_pts = INT64_MAX;
ist->max_pts = INT64_MIN;
ist->ts_scale = 1.0; ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st); MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
...@@ -1005,6 +1008,9 @@ static int open_input_file(OptionsContext *o, const char *filename) ...@@ -1005,6 +1008,9 @@ static int open_input_file(OptionsContext *o, const char *filename)
f->nb_streams = ic->nb_streams; f->nb_streams = ic->nb_streams;
f->rate_emu = o->rate_emu; f->rate_emu = o->rate_emu;
f->accurate_seek = o->accurate_seek; f->accurate_seek = o->accurate_seek;
f->loop = o->loop;
f->duration = 0;
f->time_base = (AVRational){ 1, 1 };
#if HAVE_PTHREADS #if HAVE_PTHREADS
f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8; f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8;
#endif #endif
...@@ -3152,6 +3158,8 @@ const OptionDef options[] = { ...@@ -3152,6 +3158,8 @@ const OptionDef options[] = {
{ "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC | { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) }, OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) },
"extract an attachment into a file", "filename" }, "extract an attachment into a file", "filename" },
{ "loop", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_INPUT |
OPT_OFFSET, { .off = OFFSET(loop) }, "set number of times input stream shall be looped", "loop count" },
{ "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts }, { "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts },
"print timestamp debugging info" }, "print timestamp debugging info" },
{ "max_error_rate", HAS_ARG | OPT_FLOAT, { &max_error_rate }, { "max_error_rate", HAS_ARG | OPT_FLOAT, { &max_error_rate },
......
File added
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment