Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.git] / gst / rtp / gstrtpvrawpay.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 <string.h>
25
26 #include <gst/rtp/gstrtpbuffer.h>
27
28 #include "gstrtpvrawpay.h"
29
30 GST_DEBUG_CATEGORY_STATIC (rtpvrawpay_debug);
31 #define GST_CAT_DEFAULT (rtpvrawpay_debug)
32
33 static GstStaticPadTemplate gst_rtp_vraw_pay_sink_template =
34     GST_STATIC_PAD_TEMPLATE ("sink",
35     GST_PAD_SINK,
36     GST_PAD_ALWAYS,
37     GST_STATIC_CAPS ("video/x-raw-rgb, "
38         "bpp = (int) 24, "
39         "depth = (int) 24, "
40         "endianness = (int) BIG_ENDIAN, "
41         "red_mask =   (int) 0x00FF0000, "
42         "green_mask = (int) 0x0000FF00, "
43         "blue_mask =  (int) 0x000000FF, "
44         "width = (int) [ 1, 32767 ], "
45         "height = (int) [ 1, 32767 ]; "
46         "video/x-raw-rgb, "
47         "bpp = (int) 32, "
48         "depth = (int) 32, "
49         "endianness = (int) BIG_ENDIAN, "
50         "red_mask =   (int) 0xFF000000, "
51         "green_mask = (int) 0x00FF0000, "
52         "blue_mask =  (int) 0x0000FF00, "
53         "alpha_mask = (int) 0x000000FF, "
54         "width = (int) [ 1, 32767 ], "
55         "height = (int) [ 1, 32767 ]; "
56         "video/x-raw-rgb, "
57         "bpp = (int) 24, "
58         "depth = (int) 24, "
59         "endianness = (int) BIG_ENDIAN, "
60         "red_mask =   (int) 0x000000FF, "
61         "green_mask = (int) 0x0000FF00, "
62         "blue_mask =  (int) 0x00FF0000, "
63         "width = (int) [ 1, 32767 ], "
64         "height = (int) [ 1, 32767 ]; "
65         "video/x-raw-rgb, "
66         "bpp = (int) 32, "
67         "depth = (int) 32, "
68         "endianness = (int) BIG_ENDIAN, "
69         "red_mask =   (int) 0x0000FF00, "
70         "green_mask = (int) 0x00FF0000, "
71         "blue_mask =  (int) 0xFF000000, "
72         "alpha_mask = (int) 0x000000FF, "
73         "width = (int) [ 1, 32767 ], "
74         "height = (int) [ 1, 32767 ]; "
75         "video/x-raw-yuv, "
76         "format = (fourcc) { AYUV, UYVY, I420, Y41B, UYVP }, "
77         "width = (int) [ 1, 32767 ], " "height = (int) [ 1, 32767 ]; ")
78     );
79
80 static GstStaticPadTemplate gst_rtp_vraw_pay_src_template =
81 GST_STATIC_PAD_TEMPLATE ("src",
82     GST_PAD_SRC,
83     GST_PAD_ALWAYS,
84     GST_STATIC_CAPS ("application/x-rtp, "
85         "media = (string) \"video\", "
86         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
87         "clock-rate = (int) 90000, "
88         "encoding-name = (string) \"RAW\","
89         "sampling = (string) { \"RGB\", \"RGBA\", \"BGR\", \"BGRA\", "
90         "\"YCbCr-4:4:4\", \"YCbCr-4:2:2\", \"YCbCr-4:2:0\", "
91         "\"YCbCr-4:1:1\" },"
92         /* we cannot express these as strings 
93          * "width = (string) [1 32767],"
94          * "height = (string) [1 32767],"
95          */
96         "depth = (string) { \"8\", \"10\", \"12\", \"16\" },"
97         "colorimetry = (string) { \"BT601-5\", \"BT709-2\", \"SMPTE240M\" }"
98         /* optional 
99          * interlace = 
100          * top-field-first = 
101          * chroma-position = (string) 
102          * gamma = (float)
103          */
104     )
105     );
106
107 static gboolean gst_rtp_vraw_pay_setcaps (GstBaseRTPPayload * payload,
108     GstCaps * caps);
109 static GstFlowReturn gst_rtp_vraw_pay_handle_buffer (GstBaseRTPPayload *
110     payload, GstBuffer * buffer);
111
112 GST_BOILERPLATE (GstRtpVRawPay, gst_rtp_vraw_pay, GstBaseRTPPayload,
113     GST_TYPE_BASE_RTP_PAYLOAD)
114
115      static void gst_rtp_vraw_pay_base_init (gpointer klass)
116 {
117   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
118
119   gst_element_class_add_static_pad_template (element_class,
120       &gst_rtp_vraw_pay_src_template);
121   gst_element_class_add_static_pad_template (element_class,
122       &gst_rtp_vraw_pay_sink_template);
123
124   gst_element_class_set_details_simple (element_class,
125       "RTP Raw Video payloader", "Codec/Payloader/Network/RTP",
126       "Payload raw video as RTP packets (RFC 4175)",
127       "Wim Taymans <wim.taymans@gmail.com>");
128 }
129
130 static void
131 gst_rtp_vraw_pay_class_init (GstRtpVRawPayClass * klass)
132 {
133   GstBaseRTPPayloadClass *gstbasertppayload_class;
134
135   gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
136
137   gstbasertppayload_class->set_caps = gst_rtp_vraw_pay_setcaps;
138   gstbasertppayload_class->handle_buffer = gst_rtp_vraw_pay_handle_buffer;
139
140   GST_DEBUG_CATEGORY_INIT (rtpvrawpay_debug, "rtpvrawpay", 0,
141       "Raw video RTP Payloader");
142 }
143
144 static void
145 gst_rtp_vraw_pay_init (GstRtpVRawPay * rtpvrawpay, GstRtpVRawPayClass * klass)
146 {
147 }
148
149 static gboolean
150 gst_rtp_vraw_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
151 {
152   GstRtpVRawPay *rtpvrawpay;
153   GstStructure *s;
154   gboolean res;
155   const gchar *name;
156   gint width, height;
157   gint yp, up, vp;
158   gint pgroup, ystride, uvstride = 0, xinc, yinc;
159   GstVideoFormat sampling;
160   const gchar *depthstr, *samplingstr, *colorimetrystr;
161   gchar *wstr, *hstr;
162   gboolean interlaced;
163   const gchar *color_matrix;
164   gint depth;
165
166   rtpvrawpay = GST_RTP_VRAW_PAY (payload);
167
168   s = gst_caps_get_structure (caps, 0);
169
170   /* start parsing the format */
171   name = gst_structure_get_name (s);
172
173   /* these values are the only thing we can do */
174   depthstr = "8";
175
176   /* parse common width/height */
177   res = gst_structure_get_int (s, "width", &width);
178   res &= gst_structure_get_int (s, "height", &height);
179   if (!res)
180     goto missing_dimension;
181
182   if (!gst_structure_get_boolean (s, "interlaced", &interlaced))
183     interlaced = FALSE;
184
185   color_matrix = gst_structure_get_string (s, "color-matrix");
186   colorimetrystr = "SMPTE240M";
187   if (color_matrix) {
188     if (g_str_equal (color_matrix, "sdtv")) {
189       /* BT.601 implies a bit more than just color-matrix */
190       colorimetrystr = "BT601-5";
191     } else if (g_str_equal (color_matrix, "hdtv")) {
192       colorimetrystr = "BT709-2";
193     }
194   }
195
196   yp = up = vp = 0;
197   xinc = yinc = 1;
198
199   if (!strcmp (name, "video/x-raw-rgb")) {
200     gint amask, rmask;
201     gboolean has_alpha;
202
203     has_alpha = gst_structure_get_int (s, "alpha_mask", &amask);
204     depth = 8;
205
206     if (!gst_structure_get_int (s, "red_mask", &rmask))
207       goto unknown_mask;
208
209     if (has_alpha) {
210       pgroup = 4;
211       ystride = width * 4;
212       if (rmask == 0xFF000000) {
213         sampling = GST_VIDEO_FORMAT_RGBA;
214         samplingstr = "RGBA";
215       } else {
216         sampling = GST_VIDEO_FORMAT_BGRA;
217         samplingstr = "BGRA";
218       }
219     } else {
220       pgroup = 3;
221       ystride = GST_ROUND_UP_4 (width * 3);
222       if (rmask == 0x00FF0000) {
223         sampling = GST_VIDEO_FORMAT_RGB;
224         samplingstr = "RGB";
225       } else {
226         sampling = GST_VIDEO_FORMAT_BGR;
227         samplingstr = "BGR";
228       }
229     }
230   } else if (!strcmp (name, "video/x-raw-yuv")) {
231     guint32 fourcc;
232
233     if (!gst_structure_get_fourcc (s, "format", &fourcc))
234       goto unknown_fourcc;
235
236     GST_LOG_OBJECT (payload, "have fourcc %" GST_FOURCC_FORMAT,
237         GST_FOURCC_ARGS (fourcc));
238
239     switch (fourcc) {
240       case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
241         sampling = GST_VIDEO_FORMAT_AYUV;
242         samplingstr = "YCbCr-4:4:4";
243         pgroup = 3;
244         ystride = width * 4;
245         depth = 8;
246         break;
247       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
248         sampling = GST_VIDEO_FORMAT_UYVY;
249         samplingstr = "YCbCr-4:2:2";
250         pgroup = 4;
251         xinc = 2;
252         ystride = GST_ROUND_UP_2 (width) * 2;
253         depth = 8;
254         break;
255       case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
256         sampling = GST_VIDEO_FORMAT_Y41B;
257         samplingstr = "YCbCr-4:1:1";
258         pgroup = 6;
259         xinc = 4;
260         ystride = GST_ROUND_UP_4 (width);
261         uvstride = GST_ROUND_UP_8 (width) / 4;
262         up = ystride * height;
263         vp = up + uvstride * height;
264         depth = 8;
265         break;
266       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
267         sampling = GST_VIDEO_FORMAT_I420;
268         samplingstr = "YCbCr-4:2:0";
269         pgroup = 6;
270         xinc = yinc = 2;
271         ystride = GST_ROUND_UP_4 (width);
272         uvstride = GST_ROUND_UP_8 (width) / 2;
273         up = ystride * GST_ROUND_UP_2 (height);
274         vp = up + uvstride * GST_ROUND_UP_2 (height) / 2;
275         depth = 8;
276         break;
277       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'P'):
278 #define GST_VIDEO_FORMAT_UYVP GST_VIDEO_FORMAT_UYVY     /* FIXME */
279         sampling = GST_VIDEO_FORMAT_UYVP;
280         samplingstr = "YCbCr-4:2:2";
281         pgroup = 4;
282         xinc = 2;
283         ystride = GST_ROUND_UP_2 (width) * 2;
284         depth = 10;
285         break;
286       default:
287         goto unknown_fourcc;
288     }
289   } else
290     goto unknown_format;
291
292   if (interlaced) {
293     yinc *= 2;
294   }
295   if (depth == 10) {
296     depthstr = "10";
297   }
298
299   rtpvrawpay->width = width;
300   rtpvrawpay->height = height;
301   rtpvrawpay->sampling = sampling;
302   rtpvrawpay->pgroup = pgroup;
303   rtpvrawpay->xinc = xinc;
304   rtpvrawpay->yinc = yinc;
305   rtpvrawpay->yp = yp;
306   rtpvrawpay->up = up;
307   rtpvrawpay->vp = vp;
308   rtpvrawpay->ystride = ystride;
309   rtpvrawpay->uvstride = uvstride;
310   rtpvrawpay->interlaced = interlaced;
311   rtpvrawpay->depth = depth;
312
313   GST_DEBUG_OBJECT (payload, "width %d, height %d, sampling %d", width, height,
314       sampling);
315   GST_DEBUG_OBJECT (payload, "yp %d, up %d, vp %d", yp, up, vp);
316   GST_DEBUG_OBJECT (payload, "pgroup %d, ystride %d, uvstride %d", pgroup,
317       ystride, uvstride);
318
319   wstr = g_strdup_printf ("%d", rtpvrawpay->width);
320   hstr = g_strdup_printf ("%d", rtpvrawpay->height);
321
322   gst_basertppayload_set_options (payload, "video", TRUE, "RAW", 90000);
323   if (interlaced) {
324     res = gst_basertppayload_set_outcaps (payload, "sampling", G_TYPE_STRING,
325         samplingstr, "depth", G_TYPE_STRING, depthstr, "width", G_TYPE_STRING,
326         wstr, "height", G_TYPE_STRING, hstr, "colorimetry", G_TYPE_STRING,
327         colorimetrystr, "interlace", G_TYPE_STRING, "true", NULL);
328   } else {
329     res = gst_basertppayload_set_outcaps (payload, "sampling", G_TYPE_STRING,
330         samplingstr, "depth", G_TYPE_STRING, depthstr, "width", G_TYPE_STRING,
331         wstr, "height", G_TYPE_STRING, hstr, "colorimetry", G_TYPE_STRING,
332         colorimetrystr, NULL);
333   }
334   g_free (wstr);
335   g_free (hstr);
336
337   return res;
338
339   /* ERRORS */
340 unknown_mask:
341   {
342     GST_ERROR_OBJECT (payload, "unknown red mask specified");
343     return FALSE;
344   }
345 unknown_format:
346   {
347     GST_ERROR_OBJECT (payload, "unknown caps format");
348     return FALSE;
349   }
350 unknown_fourcc:
351   {
352     GST_ERROR_OBJECT (payload, "invalid or missing fourcc");
353     return FALSE;
354   }
355 missing_dimension:
356   {
357     GST_ERROR_OBJECT (payload, "missing width or height property");
358     return FALSE;
359   }
360 }
361
362 static GstFlowReturn
363 gst_rtp_vraw_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer)
364 {
365   GstRtpVRawPay *rtpvrawpay;
366   GstFlowReturn ret = GST_FLOW_OK;
367   guint line, offset;
368   guint8 *data, *yp, *up, *vp;
369   guint ystride, uvstride;
370   guint size, pgroup;
371   guint mtu;
372   guint width, height;
373   gint field;
374
375   rtpvrawpay = GST_RTP_VRAW_PAY (payload);
376
377   data = GST_BUFFER_DATA (buffer);
378   size = GST_BUFFER_SIZE (buffer);
379
380   GST_LOG_OBJECT (rtpvrawpay, "new frame of %u bytes", size);
381
382   /* get pointer and strides of the planes */
383   yp = data + rtpvrawpay->yp;
384   up = data + rtpvrawpay->up;
385   vp = data + rtpvrawpay->vp;
386
387   ystride = rtpvrawpay->ystride;
388   uvstride = rtpvrawpay->uvstride;
389
390   mtu = GST_BASE_RTP_PAYLOAD_MTU (payload);
391
392   /* amount of bytes for one pixel */
393   pgroup = rtpvrawpay->pgroup;
394   width = rtpvrawpay->width;
395   height = rtpvrawpay->height;
396
397   /* start with line 0, offset 0 */
398
399   for (field = 0; field < 1 + rtpvrawpay->interlaced; field++) {
400     line = field;
401     offset = 0;
402
403     /* write all lines */
404     while (line < height) {
405       guint left;
406       GstBuffer *out;
407       guint8 *outdata, *headers;
408       gboolean next_line;
409       guint length, cont, pixels;
410
411       /* get the max allowed payload length size, we try to fill the complete MTU */
412       left = gst_rtp_buffer_calc_payload_len (mtu, 0, 0);
413       out = gst_rtp_buffer_new_allocate (left, 0, 0);
414
415       if (field == 0) {
416         GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (buffer);
417       } else {
418         GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (buffer) +
419             GST_BUFFER_DURATION (buffer) / 2;
420       }
421
422       outdata = gst_rtp_buffer_get_payload (out);
423
424       GST_LOG_OBJECT (rtpvrawpay, "created buffer of size %u for MTU %u", left,
425           mtu);
426
427       /*
428        *   0                   1                   2                   3
429        *   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
430        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
431        *  |   Extended Sequence Number    |            Length             |
432        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433        *  |F|          Line No            |C|           Offset            |
434        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435        *  |            Length             |F|          Line No            |
436        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437        *  |C|           Offset            |                               .
438        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               .
439        *  .                                                               .
440        *  .                 Two (partial) lines of video data             .
441        *  .                                                               .
442        *  +---------------------------------------------------------------+
443        */
444
445       /* need 2 bytes for the extended sequence number */
446       *outdata++ = 0;
447       *outdata++ = 0;
448       left -= 2;
449
450       /* the headers start here */
451       headers = outdata;
452
453       /* while we can fit at least one header and one pixel */
454       while (left > (6 + pgroup)) {
455         /* we need a 6 bytes header */
456         left -= 6;
457
458         /* get how may bytes we need for the remaining pixels */
459         pixels = width - offset;
460         length = (pixels * pgroup) / rtpvrawpay->xinc;
461
462         if (left >= length) {
463           /* pixels and header fit completely, we will write them and skip to the
464            * next line. */
465           next_line = TRUE;
466         } else {
467           /* line does not fit completely, see how many pixels fit */
468           pixels = (left / pgroup) * rtpvrawpay->xinc;
469           length = (pixels * pgroup) / rtpvrawpay->xinc;
470           next_line = FALSE;
471         }
472         GST_LOG_OBJECT (rtpvrawpay, "filling %u bytes in %u pixels", length,
473             pixels);
474         left -= length;
475
476         /* write length */
477         *outdata++ = (length >> 8) & 0xff;
478         *outdata++ = length & 0xff;
479
480         /* write line no */
481         *outdata++ = ((line >> 8) & 0x7f) | ((field << 7) & 0x80);
482         *outdata++ = line & 0xff;
483
484         if (next_line) {
485           /* go to next line we do this here to make the check below easier */
486           line += rtpvrawpay->yinc;
487         }
488
489         /* calculate continuation marker */
490         cont = (left > (6 + pgroup) && line < height) ? 0x80 : 0x00;
491
492         /* write offset and continuation marker */
493         *outdata++ = ((offset >> 8) & 0x7f) | cont;
494         *outdata++ = offset & 0xff;
495
496         if (next_line) {
497           /* reset offset */
498           offset = 0;
499           GST_LOG_OBJECT (rtpvrawpay, "go to next line %u", line);
500         } else {
501           offset += pixels;
502           GST_LOG_OBJECT (rtpvrawpay, "next offset %u", offset);
503         }
504
505         if (!cont)
506           break;
507       }
508       GST_LOG_OBJECT (rtpvrawpay, "consumed %u bytes",
509           (guint) (outdata - headers));
510
511       /* second pass, read headers and write the data */
512       while (TRUE) {
513         guint offs, lin;
514
515         /* read length and cont */
516         length = (headers[0] << 8) | headers[1];
517         lin = ((headers[2] & 0x7f) << 8) | headers[3];
518         offs = ((headers[4] & 0x7f) << 8) | headers[5];
519         cont = headers[4] & 0x80;
520         pixels = length / pgroup;
521         headers += 6;
522
523         GST_LOG_OBJECT (payload,
524             "writing length %u, line %u, offset %u, cont %d", length, lin, offs,
525             cont);
526
527         switch (rtpvrawpay->sampling) {
528           case GST_VIDEO_FORMAT_RGB:
529           case GST_VIDEO_FORMAT_RGBA:
530           case GST_VIDEO_FORMAT_BGR:
531           case GST_VIDEO_FORMAT_BGRA:
532           case GST_VIDEO_FORMAT_UYVY:
533             offs /= rtpvrawpay->xinc;
534             memcpy (outdata, yp + (lin * ystride) + (offs * pgroup), length);
535             outdata += length;
536             break;
537           case GST_VIDEO_FORMAT_AYUV:
538           {
539             gint i;
540             guint8 *datap;
541
542             datap = yp + (lin * ystride) + (offs * 4);
543
544             for (i = 0; i < pixels; i++) {
545               *outdata++ = datap[2];
546               *outdata++ = datap[1];
547               *outdata++ = datap[3];
548               datap += 4;
549             }
550             break;
551           }
552           case GST_VIDEO_FORMAT_I420:
553           {
554             gint i;
555             guint uvoff;
556             guint8 *yd1p, *yd2p, *udp, *vdp;
557
558             yd1p = yp + (lin * ystride) + (offs);
559             yd2p = yd1p + ystride;
560             uvoff =
561                 (lin / rtpvrawpay->yinc * uvstride) + (offs / rtpvrawpay->xinc);
562             udp = up + uvoff;
563             vdp = vp + uvoff;
564
565             for (i = 0; i < pixels; i++) {
566               *outdata++ = *yd1p++;
567               *outdata++ = *yd1p++;
568               *outdata++ = *yd2p++;
569               *outdata++ = *yd2p++;
570               *outdata++ = *udp++;
571               *outdata++ = *vdp++;
572             }
573             break;
574           }
575           case GST_VIDEO_FORMAT_Y41B:
576           {
577             gint i;
578             guint uvoff;
579             guint8 *ydp, *udp, *vdp;
580
581             ydp = yp + (lin * ystride) + offs;
582             uvoff =
583                 (lin / rtpvrawpay->yinc * uvstride) + (offs / rtpvrawpay->xinc);
584             udp = up + uvoff;
585             vdp = vp + uvoff;
586
587             for (i = 0; i < pixels; i++) {
588               *outdata++ = *udp++;
589               *outdata++ = *ydp++;
590               *outdata++ = *ydp++;
591               *outdata++ = *vdp++;
592               *outdata++ = *ydp++;
593               *outdata++ = *ydp++;
594             }
595             break;
596           }
597           default:
598             gst_buffer_unref (out);
599             goto unknown_sampling;
600         }
601
602         if (!cont)
603           break;
604       }
605
606       if (line >= height) {
607         GST_LOG_OBJECT (rtpvrawpay, "field/frame complete, set marker");
608         gst_rtp_buffer_set_marker (out, TRUE);
609       }
610       if (left > 0) {
611         GST_LOG_OBJECT (rtpvrawpay, "we have %u bytes left", left);
612         GST_BUFFER_SIZE (out) -= left;
613       }
614
615       /* push buffer */
616       ret = gst_basertppayload_push (payload, out);
617     }
618
619   }
620   gst_buffer_unref (buffer);
621
622   return ret;
623
624   /* ERRORS */
625 unknown_sampling:
626   {
627     GST_ELEMENT_ERROR (payload, STREAM, FORMAT,
628         (NULL), ("unimplemented sampling"));
629     gst_buffer_unref (buffer);
630     return GST_FLOW_NOT_SUPPORTED;
631   }
632 }
633
634 gboolean
635 gst_rtp_vraw_pay_plugin_init (GstPlugin * plugin)
636 {
637   return gst_element_register (plugin, "rtpvrawpay",
638       GST_RANK_SECONDARY, GST_TYPE_RTP_VRAW_PAY);
639 }