summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas George <nicolas.george@normalesup.org>2012-06-30 10:11:22 +0200
committerNicolas George <nicolas.george@normalesup.org>2012-06-30 14:03:54 +0200
commit0689d5e17ac0a3269c604b4df2c01140be328647 (patch)
treeb13f02db581e86c23feeaeffa396503ef37cef0c
parentc9c4835f5164b86510591d4ba604bfb448c7a356 (diff)
lavfi: implement samples framing on links.
Links can be set up to group samples into buffers of specified minimum and maximum size.
-rw-r--r--libavfilter/audio.c48
-rw-r--r--libavfilter/audio.h7
-rw-r--r--libavfilter/avfilter.c14
-rw-r--r--libavfilter/avfilter.h26
4 files changed, 91 insertions, 4 deletions
diff --git a/libavfilter/audio.c b/libavfilter/audio.c
index 6a86597342..0ebec3c2d0 100644
--- a/libavfilter/audio.c
+++ b/libavfilter/audio.c
@@ -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;
+}
diff --git a/libavfilter/audio.h b/libavfilter/audio.h
index d4282b59fe..cab1a6c722 100644
--- a/libavfilter/audio.h
+++ b/libavfilter/audio.h
@@ -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 */
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 0474192b1a..01f34423c9 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -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)
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index b679635805..e08a389275 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -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;
};
/**