mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
9c90508cc1
Original commit message from CVS: Add semicolons after GST_BOILERPLATE[_FULL] so that indent doesn't mess up following lines.
578 lines
17 KiB
C
578 lines
17 KiB
C
/* GStreamer
|
|
* Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <gst/gst.h>
|
|
#include "gstxine.h"
|
|
#include <xine/xine_internal.h>
|
|
#include <xine/plugin_catalog.h>
|
|
|
|
#define GST_TYPE_XINE_AUDIO_DEC \
|
|
(gst_xine_audio_dec_get_type())
|
|
#define GST_XINE_AUDIO_DEC(obj) \
|
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XINE_AUDIO_DEC,GstXineAudioDec))
|
|
#define GST_XINE_AUDIO_DEC_GET_CLASS(obj) \
|
|
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XINE_AUDIO_DEC, GstXineAudioDecClass))
|
|
#define GST_XINE_AUDIO_DEC_CLASS(klass) \
|
|
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XINE_AUDIO_DEC,GstXineAudioDecClass))
|
|
#define GST_IS_XINE_AUDIO_DEC(obj) \
|
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XINE_AUDIO_DEC))
|
|
#define GST_IS_XINE_AUDIO_DEC_CLASS(obj) \
|
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XINE_AUDIO_DEC))
|
|
|
|
GType gst_xine_audio_dec_get_type (void);
|
|
|
|
typedef struct _GstXineAudioDec GstXineAudioDec;
|
|
typedef struct _GstXineAudioDecClass GstXineAudioDecClass;
|
|
|
|
struct _GstXineAudioDec
|
|
{
|
|
GstXine parent;
|
|
|
|
GstPad *sinkpad;
|
|
GstPad *srcpad;
|
|
|
|
audio_decoder_t *decoder;
|
|
guint32 format;
|
|
xine_waveformatex wave;
|
|
gboolean setup;
|
|
};
|
|
|
|
struct _GstXineAudioDecClass
|
|
{
|
|
GstXineClass parent_class;
|
|
|
|
plugin_node_t *plugin_node;
|
|
};
|
|
|
|
/*** xine audio driver wrapper ************************************************/
|
|
|
|
typedef struct
|
|
{
|
|
xine_ao_driver_t driver;
|
|
GstXineAudioDec *xine;
|
|
gboolean open;
|
|
}
|
|
GstXineAudioDriver;
|
|
|
|
static guint32
|
|
_driver_get_capabilities (xine_ao_driver_t * driver)
|
|
{
|
|
/* FIXME: add more when gst handles more than 2 channels */
|
|
return AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_8BITS;
|
|
}
|
|
|
|
static gint
|
|
_driver_get_property (xine_ao_driver_t * driver, int property)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
_driver_set_property (xine_ao_driver_t * driver, int property, int value)
|
|
{
|
|
return ~value;
|
|
}
|
|
|
|
static gint
|
|
_driver_open (xine_ao_driver_t * driver, xine_stream_t * stream, guint32 bits,
|
|
guint32 rate, int mode)
|
|
{
|
|
GstCaps *caps;
|
|
GstXineAudioDriver *xine = ((GstXineAudioDriver *) driver);
|
|
|
|
caps = gst_caps_new_simple ("audio/x-raw-int",
|
|
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
|
"width", G_TYPE_INT, (gint) bits,
|
|
"depth", G_TYPE_INT, (gint) bits,
|
|
"signed", G_TYPE_BOOLEAN, (bits == 8) ? FALSE : TRUE,
|
|
"channels", G_TYPE_INT, (mode | AO_CAP_MODE_STEREO) ? 2 : 1,
|
|
"rate", G_TYPE_INT, rate, NULL);
|
|
|
|
if (!gst_pad_set_explicit_caps (xine->xine->srcpad, caps)) {
|
|
gst_caps_free (caps);
|
|
driver->open = FALSE;
|
|
return -1;
|
|
}
|
|
|
|
xine->open = TRUE;
|
|
gst_caps_free (caps);
|
|
return rate;
|
|
}
|
|
|
|
static void
|
|
_driver_close (xine_ao_driver_t * driver, xine_stream_t * stream)
|
|
{
|
|
/* FIXME: unset explicit caps here? And how? */
|
|
driver->open = FALSE;
|
|
}
|
|
|
|
static void
|
|
_driver_exit (xine_ao_driver_t * driver)
|
|
{
|
|
g_free (driver);
|
|
}
|
|
|
|
static int
|
|
_driver_control (xine_ao_driver_t * driver, int cmd, ...)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
_driver_flush (xine_ao_driver_t * driver)
|
|
{
|
|
}
|
|
|
|
static int
|
|
_driver_status (xine_ao_driver_t * driver, xine_stream_t * stream,
|
|
uint32_t * bits, uint32_t * rate, int *mode)
|
|
{
|
|
const GstCaps *caps;
|
|
GstStructure *structure;
|
|
gint temp;
|
|
GstXineAudioDriver *xine = (GstXineAudioDriver *) driver;
|
|
|
|
if (xine->open == FALSE
|
|
|| !(caps = gst_pad_get_negotiated_caps (xine->xine->srcpad)))
|
|
return 0;
|
|
|
|
structure = gst_caps_get_structure (caps, 0);
|
|
*bits = 0; /* FIXME */
|
|
if (!gst_structure_get_int (structure, "rate", &temp)) {
|
|
g_assert_not_reached (); /* may never happen with negotiated caps */
|
|
return 0;
|
|
}
|
|
*rate = temp;
|
|
if (!gst_structure_get_int (structure, "channels", &temp)) {
|
|
g_assert_not_reached (); /* may never happen with negotiated caps */
|
|
return 0;
|
|
}
|
|
*mode = (temp == 2) ? AO_CAP_MODE_STEREO : AO_CAP_MODE_MONO;
|
|
if (!gst_structure_get_int (structure, "width", &temp)) {
|
|
g_assert_not_reached (); /* may never happen with negotiated caps */
|
|
return 0;
|
|
}
|
|
if (temp == 8)
|
|
*mode |= AO_CAP_8BITS;
|
|
|
|
return 1;
|
|
}
|
|
|
|
#define _DRIVER_BUFFER_SIZE 4096
|
|
static audio_buffer_t *
|
|
_driver_get_buffer (xine_ao_driver_t * driver)
|
|
{
|
|
GstXineAudioDriver *xine = (GstXineAudioDriver *) driver;
|
|
audio_buffer_t *audio = g_new0 (audio_buffer_t, 1);
|
|
|
|
audio->mem = g_malloc (_DRIVER_BUFFER_SIZE);
|
|
audio->mem_size = _DRIVER_BUFFER_SIZE;
|
|
audio->stream = gst_xine_get_stream (GST_XINE (xine->xine));
|
|
/* FIXME: fill more fields */
|
|
|
|
return audio;
|
|
}
|
|
|
|
static void
|
|
_driver_put_buffer (xine_ao_driver_t * driver, audio_buffer_t * audio,
|
|
xine_stream_t * stream)
|
|
{
|
|
GstXineAudioDriver *xine = (GstXineAudioDriver *) driver;
|
|
GstBuffer *buffer;
|
|
|
|
buffer = gst_buffer_new ();
|
|
GST_BUFFER_DATA (buffer) = (guint8 *) audio->mem;
|
|
GST_BUFFER_SIZE (buffer) = audio->mem_size;
|
|
GST_BUFFER_MAXSIZE (buffer) = audio->mem_size;
|
|
/* FIXME: fill more fields */
|
|
g_free (audio);
|
|
gst_pad_push (xine->xine->srcpad, GST_DATA (buffer));
|
|
}
|
|
|
|
static xine_ao_driver_t *
|
|
_gst_xine_audio_dec_create_audio_driver (GstXine * xine)
|
|
{
|
|
GstXineAudioDriver *driver = g_new (GstXineAudioDriver, 1);
|
|
|
|
driver->xine = GST_XINE_AUDIO_DEC (xine);
|
|
driver->open = FALSE;
|
|
|
|
driver->driver.get_buffer = _driver_get_buffer;
|
|
driver->driver.put_buffer = _driver_put_buffer;
|
|
driver->driver.get_capabilities = _driver_get_capabilities;
|
|
driver->driver.get_property = _driver_get_property;
|
|
driver->driver.set_property = _driver_set_property;
|
|
driver->driver.open = _driver_open;
|
|
driver->driver.close = _driver_close;
|
|
driver->driver.exit = _driver_exit;
|
|
driver->driver.control = _driver_control;
|
|
driver->driver.flush = _driver_flush;
|
|
driver->driver.status = _driver_status;
|
|
|
|
return (xine_ao_driver_t *) driver;
|
|
}
|
|
|
|
/** GstXineAudioDec ***********************************************************/
|
|
|
|
GST_BOILERPLATE (GstXineAudioDec, gst_xine_audio_dec, GstXine, GST_TYPE_XINE);
|
|
|
|
static void gst_xine_audio_dec_chain (GstPad * pad, GstData * in);
|
|
static GstStateChangeReturn
|
|
gst_xine_audio_dec_change_state (GstElement * element,
|
|
GstStateChange transition);
|
|
|
|
/* this function handles the link with other plug-ins */
|
|
static GstPadLinkReturn
|
|
gst_xine_audio_dec_sink_link (GstPad * pad, const GstCaps * caps)
|
|
{
|
|
guint temp;
|
|
GstStructure *structure;
|
|
GstXineAudioDec *xine =
|
|
GST_XINE_AUDIO_DEC (gst_object_get_parent (GST_OBJECT (pad)));
|
|
|
|
xine->format = gst_xine_get_format_for_caps (caps);
|
|
if (xine->format == 0)
|
|
return GST_PAD_LINK_REFUSED;
|
|
|
|
/* get setup data */
|
|
xine->setup = FALSE;
|
|
structure = gst_caps_get_structure (caps, 0);
|
|
if (gst_structure_get_int (structure, "channels", &temp))
|
|
xine->wave.nChannels = temp;
|
|
if (gst_structure_get_int (structure, "rate", &temp))
|
|
xine->wave.nSamplesPerSec = temp;
|
|
xine->wave.wBitsPerSample = 16; /* FIXME: how do we figure this thing out? */
|
|
/* FIXME: fill wave header better */
|
|
|
|
return GST_PAD_LINK_OK;
|
|
}
|
|
|
|
static void
|
|
gst_xine_audio_dec_base_init (gpointer g_class)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gst_xine_audio_dec_class_init (GstXineAudioDecClass * klass)
|
|
{
|
|
GstXineClass *xine = GST_XINE_CLASS (klass);
|
|
GstElementClass *element = GST_ELEMENT_CLASS (klass);
|
|
|
|
element->change_state = gst_xine_audio_dec_change_state;
|
|
|
|
xine->create_audio_driver = _gst_xine_audio_dec_create_audio_driver;
|
|
}
|
|
|
|
static void
|
|
gst_xine_audio_dec_init (GstXineAudioDec * xine, GstXineAudioDecClass * g_class)
|
|
{
|
|
xine->setup = FALSE;
|
|
}
|
|
|
|
static void
|
|
gst_xine_audio_dec_event (GstXineAudioDec * xine, GstEvent * event)
|
|
{
|
|
gst_pad_event_default (xine->sinkpad, event);
|
|
}
|
|
|
|
static void
|
|
gst_xine_audio_dec_chain (GstPad * pad, GstData * in)
|
|
{
|
|
buf_element_t buffer = { 0, };
|
|
GstXineAudioDec *xine =
|
|
GST_XINE_AUDIO_DEC (gst_object_get_parent (GST_OBJECT (pad)));
|
|
|
|
if (GST_IS_EVENT (in)) {
|
|
gst_xine_audio_dec_event (xine, GST_EVENT (in));
|
|
return;
|
|
}
|
|
|
|
if (xine->format == 0) {
|
|
/* no caps yet */
|
|
GST_ELEMENT_ERROR (xine, CORE, NEGOTIATION, (NULL),
|
|
("buffer sent before doing caps nego"));
|
|
gst_data_unref (in);
|
|
return;
|
|
}
|
|
|
|
if (!xine->setup) {
|
|
buf_element_t element = { 0, };
|
|
guint8 stsd[150] = { 0, };
|
|
guint temp;
|
|
GstStructure *structure;
|
|
|
|
/* sent setup header */
|
|
element.type = xine->format;
|
|
element.decoder_flags = BUF_FLAG_HEADER;
|
|
element.decoder_info[0] = 0;
|
|
element.decoder_info[1] = xine->wave.nSamplesPerSec;
|
|
element.decoder_info[2] = xine->wave.wBitsPerSample;
|
|
element.decoder_info[3] = xine->wave.nChannels;
|
|
element.content = (guchar *) & xine->wave;
|
|
element.size = sizeof (xine_waveformatex);
|
|
xine->decoder->decode_data (xine->decoder, &element);
|
|
/* send stsd emulation to the decoder */
|
|
/* FIXME: qdm2 only right now */
|
|
g_assert (gst_pad_is_negotiated (xine->sinkpad));
|
|
structure =
|
|
gst_caps_get_structure (gst_pad_get_negotiated_caps (xine->sinkpad), 0);
|
|
*((guint32 *) & stsd[56]) = GUINT32_TO_BE (12);
|
|
memcpy (&stsd[60], "frmaQDM2", 8);
|
|
*((guint32 *) & stsd[68]) = GUINT32_TO_BE (36);
|
|
memcpy (&stsd[72], "QDCA", 4);
|
|
*((guint32 *) & stsd[76]) = GUINT32_TO_BE (1);
|
|
if (!gst_structure_get_int (structure, "channels", &temp))
|
|
temp = 0;
|
|
*((guint32 *) & stsd[80]) = GUINT32_TO_BE (temp);
|
|
if (!gst_structure_get_int (structure, "rate", &temp))
|
|
temp = 0;
|
|
*((guint32 *) & stsd[84]) = GUINT32_TO_BE (temp);
|
|
if (!gst_structure_get_int (structure, "bitrate", &temp))
|
|
temp = 0;
|
|
*((guint32 *) & stsd[88]) = GUINT32_TO_BE (temp);
|
|
if (!gst_structure_get_int (structure, "blocksize", &temp))
|
|
temp = 0;
|
|
*((guint32 *) & stsd[92]) = GUINT32_TO_BE (temp);
|
|
*((guint32 *) & stsd[96]) = GUINT32_TO_BE (256);
|
|
if (!gst_structure_get_int (structure, "framesize", &temp))
|
|
temp = 0;
|
|
*((guint32 *) & stsd[100]) = GUINT32_TO_BE (temp);
|
|
*((guint32 *) & stsd[104]) = GUINT32_TO_BE (28);
|
|
memcpy (&stsd[108], "QDCP", 4);
|
|
*((guint32 *) & stsd[112]) = GUINT32_TO_BE (1065353216);
|
|
*((guint32 *) & stsd[116]) = GUINT32_TO_BE (0);
|
|
*((guint32 *) & stsd[120]) = GUINT32_TO_BE (1065353216);
|
|
*((guint32 *) & stsd[124]) = GUINT32_TO_BE (1065353216);
|
|
*((guint32 *) & stsd[128]) = GUINT32_TO_BE (27);
|
|
*((guint32 *) & stsd[132]) = GUINT32_TO_BE (8);
|
|
*((guint32 *) & stsd[136]) = GUINT32_TO_BE (0);
|
|
*((guint32 *) & stsd[140]) = GUINT32_TO_BE (24);
|
|
gst_util_dump_mem (stsd, 144);
|
|
element.decoder_flags = BUF_FLAG_SPECIAL;
|
|
element.decoder_info[1] = BUF_SPECIAL_STSD_ATOM;
|
|
element.decoder_info[2] = 144;
|
|
element.decoder_info[3] = 0;
|
|
element.decoder_info_ptr[2] = stsd;
|
|
element.size = 0;
|
|
element.content = 0;
|
|
xine->decoder->decode_data (xine->decoder, &element);
|
|
|
|
xine->setup = TRUE;
|
|
}
|
|
|
|
gst_buffer_to_xine_buffer (&buffer, GST_BUFFER (in));
|
|
buffer.type = xine->format;
|
|
xine->decoder->decode_data (xine->decoder, &buffer);
|
|
gst_data_unref (in);
|
|
}
|
|
|
|
static audio_decoder_t *
|
|
_load_decoder (GstXineAudioDec * dec)
|
|
{
|
|
xine_stream_t *stream = gst_xine_get_stream (GST_XINE (dec));
|
|
plugin_catalog_t *catalog = stream->xine->plugin_catalog;
|
|
plugin_node_t *node = GST_XINE_AUDIO_DEC_GET_CLASS (dec)->plugin_node;
|
|
audio_decoder_t *ret;
|
|
|
|
/* FIXME: this is really hacky, but how to force xine to load a plugin? */
|
|
/* how it works: xine can load a plugin for a particular stream type.
|
|
* We just take one type, which should not have plugins attached to it,
|
|
* attach our plugin and load it */
|
|
g_assert (catalog->audio_decoder_map[DECODER_MAX - 1][0] == NULL);
|
|
catalog->audio_decoder_map[DECODER_MAX - 1][0] = node;
|
|
ret = _x_get_audio_decoder (stream, DECODER_MAX - 1);
|
|
catalog->audio_decoder_map[DECODER_MAX - 1][0] = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static GstStateChangeReturn
|
|
gst_xine_audio_dec_change_state (GstElement * element,
|
|
GstStateChange transition)
|
|
{
|
|
GstXineAudioDec *xine = GST_XINE_AUDIO_DEC (element);
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
xine->decoder = _load_decoder (xine);
|
|
if (!xine->decoder)
|
|
return GST_STATE_CHANGE_FAILURE;
|
|
break;
|
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
break;
|
|
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
|
break;
|
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
|
break;
|
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
break;
|
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
xine->setup = FALSE;
|
|
_x_free_audio_decoder (gst_xine_get_stream (GST_XINE (xine)),
|
|
xine->decoder);
|
|
break;
|
|
default:
|
|
GST_ERROR_OBJECT (element, "invalid state change");
|
|
break;
|
|
}
|
|
|
|
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
|
|
(element), GST_STATE_CHANGE_SUCCESS);
|
|
}
|
|
|
|
/** GstXineAudioDec subclasses ************************************************/
|
|
|
|
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
|
GST_PAD_SRC,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("audio/x-raw-int, "
|
|
"endianness = (int) BYTE_ORDER, "
|
|
"signed = (boolean) TRUE, "
|
|
"width = (int) 16, "
|
|
"depth = (int) 16, "
|
|
"rate = (int) [ 1, MAX ], "
|
|
"channels = (int) [ 1, 2 ]; "
|
|
"audio/x-raw-int, "
|
|
"signed = (boolean) FALSE, "
|
|
"width = (int) 8, "
|
|
"depth = (int) 8, "
|
|
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
|
|
);
|
|
|
|
static void
|
|
gst_xine_audio_dec_subclass_init (gpointer g_class, gpointer class_data)
|
|
{
|
|
GstXineAudioDecClass *xine_class = GST_XINE_AUDIO_DEC_CLASS (g_class);
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
|
GstElementDetails details = GST_ELEMENT_DETAILS (NULL,
|
|
"Codec/Decoder/Audio",
|
|
NULL,
|
|
"Benjamin Otte <otte@gnome.org>");
|
|
GstPadTemplate *template;
|
|
guint i = 0;
|
|
GstCaps *caps = gst_caps_new_empty ();
|
|
decoder_info_t *dec;
|
|
|
|
xine_class->plugin_node = class_data;
|
|
dec = xine_class->plugin_node->info->special_info;
|
|
details.longname =
|
|
g_strdup_printf ("%s xine audio decoder",
|
|
xine_class->plugin_node->info->id);
|
|
details.description =
|
|
g_strdup_printf ("decodes audio using the xine '%s' plugin",
|
|
xine_class->plugin_node->info->id);
|
|
gst_element_class_set_details (element_class, &details);
|
|
g_free (details.longname);
|
|
g_free (details.description);
|
|
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&src_template));
|
|
|
|
while (dec->supported_types[i] != 0) {
|
|
const gchar *type_str =
|
|
gst_xine_get_caps_for_format (dec->supported_types[i]);
|
|
if (type_str) {
|
|
gst_caps_append (caps, gst_caps_from_string (type_str));
|
|
}
|
|
i++;
|
|
}
|
|
template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
|
|
gst_element_class_add_pad_template (element_class, template);
|
|
}
|
|
|
|
static void
|
|
gst_xine_audio_dec_sub_init (GTypeInstance * instance, gpointer g_class)
|
|
{
|
|
GstElementClass *klass = GST_ELEMENT_GET_CLASS (instance);
|
|
GstXineAudioDec *xine = GST_XINE_AUDIO_DEC (instance);
|
|
|
|
xine->sinkpad =
|
|
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
|
|
"sink"), "sink");
|
|
gst_pad_set_link_function (xine->sinkpad, gst_xine_audio_dec_sink_link);
|
|
gst_pad_set_chain_function (xine->sinkpad, gst_xine_audio_dec_chain);
|
|
gst_element_add_pad (GST_ELEMENT (xine), xine->sinkpad);
|
|
|
|
xine->srcpad =
|
|
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
|
|
"src"), "src");
|
|
gst_pad_use_explicit_caps (xine->srcpad);
|
|
gst_element_add_pad (GST_ELEMENT (xine), xine->srcpad);
|
|
}
|
|
|
|
gboolean
|
|
gst_xine_audio_dec_init_plugin (GstPlugin * plugin)
|
|
{
|
|
GTypeInfo plugin_info = {
|
|
sizeof (GstXineAudioDecClass),
|
|
NULL,
|
|
NULL,
|
|
gst_xine_audio_dec_subclass_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof (GstXineAudioDec),
|
|
0,
|
|
gst_xine_audio_dec_sub_init,
|
|
};
|
|
xine_node_t *list;
|
|
GstXineClass *klass;
|
|
|
|
klass = g_type_class_ref (GST_TYPE_XINE);
|
|
|
|
list = klass->xine->plugin_catalog->audio->first;
|
|
while (list) {
|
|
plugin_node_t *node = list->content;
|
|
decoder_info_t *dec;
|
|
guint format = 0;
|
|
|
|
list = list->next;
|
|
if (!node)
|
|
continue;
|
|
|
|
dec = node->info->special_info;
|
|
while (dec->supported_types[format] != 0) {
|
|
const gchar *caps =
|
|
gst_xine_get_caps_for_format (dec->supported_types[format]);
|
|
if (caps) {
|
|
gchar *plugin_name =
|
|
g_strdup_printf ("xineaudiodec_%s", node->info->id);
|
|
gchar *type_name =
|
|
g_strdup_printf ("GstXineAudioDec%s", node->info->id);
|
|
GType type;
|
|
|
|
plugin_info.class_data = node;
|
|
type =
|
|
g_type_register_static (GST_TYPE_XINE_AUDIO_DEC, type_name,
|
|
&plugin_info, 0);
|
|
g_free (type_name);
|
|
if (!gst_element_register (plugin, plugin_name,
|
|
MAX (GST_RANK_MARGINAL,
|
|
GST_RANK_MARGINAL * dec->priority / 10 + 1), type)) {
|
|
g_free (plugin_name);
|
|
return FALSE;
|
|
}
|
|
g_free (plugin_name);
|
|
}
|
|
format++;
|
|
}
|
|
}
|
|
|
|
g_type_class_unref (klass);
|
|
return TRUE;
|
|
}
|