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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, 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")
40 /* optional SDP attributes */
43 * "height = (int) 0, "
47 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
48 GST_STATIC_PAD_TEMPLATE ("sink",
51 GST_STATIC_CAPS ("application/x-rtp, "
52 "media = (string) \"video\", "
53 "clock-rate = (int) 90000, "
54 "encoding-name = (string) \"JPEG\"; "
55 /* optional SDP attributes */
58 * "height = (int) 0, "
59 * "a-framerate = (string) 0.00, "
60 * "x-framerate = (string) 0.00, "
61 * "x-dimensions = (string) "0\,0", "
64 "media = (string) \"video\", "
65 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
66 "clock-rate = (int) 90000"
67 /* optional SDP attributes */
70 * "height = (int) 0, "
71 * "a-framerate = (string) 0.00, "
72 * "x-framerate = (string) 0.00, "
73 * "x-dimensions = (string) "0\,0", "
78 #define gst_rtp_jpeg_depay_parent_class parent_class
79 G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
80 GST_TYPE_RTP_BASE_DEPAYLOAD);
82 static void gst_rtp_jpeg_depay_finalize (GObject * object);
84 static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
85 element, GstStateChange transition);
87 static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
89 static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
93 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
95 GObjectClass *gobject_class;
96 GstElementClass *gstelement_class;
97 GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
99 gobject_class = (GObjectClass *) klass;
100 gstelement_class = (GstElementClass *) klass;
101 gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
103 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
105 gst_element_class_add_pad_template (gstelement_class,
106 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
107 gst_element_class_add_pad_template (gstelement_class,
108 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
110 gst_element_class_set_static_metadata (gstelement_class,
111 "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
112 "Extracts JPEG video from RTP packets (RFC 2435)",
113 "Wim Taymans <wim.taymans@gmail.com>");
115 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
117 gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
118 gstrtpbasedepayload_class->process = gst_rtp_jpeg_depay_process;
120 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
121 "JPEG Video RTP Depayloader");
125 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
127 rtpjpegdepay->adapter = gst_adapter_new ();
131 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
137 depay->media_width = 0;
138 depay->media_height = 0;
139 depay->frate_num = 0;
140 depay->frate_denom = 1;
141 depay->discont = TRUE;
143 for (i = 0; i < 255; i++) {
144 g_free (depay->qtables[i]);
145 depay->qtables[i] = NULL;
148 gst_adapter_clear (depay->adapter);
152 gst_rtp_jpeg_depay_finalize (GObject * object)
154 GstRtpJPEGDepay *rtpjpegdepay;
156 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
158 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
160 g_object_unref (rtpjpegdepay->adapter);
161 rtpjpegdepay->adapter = NULL;
163 G_OBJECT_CLASS (parent_class)->finalize (object);
166 static const int zigzag[] = {
167 0, 1, 8, 16, 9, 2, 3, 10,
168 17, 24, 32, 25, 18, 11, 4, 5,
169 12, 19, 26, 33, 40, 48, 41, 34,
170 27, 20, 13, 6, 7, 14, 21, 28,
171 35, 42, 49, 56, 57, 50, 43, 36,
172 29, 22, 15, 23, 30, 37, 44, 51,
173 58, 59, 52, 45, 38, 31, 39, 46,
174 53, 60, 61, 54, 47, 55, 62, 63
178 * Table K.1 from JPEG spec.
180 static const int jpeg_luma_quantizer[64] = {
181 16, 11, 10, 16, 24, 40, 51, 61,
182 12, 12, 14, 19, 26, 58, 60, 55,
183 14, 13, 16, 24, 40, 57, 69, 56,
184 14, 17, 22, 29, 51, 87, 80, 62,
185 18, 22, 37, 56, 68, 109, 103, 77,
186 24, 35, 55, 64, 81, 104, 113, 92,
187 49, 64, 78, 87, 103, 121, 120, 101,
188 72, 92, 95, 98, 112, 100, 103, 99
192 * Table K.2 from JPEG spec.
194 static const int jpeg_chroma_quantizer[64] = {
195 17, 18, 24, 47, 99, 99, 99, 99,
196 18, 21, 26, 66, 99, 99, 99, 99,
197 24, 26, 56, 99, 99, 99, 99, 99,
198 47, 66, 99, 99, 99, 99, 99, 99,
199 99, 99, 99, 99, 99, 99, 99, 99,
200 99, 99, 99, 99, 99, 99, 99, 99,
201 99, 99, 99, 99, 99, 99, 99, 99,
202 99, 99, 99, 99, 99, 99, 99, 99
205 /* Call MakeTables with the Q factor and a guint8[128] return array
208 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
213 factor = CLAMP (Q, 1, 99);
218 Q = 200 - factor * 2;
220 for (i = 0; i < 64; i++) {
221 gint lq = (jpeg_luma_quantizer[zigzag[i]] * Q + 50) / 100;
222 gint cq = (jpeg_chroma_quantizer[zigzag[i]] * Q + 50) / 100;
224 /* Limit the quantizers to 1 <= q <= 255 */
225 qtable[i] = CLAMP (lq, 1, 255);
226 qtable[i + 64] = CLAMP (cq, 1, 255);
230 static const guint8 lum_dc_codelens[] = {
231 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
234 static const guint8 lum_dc_symbols[] = {
235 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
238 static const guint8 lum_ac_codelens[] = {
239 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
242 static const guint8 lum_ac_symbols[] = {
243 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
244 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
245 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
246 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
247 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
248 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
249 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
250 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
251 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
252 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
253 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
254 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
255 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
256 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
257 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
258 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
259 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
260 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
261 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
262 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
266 static const guint8 chm_dc_codelens[] = {
267 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
270 static const guint8 chm_dc_symbols[] = {
271 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
274 static const guint8 chm_ac_codelens[] = {
275 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
278 static const guint8 chm_ac_symbols[] = {
279 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
280 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
281 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
282 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
283 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
284 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
285 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
286 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
287 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
288 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
289 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
290 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
291 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
292 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
293 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
294 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
295 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
296 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
297 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
298 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
303 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
306 *p++ = 0xdb; /* DQT */
307 *p++ = 0; /* length msb */
308 *p++ = size + 3; /* length lsb */
310 memcpy (p, qt, size);
316 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
317 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
320 *p++ = 0xc4; /* DHT */
321 *p++ = 0; /* length msb */
322 *p++ = 3 + ncodes + nsymbols; /* length lsb */
323 *p++ = (tableClass << 4) | tableNo;
324 memcpy (p, codelens, ncodes);
326 memcpy (p, symbols, nsymbols);
333 MakeDRIHeader (guint8 * p, guint16 dri)
336 *p++ = 0xdd; /* DRI */
337 *p++ = 0x0; /* length msb */
338 *p++ = 4; /* length lsb */
339 *p++ = dri >> 8; /* dri msb */
340 *p++ = dri & 0xff; /* dri lsb */
347 * type, width, height: as supplied in RTP/JPEG header
348 * qt: quantization tables as either derived from
349 * the Q field using MakeTables() or as specified
351 * dri: restart interval in MCUs, or 0 if no restarts.
353 * p: pointer to return area
356 * The length of the generated headers.
358 * Generate a frame and scan headers that can be prepended to the
359 * RTP/JPEG data payload to produce a JPEG compressed image in
360 * interchange format (except for possible trailing garbage and
361 * absence of an EOI marker to terminate the scan).
364 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
365 guint precision, guint16 dri)
371 *p++ = 0xd8; /* SOI */
373 size = ((precision & 1) ? 128 : 64);
374 p = MakeQuantHeader (p, qt, size, 0);
377 size = ((precision & 2) ? 128 : 64);
378 p = MakeQuantHeader (p, qt, size, 1);
382 p = MakeDRIHeader (p, dri);
385 *p++ = 0xc0; /* SOF */
386 *p++ = 0; /* length msb */
387 *p++ = 17; /* length lsb */
388 *p++ = 8; /* 8-bit precision */
389 *p++ = height >> 8; /* height msb */
390 *p++ = height; /* height lsb */
391 *p++ = width >> 8; /* width msb */
392 *p++ = width; /* width lsb */
393 *p++ = 3; /* number of components */
394 *p++ = 0; /* comp 0 */
395 if ((type & 0x3f) == 0)
396 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
398 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
399 *p++ = 0; /* quant table 0 */
400 *p++ = 1; /* comp 1 */
401 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
402 *p++ = 1; /* quant table 1 */
403 *p++ = 2; /* comp 2 */
404 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
405 *p++ = 1; /* quant table 1 */
407 p = MakeHuffmanHeader (p, lum_dc_codelens,
408 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
409 p = MakeHuffmanHeader (p, lum_ac_codelens,
410 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
411 p = MakeHuffmanHeader (p, chm_dc_codelens,
412 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
413 p = MakeHuffmanHeader (p, chm_ac_codelens,
414 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
417 *p++ = 0xda; /* SOS */
418 *p++ = 0; /* length msb */
419 *p++ = 12; /* length lsb */
420 *p++ = 3; /* 3 components */
421 *p++ = 0; /* comp 0 */
422 *p++ = 0; /* huffman table 0 */
423 *p++ = 1; /* comp 1 */
424 *p++ = 0x11; /* huffman table 1 */
425 *p++ = 2; /* comp 2 */
426 *p++ = 0x11; /* huffman table 1 */
427 *p++ = 0; /* first DCT coeff */
428 *p++ = 63; /* last DCT coeff */
429 *p++ = 0; /* sucessive approx. */
435 gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
437 GstRtpJPEGDepay *rtpjpegdepay;
438 GstStructure *structure;
440 const gchar *media_attr;
441 gint width = 0, height = 0;
443 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
445 structure = gst_caps_get_structure (caps, 0);
446 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
448 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
450 depayload->clock_rate = clock_rate;
453 rtpjpegdepay->width = 0;
454 rtpjpegdepay->height = 0;
455 rtpjpegdepay->media_width = 0;
456 rtpjpegdepay->media_height = 0;
457 rtpjpegdepay->frate_num = 0;
458 rtpjpegdepay->frate_denom = 1;
460 /* check for optional SDP attributes */
461 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
462 if (sscanf (media_attr, "%d,%d", &width, &height) != 2 || width <= 0 ||
464 goto invalid_dimension;
468 if (gst_structure_get_int (structure, "width", &width) && width <= 0) {
469 goto invalid_dimension;
471 if (gst_structure_get_int (structure, "height", &height) && height <= 0) {
472 goto invalid_dimension;
475 /* try to get a framerate */
476 media_attr = gst_structure_get_string (structure, "a-framerate");
478 media_attr = gst_structure_get_string (structure, "x-framerate");
485 /* canonicalise floating point string so we can handle framerate strings
486 * in the form "24.930" or "24,930" irrespective of the current locale */
487 s = g_strdup (media_attr);
488 g_strdelimit (s, ",", '.');
490 /* convert the float to a fraction */
491 g_value_init (&src, G_TYPE_DOUBLE);
492 g_value_set_double (&src, g_ascii_strtod (s, NULL));
493 g_value_init (&dest, GST_TYPE_FRACTION);
494 g_value_transform (&src, &dest);
496 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
497 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
502 rtpjpegdepay->media_width = width;
503 rtpjpegdepay->media_height = height;
509 GST_ERROR_OBJECT (rtpjpegdepay, "invalid width/height from caps");
515 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
517 GstRtpJPEGDepay *rtpjpegdepay;
519 gint payload_len, header_len;
523 guint type, width, height;
524 guint16 dri, precision, length;
526 GstRTPBuffer rtp = { NULL };
528 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
530 if (GST_BUFFER_IS_DISCONT (buf)) {
531 gst_adapter_clear (rtpjpegdepay->adapter);
532 rtpjpegdepay->discont = TRUE;
535 gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
536 payload_len = gst_rtp_buffer_get_payload_len (&rtp);
541 payload = gst_rtp_buffer_get_payload (&rtp);
545 * 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
546 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
547 * | Type-specific | Fragment Offset |
548 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
549 * | Type | Q | Width | Height |
550 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
552 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
555 width = payload[6] * 8;
556 height = payload[7] * 8;
558 /* allow frame dimensions > 2040, passed in SDP session or media attributes
559 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
561 width = rtpjpegdepay->media_width;
564 height = rtpjpegdepay->media_height;
566 if (width == 0 || height == 0)
567 goto invalid_dimension;
569 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
570 frag_offset, type, Q, width, height);
582 * 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
583 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
584 * | Restart Interval |F|L| Restart Count |
585 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
587 dri = (payload[0] << 8) | payload[1];
589 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
596 if (Q >= 128 && frag_offset == 0) {
601 * 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
602 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
603 * | MBZ | Precision | Length |
604 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
605 * | Quantization Table Data |
607 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
609 precision = payload[1];
610 length = (payload[2] << 8) | payload[3];
612 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
615 if (Q == 255 && length == 0)
622 if (length > payload_len)
628 qtable = rtpjpegdepay->qtables[Q];
631 header_len += length;
632 payload_len -= length;
639 if (frag_offset == 0) {
643 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
647 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
648 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, NULL);
650 if (width > 0 && height > 0) {
651 gst_caps_set_simple (outcaps, "width", G_TYPE_INT, width, "height",
652 G_TYPE_INT, height, NULL);
655 gst_pad_set_caps (depayload->srcpad, outcaps);
656 gst_caps_unref (outcaps);
658 rtpjpegdepay->width = width;
659 rtpjpegdepay->height = height;
662 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
668 /* no quant table, see if we have one cached */
669 qtable = rtpjpegdepay->qtables[Q];
671 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
672 /* make and cache the table */
673 qtable = g_new (guint8, 128);
674 MakeTables (rtpjpegdepay, Q, qtable);
675 rtpjpegdepay->qtables[Q] = qtable;
677 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
679 /* all 8 bit quantizers */
686 /* max header length, should be big enough */
687 outbuf = gst_buffer_new_and_alloc (1000);
688 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
689 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
690 gst_buffer_unmap (outbuf, &map);
691 gst_buffer_resize (outbuf, 0, size);
693 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
695 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
698 /* take JPEG data, push in the adapter */
699 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
700 outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, -1);
701 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
704 if (gst_rtp_buffer_get_marker (&rtp)) {
709 /* last buffer take all data out of the adapter */
710 avail = gst_adapter_available (rtpjpegdepay->adapter);
711 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
716 /* take the last bytes of the jpeg data to see if there is an EOI
718 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
720 if (end[0] != 0xff && end[1] != 0xd9) {
721 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
723 /* no EOI marker, add one */
724 outbuf = gst_buffer_new_and_alloc (2);
725 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
728 gst_buffer_unmap (outbuf, &map);
730 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
733 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
735 if (rtpjpegdepay->discont) {
736 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
737 rtpjpegdepay->discont = FALSE;
740 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
743 gst_rtp_buffer_unmap (&rtp);
750 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
751 ("Empty Payload."), (NULL));
752 gst_rtp_buffer_unmap (&rtp);
757 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
758 ("Invalid Dimension %dx%d.", width, height), (NULL));
759 gst_rtp_buffer_unmap (&rtp);
764 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
765 gst_rtp_buffer_unmap (&rtp);
770 GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
771 gst_adapter_flush (rtpjpegdepay->adapter,
772 gst_adapter_available (rtpjpegdepay->adapter));
773 gst_rtp_buffer_unmap (&rtp);
779 static GstStateChangeReturn
780 gst_rtp_jpeg_depay_change_state (GstElement * element,
781 GstStateChange transition)
783 GstRtpJPEGDepay *rtpjpegdepay;
784 GstStateChangeReturn ret;
786 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
788 switch (transition) {
789 case GST_STATE_CHANGE_READY_TO_PAUSED:
790 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
796 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
798 switch (transition) {
799 case GST_STATE_CHANGE_PAUSED_TO_READY:
809 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
811 return gst_element_register (plugin, "rtpjpegdepay",
812 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);