2
* Copyright (C) <2009> Jan Schmidt <thaytan@noraisin.net>
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Library General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Library General Public License for more details.
14
* You should have received a copy of the GNU Library General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
24
#include "rsnaudiodec.h"
26
GST_DEBUG_CATEGORY_STATIC (rsn_audiodec_debug);
27
#define GST_CAT_DEFAULT rsn_audiodec_debug
29
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
32
GST_STATIC_CAPS ("audio/mpeg,mpegversion=(int)1;"
33
"audio/x-private1-lpcm;"
34
"audio/x-private1-ac3;" "audio/ac3;" "audio/x-ac3;"
35
"audio/x-private1-dts;")
38
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
41
GST_STATIC_CAPS ("audio/x-raw-float, "
42
"rate = (int) [ 1, MAX ], "
43
"channels = (int) [ 1, MAX ], "
44
"endianness = (int) BYTE_ORDER, "
45
"width = (int) { 32, 64 }; "
47
"rate = (int) [ 1, MAX ], "
48
"channels = (int) [ 1, MAX ], "
49
"endianness = (int) BYTE_ORDER, "
52
"signed = (boolean) true; "
54
"rate = (int) [ 1, MAX ], "
55
"channels = (int) [ 1, MAX ], "
56
"endianness = (int) BYTE_ORDER, "
59
"signed = (boolean) true; "
61
"rate = (int) [ 1, MAX ], "
62
"channels = (int) [ 1, MAX ], "
63
"endianness = (int) BYTE_ORDER, "
66
"signed = (boolean) true; "
68
"rate = (int) [ 1, MAX ], "
69
"channels = (int) [ 1, MAX ], "
70
"endianness = (int) BYTE_ORDER, "
71
"width = (int) 8, " "depth = (int) 8, " "signed = (boolean) true")
74
G_DEFINE_TYPE (RsnAudioDec, rsn_audiodec, GST_TYPE_BIN);
76
static gboolean rsn_audiodec_set_sink_caps (GstPad * pad, GstCaps * caps);
77
static GstCaps *rsn_audiodec_get_sink_caps (GstPad * pad);
78
static GstFlowReturn rsn_audiodec_chain (GstPad * pad, GstBuffer * buf);
79
static gboolean rsn_audiodec_sink_event (GstPad * pad, GstEvent * event);
80
static GstStateChangeReturn rsn_audiodec_change_state (GstElement * element,
81
GstStateChange transition);
83
static GstCaps *rsn_audiodec_get_proxy_sink_caps (GstPad * pad);
84
static GstCaps *rsn_audiodec_get_proxy_src_caps (GstPad * pad);
86
static GstFlowReturn rsn_audiodec_proxy_src_chain (GstPad * pad,
88
static gboolean rsn_audiodec_proxy_src_event (GstPad * pad, GstEvent * event);
90
static void rsn_audiodec_dispose (GObject * gobj);
91
static void cleanup_child (RsnAudioDec * self);
94
rsn_audiodec_class_init (RsnAudioDecClass * klass)
96
static GstElementDetails element_details = {
99
"Resin DVD audio stream decoder",
100
"Jan Schmidt <thaytan@noraisin.net>"
102
GObjectClass *object_class = G_OBJECT_CLASS (klass);
103
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
105
GST_DEBUG_CATEGORY_INIT (rsn_audiodec_debug, "rsnaudiodec",
106
0, "Resin DVD audio stream decoder");
108
object_class->dispose = rsn_audiodec_dispose;
110
element_class->change_state = GST_DEBUG_FUNCPTR (rsn_audiodec_change_state);
112
gst_element_class_add_pad_template (element_class,
113
gst_static_pad_template_get (&src_template));
114
gst_element_class_add_pad_template (element_class,
115
gst_static_pad_template_get (&sink_template));
117
gst_element_class_set_details (element_class, &element_details);
121
rsn_audiodec_init (RsnAudioDec * self)
123
self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
124
gst_pad_set_setcaps_function (self->sinkpad,
125
GST_DEBUG_FUNCPTR (rsn_audiodec_set_sink_caps));
126
gst_pad_set_getcaps_function (self->sinkpad,
127
GST_DEBUG_FUNCPTR (rsn_audiodec_get_sink_caps));
128
gst_pad_set_chain_function (self->sinkpad,
129
GST_DEBUG_FUNCPTR (rsn_audiodec_chain));
130
gst_pad_set_event_function (self->sinkpad,
131
GST_DEBUG_FUNCPTR (rsn_audiodec_sink_event));
132
gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
134
self->srcpad = gst_pad_new_from_static_template (&src_template, "src");
135
gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
139
rsn_audiodec_dispose (GObject * object)
141
RsnAudioDec *self = (RsnAudioDec *) object;
142
cleanup_child (self);
144
G_OBJECT_CLASS (rsn_audiodec_parent_class)->dispose (object);
148
rsn_audiodec_set_sink_caps (GstPad * pad, GstCaps * caps)
150
RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad);
155
res = gst_pad_set_caps (self->child_sink, caps);
157
gst_object_unref (self);
161
gst_object_unref (self);
166
rsn_audiodec_get_sink_caps (GstPad * sinkpad)
168
/* FIXME: Calculate set of allowed caps for all discovered decoders */
169
RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (sinkpad);
171
if (self == NULL || self->child_sink == NULL)
174
res = gst_pad_get_caps (self->child_sink);
175
GST_INFO_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, res);
177
gst_object_unref (self);
181
gst_object_unref (self);
182
return gst_caps_copy (gst_pad_get_pad_template_caps (sinkpad));
186
rsn_audiodec_chain (GstPad * pad, GstBuffer * buf)
188
RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (pad);
193
GST_INFO_OBJECT (self, "Pushing buffer %" GST_PTR_FORMAT " into decoder",
195
res = gst_pad_chain (self->child_sink, buf);
197
gst_object_unref (self);
201
gst_object_unref (self);
202
return GST_FLOW_ERROR;
206
rsn_audiodec_sink_event (GstPad * pad, GstEvent * event)
208
GstPad *sinkpad = GST_PAD (gst_pad_get_parent (pad));
209
RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (sinkpad);
212
gst_object_unref (sinkpad);
217
GST_INFO_OBJECT (self, "Sending event %" GST_PTR_FORMAT " into decoder",
219
res = gst_pad_send_event (self->child_sink, event);
221
gst_object_unref (self);
225
gst_object_unref (self);
230
rsn_audiodec_get_proxy_sink_caps (GstPad * pad)
232
GstPad *sinkpad = GST_PAD (gst_pad_get_parent (pad));
235
if (sinkpad != NULL) {
236
ret = gst_pad_get_caps (sinkpad);
238
ret = gst_caps_new_any ();
240
gst_object_unref (sinkpad);
246
rsn_audiodec_get_proxy_src_caps (GstPad * pad)
248
GstPad *srcpad = GST_PAD (gst_pad_get_parent (pad));
251
if (srcpad != NULL) {
252
ret = gst_pad_get_caps (srcpad);
254
ret = gst_caps_new_any ();
256
gst_object_unref (srcpad);
262
rsn_audiodec_proxy_src_chain (GstPad * pad, GstBuffer * buf)
264
GstPad *srcpad = GST_PAD (gst_pad_get_parent (pad));
265
RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (srcpad);
268
gst_object_unref (srcpad);
271
return GST_FLOW_ERROR;
273
GST_DEBUG_OBJECT (self, "Data from decoder, pushing to pad %"
274
GST_PTR_FORMAT, self->srcpad);
275
ret = gst_pad_push (self->srcpad, buf);
277
gst_object_unref (self);
283
rsn_audiodec_proxy_src_event (GstPad * pad, GstEvent * event)
285
GstPad *srcpad = GST_PAD (gst_pad_get_parent (pad));
286
RsnAudioDec *self = (RsnAudioDec *) gst_pad_get_parent (srcpad);
289
gst_object_unref (srcpad);
294
ret = gst_pad_push_event (self->srcpad, event);
296
gst_object_unref (self);
301
create_proxy_pads (RsnAudioDec * self)
303
if (self->child_sink_proxy == NULL) {
304
/* A src pad the child can query/send events to */
305
self->child_sink_proxy = gst_pad_new ("sink_proxy", GST_PAD_SRC);
306
gst_object_set_parent ((GstObject *) self->child_sink_proxy,
307
(GstObject *) self->sinkpad);
308
gst_pad_set_getcaps_function (self->child_sink_proxy,
309
GST_DEBUG_FUNCPTR (rsn_audiodec_get_proxy_sink_caps));
312
if (self->child_src_proxy == NULL) {
313
/* A sink pad the child can push to */
314
self->child_src_proxy = gst_pad_new ("src_proxy", GST_PAD_SINK);
315
gst_object_set_parent ((GstObject *) self->child_src_proxy,
316
(GstObject *) self->srcpad);
317
gst_pad_set_getcaps_function (self->child_src_proxy,
318
GST_DEBUG_FUNCPTR (rsn_audiodec_get_proxy_src_caps));
319
gst_pad_set_chain_function (self->child_src_proxy,
320
GST_DEBUG_FUNCPTR (rsn_audiodec_proxy_src_chain));
321
gst_pad_set_event_function (self->child_src_proxy,
322
GST_DEBUG_FUNCPTR (rsn_audiodec_proxy_src_event));
327
rsn_audiodec_set_child (RsnAudioDec * self, GstElement * new_child)
329
if (self->current_decoder) {
330
gst_bin_remove ((GstBin *) self, self->current_decoder);
331
self->current_decoder = NULL;
333
if (self->child_sink) {
334
(void) gst_pad_unlink (self->child_sink_proxy, self->child_sink);
335
gst_object_unref (self->child_sink);
336
self->child_sink = NULL;
338
if (self->child_src) {
339
(void) gst_pad_unlink (self->child_src, self->child_src_proxy);
340
gst_object_unref (self->child_src);
341
self->child_src = NULL;
344
if (new_child == NULL)
347
self->child_sink = gst_element_get_static_pad (new_child, "sink");
348
if (self->child_sink == NULL) {
351
self->child_src = gst_element_get_static_pad (new_child, "src");
352
if (self->child_src == NULL) {
355
if (!gst_bin_add ((GstBin *) self, new_child)) {
359
GST_DEBUG_OBJECT (self, "Add child %" GST_PTR_FORMAT, new_child);
360
self->current_decoder = new_child;
361
if (gst_pad_link (self->child_sink_proxy,
362
self->child_sink) != GST_PAD_LINK_OK)
364
GST_DEBUG_OBJECT (self, "linked proxy sink pad %" GST_PTR_FORMAT
365
" to child sink %" GST_PTR_FORMAT, self->child_sink_proxy,
367
if (gst_pad_link (self->child_src, self->child_src_proxy) != GST_PAD_LINK_OK)
369
GST_DEBUG_OBJECT (self, "linked child src pad %" GST_PTR_FORMAT
370
" to proxy pad %" GST_PTR_FORMAT, self->child_src, self->child_src_proxy);
376
cleanup_child (RsnAudioDec * self)
378
GST_DEBUG_OBJECT (self, "Removing child element");
379
(void) rsn_audiodec_set_child (self, NULL);
380
GST_DEBUG_OBJECT (self, "Destroying proxy pads");
381
if (self->child_sink_proxy != NULL) {
382
gst_object_unparent ((GstObject *) self->child_sink_proxy);
383
self->child_sink_proxy = NULL;
385
if (self->child_src_proxy != NULL) {
386
gst_object_unparent ((GstObject *) self->child_src_proxy);
387
self->child_src_proxy = NULL;
391
static GstStateChangeReturn
392
rsn_audiodec_change_state (GstElement * element, GstStateChange transition)
394
GstStateChangeReturn ret;
395
RsnAudioDec *self = RSN_AUDIODEC (element);
397
switch (transition) {
398
case GST_STATE_CHANGE_NULL_TO_READY:{
399
GstElement *new_child;
400
create_proxy_pads (self);
401
GST_DEBUG_OBJECT (self, "Created proxy pads");
402
new_child = gst_element_factory_make ("a52dec", NULL);
403
if (new_child == NULL || !rsn_audiodec_set_child (self, new_child))
404
ret = GST_STATE_CHANGE_FAILURE;
407
case GST_STATE_CHANGE_READY_TO_PAUSED:
408
GST_DEBUG_OBJECT (self, "Activating proxy pads");
409
if (self->child_sink_proxy)
410
gst_pad_set_active (self->child_sink_proxy, TRUE);
411
if (self->child_src_proxy)
412
gst_pad_set_active (self->child_src_proxy, TRUE);
419
GST_ELEMENT_CLASS (rsn_audiodec_parent_class)->change_state (element,
421
if (ret == GST_STATE_CHANGE_FAILURE)
424
switch (transition) {
425
case GST_STATE_CHANGE_PAUSED_TO_READY:
426
GST_DEBUG_OBJECT (self, "Deactivating proxy pads");
427
if (self->child_sink_proxy)
428
gst_pad_set_active (self->child_sink_proxy, FALSE);
429
if (self->child_src_proxy)
430
gst_pad_set_active (self->child_src_proxy, FALSE);
432
case GST_STATE_CHANGE_READY_TO_NULL:
433
cleanup_child (self);