port audioconvert to basetransform fix ffmpegcsp and videoscale for basetransform changes

Original commit message from CVS:
port audioconvert to basetransform
fix ffmpegcsp and videoscale for basetransform changes
This commit is contained in:
Thomas Vander Stichele 2005-08-24 13:32:52 +00:00
parent 80ad4cff17
commit 41a43b86a8
6 changed files with 298 additions and 447 deletions

View file

@ -1,3 +1,23 @@
2005-08-24 Thomas Vander Stichele <thomas at apestaart dot org>
* gst/audioconvert/gstaudioconvert.c:
(gst_audio_convert_class_init), (gst_audio_convert_init),
(audio_convert_get_unit_size), (audio_convert_transform_caps),
(audio_convert_fixate_caps), (audio_convert_set_caps),
(audio_convert_transform),
(gst_audio_convert_buffer_to_default_format),
(gst_audio_convert_buffer_from_default_format),
(gst_audio_convert_channels):
* gst/audioconvert/gstchannelmix.c:
* gst/audioconvert/gstchannelmix.h:
port to basetransform
* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
(gst_ffmpegcsp_transform_caps), (gst_ffmpegcsp_class_init),
(gst_ffmpegcsp_get_unit_size):
* gst/videoscale/gstvideoscale.c: (gst_videoscale_class_init),
(gst_videoscale_transform_caps), (gst_videoscale_get_unit_size):
fix for basetransform changes
2005-08-24 Jan Schmidt <thaytan@mad.scientist.com>
* check/Makefile.am:

View file

@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
* Copyright (C) 2005 Thomas Vander Stichele <thomas at apestaart dot org>
*
* gstaudioconvert.c: Convert audio to different audio formats automatically
*
@ -18,12 +19,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* Element-Checklist-Version: 5 */
/*
* design decisions:
* - audioconvert converts buffers in a set of supported caps. If it supports
* a caps, it supports conversion from these caps to any other caps it
* - audioconvert converts buffers in a set of supported caps. If it supports
* a caps, it supports conversion from these caps to any other caps it
* supports. (example: if it does A=>B and A=>C, it also does B=>C)
* - audioconvert does not save state between buffers. Every incoming buffer is
* converted and the converted buffer is pushed out.
@ -37,6 +37,7 @@
#endif
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/audio/multichannel.h>
#include <string.h>
#include "gstchannelmix.h"
@ -44,6 +45,10 @@
GST_DEBUG_CATEGORY (audio_convert_debug);
/* int to float conversion: int2float(i) = 1 / (2^31-1) * i */
#define INT2FLOAT(i) (4.6566128752457969e-10 * ((gfloat)i))
/*** DEFINITIONS **************************************************************/
static GstElementDetails audio_convert_details = {
@ -60,15 +65,6 @@ static void gst_audio_convert_init (GstAudioConvert * audio_convert);
static void gst_audio_convert_dispose (GObject * obj);
/* gstreamer functions */
static GstFlowReturn gst_audio_convert_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_audio_convert_link_src (GstAudioConvert * this,
GstCaps * sinkcaps, GstAudioConvertCaps * sink_ac_caps);
static gboolean gst_audio_convert_setcaps (GstPad * pad, GstCaps * caps);
static void gst_audio_convert_fixate (GstPad * pad, GstCaps * caps);
static GstCaps *gst_audio_convert_getcaps (GstPad * pad);
static GstElementStateReturn gst_audio_convert_change_state (GstElement *
element);
static GstBuffer *gst_audio_convert_buffer_to_default_format (GstAudioConvert *
this, GstBuffer * buf);
static GstBuffer *gst_audio_convert_buffer_from_default_format (GstAudioConvert
@ -77,6 +73,21 @@ static GstBuffer *gst_audio_convert_buffer_from_default_format (GstAudioConvert
static GstBuffer *gst_audio_convert_channels (GstAudioConvert * this,
GstBuffer * buf);
static gboolean gst_audio_convert_parse_caps (const GstCaps * gst_caps,
GstAudioConvertCaps * caps);
gboolean audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
guint * size);
GstCaps *audio_convert_transform_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps);
void audio_convert_fixate_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
gboolean audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps);
static GstFlowReturn
audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
GstBuffer * outbuf);
/* AudioConvert signals and args */
enum
{
@ -93,8 +104,8 @@ enum
#define DEBUG_INIT(bla) \
GST_DEBUG_CATEGORY_INIT (audio_convert_debug, "audioconvert", 0, "audio conversion element");
GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstElement,
GST_TYPE_ELEMENT, DEBUG_INIT);
GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
/*** GSTREAMER PROTOTYPES *****************************************************/
@ -138,6 +149,8 @@ GST_STATIC_CAPS ( \
static GstAudioChannelPosition *supported_positions;
static GstStaticCaps gst_audio_convert_static_caps = STATIC_CAPS;
static GstStaticPadTemplate gst_audio_convert_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
@ -167,42 +180,31 @@ gst_audio_convert_base_init (gpointer g_class)
static void
gst_audio_convert_class_init (GstAudioConvertClass * klass)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gint i;
gstelement_class->change_state = gst_audio_convert_change_state;
gobject_class->dispose = gst_audio_convert_dispose;
supported_positions = g_new0 (GstAudioChannelPosition,
GST_AUDIO_CHANNEL_POSITION_NUM);
for (i = 0; i < GST_AUDIO_CHANNEL_POSITION_NUM; i++)
supported_positions[i] = i;
GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
GST_DEBUG_FUNCPTR (audio_convert_get_unit_size);
GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
GST_DEBUG_FUNCPTR (audio_convert_transform_caps);
GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
GST_DEBUG_FUNCPTR (audio_convert_fixate_caps);
GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
GST_DEBUG_FUNCPTR (audio_convert_set_caps);
GST_BASE_TRANSFORM_CLASS (klass)->transform =
GST_DEBUG_FUNCPTR (audio_convert_transform);
}
static void
gst_audio_convert_init (GstAudioConvert * this)
{
/* sinkpad */
this->sink =
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_audio_convert_sink_template), "sink");
gst_pad_set_getcaps_function (this->sink, gst_audio_convert_getcaps);
gst_pad_set_setcaps_function (this->sink, gst_audio_convert_setcaps);
gst_pad_set_fixatecaps_function (this->sink, gst_audio_convert_fixate);
gst_element_add_pad (GST_ELEMENT (this), this->sink);
/* srcpad */
this->src =
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_audio_convert_src_template), "src");
gst_pad_set_getcaps_function (this->src, gst_audio_convert_getcaps);
//gst_pad_set_setcaps_function (this->src, gst_audio_convert_setcaps);
gst_pad_set_fixatecaps_function (this->src, gst_audio_convert_fixate);
gst_element_add_pad (GST_ELEMENT (this), this->src);
gst_pad_set_chain_function (this->sink, gst_audio_convert_chain);
/* clear important variables */
this->convert_internal = NULL;
this->sinkcaps.pos = NULL;
@ -229,13 +231,135 @@ gst_audio_convert_dispose (GObject * obj)
/*** GSTREAMER FUNCTIONS ******************************************************/
static GstFlowReturn
gst_audio_convert_chain (GstPad * pad, GstBuffer * buf)
/* BaseTransform vmethods */
gboolean
audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
guint * size)
{
GstAudioConvert *this;
GstFlowReturn ret;
GstAudioConvertCaps ac_caps;
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
g_return_val_if_fail (size, FALSE);
memset (&ac_caps, 0, sizeof (ac_caps));
if (!gst_audio_convert_parse_caps (caps, &ac_caps))
return FALSE;
*size = ac_caps.width * ac_caps.channels / 8;
return TRUE;
}
/* audioconvert can convert anything except sample rate; so return template
* caps with rate fixed */
/* FIXME:
* it would be smart here to return the caps with the same width as the first
*/
GstCaps *
audio_convert_transform_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps)
{
int i;
const GValue *rate;
g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
GstStructure *structure = gst_caps_get_structure (caps, 0);
GstCaps *ret = gst_static_caps_get (&gst_audio_convert_static_caps);
ret = gst_caps_make_writable (ret);
rate = gst_structure_get_value (structure, "rate");
if (!rate) {
return ret;
}
for (i = 0; i < gst_caps_get_size (ret); ++i) {
structure = gst_caps_get_structure (ret, i);
gst_structure_set_value (structure, "rate", rate);
}
return ret;
}
/* try to keep as many of the structure members the same by fixating the
* possible ranges; this way we convert the least amount of things as possible
*/
void
audio_convert_fixate_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
{
GstStructure *ins, *outs;
gint rate, endianness, depth;
gboolean signedness;
g_return_if_fail (gst_caps_is_fixed (caps));
GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
" based on caps %" GST_PTR_FORMAT, othercaps, caps);
ins = gst_caps_get_structure (caps, 0);
outs = gst_caps_get_structure (othercaps, 0);
if (gst_structure_get_int (ins, "rate", &rate)) {
if (gst_structure_has_field (outs, "rate")) {
gst_caps_structure_fixate_field_nearest_int (outs, "rate", rate);
}
}
if (gst_structure_get_int (ins, "endianness", &endianness)) {
if (gst_structure_has_field (outs, "endianness")) {
gst_caps_structure_fixate_field_nearest_int (outs, "endianness",
endianness);
}
}
if (gst_structure_get_int (ins, "depth", &depth)) {
if (gst_structure_has_field (outs, "depth")) {
gst_caps_structure_fixate_field_nearest_int (outs, "depth", depth);
}
}
if (gst_structure_get_boolean (ins, "signed", &signedness)) {
if (gst_structure_has_field (outs, "signed")) {
gst_caps_structure_fixate_field_boolean (outs, "signed", signedness);
}
}
GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
}
gboolean
audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps)
{
GstAudioConvertCaps in_ac_caps = { 0 };
GstAudioConvertCaps out_ac_caps = { 0 };
GstAudioConvert *this = GST_AUDIO_CONVERT (base);
GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps);
in_ac_caps.pos = NULL;
if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps))
return FALSE;
out_ac_caps.pos = NULL;
if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps))
return FALSE;
this->sinkcaps = in_ac_caps;
this->srccaps = out_ac_caps;
GST_DEBUG ("setting up matrix");
gst_audio_convert_setup_matrix (this);
GST_DEBUG ("set up matrix, %p", this->matrix);
return TRUE;
}
static GstFlowReturn
audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstAudioConvert *this = GST_AUDIO_CONVERT (base);
GstBuffer *buf;
/*
* Theory of operation:
@ -244,116 +368,20 @@ gst_audio_convert_chain (GstPad * pad, GstBuffer * buf)
* - convert rate and channels
* - convert back to output format
*/
if (!GST_PAD_CAPS (this->sink)) {
goto not_negotiated;
} else if (!GST_PAD_CAPS (this->src)) {
if (!gst_audio_convert_link_src (this,
GST_PAD_CAPS (this->sink), &this->sinkcaps))
goto no_format;
} else if (!this->matrix) {
gst_audio_convert_setup_matrix (this);
}
/* FIXME: optimize for copying */
buf = gst_buffer_copy (inbuf);
buf = gst_audio_convert_buffer_to_default_format (this, buf);
buf = gst_audio_convert_channels (this, buf);
buf = gst_audio_convert_buffer_from_default_format (this, buf);
memcpy (GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (outbuf));
gst_buffer_unref (buf);
ret = gst_pad_push (this->src, buf);
return ret;
not_negotiated:
{
GST_ELEMENT_ERROR (this, CORE, NEGOTIATION, (NULL),
("Pad not negotiated before chain function was called"));
gst_buffer_unref (buf);
return GST_FLOW_NOT_NEGOTIATED;
}
no_format:
{
GST_ELEMENT_ERROR (this, CORE, NEGOTIATION, (NULL),
("Could not negotiate format"));
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
}
static GstCaps *
gst_audio_convert_caps_remove_format_info (GstPad * pad, GstCaps * caps)
{
int i, size;
GstAudioConvert *this;
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
size = gst_caps_get_size (caps);
caps = gst_caps_make_writable (caps);
for (i = size - 1; i >= 0; i--) {
GstStructure *structure;
structure = gst_caps_get_structure (caps, i);
gst_structure_remove_field (structure, "channels");
gst_structure_remove_field (structure, "channel-positions");
gst_structure_remove_field (structure, "endianness");
gst_structure_remove_field (structure, "width");
gst_structure_remove_field (structure, "depth");
gst_structure_remove_field (structure, "signed");
structure = gst_structure_copy (structure);
if (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0) {
gst_structure_set_name (structure, "audio/x-raw-float");
if (pad == this->sink) {
gst_structure_set (structure, "buffer-frames", GST_TYPE_INT_RANGE, 0,
G_MAXINT, NULL);
} else {
gst_structure_set (structure, "buffer-frames", G_TYPE_INT, 0, NULL);
}
} else {
gst_structure_set_name (structure, "audio/x-raw-int");
gst_structure_remove_field (structure, "buffer-frames");
}
gst_caps_append_structure (caps, structure);
}
return caps;
}
/* this function is complicated now, but it will be unnecessary when we convert
* rate. */
static GstCaps *
gst_audio_convert_getcaps (GstPad * pad)
{
GstAudioConvert *this;
GstPad *otherpad;
GstCaps *othercaps, *caps;
const GstCaps *templcaps;
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
otherpad = (pad == this->src) ? this->sink : this->src;
/* we can do all our peer can */
othercaps = gst_pad_peer_get_caps (otherpad);
if (othercaps != NULL) {
/* without the format info even */
othercaps = gst_audio_convert_caps_remove_format_info (pad, othercaps);
/* but filtered against our template */
templcaps = gst_pad_get_pad_template_caps (pad);
caps = gst_caps_intersect (othercaps, templcaps);
gst_caps_unref (othercaps);
} else {
/* no peer, then our template is enough */
caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
}
/* Get the channel positions in as well. */
gst_audio_set_caps_channel_positions_list (caps, supported_positions,
GST_AUDIO_CHANNEL_POSITION_NUM);
return caps;
return GST_FLOW_OK;
}
/* convert the given GstCaps to our ghetto format */
static gboolean
gst_audio_convert_parse_caps (const GstCaps * gst_caps,
GstAudioConvertCaps * caps)
@ -400,227 +428,6 @@ gst_audio_convert_parse_caps (const GstCaps * gst_caps,
return TRUE;
}
static gboolean
gst_audio_convert_link_src (GstAudioConvert * this,
GstCaps * sinkcaps, GstAudioConvertCaps * sink_ac_caps)
{
GstAudioConvertCaps ac_caps = { 0 };
if (gst_pad_peer_accept_caps (this->src, sinkcaps)) {
/* great, so that will be our suggestion then */
this->src_prefered = gst_caps_ref (sinkcaps);
gst_caps_replace (&GST_PAD_CAPS (this->src), sinkcaps);
ac_caps = *sink_ac_caps;
if (ac_caps.pos) {
ac_caps.pos = g_memdup (ac_caps.pos, sizeof (gint) * ac_caps.channels);
}
} else {
/* nope, find something we can convert to and the peer can
* accept. */
GstCaps *othercaps = gst_pad_peer_get_caps (this->src);
if (othercaps) {
/* peel off first one */
GstCaps *targetcaps = gst_caps_copy_nth (othercaps, 0);
GstStructure *structure = gst_caps_get_structure (targetcaps, 0);
gst_caps_unref (othercaps);
/* set the rate on the caps, this has to work */
gst_structure_set (structure,
"rate", G_TYPE_INT, sink_ac_caps->rate,
"channels", G_TYPE_INT, sink_ac_caps->channels, NULL);
/* if there is a choice, prefer no conversion */
gst_caps_structure_fixate_field_nearest_int (structure,
"endianness", sink_ac_caps->endianness);
if (strcmp (gst_structure_get_name (structure), "audio/x-raw-float") == 0) {
if (!sink_ac_caps->is_int) {
/* copy over */
gst_structure_set (structure, "buffer-frames", G_TYPE_INT,
ac_caps.buffer_frames, NULL);
} else {
/* set to anything */
gst_structure_set (structure, "buffer-frames", G_TYPE_INT, 0, NULL);
}
}
/* this will be our suggestion */
this->src_prefered = targetcaps;
if (!gst_audio_convert_parse_caps (targetcaps, &ac_caps))
return FALSE;
gst_caps_replace (&GST_PAD_CAPS (this->src), targetcaps);
}
}
this->srccaps = ac_caps;
GST_DEBUG_OBJECT (this, "negotiated pad to %" GST_PTR_FORMAT, sinkcaps);
return TRUE;
}
static gboolean
gst_audio_convert_setcaps (GstPad * pad, GstCaps * caps)
{
GstAudioConvert *this;
GstAudioConvertCaps ac_caps = { 0 };
gboolean res;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)), FALSE);
g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
/* we'll need a new matrix after every new negotiation */
gst_audio_convert_unset_matrix (this);
ac_caps.pos = NULL;
if (!gst_audio_convert_parse_caps (caps, &ac_caps))
return FALSE;
this->sink_prefered = caps;
if ((res = gst_audio_convert_link_src (this, caps, &ac_caps))) {
this->sinkcaps = ac_caps;
GST_DEBUG_OBJECT (this, "negotiated pad to %" GST_PTR_FORMAT, caps);
}
return res;
}
/* tries to fixate the given field of the given caps to the given int value */
gboolean
_fixate_caps_to_int (GstCaps * caps, const gchar * field, gint value)
{
gboolean changed = FALSE;
guint i;
/* FIXME: why don't we already return here when ret == TRUE ? */
for (i = 0; i < gst_caps_get_size (caps); i++) {
GstStructure *structure = gst_caps_get_structure (caps, i);
if (gst_structure_has_field (structure, field))
changed |=
gst_caps_structure_fixate_field_nearest_int (structure, field, value);
}
return changed;
}
static void
gst_audio_convert_fixate (GstPad * pad, GstCaps * caps)
{
const GValue *pos_val;
GstPad *otherpad;
GstAudioConvert *this;
GstAudioConvertCaps try, ac_caps;
this = GST_AUDIO_CONVERT (GST_PAD_PARENT (pad));
otherpad = (pad == this->sink ? this->src : this->sink);
ac_caps = (pad == this->sink ? this->srccaps : this->sinkcaps);
if (!GST_PAD_IS_IN_SETCAPS (otherpad)) {
try.channels = ac_caps.channels;
try.width = ac_caps.is_int ? ac_caps.width : 16;
try.depth = ac_caps.is_int ? ac_caps.depth : 16;
try.endianness = ac_caps.is_int ? ac_caps.endianness : G_BYTE_ORDER;
} else {
try.channels = 2;
try.width = 16;
try.depth = 16;
try.endianness = G_BYTE_ORDER;
}
if (_fixate_caps_to_int (caps, "channels", try.channels)) {
int n, c;
gst_structure_get_int (gst_caps_get_structure (caps, 0), "channels", &c);
if (c > 2) {
/* make sure we have a channelpositions structure or array here */
GstStructure *str;
for (n = 0; n < gst_caps_get_size (caps); n++) {
str = gst_caps_get_structure (caps, n);
if (!gst_structure_get_value (str, "channel-positions")) {
/* first try otherpad's positions, else anything */
if (ac_caps.pos != NULL && c == ac_caps.channels) {
gst_audio_set_channel_positions (str, ac_caps.pos);
} else {
gst_audio_set_structure_channel_positions_list (str,
supported_positions, GST_AUDIO_CHANNEL_POSITION_NUM);
/* FIXME: fixate (else we'll be less fixed than we used to) */
}
}
}
} else {
/* make sure we don't */
for (n = 0; n < gst_caps_get_size (caps); n++) {
gst_structure_remove_field (gst_caps_get_structure (caps, n),
"channel-positions");
}
}
}
_fixate_caps_to_int (caps, "width", try.width);
if (gst_structure_get_name (gst_caps_get_structure (caps, 0))[12] == 'i') {
_fixate_caps_to_int (caps, "depth", try.depth);
}
_fixate_caps_to_int (caps, "endianness", try.endianness);
if ((pos_val = gst_structure_get_value (gst_caps_get_structure (caps, 0),
"channel-positions")) != NULL) {
GstAudioChannelPosition *pos;
const GValue *pos_val_entry;
gint i;
for (i = 0; i < gst_value_list_get_size (pos_val); i++) {
pos_val_entry = gst_value_list_get_value (pos_val, i);
if (G_VALUE_TYPE (pos_val_entry) == GST_TYPE_LIST) {
/* unfixed */
pos =
gst_audio_fixate_channel_positions (gst_caps_get_structure (caps,
0));
if (pos) {
gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0),
pos);
g_free (pos);
pos = NULL;
}
}
}
}
}
static GstElementStateReturn
gst_audio_convert_change_state (GstElement * element)
{
GstElementStateReturn ret;
GstAudioConvert *this = GST_AUDIO_CONVERT (element);
gint transition;
transition = GST_STATE_TRANSITION (element);
switch (transition) {
default:
break;
}
ret = parent_class->change_state (element);
switch (transition) {
case GST_STATE_PAUSED_TO_READY:
this->convert_internal = NULL;
gst_audio_convert_unset_matrix (this);
gst_caps_replace (&GST_PAD_CAPS (this->sink), NULL);
gst_caps_replace (&GST_PAD_CAPS (this->src), NULL);
break;
default:
break;
}
return ret;
}
/* return a writable buffer of size which ideally is the same as before
- You must unref the new buffer
- The size of the old buffer is undefined after this operation */
@ -661,23 +468,25 @@ GINT8_IDENTITY (gint8 x)
return x;
}
#define CONVERT_TO(to, from, type, sign, endianness, LE_FUNC, BE_FUNC) \
G_STMT_START{ \
type value; \
memcpy (&value, from, sizeof (type)); \
from -= sizeof (type); \
value = (endianness == G_LITTLE_ENDIAN) ? LE_FUNC (value) : BE_FUNC (value); \
if (sign) { \
to = value; \
} else { \
to = (gint64) value - (1 << (sizeof (type) * 8 - 1)); \
} \
}G_STMT_END;
#define CONVERT_TO(to, from, type, sign, endianness, LE_FUNC, BE_FUNC) \
G_STMT_START { \
type value; \
memcpy (&value, from, sizeof (type)); \
from -= sizeof (type); \
value = (endianness == G_LITTLE_ENDIAN) ? \
LE_FUNC (value) : BE_FUNC (value); \
if (sign) { \
to = value; \
} else { \
to = (gint64) value - (1 << (sizeof (type) * 8 - 1)); \
} \
} G_STMT_END;
static GstBuffer *
gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
GstBuffer * buf)
{
GstBaseTransform *base = GST_BASE_TRANSFORM (this);
GstBuffer *ret;
gint i, count;
gint64 cur = 0;
@ -685,6 +494,8 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
gint32 *dest;
guint8 *src;
GST_LOG_OBJECT (base, "converting buffer of size %d to default format",
GST_BUFFER_SIZE (buf));
if (this->sinkcaps.is_int) {
if (this->sinkcaps.width == 32 && this->sinkcaps.depth == 32 &&
this->sinkcaps.endianness == G_BYTE_ORDER
@ -694,7 +505,7 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
ret =
gst_audio_convert_get_buffer (buf,
buf->size * 32 / this->sinkcaps.width);
gst_buffer_set_caps (ret, GST_PAD_CAPS (this->src));
gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
count = ret->size / 4;
src = buf->data + (count - 1) * (this->sinkcaps.width / 8);
@ -762,7 +573,7 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
/* should just give the same buffer, unless it's not writable -- float is
* already 32 bits */
ret = gst_audio_convert_get_buffer (buf, buf->size);
gst_buffer_set_caps (ret, GST_PAD_CAPS (this->src));
gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
in = (gfloat *) GST_BUFFER_DATA (buf);
out = (gint32 *) GST_BUFFER_DATA (ret);
@ -778,38 +589,44 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
return ret;
}
#define POPULATE(out, format, be_func, le_func) G_STMT_START{ \
format val; \
format* p = (format *) out; \
int_value >>= (32 - this->srccaps.depth); \
if (this->srccaps.sign) { \
val = (format) int_value; \
} else { \
val = (format) int_value + (1 << (this->srccaps.depth - 1)); \
} \
switch (this->srccaps.endianness) { \
case G_LITTLE_ENDIAN: \
val = le_func (val); \
break; \
case G_BIG_ENDIAN: \
val = be_func (val); \
break; \
default: \
g_assert_not_reached (); \
}; \
*p = val; \
p ++; \
out = (guint8 *) p; \
#define POPULATE(out, format, be_func, le_func) G_STMT_START { \
format val; \
format* p = (format *) out; \
int_value >>= (32 - this->srccaps.depth); \
if (this->srccaps.sign) { \
val = (format) int_value; \
} else { \
val = (format) int_value + (1 << (this->srccaps.depth - 1)); \
} \
switch (this->srccaps.endianness) { \
case G_LITTLE_ENDIAN: \
val = le_func (val); \
break; \
case G_BIG_ENDIAN: \
val = be_func (val); \
break; \
default: \
g_assert_not_reached (); \
}; \
*p = val; \
p ++; \
out = (guint8 *) p; \
}G_STMT_END
static GstBuffer *
gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
GstBuffer * buf)
{
GstBaseTransform *base;
GstBuffer *ret;
guint count, i;
gint32 *src;
base = GST_BASE_TRANSFORM (this);
GST_LOG_OBJECT (base, "converting buffer of size %d from default format",
GST_BUFFER_SIZE (buf));
if (this->srccaps.is_int && this->srccaps.width == 32
&& this->srccaps.depth == 32 && this->srccaps.endianness == G_BYTE_ORDER
&& this->srccaps.sign == TRUE)
@ -822,7 +639,7 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
ret =
gst_audio_convert_get_buffer (buf,
buf->size * this->srccaps.width / 32);
gst_buffer_set_caps (ret, GST_PAD_CAPS (this->src));
gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
dest = ret->data;
src = (gint32 *) buf->data;
@ -882,18 +699,16 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
} else {
gfloat *dest;
/* 1 / (2^31-1) * i */
#define INT2FLOAT(i) (4.6566128752457969e-10 * ((gfloat)i))
count = buf->size / 4; /* size is undefined after gst_audio_convert_get_buffer! */
ret =
gst_audio_convert_get_buffer (buf,
buf->size * this->srccaps.width / 32);
gst_buffer_set_caps (ret, GST_PAD_CAPS (this->src));
gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
dest = (gfloat *) ret->data;
src = (gint32 *) buf->data;
for (i = 0; i < count; i++) {
*dest = (4.6566128752457969e-10 * ((gfloat) * src));
*dest = INT2FLOAT (*src);
dest++;
src++;
}
@ -906,21 +721,27 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
static GstBuffer *
gst_audio_convert_channels (GstAudioConvert * this, GstBuffer * buf)
{
GstBaseTransform *base = GST_BASE_TRANSFORM (this);
GstBuffer *ret;
gint count;
gint units; /* one unit is one sample of audio for each channel, combined */
g_assert (this->matrix != NULL);
GST_LOG_OBJECT (base, "converting buffer of size %d for different channels",
GST_BUFFER_SIZE (buf));
/* check for passthrough */
if (gst_audio_convert_passthrough (this))
return buf;
/* convert */
count = GST_BUFFER_SIZE (buf) / 4 / this->sinkcaps.channels;
ret = gst_audio_convert_get_buffer (buf, count * 4 * this->srccaps.channels);
gst_buffer_set_caps (ret, GST_PAD_CAPS (this->src));
GST_LOG_OBJECT (base, "%d sinkpad channels, %d srcpad channels",
this->sinkcaps.channels, this->srccaps.channels);
units = GST_BUFFER_SIZE (buf) / 4 / this->sinkcaps.channels;
ret = gst_audio_convert_get_buffer (buf, units * 4 * this->srccaps.channels);
gst_buffer_set_caps (ret, GST_PAD_CAPS (base->srcpad));
gst_audio_convert_mix (this, (gint32 *) GST_BUFFER_DATA (buf),
(gint32 *) GST_BUFFER_DATA (ret), count);
(gint32 *) GST_BUFFER_DATA (ret), units);
gst_buffer_unref (buf);
return ret;

View file

@ -476,6 +476,7 @@ gst_audio_convert_fill_matrix (GstAudioConvert * this)
gst_audio_convert_fill_normalize (this);
}
/* only call after this->srccaps and this->sinkcaps are filled in */
void
gst_audio_convert_setup_matrix (GstAudioConvert * this)
{

View file

@ -23,6 +23,7 @@
#define __GST_CHANNEL_MIX_H__
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/audio/multichannel.h>
#define GST_TYPE_AUDIO_CONVERT (gst_audio_convert_get_type())
@ -59,11 +60,7 @@ struct _GstAudioConvertCaps
struct _GstAudioConvert
{
GstElement element;
/* pads */
GstPad *sink;
GstPad *src;
GstBaseTransform element;
GstAudioConvertCaps srccaps;
GstAudioConvertCaps sinkcaps;
@ -81,7 +78,7 @@ struct _GstAudioConvert
struct _GstAudioConvertClass
{
GstElementClass parent_class;
GstBaseTransformClass parent_class;
};
/*

View file

@ -91,11 +91,12 @@ static void gst_ffmpegcsp_init (GstFFMpegCsp * space);
static gboolean gst_ffmpegcsp_set_caps (GstBaseTransform * btrans,
GstCaps * incaps, GstCaps * outcaps);
static guint gst_ffmpegcsp_get_size (GstBaseTransform * btrans, GstCaps * caps);
static GstFlowReturn gst_ffmpegcsp_transform
(GstBaseTransform * btrans, GstBuffer * inbuf, GstBuffer * outbuf);
static GstFlowReturn gst_ffmpegcsp_transform_ip
(GstBaseTransform * btrans, GstBuffer * inbuf);
static gboolean gst_ffmpegcsp_get_unit_size (GstBaseTransform * btrans,
GstCaps * caps, guint * size);
static GstFlowReturn gst_ffmpegcsp_transform (GstBaseTransform * btrans,
GstBuffer * inbuf, GstBuffer * outbuf);
static GstFlowReturn gst_ffmpegcsp_transform_ip (GstBaseTransform * btrans,
GstBuffer * inbuf);
static GstPadTemplate *sinktempl, *srctempl;
static GstElementClass *parent_class = NULL;
@ -140,8 +141,8 @@ gst_ffmpegcsp_caps_remove_format_info (GstCaps * caps)
}
static GstCaps *
gst_ffmpegcsp_transform_caps (GstBaseTransform * btrans, GstPad * pad,
GstCaps * caps)
gst_ffmpegcsp_transform_caps (GstBaseTransform * btrans,
GstPadDirection direction, GstCaps * caps)
{
GstFFMpegCsp *space;
GstCaps *result;
@ -293,11 +294,15 @@ gst_ffmpegcsp_class_init (GstFFMpegCspClass * klass)
parent_class = g_type_class_ref (GST_TYPE_BASE_TRANSFORM);
gstbasetransform_class->transform_caps = gst_ffmpegcsp_transform_caps;
gstbasetransform_class->set_caps = gst_ffmpegcsp_set_caps;
gstbasetransform_class->get_size = gst_ffmpegcsp_get_size;
gstbasetransform_class->transform = gst_ffmpegcsp_transform;
gstbasetransform_class->transform_ip = gst_ffmpegcsp_transform_ip;
gstbasetransform_class->transform_caps =
GST_DEBUG_FUNCPTR (gst_ffmpegcsp_transform_caps);
gstbasetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_ffmpegcsp_set_caps);
gstbasetransform_class->get_unit_size =
GST_DEBUG_FUNCPTR (gst_ffmpegcsp_get_unit_size);
gstbasetransform_class->transform =
GST_DEBUG_FUNCPTR (gst_ffmpegcsp_transform);
gstbasetransform_class->transform_ip =
GST_DEBUG_FUNCPTR (gst_ffmpegcsp_transform_ip);
GST_DEBUG_CATEGORY_INIT (ffmpegcolorspace_debug, "ffmpegcolorspace", 0,
"FFMPEG-based colorspace converter");
@ -310,20 +315,23 @@ gst_ffmpegcsp_init (GstFFMpegCsp * space)
space->palette = NULL;
}
static guint
gst_ffmpegcsp_get_size (GstBaseTransform * btrans, GstCaps * caps)
static gboolean
gst_ffmpegcsp_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
guint * size)
{
GstFFMpegCsp *space;
guint size = -1;
g_return_val_if_fail (size, FALSE);
space = GST_FFMPEGCSP (btrans);
if (gst_caps_is_equal (caps, GST_PAD_CAPS (btrans->srcpad))) {
size = avpicture_get_size (space->to_pixfmt, space->width, space->height);
*size = avpicture_get_size (space->to_pixfmt, space->width, space->height);
} else if (gst_caps_is_equal (caps, GST_PAD_CAPS (btrans->sinkpad))) {
size = avpicture_get_size (space->from_pixfmt, space->width, space->height);
*size =
avpicture_get_size (space->from_pixfmt, space->width, space->height);
}
return size;
return TRUE;
}
static GstFlowReturn

View file

@ -144,12 +144,13 @@ static void gst_videoscale_init (GstVideoscale * videoscale);
static gboolean gst_videoscale_handle_src_event (GstPad * pad,
GstEvent * event);
/* base transform */
/* base transform vmethods */
static GstCaps *gst_videoscale_transform_caps (GstBaseTransform * trans,
GstPad * pad, GstCaps * caps);
GstPadDirection direction, GstCaps * caps);
static gboolean gst_videoscale_set_caps (GstBaseTransform * trans,
GstCaps * in, GstCaps * out);
static guint gst_videoscale_get_size (GstBaseTransform * trans, GstCaps * caps);
static gboolean gst_videoscale_get_unit_size (GstBaseTransform * trans,
GstCaps * caps, guint * size);
static GstFlowReturn gst_videoscale_transform_ip (GstBaseTransform * trans,
GstBuffer * in);
static GstFlowReturn gst_videoscale_transform (GstBaseTransform * trans,
@ -219,7 +220,7 @@ gst_videoscale_class_init (GstVideoscaleClass * klass)
trans_class->transform_caps = gst_videoscale_transform_caps;
trans_class->set_caps = gst_videoscale_set_caps;
trans_class->get_size = gst_videoscale_get_size;
trans_class->get_unit_size = gst_videoscale_get_unit_size;
trans_class->transform_ip = gst_videoscale_transform_ip;
trans_class->transform = gst_videoscale_transform;
@ -272,8 +273,8 @@ gst_videoscale_get_property (GObject * object, guint prop_id, GValue * value,
}
static GstCaps *
gst_videoscale_transform_caps (GstBaseTransform * trans, GstPad * pad,
GstCaps * caps)
gst_videoscale_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps)
{
GstVideoscale *videoscale;
GstCaps *ret;
@ -292,7 +293,7 @@ gst_videoscale_transform_caps (GstBaseTransform * trans, GstPad * pad,
gst_structure_remove_field (structure, "pixel-aspect-ratio");
}
GST_DEBUG_OBJECT (pad, "returning caps: %" GST_PTR_FORMAT, ret);
GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
return ret;
}
@ -423,21 +424,24 @@ gst_videoscale_prepare_sizes (GstVideoscale * videoscale, VSImage * src,
return size;
}
static guint
gst_videoscale_get_size (GstBaseTransform * trans, GstCaps * caps)
static gboolean
gst_videoscale_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
guint * size)
{
GstVideoscale *videoscale;
VSImage dest;
VSImage src;
guint size = -1;
g_return_val_if_fail (size, FALSE);
videoscale = GST_VIDEOSCALE (trans);
if (gst_caps_is_equal (caps, GST_PAD_CAPS (trans->srcpad)))
size = gst_videoscale_prepare_sizes (videoscale, &src, &dest, TRUE);
*size = gst_videoscale_prepare_sizes (videoscale, &src, &dest, TRUE);
/* don't have an easy way of getting the size on the sink side for now... */
else
return FALSE;
return size;
return TRUE;
}
static void