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