• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
gst_rtp_jpeg_depay_class_init(GstRtpJPEGDepayClass * klass)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
gst_rtp_jpeg_depay_init(GstRtpJPEGDepay * rtpjpegdepay)120 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
121 {
122   rtpjpegdepay->adapter = gst_adapter_new ();
123 }
124 
125 static void
gst_rtp_jpeg_depay_reset(GstRtpJPEGDepay * depay)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
gst_rtp_jpeg_depay_finalize(GObject * object)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
MakeTables(GstRtpJPEGDepay * rtpjpegdepay,gint Q,guint8 qtable[128])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 *
MakeQuantHeader(guint8 * p,guint8 * qt,gint size,gint tableNo)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 *
MakeHuffmanHeader(guint8 * p,const guint8 * codelens,int ncodes,const guint8 * symbols,int nsymbols,int tableNo,int tableClass)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 *
MakeDRIHeader(guint8 * p,guint16 dri)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
MakeHeaders(guint8 * p,int type,int width,int height,guint8 * qt,guint precision,guint16 dri)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
gst_rtp_jpeg_depay_setcaps(GstRTPBaseDepayload * depayload,GstCaps * caps)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 *
gst_rtp_jpeg_depay_process(GstRTPBaseDepayload * depayload,GstRTPBuffer * rtp)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
gst_rtp_jpeg_depay_change_state(GstElement * element,GstStateChange transition)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 }
796