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 "gstrtpelements.h"
32 #include "gstrtpjpegdepay.h"
33 #include "gstrtputils.h"
35 GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
36 #define GST_CAT_DEFAULT (rtpjpegdepay_debug)
38 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
39 GST_STATIC_PAD_TEMPLATE ("src",
42 GST_STATIC_CAPS ("image/jpeg")
45 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
46 GST_STATIC_PAD_TEMPLATE ("sink",
49 GST_STATIC_CAPS ("application/x-rtp, "
50 "media = (string) \"video\", "
51 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
52 /* optional SDP attributes */
54 * "a-framerate = (string) 0.00, "
55 * "x-framerate = (string) 0.00, "
56 * "x-dimensions = (string) \"1234,1234\", "
59 "media = (string) \"video\", "
60 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
61 "clock-rate = (int) 90000"
62 /* optional SDP attributes */
64 * "a-framerate = (string) 0.00, "
65 * "x-framerate = (string) 0.00, "
66 * "x-dimensions = (string) \"1234,1234\""
71 #define gst_rtp_jpeg_depay_parent_class parent_class
72 G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
73 GST_TYPE_RTP_BASE_DEPAYLOAD);
74 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (rtpjpegdepay, "rtpjpegdepay",
75 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY, rtp_element_init (plugin));
77 static void gst_rtp_jpeg_depay_finalize (GObject * object);
79 static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
80 element, GstStateChange transition);
82 static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
84 static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
88 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
90 GObjectClass *gobject_class;
91 GstElementClass *gstelement_class;
92 GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
94 gobject_class = (GObjectClass *) klass;
95 gstelement_class = (GstElementClass *) klass;
96 gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
98 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
100 gst_element_class_add_static_pad_template (gstelement_class,
101 &gst_rtp_jpeg_depay_src_template);
102 gst_element_class_add_static_pad_template (gstelement_class,
103 &gst_rtp_jpeg_depay_sink_template);
105 gst_element_class_set_static_metadata (gstelement_class,
106 "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
107 "Extracts JPEG video from RTP packets (RFC 2435)",
108 "Wim Taymans <wim.taymans@gmail.com>");
110 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
112 gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
113 gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_jpeg_depay_process;
115 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
116 "JPEG Video RTP Depayloader");
120 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
122 rtpjpegdepay->adapter = gst_adapter_new ();
126 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
132 depay->media_width = 0;
133 depay->media_height = 0;
134 depay->frate_num = 0;
135 depay->frate_denom = 1;
136 depay->discont = TRUE;
138 for (i = 0; i < 255; i++) {
139 g_free (depay->qtables[i]);
140 depay->qtables[i] = NULL;
143 gst_adapter_clear (depay->adapter);
147 gst_rtp_jpeg_depay_finalize (GObject * object)
149 GstRtpJPEGDepay *rtpjpegdepay;
151 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
153 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
155 g_object_unref (rtpjpegdepay->adapter);
156 rtpjpegdepay->adapter = NULL;
158 G_OBJECT_CLASS (parent_class)->finalize (object);
161 static const int zigzag[] = {
162 0, 1, 8, 16, 9, 2, 3, 10,
163 17, 24, 32, 25, 18, 11, 4, 5,
164 12, 19, 26, 33, 40, 48, 41, 34,
165 27, 20, 13, 6, 7, 14, 21, 28,
166 35, 42, 49, 56, 57, 50, 43, 36,
167 29, 22, 15, 23, 30, 37, 44, 51,
168 58, 59, 52, 45, 38, 31, 39, 46,
169 53, 60, 61, 54, 47, 55, 62, 63
173 * Table K.1 from JPEG spec.
175 static const int jpeg_luma_quantizer[64] = {
176 16, 11, 10, 16, 24, 40, 51, 61,
177 12, 12, 14, 19, 26, 58, 60, 55,
178 14, 13, 16, 24, 40, 57, 69, 56,
179 14, 17, 22, 29, 51, 87, 80, 62,
180 18, 22, 37, 56, 68, 109, 103, 77,
181 24, 35, 55, 64, 81, 104, 113, 92,
182 49, 64, 78, 87, 103, 121, 120, 101,
183 72, 92, 95, 98, 112, 100, 103, 99
187 * Table K.2 from JPEG spec.
189 static const int jpeg_chroma_quantizer[64] = {
190 17, 18, 24, 47, 99, 99, 99, 99,
191 18, 21, 26, 66, 99, 99, 99, 99,
192 24, 26, 56, 99, 99, 99, 99, 99,
193 47, 66, 99, 99, 99, 99, 99, 99,
194 99, 99, 99, 99, 99, 99, 99, 99,
195 99, 99, 99, 99, 99, 99, 99, 99,
196 99, 99, 99, 99, 99, 99, 99, 99,
197 99, 99, 99, 99, 99, 99, 99, 99
200 /* Call MakeTables with the Q factor and a guint8[128] return array
203 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
208 factor = CLAMP (Q, 1, 99);
213 Q = 200 - factor * 2;
215 for (i = 0; i < 64; i++) {
216 gint lq = (jpeg_luma_quantizer[zigzag[i]] * Q + 50) / 100;
217 gint cq = (jpeg_chroma_quantizer[zigzag[i]] * Q + 50) / 100;
219 /* Limit the quantizers to 1 <= q <= 255 */
220 qtable[i] = CLAMP (lq, 1, 255);
221 qtable[i + 64] = CLAMP (cq, 1, 255);
225 static const guint8 lum_dc_codelens[] = {
226 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
229 static const guint8 lum_dc_symbols[] = {
230 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
233 static const guint8 lum_ac_codelens[] = {
234 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
237 static const guint8 lum_ac_symbols[] = {
238 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
239 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
240 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
241 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
242 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
243 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
244 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
245 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
246 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
247 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
248 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
249 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
250 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
251 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
252 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
253 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
254 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
255 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
256 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
257 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
261 static const guint8 chm_dc_codelens[] = {
262 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
265 static const guint8 chm_dc_symbols[] = {
266 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
269 static const guint8 chm_ac_codelens[] = {
270 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
273 static const guint8 chm_ac_symbols[] = {
274 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
275 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
276 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
277 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
278 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
279 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
280 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
281 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
282 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
283 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
284 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
285 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
286 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
287 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
288 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
289 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
290 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
291 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
292 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
293 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
298 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
301 *p++ = 0xdb; /* DQT */
302 *p++ = 0; /* length msb */
303 *p++ = size + 3; /* length lsb */
305 memcpy (p, qt, size);
311 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
312 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
315 *p++ = 0xc4; /* DHT */
316 *p++ = 0; /* length msb */
317 *p++ = 3 + ncodes + nsymbols; /* length lsb */
318 *p++ = (tableClass << 4) | tableNo;
319 memcpy (p, codelens, ncodes);
321 memcpy (p, symbols, nsymbols);
328 MakeDRIHeader (guint8 * p, guint16 dri)
331 *p++ = 0xdd; /* DRI */
332 *p++ = 0x0; /* length msb */
333 *p++ = 4; /* length lsb */
334 *p++ = dri >> 8; /* dri msb */
335 *p++ = dri & 0xff; /* dri lsb */
342 * type, width, height: as supplied in RTP/JPEG header
343 * qt: quantization tables as either derived from
344 * the Q field using MakeTables() or as specified
346 * dri: restart interval in MCUs, or 0 if no restarts.
348 * p: pointer to return area
351 * The length of the generated headers.
353 * Generate a frame and scan headers that can be prepended to the
354 * RTP/JPEG data payload to produce a JPEG compressed image in
355 * interchange format (except for possible trailing garbage and
356 * absence of an EOI marker to terminate the scan).
359 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
360 guint precision, guint16 dri)
366 *p++ = 0xd8; /* SOI */
368 size = ((precision & 1) ? 128 : 64);
369 p = MakeQuantHeader (p, qt, size, 0);
372 size = ((precision & 2) ? 128 : 64);
373 p = MakeQuantHeader (p, qt, size, 1);
377 p = MakeDRIHeader (p, dri);
380 *p++ = 0xc0; /* SOF */
381 *p++ = 0; /* length msb */
382 *p++ = 17; /* length lsb */
383 *p++ = 8; /* 8-bit precision */
384 *p++ = height >> 8; /* height msb */
385 *p++ = height; /* height lsb */
386 *p++ = width >> 8; /* width msb */
387 *p++ = width; /* width lsb */
388 *p++ = 3; /* number of components */
389 *p++ = 0; /* comp 0 */
390 if ((type & 0x3f) == 0)
391 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
393 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
394 *p++ = 0; /* quant table 0 */
395 *p++ = 1; /* comp 1 */
396 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
397 *p++ = 1; /* quant table 1 */
398 *p++ = 2; /* comp 2 */
399 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
400 *p++ = 1; /* quant table 1 */
402 p = MakeHuffmanHeader (p, lum_dc_codelens,
403 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
404 p = MakeHuffmanHeader (p, lum_ac_codelens,
405 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
406 p = MakeHuffmanHeader (p, chm_dc_codelens,
407 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
408 p = MakeHuffmanHeader (p, chm_ac_codelens,
409 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
412 *p++ = 0xda; /* SOS */
413 *p++ = 0; /* length msb */
414 *p++ = 12; /* length lsb */
415 *p++ = 3; /* 3 components */
416 *p++ = 0; /* comp 0 */
417 *p++ = 0; /* huffman table 0 */
418 *p++ = 1; /* comp 1 */
419 *p++ = 0x11; /* huffman table 1 */
420 *p++ = 2; /* comp 2 */
421 *p++ = 0x11; /* huffman table 1 */
422 *p++ = 0; /* first DCT coeff */
423 *p++ = 63; /* last DCT coeff */
424 *p++ = 0; /* successive approx. */
430 gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
432 GstRtpJPEGDepay *rtpjpegdepay;
433 GstStructure *structure;
435 const gchar *media_attr;
437 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
439 structure = gst_caps_get_structure (caps, 0);
440 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
442 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
444 depayload->clock_rate = clock_rate;
447 rtpjpegdepay->width = 0;
448 rtpjpegdepay->height = 0;
449 rtpjpegdepay->media_width = 0;
450 rtpjpegdepay->media_height = 0;
451 rtpjpegdepay->frate_num = 0;
452 rtpjpegdepay->frate_denom = 1;
454 /* check for optional SDP attributes */
455 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
458 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
459 rtpjpegdepay->media_width = w;
460 rtpjpegdepay->media_height = h;
464 /* try to get a framerate */
465 media_attr = gst_structure_get_string (structure, "a-framerate");
467 media_attr = gst_structure_get_string (structure, "x-framerate");
474 /* canonicalise floating point string so we can handle framerate strings
475 * in the form "24.930" or "24,930" irrespective of the current locale */
476 s = g_strdup (media_attr);
477 g_strdelimit (s, ",", '.');
479 /* convert the float to a fraction */
480 g_value_init (&src, G_TYPE_DOUBLE);
481 g_value_set_double (&src, g_ascii_strtod (s, NULL));
482 g_value_init (&dest, GST_TYPE_FRACTION);
483 g_value_transform (&src, &dest);
485 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
486 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
495 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
497 GstRtpJPEGDepay *rtpjpegdepay;
499 gint payload_len, header_len;
503 guint type, width, height;
504 guint16 dri, precision, length;
507 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
509 if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
510 GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter");
511 gst_adapter_clear (rtpjpegdepay->adapter);
512 rtpjpegdepay->discont = TRUE;
515 payload_len = gst_rtp_buffer_get_payload_len (rtp);
520 payload = gst_rtp_buffer_get_payload (rtp);
524 * 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
525 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
526 * | Type-specific | Fragment Offset |
527 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
528 * | Type | Q | Width | Height |
529 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
531 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
534 width = payload[6] * 8;
535 height = payload[7] * 8;
537 /* saw a packet with fragment offset > 0 and we don't already have data queued
538 * up (most importantly, we don't have a header for this data) -- drop it
539 * XXX: maybe we can check if the jpeg is progressive and salvage the data?
540 * XXX: not implemented yet because jpegenc can't create progressive jpegs */
541 if (frag_offset > 0 && gst_adapter_available (rtpjpegdepay->adapter) == 0)
542 goto no_header_packet;
544 /* allow frame dimensions > 2040, passed in SDP session or media attributes
545 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
547 width = rtpjpegdepay->media_width;
550 height = rtpjpegdepay->media_height;
552 if (width == 0 || height == 0)
553 goto invalid_dimension;
555 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
556 frag_offset, type, Q, width, height);
568 * 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
569 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570 * | Restart Interval |F|L| Restart Count |
571 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
573 dri = (payload[0] << 8) | payload[1];
575 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
582 if (Q >= 128 && frag_offset == 0) {
587 * 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
588 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
589 * | MBZ | Precision | Length |
590 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591 * | Quantization Table Data |
593 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
595 precision = payload[1];
596 length = (payload[2] << 8) | payload[3];
598 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
601 if (Q == 255 && length == 0)
608 if (length > payload_len)
614 qtable = rtpjpegdepay->qtables[Q];
617 header_len += length;
618 payload_len -= length;
625 if (frag_offset == 0) {
629 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
633 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
634 "framerate", GST_TYPE_FRACTION, rtpjpegdepay->frate_num,
635 rtpjpegdepay->frate_denom, "width", G_TYPE_INT, width,
636 "height", G_TYPE_INT, height, NULL);
637 gst_pad_set_caps (depayload->srcpad, outcaps);
638 gst_caps_unref (outcaps);
640 rtpjpegdepay->width = width;
641 rtpjpegdepay->height = height;
644 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
650 /* no quant table, see if we have one cached */
651 qtable = rtpjpegdepay->qtables[Q];
653 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
654 /* make and cache the table */
655 qtable = g_new (guint8, 128);
656 MakeTables (rtpjpegdepay, Q, qtable);
657 rtpjpegdepay->qtables[Q] = qtable;
659 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
661 /* all 8 bit quantizers */
669 /* I think we can get here with a NULL qtable, so make sure we don't
670 go dereferencing it in MakeHeaders if we do */
674 /* max header length, should be big enough */
675 outbuf = gst_buffer_new_and_alloc (1000);
676 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
677 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
678 gst_buffer_unmap (outbuf, &map);
679 gst_buffer_resize (outbuf, 0, size);
681 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
683 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
686 /* take JPEG data, push in the adapter */
687 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
688 outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1);
689 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
692 if (gst_rtp_buffer_get_marker (rtp)) {
697 /* last buffer take all data out of the adapter */
698 avail = gst_adapter_available (rtpjpegdepay->adapter);
699 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
704 /* take the last bytes of the jpeg data to see if there is an EOI
706 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
708 if (end[0] != 0xff && end[1] != 0xd9) {
709 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
711 /* no EOI marker, add one */
712 outbuf = gst_buffer_new_and_alloc (2);
713 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
716 gst_buffer_unmap (outbuf, &map);
718 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
721 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
723 if (rtpjpegdepay->discont) {
724 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
725 rtpjpegdepay->discont = FALSE;
728 gst_rtp_drop_non_video_meta (rtpjpegdepay, outbuf);
730 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
738 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
739 ("Empty Payload."), (NULL));
744 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
745 ("Invalid Dimension %dx%d.", width, height), (NULL));
750 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
755 GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
756 gst_adapter_flush (rtpjpegdepay->adapter,
757 gst_adapter_available (rtpjpegdepay->adapter));
762 GST_WARNING_OBJECT (rtpjpegdepay,
763 "discarding data packets received when we have no header");
769 static GstStateChangeReturn
770 gst_rtp_jpeg_depay_change_state (GstElement * element,
771 GstStateChange transition)
773 GstRtpJPEGDepay *rtpjpegdepay;
774 GstStateChangeReturn ret;
776 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
778 switch (transition) {
779 case GST_STATE_CHANGE_READY_TO_PAUSED:
780 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
786 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
788 switch (transition) {
789 case GST_STATE_CHANGE_PAUSED_TO_READY: