2 * Copyright (C) <2008> 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/rtp/gstrtpbuffer.h>
27 #include "gstrtpjpegdepay.h"
29 GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
30 #define GST_CAT_DEFAULT (rtpjpegdepay_debug)
32 /* elementfactory information */
33 static const GstElementDetails gst_rtp_jpegdepay_details =
34 GST_ELEMENT_DETAILS ("RTP JPEG depayloader",
35 "Codec/Depayloader/Network",
36 "Extracts JPEG video from RTP packets (RFC 2435)",
37 "Wim Taymans <wim.taymans@gmail.com>");
39 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
40 GST_STATIC_PAD_TEMPLATE ("src",
43 GST_STATIC_CAPS ("image/jpeg")
46 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
47 GST_STATIC_PAD_TEMPLATE ("sink",
50 GST_STATIC_CAPS ("application/x-rtp, "
51 "media = (string) \"video\", "
52 "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
53 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\";"
55 "media = (string) \"video\", "
56 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
57 "clock-rate = (int) 90000")
60 GST_BOILERPLATE (GstRtpJPEGDepay, gst_rtp_jpeg_depay, GstBaseRTPDepayload,
61 GST_TYPE_BASE_RTP_DEPAYLOAD);
63 static void gst_rtp_jpeg_depay_finalize (GObject * object);
65 static gboolean gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload,
67 static GstBuffer *gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload,
71 gst_rtp_jpeg_depay_base_init (gpointer klass)
73 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
75 gst_element_class_add_pad_template (element_class,
76 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
77 gst_element_class_add_pad_template (element_class,
78 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
80 gst_element_class_set_details (element_class, &gst_rtp_jpegdepay_details);
84 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
86 GObjectClass *gobject_class;
87 GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
89 gobject_class = (GObjectClass *) klass;
90 gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
92 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
94 parent_class = g_type_class_peek_parent (klass);
96 gstbasertpdepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
97 gstbasertpdepayload_class->process = gst_rtp_jpeg_depay_process;
99 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
100 "JPEG Video RTP Depayloader");
104 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay,
105 GstRtpJPEGDepayClass * klass)
107 rtpjpegdepay->adapter = gst_adapter_new ();
111 gst_rtp_jpeg_depay_finalize (GObject * object)
113 GstRtpJPEGDepay *rtpjpegdepay;
115 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
117 g_object_unref (rtpjpegdepay->adapter);
118 rtpjpegdepay->adapter = NULL;
120 G_OBJECT_CLASS (parent_class)->finalize (object);
124 * Table K.1 from JPEG spec.
126 static const int jpeg_luma_quantizer[64] = {
127 16, 11, 10, 16, 24, 40, 51, 61,
128 12, 12, 14, 19, 26, 58, 60, 55,
129 14, 13, 16, 24, 40, 57, 69, 56,
130 14, 17, 22, 29, 51, 87, 80, 62,
131 18, 22, 37, 56, 68, 109, 103, 77,
132 24, 35, 55, 64, 81, 104, 113, 92,
133 49, 64, 78, 87, 103, 121, 120, 101,
134 72, 92, 95, 98, 112, 100, 103, 99
138 * Table K.2 from JPEG spec.
140 static const int jpeg_chroma_quantizer[64] = {
141 17, 18, 24, 47, 99, 99, 99, 99,
142 18, 21, 26, 66, 99, 99, 99, 99,
143 24, 26, 56, 99, 99, 99, 99, 99,
144 47, 66, 99, 99, 99, 99, 99, 99,
145 99, 99, 99, 99, 99, 99, 99, 99,
146 99, 99, 99, 99, 99, 99, 99, 99,
147 99, 99, 99, 99, 99, 99, 99, 99,
148 99, 99, 99, 99, 99, 99, 99, 99
151 /* Call MakeTables with the Q factor and a guint8[128] return array
154 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
159 factor = CLAMP (Q, 1, 99);
164 Q = 200 - factor * 2;
166 for (i = 0; i < 64; i++) {
167 gint lq = (jpeg_luma_quantizer[i] * Q + 50) / 100;
168 gint cq = (jpeg_chroma_quantizer[i] * Q + 50) / 100;
170 /* Limit the quantizers to 1 <= q <= 255 */
171 qtable[i] = CLAMP (lq, 1, 255);
172 qtable[i + 64] = CLAMP (cq, 1, 255);
176 static const guint8 lum_dc_codelens[] = {
177 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
180 static const guint8 lum_dc_symbols[] = {
181 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
184 static const guint8 lum_ac_codelens[] = {
185 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
188 static const guint8 lum_ac_symbols[] = {
189 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
190 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
191 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
192 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
193 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
194 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
195 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
196 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
197 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
198 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
199 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
200 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
201 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
202 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
203 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
204 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
205 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
206 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
207 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
208 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
212 static const guint8 chm_dc_codelens[] = {
213 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
216 static const guint8 chm_dc_symbols[] = {
217 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
220 static const guint8 chm_ac_codelens[] = {
221 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
224 static const guint8 chm_ac_symbols[] = {
225 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
226 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
227 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
228 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
229 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
230 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
231 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
232 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
233 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
234 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
235 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
236 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
237 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
238 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
239 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
240 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
241 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
242 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
243 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
244 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
249 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
252 *p++ = 0xdb; /* DQT */
253 *p++ = 0; /* length msb */
254 *p++ = size + 3; /* length lsb */
256 memcpy (p, qt, size);
262 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
263 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
266 *p++ = 0xc4; /* DHT */
267 *p++ = 0; /* length msb */
268 *p++ = 3 + ncodes + nsymbols; /* length lsb */
269 *p++ = (tableClass << 4) | tableNo;
270 memcpy (p, codelens, ncodes);
272 memcpy (p, symbols, nsymbols);
279 MakeDRIHeader (guint8 * p, guint16 dri)
282 *p++ = 0xdd; /* DRI */
283 *p++ = 0x0; /* length msb */
284 *p++ = 4; /* length lsb */
285 *p++ = dri >> 8; /* dri msb */
286 *p++ = dri & 0xff; /* dri lsb */
293 * type, width, height: as supplied in RTP/JPEG header
294 * qt: quantization tables as either derived from
295 * the Q field using MakeTables() or as specified
297 * dri: restart interval in MCUs, or 0 if no restarts.
299 * p: pointer to return area
302 * The length of the generated headers.
304 * Generate a frame and scan headers that can be prepended to the
305 * RTP/JPEG data payload to produce a JPEG compressed image in
306 * interchange format (except for possible trailing garbage and
307 * absence of an EOI marker to terminate the scan).
310 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
311 guint precision, guint16 dri)
317 *p++ = 0xd8; /* SOI */
319 size = ((precision & 1) ? 128 : 64);
320 p = MakeQuantHeader (p, qt, size, 0);
323 size = ((precision & 2) ? 128 : 64);
324 p = MakeQuantHeader (p, qt, size, 1);
328 p = MakeDRIHeader (p, dri);
331 *p++ = 0xc0; /* SOF */
332 *p++ = 0; /* length msb */
333 *p++ = 17; /* length lsb */
334 *p++ = 8; /* 8-bit precision */
335 *p++ = height >> 8; /* height msb */
336 *p++ = height; /* height lsb */
337 *p++ = width >> 8; /* width msb */
338 *p++ = width; /* width lsb */
339 *p++ = 3; /* number of components */
340 *p++ = 0; /* comp 0 */
341 if ((type & 0x3f) == 0)
342 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
344 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
345 *p++ = 0; /* quant table 0 */
346 *p++ = 1; /* comp 1 */
347 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
348 *p++ = 1; /* quant table 1 */
349 *p++ = 2; /* comp 2 */
350 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
351 *p++ = 1; /* quant table 1 */
353 p = MakeHuffmanHeader (p, lum_dc_codelens,
354 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
355 p = MakeHuffmanHeader (p, lum_ac_codelens,
356 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
357 p = MakeHuffmanHeader (p, chm_dc_codelens,
358 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
359 p = MakeHuffmanHeader (p, chm_ac_codelens,
360 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
363 *p++ = 0xda; /* SOS */
364 *p++ = 0; /* length msb */
365 *p++ = 12; /* length lsb */
366 *p++ = 3; /* 3 components */
367 *p++ = 0; /* comp 0 */
368 *p++ = 0; /* huffman table 0 */
369 *p++ = 1; /* comp 1 */
370 *p++ = 0x11; /* huffman table 1 */
371 *p++ = 2; /* comp 2 */
372 *p++ = 0x11; /* huffman table 1 */
373 *p++ = 0; /* first DCT coeff */
374 *p++ = 63; /* last DCT coeff */
375 *p++ = 0; /* sucessive approx. */
381 gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
383 GstRtpJPEGDepay *rtpjpegdepay;
384 GstStructure *structure;
387 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
389 structure = gst_caps_get_structure (caps, 0);
391 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
393 depayload->clock_rate = clock_rate;
395 rtpjpegdepay->width = 0;
396 rtpjpegdepay->height = 0;
402 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
404 GstRtpJPEGDepay *rtpjpegdepay;
406 gint payload_len, header_len;
410 guint type, width, height;
411 guint16 dri, precision, length;
414 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
416 if (GST_BUFFER_IS_DISCONT (buf)) {
417 gst_adapter_clear (rtpjpegdepay->adapter);
420 payload_len = gst_rtp_buffer_get_payload_len (buf);
425 payload = gst_rtp_buffer_get_payload (buf);
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 * | Type-specific | Fragment Offset |
432 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433 * | Type | Q | Width | Height |
434 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
436 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
439 width = payload[6] * 8;
440 height = payload[7] * 8;
442 if (width == 0 || height == 0)
443 goto invalid_dimension;
445 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
446 frag_offset, type, Q, width, height);
458 * 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
459 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
460 * | Restart Interval |F|L| Restart Count |
461 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
463 dri = (payload[0] << 8) | payload[1];
465 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
472 if (Q >= 128 && frag_offset == 0) {
477 * 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
478 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
479 * | MBZ | Precision | Length |
480 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
481 * | Quantization Table Data |
483 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
485 precision = payload[1];
486 length = (payload[2] << 8) | payload[3];
488 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
491 if (Q == 255 && length == 0)
498 if (length > payload_len)
504 qtable = rtpjpegdepay->qtables[Q];
507 header_len += length;
508 payload_len -= length;
515 if (frag_offset == 0) {
518 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
522 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION, 0,
523 1, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
524 gst_pad_set_caps (depayload->srcpad, outcaps);
525 gst_caps_unref (outcaps);
527 rtpjpegdepay->width = width;
528 rtpjpegdepay->height = height;
531 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
537 /* no quant table, see if we have one cached */
538 qtable = rtpjpegdepay->qtables[Q];
540 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
541 /* make and cache the table */
542 qtable = g_new (guint8, 128);
543 MakeTables (rtpjpegdepay, Q, qtable);
544 rtpjpegdepay->qtables[Q] = qtable;
546 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
548 /* all 8 bit quantizers */
555 /* max header length, should be big enough */
556 outbuf = gst_buffer_new_and_alloc (1000);
557 size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
558 width, height, qtable, precision, dri);
560 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
562 GST_BUFFER_SIZE (outbuf) = size;
564 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
567 /* take JPEG data, push in the adapter */
568 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
569 outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
570 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
573 if (gst_rtp_buffer_get_marker (buf)) {
578 /* last buffer take all data out of the adapter */
579 avail = gst_adapter_available (rtpjpegdepay->adapter);
580 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
582 /* take the last bytes of the jpeg data to see if there is an EOI
584 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
586 if (end[0] != 0xff && end[1] != 0xd9) {
587 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
589 /* no EOI marker, add one */
590 outbuf = gst_buffer_new_and_alloc (2);
591 data = GST_BUFFER_DATA (outbuf);
595 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
598 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
600 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
608 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
609 ("Empty Payload."), (NULL));
614 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
615 ("Invalid Dimension %dx%d.", width, height), (NULL));
620 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
626 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
628 return gst_element_register (plugin, "rtpjpegdepay",
629 GST_RANK_MARGINAL, GST_TYPE_RTP_JPEG_DEPAY);