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