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>
30 #include "gstrtpjpegdepay.h"
32 GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
33 #define GST_CAT_DEFAULT (rtpjpegdepay_debug)
35 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
36 GST_STATIC_PAD_TEMPLATE ("src",
39 GST_STATIC_CAPS ("image/jpeg")
42 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
43 GST_STATIC_PAD_TEMPLATE ("sink",
46 GST_STATIC_CAPS ("application/x-rtp, "
47 "media = (string) \"video\", "
48 "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
49 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
50 /* optional SDP attributes */
52 * "a-framerate = (string) 0.00, "
53 * "x-framerate = (string) 0.00, "
54 * "x-dimensions = (string) \"1234,1234\", "
57 "media = (string) \"video\", "
58 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
59 "clock-rate = (int) 90000"
60 /* optional SDP attributes */
62 * "a-framerate = (string) 0.00, "
63 * "x-framerate = (string) 0.00, "
64 * "x-dimensions = (string) \"1234,1234\""
69 #define gst_rtp_jpeg_depay_parent_class parent_class
70 G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
71 GST_TYPE_RTP_BASE_DEPAYLOAD);
73 static void gst_rtp_jpeg_depay_finalize (GObject * object);
75 static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
76 element, GstStateChange transition);
78 static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
80 static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
84 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
86 GObjectClass *gobject_class;
87 GstElementClass *gstelement_class;
88 GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
90 gobject_class = (GObjectClass *) klass;
91 gstelement_class = (GstElementClass *) klass;
92 gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
94 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
96 gst_element_class_add_pad_template (gstelement_class,
97 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
98 gst_element_class_add_pad_template (gstelement_class,
99 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
101 gst_element_class_set_static_metadata (gstelement_class,
102 "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
103 "Extracts JPEG video from RTP packets (RFC 2435)",
104 "Wim Taymans <wim.taymans@gmail.com>");
106 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
108 gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
109 gstrtpbasedepayload_class->process = gst_rtp_jpeg_depay_process;
111 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
112 "JPEG Video RTP Depayloader");
116 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
118 rtpjpegdepay->adapter = gst_adapter_new ();
122 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
128 depay->media_width = 0;
129 depay->media_height = 0;
130 depay->frate_num = 0;
131 depay->frate_denom = 1;
132 depay->discont = TRUE;
134 for (i = 0; i < 255; i++) {
135 g_free (depay->qtables[i]);
136 depay->qtables[i] = NULL;
139 gst_adapter_clear (depay->adapter);
143 gst_rtp_jpeg_depay_finalize (GObject * object)
145 GstRtpJPEGDepay *rtpjpegdepay;
147 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
149 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
151 g_object_unref (rtpjpegdepay->adapter);
152 rtpjpegdepay->adapter = NULL;
154 G_OBJECT_CLASS (parent_class)->finalize (object);
157 static const int zigzag[] = {
158 0, 1, 8, 16, 9, 2, 3, 10,
159 17, 24, 32, 25, 18, 11, 4, 5,
160 12, 19, 26, 33, 40, 48, 41, 34,
161 27, 20, 13, 6, 7, 14, 21, 28,
162 35, 42, 49, 56, 57, 50, 43, 36,
163 29, 22, 15, 23, 30, 37, 44, 51,
164 58, 59, 52, 45, 38, 31, 39, 46,
165 53, 60, 61, 54, 47, 55, 62, 63
169 * Table K.1 from JPEG spec.
171 static const int jpeg_luma_quantizer[64] = {
172 16, 11, 10, 16, 24, 40, 51, 61,
173 12, 12, 14, 19, 26, 58, 60, 55,
174 14, 13, 16, 24, 40, 57, 69, 56,
175 14, 17, 22, 29, 51, 87, 80, 62,
176 18, 22, 37, 56, 68, 109, 103, 77,
177 24, 35, 55, 64, 81, 104, 113, 92,
178 49, 64, 78, 87, 103, 121, 120, 101,
179 72, 92, 95, 98, 112, 100, 103, 99
183 * Table K.2 from JPEG spec.
185 static const int jpeg_chroma_quantizer[64] = {
186 17, 18, 24, 47, 99, 99, 99, 99,
187 18, 21, 26, 66, 99, 99, 99, 99,
188 24, 26, 56, 99, 99, 99, 99, 99,
189 47, 66, 99, 99, 99, 99, 99, 99,
190 99, 99, 99, 99, 99, 99, 99, 99,
191 99, 99, 99, 99, 99, 99, 99, 99,
192 99, 99, 99, 99, 99, 99, 99, 99,
193 99, 99, 99, 99, 99, 99, 99, 99
196 /* Call MakeTables with the Q factor and a guint8[128] return array
199 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
204 factor = CLAMP (Q, 1, 99);
209 Q = 200 - factor * 2;
211 for (i = 0; i < 64; i++) {
212 gint lq = (jpeg_luma_quantizer[zigzag[i]] * Q + 50) / 100;
213 gint cq = (jpeg_chroma_quantizer[zigzag[i]] * Q + 50) / 100;
215 /* Limit the quantizers to 1 <= q <= 255 */
216 qtable[i] = CLAMP (lq, 1, 255);
217 qtable[i + 64] = CLAMP (cq, 1, 255);
221 static const guint8 lum_dc_codelens[] = {
222 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
225 static const guint8 lum_dc_symbols[] = {
226 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
229 static const guint8 lum_ac_codelens[] = {
230 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
233 static const guint8 lum_ac_symbols[] = {
234 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
235 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
236 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
237 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
238 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
239 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
240 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
241 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
242 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
243 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
244 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
245 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
246 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
247 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
248 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
249 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
250 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
251 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
252 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
253 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
257 static const guint8 chm_dc_codelens[] = {
258 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
261 static const guint8 chm_dc_symbols[] = {
262 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
265 static const guint8 chm_ac_codelens[] = {
266 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
269 static const guint8 chm_ac_symbols[] = {
270 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
271 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
272 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
273 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
274 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
275 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
276 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
277 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
278 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
279 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
280 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
281 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
282 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
283 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
284 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
285 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
286 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
287 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
288 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
289 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
294 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
297 *p++ = 0xdb; /* DQT */
298 *p++ = 0; /* length msb */
299 *p++ = size + 3; /* length lsb */
301 memcpy (p, qt, size);
307 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
308 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
311 *p++ = 0xc4; /* DHT */
312 *p++ = 0; /* length msb */
313 *p++ = 3 + ncodes + nsymbols; /* length lsb */
314 *p++ = (tableClass << 4) | tableNo;
315 memcpy (p, codelens, ncodes);
317 memcpy (p, symbols, nsymbols);
324 MakeDRIHeader (guint8 * p, guint16 dri)
327 *p++ = 0xdd; /* DRI */
328 *p++ = 0x0; /* length msb */
329 *p++ = 4; /* length lsb */
330 *p++ = dri >> 8; /* dri msb */
331 *p++ = dri & 0xff; /* dri lsb */
338 * type, width, height: as supplied in RTP/JPEG header
339 * qt: quantization tables as either derived from
340 * the Q field using MakeTables() or as specified
342 * dri: restart interval in MCUs, or 0 if no restarts.
344 * p: pointer to return area
347 * The length of the generated headers.
349 * Generate a frame and scan headers that can be prepended to the
350 * RTP/JPEG data payload to produce a JPEG compressed image in
351 * interchange format (except for possible trailing garbage and
352 * absence of an EOI marker to terminate the scan).
355 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
356 guint precision, guint16 dri)
362 *p++ = 0xd8; /* SOI */
364 size = ((precision & 1) ? 128 : 64);
365 p = MakeQuantHeader (p, qt, size, 0);
368 size = ((precision & 2) ? 128 : 64);
369 p = MakeQuantHeader (p, qt, size, 1);
373 p = MakeDRIHeader (p, dri);
376 *p++ = 0xc0; /* SOF */
377 *p++ = 0; /* length msb */
378 *p++ = 17; /* length lsb */
379 *p++ = 8; /* 8-bit precision */
380 *p++ = height >> 8; /* height msb */
381 *p++ = height; /* height lsb */
382 *p++ = width >> 8; /* width msb */
383 *p++ = width; /* width lsb */
384 *p++ = 3; /* number of components */
385 *p++ = 0; /* comp 0 */
386 if ((type & 0x3f) == 0)
387 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
389 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
390 *p++ = 0; /* quant table 0 */
391 *p++ = 1; /* comp 1 */
392 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
393 *p++ = 1; /* quant table 1 */
394 *p++ = 2; /* comp 2 */
395 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
396 *p++ = 1; /* quant table 1 */
398 p = MakeHuffmanHeader (p, lum_dc_codelens,
399 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
400 p = MakeHuffmanHeader (p, lum_ac_codelens,
401 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
402 p = MakeHuffmanHeader (p, chm_dc_codelens,
403 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
404 p = MakeHuffmanHeader (p, chm_ac_codelens,
405 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
408 *p++ = 0xda; /* SOS */
409 *p++ = 0; /* length msb */
410 *p++ = 12; /* length lsb */
411 *p++ = 3; /* 3 components */
412 *p++ = 0; /* comp 0 */
413 *p++ = 0; /* huffman table 0 */
414 *p++ = 1; /* comp 1 */
415 *p++ = 0x11; /* huffman table 1 */
416 *p++ = 2; /* comp 2 */
417 *p++ = 0x11; /* huffman table 1 */
418 *p++ = 0; /* first DCT coeff */
419 *p++ = 63; /* last DCT coeff */
420 *p++ = 0; /* sucessive approx. */
426 gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
428 GstRtpJPEGDepay *rtpjpegdepay;
429 GstStructure *structure;
431 const gchar *media_attr;
433 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
435 structure = gst_caps_get_structure (caps, 0);
436 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
438 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
440 depayload->clock_rate = clock_rate;
443 rtpjpegdepay->width = 0;
444 rtpjpegdepay->height = 0;
445 rtpjpegdepay->media_width = 0;
446 rtpjpegdepay->media_height = 0;
447 rtpjpegdepay->frate_num = 0;
448 rtpjpegdepay->frate_denom = 1;
450 /* check for optional SDP attributes */
451 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
454 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
455 rtpjpegdepay->media_width = w;
456 rtpjpegdepay->media_height = h;
460 /* try to get a framerate */
461 media_attr = gst_structure_get_string (structure, "a-framerate");
463 media_attr = gst_structure_get_string (structure, "x-framerate");
470 /* canonicalise floating point string so we can handle framerate strings
471 * in the form "24.930" or "24,930" irrespective of the current locale */
472 s = g_strdup (media_attr);
473 g_strdelimit (s, ",", '.');
475 /* convert the float to a fraction */
476 g_value_init (&src, G_TYPE_DOUBLE);
477 g_value_set_double (&src, g_ascii_strtod (s, NULL));
478 g_value_init (&dest, GST_TYPE_FRACTION);
479 g_value_transform (&src, &dest);
481 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
482 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
491 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
493 GstRtpJPEGDepay *rtpjpegdepay;
495 gint payload_len, header_len;
499 guint type, width, height;
500 guint16 dri, precision, length;
502 GstRTPBuffer rtp = { NULL };
504 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
506 if (GST_BUFFER_IS_DISCONT (buf)) {
507 gst_adapter_clear (rtpjpegdepay->adapter);
508 rtpjpegdepay->discont = TRUE;
511 gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
512 payload_len = gst_rtp_buffer_get_payload_len (&rtp);
517 payload = gst_rtp_buffer_get_payload (&rtp);
521 * 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
522 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523 * | Type-specific | Fragment Offset |
524 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525 * | Type | Q | Width | Height |
526 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
528 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
531 width = payload[6] * 8;
532 height = payload[7] * 8;
534 /* allow frame dimensions > 2040, passed in SDP session or media attributes
535 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
537 width = rtpjpegdepay->media_width;
540 height = rtpjpegdepay->media_height;
542 if (width == 0 || height == 0)
543 goto invalid_dimension;
545 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
546 frag_offset, type, Q, width, height);
558 * 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
559 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
560 * | Restart Interval |F|L| Restart Count |
561 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
563 dri = (payload[0] << 8) | payload[1];
565 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
572 if (Q >= 128 && frag_offset == 0) {
577 * 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
578 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
579 * | MBZ | Precision | Length |
580 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
581 * | Quantization Table Data |
583 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585 precision = payload[1];
586 length = (payload[2] << 8) | payload[3];
588 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
591 if (Q == 255 && length == 0)
598 if (length > payload_len)
604 qtable = rtpjpegdepay->qtables[Q];
607 header_len += length;
608 payload_len -= length;
615 if (frag_offset == 0) {
619 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
623 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
624 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
625 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
626 gst_pad_set_caps (depayload->srcpad, outcaps);
627 gst_caps_unref (outcaps);
629 rtpjpegdepay->width = width;
630 rtpjpegdepay->height = height;
633 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
639 /* no quant table, see if we have one cached */
640 qtable = rtpjpegdepay->qtables[Q];
642 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
643 /* make and cache the table */
644 qtable = g_new (guint8, 128);
645 MakeTables (rtpjpegdepay, Q, qtable);
646 rtpjpegdepay->qtables[Q] = qtable;
648 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
650 /* all 8 bit quantizers */
657 /* max header length, should be big enough */
658 outbuf = gst_buffer_new_and_alloc (1000);
659 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
660 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
661 gst_buffer_unmap (outbuf, &map);
662 gst_buffer_resize (outbuf, 0, size);
664 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
666 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
669 /* take JPEG data, push in the adapter */
670 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
671 outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, -1);
672 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
675 if (gst_rtp_buffer_get_marker (&rtp)) {
680 /* last buffer take all data out of the adapter */
681 avail = gst_adapter_available (rtpjpegdepay->adapter);
682 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
684 /* take the last bytes of the jpeg data to see if there is an EOI
686 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
688 if (end[0] != 0xff && end[1] != 0xd9) {
689 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
691 /* no EOI marker, add one */
692 outbuf = gst_buffer_new_and_alloc (2);
693 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
696 gst_buffer_unmap (outbuf, &map);
698 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
701 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
703 if (rtpjpegdepay->discont) {
704 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
705 rtpjpegdepay->discont = FALSE;
708 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
711 gst_rtp_buffer_unmap (&rtp);
718 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
719 ("Empty Payload."), (NULL));
720 gst_rtp_buffer_unmap (&rtp);
725 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
726 ("Invalid Dimension %dx%d.", width, height), (NULL));
727 gst_rtp_buffer_unmap (&rtp);
732 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
733 gst_rtp_buffer_unmap (&rtp);
739 static GstStateChangeReturn
740 gst_rtp_jpeg_depay_change_state (GstElement * element,
741 GstStateChange transition)
743 GstRtpJPEGDepay *rtpjpegdepay;
744 GstStateChangeReturn ret;
746 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
748 switch (transition) {
749 case GST_STATE_CHANGE_READY_TO_PAUSED:
750 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
756 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
758 switch (transition) {
759 case GST_STATE_CHANGE_PAUSED_TO_READY:
769 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
771 return gst_element_register (plugin, "rtpjpegdepay",
772 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);