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