rtp: port remaining to 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_BASE_RTP_DEPAYLOAD);
66
67 static gboolean gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload,
68     GstCaps * caps);
69 static GstBuffer *gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload,
70     GstBuffer * buf);
71 static gboolean gst_rtp_theora_depay_packet_lost (GstBaseRTPDepayload *
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   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
82
83   gobject_class = (GObjectClass *) klass;
84   gstelement_class = (GstElementClass *) klass;
85   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
86
87   gobject_class->finalize = gst_rtp_theora_depay_finalize;
88
89   gstbasertpdepayload_class->process = gst_rtp_theora_depay_process;
90   gstbasertpdepayload_class->set_caps = gst_rtp_theora_depay_setcaps;
91   gstbasertpdepayload_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 %u", i, ident, length, size);
202
203     /* FIXME check if we already got this ident */
204
205     /* length might also include count of following size fields */
206     if (size < length && size + 1 != length)
207       goto too_small;
208
209     /* read header sizes we read 2 sizes, the third size (for which we allocate
210      * space) must be derived from the total packed header length. */
211     h_sizes = g_newa (guint, n_headers + 1);
212     for (j = 0; j < n_headers; j++) {
213       guint h_size;
214
215       h_size = 0;
216       do {
217         if (size < 1)
218           goto too_small;
219         b = *data++;
220         size--;
221         extra++;
222         h_size = (h_size << 7) | (b & 0x7f);
223       } while (b & 0x80);
224       GST_DEBUG_OBJECT (rtptheoradepay, "headers %d: size: %u", j, h_size);
225       h_sizes[j] = h_size;
226       length -= h_size;
227     }
228     /* last header length is the remaining space */
229     GST_DEBUG_OBJECT (rtptheoradepay, "last header size: %u", length);
230     h_sizes[j] = length;
231
232     GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
233     conf = g_new0 (GstRtpTheoraConfig, 1);
234     conf->ident = ident;
235
236     for (j = 0; j <= n_headers; j++) {
237       guint h_size;
238       guint8 *odata;
239
240       h_size = h_sizes[j];
241       if (size < h_size) {
242         if (j != n_headers || size + extra != h_size) {
243           goto too_small;
244         } else {
245           /* otherwise means that overall length field contained total length,
246            * including extra fields */
247           h_size -= extra;
248         }
249       }
250
251       GST_DEBUG_OBJECT (rtptheoradepay, "reading header %d, size %u", j,
252           h_size);
253
254       buf = gst_buffer_new_and_alloc (h_size);
255       odata = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
256       memcpy (odata, data, h_size);
257       gst_buffer_unmap (buf, odata, -1);
258       conf->headers = g_list_append (conf->headers, buf);
259       data += h_size;
260       size -= h_size;
261     }
262     rtptheoradepay->configs = g_list_append (rtptheoradepay->configs, conf);
263   }
264
265   gst_buffer_unmap (confbuf, bdata, -1);
266   return TRUE;
267
268   /* ERRORS */
269 too_small:
270   {
271     GST_DEBUG_OBJECT (rtptheoradepay, "configuration too small");
272     gst_buffer_unmap (confbuf, bdata, -1);
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_map (confbuf, NULL, NULL, GST_MAP_WRITE);
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   gst_buffer_unmap (confbuf, conf, -1);
300
301   return gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf);
302 }
303
304 static gboolean
305 gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
306 {
307   GstStructure *structure;
308   GstRtpTheoraDepay *rtptheoradepay;
309   GstCaps *srccaps;
310   const gchar *configuration;
311   gboolean res;
312
313   rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
314
315   rtptheoradepay->needs_keyframe = FALSE;
316
317   structure = gst_caps_get_structure (caps, 0);
318
319   /* read and parse configuration string */
320   configuration = gst_structure_get_string (structure, "configuration");
321   if (configuration) {
322     GstBuffer *confbuf;
323     guint8 *data;
324     gsize size;
325
326     /* configure string should be in the caps */
327     if (configuration == NULL)
328       goto no_configuration;
329
330     /* deserialize base64 to buffer */
331     data = g_base64_decode (configuration, &size);
332
333     confbuf = gst_buffer_new ();
334     gst_buffer_take_memory (confbuf, -1,
335         gst_memory_new_wrapped (0, data, g_free, size, 0, 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   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   timestamp = gst_rtp_buffer_get_timestamp (&rtp);
529
530   while (payload_len >= 2) {
531     guint16 length;
532
533     length = GST_READ_UINT16_BE (payload);
534     payload += 2;
535     payload_len -= 2;
536
537     GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
538         payload_len);
539
540     /* skip packet if something odd happens */
541     if (G_UNLIKELY (length > payload_len))
542       goto length_short;
543
544     /* handle in-band configuration */
545     if (G_UNLIKELY (TDT == 1)) {
546       GST_DEBUG_OBJECT (rtptheoradepay, "in-band configuration");
547       if (!gst_rtp_theora_depay_parse_inband_configuration (rtptheoradepay,
548               ident, payload, payload_len, length))
549         goto invalid_configuration;
550       goto no_output;
551     }
552
553     /* create buffer for packet */
554     if (G_UNLIKELY (to_free)) {
555       outbuf = gst_buffer_new ();
556       gst_buffer_take_memory (buf, -1,
557           gst_memory_new_wrapped (0, to_free, g_free,
558               (payload - to_free) + length, payload - to_free, length));
559       to_free = NULL;
560     } else {
561       guint8 *odata;
562
563       outbuf = gst_buffer_new_and_alloc (length);
564       odata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
565       memcpy (odata, payload, length);
566       gst_buffer_unmap (outbuf, odata, -1);
567     }
568
569     if (payload_len > 0 && (payload[0] & 0xC0) == 0x0)
570       rtptheoradepay->needs_keyframe = FALSE;
571
572     payload += length;
573     payload_len -= length;
574
575     if (timestamp != -1)
576       /* push with timestamp of the last packet, which is the same timestamp that
577        * should apply to the first assembled packet. */
578       ret = gst_base_rtp_depayload_push_ts (depayload, timestamp, outbuf);
579     else
580       ret = gst_base_rtp_depayload_push (depayload, outbuf);
581
582     if (ret != GST_FLOW_OK)
583       break;
584
585     /* make sure we don't set a timestamp on next buffers */
586     timestamp = -1;
587   }
588
589   g_free (to_free);
590
591   if (rtptheoradepay->needs_keyframe)
592     goto request_keyframe;
593
594   gst_rtp_buffer_unmap (&rtp);
595   return NULL;
596
597 no_output:
598   {
599     gst_rtp_buffer_unmap (&rtp);
600     return NULL;
601   }
602   /* ERORRS */
603 switch_failed:
604   {
605     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
606         (NULL), ("Could not switch codebooks"));
607     goto request_config;
608   }
609 packet_short:
610   {
611     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
612         (NULL), ("Packet was too short (%d < 4)", payload_len));
613     goto request_keyframe;
614   }
615 ignore_reserved:
616   {
617     GST_WARNING_OBJECT (rtptheoradepay, "reserved TDT ignored");
618     gst_rtp_buffer_unmap (&rtp);
619     return NULL;
620   }
621 length_short:
622   {
623     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
624         (NULL), ("Packet contains invalid data"));
625     goto request_keyframe;
626   }
627 invalid_configuration:
628   {
629     /* fatal, as we otherwise risk carrying on without output */
630     GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
631         (NULL), ("Packet contains invalid configuration"));
632     goto request_config;
633   }
634 request_config:
635   {
636     gst_pad_push_event (GST_BASE_RTP_DEPAYLOAD_SINKPAD (depayload),
637         gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
638             gst_structure_new ("GstForceKeyUnit",
639                 "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
640     gst_rtp_buffer_unmap (&rtp);
641     return NULL;
642   }
643 request_keyframe:
644   {
645     rtptheoradepay->needs_keyframe = TRUE;
646     gst_pad_push_event (GST_BASE_RTP_DEPAYLOAD_SINKPAD (depayload),
647         gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
648             gst_structure_new ("GstForceKeyUnit", NULL)));
649     gst_rtp_buffer_unmap (&rtp);
650     return NULL;
651   }
652 }
653
654 gboolean
655 gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
656 {
657   return gst_element_register (plugin, "rtptheoradepay",
658       GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_DEPAY);
659 }
660
661 static gboolean
662 gst_rtp_theora_depay_packet_lost (GstBaseRTPDepayload * depayload,
663     GstEvent * event)
664 {
665   GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
666   guint seqnum = 0;
667
668   gst_structure_get_uint (gst_event_get_structure (event), "seqnum", &seqnum);
669   GST_LOG_OBJECT (depayload, "Requested keyframe because frame with seqnum %u"
670       " is missing", seqnum);
671   rtptheoradepay->needs_keyframe = TRUE;
672
673   gst_pad_push_event (GST_BASE_RTP_DEPAYLOAD_SINKPAD (depayload),
674       gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
675           gst_structure_new ("GstForceKeyUnit", NULL)));
676
677   return TRUE;
678 }