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_BASE_RTP_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 (GstBaseRTPDepayload * depayload,
80 static GstBuffer *gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload,
84 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
86 GObjectClass *gobject_class;
87 GstElementClass *gstelement_class;
88 GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
90 gobject_class = (GObjectClass *) klass;
91 gstelement_class = (GstElementClass *) klass;
92 gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) 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 gstbasertpdepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
109 gstbasertpdepayload_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 (GstBaseRTPDepayload * 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 (GstBaseRTPDepayload * depayload, GstBuffer * buf)
482 GstRtpJPEGDepay *rtpjpegdepay;
484 gint payload_len, header_len;
488 guint type, width, height;
489 guint16 dri, precision, length;
492 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
494 if (GST_BUFFER_IS_DISCONT (buf)) {
495 gst_adapter_clear (rtpjpegdepay->adapter);
496 rtpjpegdepay->discont = TRUE;
499 payload_len = gst_rtp_buffer_get_payload_len (buf);
504 payload = gst_rtp_buffer_get_payload (buf);
508 * 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
509 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510 * | Type-specific | Fragment Offset |
511 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
512 * | Type | Q | Width | Height |
513 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
515 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
518 width = payload[6] * 8;
519 height = payload[7] * 8;
521 /* allow frame dimensions > 2040, passed in SDP session or media attributes
522 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
524 width = rtpjpegdepay->media_width;
527 height = rtpjpegdepay->media_height;
529 if (width == 0 || height == 0)
530 goto invalid_dimension;
532 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
533 frag_offset, type, Q, width, height);
545 * 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
546 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
547 * | Restart Interval |F|L| Restart Count |
548 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
550 dri = (payload[0] << 8) | payload[1];
552 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
559 if (Q >= 128 && frag_offset == 0) {
564 * 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
565 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
566 * | MBZ | Precision | Length |
567 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
568 * | Quantization Table Data |
570 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
572 precision = payload[1];
573 length = (payload[2] << 8) | payload[3];
575 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
578 if (Q == 255 && length == 0)
585 if (length > payload_len)
591 qtable = rtpjpegdepay->qtables[Q];
594 header_len += length;
595 payload_len -= length;
602 if (frag_offset == 0) {
605 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
609 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
610 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
611 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
612 gst_pad_set_caps (depayload->srcpad, outcaps);
613 gst_caps_unref (outcaps);
615 rtpjpegdepay->width = width;
616 rtpjpegdepay->height = height;
619 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
625 /* no quant table, see if we have one cached */
626 qtable = rtpjpegdepay->qtables[Q];
628 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
629 /* make and cache the table */
630 qtable = g_new (guint8, 128);
631 MakeTables (rtpjpegdepay, Q, qtable);
632 rtpjpegdepay->qtables[Q] = qtable;
634 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
636 /* all 8 bit quantizers */
643 /* max header length, should be big enough */
644 outbuf = gst_buffer_new_and_alloc (1000);
645 size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
646 width, height, qtable, precision, dri);
648 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
650 GST_BUFFER_SIZE (outbuf) = size;
652 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
655 /* take JPEG data, push in the adapter */
656 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
657 outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
658 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
661 if (gst_rtp_buffer_get_marker (buf)) {
666 /* last buffer take all data out of the adapter */
667 avail = gst_adapter_available (rtpjpegdepay->adapter);
668 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
670 /* take the last bytes of the jpeg data to see if there is an EOI
672 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
674 if (end[0] != 0xff && end[1] != 0xd9) {
675 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
677 /* no EOI marker, add one */
678 outbuf = gst_buffer_new_and_alloc (2);
679 data = GST_BUFFER_DATA (outbuf);
683 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
686 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
688 if (rtpjpegdepay->discont) {
689 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
690 rtpjpegdepay->discont = FALSE;
693 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
701 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
702 ("Empty Payload."), (NULL));
707 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
708 ("Invalid Dimension %dx%d.", width, height), (NULL));
713 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
719 static GstStateChangeReturn
720 gst_rtp_jpeg_depay_change_state (GstElement * element,
721 GstStateChange transition)
723 GstRtpJPEGDepay *rtpjpegdepay;
724 GstStateChangeReturn ret;
726 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
728 switch (transition) {
729 case GST_STATE_CHANGE_READY_TO_PAUSED:
730 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
736 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
738 switch (transition) {
739 case GST_STATE_CHANGE_PAUSED_TO_READY:
749 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
751 return gst_element_register (plugin, "rtpjpegdepay",
752 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);