~ubuntu-branches/ubuntu/quantal/gst-plugins-bad-multiverse0.10/quantal

« back to all changes in this revision

Viewing changes to ext/celt/gstceltdec.c

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2009-02-23 02:23:58 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20090223022358-9yhx5izc7dz60yc8
Tags: 0.10.10-0ubuntu1
* New upstream release.
* debian/rules
  - Disable some plugins which get built by default but we do not ship in 
    multiverse package.
  - Do not build docs as there is no multiverse-doc package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer
 
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>
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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.
 
20
 */
 
21
 
 
22
/*
 
23
 * Based on the speexdec element.
 
24
 */
 
25
 
 
26
/**
 
27
 * SECTION:element-celtdec
 
28
 * @see_also: celtenc, oggdemux
 
29
 *
 
30
 * This element decodes a CELT stream to raw integer audio.
 
31
 *
 
32
 * <refsect2>
 
33
 * <title>Example pipelines</title>
 
34
 * |[
 
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.
 
37
 * </refsect2>
 
38
 */
 
39
 
 
40
#ifdef HAVE_CONFIG_H
 
41
#  include "config.h"
 
42
#endif
 
43
 
 
44
#include "gstceltdec.h"
 
45
#include <string.h>
 
46
#include <gst/tag/tag.h>
 
47
 
 
48
GST_DEBUG_CATEGORY_STATIC (celtdec_debug);
 
49
#define GST_CAT_DEFAULT celtdec_debug
 
50
 
 
51
static GstStaticPadTemplate celt_dec_src_factory =
 
52
GST_STATIC_PAD_TEMPLATE ("src",
 
53
    GST_PAD_SRC,
 
54
    GST_PAD_ALWAYS,
 
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")
 
60
    );
 
61
 
 
62
static GstStaticPadTemplate celt_dec_sink_factory =
 
63
GST_STATIC_PAD_TEMPLATE ("sink",
 
64
    GST_PAD_SINK,
 
65
    GST_PAD_ALWAYS,
 
66
    GST_STATIC_CAPS ("audio/x-celt")
 
67
    );
 
68
 
 
69
GST_BOILERPLATE (GstCeltDec, gst_celt_dec, GstElement, GST_TYPE_ELEMENT);
 
70
 
 
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);
 
75
 
 
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);
 
84
 
 
85
static GstFlowReturn celt_dec_chain_parse_data (GstCeltDec * dec,
 
86
    GstBuffer * buf, GstClockTime timestamp, GstClockTime duration);
 
87
 
 
88
static void
 
89
gst_celt_dec_base_init (gpointer g_class)
 
90
{
 
91
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
92
 
 
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>");
 
101
}
 
102
 
 
103
static void
 
104
gst_celt_dec_class_init (GstCeltDecClass * klass)
 
105
{
 
106
  GstElementClass *gstelement_class;
 
107
 
 
108
  gstelement_class = (GstElementClass *) klass;
 
109
 
 
110
  gstelement_class->change_state = GST_DEBUG_FUNCPTR (celt_dec_change_state);
 
111
 
 
112
  GST_DEBUG_CATEGORY_INIT (celtdec_debug, "celtdec", 0,
 
113
      "celt decoding element");
 
114
}
 
115
 
 
116
static void
 
117
gst_celt_dec_reset (GstCeltDec * dec)
 
118
{
 
119
  gst_segment_init (&dec->segment, GST_FORMAT_UNDEFINED);
 
120
  dec->granulepos = -1;
 
121
  dec->packetno = 0;
 
122
  dec->frame_size = 0;
 
123
  dec->frame_duration = 0;
 
124
  if (dec->state) {
 
125
    celt_decoder_destroy (dec->state);
 
126
    dec->state = NULL;
 
127
  }
 
128
 
 
129
  if (dec->mode) {
 
130
    celt_mode_destroy (dec->mode);
 
131
    dec->mode = NULL;
 
132
  }
 
133
 
 
134
  memset (&dec->header, 0, sizeof (dec->header));
 
135
}
 
136
 
 
137
static void
 
138
gst_celt_dec_init (GstCeltDec * dec, GstCeltDecClass * g_class)
 
139
{
 
140
  dec->sinkpad =
 
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);
 
150
 
 
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);
 
160
 
 
161
  gst_celt_dec_reset (dec);
 
162
}
 
163
 
 
164
static gboolean
 
165
celt_dec_convert (GstPad * pad,
 
166
    GstFormat src_format, gint64 src_value,
 
167
    GstFormat * dest_format, gint64 * dest_value)
 
168
{
 
169
  gboolean res = TRUE;
 
170
  GstCeltDec *dec;
 
171
  guint64 scale = 1;
 
172
 
 
173
  dec = GST_CELT_DEC (gst_pad_get_parent (pad));
 
174
 
 
175
  if (dec->packetno < 1) {
 
176
    res = FALSE;
 
177
    goto cleanup;
 
178
  }
 
179
 
 
180
  if (src_format == *dest_format) {
 
181
    *dest_value = src_value;
 
182
    res = TRUE;
 
183
    goto cleanup;
 
184
  }
 
185
 
 
186
  if (pad == dec->sinkpad &&
 
187
      (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES)) {
 
188
    res = FALSE;
 
189
    goto cleanup;
 
190
  }
 
191
 
 
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:
 
198
          *dest_value =
 
199
              gst_util_uint64_scale_int (scale * src_value,
 
200
              dec->header.sample_rate, GST_SECOND);
 
201
          break;
 
202
        default:
 
203
          res = FALSE;
 
204
          break;
 
205
      }
 
206
      break;
 
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;
 
211
          break;
 
212
        case GST_FORMAT_TIME:
 
213
          *dest_value =
 
214
              gst_util_uint64_scale_int (src_value, GST_SECOND,
 
215
              dec->header.sample_rate);
 
216
          break;
 
217
        default:
 
218
          res = FALSE;
 
219
          break;
 
220
      }
 
221
      break;
 
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);
 
226
          break;
 
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);
 
231
          break;
 
232
        default:
 
233
          res = FALSE;
 
234
          break;
 
235
      }
 
236
      break;
 
237
    default:
 
238
      res = FALSE;
 
239
      break;
 
240
  }
 
241
 
 
242
cleanup:
 
243
  gst_object_unref (dec);
 
244
  return res;
 
245
}
 
246
 
 
247
static const GstQueryType *
 
248
celt_get_sink_query_types (GstPad * pad)
 
249
{
 
250
  static const GstQueryType celt_dec_sink_query_types[] = {
 
251
    GST_QUERY_CONVERT,
 
252
    0
 
253
  };
 
254
 
 
255
  return celt_dec_sink_query_types;
 
256
}
 
257
 
 
258
static gboolean
 
259
celt_dec_sink_query (GstPad * pad, GstQuery * query)
 
260
{
 
261
  GstCeltDec *dec;
 
262
  gboolean res;
 
263
 
 
264
  dec = GST_CELT_DEC (gst_pad_get_parent (pad));
 
265
 
 
266
  switch (GST_QUERY_TYPE (query)) {
 
267
    case GST_QUERY_CONVERT:
 
268
    {
 
269
      GstFormat src_fmt, dest_fmt;
 
270
      gint64 src_val, dest_val;
 
271
 
 
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);
 
274
      if (res) {
 
275
        gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
 
276
      }
 
277
      break;
 
278
    }
 
279
    default:
 
280
      res = gst_pad_query_default (pad, query);
 
281
      break;
 
282
  }
 
283
 
 
284
  gst_object_unref (dec);
 
285
  return res;
 
286
}
 
287
 
 
288
static const GstQueryType *
 
289
celt_get_src_query_types (GstPad * pad)
 
290
{
 
291
  static const GstQueryType celt_dec_src_query_types[] = {
 
292
    GST_QUERY_POSITION,
 
293
    GST_QUERY_DURATION,
 
294
    0
 
295
  };
 
296
 
 
297
  return celt_dec_src_query_types;
 
298
}
 
299
 
 
300
static gboolean
 
301
celt_dec_src_query (GstPad * pad, GstQuery * query)
 
302
{
 
303
  GstCeltDec *dec;
 
304
  gboolean res = FALSE;
 
305
 
 
306
  dec = GST_CELT_DEC (gst_pad_get_parent (pad));
 
307
 
 
308
  switch (GST_QUERY_TYPE (query)) {
 
309
    case GST_QUERY_POSITION:{
 
310
      GstSegment segment;
 
311
      GstFormat format;
 
312
      gint64 cur;
 
313
 
 
314
      gst_query_parse_position (query, &format, NULL);
 
315
 
 
316
      GST_PAD_STREAM_LOCK (dec->sinkpad);
 
317
      segment = dec->segment;
 
318
      GST_PAD_STREAM_UNLOCK (dec->sinkpad);
 
319
 
 
320
      if (segment.format != GST_FORMAT_TIME) {
 
321
        GST_DEBUG_OBJECT (dec, "segment not initialised yet");
 
322
        break;
 
323
      }
 
324
 
 
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);
 
328
      }
 
329
      break;
 
330
    }
 
331
    case GST_QUERY_DURATION:{
 
332
      GstFormat format = GST_FORMAT_TIME;
 
333
      gint64 dur;
 
334
 
 
335
      /* get duration from demuxer */
 
336
      if (!gst_pad_query_peer_duration (dec->sinkpad, &format, &dur))
 
337
        break;
 
338
 
 
339
      gst_query_parse_duration (query, &format, NULL);
 
340
 
 
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);
 
345
      }
 
346
      break;
 
347
    }
 
348
    default:
 
349
      res = gst_pad_query_default (pad, query);
 
350
      break;
 
351
  }
 
352
 
 
353
  gst_object_unref (dec);
 
354
  return res;
 
355
}
 
356
 
 
357
static gboolean
 
358
celt_dec_src_event (GstPad * pad, GstEvent * event)
 
359
{
 
360
  gboolean res = FALSE;
 
361
  GstCeltDec *dec = GST_CELT_DEC (gst_pad_get_parent (pad));
 
362
 
 
363
  GST_LOG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));
 
364
 
 
365
  switch (GST_EVENT_TYPE (event)) {
 
366
    case GST_EVENT_SEEK:{
 
367
      GstFormat format, tformat;
 
368
      gdouble rate;
 
369
      GstEvent *real_seek;
 
370
      GstSeekFlags flags;
 
371
      GstSeekType cur_type, stop_type;
 
372
      gint64 cur, stop;
 
373
      gint64 tcur, tstop;
 
374
 
 
375
      gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
 
376
          &stop_type, &stop);
 
377
 
 
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.
 
381
       *
 
382
       * First bring the requested format to time
 
383
       */
 
384
      tformat = GST_FORMAT_TIME;
 
385
      if (!(res = celt_dec_convert (pad, format, cur, &tformat, &tcur)))
 
386
        break;
 
387
      if (!(res = celt_dec_convert (pad, format, stop, &tformat, &tstop)))
 
388
        break;
 
389
 
 
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);
 
393
 
 
394
      GST_LOG_OBJECT (dec, "seek to %" GST_TIME_FORMAT, GST_TIME_ARGS (tcur));
 
395
 
 
396
      res = gst_pad_push_event (dec->sinkpad, real_seek);
 
397
      gst_event_unref (event);
 
398
      break;
 
399
    }
 
400
    default:
 
401
      res = gst_pad_event_default (pad, event);
 
402
      break;
 
403
  }
 
404
 
 
405
  gst_object_unref (dec);
 
406
  return res;
 
407
}
 
408
 
 
409
static gboolean
 
410
celt_dec_sink_event (GstPad * pad, GstEvent * event)
 
411
{
 
412
  GstCeltDec *dec;
 
413
  gboolean ret = FALSE;
 
414
 
 
415
  dec = GST_CELT_DEC (gst_pad_get_parent (pad));
 
416
 
 
417
  GST_LOG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));
 
418
 
 
419
  switch (GST_EVENT_TYPE (event)) {
 
420
    case GST_EVENT_NEWSEGMENT:{
 
421
      GstFormat format;
 
422
      gdouble rate, arate;
 
423
      gint64 start, stop, time;
 
424
      gboolean update;
 
425
 
 
426
      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
 
427
          &start, &stop, &time);
 
428
 
 
429
      if (format != GST_FORMAT_TIME)
 
430
        goto newseg_wrong_format;
 
431
 
 
432
      if (rate <= 0.0)
 
433
        goto newseg_wrong_rate;
 
434
 
 
435
      if (update) {
 
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;
 
440
 
 
441
          duration = start - dec->segment.last_stop;
 
442
          celt_dec_chain_parse_data (dec, NULL, dec->segment.last_stop,
 
443
              duration);
 
444
        }
 
445
      }
 
446
 
 
447
      /* now configure the values */
 
448
      gst_segment_set_newsegment_full (&dec->segment, update,
 
449
          rate, arate, GST_FORMAT_TIME, start, stop, time);
 
450
 
 
451
      dec->granulepos = -1;
 
452
 
 
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));
 
458
 
 
459
      ret = gst_pad_push_event (dec->srcpad, event);
 
460
      break;
 
461
    }
 
462
    default:
 
463
      ret = gst_pad_event_default (pad, event);
 
464
      break;
 
465
  }
 
466
 
 
467
  gst_object_unref (dec);
 
468
  return ret;
 
469
 
 
470
  /* ERRORS */
 
471
newseg_wrong_format:
 
472
  {
 
473
    GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
 
474
    gst_object_unref (dec);
 
475
    return FALSE;
 
476
  }
 
477
newseg_wrong_rate:
 
478
  {
 
479
    GST_DEBUG_OBJECT (dec, "negative rates not supported yet");
 
480
    gst_object_unref (dec);
 
481
    return FALSE;
 
482
  }
 
483
}
 
484
 
 
485
static GstFlowReturn
 
486
celt_dec_chain_parse_header (GstCeltDec * dec, GstBuffer * buf)
 
487
{
 
488
  GstCaps *caps;
 
489
  gint error = CELT_OK;
 
490
 
 
491
  /* get the header */
 
492
  celt_header_from_packet ((const unsigned char *) GST_BUFFER_DATA (buf),
 
493
      GST_BUFFER_SIZE (buf), &dec->header);
 
494
 
 
495
  if (memcmp (dec->header.codec_id, "CELT    ", 8) != 0)
 
496
    goto invalid_header;
 
497
 
 
498
  dec->mode =
 
499
      celt_mode_create (dec->header.sample_rate, dec->header.nb_channels,
 
500
      dec->header.frame_size, &error);
 
501
  if (!dec->mode)
 
502
    goto mode_init_failed;
 
503
 
 
504
  /* initialize the decoder */
 
505
  dec->state = celt_decoder_create (dec->mode);
 
506
  if (!dec->state)
 
507
    goto init_failed;
 
508
 
 
509
  celt_mode_info (dec->mode, CELT_GET_FRAME_SIZE, &dec->frame_size);
 
510
 
 
511
  dec->frame_duration = gst_util_uint64_scale_int (dec->frame_size,
 
512
      GST_SECOND, dec->header.sample_rate);
 
513
 
 
514
  /* set caps */
 
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);
 
521
 
 
522
  if (!gst_pad_set_caps (dec->srcpad, caps))
 
523
    goto nego_failed;
 
524
 
 
525
  gst_caps_unref (caps);
 
526
  return GST_FLOW_OK;
 
527
 
 
528
  /* ERRORS */
 
529
invalid_header:
 
530
  {
 
531
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
 
532
        (NULL), ("Invalid header"));
 
533
    return GST_FLOW_ERROR;
 
534
  }
 
535
mode_init_failed:
 
536
  {
 
537
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
 
538
        (NULL), ("Mode initialization failed: %d", error));
 
539
    return GST_FLOW_ERROR;
 
540
  }
 
541
init_failed:
 
542
  {
 
543
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
 
544
        (NULL), ("couldn't initialize decoder"));
 
545
    return GST_FLOW_ERROR;
 
546
  }
 
547
nego_failed:
 
548
  {
 
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;
 
553
  }
 
554
}
 
555
 
 
556
static GstFlowReturn
 
557
celt_dec_chain_parse_comments (GstCeltDec * dec, GstBuffer * buf)
 
558
{
 
559
  GstTagList *list;
 
560
  gchar *ver, *encoder = NULL;
 
561
 
 
562
  list = gst_tag_list_from_vorbiscomment_buffer (buf, NULL, 0, &encoder);
 
563
 
 
564
  if (!list) {
 
565
    GST_WARNING_OBJECT (dec, "couldn't decode comments");
 
566
    list = gst_tag_list_new ();
 
567
  }
 
568
 
 
569
  if (encoder) {
 
570
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
 
571
        GST_TAG_ENCODER, encoder, NULL);
 
572
  }
 
573
 
 
574
  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
 
575
      GST_TAG_AUDIO_CODEC, "Celt", NULL);
 
576
 
 
577
  ver = g_strndup (dec->header.codec_version, 20);
 
578
  g_strstrip (ver);
 
579
 
 
580
  if (ver != NULL && *ver != '\0') {
 
581
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
 
582
        GST_TAG_ENCODER_VERSION, ver, NULL);
 
583
  }
 
584
 
 
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);
 
588
  }
 
589
 
 
590
  GST_INFO_OBJECT (dec, "tags: %" GST_PTR_FORMAT, list);
 
591
 
 
592
  gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, list);
 
593
 
 
594
  g_free (encoder);
 
595
  g_free (ver);
 
596
 
 
597
  return GST_FLOW_OK;
 
598
}
 
599
 
 
600
static GstFlowReturn
 
601
celt_dec_chain_parse_data (GstCeltDec * dec, GstBuffer * buf,
 
602
    GstClockTime timestamp, GstClockTime duration)
 
603
{
 
604
  GstFlowReturn res = GST_FLOW_OK;
 
605
  gint size;
 
606
  guint8 *data;
 
607
  GstBuffer *outbuf;
 
608
  gint16 *out_data;
 
609
  gint error = CELT_OK;
 
610
 
 
611
  if (timestamp != -1) {
 
612
    dec->segment.last_stop = timestamp;
 
613
    dec->granulepos = -1;
 
614
  }
 
615
 
 
616
  if (buf) {
 
617
    data = GST_BUFFER_DATA (buf);
 
618
    size = GST_BUFFER_SIZE (buf);
 
619
 
 
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,
 
626
          dec->granulepos);
 
627
    }
 
628
 
 
629
    /* copy timestamp */
 
630
  } else {
 
631
    /* concealment data, pass NULL as the bits parameters */
 
632
    GST_DEBUG_OBJECT (dec, "creating concealment data");
 
633
    data = NULL;
 
634
    size = 0;
 
635
  }
 
636
 
 
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);
 
640
 
 
641
  if (res != GST_FLOW_OK) {
 
642
    GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res));
 
643
    return res;
 
644
  }
 
645
 
 
646
  out_data = (gint16 *) GST_BUFFER_DATA (outbuf);
 
647
 
 
648
  GST_LOG_OBJECT (dec, "decoding frame");
 
649
 
 
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;
 
654
  }
 
655
 
 
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;
 
660
    } else {
 
661
      dec->granulepos = gst_util_uint64_scale_int (dec->segment.last_stop,
 
662
          dec->header.sample_rate, GST_SECOND) + dec->frame_size;
 
663
    }
 
664
    GST_DEBUG_OBJECT (dec, "granulepos=%" G_GINT64_FORMAT, dec->granulepos);
 
665
  }
 
666
 
 
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;
 
673
 
 
674
  dec->granulepos += dec->frame_size;
 
675
  dec->segment.last_stop += dec->frame_duration;
 
676
 
 
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));
 
680
 
 
681
  res = gst_pad_push (dec->srcpad, outbuf);
 
682
 
 
683
  if (res != GST_FLOW_OK)
 
684
    GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res));
 
685
 
 
686
  return res;
 
687
}
 
688
 
 
689
static GstFlowReturn
 
690
celt_dec_chain (GstPad * pad, GstBuffer * buf)
 
691
{
 
692
  GstFlowReturn res;
 
693
  GstCeltDec *dec;
 
694
 
 
695
  dec = GST_CELT_DEC (gst_pad_get_parent (pad));
 
696
 
 
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)
 
702
    res = GST_FLOW_OK;
 
703
  else
 
704
    res =
 
705
        celt_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf),
 
706
        GST_BUFFER_DURATION (buf));
 
707
 
 
708
  dec->packetno++;
 
709
 
 
710
  gst_buffer_unref (buf);
 
711
  gst_object_unref (dec);
 
712
 
 
713
  return res;
 
714
}
 
715
 
 
716
static GstStateChangeReturn
 
717
celt_dec_change_state (GstElement * element, GstStateChange transition)
 
718
{
 
719
  GstStateChangeReturn ret;
 
720
  GstCeltDec *dec = GST_CELT_DEC (element);
 
721
 
 
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:
 
726
    default:
 
727
      break;
 
728
  }
 
729
 
 
730
  ret = parent_class->change_state (element, transition);
 
731
  if (ret != GST_STATE_CHANGE_SUCCESS)
 
732
    return ret;
 
733
 
 
734
  switch (transition) {
 
735
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
 
736
      break;
 
737
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 
738
      gst_celt_dec_reset (dec);
 
739
      break;
 
740
    case GST_STATE_CHANGE_READY_TO_NULL:
 
741
      break;
 
742
    default:
 
743
      break;
 
744
  }
 
745
 
 
746
  return ret;
 
747
}