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