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 "gstrtpjpegdepay.h"
32 #include "gstrtputils.h"
33 
34 GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
35 #define GST_CAT_DEFAULT (rtpjpegdepay_debug)
36 
37 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
38 GST_STATIC_PAD_TEMPLATE ("src",
39     GST_PAD_SRC,
40     GST_PAD_ALWAYS,
41     GST_STATIC_CAPS ("image/jpeg")
42     );
43 
44 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
45     GST_STATIC_PAD_TEMPLATE ("sink",
46     GST_PAD_SINK,
47     GST_PAD_ALWAYS,
48     GST_STATIC_CAPS ("application/x-rtp, "
49         "media = (string) \"video\", "
50         "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
51         /* optional SDP attributes */
52         /*
53          * "a-framerate = (string) 0.00, "
54          * "x-framerate = (string) 0.00, "
55          * "x-dimensions = (string) \"1234,1234\", "
56          */
57         "application/x-rtp, "
58         "media = (string) \"video\", "
59         "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
60         "clock-rate = (int) 90000"
61         /* optional SDP attributes */
62         /*
63          * "a-framerate = (string) 0.00, "
64          * "x-framerate = (string) 0.00, "
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     GstRTPBuffer * rtp);
83 
84 static void
gst_rtp_jpeg_depay_class_init(GstRtpJPEGDepayClass * klass)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_static_pad_template (gstelement_class,
98       &gst_rtp_jpeg_depay_src_template);
99   gst_element_class_add_static_pad_template (gstelement_class,
100       &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_rtp_packet = 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
gst_rtp_jpeg_depay_init(GstRtpJPEGDepay * rtpjpegdepay)117 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
118 {
119   rtpjpegdepay->adapter = gst_adapter_new ();
120 }
121 
122 static void
gst_rtp_jpeg_depay_reset(GstRtpJPEGDepay * depay)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
gst_rtp_jpeg_depay_finalize(GObject * object)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
MakeTables(GstRtpJPEGDepay * rtpjpegdepay,gint Q,guint8 qtable[128])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 *
MakeQuantHeader(guint8 * p,guint8 * qt,gint size,gint tableNo)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 *
MakeHuffmanHeader(guint8 * p,const guint8 * codelens,int ncodes,const guint8 * symbols,int nsymbols,int tableNo,int tableClass)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 *
MakeDRIHeader(guint8 * p,guint16 dri)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
MakeHeaders(guint8 * p,int type,int width,int height,guint8 * qt,guint precision,guint16 dri)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
gst_rtp_jpeg_depay_setcaps(GstRTPBaseDepayload * depayload,GstCaps * caps)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   /* try to get a framerate */
462   media_attr = gst_structure_get_string (structure, "a-framerate");
463   if (!media_attr)
464     media_attr = gst_structure_get_string (structure, "x-framerate");
465 
466   if (media_attr) {
467     GValue src = { 0 };
468     GValue dest = { 0 };
469     gchar *s;
470 
471     /* canonicalise floating point string so we can handle framerate strings
472      * in the form "24.930" or "24,930" irrespective of the current locale */
473     s = g_strdup (media_attr);
474     g_strdelimit (s, ",", '.');
475 
476     /* convert the float to a fraction */
477     g_value_init (&src, G_TYPE_DOUBLE);
478     g_value_set_double (&src, g_ascii_strtod (s, NULL));
479     g_value_init (&dest, GST_TYPE_FRACTION);
480     g_value_transform (&src, &dest);
481 
482     rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
483     rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
484 
485     g_free (s);
486   }
487 
488   return TRUE;
489 }
490 
491 static GstBuffer *
gst_rtp_jpeg_depay_process(GstRTPBaseDepayload * depayload,GstRTPBuffer * rtp)492 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
493 {
494   GstRtpJPEGDepay *rtpjpegdepay;
495   GstBuffer *outbuf;
496   gint payload_len, header_len;
497   guint8 *payload;
498   guint frag_offset;
499   gint Q;
500   guint type, width, height;
501   guint16 dri, precision, length;
502   guint8 *qtable;
503 
504   rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
505 
506   if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
507     GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter");
508     gst_adapter_clear (rtpjpegdepay->adapter);
509     rtpjpegdepay->discont = TRUE;
510   }
511 
512   payload_len = gst_rtp_buffer_get_payload_len (rtp);
513 
514   if (payload_len < 8)
515     goto empty_packet;
516 
517   payload = gst_rtp_buffer_get_payload (rtp);
518   header_len = 0;
519 
520   /*  0                   1                   2                   3
521    *  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
522    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523    * | Type-specific |              Fragment Offset                  |
524    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525    * |      Type     |       Q       |     Width     |     Height    |
526    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
527    */
528   frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
529   type = payload[4];
530   Q = payload[5];
531   width = payload[6] * 8;
532   height = payload[7] * 8;
533 
534   /* saw a packet with fragment offset > 0 and we don't already have data queued
535    * up (most importantly, we don't have a header for this data) -- drop it
536    * XXX: maybe we can check if the jpeg is progressive and salvage the data?
537    * XXX: not implemented yet because jpegenc can't create progressive jpegs */
538   if (frag_offset > 0 && gst_adapter_available (rtpjpegdepay->adapter) == 0)
539     goto no_header_packet;
540 
541   /* allow frame dimensions > 2040, passed in SDP session or media attributes
542    * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
543   if (!width)
544     width = rtpjpegdepay->media_width;
545 
546   if (!height)
547     height = rtpjpegdepay->media_height;
548 
549   if (width == 0 || height == 0)
550     goto invalid_dimension;
551 
552   GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
553       frag_offset, type, Q, width, height);
554 
555   header_len += 8;
556   payload += 8;
557   payload_len -= 8;
558 
559   dri = 0;
560   if (type > 63) {
561     if (payload_len < 4)
562       goto empty_packet;
563 
564     /*  0                   1                   2                   3
565      *  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
566      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
567      * |       Restart Interval        |F|L|       Restart Count       |
568      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
569      */
570     dri = (payload[0] << 8) | payload[1];
571 
572     GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
573 
574     payload += 4;
575     header_len += 4;
576     payload_len -= 4;
577   }
578 
579   if (Q >= 128 && frag_offset == 0) {
580     if (payload_len < 4)
581       goto empty_packet;
582 
583     /*  0                   1                   2                   3
584      *  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
585      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
586      * |      MBZ      |   Precision   |             Length            |
587      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588      * |                    Quantization Table Data                    |
589      * |                              ...                              |
590      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591      */
592     precision = payload[1];
593     length = (payload[2] << 8) | payload[3];
594 
595     GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
596         precision, length);
597 
598     if (Q == 255 && length == 0)
599       goto empty_packet;
600 
601     payload += 4;
602     header_len += 4;
603     payload_len -= 4;
604 
605     if (length > payload_len)
606       goto empty_packet;
607 
608     if (length > 0)
609       qtable = payload;
610     else
611       qtable = rtpjpegdepay->qtables[Q];
612 
613     payload += length;
614     header_len += length;
615     payload_len -= length;
616   } else {
617     length = 0;
618     qtable = NULL;
619     precision = 0;
620   }
621 
622   if (frag_offset == 0) {
623     GstMapInfo map;
624     guint size;
625 
626     if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
627       GstCaps *outcaps;
628 
629       outcaps =
630           gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
631           rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
632           G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
633       gst_pad_set_caps (depayload->srcpad, outcaps);
634       gst_caps_unref (outcaps);
635 
636       rtpjpegdepay->width = width;
637       rtpjpegdepay->height = height;
638     }
639 
640     GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
641         length);
642 
643     /* first packet */
644     if (length == 0) {
645       if (Q < 128) {
646         /* no quant table, see if we have one cached */
647         qtable = rtpjpegdepay->qtables[Q];
648         if (!qtable) {
649           GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
650           /* make and cache the table */
651           qtable = g_new (guint8, 128);
652           MakeTables (rtpjpegdepay, Q, qtable);
653           rtpjpegdepay->qtables[Q] = qtable;
654         } else {
655           GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
656         }
657         /* all 8 bit quantizers */
658         precision = 0;
659       } else {
660         if (!qtable)
661           goto no_qtable;
662       }
663     }
664 
665     /* I think we can get here with a NULL qtable, so make sure we don't
666        go dereferencing it in MakeHeaders if we do */
667     if (!qtable)
668       goto no_qtable;
669 
670     /* max header length, should be big enough */
671     outbuf = gst_buffer_new_and_alloc (1000);
672     gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
673     size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
674     gst_buffer_unmap (outbuf, &map);
675     gst_buffer_resize (outbuf, 0, size);
676 
677     GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
678 
679     gst_adapter_push (rtpjpegdepay->adapter, outbuf);
680   }
681 
682   /* take JPEG data, push in the adapter */
683   GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
684   outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1);
685   gst_adapter_push (rtpjpegdepay->adapter, outbuf);
686   outbuf = NULL;
687 
688   if (gst_rtp_buffer_get_marker (rtp)) {
689     guint avail;
690     guint8 end[2];
691     GstMapInfo map;
692 
693     /* last buffer take all data out of the adapter */
694     avail = gst_adapter_available (rtpjpegdepay->adapter);
695     GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
696 
697     if (avail < 2)
698       goto invalid_packet;
699 
700     /* take the last bytes of the jpeg data to see if there is an EOI
701      * marker */
702     gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
703 
704     if (end[0] != 0xff && end[1] != 0xd9) {
705       GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
706 
707       /* no EOI marker, add one */
708       outbuf = gst_buffer_new_and_alloc (2);
709       gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
710       map.data[0] = 0xff;
711       map.data[1] = 0xd9;
712       gst_buffer_unmap (outbuf, &map);
713 
714       gst_adapter_push (rtpjpegdepay->adapter, outbuf);
715       avail += 2;
716     }
717     outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
718 
719     if (rtpjpegdepay->discont) {
720       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
721       rtpjpegdepay->discont = FALSE;
722     }
723 
724     gst_rtp_drop_non_video_meta (rtpjpegdepay, outbuf);
725 
726     GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
727   }
728 
729   return outbuf;
730 
731   /* ERRORS */
732 empty_packet:
733   {
734     GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
735         ("Empty Payload."), (NULL));
736     return NULL;
737   }
738 invalid_dimension:
739   {
740     GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
741         ("Invalid Dimension %dx%d.", width, height), (NULL));
742     return NULL;
743   }
744 no_qtable:
745   {
746     GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
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     return NULL;
755   }
756 no_header_packet:
757   {
758     GST_WARNING_OBJECT (rtpjpegdepay,
759         "discarding data packets received when we have no header");
760     return NULL;
761   }
762 }
763 
764 
765 static GstStateChangeReturn
gst_rtp_jpeg_depay_change_state(GstElement * element,GstStateChange transition)766 gst_rtp_jpeg_depay_change_state (GstElement * element,
767     GstStateChange transition)
768 {
769   GstRtpJPEGDepay *rtpjpegdepay;
770   GstStateChangeReturn ret;
771 
772   rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
773 
774   switch (transition) {
775     case GST_STATE_CHANGE_READY_TO_PAUSED:
776       gst_rtp_jpeg_depay_reset (rtpjpegdepay);
777       break;
778     default:
779       break;
780   }
781 
782   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
783 
784   switch (transition) {
785     case GST_STATE_CHANGE_PAUSED_TO_READY:
786       break;
787     default:
788       break;
789   }
790   return ret;
791 }
792 
793 
794 gboolean
gst_rtp_jpeg_depay_plugin_init(GstPlugin * plugin)795 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
796 {
797   return gst_element_register (plugin, "rtpjpegdepay",
798       GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);
799 }
800