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