e86c5433ed46ced3ee0b24dc1f10f68b11cfe34f
[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   GstMapInfo map;
130   guint8 *data;
131   gsize size;
132   gint i, j;
133
134   gst_buffer_map (confbuf, &map, GST_MAP_READ);
135   data = map.data;
136   size = map.size;
137
138   GST_DEBUG_OBJECT (rtptheoradepay, "config size %" G_GSIZE_FORMAT, size);
139
140   /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
141    * |                     Number of packed headers                  |
142    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
143    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144    * |                          Packed header                        |
145    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
146    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147    * |                          Packed header                        |
148    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
150    * |                          ....                                 |
151    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
152    */
153   if (size < 4)
154     goto too_small;
155
156   num_headers = GST_READ_UINT32_BE (data);
157   size -= 4;
158   data += 4;
159
160   GST_DEBUG_OBJECT (rtptheoradepay, "have %u headers", num_headers);
161
162   /*  0                   1                   2                   3
163    *  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
164    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165    * |                   Ident                       | length       ..
166    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
167    * ..              | n. of headers |    length1    |    length2   ..
168    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
169    * ..              |             Identification Header            ..
170    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
171    * .................................................................
172    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
173    * ..              |         Comment Header                       ..
174    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175    * .................................................................
176    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
177    * ..                        Comment Header                        |
178    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179    * |                          Setup Header                        ..
180    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181    * .................................................................
182    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
183    * ..                         Setup Header                         |
184    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
185    */
186   for (i = 0; i < num_headers; i++) {
187     guint32 ident;
188     guint16 length;
189     guint8 n_headers, b;
190     GstRtpTheoraConfig *conf;
191     guint *h_sizes;
192     guint extra = 1;
193
194     if (size < 6)
195       goto too_small;
196
197     ident = (data[0] << 16) | (data[1] << 8) | data[2];
198     length = (data[3] << 8) | data[4];
199     n_headers = data[5];
200     size -= 6;
201     data += 6;
202
203     GST_DEBUG_OBJECT (rtptheoradepay,
204         "header %d, ident 0x%08x, length %u, left %" G_GSIZE_FORMAT, i, ident,
205         length, size);
206
207     /* FIXME check if we already got this ident */
208
209     /* length might also include count of following size fields */
210     if (size < length && size + 1 != length)
211       goto too_small;
212
213     /* read header sizes we read 2 sizes, the third size (for which we allocate
214      * space) must be derived from the total packed header length. */
215     h_sizes = g_newa (guint, n_headers + 1);
216     for (j = 0; j < n_headers; j++) {
217       guint h_size;
218
219       h_size = 0;
220       do {
221         if (size < 1)
222           goto too_small;
223         b = *data++;
224         size--;
225         extra++;
226         h_size = (h_size << 7) | (b & 0x7f);
227       } while (b & 0x80);
228       GST_DEBUG_OBJECT (rtptheoradepay, "headers %d: size: %u", j, h_size);
229       h_sizes[j] = h_size;
230       length -= h_size;
231     }
232     /* last header length is the remaining space */
233     GST_DEBUG_OBJECT (rtptheoradepay, "last header size: %u", length);
234     h_sizes[j] = length;
235
236     GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
237     conf = g_new0 (GstRtpTheoraConfig, 1);
238     conf->ident = ident;
239
240     for (j = 0; j <= n_headers; j++) {
241       guint h_size;
242
243       h_size = h_sizes[j];
244       if (size < h_size) {
245         if (j != n_headers || size + extra != h_size) {
246           goto too_small;
247         } else {
248           /* otherwise means that overall length field contained total length,
249            * including extra fields */
250           h_size -= extra;
251         }
252       }
253
254       GST_DEBUG_OBJECT (rtptheoradepay, "reading header %d, size %u", j,
255           h_size);
256
257       buf = gst_buffer_new_and_alloc (h_size);
258       gst_buffer_fill (buf, 0, data, h_size);
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, &map);
267   return TRUE;
268
269   /* ERRORS */
270 too_small:
271   {
272     GST_DEBUG_OBJECT (rtptheoradepay, "configuration too small");
273     gst_buffer_unmap (confbuf, &map);
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   GstMapInfo map;
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   gst_buffer_map (confbuf, &map, GST_MAP_WRITE);
292   /* 1 header */
293   GST_WRITE_UINT32_BE (map.data, 1);
294   /* write Ident */
295   GST_WRITE_UINT24_BE (map.data + 4, ident);
296   /* write sort-of-length */
297   GST_WRITE_UINT16_BE (map.data + 7, length);
298   /* copy remainder */
299   memcpy (map.data + 9, configuration, size);
300   gst_buffer_unmap (confbuf, &map);
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     /* deserialize base64 to buffer */
328     data = g_base64_decode (configuration, &size);
329
330     confbuf = gst_buffer_new ();
331     gst_buffer_take_memory (confbuf, -1,
332         gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
333
334     if (!gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf))
335       goto invalid_configuration;
336   }
337
338   /* set caps on pad and on header */
339   srccaps = gst_caps_new_empty_simple ("video/x-theora");
340   res = gst_pad_set_caps (depayload->srcpad, srccaps);
341   gst_caps_unref (srccaps);
342
343   /* Clock rate is always 90000 according to draft-barbato-avt-rtp-theora-01 */
344   depayload->clock_rate = 90000;
345
346   return res;
347
348   /* ERRORS */
349 invalid_configuration:
350   {
351     GST_ERROR_OBJECT (rtptheoradepay, "invalid configuration specified");
352     return FALSE;
353   }
354 }
355
356 static gboolean
357 gst_rtp_theora_depay_switch_codebook (GstRtpTheoraDepay * rtptheoradepay,
358     guint32 ident)
359 {
360   GList *walk;
361   gboolean res = FALSE;
362
363   for (walk = rtptheoradepay->configs; walk; walk = g_list_next (walk)) {
364     GstRtpTheoraConfig *conf = (GstRtpTheoraConfig *) walk->data;
365
366     if (conf->ident == ident) {
367       GList *headers;
368
369       /* FIXME, remove pads, create new pad.. */
370
371       /* push out all the headers */
372       for (headers = conf->headers; headers; headers = g_list_next (headers)) {
373         GstBuffer *header = GST_BUFFER_CAST (headers->data);
374
375         gst_buffer_ref (header);
376         gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtptheoradepay),
377             header);
378       }
379       /* remember the current config */
380       rtptheoradepay->config = conf;
381       res = TRUE;
382     }
383   }
384   if (!res) {
385     /* we don't know about the headers, figure out an alternative method for
386      * getting the codebooks. FIXME, fail for now. */
387   }
388   return res;
389 }
390
391 static GstBuffer *
392 gst_rtp_theora_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
393 {
394   GstRtpTheoraDepay *rtptheoradepay;
395   GstBuffer *outbuf;
396   GstFlowReturn ret;
397   gint payload_len;
398   guint8 *payload, *to_free = NULL;
399   guint32 header, ident;
400   guint8 F, TDT, packets;
401   GstRTPBuffer rtp = { NULL };
402
403   rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
404
405   gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
406
407   payload_len = gst_rtp_buffer_get_payload_len (&rtp);
408
409   GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
410
411   /* we need at least 4 bytes for the packet header */
412   if (G_UNLIKELY (payload_len < 4))
413     goto packet_short;
414
415   payload = gst_rtp_buffer_get_payload (&rtp);
416
417   header = GST_READ_UINT32_BE (payload);
418   /*
419    *  0                   1                   2                   3
420    *  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
421    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422    * |                     Ident                     | F |TDT|# pkts.|
423    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
424    *
425    * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
426    * TDT: Theora data type (0=theora, 1=config, 2=comment, 3=reserved)
427    * pkts: number of packets.
428    */
429   TDT = (header & 0x30) >> 4;
430   if (G_UNLIKELY (TDT == 3))
431     goto ignore_reserved;
432
433   ident = (header >> 8) & 0xffffff;
434   F = (header & 0xc0) >> 6;
435   packets = (header & 0xf);
436
437   GST_DEBUG_OBJECT (depayload, "ident: 0x%08x, F: %d, TDT: %d, packets: %d",
438       ident, F, TDT, packets);
439
440   if (TDT == 0) {
441     gboolean do_switch = FALSE;
442
443     /* we have a raw payload, find the codebook for the ident */
444     if (!rtptheoradepay->config) {
445       /* we don't have an active codebook, find the codebook and
446        * activate it */
447       do_switch = TRUE;
448     } else if (rtptheoradepay->config->ident != ident) {
449       /* codebook changed */
450       do_switch = TRUE;
451     }
452     if (do_switch) {
453       if (!gst_rtp_theora_depay_switch_codebook (rtptheoradepay, ident))
454         goto switch_failed;
455     }
456   }
457
458   /* skip header */
459   payload += 4;
460   payload_len -= 4;
461
462   /* fragmented packets, assemble */
463   if (F != 0) {
464     GstBuffer *vdata;
465     guint headerskip;
466
467     if (F == 1) {
468       /* if we start a packet, clear adapter and start assembling. */
469       gst_adapter_clear (rtptheoradepay->adapter);
470       GST_DEBUG_OBJECT (depayload, "start assemble");
471       rtptheoradepay->assembling = TRUE;
472     }
473
474     if (!rtptheoradepay->assembling)
475       goto no_output;
476
477     /* first assembled packet, reuse 2 bytes to store the length */
478     headerskip = (F == 1 ? 4 : 6);
479     /* skip header and length. */
480     vdata = gst_rtp_buffer_get_payload_subbuffer (&rtp, headerskip, -1);
481
482     GST_DEBUG_OBJECT (depayload, "assemble theora packet");
483     gst_adapter_push (rtptheoradepay->adapter, vdata);
484
485     /* packet is not complete, we are done */
486     if (F != 3)
487       goto no_output;
488
489     /* construct assembled buffer */
490     payload_len = gst_adapter_available (rtptheoradepay->adapter);
491     payload = gst_adapter_take (rtptheoradepay->adapter, payload_len);
492     /* fix the length */
493     payload[0] = ((payload_len - 2) >> 8) & 0xff;
494     payload[1] = (payload_len - 2) & 0xff;
495     to_free = payload;
496   }
497
498   GST_DEBUG_OBJECT (depayload, "assemble done, payload_len %d", payload_len);
499
500   /* we not assembling anymore now */
501   rtptheoradepay->assembling = FALSE;
502   gst_adapter_clear (rtptheoradepay->adapter);
503
504   /* payload now points to a length with that many theora data bytes.
505    * Iterate over the packets and send them out.
506    *
507    *  0                   1                   2                   3
508    *  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
509    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510    * |             length            |          theora data         ..
511    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
512    * ..                        theora data                           |
513    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
514    * |            length             |   next theora packet data    ..
515    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516    * ..                        theora data                           |
517    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
518    */
519   while (payload_len >= 2) {
520     guint16 length;
521
522     length = GST_READ_UINT16_BE (payload);
523     payload += 2;
524     payload_len -= 2;
525
526     GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
527         payload_len);
528
529     /* skip packet if something odd happens */
530     if (G_UNLIKELY (length > payload_len))
531       goto length_short;
532
533     /* handle in-band configuration */
534     if (G_UNLIKELY (TDT == 1)) {
535       GST_DEBUG_OBJECT (rtptheoradepay, "in-band configuration");
536       if (!gst_rtp_theora_depay_parse_inband_configuration (rtptheoradepay,
537               ident, payload, payload_len, length))
538         goto invalid_configuration;
539       goto no_output;
540     }
541
542     /* create buffer for packet */
543     if (G_UNLIKELY (to_free)) {
544       outbuf = gst_buffer_new ();
545       gst_buffer_take_memory (buf, -1,
546           gst_memory_new_wrapped (0, to_free,
547               (payload - to_free) + length, payload - to_free, length, to_free,
548               g_free));
549       to_free = NULL;
550     } else {
551       outbuf = gst_buffer_new_and_alloc (length);
552       gst_buffer_fill (outbuf, 0, payload, length);
553     }
554
555     if (payload_len > 0 && (payload[0] & 0xC0) == 0x0)
556       rtptheoradepay->needs_keyframe = FALSE;
557
558     payload += length;
559     payload_len -= length;
560
561     ret = gst_rtp_base_depayload_push (depayload, outbuf);
562     if (ret != GST_FLOW_OK)
563       break;
564   }
565
566   g_free (to_free);
567
568   if (rtptheoradepay->needs_keyframe)
569     goto request_keyframe;
570
571   gst_rtp_buffer_unmap (&rtp);
572   return NULL;
573
574 no_output:
575   {
576     gst_rtp_buffer_unmap (&rtp);
577     return NULL;
578   }
579   /* ERORRS */
580 switch_failed:
581   {
582     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
583         (NULL), ("Could not switch codebooks"));
584     goto request_config;
585   }
586 packet_short:
587   {
588     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
589         (NULL), ("Packet was too short (%d < 4)", payload_len));
590     goto request_keyframe;
591   }
592 ignore_reserved:
593   {
594     GST_WARNING_OBJECT (rtptheoradepay, "reserved TDT ignored");
595     gst_rtp_buffer_unmap (&rtp);
596     return NULL;
597   }
598 length_short:
599   {
600     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
601         (NULL), ("Packet contains invalid data"));
602     goto request_keyframe;
603   }
604 invalid_configuration:
605   {
606     /* fatal, as we otherwise risk carrying on without output */
607     GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
608         (NULL), ("Packet contains invalid configuration"));
609     goto request_config;
610   }
611 request_config:
612   {
613     gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
614         gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
615             gst_structure_new ("GstForceKeyUnit",
616                 "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
617     gst_rtp_buffer_unmap (&rtp);
618     return NULL;
619   }
620 request_keyframe:
621   {
622     rtptheoradepay->needs_keyframe = TRUE;
623     gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
624         gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
625             gst_structure_new_empty ("GstForceKeyUnit")));
626     gst_rtp_buffer_unmap (&rtp);
627     return NULL;
628   }
629 }
630
631 gboolean
632 gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
633 {
634   return gst_element_register (plugin, "rtptheoradepay",
635       GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_DEPAY);
636 }
637
638 static gboolean
639 gst_rtp_theora_depay_packet_lost (GstRTPBaseDepayload * depayload,
640     GstEvent * event)
641 {
642   GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
643   guint seqnum = 0;
644
645   gst_structure_get_uint (gst_event_get_structure (event), "seqnum", &seqnum);
646   GST_LOG_OBJECT (depayload, "Requested keyframe because frame with seqnum %u"
647       " is missing", seqnum);
648   rtptheoradepay->needs_keyframe = TRUE;
649
650   gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
651       gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
652           gst_structure_new_empty ("GstForceKeyUnit")));
653
654   return TRUE;
655 }