~ubuntu-branches/ubuntu/feisty/gst-plugins-good0.10/feisty-security

« back to all changes in this revision

Viewing changes to gst/rtp/gstrtptheoradepay.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2006-12-21 21:12:15 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20061221211215-3uukkusokhe0nk4f
Tags: 0.10.5-0ubuntu1
* Sync with pkg-gstreamer SVN:
  + debian/rules:
    - Use Ubuntu as distribution name and point to the proper Launchpad URL
  + debian/patches/01_esdsink-priority.patch:
    - Mark the esdsink with rank primary-2 to get
      pulse > alsadmix > esd > alsa > oss

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer
 
2
 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
 
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
#ifdef HAVE_CONFIG_H
 
21
#  include "config.h"
 
22
#endif
 
23
 
 
24
#include <gst/tag/tag.h>
 
25
#include <gst/rtp/gstrtpbuffer.h>
 
26
 
 
27
#include <string.h>
 
28
#include "gstrtptheoradepay.h"
 
29
 
 
30
GST_DEBUG_CATEGORY_STATIC (rtptheoradepay_debug);
 
31
#define GST_CAT_DEFAULT (rtptheoradepay_debug)
 
32
 
 
33
/* elementfactory information */
 
34
static const GstElementDetails gst_rtp_theora_depay_details =
 
35
GST_ELEMENT_DETAILS ("RTP packet depayloader",
 
36
    "Codec/Depayloader/Network",
 
37
    "Extracts Theora video from RTP packets (draft-01 of RFC XXXX)",
 
38
    "Wim Taymans <wim@fluendo.com>");
 
39
 
 
40
/* RtpTheoraDepay signals and args */
 
41
enum
 
42
{
 
43
  /* FILL ME */
 
44
  LAST_SIGNAL
 
45
};
 
46
 
 
47
enum
 
48
{
 
49
  ARG_0,
 
50
};
 
51
 
 
52
static GstStaticPadTemplate gst_rtp_theora_depay_sink_template =
 
53
GST_STATIC_PAD_TEMPLATE ("sink",
 
54
    GST_PAD_SINK,
 
55
    GST_PAD_ALWAYS,
 
56
    GST_STATIC_CAPS ("application/x-rtp, "
 
57
        "media = (string) \"video\", "
 
58
        "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"theora\""
 
59
        /* All required parameters 
 
60
         *
 
61
         * "encoding-params = (string) <num channels>"
 
62
         * "delivery-method = (string) { inline, in_band, out_band/<specific_name> } " 
 
63
         * "configuration = (string) ANY" 
 
64
         */
 
65
        /* All optional parameters
 
66
         *
 
67
         * "configuration-uri =" 
 
68
         */
 
69
    )
 
70
    );
 
71
 
 
72
static GstStaticPadTemplate gst_rtp_theora_depay_src_template =
 
73
GST_STATIC_PAD_TEMPLATE ("src",
 
74
    GST_PAD_SRC,
 
75
    GST_PAD_ALWAYS,
 
76
    GST_STATIC_CAPS ("video/x-theora")
 
77
    );
 
78
 
 
79
/* 42 bytes for the theora identification packet length */
 
80
#define THEORA_ID_LEN   42
 
81
 
 
82
GST_BOILERPLATE (GstRtpTheoraDepay, gst_rtp_theora_depay, GstBaseRTPDepayload,
 
83
    GST_TYPE_BASE_RTP_DEPAYLOAD);
 
84
 
 
85
static gboolean gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload,
 
86
    GstCaps * caps);
 
87
static GstBuffer *gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload,
 
88
    GstBuffer * buf);
 
89
 
 
90
static void gst_rtp_theora_depay_set_property (GObject * object, guint prop_id,
 
91
    const GValue * value, GParamSpec * pspec);
 
92
static void gst_rtp_theora_depay_get_property (GObject * object, guint prop_id,
 
93
    GValue * value, GParamSpec * pspec);
 
94
static void gst_rtp_theora_depay_finalize (GObject * object);
 
95
 
 
96
static GstStateChangeReturn gst_rtp_theora_depay_change_state (GstElement *
 
97
    element, GstStateChange transition);
 
98
 
 
99
 
 
100
static void
 
101
gst_rtp_theora_depay_base_init (gpointer klass)
 
102
{
 
103
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
104
 
 
105
  gst_element_class_add_pad_template (element_class,
 
106
      gst_static_pad_template_get (&gst_rtp_theora_depay_sink_template));
 
107
  gst_element_class_add_pad_template (element_class,
 
108
      gst_static_pad_template_get (&gst_rtp_theora_depay_src_template));
 
109
 
 
110
  gst_element_class_set_details (element_class, &gst_rtp_theora_depay_details);
 
111
}
 
112
 
 
113
static void
 
114
gst_rtp_theora_depay_class_init (GstRtpTheoraDepayClass * klass)
 
115
{
 
116
  GObjectClass *gobject_class;
 
117
  GstElementClass *gstelement_class;
 
118
  GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
 
119
 
 
120
  gobject_class = (GObjectClass *) klass;
 
121
  gstelement_class = (GstElementClass *) klass;
 
122
  gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
 
123
 
 
124
  gobject_class->set_property = gst_rtp_theora_depay_set_property;
 
125
  gobject_class->get_property = gst_rtp_theora_depay_get_property;
 
126
  gobject_class->finalize = gst_rtp_theora_depay_finalize;
 
127
 
 
128
  gstelement_class->change_state = gst_rtp_theora_depay_change_state;
 
129
 
 
130
  gstbasertpdepayload_class->process = gst_rtp_theora_depay_process;
 
131
  gstbasertpdepayload_class->set_caps = gst_rtp_theora_depay_setcaps;
 
132
 
 
133
  GST_DEBUG_CATEGORY_INIT (rtptheoradepay_debug, "rtptheoradepay", 0,
 
134
      "Theora RTP Depayloader");
 
135
}
 
136
 
 
137
static void
 
138
gst_rtp_theora_depay_init (GstRtpTheoraDepay * rtptheoradepay,
 
139
    GstRtpTheoraDepayClass * klass)
 
140
{
 
141
  rtptheoradepay->adapter = gst_adapter_new ();
 
142
}
 
143
static void
 
144
gst_rtp_theora_depay_finalize (GObject * object)
 
145
{
 
146
  GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (object);
 
147
 
 
148
  g_object_unref (rtptheoradepay->adapter);
 
149
 
 
150
  G_OBJECT_CLASS (parent_class)->finalize (object);
 
151
}
 
152
 
 
153
static gboolean
 
154
gst_rtp_theora_depay_parse_configuration (GstRtpTheoraDepay * rtptheoradepay,
 
155
    const gchar * configuration)
 
156
{
 
157
  GValue v = { 0 };
 
158
  GstBuffer *buf;
 
159
  guint32 num_headers;
 
160
  guint8 *data;
 
161
  guint size;
 
162
  gint i;
 
163
 
 
164
  /* deserialize base16 to buffer */
 
165
  g_value_init (&v, GST_TYPE_BUFFER);
 
166
  if (!gst_value_deserialize (&v, configuration))
 
167
    goto wrong_configuration;
 
168
 
 
169
  buf = gst_value_get_buffer (&v);
 
170
  gst_buffer_ref (buf);
 
171
  g_value_unset (&v);
 
172
 
 
173
  data = GST_BUFFER_DATA (buf);
 
174
  size = GST_BUFFER_SIZE (buf);
 
175
 
 
176
  GST_DEBUG_OBJECT (rtptheoradepay, "config size %u", size);
 
177
 
 
178
  /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
179
   * |                     Number of packed headers                  |
 
180
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
181
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
182
   * |                          Packed header                        |
 
183
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
184
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
185
   * |                          Packed header                        |
 
186
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
187
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
188
   * |                          ....                                 |
 
189
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
190
   */
 
191
  if (size < 4)
 
192
    goto too_small;
 
193
 
 
194
  num_headers = GST_READ_UINT32_BE (data);
 
195
  size -= 4;
 
196
  data += 4;
 
197
 
 
198
  GST_DEBUG_OBJECT (rtptheoradepay, "have %u headers", num_headers);
 
199
 
 
200
  /*  0                   1                   2                   3
 
201
   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 
202
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
203
   * |                   Ident                       |              ..
 
204
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
205
   * ..   length     |              Identification Header           ..
 
206
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
207
   * ..                    Identification Header                     |
 
208
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
209
   * |                          Setup Header                        ..
 
210
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
211
   * ..                         Setup Header                         |
 
212
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
213
   *
 
214
   */
 
215
  for (i = 0; i < num_headers; i++) {
 
216
    guint32 ident;
 
217
    guint16 length;
 
218
    GstRtpTheoraConfig *conf;
 
219
    GstTagList *list;
 
220
 
 
221
    if (size < 5)
 
222
      goto too_small;
 
223
 
 
224
    ident = (data[0] << 16) | (data[1] << 8) | data[2];
 
225
    length = (data[3] << 8) | data[4];
 
226
    size -= 5;
 
227
    data += 5;
 
228
 
 
229
    GST_DEBUG_OBJECT (rtptheoradepay, "header %d, ident %08x, length %u", i,
 
230
        ident, length);
 
231
 
 
232
    if (size < length + THEORA_ID_LEN)
 
233
      goto too_small;
 
234
 
 
235
    GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
 
236
 
 
237
    conf = g_new0 (GstRtpTheoraConfig, 1);
 
238
    conf->ident = ident;
 
239
 
 
240
    buf = gst_buffer_new_and_alloc (THEORA_ID_LEN);
 
241
    memcpy (GST_BUFFER_DATA (buf), data, THEORA_ID_LEN);
 
242
    conf->headers = g_list_append (conf->headers, buf);
 
243
    data += THEORA_ID_LEN;
 
244
    size -= THEORA_ID_LEN;
 
245
 
 
246
    /* create a dummy comment */
 
247
    list = gst_tag_list_new ();
 
248
    buf =
 
249
        gst_tag_list_to_vorbiscomment_buffer (list, (guint8 *) "\201theora", 7,
 
250
        "Theora RTP depayloader");
 
251
    conf->headers = g_list_append (conf->headers, buf);
 
252
    gst_tag_list_free (list);
 
253
 
 
254
    buf = gst_buffer_new_and_alloc (length);
 
255
    memcpy (GST_BUFFER_DATA (buf), data, length);
 
256
    conf->headers = g_list_append (conf->headers, buf);
 
257
    data += length;
 
258
    size -= length;
 
259
 
 
260
    rtptheoradepay->configs = g_list_append (rtptheoradepay->configs, conf);
 
261
  }
 
262
 
 
263
  return TRUE;
 
264
 
 
265
  /* ERRORS */
 
266
wrong_configuration:
 
267
  {
 
268
    GST_DEBUG_OBJECT (rtptheoradepay, "error parsing configuration");
 
269
    return FALSE;
 
270
  }
 
271
too_small:
 
272
  {
 
273
    GST_DEBUG_OBJECT (rtptheoradepay, "configuration too small");
 
274
    return FALSE;
 
275
  }
 
276
}
 
277
 
 
278
static gboolean
 
279
gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
 
280
{
 
281
  GstStructure *structure;
 
282
  GstRtpTheoraDepay *rtptheoradepay;
 
283
  GstCaps *srccaps;
 
284
  const gchar *delivery_method;
 
285
  const gchar *configuration;
 
286
  gint clock_rate;
 
287
 
 
288
  rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
 
289
 
 
290
  structure = gst_caps_get_structure (caps, 0);
 
291
 
 
292
  /* get clockrate */
 
293
  if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
 
294
    goto no_rate;
 
295
 
 
296
  /* see how the configuration parameters will be transmitted */
 
297
  delivery_method = gst_structure_get_string (structure, "delivery-method");
 
298
  if (delivery_method == NULL)
 
299
    goto no_delivery_method;
 
300
 
 
301
  if (g_strcasecmp (delivery_method, "inline")) {
 
302
    /* configure string is in the caps */
 
303
  } else if (g_strcasecmp (delivery_method, "in_band")) {
 
304
    /* headers will (also) be transmitted in the RTP packets */
 
305
  } else if (g_str_has_prefix (delivery_method, "out_band/")) {
 
306
    /* some other method of header delivery. */
 
307
    goto unsupported_delivery_method;
 
308
  } else
 
309
    goto unsupported_delivery_method;
 
310
 
 
311
  /* read and parse configuration string */
 
312
  configuration = gst_structure_get_string (structure, "configuration");
 
313
  if (configuration == NULL)
 
314
    goto no_configuration;
 
315
 
 
316
  if (!gst_rtp_theora_depay_parse_configuration (rtptheoradepay, configuration))
 
317
    goto invalid_configuration;
 
318
 
 
319
  /* caps seem good, configure element */
 
320
  depayload->clock_rate = clock_rate;
 
321
 
 
322
  /* set caps on pad and on header */
 
323
  srccaps = gst_caps_new_simple ("video/x-theora", NULL);
 
324
  gst_pad_set_caps (depayload->srcpad, srccaps);
 
325
  gst_caps_unref (srccaps);
 
326
 
 
327
  return TRUE;
 
328
 
 
329
  /* ERRORS */
 
330
unsupported_delivery_method:
 
331
  {
 
332
    GST_ERROR_OBJECT (rtptheoradepay,
 
333
        "unsupported delivery-method \"%s\" specified", delivery_method);
 
334
    return FALSE;
 
335
  }
 
336
no_delivery_method:
 
337
  {
 
338
    GST_ERROR_OBJECT (rtptheoradepay, "no delivery-method specified");
 
339
    return FALSE;
 
340
  }
 
341
no_configuration:
 
342
  {
 
343
    GST_ERROR_OBJECT (rtptheoradepay, "no configuration specified");
 
344
    return FALSE;
 
345
  }
 
346
invalid_configuration:
 
347
  {
 
348
    GST_ERROR_OBJECT (rtptheoradepay, "invalid configuration specified");
 
349
    return FALSE;
 
350
  }
 
351
no_rate:
 
352
  {
 
353
    GST_ERROR_OBJECT (rtptheoradepay, "no clock-rate specified");
 
354
    return FALSE;
 
355
  }
 
356
}
 
357
 
 
358
static gboolean
 
359
gst_rtp_theora_depay_switch_codebook (GstRtpTheoraDepay * rtptheoradepay,
 
360
    guint32 ident)
 
361
{
 
362
  GList *walk;
 
363
  gboolean res = FALSE;
 
364
 
 
365
  for (walk = rtptheoradepay->configs; walk; walk = g_list_next (walk)) {
 
366
    GstRtpTheoraConfig *conf = (GstRtpTheoraConfig *) walk->data;
 
367
 
 
368
    if (conf->ident == ident) {
 
369
      GList *headers;
 
370
 
 
371
      /* FIXME, remove pads, create new pad.. */
 
372
 
 
373
      /* push out all the headers */
 
374
      for (headers = conf->headers; headers; headers = g_list_next (headers)) {
 
375
        GstBuffer *header = GST_BUFFER_CAST (headers->data);
 
376
 
 
377
        gst_buffer_ref (header);
 
378
        gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtptheoradepay),
 
379
            header);
 
380
      }
 
381
      /* remember the current config */
 
382
      rtptheoradepay->config = conf;
 
383
      res = TRUE;
 
384
    }
 
385
  }
 
386
  if (!res) {
 
387
    /* we don't know about the headers, figure out an alternative method for
 
388
     * getting the codebooks. FIXME, fail for now. */
 
389
  }
 
390
  return res;
 
391
}
 
392
 
 
393
static GstBuffer *
 
394
gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 
395
{
 
396
  GstRtpTheoraDepay *rtptheoradepay;
 
397
  GstBuffer *outbuf;
 
398
  GstFlowReturn ret;
 
399
  gint payload_len;
 
400
  guint8 *payload, *to_free = NULL;
 
401
  guint32 timestamp;
 
402
  guint32 header, ident;
 
403
  guint8 F, TDT, packets;
 
404
  gboolean free_payload;
 
405
 
 
406
  rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
 
407
 
 
408
  if (!gst_rtp_buffer_validate (buf))
 
409
    goto bad_packet;
 
410
 
 
411
  payload_len = gst_rtp_buffer_get_payload_len (buf);
 
412
 
 
413
  GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
 
414
 
 
415
  /* we need at least 4 bytes for the packet header */
 
416
  if (G_UNLIKELY (payload_len < 4))
 
417
    goto packet_short;
 
418
 
 
419
  payload = gst_rtp_buffer_get_payload (buf);
 
420
  free_payload = FALSE;
 
421
 
 
422
  header = GST_READ_UINT32_BE (payload);
 
423
  /*
 
424
   *  0                   1                   2                   3
 
425
   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 
426
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
427
   * |                     Ident                     | F |TDT|# pkts.|
 
428
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
429
   *
 
430
   * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
 
431
   * TDT: Theora data type (0=theora, 1=config, 2=comment, 3=reserved)
 
432
   * pkts: number of packets.
 
433
   */
 
434
  TDT = (header & 0x30) >> 4;
 
435
  if (G_UNLIKELY (TDT == 3))
 
436
    goto ignore_reserved;
 
437
 
 
438
  ident = (header >> 8) & 0xffffff;
 
439
  F = (header & 0xc0) >> 6;
 
440
  packets = (header & 0xf);
 
441
 
 
442
  if (TDT == 0) {
 
443
    gboolean do_switch = FALSE;
 
444
 
 
445
    /* we have a raw payload, find the codebook for the ident */
 
446
    if (!rtptheoradepay->config) {
 
447
      /* we don't have an active codebook, find the codebook and
 
448
       * activate it */
 
449
      do_switch = TRUE;
 
450
    } else if (rtptheoradepay->config->ident != ident) {
 
451
      /* codebook changed */
 
452
      do_switch = TRUE;
 
453
    }
 
454
    if (do_switch) {
 
455
      if (!gst_rtp_theora_depay_switch_codebook (rtptheoradepay, ident))
 
456
        goto switch_failed;
 
457
    }
 
458
  }
 
459
 
 
460
  /* skip header */
 
461
  payload += 4;
 
462
  payload_len -= 4;
 
463
 
 
464
  GST_DEBUG_OBJECT (depayload, "ident: %u, F: %d, TDT: %d, packets: %d", ident,
 
465
      F, TDT, packets);
 
466
 
 
467
  /* fragmented packets, assemble */
 
468
  if (F != 0) {
 
469
    GstBuffer *vdata;
 
470
    guint headerskip;
 
471
 
 
472
    if (F == 1) {
 
473
      /* if we start a packet, clear adapter and start assembling. */
 
474
      gst_adapter_clear (rtptheoradepay->adapter);
 
475
      GST_DEBUG_OBJECT (depayload, "start assemble");
 
476
      rtptheoradepay->assembling = TRUE;
 
477
    }
 
478
 
 
479
    if (!rtptheoradepay->assembling)
 
480
      goto no_output;
 
481
 
 
482
    /* first assembled packet, reuse 2 bytes to store the length */
 
483
    headerskip = (F == 1 ? 4 : 6);
 
484
    /* skip header and length. */
 
485
    vdata = gst_rtp_buffer_get_payload_subbuffer (buf, headerskip, -1);
 
486
 
 
487
    GST_DEBUG_OBJECT (depayload, "assemble theora packet");
 
488
    gst_adapter_push (rtptheoradepay->adapter, vdata);
 
489
 
 
490
    /* packet is not complete, we are done */
 
491
    if (F != 3)
 
492
      goto no_output;
 
493
 
 
494
    /* construct assembled buffer */
 
495
    payload_len = gst_adapter_available (rtptheoradepay->adapter);
 
496
    payload = gst_adapter_take (rtptheoradepay->adapter, payload_len);
 
497
    /* fix the length */
 
498
    payload[0] = ((payload_len - 2) >> 8) & 0xff;
 
499
    payload[1] = (payload_len - 2) & 0xff;
 
500
    to_free = payload;
 
501
  }
 
502
 
 
503
  GST_DEBUG_OBJECT (depayload, "assemble done");
 
504
 
 
505
  /* we not assembling anymore now */
 
506
  rtptheoradepay->assembling = FALSE;
 
507
  gst_adapter_clear (rtptheoradepay->adapter);
 
508
 
 
509
  /* payload now points to a length with that many theora data bytes.
 
510
   * Iterate over the packets and send them out.
 
511
   *
 
512
   *  0                   1                   2                   3
 
513
   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 
514
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
515
   * |             length            |          theora data         ..
 
516
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
517
   * ..                        theora data                           |
 
518
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
519
   * |            length             |   next theora packet data    ..
 
520
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
521
   * ..                        theora data                           |
 
522
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
 
523
   */
 
524
  timestamp = gst_rtp_buffer_get_timestamp (buf);
 
525
 
 
526
  while (payload_len > 2) {
 
527
    guint16 length;
 
528
 
 
529
    length = GST_READ_UINT16_BE (payload);
 
530
    payload += 2;
 
531
    payload_len -= 2;
 
532
 
 
533
    GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
 
534
        payload_len);
 
535
 
 
536
    /* skip packet if something odd happens */
 
537
    if (G_UNLIKELY (length > payload_len))
 
538
      goto length_short;
 
539
 
 
540
    /* create buffer for packet */
 
541
    if (G_UNLIKELY (to_free)) {
 
542
      outbuf = gst_buffer_new ();
 
543
      GST_BUFFER_DATA (outbuf) = payload;
 
544
      GST_BUFFER_MALLOCDATA (outbuf) = to_free;
 
545
      GST_BUFFER_SIZE (outbuf) = length;
 
546
      to_free = NULL;
 
547
    } else {
 
548
      outbuf = gst_buffer_new_and_alloc (length);
 
549
      memcpy (GST_BUFFER_DATA (outbuf), payload, length);
 
550
    }
 
551
 
 
552
    payload += length;
 
553
    payload_len -= length;
 
554
 
 
555
    if (timestamp != -1)
 
556
      /* push with timestamp of the last packet, which is the same timestamp that
 
557
       * should apply to the first assembled packet. */
 
558
      ret = gst_base_rtp_depayload_push_ts (depayload, timestamp, outbuf);
 
559
    else
 
560
      ret = gst_base_rtp_depayload_push (depayload, outbuf);
 
561
 
 
562
    if (ret != GST_FLOW_OK)
 
563
      break;
 
564
 
 
565
    /* make sure we don't set a timestamp on next buffers */
 
566
    timestamp = -1;
 
567
  }
 
568
 
 
569
  g_free (to_free);
 
570
 
 
571
  return NULL;
 
572
 
 
573
no_output:
 
574
  {
 
575
    return NULL;
 
576
  }
 
577
  /* ERORRS */
 
578
bad_packet:
 
579
  {
 
580
    GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
 
581
        (NULL), ("Packet did not validate"));
 
582
    return NULL;
 
583
  }
 
584
switch_failed:
 
585
  {
 
586
    GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
 
587
        (NULL), ("Could not switch codebooks"));
 
588
    return NULL;
 
589
  }
 
590
packet_short:
 
591
  {
 
592
    GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
 
593
        (NULL), ("Packet was too short (%d < 4)", payload_len));
 
594
    return NULL;
 
595
  }
 
596
ignore_reserved:
 
597
  {
 
598
    GST_WARNING_OBJECT (rtptheoradepay, "reserved TDT ignored");
 
599
    return NULL;
 
600
  }
 
601
length_short:
 
602
  {
 
603
    GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
 
604
        (NULL), ("Packet contains invalid data"));
 
605
    return NULL;
 
606
  }
 
607
}
 
608
 
 
609
static void
 
610
gst_rtp_theora_depay_set_property (GObject * object, guint prop_id,
 
611
    const GValue * value, GParamSpec * pspec)
 
612
{
 
613
  GstRtpTheoraDepay *rtptheoradepay;
 
614
 
 
615
  rtptheoradepay = GST_RTP_THEORA_DEPAY (object);
 
616
 
 
617
  switch (prop_id) {
 
618
    default:
 
619
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
620
      break;
 
621
  }
 
622
}
 
623
 
 
624
static void
 
625
gst_rtp_theora_depay_get_property (GObject * object, guint prop_id,
 
626
    GValue * value, GParamSpec * pspec)
 
627
{
 
628
  GstRtpTheoraDepay *rtptheoradepay;
 
629
 
 
630
  rtptheoradepay = GST_RTP_THEORA_DEPAY (object);
 
631
 
 
632
  switch (prop_id) {
 
633
    default:
 
634
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
635
      break;
 
636
  }
 
637
}
 
638
 
 
639
static GstStateChangeReturn
 
640
gst_rtp_theora_depay_change_state (GstElement * element,
 
641
    GstStateChange transition)
 
642
{
 
643
  GstRtpTheoraDepay *rtptheoradepay;
 
644
  GstStateChangeReturn ret;
 
645
 
 
646
  rtptheoradepay = GST_RTP_THEORA_DEPAY (element);
 
647
 
 
648
  switch (transition) {
 
649
    case GST_STATE_CHANGE_NULL_TO_READY:
 
650
      break;
 
651
    case GST_STATE_CHANGE_READY_TO_PAUSED:
 
652
      break;
 
653
    default:
 
654
      break;
 
655
  }
 
656
 
 
657
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
658
 
 
659
  switch (transition) {
 
660
    case GST_STATE_CHANGE_READY_TO_NULL:
 
661
      break;
 
662
    default:
 
663
      break;
 
664
  }
 
665
  return ret;
 
666
}
 
667
 
 
668
gboolean
 
669
gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
 
670
{
 
671
  return gst_element_register (plugin, "rtptheoradepay",
 
672
      GST_RANK_MARGINAL, GST_TYPE_RTP_THEORA_DEPAY);
 
673
}