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