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 */
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 GstStructure *structure;
388 structure = gst_caps_get_structure (caps, 0);
390 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
392 depayload->clock_rate = clock_rate;
395 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION, 0, 1,
397 res = gst_pad_set_caps (depayload->srcpad, outcaps);
398 gst_caps_unref (outcaps);
404 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
406 GstRtpJPEGDepay *rtpjpegdepay;
408 gint payload_len, header_len;
412 guint type, width, height;
413 guint16 dri, precision, length;
416 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
418 if (GST_BUFFER_IS_DISCONT (buf)) {
419 gst_adapter_clear (rtpjpegdepay->adapter);
422 payload_len = gst_rtp_buffer_get_payload_len (buf);
427 payload = gst_rtp_buffer_get_payload (buf);
431 * 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
432 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433 * | Type-specific | Fragment Offset |
434 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435 * | Type | Q | Width | Height |
436 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
438 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
441 width = payload[6] * 8;
442 height = payload[7] * 8;
444 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
445 frag_offset, type, Q, width, height);
457 * 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
458 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
459 * | Restart Interval |F|L| Restart Count |
460 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
462 dri = (payload[0] << 8) | payload[1];
464 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
471 if (Q >= 128 && frag_offset == 0) {
476 * 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
477 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
478 * | MBZ | Precision | Length |
479 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
480 * | Quantization Table Data |
482 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
484 precision = payload[1];
485 length = (payload[2] << 8) | payload[3];
487 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
490 if (Q == 255 && length == 0)
497 if (length > payload_len)
503 header_len += length;
504 payload_len -= length;
511 if (frag_offset == 0) {
517 /* no quant table, see if we have one cached */
518 qtable = rtpjpegdepay->qtables[Q];
520 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
521 /* make and cache the table */
522 qtable = g_new (guint8, 128);
523 MakeTables (rtpjpegdepay, Q, qtable);
524 rtpjpegdepay->qtables[Q] = qtable;
526 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
528 /* all 8 bit quantizers */
532 /* max header length, should be big enough */
533 outbuf = gst_buffer_new_and_alloc (1000);
534 size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
535 width, height, qtable, precision, dri);
537 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes header", size);
539 GST_BUFFER_SIZE (outbuf) = size;
541 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
544 /* take JPEG data, push in the adapter */
545 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
546 outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
547 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
550 if (gst_rtp_buffer_get_marker (buf)) {
555 /* last buffer take all data out of the adapter */
556 avail = gst_adapter_available (rtpjpegdepay->adapter);
557 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
559 /* take the last bytes of the jpeg data to see if there is an EOI
561 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
563 if (end[0] != 0xff && end[1] != 0xd9) {
564 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
566 /* no EOI marker, add one */
567 outbuf = gst_buffer_new_and_alloc (2);
568 data = GST_BUFFER_DATA (outbuf);
572 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
575 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
577 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
585 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
586 ("Empty Payload."), (NULL));
592 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
594 return gst_element_register (plugin, "rtpjpegdepay",
595 GST_RANK_MARGINAL, GST_TYPE_RTP_JPEG_DEPAY);