2 * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
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.
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.
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.
24 #include <gst/tag/tag.h>
25 #include <gst/rtp/gstrtpbuffer.h>
28 #include "gstrtptheoradepay.h"
30 GST_DEBUG_CATEGORY_STATIC (rtptheoradepay_debug);
31 #define GST_CAT_DEFAULT (rtptheoradepay_debug)
33 static GstStaticPadTemplate gst_rtp_theora_depay_sink_template =
34 GST_STATIC_PAD_TEMPLATE ("sink",
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
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"
49 /* All optional parameters
51 * "configuration-uri ="
56 static GstStaticPadTemplate gst_rtp_theora_depay_src_template =
57 GST_STATIC_PAD_TEMPLATE ("src",
60 GST_STATIC_CAPS ("video/x-theora")
63 GST_BOILERPLATE (GstRtpTheoraDepay, gst_rtp_theora_depay, GstBaseRTPDepayload,
64 GST_TYPE_BASE_RTP_DEPAYLOAD);
66 static gboolean gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload,
68 static GstBuffer *gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload,
70 static gboolean gst_rtp_theora_depay_packet_lost (GstBaseRTPDepayload *
71 depayload, GstEvent * event);
73 static void gst_rtp_theora_depay_finalize (GObject * object);
77 gst_rtp_theora_depay_base_init (gpointer klass)
79 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
81 gst_element_class_add_pad_template (element_class,
82 gst_static_pad_template_get (&gst_rtp_theora_depay_sink_template));
83 gst_element_class_add_pad_template (element_class,
84 gst_static_pad_template_get (&gst_rtp_theora_depay_src_template));
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>");
93 gst_rtp_theora_depay_class_init (GstRtpTheoraDepayClass * klass)
95 GObjectClass *gobject_class;
96 GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
98 gobject_class = (GObjectClass *) klass;
99 gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
101 gobject_class->finalize = gst_rtp_theora_depay_finalize;
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;
107 GST_DEBUG_CATEGORY_INIT (rtptheoradepay_debug, "rtptheoradepay", 0,
108 "Theora RTP Depayloader");
112 gst_rtp_theora_depay_init (GstRtpTheoraDepay * rtptheoradepay,
113 GstRtpTheoraDepayClass * klass)
115 rtptheoradepay->adapter = gst_adapter_new ();
119 gst_rtp_theora_depay_finalize (GObject * object)
121 GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (object);
123 g_object_unref (rtptheoradepay->adapter);
125 G_OBJECT_CLASS (parent_class)->finalize (object);
129 gst_rtp_theora_depay_parse_configuration (GstRtpTheoraDepay * rtptheoradepay,
138 data = GST_BUFFER_DATA (confbuf);
139 size = GST_BUFFER_SIZE (confbuf);
141 GST_DEBUG_OBJECT (rtptheoradepay, "config size %u", size);
143 /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144 * | Number of packed headers |
145 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
146 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
148 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
152 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
154 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159 num_headers = GST_READ_UINT32_BE (data);
163 GST_DEBUG_OBJECT (rtptheoradepay, "have %u headers", num_headers);
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
183 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
184 * .................................................................
185 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
187 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
189 for (i = 0; i < num_headers; i++) {
193 GstRtpTheoraConfig *conf;
200 ident = (data[0] << 16) | (data[1] << 8) | data[2];
201 length = (data[3] << 8) | data[4];
206 GST_DEBUG_OBJECT (rtptheoradepay,
207 "header %d, ident 0x%08x, length %u, left %u", i, ident, length, size);
209 /* FIXME check if we already got this ident */
211 /* length might also include count of following size fields */
212 if (size < length && size + 1 != length)
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++) {
228 h_size = (h_size << 7) | (b & 0x7f);
230 GST_DEBUG_OBJECT (rtptheoradepay, "headers %d: size: %u", j, h_size);
234 /* last header length is the remaining space */
235 GST_DEBUG_OBJECT (rtptheoradepay, "last header size: %u", length);
238 GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
239 conf = g_new0 (GstRtpTheoraConfig, 1);
242 for (j = 0; j <= n_headers; j++) {
247 if (j != n_headers || size + extra != h_size) {
250 /* otherwise means that overall length field contained total length,
251 * including extra fields */
256 GST_DEBUG_OBJECT (rtptheoradepay, "reading header %d, size %u", j,
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);
265 rtptheoradepay->configs = g_list_append (rtptheoradepay->configs, conf);
272 GST_DEBUG_OBJECT (rtptheoradepay, "configuration too small");
278 gst_rtp_theora_depay_parse_inband_configuration (GstRtpTheoraDepay *
279 rtptheoradepay, guint ident, guint8 * configuration, guint size,
285 if (G_UNLIKELY (size < 4))
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);
292 GST_WRITE_UINT32_BE (conf, 1);
294 GST_WRITE_UINT24_BE (conf + 4, ident);
295 /* write sort-of-length */
296 GST_WRITE_UINT16_BE (conf + 7, length);
298 memcpy (conf + 9, configuration, size);
300 return gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf);
304 gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
306 GstStructure *structure;
307 GstRtpTheoraDepay *rtptheoradepay;
309 const gchar *configuration;
312 rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
314 rtptheoradepay->needs_keyframe = FALSE;
316 structure = gst_caps_get_structure (caps, 0);
318 /* read and parse configuration string */
319 configuration = gst_structure_get_string (structure, "configuration");
325 /* configure string should be in the caps */
326 if (configuration == NULL)
327 goto no_configuration;
329 /* deserialize base64 to buffer */
330 data = g_base64_decode (configuration, &size);
332 confbuf = gst_buffer_new ();
333 GST_BUFFER_DATA (confbuf) = data;
334 GST_BUFFER_MALLOCDATA (confbuf) = data;
335 GST_BUFFER_SIZE (confbuf) = size;
337 if (!gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf))
338 goto invalid_configuration;
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);
346 /* Clock rate is always 90000 according to draft-barbato-avt-rtp-theora-01 */
347 depayload->clock_rate = 90000;
354 GST_ERROR_OBJECT (rtptheoradepay, "no configuration specified");
357 invalid_configuration:
359 GST_ERROR_OBJECT (rtptheoradepay, "invalid configuration specified");
365 gst_rtp_theora_depay_switch_codebook (GstRtpTheoraDepay * rtptheoradepay,
369 gboolean res = FALSE;
371 for (walk = rtptheoradepay->configs; walk; walk = g_list_next (walk)) {
372 GstRtpTheoraConfig *conf = (GstRtpTheoraConfig *) walk->data;
374 if (conf->ident == ident) {
377 /* FIXME, remove pads, create new pad.. */
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);
383 gst_buffer_ref (header);
384 gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtptheoradepay),
387 /* remember the current config */
388 rtptheoradepay->config = conf;
393 /* we don't know about the headers, figure out an alternative method for
394 * getting the codebooks. FIXME, fail for now. */
400 gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
402 GstRtpTheoraDepay *rtptheoradepay;
406 guint8 *payload, *to_free = NULL;
408 guint32 header, ident;
409 guint8 F, TDT, packets;
411 rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
413 payload_len = gst_rtp_buffer_get_payload_len (buf);
415 GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
417 /* we need at least 4 bytes for the packet header */
418 if (G_UNLIKELY (payload_len < 4))
421 payload = gst_rtp_buffer_get_payload (buf);
423 header = GST_READ_UINT32_BE (payload);
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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.
435 TDT = (header & 0x30) >> 4;
436 if (G_UNLIKELY (TDT == 3))
437 goto ignore_reserved;
439 ident = (header >> 8) & 0xffffff;
440 F = (header & 0xc0) >> 6;
441 packets = (header & 0xf);
443 GST_DEBUG_OBJECT (depayload, "ident: 0x%08x, F: %d, TDT: %d, packets: %d",
444 ident, F, TDT, packets);
447 gboolean do_switch = FALSE;
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
454 } else if (rtptheoradepay->config->ident != ident) {
455 /* codebook changed */
459 if (!gst_rtp_theora_depay_switch_codebook (rtptheoradepay, ident))
468 /* fragmented packets, assemble */
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;
480 if (!rtptheoradepay->assembling)
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);
488 GST_DEBUG_OBJECT (depayload, "assemble theora packet");
489 gst_adapter_push (rtptheoradepay->adapter, vdata);
491 /* packet is not complete, we are done */
495 /* construct assembled buffer */
496 payload_len = gst_adapter_available (rtptheoradepay->adapter);
497 payload = gst_adapter_take (rtptheoradepay->adapter, payload_len);
499 payload[0] = ((payload_len - 2) >> 8) & 0xff;
500 payload[1] = (payload_len - 2) & 0xff;
504 GST_DEBUG_OBJECT (depayload, "assemble done, payload_len %d", payload_len);
506 /* we not assembling anymore now */
507 rtptheoradepay->assembling = FALSE;
508 gst_adapter_clear (rtptheoradepay->adapter);
510 /* payload now points to a length with that many theora data bytes.
511 * Iterate over the packets and send them out.
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
519 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
520 * | length | next theora packet data ..
521 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
525 timestamp = gst_rtp_buffer_get_timestamp (buf);
527 while (payload_len >= 2) {
530 length = GST_READ_UINT16_BE (payload);
534 GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
537 /* skip packet if something odd happens */
538 if (G_UNLIKELY (length > payload_len))
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;
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;
558 outbuf = gst_buffer_new_and_alloc (length);
559 memcpy (GST_BUFFER_DATA (outbuf), payload, length);
562 if (payload_len > 0 && (payload[0] & 0xC0) == 0x0)
563 rtptheoradepay->needs_keyframe = FALSE;
566 payload_len -= length;
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);
573 ret = gst_base_rtp_depayload_push (depayload, outbuf);
575 if (ret != GST_FLOW_OK)
578 /* make sure we don't set a timestamp on next buffers */
584 if (rtptheoradepay->needs_keyframe)
585 goto request_keyframe;
596 GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
597 (NULL), ("Could not switch codebooks"));
602 GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
603 (NULL), ("Packet was too short (%d < 4)", payload_len));
604 goto request_keyframe;
608 GST_WARNING_OBJECT (rtptheoradepay, "reserved TDT ignored");
613 GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
614 (NULL), ("Packet contains invalid data"));
615 goto request_keyframe;
617 invalid_configuration:
619 /* fatal, as we otherwise risk carrying on without output */
620 GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
621 (NULL), ("Packet contains invalid configuration"));
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)));
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)));
643 gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
645 return gst_element_register (plugin, "rtptheoradepay",
646 GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_DEPAY);
650 gst_rtp_theora_depay_packet_lost (GstBaseRTPDepayload * depayload,
653 GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
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;
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)));