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_DEBUG_OBJECT (depayload, "DISCONT, reset adapter");
518 gst_adapter_clear (rtpjpegdepay->adapter);
519 rtpjpegdepay->discont = TRUE;
522 gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
523 payload_len = gst_rtp_buffer_get_payload_len (&rtp);
528 payload = gst_rtp_buffer_get_payload (&rtp);
532 * 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
533 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
534 * | Type-specific | Fragment Offset |
535 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
536 * | Type | Q | Width | Height |
537 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
542 width = payload[6] * 8;
543 height = payload[7] * 8;
545 /* allow frame dimensions > 2040, passed in SDP session or media attributes
546 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
548 width = rtpjpegdepay->media_width;
551 height = rtpjpegdepay->media_height;
553 if (width == 0 || height == 0)
554 goto invalid_dimension;
556 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
557 frag_offset, type, Q, width, height);
569 * 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
570 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
571 * | Restart Interval |F|L| Restart Count |
572 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
574 dri = (payload[0] << 8) | payload[1];
576 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
583 if (Q >= 128 && frag_offset == 0) {
588 * 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
589 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
590 * | MBZ | Precision | Length |
591 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
592 * | Quantization Table Data |
594 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
596 precision = payload[1];
597 length = (payload[2] << 8) | payload[3];
599 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
602 if (Q == 255 && length == 0)
609 if (length > payload_len)
615 qtable = rtpjpegdepay->qtables[Q];
618 header_len += length;
619 payload_len -= length;
626 if (frag_offset == 0) {
630 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
634 gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
635 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
636 G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
637 gst_pad_set_caps (depayload->srcpad, outcaps);
638 gst_caps_unref (outcaps);
640 rtpjpegdepay->width = width;
641 rtpjpegdepay->height = height;
644 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
650 /* no quant table, see if we have one cached */
651 qtable = rtpjpegdepay->qtables[Q];
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;
659 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
661 /* all 8 bit quantizers */
668 /* max header length, should be big enough */
669 outbuf = gst_buffer_new_and_alloc (1000);
670 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
671 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
672 gst_buffer_unmap (outbuf, &map);
673 gst_buffer_resize (outbuf, 0, size);
675 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
677 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
680 /* take JPEG data, push in the adapter */
681 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
682 outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, -1);
683 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
686 if (gst_rtp_buffer_get_marker (&rtp)) {
691 /* last buffer take all data out of the adapter */
692 avail = gst_adapter_available (rtpjpegdepay->adapter);
693 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
698 /* take the last bytes of the jpeg data to see if there is an EOI
700 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
702 if (end[0] != 0xff && end[1] != 0xd9) {
703 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
705 /* no EOI marker, add one */
706 outbuf = gst_buffer_new_and_alloc (2);
707 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
710 gst_buffer_unmap (outbuf, &map);
712 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
715 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
717 if (rtpjpegdepay->discont) {
718 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
719 rtpjpegdepay->discont = FALSE;
722 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
725 gst_rtp_buffer_unmap (&rtp);
732 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
733 ("Empty Payload."), (NULL));
734 gst_rtp_buffer_unmap (&rtp);
739 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
740 ("Invalid Dimension %dx%d.", width, height), (NULL));
741 gst_rtp_buffer_unmap (&rtp);
746 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
747 gst_rtp_buffer_unmap (&rtp);
752 GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
753 gst_adapter_flush (rtpjpegdepay->adapter,
754 gst_adapter_available (rtpjpegdepay->adapter));
755 gst_rtp_buffer_unmap (&rtp);
761 static GstStateChangeReturn
762 gst_rtp_jpeg_depay_change_state (GstElement * element,
763 GstStateChange transition)
765 GstRtpJPEGDepay *rtpjpegdepay;
766 GstStateChangeReturn ret;
768 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
770 switch (transition) {
771 case GST_STATE_CHANGE_READY_TO_PAUSED:
772 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
778 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
780 switch (transition) {
781 case GST_STATE_CHANGE_PAUSED_TO_READY:
791 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
793 return gst_element_register (plugin, "rtpjpegdepay",
794 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);