X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Ff_loop.c;h=15f6076a678cd9a9d56ba8cc77c3335c01bd524d;hb=a04ad248a05e7b613abe09b3bb067f555108d794;hp=d9d55f983722fd9339f38765e0da39050916ac22;hpb=06476249cd2332e30b66576633b2827adf3478dd;p=ffmpeg diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c index d9d55f98372..15f6076a678 100644 --- a/libavfilter/f_loop.c +++ b/libavfilter/f_loop.c @@ -55,6 +55,15 @@ typedef struct LoopContext { #define VFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM #define OFFSET(x) offsetof(LoopContext, x) +static void check_size(AVFilterContext *ctx) +{ + LoopContext *s = ctx->priv; + + if (!s->size) + av_log(ctx, AV_LOG_WARNING, "Number of %s to loop is not set!\n", + ctx->input_pads[0].type == AVMEDIA_TYPE_VIDEO ? "frames" : "samples"); +} + #if CONFIG_ALOOP_FILTER static int aconfig_input(AVFilterLink *inlink) @@ -67,6 +76,8 @@ static int aconfig_input(AVFilterLink *inlink) if (!s->fifo || !s->left) return AVERROR(ENOMEM); + check_size(ctx); + return 0; } @@ -96,7 +107,7 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) } out->pts = s->pts; out->nb_samples = ret; - s->pts += out->nb_samples; + s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); i += out->nb_samples; s->current_sample += out->nb_samples; @@ -105,6 +116,7 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) return ret; if (s->current_sample >= s->nb_samples) { + s->duration = s->pts; s->current_sample = 0; if (s->loop > 0) @@ -134,7 +146,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) drain = FFMAX(0, s->start - s->ignored_samples); s->pts = frame->pts; av_audio_fifo_drain(s->fifo, drain); - s->pts += s->start - s->ignored_samples; + s->pts += av_rescale_q(s->start - s->ignored_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); } s->nb_samples += ret - drain; drain = frame->nb_samples - written; @@ -147,7 +159,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) av_audio_fifo_drain(s->left, drain); } frame->nb_samples = ret; - s->pts += ret; + s->pts += av_rescale_q(ret, (AVRational){1, outlink->sample_rate}, outlink->time_base); ret = ff_filter_frame(outlink, frame); } else { int nb_samples = frame->nb_samples; @@ -158,7 +170,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) } else { s->ignored_samples += frame->nb_samples; frame->pts = s->pts; - s->pts += frame->nb_samples; + s->pts += av_rescale_q(frame->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); ret = ff_filter_frame(outlink, frame); } @@ -184,7 +196,7 @@ static int arequest_frame(AVFilterLink *outlink) return AVERROR(ENOMEM); av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples); out->pts = s->pts; - s->pts += nb_samples; + s->pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); ret = ff_filter_frame(outlink, out); if (ret < 0) return ret; @@ -194,13 +206,55 @@ static int arequest_frame(AVFilterLink *outlink) ret = push_samples(ctx, 1024); } - if (ret == AVERROR_EOF && s->nb_samples > 0 && s->loop != 0) { - ret = push_samples(ctx, outlink->sample_rate); + if (s->eof && s->nb_samples > 0 && s->loop != 0) { + ret = push_samples(ctx, 1024); } return ret; } +static int aactivate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + LoopContext *s = ctx->priv; + AVFrame *frame = NULL; + int ret, status; + int64_t pts; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (!s->eof && (s->nb_samples < s->size || !s->loop || !s->size)) { + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) + return afilter_frame(inlink, frame); + } + + if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) { + s->size = s->nb_samples; + s->eof = 1; + } + } + + if (s->eof && (!s->loop || !s->size)) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->duration); + return 0; + } + + if (!s->eof && (!s->size || + (s->nb_samples < s->size) || + (s->nb_samples >= s->size && s->loop == 0))) { + FF_FILTER_FORWARD_WANTED(outlink, inlink); + } else if (s->loop && s->nb_samples == s->size) { + return arequest_frame(outlink); + } + + return FFERROR_NOT_READY; +} + static const AVOption aloop_options[] = { { "loop", "number of loops", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, INT_MAX, AFLAGS }, { "size", "max number of samples to loop", OFFSET(size), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT32_MAX, AFLAGS }, @@ -214,7 +268,6 @@ static const AVFilterPad ainputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = afilter_frame, .config_props = aconfig_input, }, { NULL } @@ -224,16 +277,16 @@ static const AVFilterPad aoutputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .request_frame = arequest_frame, }, { NULL } }; -AVFilter ff_af_aloop = { +const AVFilter ff_af_aloop = { .name = "aloop", .description = NULL_IF_CONFIG_SMALL("Loop audio samples."), .priv_size = sizeof(LoopContext), .priv_class = &aloop_class, + .activate = aactivate, .uninit = auninit, .inputs = ainputs, .outputs = aoutputs, @@ -250,6 +303,8 @@ static av_cold int init(AVFilterContext *ctx) if (!s->frames) return AVERROR(ENOMEM); + check_size(ctx); + return 0; } @@ -343,7 +398,7 @@ static int activate(AVFilterContext *ctx) FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); - if (!s->eof && (s->nb_frames < s->size || !s->loop)) { + if (!s->eof && (s->nb_frames < s->size || !s->loop || !s->size)) { ret = ff_inlink_consume_frame(inlink, &frame); if (ret < 0) return ret; @@ -352,11 +407,13 @@ static int activate(AVFilterContext *ctx) } if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { - if (status == AVERROR_EOF) + if (status == AVERROR_EOF) { + s->size = s->nb_frames; s->eof = 1; + } } - if (s->eof && (s->loop == 0 || s->nb_frames < s->size)) { + if (s->eof && (!s->loop || !s->size)) { ff_outlink_set_status(outlink, AVERROR_EOF, s->duration); return 0; } @@ -397,7 +454,7 @@ static const AVFilterPad outputs[] = { { NULL } }; -AVFilter ff_vf_loop = { +const AVFilter ff_vf_loop = { .name = "loop", .description = NULL_IF_CONFIG_SMALL("Loop video frames."), .priv_size = sizeof(LoopContext),