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")
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 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
49 /* optional SDP attributes */
51 * "a-framerate = (string) 0.00, "
52 * "x-framerate = (string) 0.00, "
53 * "x-dimensions = (string) \"1234,1234\", "
56 "media = (string) \"video\", "
57 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
58 "clock-rate = (int) 90000"
59 /* optional SDP attributes */
61 * "a-framerate = (string) 0.00, "
62 * "x-framerate = (string) 0.00, "
63 * "x-dimensions = (string) \"1234,1234\""
68 #define gst_rtp_jpeg_depay_parent_class parent_class
69 G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
70 GST_TYPE_RTP_BASE_DEPAYLOAD);
72 static void gst_rtp_jpeg_depay_finalize (GObject * object);
74 static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
75 element, GstStateChange transition);
77 static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
79 static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
83 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
85 GObjectClass *gobject_class;
86 GstElementClass *gstelement_class;
87 GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
89 gobject_class = (GObjectClass *) klass;
90 gstelement_class = (GstElementClass *) klass;
91 gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
93 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
95 gst_element_class_add_pad_template (gstelement_class,
96 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
97 gst_element_class_add_pad_template (gstelement_class,
98 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
100 gst_element_class_set_static_metadata (gstelement_class,
101 "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
102 "Extracts JPEG video from RTP packets (RFC 2435)",
103 "Wim Taymans <wim.taymans@gmail.com>");
105 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
107 gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
108 gstrtpbasedepayload_class->process = gst_rtp_jpeg_depay_process;
110 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
111 "JPEG Video RTP Depayloader");
115 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
117 rtpjpegdepay->adapter = gst_adapter_new ();
121 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
127 depay->media_width = 0;
128 depay->media_height = 0;
129 depay->frate_num = 0;
130 depay->frate_denom = 1;
131 depay->discont = TRUE;
133 for (i = 0; i < 255; i++) {
134 g_free (depay->qtables[i]);
135 depay->qtables[i] = NULL;
138 gst_adapter_clear (depay->adapter);
142 gst_rtp_jpeg_depay_finalize (GObject * object)
144 GstRtpJPEGDepay *rtpjpegdepay;
146 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
148 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
150 g_object_unref (rtpjpegdepay->adapter);
151 rtpjpegdepay->adapter = NULL;
153 G_OBJECT_CLASS (parent_class)->finalize (object);
156 static const int zigzag[] = {
157 0, 1, 8, 16, 9, 2, 3, 10,
158 17, 24, 32, 25, 18, 11, 4, 5,
159 12, 19, 26, 33, 40, 48, 41, 34,
160 27, 20, 13, 6, 7, 14, 21, 28,
161 35, 42, 49, 56, 57, 50, 43, 36,
162 29, 22, 15, 23, 30, 37, 44, 51,
163 58, 59, 52, 45, 38, 31, 39, 46,
164 53, 60, 61, 54, 47, 55, 62, 63
168 * Table K.1 from JPEG spec.
170 static const int jpeg_luma_quantizer[64] = {
171 16, 11, 10, 16, 24, 40, 51, 61,
172 12, 12, 14, 19, 26, 58, 60, 55,
173 14, 13, 16, 24, 40, 57, 69, 56,
174 14, 17, 22, 29, 51, 87, 80, 62,
175 18, 22, 37, 56, 68, 109, 103, 77,
176 24, 35, 55, 64, 81, 104, 113, 92,
177 49, 64, 78, 87, 103, 121, 120, 101,
178 72, 92, 95, 98, 112, 100, 103, 99
182 * Table K.2 from JPEG spec.
184 static const int jpeg_chroma_quantizer[64] = {
185 17, 18, 24, 47, 99, 99, 99, 99,
186 18, 21, 26, 66, 99, 99, 99, 99,
187 24, 26, 56, 99, 99, 99, 99, 99,
188 47, 66, 99, 99, 99, 99, 99, 99,
189 99, 99, 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
195 /* Call MakeTables with the Q factor and a guint8[128] return array
198 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
203 factor = CLAMP (Q, 1, 99);
208 Q = 200 - factor * 2;
210 for (i = 0; i < 64; i++) {
211 gint lq = (jpeg_luma_quantizer[zigzag[i]] * Q + 50) / 100;
212 gint cq = (jpeg_chroma_quantizer[zigzag[i]] * Q + 50) / 100;
214 /* Limit the quantizers to 1 <= q <= 255 */
215 qtable[i] = CLAMP (lq, 1, 255);
216 qtable[i + 64] = CLAMP (cq, 1, 255);
220 static const guint8 lum_dc_codelens[] = {
221 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
224 static const guint8 lum_dc_symbols[] = {
225 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
228 static const guint8 lum_ac_codelens[] = {
229 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
232 static const guint8 lum_ac_symbols[] = {
233 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
234 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
235 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
236 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
237 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
238 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
239 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
240 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
241 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
242 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
243 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
244 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
245 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
246 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
247 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
248 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
249 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
250 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
251 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
252 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
256 static const guint8 chm_dc_codelens[] = {
257 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
260 static const guint8 chm_dc_symbols[] = {
261 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
264 static const guint8 chm_ac_codelens[] = {
265 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
268 static const guint8 chm_ac_symbols[] = {
269 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
270 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
271 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
272 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
273 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
274 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
275 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
276 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
277 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
278 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
279 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
280 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
281 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
282 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
283 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
284 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
285 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
286 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
287 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
288 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
293 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
296 *p++ = 0xdb; /* DQT */
297 *p++ = 0; /* length msb */
298 *p++ = size + 3; /* length lsb */
300 memcpy (p, qt, size);
306 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
307 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
310 *p++ = 0xc4; /* DHT */
311 *p++ = 0; /* length msb */
312 *p++ = 3 + ncodes + nsymbols; /* length lsb */
313 *p++ = (tableClass << 4) | tableNo;
314 memcpy (p, codelens, ncodes);
316 memcpy (p, symbols, nsymbols);
323 MakeDRIHeader (guint8 * p, guint16 dri)
326 *p++ = 0xdd; /* DRI */
327 *p++ = 0x0; /* length msb */
328 *p++ = 4; /* length lsb */
329 *p++ = dri >> 8; /* dri msb */
330 *p++ = dri & 0xff; /* dri lsb */
337 * type, width, height: as supplied in RTP/JPEG header
338 * qt: quantization tables as either derived from
339 * the Q field using MakeTables() or as specified
341 * dri: restart interval in MCUs, or 0 if no restarts.
343 * p: pointer to return area
346 * The length of the generated headers.
348 * Generate a frame and scan headers that can be prepended to the
349 * RTP/JPEG data payload to produce a JPEG compressed image in
350 * interchange format (except for possible trailing garbage and
351 * absence of an EOI marker to terminate the scan).
354 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
355 guint precision, guint16 dri)
361 *p++ = 0xd8; /* SOI */
363 size = ((precision & 1) ? 128 : 64);
364 p = MakeQuantHeader (p, qt, size, 0);
367 size = ((precision & 2) ? 128 : 64);
368 p = MakeQuantHeader (p, qt, size, 1);
372 p = MakeDRIHeader (p, dri);
375 *p++ = 0xc0; /* SOF */
376 *p++ = 0; /* length msb */
377 *p++ = 17; /* length lsb */
378 *p++ = 8; /* 8-bit precision */
379 *p++ = height >> 8; /* height msb */
380 *p++ = height; /* height lsb */
381 *p++ = width >> 8; /* width msb */
382 *p++ = width; /* width lsb */
383 *p++ = 3; /* number of components */
384 *p++ = 0; /* comp 0 */
385 if ((type & 0x3f) == 0)
386 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
388 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
389 *p++ = 0; /* quant table 0 */
390 *p++ = 1; /* comp 1 */
391 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
392 *p++ = 1; /* quant table 1 */
393 *p++ = 2; /* comp 2 */
394 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
395 *p++ = 1; /* quant table 1 */
397 p = MakeHuffmanHeader (p, lum_dc_codelens,
398 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
399 p = MakeHuffmanHeader (p, lum_ac_codelens,
400 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
401 p = MakeHuffmanHeader (p, chm_dc_codelens,
402 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
403 p = MakeHuffmanHeader (p, chm_ac_codelens,
404 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
407 *p++ = 0xda; /* SOS */
408 *p++ = 0; /* length msb */
409 *p++ = 12; /* length lsb */
410 *p++ = 3; /* 3 components */
411 *p++ = 0; /* comp 0 */
412 *p++ = 0; /* huffman table 0 */
413 *p++ = 1; /* comp 1 */
414 *p++ = 0x11; /* huffman table 1 */
415 *p++ = 2; /* comp 2 */
416 *p++ = 0x11; /* huffman table 1 */
417 *p++ = 0; /* first DCT coeff */
418 *p++ = 63; /* last DCT coeff */
419 *p++ = 0; /* sucessive approx. */
425 gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
427 GstRtpJPEGDepay *rtpjpegdepay;
428 GstStructure *structure;
430 const gchar *media_attr;
432 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
434 structure = gst_caps_get_structure (caps, 0);
435 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
437 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
439 depayload->clock_rate = clock_rate;
442 rtpjpegdepay->width = 0;
443 rtpjpegdepay->height = 0;
444 rtpjpegdepay->media_width = 0;
445 rtpjpegdepay->media_height = 0;
446 rtpjpegdepay->frate_num = 0;
447 rtpjpegdepay->frate_denom = 1;
449 /* check for optional SDP attributes */
450 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
453 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
454 rtpjpegdepay->media_width = w;
455 rtpjpegdepay->media_height = h;
459 /* try to get a framerate */
460 media_attr = gst_structure_get_string (structure, "a-framerate");
462 media_attr = gst_structure_get_string (structure, "x-framerate");
469 /* canonicalise floating point string so we can handle framerate strings
470 * in the form "24.930" or "24,930" irrespective of the current locale */
471 s = g_strdup (media_attr);
472 g_strdelimit (s, ",", '.');
474 /* convert the float to a fraction */
475 g_value_init (&src, G_TYPE_DOUBLE);
476 g_value_set_double (&src, g_ascii_strtod (s, NULL));
477 g_value_init (&dest, GST_TYPE_FRACTION);
478 g_value_transform (&src, &dest);
480 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
481 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
490 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
492 GstRtpJPEGDepay *rtpjpegdepay;
494 gint payload_len, header_len;
498 guint type, width, height;
499 guint16 dri, precision, length;
501 GstRTPBuffer rtp = { NULL };
503 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
505 if (GST_BUFFER_IS_DISCONT (buf)) {
506 gst_adapter_clear (rtpjpegdepay->adapter);
507 rtpjpegdepay->discont = TRUE;
510 gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
511 payload_len = gst_rtp_buffer_get_payload_len (&rtp);
516 payload = gst_rtp_buffer_get_payload (&rtp);
520 * 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
521 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
522 * | Type-specific | Fragment Offset |
523 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
524 * | Type | Q | Width | Height |
525 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
527 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
530 width = payload[6] * 8;
531 height = payload[7] * 8;
533 /* allow frame dimensions > 2040, passed in SDP session or media attributes
534 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
536 width = rtpjpegdepay->media_width;
539 height = rtpjpegdepay->media_height;
541 if (width == 0 || height == 0)
542 goto invalid_dimension;
544 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
545 frag_offset, type, Q, width, height);
557 * 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
558 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
559 * | Restart Interval |F|L| Restart Count |
560 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
562 dri = (payload[0] << 8) | payload[1];
564 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
571 if (Q >= 128 && frag_offset == 0) {
576 * 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
577 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
578 * | MBZ | Precision | Length |
579 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
580 * | Quantization Table Data |
582 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
584 precision = payload[1];
585 length = (payload[2] << 8) | payload[3];
587 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
590 if (Q == 255 && length == 0)
597 if (length > payload_len)
603 qtable = rtpjpegdepay->qtables[Q];
606 header_len += length;
607 payload_len -= length;
614 if (frag_offset == 0) {
618 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
622 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
623 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
624 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
625 gst_pad_set_caps (depayload->srcpad, outcaps);
626 gst_caps_unref (outcaps);
628 rtpjpegdepay->width = width;
629 rtpjpegdepay->height = height;
632 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
638 /* no quant table, see if we have one cached */
639 qtable = rtpjpegdepay->qtables[Q];
641 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
642 /* make and cache the table */
643 qtable = g_new (guint8, 128);
644 MakeTables (rtpjpegdepay, Q, qtable);
645 rtpjpegdepay->qtables[Q] = qtable;
647 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
649 /* all 8 bit quantizers */
656 /* max header length, should be big enough */
657 outbuf = gst_buffer_new_and_alloc (1000);
658 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
659 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
660 gst_buffer_unmap (outbuf, &map);
661 gst_buffer_resize (outbuf, 0, size);
663 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
665 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
668 /* take JPEG data, push in the adapter */
669 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
670 outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, -1);
671 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
674 if (gst_rtp_buffer_get_marker (&rtp)) {
679 /* last buffer take all data out of the adapter */
680 avail = gst_adapter_available (rtpjpegdepay->adapter);
681 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
683 /* take the last bytes of the jpeg data to see if there is an EOI
685 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
687 if (end[0] != 0xff && end[1] != 0xd9) {
688 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
690 /* no EOI marker, add one */
691 outbuf = gst_buffer_new_and_alloc (2);
692 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
695 gst_buffer_unmap (outbuf, &map);
697 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
700 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
702 if (rtpjpegdepay->discont) {
703 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
704 rtpjpegdepay->discont = FALSE;
707 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
710 gst_rtp_buffer_unmap (&rtp);
717 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
718 ("Empty Payload."), (NULL));
719 gst_rtp_buffer_unmap (&rtp);
724 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
725 ("Invalid Dimension %dx%d.", width, height), (NULL));
726 gst_rtp_buffer_unmap (&rtp);
731 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
732 gst_rtp_buffer_unmap (&rtp);
738 static GstStateChangeReturn
739 gst_rtp_jpeg_depay_change_state (GstElement * element,
740 GstStateChange transition)
742 GstRtpJPEGDepay *rtpjpegdepay;
743 GstStateChangeReturn ret;
745 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
747 switch (transition) {
748 case GST_STATE_CHANGE_READY_TO_PAUSED:
749 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
755 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
757 switch (transition) {
758 case GST_STATE_CHANGE_PAUSED_TO_READY:
768 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
770 return gst_element_register (plugin, "rtpjpegdepay",
771 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);