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_static_pad_template (gstelement_class,
98 &gst_rtp_jpeg_depay_src_template);
99 gst_element_class_add_static_pad_template (gstelement_class,
100 &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; /* successive 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 /* saw a packet with fragment offset > 0 and we don't already have data queued
535 * up (most importantly, we don't have a header for this data) -- drop it
536 * XXX: maybe we can check if the jpeg is progressive and salvage the data?
537 * XXX: not implemented yet because jpegenc can't create progressive jpegs */
538 if (frag_offset > 0 && gst_adapter_available (rtpjpegdepay->adapter) == 0)
539 goto no_header_packet;
541 /* allow frame dimensions > 2040, passed in SDP session or media attributes
542 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
544 width = rtpjpegdepay->media_width;
547 height = rtpjpegdepay->media_height;
549 if (width == 0 || height == 0)
550 goto invalid_dimension;
552 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
553 frag_offset, type, Q, width, height);
565 * 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
566 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
567 * | Restart Interval |F|L| Restart Count |
568 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570 dri = (payload[0] << 8) | payload[1];
572 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
579 if (Q >= 128 && frag_offset == 0) {
584 * 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
585 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
586 * | MBZ | Precision | Length |
587 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588 * | Quantization Table Data |
590 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
592 precision = payload[1];
593 length = (payload[2] << 8) | payload[3];
595 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
598 if (Q == 255 && length == 0)
605 if (length > payload_len)
611 qtable = rtpjpegdepay->qtables[Q];
614 header_len += length;
615 payload_len -= length;
622 if (frag_offset == 0) {
626 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
630 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
631 "framerate", GST_TYPE_FRACTION, rtpjpegdepay->frate_num,
632 rtpjpegdepay->frate_denom, "width", G_TYPE_INT, width,
633 "height", G_TYPE_INT, height, NULL);
634 gst_pad_set_caps (depayload->srcpad, outcaps);
635 gst_caps_unref (outcaps);
637 rtpjpegdepay->width = width;
638 rtpjpegdepay->height = height;
641 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
647 /* no quant table, see if we have one cached */
648 qtable = rtpjpegdepay->qtables[Q];
650 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
651 /* make and cache the table */
652 qtable = g_new (guint8, 128);
653 MakeTables (rtpjpegdepay, Q, qtable);
654 rtpjpegdepay->qtables[Q] = qtable;
656 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
658 /* all 8 bit quantizers */
666 /* I think we can get here with a NULL qtable, so make sure we don't
667 go dereferencing it in MakeHeaders if we do */
671 /* max header length, should be big enough */
672 outbuf = gst_buffer_new_and_alloc (1000);
673 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
674 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
675 gst_buffer_unmap (outbuf, &map);
676 gst_buffer_resize (outbuf, 0, size);
678 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
680 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
683 /* take JPEG data, push in the adapter */
684 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
685 outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1);
686 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
689 if (gst_rtp_buffer_get_marker (rtp)) {
694 /* last buffer take all data out of the adapter */
695 avail = gst_adapter_available (rtpjpegdepay->adapter);
696 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
701 /* take the last bytes of the jpeg data to see if there is an EOI
703 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
705 if (end[0] != 0xff && end[1] != 0xd9) {
706 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
708 /* no EOI marker, add one */
709 outbuf = gst_buffer_new_and_alloc (2);
710 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
713 gst_buffer_unmap (outbuf, &map);
715 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
718 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
720 if (rtpjpegdepay->discont) {
721 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
722 rtpjpegdepay->discont = FALSE;
725 gst_rtp_drop_non_video_meta (rtpjpegdepay, outbuf);
727 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
735 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
736 ("Empty Payload."), (NULL));
741 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
742 ("Invalid Dimension %dx%d.", width, height), (NULL));
747 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
752 GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
753 gst_adapter_flush (rtpjpegdepay->adapter,
754 gst_adapter_available (rtpjpegdepay->adapter));
759 GST_WARNING_OBJECT (rtpjpegdepay,
760 "discarding data packets received when we have no header");
766 static GstStateChangeReturn
767 gst_rtp_jpeg_depay_change_state (GstElement * element,
768 GstStateChange transition)
770 GstRtpJPEGDepay *rtpjpegdepay;
771 GstStateChangeReturn ret;
773 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
775 switch (transition) {
776 case GST_STATE_CHANGE_READY_TO_PAUSED:
777 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
783 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
785 switch (transition) {
786 case GST_STATE_CHANGE_PAUSED_TO_READY:
796 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
798 return gst_element_register (plugin, "rtpjpegdepay",
799 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);