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