Remove unused variables in _class_init
[platform/upstream/gstreamer.git] / gst / rtp / gstrtpvrawdepay.c
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <gst/rtp/gstrtpbuffer.h>
25
26 #include <string.h>
27 #include <stdlib.h>
28 #include "gstrtpvrawdepay.h"
29
30 GST_DEBUG_CATEGORY_STATIC (rtpvrawdepay_debug);
31 #define GST_CAT_DEFAULT (rtpvrawdepay_debug)
32
33 /* elementfactory information */
34 static const GstElementDetails gst_rtp_vrawdepay_details =
35 GST_ELEMENT_DETAILS ("RTP Raw Video depayloader",
36     "Codec/Depayloader/Network",
37     "Extracts raw video from RTP packets (RFC 4175)",
38     "Wim Taymans <wim.taymans@gmail.com>");
39
40 static GstStaticPadTemplate gst_rtp_vraw_depay_src_template =
41     GST_STATIC_PAD_TEMPLATE ("src",
42     GST_PAD_SRC,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
45     );
46
47 static GstStaticPadTemplate gst_rtp_vraw_depay_sink_template =
48 GST_STATIC_PAD_TEMPLATE ("sink",
49     GST_PAD_SINK,
50     GST_PAD_ALWAYS,
51     GST_STATIC_CAPS ("application/x-rtp, "
52         "media = (string) \"video\", "
53         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
54         "clock-rate = (int) 90000, " "encoding-name = (string) \"RAW\"")
55     );
56
57 GST_BOILERPLATE (GstRtpVRawDepay, gst_rtp_vraw_depay, GstBaseRTPDepayload,
58     GST_TYPE_BASE_RTP_DEPAYLOAD);
59
60 static gboolean gst_rtp_vraw_depay_setcaps (GstBaseRTPDepayload * depayload,
61     GstCaps * caps);
62 static GstBuffer *gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload,
63     GstBuffer * buf);
64
65 static GstStateChangeReturn gst_rtp_vraw_depay_change_state (GstElement *
66     element, GstStateChange transition);
67
68 static void
69 gst_rtp_vraw_depay_base_init (gpointer klass)
70 {
71   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
72
73   gst_element_class_add_pad_template (element_class,
74       gst_static_pad_template_get (&gst_rtp_vraw_depay_src_template));
75   gst_element_class_add_pad_template (element_class,
76       gst_static_pad_template_get (&gst_rtp_vraw_depay_sink_template));
77
78   gst_element_class_set_details (element_class, &gst_rtp_vrawdepay_details);
79 }
80
81 static void
82 gst_rtp_vraw_depay_class_init (GstRtpVRawDepayClass * klass)
83 {
84   GstElementClass *gstelement_class;
85   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
86
87   gstelement_class = (GstElementClass *) klass;
88   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
89
90   parent_class = g_type_class_peek_parent (klass);
91
92   gstelement_class->change_state = gst_rtp_vraw_depay_change_state;
93
94   gstbasertpdepayload_class->set_caps = gst_rtp_vraw_depay_setcaps;
95   gstbasertpdepayload_class->process = gst_rtp_vraw_depay_process;
96
97   GST_DEBUG_CATEGORY_INIT (rtpvrawdepay_debug, "rtpvrawdepay", 0,
98       "raw video RTP Depayloader");
99 }
100
101 static void
102 gst_rtp_vraw_depay_init (GstRtpVRawDepay * rtpvrawdepay,
103     GstRtpVRawDepayClass * klass)
104 {
105   /* needed because of GST_BOILERPLATE */
106 }
107
108 static gboolean
109 gst_rtp_vraw_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
110 {
111   GstStructure *structure;
112   GstRtpVRawDepay *rtpvrawdepay;
113   gint clock_rate;
114   const gchar *str, *type;
115   gint format, width, height, pgroup, xinc, yinc;
116   guint ystride, uvstride, yp, up, vp, outsize;
117   GstCaps *srccaps;
118   guint32 fourcc = 0;
119   gboolean res;
120
121   rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload);
122
123   structure = gst_caps_get_structure (caps, 0);
124
125   yp = up = vp = uvstride = 0;
126   xinc = yinc = 1;
127
128   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
129     clock_rate = 90000;         /* default */
130   depayload->clock_rate = clock_rate;
131
132   if (!(str = gst_structure_get_string (structure, "width")))
133     goto no_width;
134   width = atoi (str);
135
136   if (!(str = gst_structure_get_string (structure, "height")))
137     goto no_height;
138   height = atoi (str);
139
140   /* optional interlace value but we don't handle interlaced
141    * formats yet */
142   if ((str = gst_structure_get_string (structure, "interlace")))
143     goto interlaced;
144
145   if (!(str = gst_structure_get_string (structure, "sampling")))
146     goto no_sampling;
147
148   if (!strcmp (str, "RGB")) {
149     format = GST_VIDEO_FORMAT_RGB;
150     pgroup = 3;
151     ystride = GST_ROUND_UP_4 (width * 3);
152     outsize = ystride * height;
153     type = "video/x-raw-rgb";
154   } else if (!strcmp (str, "RGBA")) {
155     format = GST_VIDEO_FORMAT_RGBA;
156     pgroup = 4;
157     ystride = width * 4;
158     outsize = ystride * height;
159     type = "video/x-raw-rgb";
160   } else if (!strcmp (str, "BGR")) {
161     format = GST_VIDEO_FORMAT_BGR;
162     pgroup = 3;
163     ystride = GST_ROUND_UP_4 (width * 3);
164     outsize = ystride * height;
165     type = "video/x-raw-rgb";
166   } else if (!strcmp (str, "BGRA")) {
167     format = GST_VIDEO_FORMAT_BGRA;
168     pgroup = 4;
169     ystride = width * 4;
170     outsize = ystride * height;
171     type = "video/x-raw-rgb";
172   } else if (!strcmp (str, "YCbCr-4:4:4")) {
173     format = GST_VIDEO_FORMAT_AYUV;
174     pgroup = 3;
175     ystride = width * 4;
176     outsize = ystride * height;
177     type = "video/x-raw-yuv";
178     fourcc = GST_MAKE_FOURCC ('A', 'Y', 'U', 'V');
179   } else if (!strcmp (str, "YCbCr-4:2:2")) {
180     format = GST_VIDEO_FORMAT_UYVY;
181     pgroup = 4;
182     ystride = GST_ROUND_UP_2 (width) * 2;
183     outsize = ystride * height;
184     type = "video/x-raw-yuv";
185     fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
186     xinc = 2;
187   } else if (!strcmp (str, "YCbCr-4:2:0")) {
188     format = GST_VIDEO_FORMAT_I420;
189     pgroup = 6;
190     ystride = GST_ROUND_UP_4 (width);
191     uvstride = GST_ROUND_UP_8 (width) / 2;
192     up = ystride * GST_ROUND_UP_2 (height);
193     vp = up + uvstride * GST_ROUND_UP_2 (height) / 2;
194     outsize = vp + uvstride * GST_ROUND_UP_2 (height) / 2;
195     type = "video/x-raw-yuv";
196     fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
197     xinc = yinc = 2;
198   } else if (!strcmp (str, "YCbCr-4:1:1")) {
199     format = GST_VIDEO_FORMAT_Y41B;
200     pgroup = 6;
201     ystride = GST_ROUND_UP_4 (width);
202     uvstride = GST_ROUND_UP_8 (width) / 4;
203     up = ystride * height;
204     vp = up + uvstride * height;
205     outsize = vp + uvstride * height;
206     type = "video/x-raw-yuv";
207     fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
208     xinc = 4;
209   } else
210     goto unknown_format;
211
212   rtpvrawdepay->width = width;
213   rtpvrawdepay->height = height;
214   rtpvrawdepay->format = format;
215   rtpvrawdepay->yp = yp;
216   rtpvrawdepay->up = up;
217   rtpvrawdepay->vp = vp;
218   rtpvrawdepay->pgroup = pgroup;
219   rtpvrawdepay->xinc = xinc;
220   rtpvrawdepay->yinc = yinc;
221   rtpvrawdepay->ystride = ystride;
222   rtpvrawdepay->uvstride = uvstride;
223   rtpvrawdepay->outsize = outsize;
224
225   srccaps = gst_caps_new_simple (type,
226       "width", G_TYPE_INT, width,
227       "height", G_TYPE_INT, height,
228       "format", GST_TYPE_FOURCC, fourcc,
229       "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
230
231   res = gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), srccaps);
232   gst_caps_unref (srccaps);
233
234   GST_DEBUG_OBJECT (depayload, "width %d, height %d, format %d", width, height,
235       format);
236   GST_DEBUG_OBJECT (depayload, "yp %d, up %d, vp %d", yp, up, vp);
237   GST_DEBUG_OBJECT (depayload, "pgroup %d, ystride %d, uvstride %d", pgroup,
238       ystride, uvstride);
239   GST_DEBUG_OBJECT (depayload, "outsize %u", outsize);
240
241   return res;
242
243   /* ERRORS */
244 no_width:
245   {
246     GST_ERROR_OBJECT (depayload, "no width specified");
247     return FALSE;
248   }
249 no_height:
250   {
251     GST_ERROR_OBJECT (depayload, "no height specified");
252     return FALSE;
253   }
254 interlaced:
255   {
256     GST_ERROR_OBJECT (depayload, "interlaced formats not supported yet");
257     return FALSE;
258   }
259 no_sampling:
260   {
261     GST_ERROR_OBJECT (depayload, "no sampling specified");
262     return FALSE;
263   }
264 unknown_format:
265   {
266     GST_ERROR_OBJECT (depayload, "unknown sampling format '%s'", str);
267     return FALSE;
268   }
269 }
270
271 static GstBuffer *
272 gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
273 {
274   GstRtpVRawDepay *rtpvrawdepay;
275   gint payload_len;
276   guint8 *payload, *data, *yp, *up, *vp, *headers;
277   guint32 timestamp;
278   guint cont, ystride, uvstride, pgroup;
279
280   rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload);
281
282   payload_len = gst_rtp_buffer_get_payload_len (buf);
283
284   timestamp = gst_rtp_buffer_get_timestamp (buf);
285
286   if (timestamp != rtpvrawdepay->timestamp || rtpvrawdepay->outbuf == NULL) {
287     GstBuffer *outbuf;
288     GstFlowReturn ret;
289
290     GST_LOG_OBJECT (depayload, "new frame with timestamp %u", timestamp);
291     /* new timestamp, flush old buffer and create new output buffer */
292     if (rtpvrawdepay->outbuf) {
293       gst_base_rtp_depayload_push_ts (depayload, rtpvrawdepay->timestamp,
294           rtpvrawdepay->outbuf);
295       rtpvrawdepay->outbuf = NULL;
296     }
297
298     ret = gst_pad_alloc_buffer (depayload->srcpad, -1, rtpvrawdepay->outsize,
299         GST_PAD_CAPS (depayload->srcpad), &outbuf);
300     if (ret != GST_FLOW_OK)
301       goto alloc_failed;
302
303     /* clear timestamp from alloc... */
304     GST_BUFFER_TIMESTAMP (outbuf) = -1;
305
306     rtpvrawdepay->outbuf = outbuf;
307     rtpvrawdepay->timestamp = timestamp;
308   }
309
310   data = GST_BUFFER_DATA (rtpvrawdepay->outbuf);
311
312   /* get pointer and strides of the planes */
313   yp = data + rtpvrawdepay->yp;
314   up = data + rtpvrawdepay->up;
315   vp = data + rtpvrawdepay->vp;
316
317   ystride = rtpvrawdepay->ystride;
318   uvstride = rtpvrawdepay->uvstride;
319   pgroup = rtpvrawdepay->pgroup;
320
321   payload = gst_rtp_buffer_get_payload (buf);
322
323   /* skip extended seqnum */
324   payload++;
325   payload++;
326
327   /* remember header position */
328   headers = payload;
329
330   /* find data start */
331   do {
332     cont = payload[4] & 0x80;
333     payload += 6;
334   } while (cont);
335
336   while (TRUE) {
337     guint length, line, offs;
338     guint8 *datap;
339
340     /* read length and cont */
341     length = (headers[0] << 8) | headers[1];
342     line = ((headers[2] & 0x7f) << 8) | headers[3];
343     offs = ((headers[4] & 0x7f) << 8) | headers[5];
344     cont = headers[4] & 0x80;
345     headers += 6;
346
347     /* sanity check */
348     if (line > (rtpvrawdepay->height - rtpvrawdepay->yinc))
349       continue;
350     if (offs > (rtpvrawdepay->width - rtpvrawdepay->xinc))
351       continue;
352
353     GST_LOG_OBJECT (depayload, "writing length %u, line %u, offset %u", length,
354         line, offs);
355
356     switch (rtpvrawdepay->format) {
357       case GST_VIDEO_FORMAT_RGB:
358       case GST_VIDEO_FORMAT_RGBA:
359       case GST_VIDEO_FORMAT_BGR:
360       case GST_VIDEO_FORMAT_BGRA:
361       case GST_VIDEO_FORMAT_UYVY:
362         /* samples are packed just like gstreamer packs them */
363         offs /= rtpvrawdepay->xinc;
364         datap = yp + (line * ystride) + (offs * pgroup);
365         memcpy (datap, payload, length);
366         payload += length;
367         break;
368       case GST_VIDEO_FORMAT_AYUV:
369       {
370         gint i;
371
372         datap = yp + (line * ystride) + (offs * 4);
373
374         /* samples are packed in order Cb-Y-Cr for both interlaced and
375          * progressive frames */
376         for (i = 0; i < length; i += pgroup) {
377           *datap++ = 0;
378           *datap++ = payload[1];
379           *datap++ = payload[0];
380           *datap++ = payload[2];
381           payload += pgroup;
382         }
383         break;
384       }
385       case GST_VIDEO_FORMAT_I420:
386       {
387         gint i;
388         guint uvoff;
389         guint8 *yd1p, *yd2p, *udp, *vdp;
390
391         yd1p = yp + (line * ystride) + (offs);
392         yd2p = yd1p + ystride;
393         uvoff =
394             (line / rtpvrawdepay->yinc * uvstride) +
395             (offs / rtpvrawdepay->xinc);
396         udp = up + uvoff;
397         vdp = vp + uvoff;
398
399         /* line 0/1: Y00-Y01-Y10-Y11-Cb00-Cr00 Y02-Y03-Y12-Y13-Cb01-Cr01 ...  */
400         for (i = 0; i < length; i += pgroup) {
401           *yd1p++ = payload[0];
402           *yd1p++ = payload[1];
403           *yd2p++ = payload[2];
404           *yd2p++ = payload[3];
405           *udp++ = payload[4];
406           *vdp++ = payload[5];
407           payload += pgroup;
408         }
409         break;
410       }
411       case GST_VIDEO_FORMAT_Y41B:
412       {
413         gint i;
414         guint uvoff;
415         guint8 *ydp, *udp, *vdp;
416
417         ydp = yp + (line * ystride) + (offs);
418         uvoff =
419             (line / rtpvrawdepay->yinc * uvstride) +
420             (offs / rtpvrawdepay->xinc);
421         udp = up + uvoff;
422         vdp = vp + uvoff;
423
424         /* Samples are packed in order Cb0-Y0-Y1-Cr0-Y2-Y3 for both interlaced
425          * and progressive scan lines */
426         for (i = 0; i < length; i += pgroup) {
427           *udp++ = payload[0];
428           *ydp++ = payload[1];
429           *ydp++ = payload[2];
430           *vdp++ = payload[3];
431           *ydp++ = payload[4];
432           *ydp++ = payload[5];
433           payload += pgroup;
434         }
435         break;
436       }
437       default:
438         goto unknown_sampling;
439     }
440
441     if (!cont)
442       break;
443   }
444
445   if (gst_rtp_buffer_get_marker (buf)) {
446     GST_LOG_OBJECT (depayload, "marker, flushing frame");
447     if (rtpvrawdepay->outbuf) {
448       gst_base_rtp_depayload_push_ts (depayload, timestamp,
449           rtpvrawdepay->outbuf);
450       rtpvrawdepay->outbuf = NULL;
451     }
452     rtpvrawdepay->timestamp = -1;
453   }
454   return NULL;
455
456   /* ERRORS */
457 unknown_sampling:
458   {
459     GST_ELEMENT_ERROR (depayload, STREAM, FORMAT,
460         (NULL), ("unimplemented sampling"));
461     return NULL;
462   }
463 alloc_failed:
464   {
465     GST_DEBUG_OBJECT (depayload, "failed to alloc output buffer");
466     return NULL;
467   }
468 }
469
470 static GstStateChangeReturn
471 gst_rtp_vraw_depay_change_state (GstElement * element,
472     GstStateChange transition)
473 {
474   GstRtpVRawDepay *rtpvrawdepay;
475   GstStateChangeReturn ret;
476
477   rtpvrawdepay = GST_RTP_VRAW_DEPAY (element);
478
479   switch (transition) {
480     case GST_STATE_CHANGE_NULL_TO_READY:
481       break;
482     case GST_STATE_CHANGE_READY_TO_PAUSED:
483       rtpvrawdepay->timestamp = -1;
484       break;
485     default:
486       break;
487   }
488
489   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
490
491   switch (transition) {
492     case GST_STATE_CHANGE_PAUSED_TO_READY:
493       if (rtpvrawdepay->outbuf) {
494         gst_buffer_unref (rtpvrawdepay->outbuf);
495         rtpvrawdepay->outbuf = NULL;
496       }
497       break;
498     case GST_STATE_CHANGE_READY_TO_NULL:
499       break;
500     default:
501       break;
502   }
503   return ret;
504 }
505
506 gboolean
507 gst_rtp_vraw_depay_plugin_init (GstPlugin * plugin)
508 {
509   return gst_element_register (plugin, "rtpvrawdepay",
510       GST_RANK_MARGINAL, GST_TYPE_RTP_VRAW_DEPAY);
511 }