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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, 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 "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
49 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
50 /* optional SDP attributes */
52 * "a-framerate = (string) 0.00, "
53 * "x-framerate = (string) 0.00, "
54 * "x-dimensions = (string) \"1234,1234\", "
57 "media = (string) \"video\", "
58 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
59 "clock-rate = (int) 90000"
60 /* optional SDP attributes */
62 * "a-framerate = (string) 0.00, "
63 * "x-framerate = (string) 0.00, "
64 * "x-dimensions = (string) \"1234,1234\""
69 #define gst_rtp_jpeg_depay_parent_class parent_class
70 G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
71 GST_TYPE_RTP_BASE_DEPAYLOAD);
73 static void gst_rtp_jpeg_depay_finalize (GObject * object);
75 static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
76 element, GstStateChange transition);
78 static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
80 static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
84 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
86 GObjectClass *gobject_class;
87 GstElementClass *gstelement_class;
88 GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
90 gobject_class = (GObjectClass *) klass;
91 gstelement_class = (GstElementClass *) klass;
92 gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
94 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
96 gst_element_class_add_pad_template (gstelement_class,
97 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
98 gst_element_class_add_pad_template (gstelement_class,
99 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
101 gst_element_class_set_details_simple (gstelement_class,
102 "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
103 "Extracts JPEG video from RTP packets (RFC 2435)",
104 "Wim Taymans <wim.taymans@gmail.com>");
106 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
108 gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
109 gstrtpbasedepayload_class->process = gst_rtp_jpeg_depay_process;
111 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
112 "JPEG Video RTP Depayloader");
116 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
118 rtpjpegdepay->adapter = gst_adapter_new ();
122 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
128 depay->media_width = 0;
129 depay->media_height = 0;
130 depay->frate_num = 0;
131 depay->frate_denom = 1;
132 depay->discont = TRUE;
134 for (i = 0; i < 255; i++) {
135 g_free (depay->qtables[i]);
136 depay->qtables[i] = NULL;
139 gst_adapter_clear (depay->adapter);
143 gst_rtp_jpeg_depay_finalize (GObject * object)
145 GstRtpJPEGDepay *rtpjpegdepay;
147 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
149 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
151 g_object_unref (rtpjpegdepay->adapter);
152 rtpjpegdepay->adapter = NULL;
154 G_OBJECT_CLASS (parent_class)->finalize (object);
158 * Table K.1 from JPEG spec.
160 static const int jpeg_luma_quantizer[64] = {
161 16, 11, 10, 16, 24, 40, 51, 61,
162 12, 12, 14, 19, 26, 58, 60, 55,
163 14, 13, 16, 24, 40, 57, 69, 56,
164 14, 17, 22, 29, 51, 87, 80, 62,
165 18, 22, 37, 56, 68, 109, 103, 77,
166 24, 35, 55, 64, 81, 104, 113, 92,
167 49, 64, 78, 87, 103, 121, 120, 101,
168 72, 92, 95, 98, 112, 100, 103, 99
172 * Table K.2 from JPEG spec.
174 static const int jpeg_chroma_quantizer[64] = {
175 17, 18, 24, 47, 99, 99, 99, 99,
176 18, 21, 26, 66, 99, 99, 99, 99,
177 24, 26, 56, 99, 99, 99, 99, 99,
178 47, 66, 99, 99, 99, 99, 99, 99,
179 99, 99, 99, 99, 99, 99, 99, 99,
180 99, 99, 99, 99, 99, 99, 99, 99,
181 99, 99, 99, 99, 99, 99, 99, 99,
182 99, 99, 99, 99, 99, 99, 99, 99
185 /* Call MakeTables with the Q factor and a guint8[128] return array
188 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
193 factor = CLAMP (Q, 1, 99);
198 Q = 200 - factor * 2;
200 for (i = 0; i < 64; i++) {
201 gint lq = (jpeg_luma_quantizer[i] * Q + 50) / 100;
202 gint cq = (jpeg_chroma_quantizer[i] * Q + 50) / 100;
204 /* Limit the quantizers to 1 <= q <= 255 */
205 qtable[i] = CLAMP (lq, 1, 255);
206 qtable[i + 64] = CLAMP (cq, 1, 255);
210 static const guint8 lum_dc_codelens[] = {
211 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
214 static const guint8 lum_dc_symbols[] = {
215 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
218 static const guint8 lum_ac_codelens[] = {
219 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
222 static const guint8 lum_ac_symbols[] = {
223 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
224 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
225 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
226 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
227 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
228 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
229 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
230 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
231 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
232 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
233 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
234 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
235 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
236 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
237 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
238 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
239 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
240 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
241 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
242 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
246 static const guint8 chm_dc_codelens[] = {
247 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
250 static const guint8 chm_dc_symbols[] = {
251 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
254 static const guint8 chm_ac_codelens[] = {
255 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
258 static const guint8 chm_ac_symbols[] = {
259 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
260 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
261 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
262 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
263 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
264 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
265 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
266 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
267 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
268 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
269 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
270 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
271 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
272 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
273 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
274 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
275 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
276 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
277 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
278 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
283 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
286 *p++ = 0xdb; /* DQT */
287 *p++ = 0; /* length msb */
288 *p++ = size + 3; /* length lsb */
290 memcpy (p, qt, size);
296 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
297 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
300 *p++ = 0xc4; /* DHT */
301 *p++ = 0; /* length msb */
302 *p++ = 3 + ncodes + nsymbols; /* length lsb */
303 *p++ = (tableClass << 4) | tableNo;
304 memcpy (p, codelens, ncodes);
306 memcpy (p, symbols, nsymbols);
313 MakeDRIHeader (guint8 * p, guint16 dri)
316 *p++ = 0xdd; /* DRI */
317 *p++ = 0x0; /* length msb */
318 *p++ = 4; /* length lsb */
319 *p++ = dri >> 8; /* dri msb */
320 *p++ = dri & 0xff; /* dri lsb */
327 * type, width, height: as supplied in RTP/JPEG header
328 * qt: quantization tables as either derived from
329 * the Q field using MakeTables() or as specified
331 * dri: restart interval in MCUs, or 0 if no restarts.
333 * p: pointer to return area
336 * The length of the generated headers.
338 * Generate a frame and scan headers that can be prepended to the
339 * RTP/JPEG data payload to produce a JPEG compressed image in
340 * interchange format (except for possible trailing garbage and
341 * absence of an EOI marker to terminate the scan).
344 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
345 guint precision, guint16 dri)
351 *p++ = 0xd8; /* SOI */
353 size = ((precision & 1) ? 128 : 64);
354 p = MakeQuantHeader (p, qt, size, 0);
357 size = ((precision & 2) ? 128 : 64);
358 p = MakeQuantHeader (p, qt, size, 1);
362 p = MakeDRIHeader (p, dri);
365 *p++ = 0xc0; /* SOF */
366 *p++ = 0; /* length msb */
367 *p++ = 17; /* length lsb */
368 *p++ = 8; /* 8-bit precision */
369 *p++ = height >> 8; /* height msb */
370 *p++ = height; /* height lsb */
371 *p++ = width >> 8; /* width msb */
372 *p++ = width; /* width lsb */
373 *p++ = 3; /* number of components */
374 *p++ = 0; /* comp 0 */
375 if ((type & 0x3f) == 0)
376 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
378 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
379 *p++ = 0; /* quant table 0 */
380 *p++ = 1; /* comp 1 */
381 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
382 *p++ = 1; /* quant table 1 */
383 *p++ = 2; /* comp 2 */
384 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
385 *p++ = 1; /* quant table 1 */
387 p = MakeHuffmanHeader (p, lum_dc_codelens,
388 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
389 p = MakeHuffmanHeader (p, lum_ac_codelens,
390 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
391 p = MakeHuffmanHeader (p, chm_dc_codelens,
392 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
393 p = MakeHuffmanHeader (p, chm_ac_codelens,
394 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
397 *p++ = 0xda; /* SOS */
398 *p++ = 0; /* length msb */
399 *p++ = 12; /* length lsb */
400 *p++ = 3; /* 3 components */
401 *p++ = 0; /* comp 0 */
402 *p++ = 0; /* huffman table 0 */
403 *p++ = 1; /* comp 1 */
404 *p++ = 0x11; /* huffman table 1 */
405 *p++ = 2; /* comp 2 */
406 *p++ = 0x11; /* huffman table 1 */
407 *p++ = 0; /* first DCT coeff */
408 *p++ = 63; /* last DCT coeff */
409 *p++ = 0; /* sucessive approx. */
415 gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
417 GstRtpJPEGDepay *rtpjpegdepay;
418 GstStructure *structure;
420 const gchar *media_attr;
422 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
424 structure = gst_caps_get_structure (caps, 0);
425 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
427 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
429 depayload->clock_rate = clock_rate;
432 rtpjpegdepay->width = 0;
433 rtpjpegdepay->height = 0;
434 rtpjpegdepay->media_width = 0;
435 rtpjpegdepay->media_height = 0;
436 rtpjpegdepay->frate_num = 0;
437 rtpjpegdepay->frate_denom = 1;
439 /* check for optional SDP attributes */
440 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
443 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
444 rtpjpegdepay->media_width = w;
445 rtpjpegdepay->media_height = h;
449 /* try to get a framerate */
450 media_attr = gst_structure_get_string (structure, "a-framerate");
452 media_attr = gst_structure_get_string (structure, "x-framerate");
459 /* canonicalise floating point string so we can handle framerate strings
460 * in the form "24.930" or "24,930" irrespective of the current locale */
461 s = g_strdup (media_attr);
462 g_strdelimit (s, ",", '.');
464 /* convert the float to a fraction */
465 g_value_init (&src, G_TYPE_DOUBLE);
466 g_value_set_double (&src, g_ascii_strtod (s, NULL));
467 g_value_init (&dest, GST_TYPE_FRACTION);
468 g_value_transform (&src, &dest);
470 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
471 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
480 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
482 GstRtpJPEGDepay *rtpjpegdepay;
484 gint payload_len, header_len;
488 guint type, width, height;
489 guint16 dri, precision, length;
491 GstRTPBuffer rtp = { NULL };
493 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
495 if (GST_BUFFER_IS_DISCONT (buf)) {
496 gst_adapter_clear (rtpjpegdepay->adapter);
497 rtpjpegdepay->discont = TRUE;
500 gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
501 payload_len = gst_rtp_buffer_get_payload_len (&rtp);
506 payload = gst_rtp_buffer_get_payload (&rtp);
510 * 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
511 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
512 * | Type-specific | Fragment Offset |
513 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
514 * | Type | Q | Width | Height |
515 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
517 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
520 width = payload[6] * 8;
521 height = payload[7] * 8;
523 /* allow frame dimensions > 2040, passed in SDP session or media attributes
524 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
526 width = rtpjpegdepay->media_width;
529 height = rtpjpegdepay->media_height;
531 if (width == 0 || height == 0)
532 goto invalid_dimension;
534 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
535 frag_offset, type, Q, width, height);
547 * 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
548 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
549 * | Restart Interval |F|L| Restart Count |
550 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
552 dri = (payload[0] << 8) | payload[1];
554 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
561 if (Q >= 128 && frag_offset == 0) {
566 * 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
567 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
568 * | MBZ | Precision | Length |
569 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570 * | Quantization Table Data |
572 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
574 precision = payload[1];
575 length = (payload[2] << 8) | payload[3];
577 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
580 if (Q == 255 && length == 0)
587 if (length > payload_len)
593 qtable = rtpjpegdepay->qtables[Q];
596 header_len += length;
597 payload_len -= length;
604 if (frag_offset == 0) {
608 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
612 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
613 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
614 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
615 gst_pad_set_caps (depayload->srcpad, outcaps);
616 gst_caps_unref (outcaps);
618 rtpjpegdepay->width = width;
619 rtpjpegdepay->height = height;
622 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
628 /* no quant table, see if we have one cached */
629 qtable = rtpjpegdepay->qtables[Q];
631 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
632 /* make and cache the table */
633 qtable = g_new (guint8, 128);
634 MakeTables (rtpjpegdepay, Q, qtable);
635 rtpjpegdepay->qtables[Q] = qtable;
637 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
639 /* all 8 bit quantizers */
646 /* max header length, should be big enough */
647 outbuf = gst_buffer_new_and_alloc (1000);
648 data = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
649 size = MakeHeaders (data, type, width, height, qtable, precision, dri);
650 gst_buffer_unmap (outbuf, data, size);
652 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
654 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
657 /* take JPEG data, push in the adapter */
658 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
659 outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, -1);
660 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
663 if (gst_rtp_buffer_get_marker (&rtp)) {
668 /* last buffer take all data out of the adapter */
669 avail = gst_adapter_available (rtpjpegdepay->adapter);
670 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
672 /* take the last bytes of the jpeg data to see if there is an EOI
674 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
676 if (end[0] != 0xff && end[1] != 0xd9) {
677 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
679 /* no EOI marker, add one */
680 outbuf = gst_buffer_new_and_alloc (2);
681 data = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
684 gst_buffer_unmap (outbuf, data, -1);
686 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
689 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
691 if (rtpjpegdepay->discont) {
692 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
693 rtpjpegdepay->discont = FALSE;
696 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
699 gst_rtp_buffer_unmap (&rtp);
706 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
707 ("Empty Payload."), (NULL));
708 gst_rtp_buffer_unmap (&rtp);
713 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
714 ("Invalid Dimension %dx%d.", width, height), (NULL));
715 gst_rtp_buffer_unmap (&rtp);
720 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
721 gst_rtp_buffer_unmap (&rtp);
727 static GstStateChangeReturn
728 gst_rtp_jpeg_depay_change_state (GstElement * element,
729 GstStateChange transition)
731 GstRtpJPEGDepay *rtpjpegdepay;
732 GstStateChangeReturn ret;
734 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
736 switch (transition) {
737 case GST_STATE_CHANGE_READY_TO_PAUSED:
738 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
744 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
746 switch (transition) {
747 case GST_STATE_CHANGE_PAUSED_TO_READY:
757 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
759 return gst_element_register (plugin, "rtpjpegdepay",
760 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);