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>
25 #include <gst/video/video.h>
31 #include "gstrtpjpegdepay.h"
32 #include "gstrtputils.h"
34 GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
35 #define GST_CAT_DEFAULT (rtpjpegdepay_debug)
37 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
38 GST_STATIC_PAD_TEMPLATE ("src",
41 GST_STATIC_CAPS ("image/jpeg")
44 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
45 GST_STATIC_PAD_TEMPLATE ("sink",
48 GST_STATIC_CAPS ("application/x-rtp, "
49 "media = (string) \"video\", "
50 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
51 /* optional SDP attributes */
53 * "a-framerate = (string) 0.00, "
54 * "x-framerate = (string) 0.00, "
55 * "x-dimensions = (string) \"1234,1234\", "
58 "media = (string) \"video\", "
59 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
60 "clock-rate = (int) 90000"
61 /* optional SDP attributes */
63 * "a-framerate = (string) 0.00, "
64 * "x-framerate = (string) 0.00, "
65 * "x-dimensions = (string) \"1234,1234\""
70 #define gst_rtp_jpeg_depay_parent_class parent_class
71 G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
72 GST_TYPE_RTP_BASE_DEPAYLOAD);
74 static void gst_rtp_jpeg_depay_finalize (GObject * object);
76 static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
77 element, GstStateChange transition);
79 static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
81 static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
85 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
87 GObjectClass *gobject_class;
88 GstElementClass *gstelement_class;
89 GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
91 gobject_class = (GObjectClass *) klass;
92 gstelement_class = (GstElementClass *) klass;
93 gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
95 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
97 gst_element_class_add_pad_template (gstelement_class,
98 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
99 gst_element_class_add_pad_template (gstelement_class,
100 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
102 gst_element_class_set_static_metadata (gstelement_class,
103 "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
104 "Extracts JPEG video from RTP packets (RFC 2435)",
105 "Wim Taymans <wim.taymans@gmail.com>");
107 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
109 gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
110 gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_jpeg_depay_process;
112 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
113 "JPEG Video RTP Depayloader");
117 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
119 rtpjpegdepay->adapter = gst_adapter_new ();
123 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
129 depay->media_width = 0;
130 depay->media_height = 0;
131 depay->frate_num = 0;
132 depay->frate_denom = 1;
133 depay->discont = TRUE;
135 for (i = 0; i < 255; i++) {
136 g_free (depay->qtables[i]);
137 depay->qtables[i] = NULL;
140 gst_adapter_clear (depay->adapter);
144 gst_rtp_jpeg_depay_finalize (GObject * object)
146 GstRtpJPEGDepay *rtpjpegdepay;
148 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
150 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
152 g_object_unref (rtpjpegdepay->adapter);
153 rtpjpegdepay->adapter = NULL;
155 G_OBJECT_CLASS (parent_class)->finalize (object);
158 static const int zigzag[] = {
159 0, 1, 8, 16, 9, 2, 3, 10,
160 17, 24, 32, 25, 18, 11, 4, 5,
161 12, 19, 26, 33, 40, 48, 41, 34,
162 27, 20, 13, 6, 7, 14, 21, 28,
163 35, 42, 49, 56, 57, 50, 43, 36,
164 29, 22, 15, 23, 30, 37, 44, 51,
165 58, 59, 52, 45, 38, 31, 39, 46,
166 53, 60, 61, 54, 47, 55, 62, 63
170 * Table K.1 from JPEG spec.
172 static const int jpeg_luma_quantizer[64] = {
173 16, 11, 10, 16, 24, 40, 51, 61,
174 12, 12, 14, 19, 26, 58, 60, 55,
175 14, 13, 16, 24, 40, 57, 69, 56,
176 14, 17, 22, 29, 51, 87, 80, 62,
177 18, 22, 37, 56, 68, 109, 103, 77,
178 24, 35, 55, 64, 81, 104, 113, 92,
179 49, 64, 78, 87, 103, 121, 120, 101,
180 72, 92, 95, 98, 112, 100, 103, 99
184 * Table K.2 from JPEG spec.
186 static const int jpeg_chroma_quantizer[64] = {
187 17, 18, 24, 47, 99, 99, 99, 99,
188 18, 21, 26, 66, 99, 99, 99, 99,
189 24, 26, 56, 99, 99, 99, 99, 99,
190 47, 66, 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,
194 99, 99, 99, 99, 99, 99, 99, 99
197 /* Call MakeTables with the Q factor and a guint8[128] return array
200 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
205 factor = CLAMP (Q, 1, 99);
210 Q = 200 - factor * 2;
212 for (i = 0; i < 64; i++) {
213 gint lq = (jpeg_luma_quantizer[zigzag[i]] * Q + 50) / 100;
214 gint cq = (jpeg_chroma_quantizer[zigzag[i]] * Q + 50) / 100;
216 /* Limit the quantizers to 1 <= q <= 255 */
217 qtable[i] = CLAMP (lq, 1, 255);
218 qtable[i + 64] = CLAMP (cq, 1, 255);
222 static const guint8 lum_dc_codelens[] = {
223 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
226 static const guint8 lum_dc_symbols[] = {
227 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
230 static const guint8 lum_ac_codelens[] = {
231 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
234 static const guint8 lum_ac_symbols[] = {
235 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
236 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
237 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
238 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
239 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
240 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
241 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
242 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
243 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
244 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
245 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
246 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
247 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
248 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
249 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
250 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
251 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
252 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
253 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
254 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
258 static const guint8 chm_dc_codelens[] = {
259 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
262 static const guint8 chm_dc_symbols[] = {
263 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
266 static const guint8 chm_ac_codelens[] = {
267 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
270 static const guint8 chm_ac_symbols[] = {
271 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
272 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
273 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
274 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
275 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
276 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
277 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
278 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
279 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
280 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
281 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
282 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
283 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
284 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
285 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
286 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
287 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
288 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
289 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
290 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
295 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
298 *p++ = 0xdb; /* DQT */
299 *p++ = 0; /* length msb */
300 *p++ = size + 3; /* length lsb */
302 memcpy (p, qt, size);
308 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
309 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
312 *p++ = 0xc4; /* DHT */
313 *p++ = 0; /* length msb */
314 *p++ = 3 + ncodes + nsymbols; /* length lsb */
315 *p++ = (tableClass << 4) | tableNo;
316 memcpy (p, codelens, ncodes);
318 memcpy (p, symbols, nsymbols);
325 MakeDRIHeader (guint8 * p, guint16 dri)
328 *p++ = 0xdd; /* DRI */
329 *p++ = 0x0; /* length msb */
330 *p++ = 4; /* length lsb */
331 *p++ = dri >> 8; /* dri msb */
332 *p++ = dri & 0xff; /* dri lsb */
339 * type, width, height: as supplied in RTP/JPEG header
340 * qt: quantization tables as either derived from
341 * the Q field using MakeTables() or as specified
343 * dri: restart interval in MCUs, or 0 if no restarts.
345 * p: pointer to return area
348 * The length of the generated headers.
350 * Generate a frame and scan headers that can be prepended to the
351 * RTP/JPEG data payload to produce a JPEG compressed image in
352 * interchange format (except for possible trailing garbage and
353 * absence of an EOI marker to terminate the scan).
356 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
357 guint precision, guint16 dri)
363 *p++ = 0xd8; /* SOI */
365 size = ((precision & 1) ? 128 : 64);
366 p = MakeQuantHeader (p, qt, size, 0);
369 size = ((precision & 2) ? 128 : 64);
370 p = MakeQuantHeader (p, qt, size, 1);
374 p = MakeDRIHeader (p, dri);
377 *p++ = 0xc0; /* SOF */
378 *p++ = 0; /* length msb */
379 *p++ = 17; /* length lsb */
380 *p++ = 8; /* 8-bit precision */
381 *p++ = height >> 8; /* height msb */
382 *p++ = height; /* height lsb */
383 *p++ = width >> 8; /* width msb */
384 *p++ = width; /* width lsb */
385 *p++ = 3; /* number of components */
386 *p++ = 0; /* comp 0 */
387 if ((type & 0x3f) == 0)
388 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
390 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
391 *p++ = 0; /* quant table 0 */
392 *p++ = 1; /* comp 1 */
393 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
394 *p++ = 1; /* quant table 1 */
395 *p++ = 2; /* comp 2 */
396 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
397 *p++ = 1; /* quant table 1 */
399 p = MakeHuffmanHeader (p, lum_dc_codelens,
400 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
401 p = MakeHuffmanHeader (p, lum_ac_codelens,
402 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
403 p = MakeHuffmanHeader (p, chm_dc_codelens,
404 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
405 p = MakeHuffmanHeader (p, chm_ac_codelens,
406 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
409 *p++ = 0xda; /* SOS */
410 *p++ = 0; /* length msb */
411 *p++ = 12; /* length lsb */
412 *p++ = 3; /* 3 components */
413 *p++ = 0; /* comp 0 */
414 *p++ = 0; /* huffman table 0 */
415 *p++ = 1; /* comp 1 */
416 *p++ = 0x11; /* huffman table 1 */
417 *p++ = 2; /* comp 2 */
418 *p++ = 0x11; /* huffman table 1 */
419 *p++ = 0; /* first DCT coeff */
420 *p++ = 63; /* last DCT coeff */
421 *p++ = 0; /* sucessive approx. */
427 gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
429 GstRtpJPEGDepay *rtpjpegdepay;
430 GstStructure *structure;
432 const gchar *media_attr;
434 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
436 structure = gst_caps_get_structure (caps, 0);
437 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
439 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
441 depayload->clock_rate = clock_rate;
444 rtpjpegdepay->width = 0;
445 rtpjpegdepay->height = 0;
446 rtpjpegdepay->media_width = 0;
447 rtpjpegdepay->media_height = 0;
448 rtpjpegdepay->frate_num = 0;
449 rtpjpegdepay->frate_denom = 1;
451 /* check for optional SDP attributes */
452 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
455 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
456 rtpjpegdepay->media_width = w;
457 rtpjpegdepay->media_height = h;
461 /* try to get a framerate */
462 media_attr = gst_structure_get_string (structure, "a-framerate");
464 media_attr = gst_structure_get_string (structure, "x-framerate");
471 /* canonicalise floating point string so we can handle framerate strings
472 * in the form "24.930" or "24,930" irrespective of the current locale */
473 s = g_strdup (media_attr);
474 g_strdelimit (s, ",", '.');
476 /* convert the float to a fraction */
477 g_value_init (&src, G_TYPE_DOUBLE);
478 g_value_set_double (&src, g_ascii_strtod (s, NULL));
479 g_value_init (&dest, GST_TYPE_FRACTION);
480 g_value_transform (&src, &dest);
482 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
483 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
492 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
494 GstRtpJPEGDepay *rtpjpegdepay;
496 gint payload_len, header_len;
500 guint type, width, height;
501 guint16 dri, precision, length;
504 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
506 if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
507 GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter");
508 gst_adapter_clear (rtpjpegdepay->adapter);
509 rtpjpegdepay->discont = TRUE;
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 */
658 /* I think we can get here with a NULL qtable, so make sure we don't
659 go dereferencing it in MakeHeaders if we do */
663 /* max header length, should be big enough */
664 outbuf = gst_buffer_new_and_alloc (1000);
665 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
666 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
667 gst_buffer_unmap (outbuf, &map);
668 gst_buffer_resize (outbuf, 0, size);
670 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
672 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
675 /* take JPEG data, push in the adapter */
676 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
677 outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1);
678 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
681 if (gst_rtp_buffer_get_marker (rtp)) {
686 /* last buffer take all data out of the adapter */
687 avail = gst_adapter_available (rtpjpegdepay->adapter);
688 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
693 /* take the last bytes of the jpeg data to see if there is an EOI
695 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
697 if (end[0] != 0xff && end[1] != 0xd9) {
698 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
700 /* no EOI marker, add one */
701 outbuf = gst_buffer_new_and_alloc (2);
702 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
705 gst_buffer_unmap (outbuf, &map);
707 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
710 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
712 if (rtpjpegdepay->discont) {
713 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
714 rtpjpegdepay->discont = FALSE;
717 gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpjpegdepay), outbuf,
718 g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
720 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
728 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
729 ("Empty Payload."), (NULL));
734 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
735 ("Invalid Dimension %dx%d.", width, height), (NULL));
740 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
745 GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
746 gst_adapter_flush (rtpjpegdepay->adapter,
747 gst_adapter_available (rtpjpegdepay->adapter));
753 static GstStateChangeReturn
754 gst_rtp_jpeg_depay_change_state (GstElement * element,
755 GstStateChange transition)
757 GstRtpJPEGDepay *rtpjpegdepay;
758 GstStateChangeReturn ret;
760 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
762 switch (transition) {
763 case GST_STATE_CHANGE_READY_TO_PAUSED:
764 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
770 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
772 switch (transition) {
773 case GST_STATE_CHANGE_PAUSED_TO_READY:
783 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
785 return gst_element_register (plugin, "rtpjpegdepay",
786 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);