lavfi: implement samples framing on links.
authorNicolas George <nicolas.george@normalesup.org>
Sat, 30 Jun 2012 08:11:22 +0000 (10:11 +0200)
committerNicolas George <nicolas.george@normalesup.org>
Sat, 30 Jun 2012 12:03:54 +0000 (14:03 +0200)
Links can be set up to group samples into buffers of
specified minimum and maximum size.

libavfilter/audio.c
libavfilter/audio.h
libavfilter/avfilter.c
libavfilter/avfilter.h

index 6a86597..0ebec3c 100644 (file)
@@ -156,7 +156,8 @@ static void default_filter_samples(AVFilterLink *link,
     ff_filter_samples(link->dst->outputs[0], samplesref);
 }
 
-void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
+void ff_filter_samples_framed(AVFilterLink *link,
+                              AVFilterBufferRef *samplesref)
 {
     void (*filter_samples)(AVFilterLink *, AVFilterBufferRef *);
     AVFilterPad *dst = link->dstpad;
@@ -195,3 +196,48 @@ void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
     filter_samples(link, buf_out);
     ff_update_link_current_pts(link, pts);
 }
+
+void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
+{
+    int insamples = samplesref->audio->nb_samples, inpos = 0, nb_samples;
+    AVFilterBufferRef *pbuf = link->partial_buf;
+    int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
+
+    if (!link->min_samples ||
+        (!pbuf &&
+         insamples >= link->min_samples && insamples <= link->max_samples)) {
+        ff_filter_samples_framed(link, samplesref);
+        return;
+    }
+    /* Handle framing (min_samples, max_samples) */
+    while (insamples) {
+        if (!pbuf) {
+            AVRational samples_tb = { 1, link->sample_rate };
+            int perms = link->dstpad->min_perms | AV_PERM_WRITE;
+            pbuf = ff_get_audio_buffer(link, perms, link->partial_buf_size);
+            if (!pbuf) {
+                av_log(link->dst, AV_LOG_WARNING,
+                       "Samples dropped due to memory allocation failure.\n");
+                return;
+            }
+            avfilter_copy_buffer_ref_props(pbuf, samplesref);
+            pbuf->pts = samplesref->pts +
+                        av_rescale_q(inpos, samples_tb, link->time_base);
+            pbuf->audio->nb_samples = 0;
+        }
+        nb_samples = FFMIN(insamples,
+                           link->partial_buf_size - pbuf->audio->nb_samples);
+        av_samples_copy(pbuf->extended_data, samplesref->extended_data,
+                        pbuf->audio->nb_samples, inpos,
+                        nb_samples, nb_channels, link->format);
+        inpos                   += nb_samples;
+        insamples               -= nb_samples;
+        pbuf->audio->nb_samples += nb_samples;
+        if (pbuf->audio->nb_samples >= link->min_samples) {
+            ff_filter_samples_framed(link, pbuf);
+            pbuf = NULL;
+        }
+    }
+    avfilter_unref_buffer(samplesref);
+    link->partial_buf = pbuf;
+}
index d4282b5..cab1a6c 100644 (file)
@@ -73,4 +73,11 @@ AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms,
  */
 void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
 
+/**
+ * Send a buffer of audio samples to the next link, without checking
+ * min_samples.
+ */
+void ff_filter_samples_framed(AVFilterLink *link,
+                              AVFilterBufferRef *samplesref);
+
 #endif /* AVFILTER_AUDIO_H */
index 0474192..01f3442 100644 (file)
@@ -28,6 +28,7 @@
 #include "avfilter.h"
 #include "formats.h"
 #include "internal.h"
+#include "audio.h"
 
 char *ff_get_ref_perms_string(char *buf, size_t buf_size, int perms)
 {
@@ -320,13 +321,20 @@ void ff_tlog_link(void *ctx, AVFilterLink *link, int end)
 
 int ff_request_frame(AVFilterLink *link)
 {
+    int ret = -1;
     FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1);
 
     if (link->srcpad->request_frame)
-        return link->srcpad->request_frame(link);
+        ret = link->srcpad->request_frame(link);
     else if (link->src->inputs[0])
-        return ff_request_frame(link->src->inputs[0]);
-    else return -1;
+        ret = ff_request_frame(link->src->inputs[0]);
+    if (ret == AVERROR_EOF && link->partial_buf) {
+        AVFilterBufferRef *pbuf = link->partial_buf;
+        link->partial_buf = NULL;
+        ff_filter_samples_framed(link, pbuf);
+        return 0;
+    }
+    return ret;
 }
 
 int ff_poll_frame(AVFilterLink *link)
index b679635..e08a389 100644 (file)
@@ -590,6 +590,32 @@ struct AVFilterLink {
      * It is similar to the r_frae_rate field in AVStream.
      */
     AVRational frame_rate;
+
+    /**
+     * Buffer partially filled with samples to achieve a fixed/minimum size.
+     */
+    AVFilterBufferRef *partial_buf;
+
+    /**
+     * Size of the partial buffer to allocate.
+     * Must be between min_samples and max_samples.
+     */
+    int partial_buf_size;
+
+    /**
+     * Minimum number of samples to filter at once. If filter_samples() is
+     * called with fewer samples, it will accumulate them in partial_buf.
+     * This field and the related ones must not be changed after filtering
+     * has started.
+     * If 0, all related fields are ignored.
+     */
+    int min_samples;
+
+    /**
+     * Maximum number of samples to filter at once. If filter_samples() is
+     * called with more samples, it will split them.
+     */
+    int max_samples;
 };
 
 /**