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 gstbasertpdepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
111 gstbasertpdepayload_class->process = gst_rtp_jpeg_depay_process;
113 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
114 "JPEG Video RTP Depayloader");
118 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay,
119 GstRtpJPEGDepayClass * klass)
121 rtpjpegdepay->adapter = gst_adapter_new ();
125 gst_rtp_jpeg_depay_finalize (GObject * object)
127 GstRtpJPEGDepay *rtpjpegdepay;
129 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
131 g_object_unref (rtpjpegdepay->adapter);
132 rtpjpegdepay->adapter = NULL;
134 G_OBJECT_CLASS (parent_class)->finalize (object);
138 * Table K.1 from JPEG spec.
140 static const int jpeg_luma_quantizer[64] = {
141 16, 11, 10, 16, 24, 40, 51, 61,
142 12, 12, 14, 19, 26, 58, 60, 55,
143 14, 13, 16, 24, 40, 57, 69, 56,
144 14, 17, 22, 29, 51, 87, 80, 62,
145 18, 22, 37, 56, 68, 109, 103, 77,
146 24, 35, 55, 64, 81, 104, 113, 92,
147 49, 64, 78, 87, 103, 121, 120, 101,
148 72, 92, 95, 98, 112, 100, 103, 99
152 * Table K.2 from JPEG spec.
154 static const int jpeg_chroma_quantizer[64] = {
155 17, 18, 24, 47, 99, 99, 99, 99,
156 18, 21, 26, 66, 99, 99, 99, 99,
157 24, 26, 56, 99, 99, 99, 99, 99,
158 47, 66, 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,
162 99, 99, 99, 99, 99, 99, 99, 99
165 /* Call MakeTables with the Q factor and a guint8[128] return array
168 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
173 factor = CLAMP (Q, 1, 99);
178 Q = 200 - factor * 2;
180 for (i = 0; i < 64; i++) {
181 gint lq = (jpeg_luma_quantizer[i] * Q + 50) / 100;
182 gint cq = (jpeg_chroma_quantizer[i] * Q + 50) / 100;
184 /* Limit the quantizers to 1 <= q <= 255 */
185 qtable[i] = CLAMP (lq, 1, 255);
186 qtable[i + 64] = CLAMP (cq, 1, 255);
190 static const guint8 lum_dc_codelens[] = {
191 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
194 static const guint8 lum_dc_symbols[] = {
195 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
198 static const guint8 lum_ac_codelens[] = {
199 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
202 static const guint8 lum_ac_symbols[] = {
203 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
204 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
205 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
206 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
207 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
208 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
209 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
210 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
211 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
212 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
213 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
214 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
215 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
216 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
217 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
218 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
219 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
220 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
221 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
222 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
226 static const guint8 chm_dc_codelens[] = {
227 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
230 static const guint8 chm_dc_symbols[] = {
231 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
234 static const guint8 chm_ac_codelens[] = {
235 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
238 static const guint8 chm_ac_symbols[] = {
239 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
240 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
241 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
242 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
243 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
244 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
245 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
246 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
247 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
248 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
249 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
250 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
251 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
252 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
253 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
254 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
255 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
256 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
257 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
258 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
263 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
266 *p++ = 0xdb; /* DQT */
267 *p++ = 0; /* length msb */
268 *p++ = size + 3; /* length lsb */
270 memcpy (p, qt, size);
276 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
277 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
280 *p++ = 0xc4; /* DHT */
281 *p++ = 0; /* length msb */
282 *p++ = 3 + ncodes + nsymbols; /* length lsb */
283 *p++ = (tableClass << 4) | tableNo;
284 memcpy (p, codelens, ncodes);
286 memcpy (p, symbols, nsymbols);
293 MakeDRIHeader (guint8 * p, guint16 dri)
296 *p++ = 0xdd; /* DRI */
297 *p++ = 0x0; /* length msb */
298 *p++ = 4; /* length lsb */
299 *p++ = dri >> 8; /* dri msb */
300 *p++ = dri & 0xff; /* dri lsb */
307 * type, width, height: as supplied in RTP/JPEG header
308 * qt: quantization tables as either derived from
309 * the Q field using MakeTables() or as specified
311 * dri: restart interval in MCUs, or 0 if no restarts.
313 * p: pointer to return area
316 * The length of the generated headers.
318 * Generate a frame and scan headers that can be prepended to the
319 * RTP/JPEG data payload to produce a JPEG compressed image in
320 * interchange format (except for possible trailing garbage and
321 * absence of an EOI marker to terminate the scan).
324 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
325 guint precision, guint16 dri)
331 *p++ = 0xd8; /* SOI */
333 size = ((precision & 1) ? 128 : 64);
334 p = MakeQuantHeader (p, qt, size, 0);
337 size = ((precision & 2) ? 128 : 64);
338 p = MakeQuantHeader (p, qt, size, 1);
342 p = MakeDRIHeader (p, dri);
345 *p++ = 0xc0; /* SOF */
346 *p++ = 0; /* length msb */
347 *p++ = 17; /* length lsb */
348 *p++ = 8; /* 8-bit precision */
349 *p++ = height >> 8; /* height msb */
350 *p++ = height; /* height lsb */
351 *p++ = width >> 8; /* width msb */
352 *p++ = width; /* width lsb */
353 *p++ = 3; /* number of components */
354 *p++ = 0; /* comp 0 */
355 if ((type & 0x3f) == 0)
356 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
358 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
359 *p++ = 0; /* quant table 0 */
360 *p++ = 1; /* comp 1 */
361 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
362 *p++ = 1; /* quant table 1 */
363 *p++ = 2; /* comp 2 */
364 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
365 *p++ = 1; /* quant table 1 */
367 p = MakeHuffmanHeader (p, lum_dc_codelens,
368 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
369 p = MakeHuffmanHeader (p, lum_ac_codelens,
370 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
371 p = MakeHuffmanHeader (p, chm_dc_codelens,
372 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
373 p = MakeHuffmanHeader (p, chm_ac_codelens,
374 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
377 *p++ = 0xda; /* SOS */
378 *p++ = 0; /* length msb */
379 *p++ = 12; /* length lsb */
380 *p++ = 3; /* 3 components */
381 *p++ = 0; /* comp 0 */
382 *p++ = 0; /* huffman table 0 */
383 *p++ = 1; /* comp 1 */
384 *p++ = 0x11; /* huffman table 1 */
385 *p++ = 2; /* comp 2 */
386 *p++ = 0x11; /* huffman table 1 */
387 *p++ = 0; /* first DCT coeff */
388 *p++ = 63; /* last DCT coeff */
389 *p++ = 0; /* sucessive approx. */
395 gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
397 GstRtpJPEGDepay *rtpjpegdepay;
398 GstStructure *structure;
400 const gchar *media_attr;
402 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
404 structure = gst_caps_get_structure (caps, 0);
405 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
407 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
409 depayload->clock_rate = clock_rate;
412 rtpjpegdepay->width = 0;
413 rtpjpegdepay->height = 0;
414 rtpjpegdepay->media_width = 0;
415 rtpjpegdepay->media_height = 0;
416 rtpjpegdepay->frate_num = 0;
417 rtpjpegdepay->frate_denom = 1;
419 /* check for optional SDP attributes */
420 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
423 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
424 rtpjpegdepay->media_width = w;
425 rtpjpegdepay->media_height = h;
429 /* try to get a framerate */
430 media_attr = gst_structure_get_string (structure, "a-framerate");
432 media_attr = gst_structure_get_string (structure, "x-framerate");
438 /* convert the float to a fraction */
439 g_value_init (&src, G_TYPE_DOUBLE);
440 g_value_set_double (&src, atof (media_attr));
441 g_value_init (&dest, GST_TYPE_FRACTION);
442 g_value_transform (&src, &dest);
444 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
445 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
452 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
454 GstRtpJPEGDepay *rtpjpegdepay;
456 gint payload_len, header_len;
460 guint type, width, height;
461 guint16 dri, precision, length;
464 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
466 if (GST_BUFFER_IS_DISCONT (buf)) {
467 gst_adapter_clear (rtpjpegdepay->adapter);
470 payload_len = gst_rtp_buffer_get_payload_len (buf);
475 payload = gst_rtp_buffer_get_payload (buf);
479 * 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
480 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
481 * | Type-specific | Fragment Offset |
482 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
483 * | Type | Q | Width | Height |
484 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
486 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
489 width = payload[6] * 8;
490 height = payload[7] * 8;
492 /* allow frame dimensions > 2040, passed in SDP session or media attributes
493 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
495 width = rtpjpegdepay->media_width;
498 height = rtpjpegdepay->media_height;
500 if (width == 0 || height == 0)
501 goto invalid_dimension;
503 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
504 frag_offset, type, Q, width, height);
516 * 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
517 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518 * | Restart Interval |F|L| Restart Count |
519 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
521 dri = (payload[0] << 8) | payload[1];
523 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
530 if (Q >= 128 && frag_offset == 0) {
535 * 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
536 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537 * | MBZ | Precision | Length |
538 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539 * | Quantization Table Data |
541 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
543 precision = payload[1];
544 length = (payload[2] << 8) | payload[3];
546 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
549 if (Q == 255 && length == 0)
556 if (length > payload_len)
562 qtable = rtpjpegdepay->qtables[Q];
565 header_len += length;
566 payload_len -= length;
573 if (frag_offset == 0) {
576 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
580 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
581 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
582 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
583 gst_pad_set_caps (depayload->srcpad, outcaps);
584 gst_caps_unref (outcaps);
586 rtpjpegdepay->width = width;
587 rtpjpegdepay->height = height;
590 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
596 /* no quant table, see if we have one cached */
597 qtable = rtpjpegdepay->qtables[Q];
599 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
600 /* make and cache the table */
601 qtable = g_new (guint8, 128);
602 MakeTables (rtpjpegdepay, Q, qtable);
603 rtpjpegdepay->qtables[Q] = qtable;
605 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
607 /* all 8 bit quantizers */
614 /* max header length, should be big enough */
615 outbuf = gst_buffer_new_and_alloc (1000);
616 size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
617 width, height, qtable, precision, dri);
619 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
621 GST_BUFFER_SIZE (outbuf) = size;
623 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
626 /* take JPEG data, push in the adapter */
627 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
628 outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
629 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
632 if (gst_rtp_buffer_get_marker (buf)) {
637 /* last buffer take all data out of the adapter */
638 avail = gst_adapter_available (rtpjpegdepay->adapter);
639 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
641 /* take the last bytes of the jpeg data to see if there is an EOI
643 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
645 if (end[0] != 0xff && end[1] != 0xd9) {
646 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
648 /* no EOI marker, add one */
649 outbuf = gst_buffer_new_and_alloc (2);
650 data = GST_BUFFER_DATA (outbuf);
654 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
657 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
659 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
667 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
668 ("Empty Payload."), (NULL));
673 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
674 ("Invalid Dimension %dx%d.", width, height), (NULL));
679 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
685 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
687 return gst_element_register (plugin, "rtpjpegdepay",
688 GST_RANK_MARGINAL, GST_TYPE_RTP_JPEG_DEPAY);