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>
27 #include "gstrtpjpegdepay.h"
29 GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
30 #define GST_CAT_DEFAULT (rtpjpegdepay_debug)
32 /* elementfactory information */
33 static const GstElementDetails gst_rtp_jpegdepay_details =
34 GST_ELEMENT_DETAILS ("RTP JPEG depayloader",
35 "Codec/Depayloader/Network",
36 "Extracts JPEG video from RTP packets (RFC 2435)",
37 "Wim Taymans <wim.taymans@gmail.com>");
39 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
40 GST_STATIC_PAD_TEMPLATE ("src",
43 GST_STATIC_CAPS ("image/jpeg")
46 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
47 GST_STATIC_PAD_TEMPLATE ("sink",
50 GST_STATIC_CAPS ("application/x-rtp, "
51 "media = (string) \"video\", "
52 "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
53 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
54 /* optional SDP attributes */
56 * "a-framerate = (string) 0.00, "
57 * "x-framerate = (string) 0.00, "
58 * "x-dimensions = (string) \"1234,1234\", "
61 "media = (string) \"video\", "
62 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
63 "clock-rate = (int) 90000"
64 /* optional SDP attributes */
66 * "a-framerate = (string) 0.00, "
67 * "x-framerate = (string) 0.00, "
68 * "x-dimensions = (string) \"1234,1234\""
73 GST_BOILERPLATE (GstRtpJPEGDepay, gst_rtp_jpeg_depay, GstBaseRTPDepayload,
74 GST_TYPE_BASE_RTP_DEPAYLOAD);
76 static void gst_rtp_jpeg_depay_finalize (GObject * object);
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_base_init (gpointer klass)
86 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
88 gst_element_class_add_pad_template (element_class,
89 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
90 gst_element_class_add_pad_template (element_class,
91 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
93 gst_element_class_set_details (element_class, &gst_rtp_jpegdepay_details);
97 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
99 GObjectClass *gobject_class;
100 GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
102 gobject_class = (GObjectClass *) klass;
103 gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
105 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
107 parent_class = g_type_class_peek_parent (klass);
109 gstbasertpdepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
110 gstbasertpdepayload_class->process = gst_rtp_jpeg_depay_process;
112 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
113 "JPEG Video RTP Depayloader");
117 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay,
118 GstRtpJPEGDepayClass * klass)
120 rtpjpegdepay->adapter = gst_adapter_new ();
124 gst_rtp_jpeg_depay_finalize (GObject * object)
126 GstRtpJPEGDepay *rtpjpegdepay;
128 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
130 g_object_unref (rtpjpegdepay->adapter);
131 rtpjpegdepay->adapter = NULL;
133 G_OBJECT_CLASS (parent_class)->finalize (object);
137 * Table K.1 from JPEG spec.
139 static const int jpeg_luma_quantizer[64] = {
140 16, 11, 10, 16, 24, 40, 51, 61,
141 12, 12, 14, 19, 26, 58, 60, 55,
142 14, 13, 16, 24, 40, 57, 69, 56,
143 14, 17, 22, 29, 51, 87, 80, 62,
144 18, 22, 37, 56, 68, 109, 103, 77,
145 24, 35, 55, 64, 81, 104, 113, 92,
146 49, 64, 78, 87, 103, 121, 120, 101,
147 72, 92, 95, 98, 112, 100, 103, 99
151 * Table K.2 from JPEG spec.
153 static const int jpeg_chroma_quantizer[64] = {
154 17, 18, 24, 47, 99, 99, 99, 99,
155 18, 21, 26, 66, 99, 99, 99, 99,
156 24, 26, 56, 99, 99, 99, 99, 99,
157 47, 66, 99, 99, 99, 99, 99, 99,
158 99, 99, 99, 99, 99, 99, 99, 99,
159 99, 99, 99, 99, 99, 99, 99, 99,
160 99, 99, 99, 99, 99, 99, 99, 99,
161 99, 99, 99, 99, 99, 99, 99, 99
164 /* Call MakeTables with the Q factor and a guint8[128] return array
167 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
172 factor = CLAMP (Q, 1, 99);
177 Q = 200 - factor * 2;
179 for (i = 0; i < 64; i++) {
180 gint lq = (jpeg_luma_quantizer[i] * Q + 50) / 100;
181 gint cq = (jpeg_chroma_quantizer[i] * Q + 50) / 100;
183 /* Limit the quantizers to 1 <= q <= 255 */
184 qtable[i] = CLAMP (lq, 1, 255);
185 qtable[i + 64] = CLAMP (cq, 1, 255);
189 static const guint8 lum_dc_codelens[] = {
190 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
193 static const guint8 lum_dc_symbols[] = {
194 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
197 static const guint8 lum_ac_codelens[] = {
198 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
201 static const guint8 lum_ac_symbols[] = {
202 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
203 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
204 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
205 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
206 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
207 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
208 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
209 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
210 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
211 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
212 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
213 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
214 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
215 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
216 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
217 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
218 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
219 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
220 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
221 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
225 static const guint8 chm_dc_codelens[] = {
226 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
229 static const guint8 chm_dc_symbols[] = {
230 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
233 static const guint8 chm_ac_codelens[] = {
234 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
237 static const guint8 chm_ac_symbols[] = {
238 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
239 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
240 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
241 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
242 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
243 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
244 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
245 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
246 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
247 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
248 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
249 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
250 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
251 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
252 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
253 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
254 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
255 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
256 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
257 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
262 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
265 *p++ = 0xdb; /* DQT */
266 *p++ = 0; /* length msb */
267 *p++ = size + 3; /* length lsb */
269 memcpy (p, qt, size);
275 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
276 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
279 *p++ = 0xc4; /* DHT */
280 *p++ = 0; /* length msb */
281 *p++ = 3 + ncodes + nsymbols; /* length lsb */
282 *p++ = (tableClass << 4) | tableNo;
283 memcpy (p, codelens, ncodes);
285 memcpy (p, symbols, nsymbols);
292 MakeDRIHeader (guint8 * p, guint16 dri)
295 *p++ = 0xdd; /* DRI */
296 *p++ = 0x0; /* length msb */
297 *p++ = 4; /* length lsb */
298 *p++ = dri >> 8; /* dri msb */
299 *p++ = dri & 0xff; /* dri lsb */
306 * type, width, height: as supplied in RTP/JPEG header
307 * qt: quantization tables as either derived from
308 * the Q field using MakeTables() or as specified
310 * dri: restart interval in MCUs, or 0 if no restarts.
312 * p: pointer to return area
315 * The length of the generated headers.
317 * Generate a frame and scan headers that can be prepended to the
318 * RTP/JPEG data payload to produce a JPEG compressed image in
319 * interchange format (except for possible trailing garbage and
320 * absence of an EOI marker to terminate the scan).
323 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
324 guint precision, guint16 dri)
330 *p++ = 0xd8; /* SOI */
332 size = ((precision & 1) ? 128 : 64);
333 p = MakeQuantHeader (p, qt, size, 0);
336 size = ((precision & 2) ? 128 : 64);
337 p = MakeQuantHeader (p, qt, size, 1);
341 p = MakeDRIHeader (p, dri);
344 *p++ = 0xc0; /* SOF */
345 *p++ = 0; /* length msb */
346 *p++ = 17; /* length lsb */
347 *p++ = 8; /* 8-bit precision */
348 *p++ = height >> 8; /* height msb */
349 *p++ = height; /* height lsb */
350 *p++ = width >> 8; /* width msb */
351 *p++ = width; /* width lsb */
352 *p++ = 3; /* number of components */
353 *p++ = 0; /* comp 0 */
354 if ((type & 0x3f) == 0)
355 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
357 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
358 *p++ = 0; /* quant table 0 */
359 *p++ = 1; /* comp 1 */
360 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
361 *p++ = 1; /* quant table 1 */
362 *p++ = 2; /* comp 2 */
363 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
364 *p++ = 1; /* quant table 1 */
366 p = MakeHuffmanHeader (p, lum_dc_codelens,
367 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
368 p = MakeHuffmanHeader (p, lum_ac_codelens,
369 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
370 p = MakeHuffmanHeader (p, chm_dc_codelens,
371 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
372 p = MakeHuffmanHeader (p, chm_ac_codelens,
373 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
376 *p++ = 0xda; /* SOS */
377 *p++ = 0; /* length msb */
378 *p++ = 12; /* length lsb */
379 *p++ = 3; /* 3 components */
380 *p++ = 0; /* comp 0 */
381 *p++ = 0; /* huffman table 0 */
382 *p++ = 1; /* comp 1 */
383 *p++ = 0x11; /* huffman table 1 */
384 *p++ = 2; /* comp 2 */
385 *p++ = 0x11; /* huffman table 1 */
386 *p++ = 0; /* first DCT coeff */
387 *p++ = 63; /* last DCT coeff */
388 *p++ = 0; /* sucessive approx. */
394 gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
396 GstRtpJPEGDepay *rtpjpegdepay;
397 GstStructure *structure;
399 const gchar *media_attr;
401 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
403 structure = gst_caps_get_structure (caps, 0);
404 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
406 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
408 depayload->clock_rate = clock_rate;
411 rtpjpegdepay->width = 0;
412 rtpjpegdepay->height = 0;
413 rtpjpegdepay->media_width = 0;
414 rtpjpegdepay->media_height = 0;
415 rtpjpegdepay->frate_num = 0;
416 rtpjpegdepay->frate_denom = 1;
418 /* check for optional SDP attributes */
419 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
422 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
423 rtpjpegdepay->media_width = w;
424 rtpjpegdepay->media_height = h;
428 /* try to get a framerate */
429 media_attr = gst_structure_get_string (structure, "a-framerate");
431 media_attr = gst_structure_get_string (structure, "x-framerate");
437 /* convert the float to a fraction */
438 g_value_init (&src, G_TYPE_DOUBLE);
439 g_value_set_double (&src, atof (media_attr));
440 g_value_init (&dest, GST_TYPE_FRACTION);
441 g_value_transform (&src, &dest);
443 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
444 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
451 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
453 GstRtpJPEGDepay *rtpjpegdepay;
455 gint payload_len, header_len;
459 guint type, width, height;
460 guint16 dri, precision, length;
463 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
465 if (GST_BUFFER_IS_DISCONT (buf)) {
466 gst_adapter_clear (rtpjpegdepay->adapter);
469 payload_len = gst_rtp_buffer_get_payload_len (buf);
474 payload = gst_rtp_buffer_get_payload (buf);
478 * 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
479 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
480 * | Type-specific | Fragment Offset |
481 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
482 * | Type | Q | Width | Height |
483 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
485 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
488 width = payload[6] * 8;
489 height = payload[7] * 8;
491 /* allow frame dimensions > 2040, passed in SDP session or media attributes
492 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
494 width = rtpjpegdepay->media_width;
497 height = rtpjpegdepay->media_height;
499 if (width == 0 || height == 0)
500 goto invalid_dimension;
502 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
503 frag_offset, type, Q, width, height);
515 * 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
516 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
517 * | Restart Interval |F|L| Restart Count |
518 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
520 dri = (payload[0] << 8) | payload[1];
522 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
529 if (Q >= 128 && frag_offset == 0) {
534 * 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
535 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
536 * | MBZ | Precision | Length |
537 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538 * | Quantization Table Data |
540 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542 precision = payload[1];
543 length = (payload[2] << 8) | payload[3];
545 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
548 if (Q == 255 && length == 0)
555 if (length > payload_len)
561 qtable = rtpjpegdepay->qtables[Q];
564 header_len += length;
565 payload_len -= length;
572 if (frag_offset == 0) {
575 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
579 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
580 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
581 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
582 gst_pad_set_caps (depayload->srcpad, outcaps);
583 gst_caps_unref (outcaps);
585 rtpjpegdepay->width = width;
586 rtpjpegdepay->height = height;
589 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
595 /* no quant table, see if we have one cached */
596 qtable = rtpjpegdepay->qtables[Q];
598 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
599 /* make and cache the table */
600 qtable = g_new (guint8, 128);
601 MakeTables (rtpjpegdepay, Q, qtable);
602 rtpjpegdepay->qtables[Q] = qtable;
604 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
606 /* all 8 bit quantizers */
613 /* max header length, should be big enough */
614 outbuf = gst_buffer_new_and_alloc (1000);
615 size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
616 width, height, qtable, precision, dri);
618 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
620 GST_BUFFER_SIZE (outbuf) = size;
622 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
625 /* take JPEG data, push in the adapter */
626 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
627 outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
628 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
631 if (gst_rtp_buffer_get_marker (buf)) {
636 /* last buffer take all data out of the adapter */
637 avail = gst_adapter_available (rtpjpegdepay->adapter);
638 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
640 /* take the last bytes of the jpeg data to see if there is an EOI
642 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
644 if (end[0] != 0xff && end[1] != 0xd9) {
645 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
647 /* no EOI marker, add one */
648 outbuf = gst_buffer_new_and_alloc (2);
649 data = GST_BUFFER_DATA (outbuf);
653 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
656 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
658 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
666 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
667 ("Empty Payload."), (NULL));
672 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
673 ("Invalid Dimension %dx%d.", width, height), (NULL));
678 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
684 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
686 return gst_element_register (plugin, "rtpjpegdepay",
687 GST_RANK_MARGINAL, GST_TYPE_RTP_JPEG_DEPAY);