jpegdepay: use attributes for extra properties
[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         /* optional SDP attributes */
55         /*
56          * "a-framerate = (string) 0.00, "
57          * "x-framerate = (string) 0.00, "
58          * "x-dimensions = (string) \"1234,1234\", "
59          */
60         "application/x-rtp, "
61         "media = (string) \"video\", "
62         "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
63         "clock-rate = (int) 90000"
64         /* optional SDP attributes */
65         /*
66          * "a-framerate = (string) 0.00, "
67          * "x-framerate = (string) 0.00, "
68          * "x-dimensions = (string) \"1234,1234\""
69          */
70     )
71     );
72
73 GST_BOILERPLATE (GstRtpJPEGDepay, gst_rtp_jpeg_depay, GstBaseRTPDepayload,
74     GST_TYPE_BASE_RTP_DEPAYLOAD);
75
76 static void gst_rtp_jpeg_depay_finalize (GObject * object);
77
78 static gboolean gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload,
79     GstCaps * caps);
80 static GstBuffer *gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload,
81     GstBuffer * buf);
82
83 static void
84 gst_rtp_jpeg_depay_base_init (gpointer klass)
85 {
86   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
87
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));
92
93   gst_element_class_set_details (element_class, &gst_rtp_jpegdepay_details);
94 }
95
96 static void
97 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
98 {
99   GObjectClass *gobject_class;
100   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
101
102   gobject_class = (GObjectClass *) klass;
103   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
104
105   gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
106
107   parent_class = g_type_class_peek_parent (klass);
108
109   gstbasertpdepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
110   gstbasertpdepayload_class->process = gst_rtp_jpeg_depay_process;
111
112   GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
113       "JPEG Video RTP Depayloader");
114 }
115
116 static void
117 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay,
118     GstRtpJPEGDepayClass * klass)
119 {
120   rtpjpegdepay->adapter = gst_adapter_new ();
121 }
122
123 static void
124 gst_rtp_jpeg_depay_finalize (GObject * object)
125 {
126   GstRtpJPEGDepay *rtpjpegdepay;
127
128   rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
129
130   g_object_unref (rtpjpegdepay->adapter);
131   rtpjpegdepay->adapter = NULL;
132
133   G_OBJECT_CLASS (parent_class)->finalize (object);
134 }
135
136 /*
137  * Table K.1 from JPEG spec.
138  */
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
148 };
149
150 /*
151  * Table K.2 from JPEG spec.
152  */
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
162 };
163
164 /* Call MakeTables with the Q factor and a guint8[128] return array
165  */
166 static void
167 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
168 {
169   gint i;
170   guint factor;
171
172   factor = CLAMP (Q, 1, 99);
173
174   if (Q < 50)
175     Q = 5000 / factor;
176   else
177     Q = 200 - factor * 2;
178
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;
182
183     /* Limit the quantizers to 1 <= q <= 255 */
184     qtable[i] = CLAMP (lq, 1, 255);
185     qtable[i + 64] = CLAMP (cq, 1, 255);
186   }
187 }
188
189 static const guint8 lum_dc_codelens[] = {
190   0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
191 };
192
193 static const guint8 lum_dc_symbols[] = {
194   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
195 };
196
197 static const guint8 lum_ac_codelens[] = {
198   0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
199 };
200
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,
222   0xf9, 0xfa
223 };
224
225 static const guint8 chm_dc_codelens[] = {
226   0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
227 };
228
229 static const guint8 chm_dc_symbols[] = {
230   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
231 };
232
233 static const guint8 chm_ac_codelens[] = {
234   0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
235 };
236
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,
258   0xf9, 0xfa
259 };
260
261 static guint8 *
262 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
263 {
264   *p++ = 0xff;
265   *p++ = 0xdb;                  /* DQT */
266   *p++ = 0;                     /* length msb */
267   *p++ = size + 3;              /* length lsb */
268   *p++ = tableNo;
269   memcpy (p, qt, size);
270
271   return (p + size);
272 }
273
274 static guint8 *
275 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
276     const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
277 {
278   *p++ = 0xff;
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);
284   p += ncodes;
285   memcpy (p, symbols, nsymbols);
286   p += nsymbols;
287
288   return (p);
289 }
290
291 static guint8 *
292 MakeDRIHeader (guint8 * p, guint16 dri)
293 {
294   *p++ = 0xff;
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 */
300
301   return (p);
302 }
303
304 /*
305  *  Arguments:
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
309  *        in section 4.2.
310  *    dri: restart interval in MCUs, or 0 if no restarts.
311  *
312  *    p: pointer to return area
313  *
314  *  Return value:
315  *    The length of the generated headers.
316  *
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).
321  */
322 static guint
323 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
324     guint precision, guint16 dri)
325 {
326   guint8 *start = p;
327   gint size;
328
329   *p++ = 0xff;
330   *p++ = 0xd8;                  /* SOI */
331
332   size = ((precision & 1) ? 128 : 64);
333   p = MakeQuantHeader (p, qt, size, 0);
334   qt += size;
335
336   size = ((precision & 2) ? 128 : 64);
337   p = MakeQuantHeader (p, qt, size, 1);
338   qt += size;
339
340   if (dri != 0)
341     p = MakeDRIHeader (p, dri);
342
343   *p++ = 0xff;
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 */
356   else
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 */
365
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);
374
375   *p++ = 0xff;
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. */
389
390   return (p - start);
391 };
392
393 static gboolean
394 gst_rtp_jpeg_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
395 {
396   GstRtpJPEGDepay *rtpjpegdepay;
397   GstStructure *structure;
398   gint clock_rate;
399   const gchar *media_attr;
400
401   rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
402
403   structure = gst_caps_get_structure (caps, 0);
404   GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
405
406   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
407     clock_rate = 90000;
408   depayload->clock_rate = clock_rate;
409
410   /* reset defaults */
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;
417
418   /* check for optional SDP attributes */
419   if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
420     gint w, h;
421
422     if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
423       rtpjpegdepay->media_width = w;
424       rtpjpegdepay->media_height = h;
425     }
426   }
427
428   /* try to get a framerate */
429   media_attr = gst_structure_get_string (structure, "a-framerate");
430   if (!media_attr)
431     media_attr = gst_structure_get_string (structure, "x-framerate");
432
433   if (media_attr) {
434     GValue src = { 0 };
435     GValue dest = { 0 };
436
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);
442
443     rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
444     rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
445   }
446
447   return TRUE;
448 }
449
450 static GstBuffer *
451 gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
452 {
453   GstRtpJPEGDepay *rtpjpegdepay;
454   GstBuffer *outbuf;
455   gint payload_len, header_len;
456   guint8 *payload;
457   guint frag_offset;
458   gint Q;
459   guint type, width, height;
460   guint16 dri, precision, length;
461   guint8 *qtable;
462
463   rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
464
465   if (GST_BUFFER_IS_DISCONT (buf)) {
466     gst_adapter_clear (rtpjpegdepay->adapter);
467   }
468
469   payload_len = gst_rtp_buffer_get_payload_len (buf);
470
471   if (payload_len < 8)
472     goto empty_packet;
473
474   payload = gst_rtp_buffer_get_payload (buf);
475   header_len = 0;
476
477   /*  0                   1                   2                   3
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    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
484    */
485   frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
486   type = payload[4];
487   Q = payload[5];
488   width = payload[6] * 8;
489   height = payload[7] * 8;
490
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 */
493   if (!width)
494     width = rtpjpegdepay->media_width;
495
496   if (!height)
497     height = rtpjpegdepay->media_height;
498
499   if (width == 0 || height == 0)
500     goto invalid_dimension;
501
502   GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
503       frag_offset, type, Q, width, height);
504
505   header_len += 8;
506   payload += 8;
507   payload_len -= 8;
508
509   dri = 0;
510   if (type > 63) {
511     if (payload_len < 4)
512       goto empty_packet;
513
514     /*  0                   1                   2                   3
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      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
519      */
520     dri = (payload[0] << 8) | payload[1];
521
522     GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
523
524     payload += 4;
525     header_len += 4;
526     payload_len -= 4;
527   }
528
529   if (Q >= 128 && frag_offset == 0) {
530     if (payload_len < 4)
531       goto empty_packet;
532
533     /*  0                   1                   2                   3
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                    |
539      * |                              ...                              |
540      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541      */
542     precision = payload[1];
543     length = (payload[2] << 8) | payload[3];
544
545     GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
546         precision, length);
547
548     if (Q == 255 && length == 0)
549       goto empty_packet;
550
551     payload += 4;
552     header_len += 4;
553     payload_len -= 4;
554
555     if (length > payload_len)
556       goto empty_packet;
557
558     if (length > 0)
559       qtable = payload;
560     else
561       qtable = rtpjpegdepay->qtables[Q];
562
563     payload += length;
564     header_len += length;
565     payload_len -= length;
566   } else {
567     length = 0;
568     qtable = NULL;
569     precision = 0;
570   }
571
572   if (frag_offset == 0) {
573     guint size;
574
575     if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
576       GstCaps *outcaps;
577
578       outcaps =
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);
584
585       rtpjpegdepay->width = width;
586       rtpjpegdepay->height = height;
587     }
588
589     GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
590         length);
591
592     /* first packet */
593     if (length == 0) {
594       if (Q < 128) {
595         /* no quant table, see if we have one cached */
596         qtable = rtpjpegdepay->qtables[Q];
597         if (!qtable) {
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;
603         } else {
604           GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
605         }
606         /* all 8 bit quantizers */
607         precision = 0;
608       } else {
609         if (!qtable)
610           goto no_qtable;
611       }
612     }
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);
617
618     GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
619
620     GST_BUFFER_SIZE (outbuf) = size;
621
622     gst_adapter_push (rtpjpegdepay->adapter, outbuf);
623   }
624
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);
629   outbuf = NULL;
630
631   if (gst_rtp_buffer_get_marker (buf)) {
632     guint avail;
633     guint8 end[2];
634     guint8 *data;
635
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");
639
640     /* take the last bytes of the jpeg data to see if there is an EOI
641      * marker */
642     gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
643
644     if (end[0] != 0xff && end[1] != 0xd9) {
645       GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
646
647       /* no EOI marker, add one */
648       outbuf = gst_buffer_new_and_alloc (2);
649       data = GST_BUFFER_DATA (outbuf);
650       data[0] = 0xff;
651       data[1] = 0xd9;
652
653       gst_adapter_push (rtpjpegdepay->adapter, outbuf);
654       avail += 2;
655     }
656     outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
657
658     GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
659   }
660
661   return outbuf;
662
663   /* ERRORS */
664 empty_packet:
665   {
666     GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
667         ("Empty Payload."), (NULL));
668     return NULL;
669   }
670 invalid_dimension:
671   {
672     GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
673         ("Invalid Dimension %dx%d.", width, height), (NULL));
674     return NULL;
675   }
676 no_qtable:
677   {
678     GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
679     return NULL;
680   }
681 }
682
683 gboolean
684 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
685 {
686   return gst_element_register (plugin, "rtpjpegdepay",
687       GST_RANK_MARGINAL, GST_TYPE_RTP_JPEG_DEPAY);
688 }