Skip to content

Instantly share code, notes, and snippets.

@sasshka
Last active August 29, 2015 14:00
Show Gist options
  • Save sasshka/11168994 to your computer and use it in GitHub Desktop.
Save sasshka/11168994 to your computer and use it in GitHub Desktop.
commit e329bfbb3c38e803b16c3ef9015f4a65b0d05987
Author: Alexandra Khirnova <[email protected]>
Date: Fri Apr 11 11:17:38 2014 +0200
avconv: Add loop option.
diff --git a/avconv.c b/avconv.c
index 13e6778..9a1a0f6 100644
--- a/avconv.c
+++ b/avconv.c
@@ -1131,6 +1131,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, ist->st->codec->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;
@@ -2145,6 +2146,81 @@ static void reset_eagain(void)
input_files[i]->eagain = 0;
}
+//seek to the beggining of file
+static int seek_to_start(InputFile *ifile, AVFormatContext *is)
+{
+ InputStream *ist;
+ int i, ret, is_audio = 0;
+ int64_t *duration; //duration of last frame
+
+ ret = av_seek_frame(is, -1, is->start_time, 0);
+ if (ret < 0)
+ return ret;
+ duration = av_mallocz(ifile->nb_streams * sizeof(*duration));
+ if (!duration)
+ return AVERROR(ENOMEM);
+ //flush decoders
+ for (i = 0; i < ifile->nb_streams; i++) {
+ int got_output;
+ AVFrame *frame;
+ AVPacket avpkt;
+
+ ist = input_streams[ifile->ist_index + i];
+ av_init_packet(&avpkt);
+ avpkt.data = NULL;
+ avpkt.size = 0;
+ if (!(frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ if (ist->decoding_needed) {
+ switch (ist->st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ avcodec_decode_audio4(ist->st->codec, frame, &got_output, &avpkt);
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ avcodec_decode_video2(ist->st->codec,
+ frame, &got_output, &avpkt);
+ break;
+ }
+ }
+ av_frame_unref(frame);
+ }
+ for (i = 0; i < ifile->nb_streams; i++) {
+ ist = input_streams[ifile->ist_index + i];
+ avcodec_flush_buffers(ist->st->codec);
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ AVRational sample_rate = {1, ist->st->codec->sample_rate};
+
+ if (ist->nb_samples) {
+ duration[i] = av_rescale_q(ist->nb_samples, sample_rate, ist->st->time_base);
+ is_audio = 1;
+ }
+ }
+ }
+ for (i = 0; i < ifile->nb_streams; i++) {
+ ist = input_streams[ifile->ist_index + i];
+ if (!is_audio) {
+ if (ist->framerate.num) {
+ duration[i] = av_rescale_q(1, ist->framerate, ist->st->time_base);
+ } else if (ist->st->avg_frame_rate.num) {
+ duration[i] = av_rescale_q(1, ist->st->avg_frame_rate, ist->st->time_base);
+ } else duration[i] = 1;
+ }
+ ist->duration = duration[i] + ist->max_pts - ist->min_pts;
+ }
+ //looking for the longest stream in a file
+ for (i = 0; i < ifile->nb_streams; i++) {
+ ist = input_streams[ifile->ist_index + i];
+ if (ifile->duration < ist->duration) {
+ ifile->duration = ist->duration;
+ ifile->time_base = ist->st->time_base;
+ }
+ }
+ ifile->loop--;
+ av_freep(&duration);
+
+ return ret;
+}
+
/*
* Read one packet from an input file and send it for
* - decoding -> lavfi (audio/video)
@@ -2164,6 +2240,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();
@@ -2181,6 +2258,12 @@ static int process_input(void)
is = ifile->ctx;
ret = get_input_packet(ifile, &pkt);
+ if ((ret == AVERROR_EOF) && (ifile->loop > 1)) {
+ if ((ret = seek_to_start(ifile, is)) < 0)
+ return ret;
+ ret = get_input_packet(ifile, &pkt);
+
+ }
if (ret == AVERROR(EAGAIN)) {
ifile->eagain = 1;
return ret;
@@ -2251,6 +2334,15 @@ 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);
+ }
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts += duration;
ret = output_packet(ist, &pkt);
if (ret < 0) {
diff --git a/avconv.h b/avconv.h
index c912fae..d794881 100644
--- a/avconv.h
+++ b/avconv.h
@@ -100,6 +100,7 @@ typedef struct OptionsContext {
/* input options */
int64_t input_ts_offset;
+ int loop;
int rate_emu;
int accurate_seek;
@@ -227,6 +228,10 @@ typedef struct InputStream {
int64_t next_dts;
/* dts of the last packet read for this stream */
int64_t last_dts;
+ int64_t min_pts; /* smallest pts in the stream */
+ int64_t max_pts; /* largest pts it the stream */
+ int64_t duration; /* duration of the stream in AVStream time_base */
+ int64_t nb_samples; /* number of samples in the current audio frame */
PtsCorrectionContext pts_ctx;
double ts_scale;
int showed_multi_packet_warning;
@@ -266,6 +271,9 @@ typedef struct InputFile {
int eof_reached; /* true if eof reached */
int eagain; /* true if last read attempt returned EAGAIN */
int ist_index; /* index of first stream in ist_table */
+ int loop; /* set number of times input stream should be looped */
+ int64_t duration; /* duration of the longest stream in a file in time_base */
+ AVRational time_base; /* time base of the duration */
int64_t ts_offset;
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
int64_t recording_time;
diff --git a/avconv_opt.c b/avconv_opt.c
index 7bc41c9..edbf28a 100644
--- a/avconv_opt.c
+++ b/avconv_opt.c
@@ -476,6 +476,10 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
ist->file_index = nb_input_files;
ist->discard = 1;
st->discard = AVDISCARD_ALL;
+ ist->duration = 0;
+ ist->nb_samples = 0;
+ ist->min_pts = INT64_MAX;
+ ist->max_pts = INT64_MIN;
ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
@@ -746,6 +750,9 @@ static int open_input_file(OptionsContext *o, const char *filename)
f->nb_streams = ic->nb_streams;
f->rate_emu = o->rate_emu;
f->accurate_seek = o->accurate_seek;
+ f->loop = o->loop;
+ f->duration = 0;
+ f->time_base = (AVRational){1, 1};
/* check if all codec options have been used */
unused_opts = strip_specifiers(o->g->codec_opts);
@@ -2272,6 +2279,8 @@ const OptionDef options[] = {
{ "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) },
"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" },
/* video options */
{ "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
diff --git a/doc/avconv.texi b/doc/avconv.texi
index 0c17eb9..026158b 100644
--- a/doc/avconv.texi
+++ b/doc/avconv.texi
@@ -236,6 +236,9 @@ Overwrite output files without asking.
@item -n (@emph{global})
Immediately exit when output files already exist.
+@item -loop @var{number}
+Loops input stream <number> times.
+
@item -c[:@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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment