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 /* elementfactory information */
36 static const GstElementDetails gst_rtp_jpegdepay_details =
37 GST_ELEMENT_DETAILS ("RTP JPEG depayloader",
38 "Codec/Depayloader/Network",
39 "Extracts JPEG video from RTP packets (RFC 2435)",
40 "Wim Taymans <wim.taymans@gmail.com>");
42 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
43 GST_STATIC_PAD_TEMPLATE ("src",
46 GST_STATIC_CAPS ("image/jpeg")
49 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
50 GST_STATIC_PAD_TEMPLATE ("sink",
53 GST_STATIC_CAPS ("application/x-rtp, "
54 "media = (string) \"video\", "
55 "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
56 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
57 /* optional SDP attributes */
59 * "a-framerate = (string) 0.00, "
60 * "x-framerate = (string) 0.00, "
61 * "x-dimensions = (string) \"1234,1234\", "
64 "media = (string) \"video\", "
65 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
66 "clock-rate = (int) 90000"
67 /* optional SDP attributes */
69 * "a-framerate = (string) 0.00, "
70 * "x-framerate = (string) 0.00, "
71 * "x-dimensions = (string) \"1234,1234\""
76 GST_BOILERPLATE (GstRtpJPEGDepay, gst_rtp_jpeg_depay, GstBaseRTPDepayload,
77 GST_TYPE_BASE_RTP_DEPAYLOAD);
79 static void gst_rtp_jpeg_depay_finalize (GObject * object);
81 static gboolean gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload,
83 static GstBuffer *gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload,
87 gst_rtp_jpeg_depay_base_init (gpointer klass)
89 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
91 gst_element_class_add_pad_template (element_class,
92 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
93 gst_element_class_add_pad_template (element_class,
94 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
96 gst_element_class_set_details (element_class, &gst_rtp_jpegdepay_details);
100 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
102 GObjectClass *gobject_class;
103 GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
105 gobject_class = (GObjectClass *) klass;
106 gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
108 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
110 parent_class = g_type_class_peek_parent (klass);
112 gstbasertpdepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
113 gstbasertpdepayload_class->process = gst_rtp_jpeg_depay_process;
115 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
116 "JPEG Video RTP Depayloader");
120 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay,
121 GstRtpJPEGDepayClass * klass)
123 rtpjpegdepay->adapter = gst_adapter_new ();
127 gst_rtp_jpeg_depay_finalize (GObject * object)
129 GstRtpJPEGDepay *rtpjpegdepay;
131 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
133 g_object_unref (rtpjpegdepay->adapter);
134 rtpjpegdepay->adapter = NULL;
136 G_OBJECT_CLASS (parent_class)->finalize (object);
140 * Table K.1 from JPEG spec.
142 static const int jpeg_luma_quantizer[64] = {
143 16, 11, 10, 16, 24, 40, 51, 61,
144 12, 12, 14, 19, 26, 58, 60, 55,
145 14, 13, 16, 24, 40, 57, 69, 56,
146 14, 17, 22, 29, 51, 87, 80, 62,
147 18, 22, 37, 56, 68, 109, 103, 77,
148 24, 35, 55, 64, 81, 104, 113, 92,
149 49, 64, 78, 87, 103, 121, 120, 101,
150 72, 92, 95, 98, 112, 100, 103, 99
154 * Table K.2 from JPEG spec.
156 static const int jpeg_chroma_quantizer[64] = {
157 17, 18, 24, 47, 99, 99, 99, 99,
158 18, 21, 26, 66, 99, 99, 99, 99,
159 24, 26, 56, 99, 99, 99, 99, 99,
160 47, 66, 99, 99, 99, 99, 99, 99,
161 99, 99, 99, 99, 99, 99, 99, 99,
162 99, 99, 99, 99, 99, 99, 99, 99,
163 99, 99, 99, 99, 99, 99, 99, 99,
164 99, 99, 99, 99, 99, 99, 99, 99
167 /* Call MakeTables with the Q factor and a guint8[128] return array
170 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
175 factor = CLAMP (Q, 1, 99);
180 Q = 200 - factor * 2;
182 for (i = 0; i < 64; i++) {
183 gint lq = (jpeg_luma_quantizer[i] * Q + 50) / 100;
184 gint cq = (jpeg_chroma_quantizer[i] * Q + 50) / 100;
186 /* Limit the quantizers to 1 <= q <= 255 */
187 qtable[i] = CLAMP (lq, 1, 255);
188 qtable[i + 64] = CLAMP (cq, 1, 255);
192 static const guint8 lum_dc_codelens[] = {
193 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
196 static const guint8 lum_dc_symbols[] = {
197 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
200 static const guint8 lum_ac_codelens[] = {
201 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
204 static const guint8 lum_ac_symbols[] = {
205 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
206 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
207 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
208 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
209 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
210 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
211 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
212 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
213 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
214 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
215 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
216 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
217 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
218 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
219 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
220 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
221 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
222 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
223 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
224 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
228 static const guint8 chm_dc_codelens[] = {
229 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
232 static const guint8 chm_dc_symbols[] = {
233 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
236 static const guint8 chm_ac_codelens[] = {
237 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
240 static const guint8 chm_ac_symbols[] = {
241 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
242 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
243 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
244 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
245 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
246 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
247 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
248 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
249 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
250 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
251 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
252 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
253 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
254 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
255 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
256 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
257 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
258 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
259 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
260 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
265 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
268 *p++ = 0xdb; /* DQT */
269 *p++ = 0; /* length msb */
270 *p++ = size + 3; /* length lsb */
272 memcpy (p, qt, size);
278 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
279 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
282 *p++ = 0xc4; /* DHT */
283 *p++ = 0; /* length msb */
284 *p++ = 3 + ncodes + nsymbols; /* length lsb */
285 *p++ = (tableClass << 4) | tableNo;
286 memcpy (p, codelens, ncodes);
288 memcpy (p, symbols, nsymbols);
295 MakeDRIHeader (guint8 * p, guint16 dri)
298 *p++ = 0xdd; /* DRI */
299 *p++ = 0x0; /* length msb */
300 *p++ = 4; /* length lsb */
301 *p++ = dri >> 8; /* dri msb */
302 *p++ = dri & 0xff; /* dri lsb */
309 * type, width, height: as supplied in RTP/JPEG header
310 * qt: quantization tables as either derived from
311 * the Q field using MakeTables() or as specified
313 * dri: restart interval in MCUs, or 0 if no restarts.
315 * p: pointer to return area
318 * The length of the generated headers.
320 * Generate a frame and scan headers that can be prepended to the
321 * RTP/JPEG data payload to produce a JPEG compressed image in
322 * interchange format (except for possible trailing garbage and
323 * absence of an EOI marker to terminate the scan).
326 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
327 guint precision, guint16 dri)
333 *p++ = 0xd8; /* SOI */
335 size = ((precision & 1) ? 128 : 64);
336 p = MakeQuantHeader (p, qt, size, 0);
339 size = ((precision & 2) ? 128 : 64);
340 p = MakeQuantHeader (p, qt, size, 1);
344 p = MakeDRIHeader (p, dri);
347 *p++ = 0xc0; /* SOF */
348 *p++ = 0; /* length msb */
349 *p++ = 17; /* length lsb */
350 *p++ = 8; /* 8-bit precision */
351 *p++ = height >> 8; /* height msb */
352 *p++ = height; /* height lsb */
353 *p++ = width >> 8; /* width msb */
354 *p++ = width; /* width lsb */
355 *p++ = 3; /* number of components */
356 *p++ = 0; /* comp 0 */
357 if ((type & 0x3f) == 0)
358 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
360 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
361 *p++ = 0; /* quant table 0 */
362 *p++ = 1; /* comp 1 */
363 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
364 *p++ = 1; /* quant table 1 */
365 *p++ = 2; /* comp 2 */
366 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
367 *p++ = 1; /* quant table 1 */
369 p = MakeHuffmanHeader (p, lum_dc_codelens,
370 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
371 p = MakeHuffmanHeader (p, lum_ac_codelens,
372 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
373 p = MakeHuffmanHeader (p, chm_dc_codelens,
374 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
375 p = MakeHuffmanHeader (p, chm_ac_codelens,
376 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
379 *p++ = 0xda; /* SOS */
380 *p++ = 0; /* length msb */
381 *p++ = 12; /* length lsb */
382 *p++ = 3; /* 3 components */
383 *p++ = 0; /* comp 0 */
384 *p++ = 0; /* huffman table 0 */
385 *p++ = 1; /* comp 1 */
386 *p++ = 0x11; /* huffman table 1 */
387 *p++ = 2; /* comp 2 */
388 *p++ = 0x11; /* huffman table 1 */
389 *p++ = 0; /* first DCT coeff */
390 *p++ = 63; /* last DCT coeff */
391 *p++ = 0; /* sucessive approx. */
397 gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
399 GstRtpJPEGDepay *rtpjpegdepay;
400 GstStructure *structure;
402 const gchar *media_attr;
404 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
406 structure = gst_caps_get_structure (caps, 0);
407 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
409 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
411 depayload->clock_rate = clock_rate;
414 rtpjpegdepay->width = 0;
415 rtpjpegdepay->height = 0;
416 rtpjpegdepay->media_width = 0;
417 rtpjpegdepay->media_height = 0;
418 rtpjpegdepay->frate_num = 0;
419 rtpjpegdepay->frate_denom = 1;
421 /* check for optional SDP attributes */
422 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
425 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
426 rtpjpegdepay->media_width = w;
427 rtpjpegdepay->media_height = h;
431 /* try to get a framerate */
432 media_attr = gst_structure_get_string (structure, "a-framerate");
434 media_attr = gst_structure_get_string (structure, "x-framerate");
440 /* convert the float to a fraction */
441 g_value_init (&src, G_TYPE_DOUBLE);
442 g_value_set_double (&src, atof (media_attr));
443 g_value_init (&dest, GST_TYPE_FRACTION);
444 g_value_transform (&src, &dest);
446 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
447 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
454 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
456 GstRtpJPEGDepay *rtpjpegdepay;
458 gint payload_len, header_len;
462 guint type, width, height;
463 guint16 dri, precision, length;
466 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
468 if (GST_BUFFER_IS_DISCONT (buf)) {
469 gst_adapter_clear (rtpjpegdepay->adapter);
472 payload_len = gst_rtp_buffer_get_payload_len (buf);
477 payload = gst_rtp_buffer_get_payload (buf);
481 * 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
482 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
483 * | Type-specific | Fragment Offset |
484 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
485 * | Type | Q | Width | Height |
486 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
488 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
491 width = payload[6] * 8;
492 height = payload[7] * 8;
494 /* allow frame dimensions > 2040, passed in SDP session or media attributes
495 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
497 width = rtpjpegdepay->media_width;
500 height = rtpjpegdepay->media_height;
502 if (width == 0 || height == 0)
503 goto invalid_dimension;
505 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
506 frag_offset, type, Q, width, height);
518 * 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
519 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
520 * | Restart Interval |F|L| Restart Count |
521 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523 dri = (payload[0] << 8) | payload[1];
525 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
532 if (Q >= 128 && frag_offset == 0) {
537 * 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
538 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539 * | MBZ | Precision | Length |
540 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541 * | Quantization Table Data |
543 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
545 precision = payload[1];
546 length = (payload[2] << 8) | payload[3];
548 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
551 if (Q == 255 && length == 0)
558 if (length > payload_len)
564 qtable = rtpjpegdepay->qtables[Q];
567 header_len += length;
568 payload_len -= length;
575 if (frag_offset == 0) {
578 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
582 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
583 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
584 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
585 gst_pad_set_caps (depayload->srcpad, outcaps);
586 gst_caps_unref (outcaps);
588 rtpjpegdepay->width = width;
589 rtpjpegdepay->height = height;
592 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
598 /* no quant table, see if we have one cached */
599 qtable = rtpjpegdepay->qtables[Q];
601 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
602 /* make and cache the table */
603 qtable = g_new (guint8, 128);
604 MakeTables (rtpjpegdepay, Q, qtable);
605 rtpjpegdepay->qtables[Q] = qtable;
607 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
609 /* all 8 bit quantizers */
616 /* max header length, should be big enough */
617 outbuf = gst_buffer_new_and_alloc (1000);
618 size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
619 width, height, qtable, precision, dri);
621 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
623 GST_BUFFER_SIZE (outbuf) = size;
625 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
628 /* take JPEG data, push in the adapter */
629 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
630 outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
631 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
634 if (gst_rtp_buffer_get_marker (buf)) {
639 /* last buffer take all data out of the adapter */
640 avail = gst_adapter_available (rtpjpegdepay->adapter);
641 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
643 /* take the last bytes of the jpeg data to see if there is an EOI
645 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
647 if (end[0] != 0xff && end[1] != 0xd9) {
648 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
650 /* no EOI marker, add one */
651 outbuf = gst_buffer_new_and_alloc (2);
652 data = GST_BUFFER_DATA (outbuf);
656 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
659 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
661 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
669 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
670 ("Empty Payload."), (NULL));
675 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
676 ("Invalid Dimension %dx%d.", width, height), (NULL));
681 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
687 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
689 return gst_element_register (plugin, "rtpjpegdepay",
690 GST_RANK_MARGINAL, GST_TYPE_RTP_JPEG_DEPAY);