mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
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:
parent
80ad4cff17
commit
41a43b86a8
6 changed files with 298 additions and 447 deletions
20
ChangeLog
20
ChangeLog
|
@ -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>
|
2005-08-24 Jan Schmidt <thaytan@mad.scientist.com>
|
||||||
|
|
||||||
* check/Makefile.am:
|
* check/Makefile.am:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
* 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
|
* gstaudioconvert.c: Convert audio to different audio formats automatically
|
||||||
*
|
*
|
||||||
|
@ -18,12 +19,11 @@
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
/* Element-Checklist-Version: 5 */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* design decisions:
|
* design decisions:
|
||||||
* - audioconvert converts buffers in a set of supported caps. If it supports
|
* - 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
|
* 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)
|
* 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
|
* - audioconvert does not save state between buffers. Every incoming buffer is
|
||||||
* converted and the converted buffer is pushed out.
|
* converted and the converted buffer is pushed out.
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/base/gstbasetransform.h>
|
||||||
#include <gst/audio/multichannel.h>
|
#include <gst/audio/multichannel.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "gstchannelmix.h"
|
#include "gstchannelmix.h"
|
||||||
|
@ -44,6 +45,10 @@
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (audio_convert_debug);
|
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 **************************************************************/
|
/*** DEFINITIONS **************************************************************/
|
||||||
|
|
||||||
static GstElementDetails audio_convert_details = {
|
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);
|
static void gst_audio_convert_dispose (GObject * obj);
|
||||||
|
|
||||||
/* gstreamer functions */
|
/* 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 *
|
static GstBuffer *gst_audio_convert_buffer_to_default_format (GstAudioConvert *
|
||||||
this, GstBuffer * buf);
|
this, GstBuffer * buf);
|
||||||
static GstBuffer *gst_audio_convert_buffer_from_default_format (GstAudioConvert
|
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,
|
static GstBuffer *gst_audio_convert_channels (GstAudioConvert * this,
|
||||||
GstBuffer * buf);
|
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 */
|
/* AudioConvert signals and args */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -93,8 +104,8 @@ enum
|
||||||
#define DEBUG_INIT(bla) \
|
#define DEBUG_INIT(bla) \
|
||||||
GST_DEBUG_CATEGORY_INIT (audio_convert_debug, "audioconvert", 0, "audio conversion element");
|
GST_DEBUG_CATEGORY_INIT (audio_convert_debug, "audioconvert", 0, "audio conversion element");
|
||||||
|
|
||||||
GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstElement,
|
GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstBaseTransform,
|
||||||
GST_TYPE_ELEMENT, DEBUG_INIT);
|
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
|
||||||
|
|
||||||
/*** GSTREAMER PROTOTYPES *****************************************************/
|
/*** GSTREAMER PROTOTYPES *****************************************************/
|
||||||
|
|
||||||
|
@ -138,6 +149,8 @@ GST_STATIC_CAPS ( \
|
||||||
|
|
||||||
static GstAudioChannelPosition *supported_positions;
|
static GstAudioChannelPosition *supported_positions;
|
||||||
|
|
||||||
|
static GstStaticCaps gst_audio_convert_static_caps = STATIC_CAPS;
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_audio_convert_src_template =
|
static GstStaticPadTemplate gst_audio_convert_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
|
@ -167,42 +180,31 @@ gst_audio_convert_base_init (gpointer g_class)
|
||||||
static void
|
static void
|
||||||
gst_audio_convert_class_init (GstAudioConvertClass * klass)
|
gst_audio_convert_class_init (GstAudioConvertClass * klass)
|
||||||
{
|
{
|
||||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
gstelement_class->change_state = gst_audio_convert_change_state;
|
|
||||||
gobject_class->dispose = gst_audio_convert_dispose;
|
gobject_class->dispose = gst_audio_convert_dispose;
|
||||||
|
|
||||||
supported_positions = g_new0 (GstAudioChannelPosition,
|
supported_positions = g_new0 (GstAudioChannelPosition,
|
||||||
GST_AUDIO_CHANNEL_POSITION_NUM);
|
GST_AUDIO_CHANNEL_POSITION_NUM);
|
||||||
for (i = 0; i < GST_AUDIO_CHANNEL_POSITION_NUM; i++)
|
for (i = 0; i < GST_AUDIO_CHANNEL_POSITION_NUM; i++)
|
||||||
supported_positions[i] = 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
|
static void
|
||||||
gst_audio_convert_init (GstAudioConvert * this)
|
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 */
|
/* clear important variables */
|
||||||
this->convert_internal = NULL;
|
this->convert_internal = NULL;
|
||||||
this->sinkcaps.pos = NULL;
|
this->sinkcaps.pos = NULL;
|
||||||
|
@ -229,13 +231,135 @@ gst_audio_convert_dispose (GObject * obj)
|
||||||
|
|
||||||
/*** GSTREAMER FUNCTIONS ******************************************************/
|
/*** GSTREAMER FUNCTIONS ******************************************************/
|
||||||
|
|
||||||
static GstFlowReturn
|
/* BaseTransform vmethods */
|
||||||
gst_audio_convert_chain (GstPad * pad, GstBuffer * buf)
|
gboolean
|
||||||
|
audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
|
||||||
|
guint * size)
|
||||||
{
|
{
|
||||||
GstAudioConvert *this;
|
GstAudioConvertCaps ac_caps;
|
||||||
GstFlowReturn ret;
|
|
||||||
|
|
||||||
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:
|
* Theory of operation:
|
||||||
|
@ -244,116 +368,20 @@ gst_audio_convert_chain (GstPad * pad, GstBuffer * buf)
|
||||||
* - convert rate and channels
|
* - convert rate and channels
|
||||||
* - convert back to output format
|
* - 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_buffer_to_default_format (this, buf);
|
||||||
buf = gst_audio_convert_channels (this, buf);
|
buf = gst_audio_convert_channels (this, buf);
|
||||||
buf = gst_audio_convert_buffer_from_default_format (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 GST_FLOW_OK;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* convert the given GstCaps to our ghetto format */
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_audio_convert_parse_caps (const GstCaps * gst_caps,
|
gst_audio_convert_parse_caps (const GstCaps * gst_caps,
|
||||||
GstAudioConvertCaps * caps)
|
GstAudioConvertCaps * caps)
|
||||||
|
@ -400,227 +428,6 @@ gst_audio_convert_parse_caps (const GstCaps * gst_caps,
|
||||||
return TRUE;
|
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
|
/* return a writable buffer of size which ideally is the same as before
|
||||||
- You must unref the new buffer
|
- You must unref the new buffer
|
||||||
- The size of the old buffer is undefined after this operation */
|
- The size of the old buffer is undefined after this operation */
|
||||||
|
@ -661,23 +468,25 @@ GINT8_IDENTITY (gint8 x)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CONVERT_TO(to, from, type, sign, endianness, LE_FUNC, BE_FUNC) \
|
#define CONVERT_TO(to, from, type, sign, endianness, LE_FUNC, BE_FUNC) \
|
||||||
G_STMT_START{ \
|
G_STMT_START { \
|
||||||
type value; \
|
type value; \
|
||||||
memcpy (&value, from, sizeof (type)); \
|
memcpy (&value, from, sizeof (type)); \
|
||||||
from -= sizeof (type); \
|
from -= sizeof (type); \
|
||||||
value = (endianness == G_LITTLE_ENDIAN) ? LE_FUNC (value) : BE_FUNC (value); \
|
value = (endianness == G_LITTLE_ENDIAN) ? \
|
||||||
if (sign) { \
|
LE_FUNC (value) : BE_FUNC (value); \
|
||||||
to = value; \
|
if (sign) { \
|
||||||
} else { \
|
to = value; \
|
||||||
to = (gint64) value - (1 << (sizeof (type) * 8 - 1)); \
|
} else { \
|
||||||
} \
|
to = (gint64) value - (1 << (sizeof (type) * 8 - 1)); \
|
||||||
}G_STMT_END;
|
} \
|
||||||
|
} G_STMT_END;
|
||||||
|
|
||||||
static GstBuffer *
|
static GstBuffer *
|
||||||
gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
|
gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
|
||||||
GstBuffer * buf)
|
GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
GstBaseTransform *base = GST_BASE_TRANSFORM (this);
|
||||||
GstBuffer *ret;
|
GstBuffer *ret;
|
||||||
gint i, count;
|
gint i, count;
|
||||||
gint64 cur = 0;
|
gint64 cur = 0;
|
||||||
|
@ -685,6 +494,8 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
|
||||||
gint32 *dest;
|
gint32 *dest;
|
||||||
guint8 *src;
|
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.is_int) {
|
||||||
if (this->sinkcaps.width == 32 && this->sinkcaps.depth == 32 &&
|
if (this->sinkcaps.width == 32 && this->sinkcaps.depth == 32 &&
|
||||||
this->sinkcaps.endianness == G_BYTE_ORDER
|
this->sinkcaps.endianness == G_BYTE_ORDER
|
||||||
|
@ -694,7 +505,7 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
|
||||||
ret =
|
ret =
|
||||||
gst_audio_convert_get_buffer (buf,
|
gst_audio_convert_get_buffer (buf,
|
||||||
buf->size * 32 / this->sinkcaps.width);
|
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;
|
count = ret->size / 4;
|
||||||
src = buf->data + (count - 1) * (this->sinkcaps.width / 8);
|
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
|
/* should just give the same buffer, unless it's not writable -- float is
|
||||||
* already 32 bits */
|
* already 32 bits */
|
||||||
ret = gst_audio_convert_get_buffer (buf, buf->size);
|
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);
|
in = (gfloat *) GST_BUFFER_DATA (buf);
|
||||||
out = (gint32 *) GST_BUFFER_DATA (ret);
|
out = (gint32 *) GST_BUFFER_DATA (ret);
|
||||||
|
@ -778,38 +589,44 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define POPULATE(out, format, be_func, le_func) G_STMT_START{ \
|
#define POPULATE(out, format, be_func, le_func) G_STMT_START { \
|
||||||
format val; \
|
format val; \
|
||||||
format* p = (format *) out; \
|
format* p = (format *) out; \
|
||||||
int_value >>= (32 - this->srccaps.depth); \
|
int_value >>= (32 - this->srccaps.depth); \
|
||||||
if (this->srccaps.sign) { \
|
if (this->srccaps.sign) { \
|
||||||
val = (format) int_value; \
|
val = (format) int_value; \
|
||||||
} else { \
|
} else { \
|
||||||
val = (format) int_value + (1 << (this->srccaps.depth - 1)); \
|
val = (format) int_value + (1 << (this->srccaps.depth - 1)); \
|
||||||
} \
|
} \
|
||||||
switch (this->srccaps.endianness) { \
|
switch (this->srccaps.endianness) { \
|
||||||
case G_LITTLE_ENDIAN: \
|
case G_LITTLE_ENDIAN: \
|
||||||
val = le_func (val); \
|
val = le_func (val); \
|
||||||
break; \
|
break; \
|
||||||
case G_BIG_ENDIAN: \
|
case G_BIG_ENDIAN: \
|
||||||
val = be_func (val); \
|
val = be_func (val); \
|
||||||
break; \
|
break; \
|
||||||
default: \
|
default: \
|
||||||
g_assert_not_reached (); \
|
g_assert_not_reached (); \
|
||||||
}; \
|
}; \
|
||||||
*p = val; \
|
*p = val; \
|
||||||
p ++; \
|
p ++; \
|
||||||
out = (guint8 *) p; \
|
out = (guint8 *) p; \
|
||||||
}G_STMT_END
|
}G_STMT_END
|
||||||
|
|
||||||
static GstBuffer *
|
static GstBuffer *
|
||||||
gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
|
gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
|
||||||
GstBuffer * buf)
|
GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
GstBaseTransform *base;
|
||||||
GstBuffer *ret;
|
GstBuffer *ret;
|
||||||
guint count, i;
|
guint count, i;
|
||||||
gint32 *src;
|
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
|
if (this->srccaps.is_int && this->srccaps.width == 32
|
||||||
&& this->srccaps.depth == 32 && this->srccaps.endianness == G_BYTE_ORDER
|
&& this->srccaps.depth == 32 && this->srccaps.endianness == G_BYTE_ORDER
|
||||||
&& this->srccaps.sign == TRUE)
|
&& this->srccaps.sign == TRUE)
|
||||||
|
@ -822,7 +639,7 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
|
||||||
ret =
|
ret =
|
||||||
gst_audio_convert_get_buffer (buf,
|
gst_audio_convert_get_buffer (buf,
|
||||||
buf->size * this->srccaps.width / 32);
|
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;
|
dest = ret->data;
|
||||||
src = (gint32 *) buf->data;
|
src = (gint32 *) buf->data;
|
||||||
|
@ -882,18 +699,16 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
|
||||||
} else {
|
} else {
|
||||||
gfloat *dest;
|
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! */
|
count = buf->size / 4; /* size is undefined after gst_audio_convert_get_buffer! */
|
||||||
ret =
|
ret =
|
||||||
gst_audio_convert_get_buffer (buf,
|
gst_audio_convert_get_buffer (buf,
|
||||||
buf->size * this->srccaps.width / 32);
|
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;
|
dest = (gfloat *) ret->data;
|
||||||
src = (gint32 *) buf->data;
|
src = (gint32 *) buf->data;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
*dest = (4.6566128752457969e-10 * ((gfloat) * src));
|
*dest = INT2FLOAT (*src);
|
||||||
dest++;
|
dest++;
|
||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
|
@ -906,21 +721,27 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
|
||||||
static GstBuffer *
|
static GstBuffer *
|
||||||
gst_audio_convert_channels (GstAudioConvert * this, GstBuffer * buf)
|
gst_audio_convert_channels (GstAudioConvert * this, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
GstBaseTransform *base = GST_BASE_TRANSFORM (this);
|
||||||
GstBuffer *ret;
|
GstBuffer *ret;
|
||||||
gint count;
|
gint units; /* one unit is one sample of audio for each channel, combined */
|
||||||
|
|
||||||
g_assert (this->matrix != NULL);
|
g_assert (this->matrix != NULL);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (base, "converting buffer of size %d for different channels",
|
||||||
|
GST_BUFFER_SIZE (buf));
|
||||||
|
|
||||||
/* check for passthrough */
|
/* check for passthrough */
|
||||||
if (gst_audio_convert_passthrough (this))
|
if (gst_audio_convert_passthrough (this))
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
/* convert */
|
/* convert */
|
||||||
count = GST_BUFFER_SIZE (buf) / 4 / this->sinkcaps.channels;
|
GST_LOG_OBJECT (base, "%d sinkpad channels, %d srcpad channels",
|
||||||
ret = gst_audio_convert_get_buffer (buf, count * 4 * this->srccaps.channels);
|
this->sinkcaps.channels, this->srccaps.channels);
|
||||||
gst_buffer_set_caps (ret, GST_PAD_CAPS (this->src));
|
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),
|
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);
|
gst_buffer_unref (buf);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -476,6 +476,7 @@ gst_audio_convert_fill_matrix (GstAudioConvert * this)
|
||||||
gst_audio_convert_fill_normalize (this);
|
gst_audio_convert_fill_normalize (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* only call after this->srccaps and this->sinkcaps are filled in */
|
||||||
void
|
void
|
||||||
gst_audio_convert_setup_matrix (GstAudioConvert * this)
|
gst_audio_convert_setup_matrix (GstAudioConvert * this)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define __GST_CHANNEL_MIX_H__
|
#define __GST_CHANNEL_MIX_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/base/gstbasetransform.h>
|
||||||
#include <gst/audio/multichannel.h>
|
#include <gst/audio/multichannel.h>
|
||||||
|
|
||||||
#define GST_TYPE_AUDIO_CONVERT (gst_audio_convert_get_type())
|
#define GST_TYPE_AUDIO_CONVERT (gst_audio_convert_get_type())
|
||||||
|
@ -59,11 +60,7 @@ struct _GstAudioConvertCaps
|
||||||
|
|
||||||
struct _GstAudioConvert
|
struct _GstAudioConvert
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstBaseTransform element;
|
||||||
|
|
||||||
/* pads */
|
|
||||||
GstPad *sink;
|
|
||||||
GstPad *src;
|
|
||||||
|
|
||||||
GstAudioConvertCaps srccaps;
|
GstAudioConvertCaps srccaps;
|
||||||
GstAudioConvertCaps sinkcaps;
|
GstAudioConvertCaps sinkcaps;
|
||||||
|
@ -81,7 +78,7 @@ struct _GstAudioConvert
|
||||||
|
|
||||||
struct _GstAudioConvertClass
|
struct _GstAudioConvertClass
|
||||||
{
|
{
|
||||||
GstElementClass parent_class;
|
GstBaseTransformClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -91,11 +91,12 @@ static void gst_ffmpegcsp_init (GstFFMpegCsp * space);
|
||||||
|
|
||||||
static gboolean gst_ffmpegcsp_set_caps (GstBaseTransform * btrans,
|
static gboolean gst_ffmpegcsp_set_caps (GstBaseTransform * btrans,
|
||||||
GstCaps * incaps, GstCaps * outcaps);
|
GstCaps * incaps, GstCaps * outcaps);
|
||||||
static guint gst_ffmpegcsp_get_size (GstBaseTransform * btrans, GstCaps * caps);
|
static gboolean gst_ffmpegcsp_get_unit_size (GstBaseTransform * btrans,
|
||||||
static GstFlowReturn gst_ffmpegcsp_transform
|
GstCaps * caps, guint * size);
|
||||||
(GstBaseTransform * btrans, GstBuffer * inbuf, GstBuffer * outbuf);
|
static GstFlowReturn gst_ffmpegcsp_transform (GstBaseTransform * btrans,
|
||||||
static GstFlowReturn gst_ffmpegcsp_transform_ip
|
GstBuffer * inbuf, GstBuffer * outbuf);
|
||||||
(GstBaseTransform * btrans, GstBuffer * inbuf);
|
static GstFlowReturn gst_ffmpegcsp_transform_ip (GstBaseTransform * btrans,
|
||||||
|
GstBuffer * inbuf);
|
||||||
|
|
||||||
static GstPadTemplate *sinktempl, *srctempl;
|
static GstPadTemplate *sinktempl, *srctempl;
|
||||||
static GstElementClass *parent_class = NULL;
|
static GstElementClass *parent_class = NULL;
|
||||||
|
@ -140,8 +141,8 @@ gst_ffmpegcsp_caps_remove_format_info (GstCaps * caps)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstCaps *
|
static GstCaps *
|
||||||
gst_ffmpegcsp_transform_caps (GstBaseTransform * btrans, GstPad * pad,
|
gst_ffmpegcsp_transform_caps (GstBaseTransform * btrans,
|
||||||
GstCaps * caps)
|
GstPadDirection direction, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstFFMpegCsp *space;
|
GstFFMpegCsp *space;
|
||||||
GstCaps *result;
|
GstCaps *result;
|
||||||
|
@ -293,11 +294,15 @@ gst_ffmpegcsp_class_init (GstFFMpegCspClass * klass)
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_BASE_TRANSFORM);
|
parent_class = g_type_class_ref (GST_TYPE_BASE_TRANSFORM);
|
||||||
|
|
||||||
gstbasetransform_class->transform_caps = gst_ffmpegcsp_transform_caps;
|
gstbasetransform_class->transform_caps =
|
||||||
gstbasetransform_class->set_caps = gst_ffmpegcsp_set_caps;
|
GST_DEBUG_FUNCPTR (gst_ffmpegcsp_transform_caps);
|
||||||
gstbasetransform_class->get_size = gst_ffmpegcsp_get_size;
|
gstbasetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_ffmpegcsp_set_caps);
|
||||||
gstbasetransform_class->transform = gst_ffmpegcsp_transform;
|
gstbasetransform_class->get_unit_size =
|
||||||
gstbasetransform_class->transform_ip = gst_ffmpegcsp_transform_ip;
|
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,
|
GST_DEBUG_CATEGORY_INIT (ffmpegcolorspace_debug, "ffmpegcolorspace", 0,
|
||||||
"FFMPEG-based colorspace converter");
|
"FFMPEG-based colorspace converter");
|
||||||
|
@ -310,20 +315,23 @@ gst_ffmpegcsp_init (GstFFMpegCsp * space)
|
||||||
space->palette = NULL;
|
space->palette = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static guint
|
static gboolean
|
||||||
gst_ffmpegcsp_get_size (GstBaseTransform * btrans, GstCaps * caps)
|
gst_ffmpegcsp_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
|
||||||
|
guint * size)
|
||||||
{
|
{
|
||||||
GstFFMpegCsp *space;
|
GstFFMpegCsp *space;
|
||||||
guint size = -1;
|
|
||||||
|
g_return_val_if_fail (size, FALSE);
|
||||||
|
|
||||||
space = GST_FFMPEGCSP (btrans);
|
space = GST_FFMPEGCSP (btrans);
|
||||||
if (gst_caps_is_equal (caps, GST_PAD_CAPS (btrans->srcpad))) {
|
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))) {
|
} 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
|
static GstFlowReturn
|
||||||
|
|
|
@ -144,12 +144,13 @@ static void gst_videoscale_init (GstVideoscale * videoscale);
|
||||||
static gboolean gst_videoscale_handle_src_event (GstPad * pad,
|
static gboolean gst_videoscale_handle_src_event (GstPad * pad,
|
||||||
GstEvent * event);
|
GstEvent * event);
|
||||||
|
|
||||||
/* base transform */
|
/* base transform vmethods */
|
||||||
static GstCaps *gst_videoscale_transform_caps (GstBaseTransform * trans,
|
static GstCaps *gst_videoscale_transform_caps (GstBaseTransform * trans,
|
||||||
GstPad * pad, GstCaps * caps);
|
GstPadDirection direction, GstCaps * caps);
|
||||||
static gboolean gst_videoscale_set_caps (GstBaseTransform * trans,
|
static gboolean gst_videoscale_set_caps (GstBaseTransform * trans,
|
||||||
GstCaps * in, GstCaps * out);
|
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,
|
static GstFlowReturn gst_videoscale_transform_ip (GstBaseTransform * trans,
|
||||||
GstBuffer * in);
|
GstBuffer * in);
|
||||||
static GstFlowReturn gst_videoscale_transform (GstBaseTransform * trans,
|
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->transform_caps = gst_videoscale_transform_caps;
|
||||||
trans_class->set_caps = gst_videoscale_set_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_ip = gst_videoscale_transform_ip;
|
||||||
trans_class->transform = gst_videoscale_transform;
|
trans_class->transform = gst_videoscale_transform;
|
||||||
|
|
||||||
|
@ -272,8 +273,8 @@ gst_videoscale_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstCaps *
|
static GstCaps *
|
||||||
gst_videoscale_transform_caps (GstBaseTransform * trans, GstPad * pad,
|
gst_videoscale_transform_caps (GstBaseTransform * trans,
|
||||||
GstCaps * caps)
|
GstPadDirection direction, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstVideoscale *videoscale;
|
GstVideoscale *videoscale;
|
||||||
GstCaps *ret;
|
GstCaps *ret;
|
||||||
|
@ -292,7 +293,7 @@ gst_videoscale_transform_caps (GstBaseTransform * trans, GstPad * pad,
|
||||||
gst_structure_remove_field (structure, "pixel-aspect-ratio");
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,21 +424,24 @@ gst_videoscale_prepare_sizes (GstVideoscale * videoscale, VSImage * src,
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static guint
|
static gboolean
|
||||||
gst_videoscale_get_size (GstBaseTransform * trans, GstCaps * caps)
|
gst_videoscale_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
|
||||||
|
guint * size)
|
||||||
{
|
{
|
||||||
GstVideoscale *videoscale;
|
GstVideoscale *videoscale;
|
||||||
VSImage dest;
|
VSImage dest;
|
||||||
VSImage src;
|
VSImage src;
|
||||||
guint size = -1;
|
|
||||||
|
|
||||||
|
g_return_val_if_fail (size, FALSE);
|
||||||
videoscale = GST_VIDEOSCALE (trans);
|
videoscale = GST_VIDEOSCALE (trans);
|
||||||
|
|
||||||
if (gst_caps_is_equal (caps, GST_PAD_CAPS (trans->srcpad)))
|
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... */
|
/* 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
|
static void
|
||||||
|
|
Loading…
Reference in a new issue