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