2 * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
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.
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.
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.
24 #include <gst/rtp/gstrtpbuffer.h>
30 #include "gstrtpjpegdepay.h"
32 GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
33 #define GST_CAT_DEFAULT (rtpjpegdepay_debug)
35 static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
36 GST_STATIC_PAD_TEMPLATE ("src",
39 GST_STATIC_CAPS ("image/jpeg")
42 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
43 GST_STATIC_PAD_TEMPLATE ("sink",
46 GST_STATIC_CAPS ("application/x-rtp, "
47 "media = (string) \"video\", "
48 "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
49 /* optional SDP attributes */
51 * "a-framerate = (string) 0.00, "
52 * "x-framerate = (string) 0.00, "
53 * "a-framesize = (string) 1234-1234, "
54 * "x-dimensions = (string) \"1234,1234\", "
57 "media = (string) \"video\", "
58 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
59 "clock-rate = (int) 90000"
60 /* optional SDP attributes */
62 * "a-framerate = (string) 0.00, "
63 * "x-framerate = (string) 0.00, "
64 * "a-framesize = (string) 1234-1234, "
65 * "x-dimensions = (string) \"1234,1234\""
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);
74 static void gst_rtp_jpeg_depay_finalize (GObject * object);
76 static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
77 element, GstStateChange transition);
79 static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
81 static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
85 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
87 GObjectClass *gobject_class;
88 GstElementClass *gstelement_class;
89 GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
91 gobject_class = (GObjectClass *) klass;
92 gstelement_class = (GstElementClass *) klass;
93 gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
95 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
97 gst_element_class_add_pad_template (gstelement_class,
98 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
99 gst_element_class_add_pad_template (gstelement_class,
100 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
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>");
107 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
109 gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
110 gstrtpbasedepayload_class->process = gst_rtp_jpeg_depay_process;
112 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
113 "JPEG Video RTP Depayloader");
117 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
119 rtpjpegdepay->adapter = gst_adapter_new ();
123 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
129 depay->media_width = 0;
130 depay->media_height = 0;
131 depay->frate_num = 0;
132 depay->frate_denom = 1;
133 depay->discont = TRUE;
135 for (i = 0; i < 255; i++) {
136 g_free (depay->qtables[i]);
137 depay->qtables[i] = NULL;
140 gst_adapter_clear (depay->adapter);
144 gst_rtp_jpeg_depay_finalize (GObject * object)
146 GstRtpJPEGDepay *rtpjpegdepay;
148 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
150 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
152 g_object_unref (rtpjpegdepay->adapter);
153 rtpjpegdepay->adapter = NULL;
155 G_OBJECT_CLASS (parent_class)->finalize (object);
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
170 * Table K.1 from JPEG spec.
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
184 * Table K.2 from JPEG spec.
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
197 /* Call MakeTables with the Q factor and a guint8[128] return array
200 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
205 factor = CLAMP (Q, 1, 99);
210 Q = 200 - factor * 2;
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;
216 /* Limit the quantizers to 1 <= q <= 255 */
217 qtable[i] = CLAMP (lq, 1, 255);
218 qtable[i + 64] = CLAMP (cq, 1, 255);
222 static const guint8 lum_dc_codelens[] = {
223 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
226 static const guint8 lum_dc_symbols[] = {
227 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
230 static const guint8 lum_ac_codelens[] = {
231 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
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,
258 static const guint8 chm_dc_codelens[] = {
259 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
262 static const guint8 chm_dc_symbols[] = {
263 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
266 static const guint8 chm_ac_codelens[] = {
267 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
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,
295 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
298 *p++ = 0xdb; /* DQT */
299 *p++ = 0; /* length msb */
300 *p++ = size + 3; /* length lsb */
302 memcpy (p, qt, size);
308 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
309 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
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);
318 memcpy (p, symbols, nsymbols);
325 MakeDRIHeader (guint8 * p, guint16 dri)
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 */
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
343 * dri: restart interval in MCUs, or 0 if no restarts.
345 * p: pointer to return area
348 * The length of the generated headers.
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).
356 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
357 guint precision, guint16 dri)
363 *p++ = 0xd8; /* SOI */
365 size = ((precision & 1) ? 128 : 64);
366 p = MakeQuantHeader (p, qt, size, 0);
369 size = ((precision & 2) ? 128 : 64);
370 p = MakeQuantHeader (p, qt, size, 1);
374 p = MakeDRIHeader (p, dri);
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 */
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 */
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);
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. */
427 gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
429 GstRtpJPEGDepay *rtpjpegdepay;
430 GstStructure *structure;
432 const gchar *media_attr;
434 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
436 structure = gst_caps_get_structure (caps, 0);
437 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
439 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
441 depayload->clock_rate = clock_rate;
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;
451 /* check for optional SDP attributes */
452 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
455 if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
456 rtpjpegdepay->media_width = w;
457 rtpjpegdepay->media_height = h;
461 if ((media_attr = gst_structure_get_string (structure, "a-framesize"))) {
464 if (sscanf (media_attr, "%d-%d", &w, &h) == 2) {
465 rtpjpegdepay->media_width = w;
466 rtpjpegdepay->media_height = h;
470 /* try to get a framerate */
471 media_attr = gst_structure_get_string (structure, "a-framerate");
473 media_attr = gst_structure_get_string (structure, "x-framerate");
480 /* canonicalise floating point string so we can handle framerate strings
481 * in the form "24.930" or "24,930" irrespective of the current locale */
482 s = g_strdup (media_attr);
483 g_strdelimit (s, ",", '.');
485 /* convert the float to a fraction */
486 g_value_init (&src, G_TYPE_DOUBLE);
487 g_value_set_double (&src, g_ascii_strtod (s, NULL));
488 g_value_init (&dest, GST_TYPE_FRACTION);
489 g_value_transform (&src, &dest);
491 rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
492 rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
501 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
503 GstRtpJPEGDepay *rtpjpegdepay;
505 gint payload_len, header_len;
509 guint type, width, height;
510 guint16 dri, precision, length;
512 GstRTPBuffer rtp = { NULL };
514 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
516 if (GST_BUFFER_IS_DISCONT (buf)) {
517 gst_adapter_clear (rtpjpegdepay->adapter);
518 rtpjpegdepay->discont = TRUE;
521 gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
522 payload_len = gst_rtp_buffer_get_payload_len (&rtp);
527 payload = gst_rtp_buffer_get_payload (&rtp);
531 * 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
532 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
533 * | Type-specific | Fragment Offset |
534 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
535 * | Type | Q | Width | Height |
536 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
541 width = payload[6] * 8;
542 height = payload[7] * 8;
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 */
547 width = rtpjpegdepay->media_width;
550 height = rtpjpegdepay->media_height;
552 if (width == 0 || height == 0)
553 goto invalid_dimension;
555 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
556 frag_offset, type, Q, width, height);
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
573 dri = (payload[0] << 8) | payload[1];
575 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
582 if (Q >= 128 && frag_offset == 0) {
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 |
593 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
595 precision = payload[1];
596 length = (payload[2] << 8) | payload[3];
598 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
601 if (Q == 255 && length == 0)
608 if (length > payload_len)
614 qtable = rtpjpegdepay->qtables[Q];
617 header_len += length;
618 payload_len -= length;
625 if (frag_offset == 0) {
629 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
633 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
634 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
635 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
636 gst_pad_set_caps (depayload->srcpad, outcaps);
637 gst_caps_unref (outcaps);
639 rtpjpegdepay->width = width;
640 rtpjpegdepay->height = height;
643 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
649 /* no quant table, see if we have one cached */
650 qtable = rtpjpegdepay->qtables[Q];
652 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
653 /* make and cache the table */
654 qtable = g_new (guint8, 128);
655 MakeTables (rtpjpegdepay, Q, qtable);
656 rtpjpegdepay->qtables[Q] = qtable;
658 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
660 /* all 8 bit quantizers */
667 /* max header length, should be big enough */
668 outbuf = gst_buffer_new_and_alloc (1000);
669 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
670 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
671 gst_buffer_unmap (outbuf, &map);
672 gst_buffer_resize (outbuf, 0, size);
674 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
676 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
679 /* take JPEG data, push in the adapter */
680 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
681 outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, -1);
682 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
685 if (gst_rtp_buffer_get_marker (&rtp)) {
690 /* last buffer take all data out of the adapter */
691 avail = gst_adapter_available (rtpjpegdepay->adapter);
692 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
697 /* take the last bytes of the jpeg data to see if there is an EOI
699 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
701 if (end[0] != 0xff && end[1] != 0xd9) {
702 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
704 /* no EOI marker, add one */
705 outbuf = gst_buffer_new_and_alloc (2);
706 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
709 gst_buffer_unmap (outbuf, &map);
711 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
714 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
716 if (rtpjpegdepay->discont) {
717 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
718 rtpjpegdepay->discont = FALSE;
721 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
724 gst_rtp_buffer_unmap (&rtp);
731 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
732 ("Empty Payload."), (NULL));
733 gst_rtp_buffer_unmap (&rtp);
738 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
739 ("Invalid Dimension %dx%d.", width, height), (NULL));
740 gst_rtp_buffer_unmap (&rtp);
745 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
746 gst_rtp_buffer_unmap (&rtp);
751 GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
752 gst_adapter_flush (rtpjpegdepay->adapter,
753 gst_adapter_available (rtpjpegdepay->adapter));
754 gst_rtp_buffer_unmap (&rtp);
760 static GstStateChangeReturn
761 gst_rtp_jpeg_depay_change_state (GstElement * element,
762 GstStateChange transition)
764 GstRtpJPEGDepay *rtpjpegdepay;
765 GstStateChangeReturn ret;
767 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
769 switch (transition) {
770 case GST_STATE_CHANGE_READY_TO_PAUSED:
771 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
777 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
779 switch (transition) {
780 case GST_STATE_CHANGE_PAUSED_TO_READY:
790 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
792 return gst_element_register (plugin, "rtpjpegdepay",
793 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);