~oah-dev/oah/gst-plugins-bad

« back to all changes in this revision

Viewing changes to ext/amrwb/gstamrwbparse.c

  • Committer: Haakon Sporsheim
  • Date: 2009-03-12 13:52:03 UTC
  • Revision ID: haakon.sporsheim@tandberg.com-20090312135203-i5k294hgkushb0mt
Initial import of git repository: git://anongit.freedesktop.org/gstreamer/gst-plugins-bad (tag: RELEASE-0_10_10)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer Adaptive Multi-Rate Wide-Band (AMR-WB) plugin
 
2
 * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br>
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
18
 */
 
19
 
 
20
/**
 
21
 * SECTION:element-amrwbparse
 
22
 * @see_also: #GstAmrwbDec, #GstAmrwbEnc
 
23
 *
 
24
 * This is an AMR wideband parser.
 
25
 * 
 
26
 * <refsect2>
 
27
 * <title>Example launch line</title>
 
28
 * |[
 
29
 * gst-launch filesrc location=abc.amr ! amrwbparse ! amrwbdec ! audioresample ! audioconvert ! alsasink
 
30
 * ]|
 
31
 * </refsect2>
 
32
 */
 
33
 
 
34
#ifdef HAVE_CONFIG_H
 
35
#include "config.h"
 
36
#endif
 
37
 
 
38
#include <string.h>
 
39
#include "gstamrwbparse.h"
 
40
 
 
41
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
 
42
    GST_PAD_SRC,
 
43
    GST_PAD_ALWAYS,
 
44
    GST_STATIC_CAPS ("audio/AMR-WB, "
 
45
        "rate = (int) 16000, " "channels = (int) 1")
 
46
    );
 
47
 
 
48
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
 
49
    GST_PAD_SINK,
 
50
    GST_PAD_ALWAYS,
 
51
    GST_STATIC_CAPS ("audio/x-amr-wb-sh")
 
52
    );
 
53
 
 
54
GST_DEBUG_CATEGORY_STATIC (gst_amrwbparse_debug);
 
55
#define GST_CAT_DEFAULT gst_amrwbparse_debug
 
56
 
 
57
extern const UWord8 block_size[];
 
58
 
 
59
#define AMRWB_HEADER_SIZE 9
 
60
#define AMRWB_HEADER_STR "#!AMR-WB\n"
 
61
 
 
62
static void gst_amrwbparse_base_init (gpointer klass);
 
63
static void gst_amrwbparse_class_init (GstAmrwbParseClass * klass);
 
64
static void gst_amrwbparse_init (GstAmrwbParse * amrwbparse,
 
65
    GstAmrwbParseClass * klass);
 
66
 
 
67
static const GstQueryType *gst_amrwbparse_querytypes (GstPad * pad);
 
68
static gboolean gst_amrwbparse_query (GstPad * pad, GstQuery * query);
 
69
 
 
70
static gboolean gst_amrwbparse_sink_event (GstPad * pad, GstEvent * event);
 
71
static gboolean gst_amrwbparse_src_event (GstPad * pad, GstEvent * event);
 
72
static GstFlowReturn gst_amrwbparse_chain (GstPad * pad, GstBuffer * buffer);
 
73
static void gst_amrwbparse_loop (GstPad * pad);
 
74
static gboolean gst_amrwbparse_sink_activate (GstPad * sinkpad);
 
75
static gboolean gst_amrwbparse_sink_activate_pull (GstPad * sinkpad,
 
76
    gboolean active);
 
77
static gboolean gst_amrwbparse_sink_activate_push (GstPad * sinkpad,
 
78
    gboolean active);
 
79
static GstStateChangeReturn gst_amrwbparse_state_change (GstElement * element,
 
80
    GstStateChange transition);
 
81
 
 
82
static void gst_amrwbparse_finalize (GObject * object);
 
83
 
 
84
#define _do_init(bla) \
 
85
    GST_DEBUG_CATEGORY_INIT (gst_amrwbparse_debug, "amrwbparse", 0, "AMR-WB audio stream parser");
 
86
 
 
87
GST_BOILERPLATE_FULL (GstAmrwbParse, gst_amrwbparse, GstElement,
 
88
    GST_TYPE_ELEMENT, _do_init);
 
89
 
 
90
static void
 
91
gst_amrwbparse_base_init (gpointer klass)
 
92
{
 
93
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
94
  GstElementDetails details = GST_ELEMENT_DETAILS ("AMR-WB audio stream parser",
 
95
      "Codec/Parser/Audio",
 
96
      "Adaptive Multi-Rate WideBand audio parser",
 
97
      "Renato Filho <renato.filho@indt.org.br>");
 
98
 
 
99
  gst_element_class_add_pad_template (element_class,
 
100
      gst_static_pad_template_get (&sink_template));
 
101
  gst_element_class_add_pad_template (element_class,
 
102
      gst_static_pad_template_get (&src_template));
 
103
 
 
104
  gst_element_class_set_details (element_class, &details);
 
105
 
 
106
}
 
107
 
 
108
static void
 
109
gst_amrwbparse_class_init (GstAmrwbParseClass * klass)
 
110
{
 
111
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
112
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
113
 
 
114
  object_class->finalize = gst_amrwbparse_finalize;
 
115
 
 
116
  element_class->change_state = GST_DEBUG_FUNCPTR (gst_amrwbparse_state_change);
 
117
}
 
118
 
 
119
static void
 
120
gst_amrwbparse_init (GstAmrwbParse * amrwbparse, GstAmrwbParseClass * klass)
 
121
{
 
122
  /* create the sink pad */
 
123
  amrwbparse->sinkpad =
 
124
      gst_pad_new_from_static_template (&sink_template, "sink");
 
125
  gst_pad_set_chain_function (amrwbparse->sinkpad,
 
126
      GST_DEBUG_FUNCPTR (gst_amrwbparse_chain));
 
127
  gst_pad_set_event_function (amrwbparse->sinkpad,
 
128
      GST_DEBUG_FUNCPTR (gst_amrwbparse_sink_event));
 
129
  gst_pad_set_activate_function (amrwbparse->sinkpad,
 
130
      gst_amrwbparse_sink_activate);
 
131
  gst_pad_set_activatepull_function (amrwbparse->sinkpad,
 
132
      gst_amrwbparse_sink_activate_pull);
 
133
  gst_pad_set_activatepush_function (amrwbparse->sinkpad,
 
134
      gst_amrwbparse_sink_activate_push);
 
135
  gst_element_add_pad (GST_ELEMENT (amrwbparse), amrwbparse->sinkpad);
 
136
 
 
137
  /* create the src pad */
 
138
  amrwbparse->srcpad = gst_pad_new_from_static_template (&src_template, "src");
 
139
  gst_pad_set_event_function (amrwbparse->srcpad,
 
140
      GST_DEBUG_FUNCPTR (gst_amrwbparse_src_event));
 
141
  gst_pad_set_query_function (amrwbparse->srcpad,
 
142
      GST_DEBUG_FUNCPTR (gst_amrwbparse_query));
 
143
  gst_pad_set_query_type_function (amrwbparse->srcpad,
 
144
      GST_DEBUG_FUNCPTR (gst_amrwbparse_querytypes));
 
145
  gst_element_add_pad (GST_ELEMENT (amrwbparse), amrwbparse->srcpad);
 
146
 
 
147
  amrwbparse->adapter = gst_adapter_new ();
 
148
 
 
149
  /* init rest */
 
150
  amrwbparse->ts = 0;
 
151
}
 
152
 
 
153
static void
 
154
gst_amrwbparse_finalize (GObject * object)
 
155
{
 
156
  GstAmrwbParse *amrwbparse;
 
157
 
 
158
  amrwbparse = GST_AMRWBPARSE (object);
 
159
 
 
160
  gst_adapter_clear (amrwbparse->adapter);
 
161
  g_object_unref (amrwbparse->adapter);
 
162
 
 
163
  G_OBJECT_CLASS (parent_class)->finalize (object);
 
164
}
 
165
 
 
166
 
 
167
static const GstQueryType *
 
168
gst_amrwbparse_querytypes (GstPad * pad)
 
169
{
 
170
  static const GstQueryType list[] = {
 
171
    GST_QUERY_POSITION,
 
172
    GST_QUERY_DURATION,
 
173
    0
 
174
  };
 
175
 
 
176
  return list;
 
177
}
 
178
 
 
179
static gboolean
 
180
gst_amrwbparse_query (GstPad * pad, GstQuery * query)
 
181
{
 
182
  GstAmrwbParse *amrwbparse;
 
183
  gboolean res = TRUE;
 
184
 
 
185
  amrwbparse = GST_AMRWBPARSE (gst_pad_get_parent (pad));
 
186
 
 
187
  switch (GST_QUERY_TYPE (query)) {
 
188
    case GST_QUERY_POSITION:
 
189
    {
 
190
      GstFormat format;
 
191
      gint64 cur;
 
192
 
 
193
      gst_query_parse_position (query, &format, NULL);
 
194
 
 
195
      if (format != GST_FORMAT_TIME) {
 
196
        res = FALSE;
 
197
        break;
 
198
      }
 
199
 
 
200
      cur = amrwbparse->ts;
 
201
 
 
202
      gst_query_set_position (query, GST_FORMAT_TIME, cur);
 
203
      res = TRUE;
 
204
      break;
 
205
    }
 
206
    case GST_QUERY_DURATION:
 
207
    {
 
208
      GstFormat format;
 
209
      gint64 tot;
 
210
      GstPad *peer;
 
211
 
 
212
      gst_query_parse_duration (query, &format, NULL);
 
213
 
 
214
      if (format != GST_FORMAT_TIME) {
 
215
        res = FALSE;
 
216
        break;
 
217
      }
 
218
 
 
219
      tot = -1;
 
220
      res = FALSE;
 
221
 
 
222
      peer = gst_pad_get_peer (amrwbparse->sinkpad);
 
223
      if (peer) {
 
224
        GstFormat pformat;
 
225
        gint64 ptot;
 
226
 
 
227
        pformat = GST_FORMAT_BYTES;
 
228
        res = gst_pad_query_duration (peer, &pformat, &ptot);
 
229
        if (res && amrwbparse->block) {
 
230
          tot = gst_util_uint64_scale_int (ptot, 20 * GST_MSECOND,
 
231
              amrwbparse->block);
 
232
        }
 
233
        gst_object_unref (GST_OBJECT (peer));
 
234
      }
 
235
      gst_query_set_duration (query, GST_FORMAT_TIME, tot);
 
236
      res = TRUE;
 
237
      break;
 
238
    }
 
239
    default:
 
240
      res = gst_pad_query_default (pad, query);
 
241
      break;
 
242
  }
 
243
 
 
244
  gst_object_unref (amrwbparse);
 
245
  return res;
 
246
}
 
247
 
 
248
 
 
249
static gboolean
 
250
gst_amrwbparse_handle_pull_seek (GstAmrwbParse * amrwbparse, GstPad * pad,
 
251
    GstEvent * event)
 
252
{
 
253
  GstFormat format;
 
254
  gdouble rate;
 
255
  GstSeekFlags flags;
 
256
  GstSeekType cur_type, stop_type;
 
257
  gint64 cur, stop;
 
258
  gint64 byte_cur = -1, byte_stop = -1;
 
259
  gboolean flush;
 
260
 
 
261
  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
 
262
      &stop_type, &stop);
 
263
 
 
264
  GST_DEBUG_OBJECT (amrwbparse, "Performing seek to %" GST_TIME_FORMAT,
 
265
      GST_TIME_ARGS (cur));
 
266
 
 
267
  /* For any format other than TIME, see if upstream handles
 
268
   * it directly or fail. For TIME, try upstream, but do it ourselves if
 
269
   * it fails upstream */
 
270
  if (format != GST_FORMAT_TIME) {
 
271
    return gst_pad_push_event (amrwbparse->sinkpad, event);
 
272
  } else {
 
273
    if (gst_pad_push_event (amrwbparse->sinkpad, event))
 
274
      return TRUE;
 
275
  }
 
276
 
 
277
  flush = flags & GST_SEEK_FLAG_FLUSH;
 
278
 
 
279
  /* send flush start */
 
280
  if (flush)
 
281
    gst_pad_push_event (amrwbparse->sinkpad, gst_event_new_flush_start ());
 
282
  /* we only handle FLUSH seeks at the moment */
 
283
  else
 
284
    return FALSE;
 
285
 
 
286
  /* grab streaming lock, this should eventually be possible, either
 
287
   * because the task is paused or our streaming thread stopped
 
288
   * because our peer is flushing. */
 
289
  GST_PAD_STREAM_LOCK (amrwbparse->sinkpad);
 
290
 
 
291
  /* Convert the TIME to the appropriate BYTE position at which to resume
 
292
   * decoding. */
 
293
  cur = cur / (20 * GST_MSECOND) * (20 * GST_MSECOND);
 
294
  if (cur != -1)
 
295
    byte_cur = amrwbparse->block * (cur / 20 / GST_MSECOND) + AMRWB_HEADER_SIZE;
 
296
  if (stop != -1)
 
297
    byte_stop =
 
298
        amrwbparse->block * (stop / 20 / GST_MSECOND) + AMRWB_HEADER_SIZE;
 
299
  amrwbparse->offset = byte_cur;
 
300
  amrwbparse->ts = cur;
 
301
 
 
302
  GST_DEBUG_OBJECT (amrwbparse, "Seeking to byte range %" G_GINT64_FORMAT
 
303
      " to %" G_GINT64_FORMAT, byte_cur, cur);
 
304
 
 
305
  /* and prepare to continue streaming */
 
306
  /* send flush stop, peer will accept data and events again. We
 
307
   * are not yet providing data as we still have the STREAM_LOCK. */
 
308
  gst_pad_push_event (amrwbparse->sinkpad, gst_event_new_flush_stop ());
 
309
  gst_pad_push_event (amrwbparse->srcpad, gst_event_new_new_segment (FALSE,
 
310
          rate, format, cur, -1, cur));
 
311
 
 
312
  /* and restart the task in case it got paused explicitely or by
 
313
   * the FLUSH_START event we pushed out. */
 
314
  gst_pad_start_task (amrwbparse->sinkpad,
 
315
      (GstTaskFunction) gst_amrwbparse_loop, amrwbparse->sinkpad);
 
316
 
 
317
  /* and release the lock again so we can continue streaming */
 
318
  GST_PAD_STREAM_UNLOCK (amrwbparse->sinkpad);
 
319
 
 
320
  return TRUE;
 
321
}
 
322
 
 
323
static gboolean
 
324
gst_amrwbparse_handle_push_seek (GstAmrwbParse * amrwbparse, GstPad * pad,
 
325
    GstEvent * event)
 
326
{
 
327
  GstFormat format;
 
328
  gdouble rate;
 
329
  GstSeekFlags flags;
 
330
  GstSeekType cur_type, stop_type;
 
331
  gint64 cur, stop;
 
332
  gint64 byte_cur = -1, byte_stop = -1;
 
333
 
 
334
  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
 
335
      &stop_type, &stop);
 
336
 
 
337
  GST_DEBUG_OBJECT (amrwbparse, "Performing seek to %" GST_TIME_FORMAT,
 
338
      GST_TIME_ARGS (cur));
 
339
 
 
340
  /* For any format other than TIME, see if upstream handles
 
341
   * it directly or fail. For TIME, try upstream, but do it ourselves if
 
342
   * it fails upstream */
 
343
  if (format != GST_FORMAT_TIME) {
 
344
    return gst_pad_push_event (amrwbparse->sinkpad, event);
 
345
  } else {
 
346
    if (gst_pad_push_event (amrwbparse->sinkpad, event))
 
347
      return TRUE;
 
348
  }
 
349
 
 
350
  /* Convert the TIME to the appropriate BYTE position at which to resume
 
351
   * decoding. */
 
352
  cur = cur / (20 * GST_MSECOND) * (20 * GST_MSECOND);
 
353
  if (cur != -1)
 
354
    byte_cur = amrwbparse->block * (cur / 20 / GST_MSECOND) + AMRWB_HEADER_SIZE;
 
355
  if (stop != -1)
 
356
    byte_stop =
 
357
        amrwbparse->block * (stop / 20 / GST_MSECOND) + AMRWB_HEADER_SIZE;
 
358
  amrwbparse->ts = cur;
 
359
 
 
360
  GST_DEBUG_OBJECT (amrwbparse, "Seeking to byte range %" G_GINT64_FORMAT
 
361
      " to %" G_GINT64_FORMAT, byte_cur, byte_stop);
 
362
 
 
363
  /* Send BYTE based seek upstream */
 
364
  event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
 
365
      byte_cur, stop_type, byte_stop);
 
366
 
 
367
  return gst_pad_push_event (amrwbparse->sinkpad, event);
 
368
}
 
369
 
 
370
static gboolean
 
371
gst_amrwbparse_src_event (GstPad * pad, GstEvent * event)
 
372
{
 
373
  GstAmrwbParse *amrwbparse = GST_AMRWBPARSE (gst_pad_get_parent (pad));
 
374
  gboolean res;
 
375
 
 
376
  GST_DEBUG_OBJECT (amrwbparse, "handling event %d", GST_EVENT_TYPE (event));
 
377
 
 
378
  switch (GST_EVENT_TYPE (event)) {
 
379
    case GST_EVENT_SEEK:
 
380
      if (amrwbparse->seek_handler)
 
381
        res = amrwbparse->seek_handler (amrwbparse, pad, event);
 
382
      else
 
383
        res = FALSE;
 
384
      break;
 
385
    default:
 
386
      res = gst_pad_push_event (amrwbparse->sinkpad, event);
 
387
      break;
 
388
  }
 
389
  gst_object_unref (amrwbparse);
 
390
 
 
391
  return res;
 
392
}
 
393
 
 
394
 
 
395
/*
 
396
 * Data reading.
 
397
 */
 
398
static gboolean
 
399
gst_amrwbparse_sink_event (GstPad * pad, GstEvent * event)
 
400
{
 
401
  GstAmrwbParse *amrwbparse;
 
402
  gboolean res;
 
403
 
 
404
  amrwbparse = GST_AMRWBPARSE (gst_pad_get_parent (pad));
 
405
 
 
406
  GST_LOG ("handling event %d", GST_EVENT_TYPE (event));
 
407
 
 
408
  switch (GST_EVENT_TYPE (event)) {
 
409
    case GST_EVENT_FLUSH_START:
 
410
      res = gst_pad_push_event (amrwbparse->srcpad, event);
 
411
      break;
 
412
    case GST_EVENT_FLUSH_STOP:
 
413
      gst_adapter_clear (amrwbparse->adapter);
 
414
      gst_segment_init (&amrwbparse->segment, GST_FORMAT_TIME);
 
415
      res = gst_pad_push_event (amrwbparse->srcpad, event);
 
416
      break;
 
417
    case GST_EVENT_EOS:
 
418
      res = gst_pad_push_event (amrwbparse->srcpad, event);
 
419
      break;
 
420
    case GST_EVENT_NEWSEGMENT:
 
421
    {
 
422
      /* eat for now, we send a newsegment at start with infinite
 
423
       * duration. */
 
424
      gst_event_unref (event);
 
425
      res = TRUE;
 
426
      break;
 
427
    }
 
428
    default:
 
429
      res = gst_pad_push_event (amrwbparse->srcpad, event);
 
430
      break;
 
431
  }
 
432
  gst_object_unref (amrwbparse);
 
433
 
 
434
  return res;
 
435
}
 
436
 
 
437
/* streaming mode */
 
438
static GstFlowReturn
 
439
gst_amrwbparse_chain (GstPad * pad, GstBuffer * buffer)
 
440
{
 
441
  GstAmrwbParse *amrwbparse;
 
442
  GstFlowReturn res = GST_FLOW_OK;
 
443
  gint mode;
 
444
  const guint8 *data;
 
445
  GstBuffer *out;
 
446
  GstClockTime timestamp;
 
447
 
 
448
  amrwbparse = GST_AMRWBPARSE (gst_pad_get_parent (pad));
 
449
 
 
450
  timestamp = GST_BUFFER_TIMESTAMP (buffer);
 
451
  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
 
452
    GST_DEBUG_OBJECT (amrwbparse, "Lock on timestamp %" GST_TIME_FORMAT,
 
453
        GST_TIME_ARGS (timestamp));
 
454
    amrwbparse->ts = timestamp;
 
455
  }
 
456
 
 
457
  gst_adapter_push (amrwbparse->adapter, buffer);
 
458
 
 
459
  /* init */
 
460
  if (amrwbparse->need_header) {
 
461
    GstEvent *segev;
 
462
    GstCaps *caps;
 
463
 
 
464
    if (gst_adapter_available (amrwbparse->adapter) < AMRWB_HEADER_SIZE)
 
465
      goto done;
 
466
 
 
467
    data = gst_adapter_peek (amrwbparse->adapter, AMRWB_HEADER_SIZE);
 
468
    if (memcmp (data, AMRWB_HEADER_STR, AMRWB_HEADER_SIZE) != 0)
 
469
      goto done;
 
470
 
 
471
    gst_adapter_flush (amrwbparse->adapter, AMRWB_HEADER_SIZE);
 
472
 
 
473
    amrwbparse->need_header = FALSE;
 
474
 
 
475
    caps = gst_caps_new_simple ("audio/AMR-WB",
 
476
        "rate", G_TYPE_INT, 16000, "channels", G_TYPE_INT, 1, NULL);
 
477
    gst_pad_set_caps (amrwbparse->srcpad, caps);
 
478
    gst_caps_unref (caps);
 
479
 
 
480
    GST_DEBUG_OBJECT (amrwbparse, "Sending first segment");
 
481
    segev = gst_event_new_new_segment_full (FALSE, 1.0, 1.0,
 
482
        GST_FORMAT_TIME, 0, -1, 0);
 
483
 
 
484
    gst_pad_push_event (amrwbparse->srcpad, segev);
 
485
  }
 
486
 
 
487
  while (TRUE) {
 
488
    if (gst_adapter_available (amrwbparse->adapter) < 1)
 
489
      break;
 
490
 
 
491
    data = gst_adapter_peek (amrwbparse->adapter, 1);
 
492
 
 
493
    /* get size */
 
494
    mode = (data[0] >> 3) & 0x0F;
 
495
    amrwbparse->block = block_size[mode] + 1;   /* add one for the mode */
 
496
 
 
497
    if (gst_adapter_available (amrwbparse->adapter) < amrwbparse->block)
 
498
      break;
 
499
 
 
500
    out = gst_buffer_new_and_alloc (amrwbparse->block);
 
501
 
 
502
    data = gst_adapter_peek (amrwbparse->adapter, amrwbparse->block);
 
503
    memcpy (GST_BUFFER_DATA (out), data, amrwbparse->block);
 
504
 
 
505
    /* timestamp, all constants that won't overflow */
 
506
    GST_BUFFER_DURATION (out) = GST_SECOND * L_FRAME16k / 16000;
 
507
    GST_BUFFER_TIMESTAMP (out) = amrwbparse->ts;
 
508
    if (GST_CLOCK_TIME_IS_VALID (amrwbparse->ts))
 
509
      amrwbparse->ts += GST_BUFFER_DURATION (out);
 
510
 
 
511
    gst_buffer_set_caps (out, GST_PAD_CAPS (amrwbparse->srcpad));
 
512
 
 
513
    GST_DEBUG_OBJECT (amrwbparse, "Pushing %d bytes of data",
 
514
        amrwbparse->block);
 
515
 
 
516
    res = gst_pad_push (amrwbparse->srcpad, out);
 
517
 
 
518
    gst_adapter_flush (amrwbparse->adapter, amrwbparse->block);
 
519
  }
 
520
done:
 
521
 
 
522
  gst_object_unref (amrwbparse);
 
523
  return res;
 
524
}
 
525
 
 
526
static gboolean
 
527
gst_amrwbparse_pull_header (GstAmrwbParse * amrwbparse)
 
528
{
 
529
  GstBuffer *buffer;
 
530
  GstFlowReturn ret;
 
531
  guint8 *data;
 
532
  gint size;
 
533
 
 
534
  ret = gst_pad_pull_range (amrwbparse->sinkpad, G_GUINT64_CONSTANT (0),
 
535
      AMRWB_HEADER_SIZE, &buffer);
 
536
  if (ret != GST_FLOW_OK)
 
537
    return FALSE;
 
538
 
 
539
  data = GST_BUFFER_DATA (buffer);
 
540
  size = GST_BUFFER_SIZE (buffer);
 
541
 
 
542
  if (size < AMRWB_HEADER_SIZE)
 
543
    goto not_enough;
 
544
 
 
545
  if (memcmp (data, AMRWB_HEADER_STR, AMRWB_HEADER_SIZE))
 
546
    goto no_header;
 
547
 
 
548
  gst_buffer_unref (buffer);
 
549
 
 
550
  amrwbparse->offset = AMRWB_HEADER_SIZE;
 
551
  return TRUE;
 
552
 
 
553
not_enough:
 
554
  {
 
555
    gst_buffer_unref (buffer);
 
556
    return FALSE;
 
557
  }
 
558
no_header:
 
559
  {
 
560
    gst_buffer_unref (buffer);
 
561
    return FALSE;
 
562
  }
 
563
}
 
564
 
 
565
/* random access mode, could just read a fixed size buffer and push it to
 
566
 * the chain function but we don't... */
 
567
static void
 
568
gst_amrwbparse_loop (GstPad * pad)
 
569
{
 
570
  GstAmrwbParse *amrwbparse;
 
571
  GstBuffer *buffer;
 
572
  guint8 *data;
 
573
  gint size;
 
574
  gint block, mode;
 
575
  GstFlowReturn ret = GST_FLOW_OK;
 
576
 
 
577
  amrwbparse = GST_AMRWBPARSE (GST_PAD_PARENT (pad));
 
578
 
 
579
  /* init */
 
580
  if (G_UNLIKELY (amrwbparse->need_header)) {
 
581
    GstCaps *caps;
 
582
 
 
583
    if (!gst_amrwbparse_pull_header (amrwbparse)) {
 
584
      GST_ELEMENT_ERROR (amrwbparse, STREAM, WRONG_TYPE, (NULL), (NULL));
 
585
      GST_LOG_OBJECT (amrwbparse, "could not read header");
 
586
      goto need_pause;
 
587
    }
 
588
 
 
589
    caps = gst_caps_new_simple ("audio/AMR-WB",
 
590
        "rate", G_TYPE_INT, 16000, "channels", G_TYPE_INT, 1, NULL);
 
591
    gst_pad_set_caps (amrwbparse->srcpad, caps);
 
592
    gst_caps_unref (caps);
 
593
 
 
594
    GST_DEBUG_OBJECT (amrwbparse, "Sending newsegment event");
 
595
    gst_pad_push_event (amrwbparse->srcpad,
 
596
        gst_event_new_new_segment_full (FALSE, 1.0, 1.0,
 
597
            GST_FORMAT_TIME, 0, -1, 0));
 
598
 
 
599
    amrwbparse->need_header = FALSE;
 
600
  }
 
601
 
 
602
  ret =
 
603
      gst_pad_pull_range (amrwbparse->sinkpad, amrwbparse->offset, 1, &buffer);
 
604
 
 
605
  if (ret == GST_FLOW_UNEXPECTED)
 
606
    goto eos;
 
607
  else if (ret != GST_FLOW_OK)
 
608
    goto need_pause;
 
609
 
 
610
  data = GST_BUFFER_DATA (buffer);
 
611
  size = GST_BUFFER_SIZE (buffer);
 
612
 
 
613
  /* EOS */
 
614
  if (size < 1) {
 
615
    gst_buffer_unref (buffer);
 
616
    goto eos;
 
617
  }
 
618
 
 
619
  /* get size */
 
620
  mode = (data[0] >> 3) & 0x0F;
 
621
  block = block_size[mode];     /* add one for the mode */
 
622
 
 
623
  gst_buffer_unref (buffer);
 
624
 
 
625
  ret = gst_pad_pull_range (amrwbparse->sinkpad,
 
626
      amrwbparse->offset, block, &buffer);
 
627
 
 
628
  if (ret == GST_FLOW_UNEXPECTED)
 
629
    goto eos;
 
630
  else if (ret != GST_FLOW_OK)
 
631
    goto need_pause;
 
632
 
 
633
  amrwbparse->offset += block;
 
634
 
 
635
  /* output */
 
636
  GST_BUFFER_DURATION (buffer) = GST_SECOND * L_FRAME16k / 16000;
 
637
  GST_BUFFER_TIMESTAMP (buffer) = amrwbparse->ts;
 
638
 
 
639
  gst_buffer_set_caps (buffer,
 
640
      (GstCaps *) gst_pad_get_pad_template_caps (amrwbparse->srcpad));
 
641
 
 
642
  ret = gst_pad_push (amrwbparse->srcpad, buffer);
 
643
 
 
644
  if (ret != GST_FLOW_OK) {
 
645
    GST_DEBUG_OBJECT (amrwbparse, "Flow: %s", gst_flow_get_name (ret));
 
646
    if (GST_FLOW_IS_FATAL (ret)) {
 
647
      GST_ELEMENT_ERROR (amrwbparse, STREAM, FAILED, (NULL),    /* _("Internal data flow error.")), */
 
648
          ("streaming task paused, reason: %s", gst_flow_get_name (ret)));
 
649
      gst_pad_push_event (pad, gst_event_new_eos ());
 
650
    }
 
651
    goto need_pause;
 
652
  }
 
653
 
 
654
  amrwbparse->ts += GST_BUFFER_DURATION (buffer);
 
655
 
 
656
  return;
 
657
 
 
658
need_pause:
 
659
  {
 
660
    GST_LOG_OBJECT (amrwbparse, "pausing task");
 
661
    gst_pad_pause_task (pad);
 
662
    return;
 
663
  }
 
664
eos:
 
665
  {
 
666
    GST_LOG_OBJECT (amrwbparse, "pausing task %d", ret);
 
667
    gst_pad_push_event (amrwbparse->srcpad, gst_event_new_eos ());
 
668
    gst_pad_pause_task (pad);
 
669
    return;
 
670
  }
 
671
}
 
672
 
 
673
static gboolean
 
674
gst_amrwbparse_sink_activate (GstPad * sinkpad)
 
675
{
 
676
  gboolean result = FALSE;
 
677
  GstAmrwbParse *amrwbparse;
 
678
 
 
679
  amrwbparse = GST_AMRWBPARSE (gst_pad_get_parent (sinkpad));
 
680
 
 
681
  if (gst_pad_check_pull_range (sinkpad)) {
 
682
    GST_DEBUG ("Trying to activate in pull mode");
 
683
    amrwbparse->seekable = TRUE;
 
684
    amrwbparse->ts = 0;
 
685
    result = gst_pad_activate_pull (sinkpad, TRUE);
 
686
  } else {
 
687
    GST_DEBUG ("Try to activate in push mode");
 
688
    amrwbparse->seekable = FALSE;
 
689
    result = gst_pad_activate_push (sinkpad, TRUE);
 
690
  }
 
691
 
 
692
  gst_object_unref (amrwbparse);
 
693
  return result;
 
694
}
 
695
 
 
696
 
 
697
 
 
698
static gboolean
 
699
gst_amrwbparse_sink_activate_push (GstPad * sinkpad, gboolean active)
 
700
{
 
701
  GstAmrwbParse *amrwbparse = GST_AMRWBPARSE (gst_pad_get_parent (sinkpad));
 
702
 
 
703
  if (active) {
 
704
    amrwbparse->seek_handler = gst_amrwbparse_handle_push_seek;
 
705
  } else {
 
706
    amrwbparse->seek_handler = NULL;
 
707
  }
 
708
 
 
709
  gst_object_unref (amrwbparse);
 
710
  return TRUE;
 
711
}
 
712
 
 
713
static gboolean
 
714
gst_amrwbparse_sink_activate_pull (GstPad * sinkpad, gboolean active)
 
715
{
 
716
  gboolean result;
 
717
  GstAmrwbParse *amrwbparse;
 
718
 
 
719
  amrwbparse = GST_AMRWBPARSE (gst_pad_get_parent (sinkpad));
 
720
  if (active) {
 
721
    amrwbparse->seek_handler = gst_amrwbparse_handle_pull_seek;
 
722
    result = gst_pad_start_task (sinkpad,
 
723
        (GstTaskFunction) gst_amrwbparse_loop, sinkpad);
 
724
  } else {
 
725
    amrwbparse->seek_handler = NULL;
 
726
    result = gst_pad_stop_task (sinkpad);
 
727
  }
 
728
 
 
729
  gst_object_unref (amrwbparse);
 
730
  return result;
 
731
}
 
732
 
 
733
 
 
734
static GstStateChangeReturn
 
735
gst_amrwbparse_state_change (GstElement * element, GstStateChange transition)
 
736
{
 
737
  GstAmrwbParse *amrwbparse;
 
738
  GstStateChangeReturn ret;
 
739
 
 
740
  amrwbparse = GST_AMRWBPARSE (element);
 
741
 
 
742
  switch (transition) {
 
743
    case GST_STATE_CHANGE_NULL_TO_READY:
 
744
      break;
 
745
    case GST_STATE_CHANGE_READY_TO_PAUSED:
 
746
      amrwbparse->need_header = TRUE;
 
747
      amrwbparse->ts = -1;
 
748
      amrwbparse->block = 0;
 
749
      gst_segment_init (&amrwbparse->segment, GST_FORMAT_TIME);
 
750
      break;
 
751
    default:
 
752
      break;
 
753
  }
 
754
 
 
755
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
756
 
 
757
  switch (transition) {
 
758
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 
759
      break;
 
760
    case GST_STATE_CHANGE_READY_TO_NULL:
 
761
      break;
 
762
    default:
 
763
      break;
 
764
  }
 
765
 
 
766
  return ret;
 
767
}