summaryrefslogtreecommitdiff
path: root/libavfilter
diff options
context:
space:
mode:
Diffstat (limited to 'libavfilter')
-rw-r--r--libavfilter/Makefile1
-rw-r--r--libavfilter/allfilters.c4
-rw-r--r--libavfilter/avcodec.c44
-rw-r--r--libavfilter/avcodec.h10
-rw-r--r--libavfilter/avfilter.c87
-rw-r--r--libavfilter/avfilter.h61
-rw-r--r--libavfilter/buffersink.c114
-rw-r--r--libavfilter/buffersink.h14
-rw-r--r--libavfilter/defaults.c2
9 files changed, 333 insertions, 4 deletions
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 7da07eb76a..0647772128 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -23,6 +23,7 @@ HEADERS = asrc_abuffer.h \
OBJS = allfilters.o \
avfilter.o \
avfiltergraph.o \
+ buffersink.o \
defaults.o \
drawutils.o \
formats.o \
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 96de563606..e4f82c96c5 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -129,6 +129,10 @@ void avfilter_register_all(void)
avfilter_register(&avfilter_vsrc_buffer);
}
{
+ extern AVFilter avfilter_vsink_buffer;
+ avfilter_register(&avfilter_vsink_buffer);
+ }
+ {
extern AVFilter avfilter_vf_scale;
avfilter_register(&avfilter_vf_scale);
}
diff --git a/libavfilter/avcodec.c b/libavfilter/avcodec.c
index a63c2a3c95..b71cf97f70 100644
--- a/libavfilter/avcodec.c
+++ b/libavfilter/avcodec.c
@@ -51,6 +51,50 @@ int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src)
return 0;
}
+int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src)
+{
+ int planes, nb_channels;
+
+ memcpy(dst->data, src->data, sizeof(dst->data));
+ memcpy(dst->linesize, src->linesize, sizeof(dst->linesize));
+
+ dst->pts = src->pts;
+ dst->format = src->format;
+
+ switch (src->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ dst->width = src->video->w;
+ dst->height = src->video->h;
+ dst->sample_aspect_ratio = src->video->sample_aspect_ratio;
+ dst->interlaced_frame = src->video->interlaced;
+ dst->top_field_first = src->video->top_field_first;
+ dst->key_frame = src->video->key_frame;
+ dst->pict_type = src->video->pict_type;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ nb_channels = av_get_channel_layout_nb_channels(src->audio->channel_layout);
+ planes = av_sample_fmt_is_planar(src->format) ? nb_channels : 1;
+
+ if (planes > FF_ARRAY_ELEMS(dst->data)) {
+ dst->extended_data = av_mallocz(planes * sizeof(*dst->extended_data));
+ if (!dst->extended_data)
+ return AVERROR(ENOMEM);
+ memcpy(dst->extended_data, src->extended_data,
+ planes * sizeof(dst->extended_data));
+ } else
+ dst->extended_data = dst->data;
+
+ dst->sample_rate = src->audio->sample_rate;
+ dst->channel_layout = src->audio->channel_layout;
+ dst->nb_samples = src->audio->nb_samples;
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
AVFilterBufferRef *avfilter_get_video_buffer_ref_from_frame(const AVFrame *frame,
int perms)
{
diff --git a/libavfilter/avcodec.h b/libavfilter/avcodec.h
index cec847146f..9636cfd1bc 100644
--- a/libavfilter/avcodec.h
+++ b/libavfilter/avcodec.h
@@ -35,10 +35,20 @@
/**
* Copy the frame properties of src to dst, without copying the actual
* image data.
+ *
+ * @return 0 on success, a negative number on error.
*/
int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src);
/**
+ * Copy the frame properties and data pointers of src to dst, without copying
+ * the actual data.
+ *
+ * @return 0 on success, a negative number on error.
+ */
+int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src);
+
+/**
* Create and return a picref reference from the data and properties
* contained in frame.
*
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 99b97dfc5c..89afee060f 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -68,6 +68,7 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask)
return NULL;
}
*ret->video = *ref->video;
+ ret->extended_data = ret->data;
} else if (ref->type == AVMEDIA_TYPE_AUDIO) {
ret->audio = av_malloc(sizeof(AVFilterBufferRefAudioProps));
if (!ret->audio) {
@@ -75,6 +76,19 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask)
return NULL;
}
*ret->audio = *ref->audio;
+
+ if (ref->extended_data != ref->data) {
+ int nb_channels = av_get_channel_layout_nb_channels(ref->audio->channel_layout);
+ if (!(ret->extended_data = av_malloc(sizeof(*ret->extended_data) *
+ nb_channels))) {
+ av_freep(&ret->audio);
+ av_freep(&ret);
+ return NULL;
+ }
+ memcpy(ret->extended_data, ref->extended_data,
+ sizeof(*ret->extended_data) * nb_channels);
+ } else
+ ret->extended_data = ret->data;
}
ret->perms &= pmask;
ret->buf->refcount ++;
@@ -155,6 +169,8 @@ void avfilter_unref_buffer(AVFilterBufferRef *ref)
}
ref->buf->free(ref->buf);
}
+ if (ref->extended_data != ref->data)
+ av_freep(&ref->extended_data);
av_freep(&ref->video);
av_freep(&ref->audio);
av_free(ref);
@@ -472,6 +488,9 @@ avfilter_get_video_buffer_ref_from_arrays(uint8_t * const data[4], const int lin
memcpy(picref->data, pic->data, sizeof(picref->data));
memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
+ pic-> extended_data = pic->data;
+ picref->extended_data = picref->data;
+
return picref;
fail:
@@ -541,6 +560,74 @@ fail:
return NULL;
}
+AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays_alt(uint8_t **data,
+ int linesize, int perms,
+ int nb_samples,
+ enum AVSampleFormat sample_fmt,
+ uint64_t channel_layout)
+{
+ int planes;
+ AVFilterBuffer *samples = av_mallocz(sizeof(*samples));
+ AVFilterBufferRef *samplesref = av_mallocz(sizeof(*samplesref));
+
+ if (!samples || !samplesref)
+ goto fail;
+
+ samplesref->buf = samples;
+ samplesref->buf->free = ff_avfilter_default_free_buffer;
+ if (!(samplesref->audio = av_mallocz(sizeof(*samplesref->audio))))
+ goto fail;
+
+ samplesref->audio->nb_samples = nb_samples;
+ samplesref->audio->channel_layout = channel_layout;
+ samplesref->audio->planar = av_sample_fmt_is_planar(sample_fmt);
+
+ planes = samplesref->audio->planar ? av_get_channel_layout_nb_channels(channel_layout) : 1;
+
+ /* make sure the buffer gets read permission or it's useless for output */
+ samplesref->perms = perms | AV_PERM_READ;
+
+ samples->refcount = 1;
+ samplesref->type = AVMEDIA_TYPE_AUDIO;
+ samplesref->format = sample_fmt;
+
+ memcpy(samples->data, data,
+ FFMIN(FF_ARRAY_ELEMS(samples->data), planes)*sizeof(samples->data[0]));
+ memcpy(samplesref->data, samples->data, sizeof(samples->data));
+
+ samples->linesize[0] = samplesref->linesize[0] = linesize;
+
+ if (planes > FF_ARRAY_ELEMS(samples->data)) {
+ samples-> extended_data = av_mallocz(sizeof(*samples->extended_data) *
+ planes);
+ samplesref->extended_data = av_mallocz(sizeof(*samplesref->extended_data) *
+ planes);
+
+ if (!samples->extended_data || !samplesref->extended_data)
+ goto fail;
+
+ memcpy(samples-> extended_data, data, sizeof(*data)*planes);
+ memcpy(samplesref->extended_data, data, sizeof(*data)*planes);
+ } else {
+ samples->extended_data = samples->data;
+ samplesref->extended_data = samplesref->data;
+ }
+
+ return samplesref;
+
+fail:
+ if (samples && samples->extended_data != samples->data)
+ av_freep(&samples->extended_data);
+ if (samplesref) {
+ av_freep(&samplesref->audio);
+ if (samplesref->extended_data != samplesref->data)
+ av_freep(&samplesref->extended_data);
+ }
+ av_freep(&samplesref);
+ av_freep(&samples);
+ return NULL;
+}
+
int avfilter_request_frame(AVFilterLink *link)
{
FF_DPRINTF_START(NULL, request_frame); ff_dlog_link(NULL, link, 1);
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index c526df4a9f..d7d4c16ec0 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -84,6 +84,22 @@ typedef struct AVFilterBuffer {
int format; ///< media format
int w, h; ///< width and height of the allocated buffer
+
+ /**
+ * pointers to the data planes/channels.
+ *
+ * For video, this should simply point to data[].
+ *
+ * For planar audio, each channel has a separate data pointer, and
+ * linesize[0] contains the size of each channel buffer.
+ * For packed audio, there is just one data pointer, and linesize[0]
+ * contains the total size of the buffer for all channels.
+ *
+ * Note: Both data and extended_data will always be set, but for planar
+ * audio with more channels that can fit in data, extended_data must be used
+ * in order to access all channels.
+ */
+ uint8_t **extended_data;
} AVFilterBuffer;
#define AV_PERM_READ 0x01 ///< can read from the buffer
@@ -150,6 +166,22 @@ typedef struct AVFilterBufferRef {
enum AVMediaType type; ///< media type of buffer data
AVFilterBufferRefVideoProps *video; ///< video buffer specific properties
AVFilterBufferRefAudioProps *audio; ///< audio buffer specific properties
+
+ /**
+ * pointers to the data planes/channels.
+ *
+ * For video, this should simply point to data[].
+ *
+ * For planar audio, each channel has a separate data pointer, and
+ * linesize[0] contains the size of each channel buffer.
+ * For packed audio, there is just one data pointer, and linesize[0]
+ * contains the total size of the buffer for all channels.
+ *
+ * Note: Both data and extended_data will always be set, but for planar
+ * audio with more channels that can fit in data, extended_data must be used
+ * in order to access all channels.
+ */
+ uint8_t **extended_data;
} AVFilterBufferRef;
/**
@@ -783,10 +815,31 @@ AVFilterBufferRef *avfilter_get_audio_buffer(AVFilterLink *link, int perms,
* @param channel_layout the channel layout of the buffer
* @param planar audio data layout - planar or packed
*/
-AVFilterBufferRef *
-avfilter_get_audio_buffer_ref_from_arrays(uint8_t *data[8], int linesize[8], int perms,
- int nb_samples, enum AVSampleFormat sample_fmt,
- uint64_t channel_layout, int planar);
+AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays(uint8_t *data[8],
+ int linesize[8],
+ int perms,
+ int nb_samples,
+ enum AVSampleFormat sample_fmt,
+ uint64_t channel_layout,
+ int planar);
+/**
+ * Create an audio buffer reference wrapped around an already
+ * allocated samples buffer.
+ *
+ * @param data pointers to the samples plane buffers
+ * @param linesize linesize for the samples plane buffers
+ * @param perms the required access permissions
+ * @param nb_samples number of samples per channel
+ * @param sample_fmt the format of each sample in the buffer to allocate
+ * @param channel_layout the channel layout of the buffer
+ */
+AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays_alt(uint8_t **data,
+ int linesize,
+ int perms,
+ int nb_samples,
+ enum AVSampleFormat sample_fmt,
+ uint64_t channel_layout);
+
/**
* Request an input frame from the filter at the other end of the link.
*
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
new file mode 100644
index 0000000000..f0fcab553e
--- /dev/null
+++ b/libavfilter/buffersink.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * buffer sink
+ */
+
+#include "libavutil/fifo.h"
+
+#include "avfilter.h"
+#include "buffersink.h"
+
+typedef struct {
+ AVFifoBuffer *fifo; ///< FIFO buffer of video frame references
+} BufferSinkContext;
+
+#define FIFO_INIT_SIZE 8
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ BufferSinkContext *sink = ctx->priv;
+
+ while (sink->fifo && av_fifo_size(sink->fifo)) {
+ AVFilterBufferRef *buf;
+ av_fifo_generic_read(sink->fifo, &buf, sizeof(buf), NULL);
+ avfilter_unref_buffer(buf);
+ }
+ av_fifo_free(sink->fifo);
+}
+
+static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ BufferSinkContext *sink = ctx->priv;
+
+ if (!(sink->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef*)))) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static void end_frame(AVFilterLink *link)
+{
+ AVFilterContext *ctx = link->dst;
+ BufferSinkContext *sink = ctx->priv;
+
+ if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
+ (av_fifo_realloc2(sink->fifo, av_fifo_size(sink->fifo) * 2) < 0)) {
+ av_log(ctx, AV_LOG_ERROR, "Error reallocating the FIFO.\n");
+ return;
+ }
+
+ av_fifo_generic_write(sink->fifo, &link->cur_buf, sizeof(link->cur_buf), NULL);
+ link->cur_buf = NULL;
+}
+
+int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
+{
+ BufferSinkContext *sink = ctx->priv;
+ AVFilterLink *link = ctx->inputs[0];
+ int ret;
+
+ if (!buf) {
+ if (av_fifo_size(sink->fifo))
+ return av_fifo_size(sink->fifo)/sizeof(*buf);
+ else
+ return avfilter_poll_frame(ctx->inputs[0]);
+ }
+
+ if (!av_fifo_size(sink->fifo) &&
+ (ret = avfilter_request_frame(link)) < 0)
+ return ret;
+
+ if (!av_fifo_size(sink->fifo))
+ return AVERROR(EINVAL);
+
+ av_fifo_generic_read(sink->fifo, buf, sizeof(*buf), NULL);
+
+ return 0;
+}
+
+AVFilter avfilter_vsink_buffer = {
+ .name = "buffersink_old",
+ .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
+ .priv_size = sizeof(BufferSinkContext),
+ .init = init,
+ .uninit = uninit,
+
+ .inputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .end_frame = end_frame,
+ .min_perms = AV_PERM_READ, },
+ { .name = NULL }},
+ .outputs = (AVFilterPad[]) {{ .name = NULL }},
+};
diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
index 4c13f0df64..86a4b2462b 100644
--- a/libavfilter/buffersink.h
+++ b/libavfilter/buffersink.h
@@ -98,4 +98,18 @@ int av_vsink_buffer_get_video_buffer_ref(AVFilterContext *buffer_sink,
AVFilterBufferRef **picref, int flags);
#endif
+/**
+ * Get a buffer with filtered data from sink and put it in buf.
+ *
+ * @param sink pointer to a context of a buffersink AVFilter.
+ * @param buf pointer to the buffer will be written here if buf is non-NULL. buf
+ * must be freed by the caller using avfilter_unref_buffer().
+ * Buf may also be NULL to query whether a buffer is ready to be
+ * output.
+ *
+ * @return >= 0 in case of success, a negative AVERROR code in case of
+ * failure.
+ */
+int av_buffersink_read(AVFilterContext *sink, AVFilterBufferRef **buf);
+
#endif /* AVFILTER_BUFFERSINK_H */
diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c
index e71041ecb4..e57a1290aa 100644
--- a/libavfilter/defaults.c
+++ b/libavfilter/defaults.c
@@ -28,6 +28,8 @@
void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr)
{
+ if (ptr->extended_data != ptr->data)
+ av_freep(&ptr->extended_data);
av_free(ptr->data[0]);
av_free(ptr);
}