@@ -23,6 +23,7 @@
* audio to video multimedia filter
*/
+#include "libavutil/audio_fifo.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
@@ -70,6 +71,7 @@ typedef struct ShowWavesContext {
int buf_idx;
int16_t *buf_idy; /* y coordinate of previous sample for each channel */
AVFrame *outpicref;
+ AVFrame *tmp;
int n;
int pixstep;
int sample_count_mod;
@@ -89,6 +91,11 @@ typedef struct ShowWavesContext {
struct frame_node *last_frame;
int64_t total_samples;
int64_t *sum; /* abs sum of the samples per channel */
+ int hop_size;
+ int64_t pts;
+ int64_t samples_in;
+ int64_t samples_out;
+ AVAudioFifo *fifo;
} ShowWavesContext;
#define OFFSET(x) offsetof(ShowWavesContext, x)
@@ -124,6 +131,7 @@ static av_cold void uninit(AVFilterContext *ctx)
{
ShowWavesContext *showwaves = ctx->priv;
+ av_frame_free(&showwaves->tmp);
av_frame_free(&showwaves->outpicref);
av_freep(&showwaves->buf_idy);
av_freep(&showwaves->fg);
@@ -139,6 +147,8 @@ static av_cold void uninit(AVFilterContext *ctx)
}
av_freep(&showwaves->sum);
showwaves->last_frame = NULL;
+ } else {
+ av_audio_fifo_free(showwaves->fifo);
}
}
@@ -413,11 +423,22 @@ static int config_output(AVFilterLink *outlink)
uint8_t x;
int ch;
- if (showwaves->single_pic)
+ if (showwaves->single_pic) {
showwaves->n = 1;
+ } else {
+ showwaves->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, 1024);
+ if (!showwaves->fifo)
+ return AVERROR(ENOMEM);
+ }
if (!showwaves->n)
showwaves->n = FFMAX(1, av_rescale_q(inlink->sample_rate, av_make_q(1, showwaves->w), showwaves->rate));
+ showwaves->hop_size = FFMIN(showwaves->n * showwaves->w, av_rescale(inlink->sample_rate, showwaves->rate.den, showwaves->rate.num));
+ if (!showwaves->single_pic) {
+ showwaves->tmp = ff_get_audio_buffer(inlink, showwaves->n * showwaves->w);
+ if (!showwaves->tmp)
+ return AVERROR(ENOMEM);
+ }
showwaves->buf_idx = 0;
if (!(showwaves->buf_idy = av_mallocz_array(nb_channels, sizeof(*showwaves->buf_idy)))) {
@@ -428,11 +449,12 @@ static int config_output(AVFilterLink *outlink)
outlink->h = showwaves->h;
outlink->sample_aspect_ratio = (AVRational){1,1};
- outlink->frame_rate = av_div_q((AVRational){inlink->sample_rate,showwaves->n},
- (AVRational){showwaves->w,1});
+ outlink->frame_rate = showwaves->rate;
+ outlink->time_base = inlink->time_base;
- av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%d\n",
- showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), showwaves->n);
+ av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%d hop:%d tb:%d/%d\n",
+ showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), showwaves->n,
+ showwaves->hop_size, outlink->time_base.num, outlink->time_base.den);
switch (outlink->format) {
case AV_PIX_FMT_GRAY8:
@@ -635,7 +657,7 @@ static int request_frame(AVFilterLink *outlink)
static int alloc_out_frame(ShowWavesContext *showwaves, const int16_t *p,
const AVFilterLink *inlink, AVFilterLink *outlink,
- const AVFrame *in)
+ const AVFrame *in, int64_t pts)
{
if (!showwaves->outpicref) {
int j;
@@ -645,9 +667,9 @@ static int alloc_out_frame(ShowWavesContext *showwaves, const int16_t *p,
return AVERROR(ENOMEM);
out->width = outlink->w;
out->height = outlink->h;
- out->pts = in->pts + av_rescale_q((p - (int16_t *)in->data[0]) / inlink->channels,
- av_make_q(1, inlink->sample_rate),
- outlink->time_base);
+ out->pts = pts + av_rescale_q(showwaves->samples_out + showwaves->n * showwaves->w - showwaves->samples_in,
+ av_make_q(1, inlink->sample_rate),
+ outlink->time_base);
for (j = 0; j < outlink->h; j++)
memset(out->data[0] + j*out->linesize[0], 0, outlink->w * showwaves->pixstep);
}
@@ -668,7 +690,7 @@ static av_cold int init(AVFilterContext *ctx)
#if CONFIG_SHOWWAVES_FILTER
-static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples, int64_t pts)
{
AVFilterContext *ctx = inlink->dst;
AVFilterLink *outlink = ctx->outputs[0];
@@ -685,7 +707,7 @@ static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
/* draw data in the buffer */
for (i = 0; i < nb_samples; i++) {
- ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples);
+ ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples, pts);
if (ret < 0)
goto end;
outpicref = showwaves->outpicref;
@@ -708,14 +730,16 @@ static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
showwaves->buf_idx++;
}
if (showwaves->buf_idx == showwaves->w ||
- (ff_outlink_get_status(inlink) && i == nb_samples - 1))
+ av_audio_fifo_size(showwaves->fifo) <= 0) {
+ av_audio_fifo_drain(showwaves->fifo, showwaves->hop_size);
+ showwaves->samples_out += showwaves->hop_size;
if ((ret = push_frame(outlink)) < 0)
break;
+ }
outpicref = showwaves->outpicref;
}
end:
- av_frame_free(&insamples);
return ret;
}
@@ -730,11 +754,26 @@ static int activate(AVFilterContext *ctx)
FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
- ret = ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &in);
- if (ret < 0)
- return ret;
- if (ret > 0)
- return showwaves_filter_frame(inlink, in);
+ if (av_audio_fifo_size(showwaves->fifo) < nb_samples) {
+ ret = ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &in);
+ if (ret < 0)
+ return ret;
+ if (ret > 0) {
+ showwaves->pts = in->pts;
+ ret = av_audio_fifo_write(showwaves->fifo, (void **)in->extended_data,
+ in->nb_samples);
+ showwaves->samples_in += in->nb_samples;
+ av_frame_free(&in);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ if (av_audio_fifo_size(showwaves->fifo) >= nb_samples) {
+ ret = av_audio_fifo_peek(showwaves->fifo, (void **)showwaves->tmp->extended_data, nb_samples);
+ if (ret < 0)
+ return ret;
+ return showwaves_filter_frame(inlink, showwaves->tmp, showwaves->pts);
+ }
FF_FILTER_FORWARD_STATUS(inlink, outlink);
FF_FILTER_FORWARD_WANTED(outlink, inlink);
@@ -822,7 +861,7 @@ static int showwavespic_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
if (showwaves->single_pic) {
struct frame_node *f;
- ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples);
+ ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples, 0);
if (ret < 0)
goto end;
Signed-off-by: Paul B Mahol <onemda@gmail.com> --- libavfilter/avf_showwaves.c | 77 ++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 19 deletions(-)