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")
40 /* optional SDP attributes */
43 * "height = (int) 0, "
44 * "framerate = (fraction) 0/1, "
45 * "x-dimensions = (string) "0\,0", "
49 static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
50 GST_STATIC_PAD_TEMPLATE ("sink",
53 GST_STATIC_CAPS ("application/x-rtp, "
54 "media = (string) \"video\", "
55 "clock-rate = (int) 90000, "
56 "encoding-name = (string) \"JPEG\"; "
57 /* optional SDP attributes */
60 * "height = (int) 0, "
61 * "framerate = (fraction) 0/1, "
62 * "a-framerate = (string) 0.00, "
63 * "x-framerate = (string) 0.00, "
64 * "x-dimensions = (string) "0\,0", "
67 "media = (string) \"video\", "
68 "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
69 "clock-rate = (int) 90000"
70 /* optional SDP attributes */
73 * "height = (int) 0, "
74 * "framerate = (fraction) 0/1, "
75 * "a-framerate = (string) 0.00, "
76 * "x-framerate = (string) 0.00, "
77 * "x-dimensions = (string) "0\,0", "
82 #define gst_rtp_jpeg_depay_parent_class parent_class
83 G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
84 GST_TYPE_RTP_BASE_DEPAYLOAD);
86 static void gst_rtp_jpeg_depay_finalize (GObject * object);
88 static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
89 element, GstStateChange transition);
91 static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
93 static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
97 gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
99 GObjectClass *gobject_class;
100 GstElementClass *gstelement_class;
101 GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
103 gobject_class = (GObjectClass *) klass;
104 gstelement_class = (GstElementClass *) klass;
105 gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
107 gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
109 gst_element_class_add_pad_template (gstelement_class,
110 gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
111 gst_element_class_add_pad_template (gstelement_class,
112 gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
114 gst_element_class_set_static_metadata (gstelement_class,
115 "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
116 "Extracts JPEG video from RTP packets (RFC 2435)",
117 "Wim Taymans <wim.taymans@gmail.com>");
119 gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
121 gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
122 gstrtpbasedepayload_class->process = gst_rtp_jpeg_depay_process;
124 GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
125 "JPEG Video RTP Depayloader");
129 gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
131 rtpjpegdepay->adapter = gst_adapter_new ();
135 gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
141 depay->media_width = 0;
142 depay->media_height = 0;
143 depay->frate_num = 0;
144 depay->frate_denom = 1;
145 depay->discont = TRUE;
147 for (i = 0; i < 255; i++) {
148 g_free (depay->qtables[i]);
149 depay->qtables[i] = NULL;
152 gst_adapter_clear (depay->adapter);
156 gst_rtp_jpeg_depay_finalize (GObject * object)
158 GstRtpJPEGDepay *rtpjpegdepay;
160 rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
162 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
164 g_object_unref (rtpjpegdepay->adapter);
165 rtpjpegdepay->adapter = NULL;
167 G_OBJECT_CLASS (parent_class)->finalize (object);
170 static const int zigzag[] = {
171 0, 1, 8, 16, 9, 2, 3, 10,
172 17, 24, 32, 25, 18, 11, 4, 5,
173 12, 19, 26, 33, 40, 48, 41, 34,
174 27, 20, 13, 6, 7, 14, 21, 28,
175 35, 42, 49, 56, 57, 50, 43, 36,
176 29, 22, 15, 23, 30, 37, 44, 51,
177 58, 59, 52, 45, 38, 31, 39, 46,
178 53, 60, 61, 54, 47, 55, 62, 63
182 * Table K.1 from JPEG spec.
184 static const int jpeg_luma_quantizer[64] = {
185 16, 11, 10, 16, 24, 40, 51, 61,
186 12, 12, 14, 19, 26, 58, 60, 55,
187 14, 13, 16, 24, 40, 57, 69, 56,
188 14, 17, 22, 29, 51, 87, 80, 62,
189 18, 22, 37, 56, 68, 109, 103, 77,
190 24, 35, 55, 64, 81, 104, 113, 92,
191 49, 64, 78, 87, 103, 121, 120, 101,
192 72, 92, 95, 98, 112, 100, 103, 99
196 * Table K.2 from JPEG spec.
198 static const int jpeg_chroma_quantizer[64] = {
199 17, 18, 24, 47, 99, 99, 99, 99,
200 18, 21, 26, 66, 99, 99, 99, 99,
201 24, 26, 56, 99, 99, 99, 99, 99,
202 47, 66, 99, 99, 99, 99, 99, 99,
203 99, 99, 99, 99, 99, 99, 99, 99,
204 99, 99, 99, 99, 99, 99, 99, 99,
205 99, 99, 99, 99, 99, 99, 99, 99,
206 99, 99, 99, 99, 99, 99, 99, 99
209 /* Call MakeTables with the Q factor and a guint8[128] return array
212 MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
217 factor = CLAMP (Q, 1, 99);
222 Q = 200 - factor * 2;
224 for (i = 0; i < 64; i++) {
225 gint lq = (jpeg_luma_quantizer[zigzag[i]] * Q + 50) / 100;
226 gint cq = (jpeg_chroma_quantizer[zigzag[i]] * Q + 50) / 100;
228 /* Limit the quantizers to 1 <= q <= 255 */
229 qtable[i] = CLAMP (lq, 1, 255);
230 qtable[i + 64] = CLAMP (cq, 1, 255);
234 static const guint8 lum_dc_codelens[] = {
235 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
238 static const guint8 lum_dc_symbols[] = {
239 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
242 static const guint8 lum_ac_codelens[] = {
243 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
246 static const guint8 lum_ac_symbols[] = {
247 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
248 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
249 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
250 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
251 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
252 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
253 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
254 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
255 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
256 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
257 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
258 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
259 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
260 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
261 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
262 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
263 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
264 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
265 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
266 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
270 static const guint8 chm_dc_codelens[] = {
271 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
274 static const guint8 chm_dc_symbols[] = {
275 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
278 static const guint8 chm_ac_codelens[] = {
279 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
282 static const guint8 chm_ac_symbols[] = {
283 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
284 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
285 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
286 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
287 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
288 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
289 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
290 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
291 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
292 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
293 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
294 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
295 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
296 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
297 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
298 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
299 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
300 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
301 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
302 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
307 MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
310 *p++ = 0xdb; /* DQT */
311 *p++ = 0; /* length msb */
312 *p++ = size + 3; /* length lsb */
314 memcpy (p, qt, size);
320 MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
321 const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
324 *p++ = 0xc4; /* DHT */
325 *p++ = 0; /* length msb */
326 *p++ = 3 + ncodes + nsymbols; /* length lsb */
327 *p++ = (tableClass << 4) | tableNo;
328 memcpy (p, codelens, ncodes);
330 memcpy (p, symbols, nsymbols);
337 MakeDRIHeader (guint8 * p, guint16 dri)
340 *p++ = 0xdd; /* DRI */
341 *p++ = 0x0; /* length msb */
342 *p++ = 4; /* length lsb */
343 *p++ = dri >> 8; /* dri msb */
344 *p++ = dri & 0xff; /* dri lsb */
351 * type, width, height: as supplied in RTP/JPEG header
352 * qt: quantization tables as either derived from
353 * the Q field using MakeTables() or as specified
355 * dri: restart interval in MCUs, or 0 if no restarts.
357 * p: pointer to return area
360 * The length of the generated headers.
362 * Generate a frame and scan headers that can be prepended to the
363 * RTP/JPEG data payload to produce a JPEG compressed image in
364 * interchange format (except for possible trailing garbage and
365 * absence of an EOI marker to terminate the scan).
368 MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
369 guint precision, guint16 dri)
375 *p++ = 0xd8; /* SOI */
377 size = ((precision & 1) ? 128 : 64);
378 p = MakeQuantHeader (p, qt, size, 0);
381 size = ((precision & 2) ? 128 : 64);
382 p = MakeQuantHeader (p, qt, size, 1);
386 p = MakeDRIHeader (p, dri);
389 *p++ = 0xc0; /* SOF */
390 *p++ = 0; /* length msb */
391 *p++ = 17; /* length lsb */
392 *p++ = 8; /* 8-bit precision */
393 *p++ = height >> 8; /* height msb */
394 *p++ = height; /* height lsb */
395 *p++ = width >> 8; /* width msb */
396 *p++ = width; /* width lsb */
397 *p++ = 3; /* number of components */
398 *p++ = 0; /* comp 0 */
399 if ((type & 0x3f) == 0)
400 *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
402 *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
403 *p++ = 0; /* quant table 0 */
404 *p++ = 1; /* comp 1 */
405 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
406 *p++ = 1; /* quant table 1 */
407 *p++ = 2; /* comp 2 */
408 *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
409 *p++ = 1; /* quant table 1 */
411 p = MakeHuffmanHeader (p, lum_dc_codelens,
412 sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
413 p = MakeHuffmanHeader (p, lum_ac_codelens,
414 sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
415 p = MakeHuffmanHeader (p, chm_dc_codelens,
416 sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
417 p = MakeHuffmanHeader (p, chm_ac_codelens,
418 sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
421 *p++ = 0xda; /* SOS */
422 *p++ = 0; /* length msb */
423 *p++ = 12; /* length lsb */
424 *p++ = 3; /* 3 components */
425 *p++ = 0; /* comp 0 */
426 *p++ = 0; /* huffman table 0 */
427 *p++ = 1; /* comp 1 */
428 *p++ = 0x11; /* huffman table 1 */
429 *p++ = 2; /* comp 2 */
430 *p++ = 0x11; /* huffman table 1 */
431 *p++ = 0; /* first DCT coeff */
432 *p++ = 63; /* last DCT coeff */
433 *p++ = 0; /* sucessive approx. */
439 gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
441 GstRtpJPEGDepay *rtpjpegdepay;
442 GstStructure *structure;
444 const gchar *media_attr;
445 gint width = 0, height = 0;
446 gint num = 0, denom = 1;
448 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
450 structure = gst_caps_get_structure (caps, 0);
451 GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
453 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
455 depayload->clock_rate = clock_rate;
457 /* check for optional SDP attributes */
458 if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
459 if (sscanf (media_attr, "%d,%d", &width, &height) != 2 || width <= 0 ||
461 goto invalid_dimension;
465 if (gst_structure_get_int (structure, "width", &width) && width <= 0) {
466 goto invalid_dimension;
468 if (gst_structure_get_int (structure, "height", &height) && height <= 0) {
469 goto invalid_dimension;
472 /* try to get a framerate */
473 media_attr = gst_structure_get_string (structure, "a-framerate");
475 media_attr = gst_structure_get_string (structure, "x-framerate");
481 /* canonicalise floating point string so we can handle framerate strings
482 * in the form "24.930" or "24,930" irrespective of the current locale */
483 s = g_strdup (media_attr);
484 g_strdelimit (s, ",", '.');
486 /* convert the float to a fraction */
487 rate = g_ascii_strtod (s, NULL);
488 gst_util_double_to_fraction (rate, &num, &denom);
490 if (num < 0 || denom <= 0) {
491 goto invalid_framerate;
495 if (gst_structure_get_fraction (structure, "framerate", &num, &denom) &&
496 (num < 0 || denom <= 0)) {
497 goto invalid_framerate;
500 rtpjpegdepay->width = 0;
501 rtpjpegdepay->height = 0;
502 rtpjpegdepay->media_width = width;
503 rtpjpegdepay->media_height = height;
504 rtpjpegdepay->frate_num = num;
505 rtpjpegdepay->frate_denom = denom;
511 GST_ERROR_OBJECT (rtpjpegdepay, "invalid width/height from caps");
516 GST_ERROR_OBJECT (rtpjpegdepay, "invalid framerate from caps");
522 gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
524 GstRtpJPEGDepay *rtpjpegdepay;
526 gint payload_len, header_len;
530 guint type, width, height;
531 guint16 dri, precision, length;
533 GstRTPBuffer rtp = { NULL };
535 rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
537 if (GST_BUFFER_IS_DISCONT (buf)) {
538 gst_adapter_clear (rtpjpegdepay->adapter);
539 rtpjpegdepay->discont = TRUE;
542 gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
543 payload_len = gst_rtp_buffer_get_payload_len (&rtp);
548 payload = gst_rtp_buffer_get_payload (&rtp);
552 * 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
553 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
554 * | Type-specific | Fragment Offset |
555 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
556 * | Type | Q | Width | Height |
557 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
559 frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
562 width = payload[6] * 8;
563 height = payload[7] * 8;
565 /* allow frame dimensions > 2040, passed in SDP session or media attributes
566 * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
568 width = rtpjpegdepay->media_width;
571 height = rtpjpegdepay->media_height;
573 if (width == 0 || height == 0)
574 goto invalid_dimension;
576 GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
577 frag_offset, type, Q, width, height);
589 * 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
590 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591 * | Restart Interval |F|L| Restart Count |
592 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
594 dri = (payload[0] << 8) | payload[1];
596 GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
603 if (Q >= 128 && frag_offset == 0) {
608 * 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
609 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
610 * | MBZ | Precision | Length |
611 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
612 * | Quantization Table Data |
614 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
616 precision = payload[1];
617 length = (payload[2] << 8) | payload[3];
619 GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
622 if (Q == 255 && length == 0)
629 if (length > payload_len)
635 qtable = rtpjpegdepay->qtables[Q];
638 header_len += length;
639 payload_len -= length;
646 if (frag_offset == 0) {
650 if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
653 outcaps = gst_caps_new_empty_simple ("image/jpeg");
655 if (width > 0 && height > 0) {
656 gst_caps_set_simple (outcaps, "width", G_TYPE_INT, width, "height",
657 G_TYPE_INT, height, NULL);
660 if (rtpjpegdepay->frate_num > 0) {
661 gst_caps_set_simple (outcaps, "framerate", GST_TYPE_FRACTION,
662 rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, NULL);
665 gst_pad_set_caps (depayload->srcpad, outcaps);
666 gst_caps_unref (outcaps);
668 rtpjpegdepay->width = width;
669 rtpjpegdepay->height = height;
672 GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
678 /* no quant table, see if we have one cached */
679 qtable = rtpjpegdepay->qtables[Q];
681 GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
682 /* make and cache the table */
683 qtable = g_new (guint8, 128);
684 MakeTables (rtpjpegdepay, Q, qtable);
685 rtpjpegdepay->qtables[Q] = qtable;
687 GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
689 /* all 8 bit quantizers */
696 /* max header length, should be big enough */
697 outbuf = gst_buffer_new_and_alloc (1000);
698 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
699 size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
700 gst_buffer_unmap (outbuf, &map);
701 gst_buffer_resize (outbuf, 0, size);
703 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
705 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
708 /* take JPEG data, push in the adapter */
709 GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
710 outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, -1);
711 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
714 if (gst_rtp_buffer_get_marker (&rtp)) {
719 /* last buffer take all data out of the adapter */
720 avail = gst_adapter_available (rtpjpegdepay->adapter);
721 GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
726 /* take the last bytes of the jpeg data to see if there is an EOI
728 gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
730 if (end[0] != 0xff && end[1] != 0xd9) {
731 GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
733 /* no EOI marker, add one */
734 outbuf = gst_buffer_new_and_alloc (2);
735 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
738 gst_buffer_unmap (outbuf, &map);
740 gst_adapter_push (rtpjpegdepay->adapter, outbuf);
743 outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
745 if (rtpjpegdepay->discont) {
746 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
747 rtpjpegdepay->discont = FALSE;
750 GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
753 gst_rtp_buffer_unmap (&rtp);
760 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
761 ("Empty Payload."), (NULL));
762 gst_rtp_buffer_unmap (&rtp);
767 GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
768 ("Invalid Dimension %dx%d.", width, height), (NULL));
769 gst_rtp_buffer_unmap (&rtp);
774 GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
775 gst_rtp_buffer_unmap (&rtp);
780 GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
781 gst_adapter_flush (rtpjpegdepay->adapter,
782 gst_adapter_available (rtpjpegdepay->adapter));
783 gst_rtp_buffer_unmap (&rtp);
789 static GstStateChangeReturn
790 gst_rtp_jpeg_depay_change_state (GstElement * element,
791 GstStateChange transition)
793 GstRtpJPEGDepay *rtpjpegdepay;
794 GstStateChangeReturn ret;
796 rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
798 switch (transition) {
799 case GST_STATE_CHANGE_READY_TO_PAUSED:
800 gst_rtp_jpeg_depay_reset (rtpjpegdepay);
806 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
808 switch (transition) {
809 case GST_STATE_CHANGE_PAUSED_TO_READY:
819 gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
821 return gst_element_register (plugin, "rtpjpegdepay",
822 GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);