2
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3
* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Library General Public
8
* License as published by the Free Software Foundation; either
9
* version 2 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Library General Public License for more details.
16
* You should have received a copy of the GNU Library General Public
17
* License along with this library; if not, write to the
18
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
* Boston, MA 02111-1307, USA.
23
* Based on the speexdec element.
27
* SECTION:element-celtdec
28
* @see_also: celtenc, oggdemux
30
* This element decodes a CELT stream to raw integer audio.
33
* <title>Example pipelines</title>
35
* gst-launch -v filesrc location=celt.ogg ! oggdemux ! celtdec ! audioconvert ! audioresample ! alsasink
36
* ]| Decode an Ogg/Celt file. To create an Ogg/Celt file refer to the documentation of celtenc.
44
#include "gstceltdec.h"
46
#include <gst/tag/tag.h>
48
GST_DEBUG_CATEGORY_STATIC (celtdec_debug);
49
#define GST_CAT_DEFAULT celtdec_debug
51
static GstStaticPadTemplate celt_dec_src_factory =
52
GST_STATIC_PAD_TEMPLATE ("src",
55
GST_STATIC_CAPS ("audio/x-raw-int, "
56
"rate = (int) [ 32000, 64000 ], "
57
"channels = (int) [ 1, 2 ], "
58
"endianness = (int) BYTE_ORDER, "
59
"signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16")
62
static GstStaticPadTemplate celt_dec_sink_factory =
63
GST_STATIC_PAD_TEMPLATE ("sink",
66
GST_STATIC_CAPS ("audio/x-celt")
69
GST_BOILERPLATE (GstCeltDec, gst_celt_dec, GstElement, GST_TYPE_ELEMENT);
71
static gboolean celt_dec_sink_event (GstPad * pad, GstEvent * event);
72
static GstFlowReturn celt_dec_chain (GstPad * pad, GstBuffer * buf);
73
static GstStateChangeReturn celt_dec_change_state (GstElement * element,
74
GstStateChange transition);
76
static gboolean celt_dec_src_event (GstPad * pad, GstEvent * event);
77
static gboolean celt_dec_src_query (GstPad * pad, GstQuery * query);
78
static gboolean celt_dec_sink_query (GstPad * pad, GstQuery * query);
79
static const GstQueryType *celt_get_src_query_types (GstPad * pad);
80
static const GstQueryType *celt_get_sink_query_types (GstPad * pad);
81
static gboolean celt_dec_convert (GstPad * pad,
82
GstFormat src_format, gint64 src_value,
83
GstFormat * dest_format, gint64 * dest_value);
85
static GstFlowReturn celt_dec_chain_parse_data (GstCeltDec * dec,
86
GstBuffer * buf, GstClockTime timestamp, GstClockTime duration);
89
gst_celt_dec_base_init (gpointer g_class)
91
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
93
gst_element_class_add_pad_template (element_class,
94
gst_static_pad_template_get (&celt_dec_src_factory));
95
gst_element_class_add_pad_template (element_class,
96
gst_static_pad_template_get (&celt_dec_sink_factory));
97
gst_element_class_set_details_simple (element_class, "Celt audio decoder",
98
"Codec/Decoder/Audio",
99
"decode celt streams to audio",
100
"Sebastian Dröge <sebastian.droege@collabora.co.uk>");
104
gst_celt_dec_class_init (GstCeltDecClass * klass)
106
GstElementClass *gstelement_class;
108
gstelement_class = (GstElementClass *) klass;
110
gstelement_class->change_state = GST_DEBUG_FUNCPTR (celt_dec_change_state);
112
GST_DEBUG_CATEGORY_INIT (celtdec_debug, "celtdec", 0,
113
"celt decoding element");
117
gst_celt_dec_reset (GstCeltDec * dec)
119
gst_segment_init (&dec->segment, GST_FORMAT_UNDEFINED);
120
dec->granulepos = -1;
123
dec->frame_duration = 0;
125
celt_decoder_destroy (dec->state);
130
celt_mode_destroy (dec->mode);
134
memset (&dec->header, 0, sizeof (dec->header));
138
gst_celt_dec_init (GstCeltDec * dec, GstCeltDecClass * g_class)
141
gst_pad_new_from_static_template (&celt_dec_sink_factory, "sink");
142
gst_pad_set_chain_function (dec->sinkpad, GST_DEBUG_FUNCPTR (celt_dec_chain));
143
gst_pad_set_event_function (dec->sinkpad,
144
GST_DEBUG_FUNCPTR (celt_dec_sink_event));
145
gst_pad_set_query_type_function (dec->sinkpad,
146
GST_DEBUG_FUNCPTR (celt_get_sink_query_types));
147
gst_pad_set_query_function (dec->sinkpad,
148
GST_DEBUG_FUNCPTR (celt_dec_sink_query));
149
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
151
dec->srcpad = gst_pad_new_from_static_template (&celt_dec_src_factory, "src");
152
gst_pad_use_fixed_caps (dec->srcpad);
153
gst_pad_set_event_function (dec->srcpad,
154
GST_DEBUG_FUNCPTR (celt_dec_src_event));
155
gst_pad_set_query_type_function (dec->srcpad,
156
GST_DEBUG_FUNCPTR (celt_get_src_query_types));
157
gst_pad_set_query_function (dec->srcpad,
158
GST_DEBUG_FUNCPTR (celt_dec_src_query));
159
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
161
gst_celt_dec_reset (dec);
165
celt_dec_convert (GstPad * pad,
166
GstFormat src_format, gint64 src_value,
167
GstFormat * dest_format, gint64 * dest_value)
173
dec = GST_CELT_DEC (gst_pad_get_parent (pad));
175
if (dec->packetno < 1) {
180
if (src_format == *dest_format) {
181
*dest_value = src_value;
186
if (pad == dec->sinkpad &&
187
(src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES)) {
192
switch (src_format) {
193
case GST_FORMAT_TIME:
194
switch (*dest_format) {
195
case GST_FORMAT_BYTES:
196
scale = sizeof (gint16) * dec->header.nb_channels;
197
case GST_FORMAT_DEFAULT:
199
gst_util_uint64_scale_int (scale * src_value,
200
dec->header.sample_rate, GST_SECOND);
207
case GST_FORMAT_DEFAULT:
208
switch (*dest_format) {
209
case GST_FORMAT_BYTES:
210
*dest_value = src_value * sizeof (gint16) * dec->header.nb_channels;
212
case GST_FORMAT_TIME:
214
gst_util_uint64_scale_int (src_value, GST_SECOND,
215
dec->header.sample_rate);
222
case GST_FORMAT_BYTES:
223
switch (*dest_format) {
224
case GST_FORMAT_DEFAULT:
225
*dest_value = src_value / (sizeof (gint16) * dec->header.nb_channels);
227
case GST_FORMAT_TIME:
228
*dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
229
dec->header.sample_rate * sizeof (gint16) *
230
dec->header.nb_channels);
243
gst_object_unref (dec);
247
static const GstQueryType *
248
celt_get_sink_query_types (GstPad * pad)
250
static const GstQueryType celt_dec_sink_query_types[] = {
255
return celt_dec_sink_query_types;
259
celt_dec_sink_query (GstPad * pad, GstQuery * query)
264
dec = GST_CELT_DEC (gst_pad_get_parent (pad));
266
switch (GST_QUERY_TYPE (query)) {
267
case GST_QUERY_CONVERT:
269
GstFormat src_fmt, dest_fmt;
270
gint64 src_val, dest_val;
272
gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
273
res = celt_dec_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val);
275
gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
280
res = gst_pad_query_default (pad, query);
284
gst_object_unref (dec);
288
static const GstQueryType *
289
celt_get_src_query_types (GstPad * pad)
291
static const GstQueryType celt_dec_src_query_types[] = {
297
return celt_dec_src_query_types;
301
celt_dec_src_query (GstPad * pad, GstQuery * query)
304
gboolean res = FALSE;
306
dec = GST_CELT_DEC (gst_pad_get_parent (pad));
308
switch (GST_QUERY_TYPE (query)) {
309
case GST_QUERY_POSITION:{
314
gst_query_parse_position (query, &format, NULL);
316
GST_PAD_STREAM_LOCK (dec->sinkpad);
317
segment = dec->segment;
318
GST_PAD_STREAM_UNLOCK (dec->sinkpad);
320
if (segment.format != GST_FORMAT_TIME) {
321
GST_DEBUG_OBJECT (dec, "segment not initialised yet");
325
if ((res = celt_dec_convert (dec->srcpad, GST_FORMAT_TIME,
326
segment.last_stop, &format, &cur))) {
327
gst_query_set_position (query, format, cur);
331
case GST_QUERY_DURATION:{
332
GstFormat format = GST_FORMAT_TIME;
335
/* get duration from demuxer */
336
if (!gst_pad_query_peer_duration (dec->sinkpad, &format, &dur))
339
gst_query_parse_duration (query, &format, NULL);
341
/* and convert it into the requested format */
342
if ((res = celt_dec_convert (dec->srcpad, GST_FORMAT_TIME,
343
dur, &format, &dur))) {
344
gst_query_set_duration (query, format, dur);
349
res = gst_pad_query_default (pad, query);
353
gst_object_unref (dec);
358
celt_dec_src_event (GstPad * pad, GstEvent * event)
360
gboolean res = FALSE;
361
GstCeltDec *dec = GST_CELT_DEC (gst_pad_get_parent (pad));
363
GST_LOG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));
365
switch (GST_EVENT_TYPE (event)) {
366
case GST_EVENT_SEEK:{
367
GstFormat format, tformat;
371
GstSeekType cur_type, stop_type;
375
gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
378
/* we have to ask our peer to seek to time here as we know
379
* nothing about how to generate a granulepos from the src
380
* formats or anything.
382
* First bring the requested format to time
384
tformat = GST_FORMAT_TIME;
385
if (!(res = celt_dec_convert (pad, format, cur, &tformat, &tcur)))
387
if (!(res = celt_dec_convert (pad, format, stop, &tformat, &tstop)))
390
/* then seek with time on the peer */
391
real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
392
flags, cur_type, tcur, stop_type, tstop);
394
GST_LOG_OBJECT (dec, "seek to %" GST_TIME_FORMAT, GST_TIME_ARGS (tcur));
396
res = gst_pad_push_event (dec->sinkpad, real_seek);
397
gst_event_unref (event);
401
res = gst_pad_event_default (pad, event);
405
gst_object_unref (dec);
410
celt_dec_sink_event (GstPad * pad, GstEvent * event)
413
gboolean ret = FALSE;
415
dec = GST_CELT_DEC (gst_pad_get_parent (pad));
417
GST_LOG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));
419
switch (GST_EVENT_TYPE (event)) {
420
case GST_EVENT_NEWSEGMENT:{
423
gint64 start, stop, time;
426
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
427
&start, &stop, &time);
429
if (format != GST_FORMAT_TIME)
430
goto newseg_wrong_format;
433
goto newseg_wrong_rate;
436
/* time progressed without data, see if we can fill the gap with
437
* some concealment data */
438
if (dec->segment.last_stop < start) {
439
GstClockTime duration;
441
duration = start - dec->segment.last_stop;
442
celt_dec_chain_parse_data (dec, NULL, dec->segment.last_stop,
447
/* now configure the values */
448
gst_segment_set_newsegment_full (&dec->segment, update,
449
rate, arate, GST_FORMAT_TIME, start, stop, time);
451
dec->granulepos = -1;
453
GST_DEBUG_OBJECT (dec, "segment now: cur = %" GST_TIME_FORMAT " [%"
454
GST_TIME_FORMAT " - %" GST_TIME_FORMAT "]",
455
GST_TIME_ARGS (dec->segment.last_stop),
456
GST_TIME_ARGS (dec->segment.start),
457
GST_TIME_ARGS (dec->segment.stop));
459
ret = gst_pad_push_event (dec->srcpad, event);
463
ret = gst_pad_event_default (pad, event);
467
gst_object_unref (dec);
473
GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
474
gst_object_unref (dec);
479
GST_DEBUG_OBJECT (dec, "negative rates not supported yet");
480
gst_object_unref (dec);
486
celt_dec_chain_parse_header (GstCeltDec * dec, GstBuffer * buf)
489
gint error = CELT_OK;
492
celt_header_from_packet ((const unsigned char *) GST_BUFFER_DATA (buf),
493
GST_BUFFER_SIZE (buf), &dec->header);
495
if (memcmp (dec->header.codec_id, "CELT ", 8) != 0)
499
celt_mode_create (dec->header.sample_rate, dec->header.nb_channels,
500
dec->header.frame_size, &error);
502
goto mode_init_failed;
504
/* initialize the decoder */
505
dec->state = celt_decoder_create (dec->mode);
509
celt_mode_info (dec->mode, CELT_GET_FRAME_SIZE, &dec->frame_size);
511
dec->frame_duration = gst_util_uint64_scale_int (dec->frame_size,
512
GST_SECOND, dec->header.sample_rate);
515
caps = gst_caps_new_simple ("audio/x-raw-int",
516
"rate", G_TYPE_INT, dec->header.sample_rate,
517
"channels", G_TYPE_INT, dec->header.nb_channels,
518
"signed", G_TYPE_BOOLEAN, TRUE,
519
"endianness", G_TYPE_INT, G_BYTE_ORDER,
520
"width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
522
if (!gst_pad_set_caps (dec->srcpad, caps))
525
gst_caps_unref (caps);
531
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
532
(NULL), ("Invalid header"));
533
return GST_FLOW_ERROR;
537
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
538
(NULL), ("Mode initialization failed: %d", error));
539
return GST_FLOW_ERROR;
543
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
544
(NULL), ("couldn't initialize decoder"));
545
return GST_FLOW_ERROR;
549
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
550
(NULL), ("couldn't negotiate format"));
551
gst_caps_unref (caps);
552
return GST_FLOW_NOT_NEGOTIATED;
557
celt_dec_chain_parse_comments (GstCeltDec * dec, GstBuffer * buf)
560
gchar *ver, *encoder = NULL;
562
list = gst_tag_list_from_vorbiscomment_buffer (buf, NULL, 0, &encoder);
565
GST_WARNING_OBJECT (dec, "couldn't decode comments");
566
list = gst_tag_list_new ();
570
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
571
GST_TAG_ENCODER, encoder, NULL);
574
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
575
GST_TAG_AUDIO_CODEC, "Celt", NULL);
577
ver = g_strndup (dec->header.codec_version, 20);
580
if (ver != NULL && *ver != '\0') {
581
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
582
GST_TAG_ENCODER_VERSION, ver, NULL);
585
if (dec->header.bytes_per_packet > 0) {
586
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
587
GST_TAG_BITRATE, (guint) dec->header.bytes_per_packet * 8, NULL);
590
GST_INFO_OBJECT (dec, "tags: %" GST_PTR_FORMAT, list);
592
gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, list);
601
celt_dec_chain_parse_data (GstCeltDec * dec, GstBuffer * buf,
602
GstClockTime timestamp, GstClockTime duration)
604
GstFlowReturn res = GST_FLOW_OK;
609
gint error = CELT_OK;
611
if (timestamp != -1) {
612
dec->segment.last_stop = timestamp;
613
dec->granulepos = -1;
617
data = GST_BUFFER_DATA (buf);
618
size = GST_BUFFER_SIZE (buf);
620
GST_DEBUG_OBJECT (dec, "received buffer of size %u", size);
621
if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)
622
&& GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
623
dec->granulepos = GST_BUFFER_OFFSET_END (buf);
624
GST_DEBUG_OBJECT (dec,
625
"Taking granulepos from upstream: %" G_GUINT64_FORMAT,
631
/* concealment data, pass NULL as the bits parameters */
632
GST_DEBUG_OBJECT (dec, "creating concealment data");
637
res = gst_pad_alloc_buffer_and_set_caps (dec->srcpad,
638
GST_BUFFER_OFFSET_NONE, dec->frame_size * dec->header.nb_channels * 2,
639
GST_PAD_CAPS (dec->srcpad), &outbuf);
641
if (res != GST_FLOW_OK) {
642
GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res));
646
out_data = (gint16 *) GST_BUFFER_DATA (outbuf);
648
GST_LOG_OBJECT (dec, "decoding frame");
650
error = celt_decode (dec->state, data, size, out_data);
651
if (error != CELT_OK) {
652
GST_WARNING_OBJECT (dec, "Decoding error: %d", error);
653
return GST_FLOW_ERROR;
656
if (dec->granulepos == -1) {
657
if (dec->segment.format != GST_FORMAT_TIME) {
658
GST_WARNING_OBJECT (dec, "segment not initialized or not TIME format");
659
dec->granulepos = dec->frame_size;
661
dec->granulepos = gst_util_uint64_scale_int (dec->segment.last_stop,
662
dec->header.sample_rate, GST_SECOND) + dec->frame_size;
664
GST_DEBUG_OBJECT (dec, "granulepos=%" G_GINT64_FORMAT, dec->granulepos);
667
GST_BUFFER_OFFSET (outbuf) = dec->granulepos - dec->frame_size;
668
GST_BUFFER_OFFSET_END (outbuf) = dec->granulepos;
669
GST_BUFFER_TIMESTAMP (outbuf) =
670
gst_util_uint64_scale_int (dec->granulepos - dec->frame_size, GST_SECOND,
671
dec->header.sample_rate);
672
GST_BUFFER_DURATION (outbuf) = dec->frame_duration;
674
dec->granulepos += dec->frame_size;
675
dec->segment.last_stop += dec->frame_duration;
677
GST_LOG_OBJECT (dec, "pushing buffer with ts=%" GST_TIME_FORMAT ", dur=%"
678
GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
679
GST_TIME_ARGS (dec->frame_duration));
681
res = gst_pad_push (dec->srcpad, outbuf);
683
if (res != GST_FLOW_OK)
684
GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res));
690
celt_dec_chain (GstPad * pad, GstBuffer * buf)
695
dec = GST_CELT_DEC (gst_pad_get_parent (pad));
697
if (dec->packetno == 0)
698
res = celt_dec_chain_parse_header (dec, buf);
699
else if (dec->packetno == 1)
700
res = celt_dec_chain_parse_comments (dec, buf);
701
else if (dec->packetno <= 1 + dec->header.extra_headers)
705
celt_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf),
706
GST_BUFFER_DURATION (buf));
710
gst_buffer_unref (buf);
711
gst_object_unref (dec);
716
static GstStateChangeReturn
717
celt_dec_change_state (GstElement * element, GstStateChange transition)
719
GstStateChangeReturn ret;
720
GstCeltDec *dec = GST_CELT_DEC (element);
722
switch (transition) {
723
case GST_STATE_CHANGE_NULL_TO_READY:
724
case GST_STATE_CHANGE_READY_TO_PAUSED:
725
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
730
ret = parent_class->change_state (element, transition);
731
if (ret != GST_STATE_CHANGE_SUCCESS)
734
switch (transition) {
735
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
737
case GST_STATE_CHANGE_PAUSED_TO_READY:
738
gst_celt_dec_reset (dec);
740
case GST_STATE_CHANGE_READY_TO_NULL: