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 GST_BOILERPLATE (GstRtpJPEGDepay, gst_rtp_jpeg_depay, GstBaseRTPDepayload,
70 GST_TYPE_BASE_RTP_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 (GstBaseRTPDepayload * depayload,
79 static GstBuffer *gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload,
83 gst_rtp_jpeg_depay_base_init (gpointer klass)
85 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
87 gst_element_class_add_pad_template (element_class,
88 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
89 gst_element_class_add_pad_template (element_class,
90 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
92 gst_element_class_set_details_simple (element_class, "RTP JPEG depayloader",
93 "Codec/Depayloader/Network/RTP",
94 "Extracts JPEG video from RTP packets (RFC 2435)",
95 "Wim Taymans <wim.taymans@gmail.com>");
99 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
101 GObjectClass *gobject_class;
102 GstElementClass *gstelement_class;
103 GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
105 gobject_class = (GObjectClass *) klass;
106 gstelement_class = (GstElementClass *) klass;
107 gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
109 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
111 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
113 gstbasertpdepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
114 gstbasertpdepayload_class->process = gst_rtp_jpeg_depay_process;
116 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
117 "JPEG Video RTP Depayloader");
121 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay,
122 GstRtpJPEGDepayClass * klass)
124 rtpjpegdepay->adapter = gst_adapter_new ();
128 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
134 depay->media_width = 0;
135 depay->media_height = 0;
136 depay->frate_num = 0;
137 depay->frate_denom = 1;
138 depay->discont = TRUE;
140 for (i = 0; i < 255; i++) {
141 g_free (depay->qtables[i]);
142 depay->qtables[i] = NULL;
145 gst_adapter_clear (depay->adapter);
149 gst_rtp_jpeg_depay_finalize (GObject * object)
151 GstRtpJPEGDepay *rtpjpegdepay;
153 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
155 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
157 g_object_unref (rtpjpegdepay->adapter);
158 rtpjpegdepay->adapter = NULL;
160 G_OBJECT_CLASS (parent_class)->finalize (object);
164 * Table K.1 from JPEG spec.
166 static const int jpeg_luma_quantizer[64] = {
167 16, 11, 10, 16, 24, 40, 51, 61,
168 12, 12, 14, 19, 26, 58, 60, 55,
169 14, 13, 16, 24, 40, 57, 69, 56,
170 14, 17, 22, 29, 51, 87, 80, 62,
171 18, 22, 37, 56, 68, 109, 103, 77,
172 24, 35, 55, 64, 81, 104, 113, 92,
173 49, 64, 78, 87, 103, 121, 120, 101,
174 72, 92, 95, 98, 112, 100, 103, 99
178 * Table K.2 from JPEG spec.
180 static const int jpeg_chroma_quantizer[64] = {
181 17, 18, 24, 47, 99, 99, 99, 99,
182 18, 21, 26, 66, 99, 99, 99, 99,
183 24, 26, 56, 99, 99, 99, 99, 99,
184 47, 66, 99, 99, 99, 99, 99, 99,
185 99, 99, 99, 99, 99, 99, 99, 99,
186 99, 99, 99, 99, 99, 99, 99, 99,
187 99, 99, 99, 99, 99, 99, 99, 99,
188 99, 99, 99, 99, 99, 99, 99, 99
191 /* Call MakeTables with the Q factor and a guint8[128] return array
194 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
199 factor = CLAMP (Q, 1, 99);
204 Q = 200 - factor * 2;
206 for (i = 0; i < 64; i++) {
207 gint lq = (jpeg_luma_quantizer[i] * Q + 50) / 100;
208 gint cq = (jpeg_chroma_quantizer[i] * Q + 50) / 100;
210 /* Limit the quantizers to 1 <= q <= 255 */
211 qtable[i] = CLAMP (lq, 1, 255);
212 qtable[i + 64] = CLAMP (cq, 1, 255);
216 static const guint8 lum_dc_codelens[] = {
217 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
220 static const guint8 lum_dc_symbols[] = {
221 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
224 static const guint8 lum_ac_codelens[] = {
225 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
228 static const guint8 lum_ac_symbols[] = {
229 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
230 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
231 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
232 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
233 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
234 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
235 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
236 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
237 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
238 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
239 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
240 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
241 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
242 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
243 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
244 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
245 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
246 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
247 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
248 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
252 static const guint8 chm_dc_codelens[] = {
253 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
256 static const guint8 chm_dc_symbols[] = {
257 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
260 static const guint8 chm_ac_codelens[] = {
261 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
264 static const guint8 chm_ac_symbols[] = {
265 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
266 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
267 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
268 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
269 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
270 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
271 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
272 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
273 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
274 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
275 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
276 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
277 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
278 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
279 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
280 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
281 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
282 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
283 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
284 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
289 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
292 *p++ = 0xdb; /* DQT */
293 *p++ = 0; /* length msb */
294 *p++ = size + 3; /* length lsb */
296 memcpy (p, qt, size);
302 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
303 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
306 *p++ = 0xc4; /* DHT */
307 *p++ = 0; /* length msb */
308 *p++ = 3 + ncodes + nsymbols; /* length lsb */
309 *p++ = (tableClass << 4) | tableNo;
310 memcpy (p, codelens, ncodes);
312 memcpy (p, symbols, nsymbols);
319 MakeDRIHeader (guint8 * p, guint16 dri)
322 *p++ = 0xdd; /* DRI */
323 *p++ = 0x0; /* length msb */
324 *p++ = 4; /* length lsb */
325 *p++ = dri >> 8; /* dri msb */
326 *p++ = dri & 0xff; /* dri lsb */
333 * type, width, height: as supplied in RTP/JPEG header
334 * qt: quantization tables as either derived from
335 * the Q field using MakeTables() or as specified
337 * dri: restart interval in MCUs, or 0 if no restarts.
339 * p: pointer to return area
342 * The length of the generated headers.
344 * Generate a frame and scan headers that can be prepended to the
345 * RTP/JPEG data payload to produce a JPEG compressed image in
346 * interchange format (except for possible trailing garbage and
347 * absence of an EOI marker to terminate the scan).
350 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
351 guint precision, guint16 dri)
357 *p++ = 0xd8; /* SOI */
359 size = ((precision & 1) ? 128 : 64);
360 p = MakeQuantHeader (p, qt, size, 0);
363 size = ((precision & 2) ? 128 : 64);
364 p = MakeQuantHeader (p, qt, size, 1);
368 p = MakeDRIHeader (p, dri);
371 *p++ = 0xc0; /* SOF */
372 *p++ = 0; /* length msb */
373 *p++ = 17; /* length lsb */
374 *p++ = 8; /* 8-bit precision */
375 *p++ = height >> 8; /* height msb */
376 *p++ = height; /* height lsb */
377 *p++ = width >> 8; /* width msb */
378 *p++ = width; /* width lsb */
379 *p++ = 3; /* number of components */
380 *p++ = 0; /* comp 0 */
381 if ((type & 0x3f) == 0)
382 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
384 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
385 *p++ = 0; /* quant table 0 */
386 *p++ = 1; /* comp 1 */
387 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
388 *p++ = 1; /* quant table 1 */
389 *p++ = 2; /* comp 2 */
390 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
391 *p++ = 1; /* quant table 1 */
393 p = MakeHuffmanHeader (p, lum_dc_codelens,
394 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
395 p = MakeHuffmanHeader (p, lum_ac_codelens,
396 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
397 p = MakeHuffmanHeader (p, chm_dc_codelens,
398 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
399 p = MakeHuffmanHeader (p, chm_ac_codelens,
400 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
403 *p++ = 0xda; /* SOS */
404 *p++ = 0; /* length msb */
405 *p++ = 12; /* length lsb */
406 *p++ = 3; /* 3 components */
407 *p++ = 0; /* comp 0 */
408 *p++ = 0; /* huffman table 0 */
409 *p++ = 1; /* comp 1 */
410 *p++ = 0x11; /* huffman table 1 */
411 *p++ = 2; /* comp 2 */
412 *p++ = 0x11; /* huffman table 1 */
413 *p++ = 0; /* first DCT coeff */
414 *p++ = 63; /* last DCT coeff */
415 *p++ = 0; /* sucessive approx. */
421 gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
423 GstRtpJPEGDepay *rtpjpegdepay;
424 GstStructure *structure;
426 const gchar *media_attr;
428 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
430 structure = gst_caps_get_structure (caps, 0);
431 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
433 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
435 depayload->clock_rate = clock_rate;
438 rtpjpegdepay->width = 0;
439 rtpjpegdepay->height = 0;
440 rtpjpegdepay->media_width = 0;
441 rtpjpegdepay->media_height = 0;
442 rtpjpegdepay->frate_num = 0;
443 rtpjpegdepay->frate_denom = 1;
445 /* check for optional SDP attributes */
446 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
449 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
450 rtpjpegdepay->media_width = w;
451 rtpjpegdepay->media_height = h;
455 /* try to get a framerate */
456 media_attr = gst_structure_get_string (structure, "a-framerate");
458 media_attr = gst_structure_get_string (structure, "x-framerate");
464 /* convert the float to a fraction */
465 g_value_init (&src, G_TYPE_DOUBLE);
466 g_value_set_double (&src, atof (media_attr));
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);
478 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
480 GstRtpJPEGDepay *rtpjpegdepay;
482 gint payload_len, header_len;
486 guint type, width, height;
487 guint16 dri, precision, length;
490 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
492 if (GST_BUFFER_IS_DISCONT (buf)) {
493 gst_adapter_clear (rtpjpegdepay->adapter);
494 rtpjpegdepay->discont = TRUE;
497 payload_len = gst_rtp_buffer_get_payload_len (buf);
502 payload = gst_rtp_buffer_get_payload (buf);
506 * 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
507 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
508 * | Type-specific | Fragment Offset |
509 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510 * | Type | Q | Width | Height |
511 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
513 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
516 width = payload[6] * 8;
517 height = payload[7] * 8;
519 /* allow frame dimensions > 2040, passed in SDP session or media attributes
520 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
522 width = rtpjpegdepay->media_width;
525 height = rtpjpegdepay->media_height;
527 if (width == 0 || height == 0)
528 goto invalid_dimension;
530 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
531 frag_offset, type, Q, width, height);
543 * 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
544 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
545 * | Restart Interval |F|L| Restart Count |
546 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
548 dri = (payload[0] << 8) | payload[1];
550 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
557 if (Q >= 128 && frag_offset == 0) {
562 * 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
563 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
564 * | MBZ | Precision | Length |
565 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
566 * | Quantization Table Data |
568 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570 precision = payload[1];
571 length = (payload[2] << 8) | payload[3];
573 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
576 if (Q == 255 && length == 0)
583 if (length > payload_len)
589 qtable = rtpjpegdepay->qtables[Q];
592 header_len += length;
593 payload_len -= length;
600 if (frag_offset == 0) {
603 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
607 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
608 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
609 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
610 gst_pad_set_caps (depayload->srcpad, outcaps);
611 gst_caps_unref (outcaps);
613 rtpjpegdepay->width = width;
614 rtpjpegdepay->height = height;
617 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
623 /* no quant table, see if we have one cached */
624 qtable = rtpjpegdepay->qtables[Q];
626 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
627 /* make and cache the table */
628 qtable = g_new (guint8, 128);
629 MakeTables (rtpjpegdepay, Q, qtable);
630 rtpjpegdepay->qtables[Q] = qtable;
632 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
634 /* all 8 bit quantizers */
641 /* max header length, should be big enough */
642 outbuf = gst_buffer_new_and_alloc (1000);
643 size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
644 width, height, qtable, precision, dri);
646 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
648 GST_BUFFER_SIZE (outbuf) = size;
650 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
653 /* take JPEG data, push in the adapter */
654 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
655 outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
656 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
659 if (gst_rtp_buffer_get_marker (buf)) {
664 /* last buffer take all data out of the adapter */
665 avail = gst_adapter_available (rtpjpegdepay->adapter);
666 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
668 /* take the last bytes of the jpeg data to see if there is an EOI
670 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
672 if (end[0] != 0xff && end[1] != 0xd9) {
673 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
675 /* no EOI marker, add one */
676 outbuf = gst_buffer_new_and_alloc (2);
677 data = GST_BUFFER_DATA (outbuf);
681 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
684 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
686 if (rtpjpegdepay->discont) {
687 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
688 rtpjpegdepay->discont = FALSE;
691 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
699 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
700 ("Empty Payload."), (NULL));
705 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
706 ("Invalid Dimension %dx%d.", width, height), (NULL));
711 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
717 static GstStateChangeReturn
718 gst_rtp_jpeg_depay_change_state (GstElement * element,
719 GstStateChange transition)
721 GstRtpJPEGDepay *rtpjpegdepay;
722 GstStateChangeReturn ret;
724 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
726 switch (transition) {
727 case GST_STATE_CHANGE_READY_TO_PAUSED:
728 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
734 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
736 switch (transition) {
737 case GST_STATE_CHANGE_PAUSED_TO_READY:
747 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
749 return gst_element_register (plugin, "rtpjpegdepay",
750 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);