mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 02:01:12 +00:00
gst/interleave/: Add support for all raw audio formats and provide better negotiation if the caps are changing.
Original commit message from CVS: * gst/interleave/Makefile.am: * gst/interleave/deinterleave.c: (deinterleave_24), (gst_deinterleave_finalize), (gst_deinterleave_base_init), (gst_deinterleave_class_init), (gst_deinterleave_init), (gst_deinterleave_add_new_pads), (gst_deinterleave_set_pads_caps), (gst_deinterleave_set_process_function), (gst_deinterleave_sink_setcaps), (__remove_channels), (__set_channels), (gst_deinterleave_getcaps), (gst_deinterleave_process), (gst_deinterleave_chain), (gst_deinterleave_sink_activate_push): * gst/interleave/deinterleave.h: Add support for all raw audio formats and provide better negotiation if the caps are changing. Don't allow changes of the channel positions and set the position of the corresponding channel on the src pad caps. General cleanup and smaller bugfixes. * tests/check/elements/deinterleave.c: (float_buffer_check_probe): Check the channel positions on the output buffer caps.
This commit is contained in:
parent
e9370329dd
commit
8c254cffdc
4 changed files with 381 additions and 66 deletions
|
@ -2,8 +2,8 @@
|
|||
plugin_LTLIBRARIES = libgstinterleave.la
|
||||
|
||||
libgstinterleave_la_SOURCES = plugin.c interleave.c deinterleave.c
|
||||
libgstinterleave_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstinterleave_la_LIBADD = $(GST_LIBS)
|
||||
libgstinterleave_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
|
||||
libgstinterleave_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR)
|
||||
libgstinterleave_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = plugin.h interleave.h deinterleave.h
|
||||
|
|
|
@ -23,11 +23,19 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
* - handle changes in number of channels
|
||||
* - handle changes in channel positions
|
||||
* - better capsnego by using a buffer alloc function
|
||||
* and passing downstream caps changes upstream there
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
#include "deinterleave.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_deinterleave_debug);
|
||||
|
@ -36,62 +44,131 @@ GST_DEBUG_CATEGORY_STATIC (gst_deinterleave_debug);
|
|||
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_SOMETIMES,
|
||||
GST_STATIC_CAPS ("audio/x-raw-float, "
|
||||
GST_STATIC_CAPS ("audio/x-raw-int, "
|
||||
"rate = (int) [ 1, MAX ], "
|
||||
"channels = (int) 1, "
|
||||
"endianness = (int) BYTE_ORDER, " "width = (int) 32")
|
||||
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
|
||||
"width = (int) { 8, 16, 24, 32 }, "
|
||||
"depth = (int) [ 1, 32 ], "
|
||||
"signed = (boolean) { true, false }; "
|
||||
"audio/x-raw-float, "
|
||||
"rate = (int) [ 1, MAX ], "
|
||||
"channels = (int) 1, "
|
||||
"endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, "
|
||||
"width = (int) { 32, 64 }")
|
||||
);
|
||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("audio/x-raw-float, "
|
||||
GST_STATIC_CAPS ("audio/x-raw-int, "
|
||||
"rate = (int) [ 1, MAX ], "
|
||||
"channels = (int) [ 1, MAX ], "
|
||||
"endianness = (int) BYTE_ORDER, " "width = (int) 32")
|
||||
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
|
||||
"width = (int) { 8, 16, 24, 32 }, "
|
||||
"depth = (int) [ 1, 32 ], "
|
||||
"signed = (boolean) { true, false }; "
|
||||
"audio/x-raw-float, "
|
||||
"rate = (int) [ 1, MAX ], "
|
||||
"channels = (int) [ 1, MAX ], "
|
||||
"endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, "
|
||||
"width = (int) { 32, 64 }")
|
||||
);
|
||||
|
||||
#define MAKE_FUNC(type) \
|
||||
static void deinterleave_##type (guint##type *out, guint##type *in, \
|
||||
guint stride, guint nframes) \
|
||||
{ \
|
||||
gint i; \
|
||||
\
|
||||
for (i = 0; i < nframes; i++) { \
|
||||
out[i] = *in; \
|
||||
in += stride; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_FUNC (8);
|
||||
MAKE_FUNC (16);
|
||||
MAKE_FUNC (32);
|
||||
MAKE_FUNC (64);
|
||||
|
||||
static void
|
||||
deinterleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < nframes; i++) {
|
||||
memcpy (out, in, 3);
|
||||
out += 3;
|
||||
in += stride * 3;
|
||||
}
|
||||
}
|
||||
|
||||
GST_BOILERPLATE (GstDeinterleave, gst_deinterleave, GstElement,
|
||||
GST_TYPE_ELEMENT);
|
||||
|
||||
static GstFlowReturn gst_deinterleave_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static gboolean gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps);
|
||||
static GstCaps *gst_deinterleave_getcaps (GstPad * pad);
|
||||
static gboolean gst_deinterleave_sink_activate_push (GstPad * pad,
|
||||
gboolean active);
|
||||
|
||||
static void
|
||||
gst_deinterleave_finalize (GObject * obj)
|
||||
{
|
||||
GstDeinterleave *self = GST_DEINTERLEAVE (obj);
|
||||
|
||||
if (self->pos) {
|
||||
g_free (self->pos);
|
||||
self->pos = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_deinterleave_base_init (gpointer g_class)
|
||||
{
|
||||
gst_element_class_set_details_simple (g_class, "Audio deinterleaver",
|
||||
GstElementClass *gstelement_class = (GstElementClass *) g_class;
|
||||
|
||||
gst_element_class_set_details_simple (gstelement_class, "Audio deinterleaver",
|
||||
"Filter/Converter/Audio",
|
||||
"Splits one interleaved multichannel audio stream into many mono audio streams",
|
||||
"Andy Wingo <wingo at pobox.com>, " "Iain <iain@prettypeople.org>");
|
||||
|
||||
gst_element_class_add_pad_template (g_class,
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
gst_element_class_add_pad_template (g_class,
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&src_template));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_deinterleave_class_init (GstDeinterleaveClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_deinterleave_debug, "deinterleave", 0,
|
||||
"deinterleave element");
|
||||
|
||||
gobject_class->finalize = gst_deinterleave_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_deinterleave_init (GstDeinterleave * self, GstDeinterleaveClass * klass)
|
||||
{
|
||||
self->sink = gst_pad_new_from_static_template (&sink_template, "sink");
|
||||
self->channels = 0;
|
||||
self->pos = NULL;
|
||||
self->width = 0;
|
||||
self->func = NULL;
|
||||
|
||||
/* Add sink pad */
|
||||
self->sink = gst_pad_new_from_static_template (&sink_template, "sink");
|
||||
gst_pad_set_chain_function (self->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_deinterleave_chain));
|
||||
gst_pad_set_setcaps_function (self->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_deinterleave_sink_setcaps));
|
||||
gst_pad_set_getcaps_function (self->sink, gst_deinterleave_getcaps);
|
||||
gst_pad_set_activatepush_function (self->sink,
|
||||
GST_DEBUG_FUNCPTR (gst_deinterleave_sink_activate_push));
|
||||
|
||||
gst_element_add_pad (GST_ELEMENT (self), self->sink);
|
||||
}
|
||||
|
||||
|
@ -103,20 +180,63 @@ gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps)
|
|||
|
||||
for (i = 0; i < self->channels; i++) {
|
||||
gchar *name = g_strdup_printf ("src%d", i);
|
||||
GstCaps *srccaps;
|
||||
GstStructure *s;
|
||||
|
||||
pad = gst_pad_new_from_static_template (&src_template, name);
|
||||
g_free (name);
|
||||
gst_pad_set_caps (pad, caps);
|
||||
|
||||
/* Set channel position if we know it */
|
||||
if (self->pos) {
|
||||
srccaps = gst_caps_copy (caps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
gst_audio_set_channel_positions (s, &self->pos[i]);
|
||||
} else {
|
||||
srccaps = caps;
|
||||
}
|
||||
|
||||
gst_pad_set_getcaps_function (pad, gst_deinterleave_getcaps);
|
||||
gst_pad_set_caps (pad, srccaps);
|
||||
gst_pad_use_fixed_caps (pad);
|
||||
gst_pad_set_active (pad, TRUE);
|
||||
gst_element_add_pad (GST_ELEMENT (self), pad);
|
||||
self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad));
|
||||
|
||||
if (self->pos)
|
||||
gst_caps_unref (srccaps);
|
||||
}
|
||||
|
||||
gst_element_no_more_pads (GST_ELEMENT (self));
|
||||
self->srcpads = g_list_reverse (self->srcpads);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_deinterleave_set_pads_caps (GstDeinterleave * self, GstCaps * caps)
|
||||
{
|
||||
GList *l;
|
||||
GstStructure *s;
|
||||
gint i;
|
||||
|
||||
for (l = self->srcpads, i = 0; l; l = l->next, i++) {
|
||||
GstPad *pad = GST_PAD (l->data);
|
||||
GstCaps *srccaps;
|
||||
|
||||
/* Set channel position if we know it */
|
||||
if (self->pos) {
|
||||
srccaps = gst_caps_copy (caps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
gst_audio_set_channel_positions (s, &self->pos[i]);
|
||||
} else {
|
||||
srccaps = caps;
|
||||
}
|
||||
|
||||
gst_pad_set_caps (pad, srccaps);
|
||||
|
||||
if (self->pos)
|
||||
gst_caps_unref (srccaps);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_deinterleave_remove_pads (GstDeinterleave * self)
|
||||
{
|
||||
|
@ -137,6 +257,37 @@ gst_deinterleave_remove_pads (GstDeinterleave * self)
|
|||
gst_caps_replace (&self->sinkcaps, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_deinterleave_set_process_function (GstDeinterleave * self, GstCaps * caps)
|
||||
{
|
||||
GstStructure *s;
|
||||
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
if (!gst_structure_get_int (s, "width", &self->width))
|
||||
return FALSE;
|
||||
|
||||
switch (self->width) {
|
||||
case 8:
|
||||
self->func = (GstDeinterleaveFunc) deinterleave_8;
|
||||
break;
|
||||
case 16:
|
||||
self->func = (GstDeinterleaveFunc) deinterleave_16;
|
||||
break;
|
||||
case 24:
|
||||
self->func = (GstDeinterleaveFunc) deinterleave_24;
|
||||
break;
|
||||
case 32:
|
||||
self->func = (GstDeinterleaveFunc) deinterleave_32;
|
||||
break;
|
||||
case 64:
|
||||
self->func = (GstDeinterleaveFunc) deinterleave_64;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
|
@ -146,52 +297,72 @@ gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps)
|
|||
|
||||
self = GST_DEINTERLEAVE (gst_pad_get_parent (pad));
|
||||
|
||||
if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) {
|
||||
GList *l;
|
||||
gint new_channels;
|
||||
GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps);
|
||||
|
||||
if (!caps)
|
||||
goto cannot_change_caps;
|
||||
if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) {
|
||||
gint new_channels;
|
||||
GstAudioChannelPosition *pos;
|
||||
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
|
||||
/* We allow caps changes as long as the number of channels doesn't change */
|
||||
/* We allow caps changes as long as the number of channels doesn't change
|
||||
* and the channel positions stay the same. _getcaps() should've cared
|
||||
* for this already but better be safe.
|
||||
*/
|
||||
if (!gst_structure_get_int (s, "channels", &new_channels) ||
|
||||
new_channels != self->channels)
|
||||
new_channels != self->channels ||
|
||||
!gst_deinterleave_set_process_function (self, caps))
|
||||
goto cannot_change_caps;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps);
|
||||
gst_caps_replace (&self->sinkcaps, caps);
|
||||
if (gst_structure_has_field (s, "channel-positions")) {
|
||||
gint i;
|
||||
gboolean same = TRUE;
|
||||
|
||||
/* Set new caps on all srcpads */
|
||||
srccaps = gst_caps_copy (caps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
|
||||
gst_structure_remove_field (s, "channel-positions");
|
||||
if (!self->pos)
|
||||
goto cannot_change_caps;
|
||||
|
||||
for (l = self->srcpads; l; l = l->next) {
|
||||
GstPad *pad = GST_PAD (l->data);
|
||||
pos = gst_audio_get_channel_positions (s);
|
||||
for (i = 0; i < self->channels; i++) {
|
||||
if (self->pos[i] != pos[i]) {
|
||||
same = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gst_pad_set_caps (pad, srccaps))
|
||||
g_free (pos);
|
||||
if (!same)
|
||||
goto cannot_change_caps;
|
||||
}
|
||||
|
||||
gst_caps_unref (srccaps);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps);
|
||||
gst_caps_replace (&self->sinkcaps, caps);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
|
||||
/* Add all srcpads */
|
||||
srccaps = gst_caps_copy (caps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
if (!gst_structure_get_int (s, "channels", &self->channels))
|
||||
goto no_channels;
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
|
||||
gst_structure_remove_field (s, "channel-positions");
|
||||
gst_deinterleave_add_new_pads (self, srccaps);
|
||||
gst_caps_unref (srccaps);
|
||||
|
||||
if (!gst_deinterleave_set_process_function (self, caps))
|
||||
goto unsupported_caps;
|
||||
|
||||
if (gst_structure_has_field (s, "channel-positions"))
|
||||
self->pos = gst_audio_get_channel_positions (s);
|
||||
}
|
||||
|
||||
gst_caps_replace (&self->sinkcaps, caps);
|
||||
|
||||
/* Get srcpad caps */
|
||||
srccaps = gst_caps_copy (caps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
|
||||
gst_structure_remove_field (s, "channel-positions");
|
||||
|
||||
/* If we already have pads, update the caps otherwise
|
||||
* add new pads */
|
||||
if (self->srcpads) {
|
||||
gst_deinterleave_set_pads_caps (self, srccaps);
|
||||
} else {
|
||||
gst_deinterleave_add_new_pads (self, srccaps);
|
||||
}
|
||||
|
||||
gst_caps_unref (srccaps);
|
||||
gst_object_unref (self);
|
||||
|
||||
return TRUE;
|
||||
|
@ -202,6 +373,12 @@ cannot_change_caps:
|
|||
gst_object_unref (self);
|
||||
return FALSE;
|
||||
}
|
||||
unsupported_caps:
|
||||
{
|
||||
GST_ERROR_OBJECT (self, "caps not supported: %" GST_PTR_FORMAT, caps);
|
||||
gst_object_unref (self);
|
||||
return FALSE;
|
||||
}
|
||||
no_channels:
|
||||
{
|
||||
GST_ERROR_OBJECT (self, "invalid caps");
|
||||
|
@ -210,21 +387,114 @@ no_channels:
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
__remove_channels (GstCaps * caps)
|
||||
{
|
||||
GstStructure *s;
|
||||
gint i, size;
|
||||
|
||||
size = gst_caps_get_size (caps);
|
||||
for (i = 0; i < size; i++) {
|
||||
s = gst_caps_get_structure (caps, i);
|
||||
gst_structure_remove_field (s, "channel-positions");
|
||||
gst_structure_remove_field (s, "channels");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
__set_channels (GstCaps * caps, gint channels)
|
||||
{
|
||||
GstStructure *s;
|
||||
gint i, size;
|
||||
|
||||
size = gst_caps_get_size (caps);
|
||||
for (i = 0; i < size; i++) {
|
||||
s = gst_caps_get_structure (caps, i);
|
||||
if (channels > 0)
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
|
||||
else
|
||||
gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_deinterleave_getcaps (GstPad * pad)
|
||||
{
|
||||
GstDeinterleave *self = GST_DEINTERLEAVE (gst_pad_get_parent (pad));
|
||||
GstCaps *ret;
|
||||
GList *l;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
/* Intersect all of our pad template caps with the peer caps of the pad
|
||||
* to get all formats that are possible up- and downstream.
|
||||
*
|
||||
* For the pad for which the caps are requested we don't remove the channel
|
||||
* informations as they must be in the returned caps and incompatibilities
|
||||
* will be detected here already
|
||||
*/
|
||||
ret = gst_caps_new_any ();
|
||||
for (l = GST_ELEMENT (self)->pads; l != NULL; l = l->next) {
|
||||
GstPad *ourpad = GST_PAD (l->data);
|
||||
GstCaps *peercaps, *ourcaps;
|
||||
|
||||
ourcaps = gst_caps_copy (gst_pad_get_pad_template_caps (ourpad));
|
||||
|
||||
if (pad == ourpad) {
|
||||
if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK)
|
||||
__set_channels (ourcaps, self->channels);
|
||||
else
|
||||
__set_channels (ourcaps, 1);
|
||||
} else {
|
||||
__remove_channels (ourcaps);
|
||||
}
|
||||
|
||||
peercaps = gst_pad_peer_get_caps (ourpad);
|
||||
if (pad != ourpad && peercaps)
|
||||
__remove_channels (peercaps);
|
||||
|
||||
/* If the peer exists and has caps add them to the intersection,
|
||||
* otherwise assume that the peer accepts everything */
|
||||
if (peercaps) {
|
||||
GstCaps *intersection;
|
||||
GstCaps *oldret = ret;
|
||||
|
||||
intersection = gst_caps_intersect (peercaps, ourcaps);
|
||||
|
||||
ret = gst_caps_intersect (ret, intersection);
|
||||
gst_caps_unref (intersection);
|
||||
gst_caps_unref (peercaps);
|
||||
gst_caps_unref (oldret);
|
||||
} else {
|
||||
GstCaps *oldret = ret;
|
||||
|
||||
ret = gst_caps_intersect (ret, ourcaps);
|
||||
gst_caps_unref (oldret);
|
||||
}
|
||||
gst_caps_unref (ourcaps);
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
gst_object_unref (self);
|
||||
|
||||
GST_DEBUG_OBJECT (pad, "Intersected caps to %" GST_PTR_FORMAT, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK; /* initialized to silence a warning */
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint channels = self->channels;
|
||||
guint pads_pushed = 0, buffers_allocated = 0;
|
||||
guint nframes = GST_BUFFER_SIZE (buf) / channels / (self->width / 8);
|
||||
guint bufsize = nframes * (self->width / 8);
|
||||
guint i;
|
||||
GList *srcs;
|
||||
guint bufsize, i, j, channels, pads_pushed, buffers_allocated, nframes;
|
||||
GstBuffer **buffers_out;
|
||||
gfloat *in, *out;
|
||||
|
||||
channels = self->channels;
|
||||
buffers_out = g_new0 (GstBuffer *, channels);
|
||||
nframes = GST_BUFFER_SIZE (buf) / channels / sizeof (gfloat);
|
||||
bufsize = nframes * sizeof (gfloat);
|
||||
pads_pushed = 0;
|
||||
buffers_allocated = 0;
|
||||
GstBuffer **buffers_out = g_new0 (GstBuffer *, channels);
|
||||
guint8 *in, *out;
|
||||
|
||||
/* Allocate buffers */
|
||||
for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) {
|
||||
|
@ -235,10 +505,16 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf)
|
|||
gst_pad_alloc_buffer (pad, GST_BUFFER_OFFSET_NONE, bufsize,
|
||||
GST_PAD_CAPS (pad), &buffers_out[i]);
|
||||
|
||||
/* Make sure we got a correct buffer. The only other case we allow
|
||||
* here is an unliked pad */
|
||||
if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
|
||||
goto alloc_buffer_failed;
|
||||
if (buffers_out[i] && GST_BUFFER_SIZE (buffers_out[i]) != bufsize)
|
||||
else if (buffers_out[i] && GST_BUFFER_SIZE (buffers_out[i]) != bufsize)
|
||||
goto alloc_buffer_bad_size;
|
||||
else if (buffers_out[i] &&
|
||||
!gst_caps_is_equal (GST_BUFFER_CAPS (buffers_out[i]),
|
||||
GST_PAD_CAPS (pad)))
|
||||
goto invalid_caps;
|
||||
|
||||
if (buffers_out[i]) {
|
||||
gst_buffer_copy_metadata (buffers_out[i], buf,
|
||||
|
@ -247,7 +523,7 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return NOT_LINKED if we couldn't allocate any buffers */
|
||||
/* Return NOT_LINKED if no pad was linked */
|
||||
if (!buffers_allocated) {
|
||||
ret = GST_FLOW_NOT_LINKED;
|
||||
goto done;
|
||||
|
@ -257,12 +533,12 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf)
|
|||
for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) {
|
||||
GstPad *pad = (GstPad *) srcs->data;
|
||||
|
||||
in = (gfloat *) GST_BUFFER_DATA (buf);
|
||||
in += i; /* gfloat * arith */
|
||||
in = (guint8 *) GST_BUFFER_DATA (buf);
|
||||
in += i * (self->width / 8);
|
||||
if (buffers_out[i]) {
|
||||
out = (gfloat *) GST_BUFFER_DATA (buffers_out[i]);
|
||||
for (j = 0; j < nframes * channels; j += channels)
|
||||
*out++ = in[j];
|
||||
out = (guint8 *) GST_BUFFER_DATA (buffers_out[i]);
|
||||
|
||||
self->func (out, in, channels, nframes);
|
||||
|
||||
ret = gst_pad_push (pad, buffers_out[i]);
|
||||
buffers_out[i] = NULL;
|
||||
|
@ -275,6 +551,7 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return NOT_LINKED if no pad was linked */
|
||||
if (!pads_pushed)
|
||||
ret = GST_FLOW_NOT_LINKED;
|
||||
|
||||
|
@ -295,6 +572,12 @@ alloc_buffer_bad_size:
|
|||
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||
goto clean_buffers;
|
||||
}
|
||||
invalid_caps:
|
||||
{
|
||||
GST_WARNING ("called alloc_buffer(), but didn't get requested caps");
|
||||
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||
goto clean_buffers;
|
||||
}
|
||||
push_failed:
|
||||
{
|
||||
GST_DEBUG ("push() failed, flow = %s", gst_flow_get_name (ret));
|
||||
|
@ -315,15 +598,17 @@ clean_buffers:
|
|||
static GstFlowReturn
|
||||
gst_deinterleave_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstDeinterleave *self;
|
||||
GstDeinterleave *self = GST_DEINTERLEAVE (GST_PAD_PARENT (pad));
|
||||
GstFlowReturn ret;
|
||||
|
||||
self = GST_DEINTERLEAVE (GST_PAD_PARENT (pad));
|
||||
g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
|
||||
g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED);
|
||||
g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED);
|
||||
|
||||
ret = gst_deinterleave_process (self, buffer);
|
||||
|
||||
if (ret != GST_FLOW_OK)
|
||||
GST_DEBUG_OBJECT (self, "flow: %s", gst_flow_get_name (ret));
|
||||
GST_DEBUG_OBJECT (self, "flow return: %s", gst_flow_get_name (ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -331,12 +616,19 @@ gst_deinterleave_chain (GstPad * pad, GstBuffer * buffer)
|
|||
static gboolean
|
||||
gst_deinterleave_sink_activate_push (GstPad * pad, gboolean active)
|
||||
{
|
||||
GstDeinterleave *self;
|
||||
GstDeinterleave *self = GST_DEINTERLEAVE (gst_pad_get_parent (pad));
|
||||
|
||||
self = GST_DEINTERLEAVE (gst_pad_get_parent (pad));
|
||||
|
||||
if (!active)
|
||||
/* Reset everything when the pad is deactivated */
|
||||
if (!active) {
|
||||
gst_deinterleave_remove_pads (self);
|
||||
if (self->pos) {
|
||||
g_free (self->pos);
|
||||
self->pos = NULL;
|
||||
}
|
||||
self->channels = 0;
|
||||
self->width = 0;
|
||||
self->func = NULL;
|
||||
}
|
||||
|
||||
gst_object_unref (self);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
G_BEGIN_DECLS
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/audio/multichannel.h>
|
||||
|
||||
#define GST_TYPE_DEINTERLEAVE (gst_deinterleave_get_type())
|
||||
#define GST_DEINTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLEAVE,GstDeinterleave))
|
||||
|
@ -41,6 +42,8 @@ G_BEGIN_DECLS
|
|||
typedef struct _GstDeinterleave GstDeinterleave;
|
||||
typedef struct _GstDeinterleaveClass GstDeinterleaveClass;
|
||||
|
||||
typedef void (*GstDeinterleaveFunc) (gpointer out, gpointer in, guint stride, guint nframes);
|
||||
|
||||
struct _GstDeinterleave
|
||||
{
|
||||
GstElement element;
|
||||
|
@ -49,8 +52,12 @@ struct _GstDeinterleave
|
|||
GList *srcpads;
|
||||
GstCaps *sinkcaps;
|
||||
gint channels;
|
||||
GstAudioChannelPosition *pos;
|
||||
|
||||
GstPad *sink;
|
||||
|
||||
gint width;
|
||||
GstDeinterleaveFunc func;
|
||||
};
|
||||
|
||||
struct _GstDeinterleaveClass
|
||||
|
|
|
@ -55,7 +55,7 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("audio/x-raw-float, "
|
||||
"width = (int) 32, "
|
||||
"channels = (int) 2, "
|
||||
"channels = (int) { 2, 3 }, "
|
||||
"rate = (int) {32000, 48000}, " "endianness = (int) BYTE_ORDER"));
|
||||
|
||||
#define CAPS_32khz \
|
||||
|
@ -417,14 +417,30 @@ float_buffer_check_probe (GstPad * pad, GstBuffer * buf, gpointer userdata)
|
|||
gfloat *data;
|
||||
guint padnum, numpads;
|
||||
guint num, i;
|
||||
GstCaps *caps;
|
||||
GstStructure *s;
|
||||
GstAudioChannelPosition *pos;
|
||||
gint channels;
|
||||
|
||||
fail_unless_equals_int (sscanf (GST_PAD_NAME (pad), "src%u", &padnum), 1);
|
||||
|
||||
numpads = pads_created;
|
||||
|
||||
/* Check caps */
|
||||
caps = GST_BUFFER_CAPS (buf);
|
||||
fail_unless (caps != NULL);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
fail_unless (gst_structure_get_int (s, "channels", &channels));
|
||||
fail_unless_equals_int (channels, 1);
|
||||
fail_unless (gst_structure_has_field (s, "channel-positions"));
|
||||
pos = gst_audio_get_channel_positions (s);
|
||||
fail_unless (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE);
|
||||
g_free (pos);
|
||||
|
||||
data = (gfloat *) GST_BUFFER_DATA (buf);
|
||||
num = GST_BUFFER_SIZE (buf) / sizeof (gfloat);
|
||||
|
||||
/* Check buffer content */
|
||||
for (i = 0; i < num; ++i) {
|
||||
guint val, rest;
|
||||
|
||||
|
|
Loading…
Reference in a new issue