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");
465 /* canonicalise floating point string so we can handle framerate strings
466 * in the form "24.930" or "24,930" irrespective of the current locale */
467 s = g_strdup (media_attr);
468 g_strdelimit (s, ",", '.');
470 /* convert the float to a fraction */
471 g_value_init (&src, G_TYPE_DOUBLE);
472 g_value_set_double (&src, g_ascii_strtod (s, NULL));
473 g_value_init (&dest, GST_TYPE_FRACTION);
474 g_value_transform (&src, &dest);
476 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
477 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
486 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
488 GstRtpJPEGDepay *rtpjpegdepay;
490 gint payload_len, header_len;
494 guint type, width, height;
495 guint16 dri, precision, length;
498 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
500 if (GST_BUFFER_IS_DISCONT (buf)) {
501 gst_adapter_clear (rtpjpegdepay->adapter);
502 rtpjpegdepay->discont = TRUE;
505 payload_len = gst_rtp_buffer_get_payload_len (buf);
510 payload = gst_rtp_buffer_get_payload (buf);
514 * 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
515 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516 * | Type-specific | Fragment Offset |
517 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518 * | Type | Q | Width | Height |
519 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
521 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
524 width = payload[6] * 8;
525 height = payload[7] * 8;
527 /* allow frame dimensions > 2040, passed in SDP session or media attributes
528 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
530 width = rtpjpegdepay->media_width;
533 height = rtpjpegdepay->media_height;
535 if (width == 0 || height == 0)
536 goto invalid_dimension;
538 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
539 frag_offset, type, Q, width, height);
551 * 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
552 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
553 * | Restart Interval |F|L| Restart Count |
554 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
556 dri = (payload[0] << 8) | payload[1];
558 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
565 if (Q >= 128 && frag_offset == 0) {
570 * 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
571 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
572 * | MBZ | Precision | Length |
573 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
574 * | Quantization Table Data |
576 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
578 precision = payload[1];
579 length = (payload[2] << 8) | payload[3];
581 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
584 if (Q == 255 && length == 0)
591 if (length > payload_len)
597 qtable = rtpjpegdepay->qtables[Q];
600 header_len += length;
601 payload_len -= length;
608 if (frag_offset == 0) {
611 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
615 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
616 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
617 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
618 gst_pad_set_caps (depayload->srcpad, outcaps);
619 gst_caps_unref (outcaps);
621 rtpjpegdepay->width = width;
622 rtpjpegdepay->height = height;
625 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
631 /* no quant table, see if we have one cached */
632 qtable = rtpjpegdepay->qtables[Q];
634 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
635 /* make and cache the table */
636 qtable = g_new (guint8, 128);
637 MakeTables (rtpjpegdepay, Q, qtable);
638 rtpjpegdepay->qtables[Q] = qtable;
640 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
642 /* all 8 bit quantizers */
649 /* max header length, should be big enough */
650 outbuf = gst_buffer_new_and_alloc (1000);
651 size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
652 width, height, qtable, precision, dri);
654 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
656 GST_BUFFER_SIZE (outbuf) = size;
658 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
661 /* take JPEG data, push in the adapter */
662 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
663 outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
664 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
667 if (gst_rtp_buffer_get_marker (buf)) {
672 /* last buffer take all data out of the adapter */
673 avail = gst_adapter_available (rtpjpegdepay->adapter);
674 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
676 /* take the last bytes of the jpeg data to see if there is an EOI
678 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
680 if (end[0] != 0xff && end[1] != 0xd9) {
681 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
683 /* no EOI marker, add one */
684 outbuf = gst_buffer_new_and_alloc (2);
685 data = GST_BUFFER_DATA (outbuf);
689 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
692 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
694 if (rtpjpegdepay->discont) {
695 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
696 rtpjpegdepay->discont = FALSE;
699 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
707 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
708 ("Empty Payload."), (NULL));
713 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
714 ("Invalid Dimension %dx%d.", width, height), (NULL));
719 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
725 static GstStateChangeReturn
726 gst_rtp_jpeg_depay_change_state (GstElement * element,
727 GstStateChange transition)
729 GstRtpJPEGDepay *rtpjpegdepay;
730 GstStateChangeReturn ret;
732 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
734 switch (transition) {
735 case GST_STATE_CHANGE_READY_TO_PAUSED:
736 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
742 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
744 switch (transition) {
745 case GST_STATE_CHANGE_PAUSED_TO_READY:
755 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
757 return gst_element_register (plugin, "rtpjpegdepay",
758 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);