Merge commit 'a2337b8af45cb5e8c091ff0e1c3ef4b6cc7b20a3' into 0.11
[platform/upstream/gstreamer.git] / gst / rtp / gstrtptheoradepay.c
1 /* GStreamer
2  * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.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 static GstStaticPadTemplate gst_rtp_theora_depay_sink_template =
34 GST_STATIC_PAD_TEMPLATE ("sink",
35     GST_PAD_SINK,
36     GST_PAD_ALWAYS,
37     GST_STATIC_CAPS ("application/x-rtp, "
38         "media = (string) \"video\", "
39         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
40         "clock-rate = (int) 90000, " "encoding-name = (string) \"THEORA\""
41         /* All required parameters 
42          *
43          * "sampling = (string) { "YCbCr-4:2:0", "YCbCr-4:2:2", "YCbCr-4:4:4" } "
44          * "width = (string) [1, 1048561] (multiples of 16) "
45          * "height = (string) [1, 1048561] (multiples of 16) "
46          * "delivery-method = (string) { inline, in_band, out_band/<specific_name> } " 
47          * "configuration = (string) ANY" 
48          */
49         /* All optional parameters
50          *
51          * "configuration-uri =" 
52          */
53     )
54     );
55
56 static GstStaticPadTemplate gst_rtp_theora_depay_src_template =
57 GST_STATIC_PAD_TEMPLATE ("src",
58     GST_PAD_SRC,
59     GST_PAD_ALWAYS,
60     GST_STATIC_CAPS ("video/x-theora")
61     );
62
63 #define gst_rtp_theora_depay_parent_class parent_class
64 G_DEFINE_TYPE (GstRtpTheoraDepay, gst_rtp_theora_depay,
65     GST_TYPE_RTP_BASE_DEPAYLOAD);
66
67 static gboolean gst_rtp_theora_depay_setcaps (GstRTPBaseDepayload * depayload,
68     GstCaps * caps);
69 static GstBuffer *gst_rtp_theora_depay_process (GstRTPBaseDepayload * depayload,
70     GstBuffer * buf);
71 static gboolean gst_rtp_theora_depay_packet_lost (GstRTPBaseDepayload *
72     depayload, GstEvent * event);
73
74 static void gst_rtp_theora_depay_finalize (GObject * object);
75
76 static void
77 gst_rtp_theora_depay_class_init (GstRtpTheoraDepayClass * klass)
78 {
79   GObjectClass *gobject_class;
80   GstElementClass *gstelement_class;
81   GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
82
83   gobject_class = (GObjectClass *) klass;
84   gstelement_class = (GstElementClass *) klass;
85   gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
86
87   gobject_class->finalize = gst_rtp_theora_depay_finalize;
88
89   gstrtpbasedepayload_class->process = gst_rtp_theora_depay_process;
90   gstrtpbasedepayload_class->set_caps = gst_rtp_theora_depay_setcaps;
91   gstrtpbasedepayload_class->packet_lost = gst_rtp_theora_depay_packet_lost;
92
93   gst_element_class_add_pad_template (gstelement_class,
94       gst_static_pad_template_get (&gst_rtp_theora_depay_sink_template));
95   gst_element_class_add_pad_template (gstelement_class,
96       gst_static_pad_template_get (&gst_rtp_theora_depay_src_template));
97
98   gst_element_class_set_details_simple (gstelement_class,
99       "RTP Theora depayloader", "Codec/Depayloader/Network/RTP",
100       "Extracts Theora video from RTP packets (draft-01 of RFC XXXX)",
101       "Wim Taymans <wim.taymans@gmail.com>");
102
103   GST_DEBUG_CATEGORY_INIT (rtptheoradepay_debug, "rtptheoradepay", 0,
104       "Theora RTP Depayloader");
105 }
106
107 static void
108 gst_rtp_theora_depay_init (GstRtpTheoraDepay * rtptheoradepay)
109 {
110   rtptheoradepay->adapter = gst_adapter_new ();
111 }
112
113 static void
114 gst_rtp_theora_depay_finalize (GObject * object)
115 {
116   GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (object);
117
118   g_object_unref (rtptheoradepay->adapter);
119
120   G_OBJECT_CLASS (parent_class)->finalize (object);
121 }
122
123 static gboolean
124 gst_rtp_theora_depay_parse_configuration (GstRtpTheoraDepay * rtptheoradepay,
125     GstBuffer * confbuf)
126 {
127   GstBuffer *buf;
128   guint32 num_headers;
129   guint8 *data, *bdata;
130   gsize size;
131   gint i, j;
132
133   data = bdata = gst_buffer_map (confbuf, &size, NULL, GST_MAP_READ);
134
135   GST_DEBUG_OBJECT (rtptheoradepay, "config size %" G_GSIZE_FORMAT, size);
136
137   /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138    * |                     Number of packed headers                  |
139    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
141    * |                          Packed header                        |
142    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
143    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144    * |                          Packed header                        |
145    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
146    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147    * |                          ....                                 |
148    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149    */
150   if (size < 4)
151     goto too_small;
152
153   num_headers = GST_READ_UINT32_BE (data);
154   size -= 4;
155   data += 4;
156
157   GST_DEBUG_OBJECT (rtptheoradepay, "have %u headers", num_headers);
158
159   /*  0                   1                   2                   3
160    *  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
161    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162    * |                   Ident                       | length       ..
163    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
164    * ..              | n. of headers |    length1    |    length2   ..
165    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
166    * ..              |             Identification Header            ..
167    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
168    * .................................................................
169    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
170    * ..              |         Comment Header                       ..
171    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
172    * .................................................................
173    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174    * ..                        Comment Header                        |
175    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176    * |                          Setup Header                        ..
177    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178    * .................................................................
179    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
180    * ..                         Setup Header                         |
181    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
182    */
183   for (i = 0; i < num_headers; i++) {
184     guint32 ident;
185     guint16 length;
186     guint8 n_headers, b;
187     GstRtpTheoraConfig *conf;
188     guint *h_sizes;
189     guint extra = 1;
190
191     if (size < 6)
192       goto too_small;
193
194     ident = (data[0] << 16) | (data[1] << 8) | data[2];
195     length = (data[3] << 8) | data[4];
196     n_headers = data[5];
197     size -= 6;
198     data += 6;
199
200     GST_DEBUG_OBJECT (rtptheoradepay,
201         "header %d, ident 0x%08x, length %u, left %" G_GSIZE_FORMAT, i, ident,
202         length, size);
203
204     /* FIXME check if we already got this ident */
205
206     /* length might also include count of following size fields */
207     if (size < length && size + 1 != length)
208       goto too_small;
209
210     /* read header sizes we read 2 sizes, the third size (for which we allocate
211      * space) must be derived from the total packed header length. */
212     h_sizes = g_newa (guint, n_headers + 1);
213     for (j = 0; j < n_headers; j++) {
214       guint h_size;
215
216       h_size = 0;
217       do {
218         if (size < 1)
219           goto too_small;
220         b = *data++;
221         size--;
222         extra++;
223         h_size = (h_size << 7) | (b & 0x7f);
224       } while (b & 0x80);
225       GST_DEBUG_OBJECT (rtptheoradepay, "headers %d: size: %u", j, h_size);
226       h_sizes[j] = h_size;
227       length -= h_size;
228     }
229     /* last header length is the remaining space */
230     GST_DEBUG_OBJECT (rtptheoradepay, "last header size: %u", length);
231     h_sizes[j] = length;
232
233     GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
234     conf = g_new0 (GstRtpTheoraConfig, 1);
235     conf->ident = ident;
236
237     for (j = 0; j <= n_headers; j++) {
238       guint h_size;
239       guint8 *odata;
240
241       h_size = h_sizes[j];
242       if (size < h_size) {
243         if (j != n_headers || size + extra != h_size) {
244           goto too_small;
245         } else {
246           /* otherwise means that overall length field contained total length,
247            * including extra fields */
248           h_size -= extra;
249         }
250       }
251
252       GST_DEBUG_OBJECT (rtptheoradepay, "reading header %d, size %u", j,
253           h_size);
254
255       buf = gst_buffer_new_and_alloc (h_size);
256       odata = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
257       memcpy (odata, data, h_size);
258       gst_buffer_unmap (buf, odata, -1);
259       conf->headers = g_list_append (conf->headers, buf);
260       data += h_size;
261       size -= h_size;
262     }
263     rtptheoradepay->configs = g_list_append (rtptheoradepay->configs, conf);
264   }
265
266   gst_buffer_unmap (confbuf, bdata, -1);
267   return TRUE;
268
269   /* ERRORS */
270 too_small:
271   {
272     GST_DEBUG_OBJECT (rtptheoradepay, "configuration too small");
273     gst_buffer_unmap (confbuf, bdata, -1);
274     return FALSE;
275   }
276 }
277
278 static gboolean
279 gst_rtp_theora_depay_parse_inband_configuration (GstRtpTheoraDepay *
280     rtptheoradepay, guint ident, guint8 * configuration, guint size,
281     guint length)
282 {
283   GstBuffer *confbuf;
284   guint8 *conf;
285
286   if (G_UNLIKELY (size < 4))
287     return FALSE;
288
289   /* transform inline to out-of-band and parse that one */
290   confbuf = gst_buffer_new_and_alloc (size + 9);
291   conf = gst_buffer_map (confbuf, NULL, NULL, GST_MAP_WRITE);
292   /* 1 header */
293   GST_WRITE_UINT32_BE (conf, 1);
294   /* write Ident */
295   GST_WRITE_UINT24_BE (conf + 4, ident);
296   /* write sort-of-length */
297   GST_WRITE_UINT16_BE (conf + 7, length);
298   /* copy remainder */
299   memcpy (conf + 9, configuration, size);
300   gst_buffer_unmap (confbuf, conf, -1);
301
302   return gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf);
303 }
304
305 static gboolean
306 gst_rtp_theora_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
307 {
308   GstStructure *structure;
309   GstRtpTheoraDepay *rtptheoradepay;
310   GstCaps *srccaps;
311   const gchar *configuration;
312   gboolean res;
313
314   rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
315
316   rtptheoradepay->needs_keyframe = FALSE;
317
318   structure = gst_caps_get_structure (caps, 0);
319
320   /* read and parse configuration string */
321   configuration = gst_structure_get_string (structure, "configuration");
322   if (configuration) {
323     GstBuffer *confbuf;
324     guint8 *data;
325     gsize size;
326
327     /* configure string should be in the caps */
328     if (configuration == NULL)
329       goto no_configuration;
330
331     /* deserialize base64 to buffer */
332     data = g_base64_decode (configuration, &size);
333
334     confbuf = gst_buffer_new ();
335     gst_buffer_take_memory (confbuf, -1,
336         gst_memory_new_wrapped (0, data, g_free, size, 0, size));
337
338     if (!gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf))
339       goto invalid_configuration;
340   }
341
342   /* set caps on pad and on header */
343   srccaps = gst_caps_new_empty_simple ("video/x-theora");
344   res = gst_pad_set_caps (depayload->srcpad, srccaps);
345   gst_caps_unref (srccaps);
346
347   /* Clock rate is always 90000 according to draft-barbato-avt-rtp-theora-01 */
348   depayload->clock_rate = 90000;
349
350   return res;
351
352   /* ERRORS */
353 no_configuration:
354   {
355     GST_ERROR_OBJECT (rtptheoradepay, "no configuration specified");
356     return FALSE;
357   }
358 invalid_configuration:
359   {
360     GST_ERROR_OBJECT (rtptheoradepay, "invalid configuration specified");
361     return FALSE;
362   }
363 }
364
365 static gboolean
366 gst_rtp_theora_depay_switch_codebook (GstRtpTheoraDepay * rtptheoradepay,
367     guint32 ident)
368 {
369   GList *walk;
370   gboolean res = FALSE;
371
372   for (walk = rtptheoradepay->configs; walk; walk = g_list_next (walk)) {
373     GstRtpTheoraConfig *conf = (GstRtpTheoraConfig *) walk->data;
374
375     if (conf->ident == ident) {
376       GList *headers;
377
378       /* FIXME, remove pads, create new pad.. */
379
380       /* push out all the headers */
381       for (headers = conf->headers; headers; headers = g_list_next (headers)) {
382         GstBuffer *header = GST_BUFFER_CAST (headers->data);
383
384         gst_buffer_ref (header);
385         gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtptheoradepay),
386             header);
387       }
388       /* remember the current config */
389       rtptheoradepay->config = conf;
390       res = TRUE;
391     }
392   }
393   if (!res) {
394     /* we don't know about the headers, figure out an alternative method for
395      * getting the codebooks. FIXME, fail for now. */
396   }
397   return res;
398 }
399
400 static GstBuffer *
401 gst_rtp_theora_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
402 {
403   GstRtpTheoraDepay *rtptheoradepay;
404   GstBuffer *outbuf;
405   GstFlowReturn ret;
406   gint payload_len;
407   guint8 *payload, *to_free = NULL;
408   guint32 header, ident;
409   guint8 F, TDT, packets;
410   GstRTPBuffer rtp;
411
412   rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
413
414   gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
415
416   payload_len = gst_rtp_buffer_get_payload_len (&rtp);
417
418   GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
419
420   /* we need at least 4 bytes for the packet header */
421   if (G_UNLIKELY (payload_len < 4))
422     goto packet_short;
423
424   payload = gst_rtp_buffer_get_payload (&rtp);
425
426   header = GST_READ_UINT32_BE (payload);
427   /*
428    *  0                   1                   2                   3
429    *  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
430    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
431    * |                     Ident                     | F |TDT|# pkts.|
432    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433    *
434    * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
435    * TDT: Theora data type (0=theora, 1=config, 2=comment, 3=reserved)
436    * pkts: number of packets.
437    */
438   TDT = (header & 0x30) >> 4;
439   if (G_UNLIKELY (TDT == 3))
440     goto ignore_reserved;
441
442   ident = (header >> 8) & 0xffffff;
443   F = (header & 0xc0) >> 6;
444   packets = (header & 0xf);
445
446   GST_DEBUG_OBJECT (depayload, "ident: 0x%08x, F: %d, TDT: %d, packets: %d",
447       ident, F, TDT, packets);
448
449   if (TDT == 0) {
450     gboolean do_switch = FALSE;
451
452     /* we have a raw payload, find the codebook for the ident */
453     if (!rtptheoradepay->config) {
454       /* we don't have an active codebook, find the codebook and
455        * activate it */
456       do_switch = TRUE;
457     } else if (rtptheoradepay->config->ident != ident) {
458       /* codebook changed */
459       do_switch = TRUE;
460     }
461     if (do_switch) {
462       if (!gst_rtp_theora_depay_switch_codebook (rtptheoradepay, ident))
463         goto switch_failed;
464     }
465   }
466
467   /* skip header */
468   payload += 4;
469   payload_len -= 4;
470
471   /* fragmented packets, assemble */
472   if (F != 0) {
473     GstBuffer *vdata;
474     guint headerskip;
475
476     if (F == 1) {
477       /* if we start a packet, clear adapter and start assembling. */
478       gst_adapter_clear (rtptheoradepay->adapter);
479       GST_DEBUG_OBJECT (depayload, "start assemble");
480       rtptheoradepay->assembling = TRUE;
481     }
482
483     if (!rtptheoradepay->assembling)
484       goto no_output;
485
486     /* first assembled packet, reuse 2 bytes to store the length */
487     headerskip = (F == 1 ? 4 : 6);
488     /* skip header and length. */
489     vdata = gst_rtp_buffer_get_payload_subbuffer (&rtp, headerskip, -1);
490
491     GST_DEBUG_OBJECT (depayload, "assemble theora packet");
492     gst_adapter_push (rtptheoradepay->adapter, vdata);
493
494     /* packet is not complete, we are done */
495     if (F != 3)
496       goto no_output;
497
498     /* construct assembled buffer */
499     payload_len = gst_adapter_available (rtptheoradepay->adapter);
500     payload = gst_adapter_take (rtptheoradepay->adapter, payload_len);
501     /* fix the length */
502     payload[0] = ((payload_len - 2) >> 8) & 0xff;
503     payload[1] = (payload_len - 2) & 0xff;
504     to_free = payload;
505   }
506
507   GST_DEBUG_OBJECT (depayload, "assemble done, payload_len %d", payload_len);
508
509   /* we not assembling anymore now */
510   rtptheoradepay->assembling = FALSE;
511   gst_adapter_clear (rtptheoradepay->adapter);
512
513   /* payload now points to a length with that many theora data bytes.
514    * Iterate over the packets and send them out.
515    *
516    *  0                   1                   2                   3
517    *  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
518    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
519    * |             length            |          theora data         ..
520    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
521    * ..                        theora data                           |
522    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523    * |            length             |   next theora packet data    ..
524    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525    * ..                        theora data                           |
526    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
527    */
528   while (payload_len >= 2) {
529     guint16 length;
530
531     length = GST_READ_UINT16_BE (payload);
532     payload += 2;
533     payload_len -= 2;
534
535     GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
536         payload_len);
537
538     /* skip packet if something odd happens */
539     if (G_UNLIKELY (length > payload_len))
540       goto length_short;
541
542     /* handle in-band configuration */
543     if (G_UNLIKELY (TDT == 1)) {
544       GST_DEBUG_OBJECT (rtptheoradepay, "in-band configuration");
545       if (!gst_rtp_theora_depay_parse_inband_configuration (rtptheoradepay,
546               ident, payload, payload_len, length))
547         goto invalid_configuration;
548       goto no_output;
549     }
550
551     /* create buffer for packet */
552     if (G_UNLIKELY (to_free)) {
553       outbuf = gst_buffer_new ();
554       gst_buffer_take_memory (buf, -1,
555           gst_memory_new_wrapped (0, to_free, g_free,
556               (payload - to_free) + length, payload - to_free, length));
557       to_free = NULL;
558     } else {
559       guint8 *odata;
560
561       outbuf = gst_buffer_new_and_alloc (length);
562       odata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
563       memcpy (odata, payload, length);
564       gst_buffer_unmap (outbuf, odata, -1);
565     }
566
567     if (payload_len > 0 && (payload[0] & 0xC0) == 0x0)
568       rtptheoradepay->needs_keyframe = FALSE;
569
570     payload += length;
571     payload_len -= length;
572
573     ret = gst_rtp_base_depayload_push (depayload, outbuf);
574     if (ret != GST_FLOW_OK)
575       break;
576   }
577
578   g_free (to_free);
579
580   if (rtptheoradepay->needs_keyframe)
581     goto request_keyframe;
582
583   gst_rtp_buffer_unmap (&rtp);
584   return NULL;
585
586 no_output:
587   {
588     gst_rtp_buffer_unmap (&rtp);
589     return NULL;
590   }
591   /* ERORRS */
592 switch_failed:
593   {
594     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
595         (NULL), ("Could not switch codebooks"));
596     goto request_config;
597   }
598 packet_short:
599   {
600     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
601         (NULL), ("Packet was too short (%d < 4)", payload_len));
602     goto request_keyframe;
603   }
604 ignore_reserved:
605   {
606     GST_WARNING_OBJECT (rtptheoradepay, "reserved TDT ignored");
607     gst_rtp_buffer_unmap (&rtp);
608     return NULL;
609   }
610 length_short:
611   {
612     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
613         (NULL), ("Packet contains invalid data"));
614     goto request_keyframe;
615   }
616 invalid_configuration:
617   {
618     /* fatal, as we otherwise risk carrying on without output */
619     GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
620         (NULL), ("Packet contains invalid configuration"));
621     goto request_config;
622   }
623 request_config:
624   {
625     gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
626         gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
627             gst_structure_new ("GstForceKeyUnit",
628                 "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
629     gst_rtp_buffer_unmap (&rtp);
630     return NULL;
631   }
632 request_keyframe:
633   {
634     rtptheoradepay->needs_keyframe = TRUE;
635     gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
636         gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
637             gst_structure_new_empty ("GstForceKeyUnit")));
638     gst_rtp_buffer_unmap (&rtp);
639     return NULL;
640   }
641 }
642
643 gboolean
644 gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
645 {
646   return gst_element_register (plugin, "rtptheoradepay",
647       GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_DEPAY);
648 }
649
650 static gboolean
651 gst_rtp_theora_depay_packet_lost (GstRTPBaseDepayload * depayload,
652     GstEvent * event)
653 {
654   GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
655   guint seqnum = 0;
656
657   gst_structure_get_uint (gst_event_get_structure (event), "seqnum", &seqnum);
658   GST_LOG_OBJECT (depayload, "Requested keyframe because frame with seqnum %u"
659       " is missing", seqnum);
660   rtptheoradepay->needs_keyframe = TRUE;
661
662   gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
663       gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
664           gst_structure_new_empty ("GstForceKeyUnit")));
665
666   return TRUE;
667 }