01216adcd65b8dba7c36f8bb5e3e6ac4222048ff
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpjpegdepay.c
1 /* GStreamer
2  * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <gst/rtp/gstrtpbuffer.h>
25
26 #include <string.h>
27 #include "gstrtpjpegdepay.h"
28
29 GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
30 #define GST_CAT_DEFAULT (rtpjpegdepay_debug)
31
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>");
38
39 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
40 GST_STATIC_PAD_TEMPLATE ("src",
41     GST_PAD_SRC,
42     GST_PAD_ALWAYS,
43     GST_STATIC_CAPS ("image/jpeg")
44     );
45
46 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
47     GST_STATIC_PAD_TEMPLATE ("sink",
48     GST_PAD_SINK,
49     GST_PAD_ALWAYS,
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         "application/x-rtp, "
55         "media = (string) \"video\", "
56         "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
57         "clock-rate = (int) 90000")
58     );
59
60 GST_BOILERPLATE (GstRtpJPEGDepay, gst_rtp_jpeg_depay, GstBaseRTPDepayload,
61     GST_TYPE_BASE_RTP_DEPAYLOAD);
62
63 static void gst_rtp_jpeg_depay_finalize (GObject * object);
64
65 static gboolean gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload,
66     GstCaps * caps);
67 static GstBuffer *gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload,
68     GstBuffer * buf);
69
70 static void
71 gst_rtp_jpeg_depay_base_init (gpointer klass)
72 {
73   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
74
75   gst_element_class_add_pad_template (element_class,
76       gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
77   gst_element_class_add_pad_template (element_class,
78       gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
79
80   gst_element_class_set_details (element_class, &gst_rtp_jpegdepay_details);
81 }
82
83 static void
84 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
85 {
86   GObjectClass *gobject_class;
87   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
88
89   gobject_class = (GObjectClass *) klass;
90   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
91
92   gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
93
94   parent_class = g_type_class_peek_parent (klass);
95
96   gstbasertpdepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
97   gstbasertpdepayload_class->process = gst_rtp_jpeg_depay_process;
98
99   GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
100       "JPEG Video RTP Depayloader");
101 }
102
103 static void
104 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay,
105     GstRtpJPEGDepayClass * klass)
106 {
107   rtpjpegdepay->adapter = gst_adapter_new ();
108 }
109
110 static void
111 gst_rtp_jpeg_depay_finalize (GObject * object)
112 {
113   GstRtpJPEGDepay *rtpjpegdepay;
114
115   rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
116
117   g_object_unref (rtpjpegdepay->adapter);
118   rtpjpegdepay->adapter = NULL;
119
120   G_OBJECT_CLASS (parent_class)->finalize (object);
121 }
122
123 /*
124  * Table K.1 from JPEG spec.
125  */
126 static const int jpeg_luma_quantizer[64] = {
127   16, 11, 10, 16, 24, 40, 51, 61,
128   12, 12, 14, 19, 26, 58, 60, 55,
129   14, 13, 16, 24, 40, 57, 69, 56,
130   14, 17, 22, 29, 51, 87, 80, 62,
131   18, 22, 37, 56, 68, 109, 103, 77,
132   24, 35, 55, 64, 81, 104, 113, 92,
133   49, 64, 78, 87, 103, 121, 120, 101,
134   72, 92, 95, 98, 112, 100, 103, 99
135 };
136
137 /*
138  * Table K.2 from JPEG spec.
139  */
140 static const int jpeg_chroma_quantizer[64] = {
141   17, 18, 24, 47, 99, 99, 99, 99,
142   18, 21, 26, 66, 99, 99, 99, 99,
143   24, 26, 56, 99, 99, 99, 99, 99,
144   47, 66, 99, 99, 99, 99, 99, 99,
145   99, 99, 99, 99, 99, 99, 99, 99,
146   99, 99, 99, 99, 99, 99, 99, 99,
147   99, 99, 99, 99, 99, 99, 99, 99,
148   99, 99, 99, 99, 99, 99, 99, 99
149 };
150
151 /* Call MakeTables with the Q factor and a guint8[128] return array
152  */
153 static void
154 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
155 {
156   gint i;
157   guint factor;
158
159   factor = CLAMP (Q, 1, 99);
160
161   if (Q < 50)
162     Q = 5000 / factor;
163   else
164     Q = 200 - factor * 2;
165
166   for (i = 0; i < 64; i++) {
167     gint lq = (jpeg_luma_quantizer[i] * Q + 50) / 100;
168     gint cq = (jpeg_chroma_quantizer[i] * Q + 50) / 100;
169
170     /* Limit the quantizers to 1 <= q <= 255 */
171     qtable[i] = CLAMP (lq, 1, 255);
172     qtable[i + 64] = CLAMP (cq, 1, 255);
173   }
174 }
175
176 static const guint8 lum_dc_codelens[] = {
177   0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
178 };
179
180 static const guint8 lum_dc_symbols[] = {
181   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
182 };
183
184 static const guint8 lum_ac_codelens[] = {
185   0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
186 };
187
188 static const guint8 lum_ac_symbols[] = {
189   0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
190   0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
191   0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
192   0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
193   0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
194   0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
195   0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
196   0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
197   0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
198   0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
199   0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
200   0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
201   0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
202   0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
203   0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
204   0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
205   0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
206   0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
207   0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
208   0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
209   0xf9, 0xfa
210 };
211
212 static const guint8 chm_dc_codelens[] = {
213   0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
214 };
215
216 static const guint8 chm_dc_symbols[] = {
217   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
218 };
219
220 static const guint8 chm_ac_codelens[] = {
221   0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
222 };
223
224 static const guint8 chm_ac_symbols[] = {
225   0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
226   0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
227   0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
228   0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
229   0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
230   0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
231   0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
232   0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
233   0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
234   0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
235   0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
236   0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
237   0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
238   0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
239   0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
240   0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
241   0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
242   0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
243   0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
244   0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
245   0xf9, 0xfa
246 };
247
248 static guint8 *
249 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
250 {
251   *p++ = 0xff;
252   *p++ = 0xdb;                  /* DQT */
253   *p++ = 0;                     /* length msb */
254   *p++ = size + 3;              /* length lsb */
255   *p++ = tableNo;
256   memcpy (p, qt, size);
257
258   return (p + size);
259 }
260
261 static guint8 *
262 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
263     const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
264 {
265   *p++ = 0xff;
266   *p++ = 0xc4;                  /* DHT */
267   *p++ = 0;                     /* length msb */
268   *p++ = 3 + ncodes + nsymbols; /* length lsb */
269   *p++ = (tableClass << 4) | tableNo;
270   memcpy (p, codelens, ncodes);
271   p += ncodes;
272   memcpy (p, symbols, nsymbols);
273   p += nsymbols;
274
275   return (p);
276 }
277
278 static guint8 *
279 MakeDRIHeader (guint8 * p, guint16 dri)
280 {
281   *p++ = 0xff;
282   *p++ = 0xdd;                  /* DRI */
283   *p++ = 0x0;                   /* length msb */
284   *p++ = 4;                     /* length lsb */
285   *p++ = dri >> 8;              /* dri msb */
286   *p++ = dri & 0xff;            /* dri lsb */
287
288   return (p);
289 }
290
291 /*
292  *  Arguments:
293  *    type, width, height: as supplied in RTP/JPEG header
294  *    qt: quantization tables as either derived from
295  *        the Q field using MakeTables() or as specified
296  *        in section 4.2.
297  *    dri: restart interval in MCUs, or 0 if no restarts.
298  *
299  *    p: pointer to return area
300  *
301  *  Return value:
302  *    The length of the generated headers.
303  *
304  *    Generate a frame and scan headers that can be prepended to the
305  *    RTP/JPEG data payload to produce a JPEG compressed image in
306  *    interchange format (except for possible trailing garbage and
307  *    absence of an EOI marker to terminate the scan).
308  */
309 static guint
310 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
311     guint precision, guint16 dri)
312 {
313   guint8 *start = p;
314   gint size;
315
316   *p++ = 0xff;
317   *p++ = 0xd8;                  /* SOI */
318
319   size = ((precision & 1) ? 128 : 64);
320   p = MakeQuantHeader (p, qt, size, 0);
321   qt += size;
322
323   size = ((precision & 2) ? 128 : 64);
324   p = MakeQuantHeader (p, qt, size, 1);
325   qt += size;
326
327   if (dri != 0)
328     p = MakeDRIHeader (p, dri);
329
330   *p++ = 0xff;
331   *p++ = 0xc0;                  /* SOF */
332   *p++ = 0;                     /* length msb */
333   *p++ = 17;                    /* length lsb */
334   *p++ = 8;                     /* 8-bit precision */
335   *p++ = height >> 8;           /* height msb */
336   *p++ = height;                /* height lsb */
337   *p++ = width >> 8;            /* width msb */
338   *p++ = width;                 /* width lsb */
339   *p++ = 3;                     /* number of components */
340   *p++ = 0;                     /* comp 0 */
341   if ((type & 0x3f) == 0)
342     *p++ = 0x21;                /* hsamp = 2, vsamp = 1 */
343   else
344     *p++ = 0x22;                /* hsamp = 2, vsamp = 2 */
345   *p++ = 0;                     /* quant table 0 */
346   *p++ = 1;                     /* comp 1 */
347   *p++ = 0x11;                  /* hsamp = 1, vsamp = 1 */
348   *p++ = 1;                     /* quant table 1 */
349   *p++ = 2;                     /* comp 2 */
350   *p++ = 0x11;                  /* hsamp = 1, vsamp = 1 */
351   *p++ = 1;                     /* quant table 1 */
352
353   p = MakeHuffmanHeader (p, lum_dc_codelens,
354       sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
355   p = MakeHuffmanHeader (p, lum_ac_codelens,
356       sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
357   p = MakeHuffmanHeader (p, chm_dc_codelens,
358       sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
359   p = MakeHuffmanHeader (p, chm_ac_codelens,
360       sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
361
362   *p++ = 0xff;
363   *p++ = 0xda;                  /* SOS */
364   *p++ = 0;                     /* length msb */
365   *p++ = 12;                    /* length lsb */
366   *p++ = 3;                     /* 3 components */
367   *p++ = 0;                     /* comp 0 */
368   *p++ = 0;                     /* huffman table 0 */
369   *p++ = 1;                     /* comp 1 */
370   *p++ = 0x11;                  /* huffman table 1 */
371   *p++ = 2;                     /* comp 2 */
372   *p++ = 0x11;                  /* huffman table 1 */
373   *p++ = 0;                     /* first DCT coeff */
374   *p++ = 63;                    /* last DCT coeff */
375   *p++ = 0;                     /* sucessive approx. */
376
377   return (p - start);
378 };
379
380 static gboolean
381 gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
382 {
383   GstRtpJPEGDepay *rtpjpegdepay;
384   GstStructure *structure;
385   gint clock_rate;
386
387   rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
388
389   structure = gst_caps_get_structure (caps, 0);
390
391   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
392     clock_rate = 90000;
393   depayload->clock_rate = clock_rate;
394
395   rtpjpegdepay->width = 0;
396   rtpjpegdepay->height = 0;
397
398   return TRUE;
399 }
400
401 static GstBuffer *
402 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
403 {
404   GstRtpJPEGDepay *rtpjpegdepay;
405   GstBuffer *outbuf;
406   gint payload_len, header_len;
407   guint8 *payload;
408   guint frag_offset;
409   gint Q;
410   guint type, width, height;
411   guint16 dri, precision, length;
412   guint8 *qtable;
413
414   rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
415
416   if (GST_BUFFER_IS_DISCONT (buf)) {
417     gst_adapter_clear (rtpjpegdepay->adapter);
418   }
419
420   payload_len = gst_rtp_buffer_get_payload_len (buf);
421
422   if (payload_len < 8)
423     goto empty_packet;
424
425   payload = gst_rtp_buffer_get_payload (buf);
426   header_len = 0;
427
428   /*  0                   1                   2                   3
429    *  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
430    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
431    * | Type-specific |              Fragment Offset                  |
432    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433    * |      Type     |       Q       |     Width     |     Height    |
434    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435    */
436   frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
437   type = payload[4];
438   Q = payload[5];
439   width = payload[6] * 8;
440   height = payload[7] * 8;
441
442   if (width == 0 || height == 0)
443     goto invalid_dimension;
444
445   GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
446       frag_offset, type, Q, width, height);
447
448   header_len += 8;
449   payload += 8;
450   payload_len -= 8;
451
452   dri = 0;
453   if (type > 63) {
454     if (payload_len < 4)
455       goto empty_packet;
456
457     /*  0                   1                   2                   3
458      *  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
459      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
460      * |       Restart Interval        |F|L|       Restart Count       |
461      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
462      */
463     dri = (payload[0] << 8) | payload[1];
464
465     GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
466
467     payload += 4;
468     header_len += 4;
469     payload_len -= 4;
470   }
471
472   if (Q >= 128 && frag_offset == 0) {
473     if (payload_len < 4)
474       goto empty_packet;
475
476     /*  0                   1                   2                   3
477      *  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
478      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
479      * |      MBZ      |   Precision   |             Length            |
480      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
481      * |                    Quantization Table Data                    |
482      * |                              ...                              |
483      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
484      */
485     precision = payload[1];
486     length = (payload[2] << 8) | payload[3];
487
488     GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
489         precision, length);
490
491     if (Q == 255 && length == 0)
492       goto empty_packet;
493
494     payload += 4;
495     header_len += 4;
496     payload_len -= 4;
497
498     if (length > payload_len)
499       goto empty_packet;
500
501     if (length > 0)
502       qtable = payload;
503     else
504       qtable = rtpjpegdepay->qtables[Q];
505
506     payload += length;
507     header_len += length;
508     payload_len -= length;
509   } else {
510     length = 0;
511     qtable = NULL;
512     precision = 0;
513   }
514
515   if (frag_offset == 0) {
516     guint size;
517
518     if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
519       GstCaps *outcaps;
520
521       outcaps =
522           gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION, 0,
523           1, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
524       gst_pad_set_caps (depayload->srcpad, outcaps);
525       gst_caps_unref (outcaps);
526
527       rtpjpegdepay->width = width;
528       rtpjpegdepay->height = height;
529     }
530
531     GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
532         length);
533
534     /* first packet */
535     if (length == 0) {
536       if (Q < 128) {
537         /* no quant table, see if we have one cached */
538         qtable = rtpjpegdepay->qtables[Q];
539         if (!qtable) {
540           GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
541           /* make and cache the table */
542           qtable = g_new (guint8, 128);
543           MakeTables (rtpjpegdepay, Q, qtable);
544           rtpjpegdepay->qtables[Q] = qtable;
545         } else {
546           GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
547         }
548         /* all 8 bit quantizers */
549         precision = 0;
550       } else {
551         if (!qtable)
552           goto no_qtable;
553       }
554     }
555     /* max header length, should be big enough */
556     outbuf = gst_buffer_new_and_alloc (1000);
557     size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
558         width, height, qtable, precision, dri);
559
560     GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
561
562     GST_BUFFER_SIZE (outbuf) = size;
563
564     gst_adapter_push (rtpjpegdepay->adapter, outbuf);
565   }
566
567   /* take JPEG data, push in the adapter */
568   GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
569   outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
570   gst_adapter_push (rtpjpegdepay->adapter, outbuf);
571   outbuf = NULL;
572
573   if (gst_rtp_buffer_get_marker (buf)) {
574     guint avail;
575     guint8 end[2];
576     guint8 *data;
577
578     /* last buffer take all data out of the adapter */
579     avail = gst_adapter_available (rtpjpegdepay->adapter);
580     GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
581
582     /* take the last bytes of the jpeg data to see if there is an EOI
583      * marker */
584     gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
585
586     if (end[0] != 0xff && end[1] != 0xd9) {
587       GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
588
589       /* no EOI marker, add one */
590       outbuf = gst_buffer_new_and_alloc (2);
591       data = GST_BUFFER_DATA (outbuf);
592       data[0] = 0xff;
593       data[1] = 0xd9;
594
595       gst_adapter_push (rtpjpegdepay->adapter, outbuf);
596       avail += 2;
597     }
598     outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
599
600     GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
601   }
602
603   return outbuf;
604
605   /* ERRORS */
606 empty_packet:
607   {
608     GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
609         ("Empty Payload."), (NULL));
610     return NULL;
611   }
612 invalid_dimension:
613   {
614     GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
615         ("Invalid Dimension %dx%d.", width, height), (NULL));
616     return NULL;
617   }
618 no_qtable:
619   {
620     GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
621     return NULL;
622   }
623 }
624
625 gboolean
626 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
627 {
628   return gst_element_register (plugin, "rtpjpegdepay",
629       GST_RANK_MARGINAL, GST_TYPE_RTP_JPEG_DEPAY);
630 }