[PATCH 14/33] kmssink: do modeset
[gstreamer-omap:gst-plugins-bad.git] / sys / kms / gstkmssink.c
1 /* GStreamer
2  * Copyright (C) 2012 Texas Instruments
3  * Copyright (C) 2012 Collabora Ltd
4  *
5  * Authors:
6  *  Alessandro Decina <alessandro.decina@collabora.co.uk>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  * Authors:
24  *  Alessandro Decina <alessandro.decina@collabora.co.uk>
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <gst/video/videocontext.h>
32 #include "gstkmssink.h"
33 #include "gstkmsbufferpriv.h"
34
35 #include <omap_drm.h>
36 #include <omap_drmif.h>
37 #include <xf86drmMode.h>
38
39 GST_DEBUG_CATEGORY_STATIC (gst_debug_kms_sink);
40 #define GST_CAT_DEFAULT gst_debug_kms_sink
41
42 static void
43 gst_kms_sink_video_context_interface_init (GstVideoContextInterface * iface);
44
45 G_DEFINE_TYPE_EXTENDED (GstKMSSink, gst_kms_sink, GST_TYPE_VIDEO_SINK, 0,
46     G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_CONTEXT,
47         gst_kms_sink_video_context_interface_init));
48
49 static void gst_kms_sink_reset (GstKMSSink * sink);
50
51 static GstStaticPadTemplate gst_kms_sink_template_factory =
52 GST_STATIC_PAD_TEMPLATE ("sink",
53     GST_PAD_SINK,
54     GST_PAD_ALWAYS,
55     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12"))
56     );
57
58 enum
59 {
60   PROP_0,
61   PROP_PIXEL_ASPECT_RATIO,
62   PROP_FORCE_ASPECT_RATIO,
63   PROP_SCALE,
64   PROP_CONNECTOR,
65 };
66
67 static gboolean
68 gst_kms_sink_calculate_aspect_ratio (GstKMSSink * sink, gint width,
69     gint height, gint video_par_n, gint video_par_d)
70 {
71   guint calculated_par_n;
72   guint calculated_par_d;
73
74   if (!gst_video_calculate_display_ratio (&calculated_par_n, &calculated_par_d,
75           width, height, video_par_n, video_par_d, 1, 1)) {
76     GST_ELEMENT_ERROR (sink, CORE, NEGOTIATION, (NULL),
77         ("Error calculating the output display ratio of the video."));
78     return FALSE;
79   }
80   GST_DEBUG_OBJECT (sink,
81       "video width/height: %dx%d, calculated display ratio: %d/%d",
82       width, height, calculated_par_n, calculated_par_d);
83
84   /* now find a width x height that respects this display ratio.
85    * prefer those that have one of w/h the same as the incoming video
86    * using wd / hd = calculated_pad_n / calculated_par_d */
87
88   /* start with same height, because of interlaced video */
89   /* check hd / calculated_par_d is an integer scale factor, and scale wd with the PAR */
90   if (height % calculated_par_d == 0) {
91     GST_DEBUG_OBJECT (sink, "keeping video height");
92     GST_VIDEO_SINK_WIDTH (sink) = (guint)
93         gst_util_uint64_scale_int (height, calculated_par_n, calculated_par_d);
94     GST_VIDEO_SINK_HEIGHT (sink) = height;
95   } else if (width % calculated_par_n == 0) {
96     GST_DEBUG_OBJECT (sink, "keeping video width");
97     GST_VIDEO_SINK_WIDTH (sink) = width;
98     GST_VIDEO_SINK_HEIGHT (sink) = (guint)
99         gst_util_uint64_scale_int (width, calculated_par_d, calculated_par_n);
100   } else {
101     GST_DEBUG_OBJECT (sink, "approximating while keeping video height");
102     GST_VIDEO_SINK_WIDTH (sink) = (guint)
103         gst_util_uint64_scale_int (height, calculated_par_n, calculated_par_d);
104     GST_VIDEO_SINK_HEIGHT (sink) = height;
105   }
106   GST_DEBUG_OBJECT (sink, "scaling to %dx%d",
107       GST_VIDEO_SINK_WIDTH (sink), GST_VIDEO_SINK_HEIGHT (sink));
108
109   return TRUE;
110 }
111
112 static gboolean
113 gst_kms_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
114 {
115   GstKMSSink *sink;
116   gboolean ret = TRUE;
117   gint width, height;
118   gint fps_n, fps_d;
119   gint par_n, par_d;
120   GstVideoFormat format;
121
122   sink = GST_KMS_SINK (bsink);
123
124   ret = gst_video_format_parse_caps (caps, &format, &width, &height);
125   ret &= gst_video_parse_caps_framerate (caps, &fps_n, &fps_d);
126   ret &= gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d);
127   if (!ret)
128     return FALSE;
129
130   if (width <= 0 || height <= 0) {
131     GST_ELEMENT_ERROR (sink, CORE, NEGOTIATION, (NULL),
132         ("Invalid image size."));
133     return FALSE;
134   }
135
136   sink->format = format;
137   sink->par_n = par_n;
138   sink->par_d = par_d;
139   sink->src_rect.x = sink->src_rect.y = 0;
140   sink->src_rect.w = width;
141   sink->src_rect.h = height;
142   sink->input_width = width;
143   sink->input_height = height;
144
145   if (!sink->pool || !gst_drm_buffer_pool_check_caps (sink->pool, caps)) {
146     int size;
147
148     if (sink->pool) {
149       gst_drm_buffer_pool_destroy (sink->pool);
150       sink->pool = NULL;
151     }
152
153     size = gst_video_format_get_size (format, width, height);
154     sink->pool = gst_drm_buffer_pool_new (GST_ELEMENT (sink),
155         sink->fd, caps, size);
156   }
157
158   sink->conn.crtc = -1;
159   sink->plane = NULL;
160
161   return TRUE;
162 }
163
164 static void
165 gst_kms_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
166     GstClockTime * start, GstClockTime * end)
167 {
168   GstKMSSink *sink;
169
170   sink = GST_KMS_SINK (bsink);
171
172   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
173     *start = GST_BUFFER_TIMESTAMP (buf);
174     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
175       *end = *start + GST_BUFFER_DURATION (buf);
176     } else {
177       if (sink->fps_n > 0) {
178         *end = *start +
179             gst_util_uint64_scale_int (GST_SECOND, sink->fps_d, sink->fps_n);
180       }
181     }
182   }
183 }
184
185 static gboolean
186 gst_kms_sink_query (GstBaseSink * basesink, GstQuery * query)
187 {
188   gboolean res = FALSE;
189   GstKMSSink *sink = GST_KMS_SINK (basesink);
190
191   switch (GST_QUERY_TYPE (query)) {
192     case GST_QUERY_CUSTOM:
193     {
194       const gchar **types;
195       gint i;
196       GstStructure *structure;
197
198       structure = gst_query_get_structure (query);
199       if (strcmp (gst_structure_get_name (structure), "prepare-video-context"))
200         break;
201
202       types = gst_video_context_query_get_supported_types (query);
203       for (i = 0; types[i]; i++) {
204         if (strcmp (types[i], "drm-fd"))
205           continue;
206
207         if (sink->fd != -1) {
208           gst_structure_set (structure,
209               "video-context-type", G_TYPE_STRING, types[i],
210               "video-context", G_TYPE_INT, sink->fd, NULL);
211
212           res = TRUE;
213         }
214
215         break;
216       }
217
218       break;
219     }
220     default:
221       break;
222   }
223
224   return res;
225 }
226
227 static GstFlowReturn
228 gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * inbuf)
229 {
230   GstKMSSink *sink = GST_KMS_SINK (vsink);
231   GstBuffer *buf = NULL;
232   GstKMSBufferPriv *priv;
233   GstFlowReturn flow_ret = GST_FLOW_OK;
234   int ret;
235
236   GST_INFO_OBJECT (sink, "enter");
237
238   if (sink->conn.crtc == -1) {
239     GstVideoRectangle dest = { 0 };
240
241     if (!gst_drm_connector_find_mode_and_plane (sink->fd,
242             sink->dev, sink->src_rect.w, sink->src_rect.h,
243             sink->resources, sink->plane_resources, &sink->conn, &sink->plane))
244       goto connector_not_found;
245
246     dest.w = sink->conn.mode->hdisplay;
247     dest.h = sink->conn.mode->vdisplay;
248     gst_video_sink_center_rect (sink->src_rect, dest, &sink->dst_rect,
249         sink->scale);
250   }
251
252   priv = gst_kms_buffer_priv (sink, inbuf);
253   if (priv) {
254     buf = gst_buffer_ref (inbuf);
255   } else {
256     GST_LOG_OBJECT (sink, "not a KMS buffer, slow-path!");
257     buf = gst_drm_buffer_pool_get (sink->pool, FALSE);
258     if (buf) {
259       GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_TIMESTAMP (inbuf);
260       GST_BUFFER_DURATION (buf) = GST_BUFFER_DURATION (inbuf);
261       memcpy (GST_BUFFER_DATA (buf),
262           GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
263       priv = gst_kms_buffer_priv (sink, buf);
264     }
265     if (!priv)
266       goto add_fb2_failed;
267   }
268
269   ret = drmModeSetPlane (sink->fd, sink->plane->plane_id,
270       sink->conn.crtc, priv->fb_id, 0,
271       /* make video fullscreen: */
272       sink->dst_rect.x, sink->dst_rect.y, sink->dst_rect.w, sink->dst_rect.h,
273       /* source/cropping coordinates are given in Q16 */
274       sink->src_rect.x << 16, sink->src_rect.y << 16,
275       sink->src_rect.w << 16, sink->src_rect.h << 16);
276   if (ret)
277     goto set_plane_failed;
278
279   if (sink->last_buf)
280     gst_buffer_unref (sink->last_buf);
281
282   sink->last_buf = sink->display_buf;
283   sink->display_buf = gst_buffer_ref (buf);
284
285 out:
286   GST_INFO_OBJECT (sink, "exit");
287   /* TODO: we probably want to unref after displaying the *next* frame */
288   gst_buffer_unref (buf);
289   return flow_ret;
290
291 add_fb2_failed:
292   GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
293       (NULL), ("drmModeAddFB2 failed: %s (%d)", strerror (errno), errno));
294   flow_ret = GST_FLOW_ERROR;
295   goto out;
296
297 set_plane_failed:
298   GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
299       (NULL), ("drmModeSetPlane failed: %s (%d)", strerror (errno), errno));
300   flow_ret = GST_FLOW_ERROR;
301   goto out;
302
303 connector_not_found:
304   GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
305       (NULL), ("connector not found", strerror (errno), errno));
306   goto out;
307 }
308
309
310 static gboolean
311 gst_kms_sink_event (GstBaseSink * bsink, GstEvent * event)
312 {
313   GstKMSSink *sink = GST_KMS_SINK (bsink);
314
315   switch (GST_EVENT_TYPE (event)) {
316     case GST_EVENT_CROP:{
317       gint left, top, width, height;
318       GstStructure *structure;
319       GstMessage *message;
320       GstVideoRectangle *c = &sink->src_rect;
321
322       gst_event_parse_crop (event, &top, &left, &width, &height);
323
324       c->y = top;
325       c->x = left;
326
327       if (width == -1)
328         width = GST_VIDEO_SINK_WIDTH (sink);
329       if (height == -1)
330         height = GST_VIDEO_SINK_HEIGHT (sink);
331
332       c->w = width;
333       c->h = height;
334
335       structure = gst_structure_new ("video-size-src_rect", "width", G_TYPE_INT,
336           width, "height", G_TYPE_INT, height, NULL);
337       message = gst_message_new_application (GST_OBJECT (sink), structure);
338       gst_bus_post (gst_element_get_bus (GST_ELEMENT (sink)), message);
339
340       if (!gst_kms_sink_calculate_aspect_ratio (sink, width, height,
341               sink->par_n, sink->par_d))
342         return FALSE;
343
344       break;
345     }
346     default:
347       break;
348   }
349   if (GST_BASE_SINK_CLASS (gst_kms_sink_parent_class)->event)
350     return GST_BASE_SINK_CLASS (gst_kms_sink_parent_class)->event (bsink,
351         event);
352   else
353     return TRUE;
354 }
355
356 static void
357 gst_kms_sink_set_property (GObject * object, guint prop_id,
358     const GValue * value, GParamSpec * pspec)
359 {
360   GstKMSSink *sink;
361
362   g_return_if_fail (GST_IS_KMS_SINK (object));
363
364   sink = GST_KMS_SINK (object);
365
366   switch (prop_id) {
367     case PROP_FORCE_ASPECT_RATIO:
368       sink->keep_aspect = g_value_get_boolean (value);
369       break;
370     case PROP_SCALE:
371       sink->scale = g_value_get_boolean (value);
372       break;
373     case PROP_CONNECTOR:
374       sink->conn.id = g_value_get_int (value);
375       break;
376     case PROP_PIXEL_ASPECT_RATIO:
377     {
378       GValue *tmp;
379
380       tmp = g_new0 (GValue, 1);
381       g_value_init (tmp, GST_TYPE_FRACTION);
382
383       if (!g_value_transform (value, tmp)) {
384         GST_WARNING_OBJECT (sink, "Could not transform string to aspect ratio");
385         g_free (tmp);
386       } else {
387         sink->par_n = gst_value_get_fraction_numerator (tmp);
388         sink->par_d = gst_value_get_fraction_denominator (tmp);
389         GST_DEBUG_OBJECT (sink, "set PAR to %d/%d", sink->par_n, sink->par_d);
390       }
391     }
392       break;
393     default:
394       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
395       break;
396   }
397 }
398
399 static void
400 gst_kms_sink_get_property (GObject * object, guint prop_id,
401     GValue * value, GParamSpec * pspec)
402 {
403   GstKMSSink *sink;
404
405   g_return_if_fail (GST_IS_KMS_SINK (object));
406
407   sink = GST_KMS_SINK (object);
408
409   switch (prop_id) {
410     case PROP_FORCE_ASPECT_RATIO:
411       g_value_set_boolean (value, sink->keep_aspect);
412       break;
413     case PROP_SCALE:
414       g_value_set_boolean (value, sink->scale);
415       break;
416     case PROP_CONNECTOR:
417       g_value_set_int (value, sink->conn.id);
418       break;
419     case PROP_PIXEL_ASPECT_RATIO:
420     {
421       char *v = g_strdup_printf ("%d/%d", sink->par_n, sink->par_d);
422       g_value_take_string (value, v);
423       break;
424     }
425     default:
426       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
427       break;
428   }
429 }
430
431 static void
432 gst_kms_sink_reset (GstKMSSink * sink)
433 {
434   memset (&sink->conn, 0, sizeof (struct connector));
435
436   if (sink->pool) {
437     gst_drm_buffer_pool_destroy (sink->pool);
438     sink->pool = NULL;
439   }
440
441   if (sink->plane) {
442     drmModeFreePlane (sink->plane);
443     sink->plane = NULL;
444   }
445
446   if (sink->plane_resources) {
447     drmModeFreePlaneResources (sink->plane_resources);
448     sink->plane_resources = NULL;
449   }
450
451   if (sink->resources) {
452     drmModeFreeResources (sink->resources);
453     sink->resources = NULL;
454   }
455
456   if (sink->last_buf) {
457     gst_buffer_unref (sink->last_buf);
458     sink->last_buf = NULL;
459   }
460
461   if (sink->display_buf) {
462     gst_buffer_unref (sink->display_buf);
463     sink->display_buf = NULL;
464   }
465
466   if (sink->dev) {
467     omap_device_del (sink->dev);
468     sink->dev = NULL;
469   }
470
471   if (sink->fd != -1) {
472     close (sink->fd);
473     sink->fd = -1;
474   }
475
476   sink->par_n = sink->par_d = 1;
477   sink->src_rect.x = 0;
478   sink->src_rect.y = 0;
479   sink->src_rect.w = 0;
480   sink->src_rect.h = 0;
481   sink->input_width = 0;
482   sink->input_height = 0;
483   sink->format = GST_VIDEO_FORMAT_UNKNOWN;
484
485   memset (&sink->src_rect, 0, sizeof (GstVideoRectangle));
486   memset (&sink->dst_rect, 0, sizeof (GstVideoRectangle));
487 }
488
489 static gboolean
490 gst_kms_sink_start (GstBaseSink * bsink)
491 {
492   GstKMSSink *sink;
493   const gchar *context_types[] = { "drm-fd", NULL };
494
495   sink = GST_KMS_SINK (bsink);
496
497   gst_video_context_prepare (GST_VIDEO_CONTEXT (sink), context_types);
498   if (sink->fd == -1) {
499     sink->fd = drmOpen ("omapdrm", NULL);
500     if (sink->fd < 0)
501       goto open_failed;
502   }
503
504   sink->dev = omap_device_new (sink->fd);
505   if (sink->dev == NULL)
506     goto device_failed;
507
508   sink->resources = drmModeGetResources (sink->fd);
509   if (sink->resources == NULL)
510     goto resources_failed;
511
512   sink->plane_resources = drmModeGetPlaneResources (sink->fd);
513   if (sink->plane_resources == NULL)
514     goto plane_resources_failed;
515
516   return TRUE;
517
518 fail:
519   gst_kms_sink_reset (sink);
520   return FALSE;
521
522 open_failed:
523   GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
524       (NULL), ("drmOpen failed: %s (%d)", strerror (errno), errno));
525   goto fail;
526
527 device_failed:
528   GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
529       (NULL), ("omap_device_new failed"));
530   goto fail;
531
532 resources_failed:
533   GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
534       (NULL), ("drmModeGetResources failed: %s (%d)", strerror (errno), errno));
535   goto fail;
536
537 plane_resources_failed:
538   GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
539       (NULL), ("drmModeGetPlaneResources failed: %s (%d)",
540           strerror (errno), errno));
541   goto fail;
542 }
543
544 static gboolean
545 gst_kms_sink_stop (GstBaseSink * bsink)
546 {
547   GstKMSSink *sink;
548
549   sink = GST_KMS_SINK (bsink);
550   gst_kms_sink_reset (sink);
551
552   return TRUE;
553 }
554
555 static GstFlowReturn
556 gst_kms_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
557     GstCaps * caps, GstBuffer ** buf)
558 {
559   GstKMSSink *sink;
560   GstFlowReturn ret = GST_FLOW_OK;
561
562   sink = GST_KMS_SINK (bsink);
563
564   GST_DEBUG_OBJECT (sink, "begin");
565
566   if (G_UNLIKELY (!caps)) {
567     GST_WARNING_OBJECT (sink, "have no caps, doing fallback allocation");
568     *buf = NULL;
569     ret = GST_FLOW_OK;
570     goto beach;
571   }
572
573   GST_LOG_OBJECT (sink,
574       "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT
575       " and offset %" G_GUINT64_FORMAT, size, caps, offset);
576
577   /* initialize the buffer pool if not initialized yet */
578   if (G_UNLIKELY (!sink->pool ||
579       gst_drm_buffer_pool_size (sink->pool) != size)) {
580     GstVideoFormat format;
581     gint width, height;
582
583     if (sink->pool) {
584       GST_INFO_OBJECT (sink, "in buffer alloc, pool->size != size");
585       gst_drm_buffer_pool_destroy (sink->pool);
586       sink->pool = NULL;
587     }
588
589     gst_video_format_parse_caps (caps, &format, &width, &height);
590     size = gst_video_format_get_size (format, width, height);
591     sink->pool = gst_drm_buffer_pool_new (GST_ELEMENT (sink),
592         sink->fd, caps, size);
593   }
594   *buf = GST_BUFFER_CAST (gst_drm_buffer_pool_get (sink->pool, FALSE));
595
596 beach:
597   return ret;
598 }
599
600 static void
601 gst_kms_sink_set_video_context (GstVideoContext * context,
602     const gchar * type, const GValue * value)
603 {
604   GstKMSSink *sink = GST_KMS_SINK (context);
605
606   sink->fd = g_value_get_int (value);
607 }
608
609 static void
610 gst_kms_sink_video_context_interface_init (GstVideoContextInterface * iface)
611 {
612   iface->set_context = gst_kms_sink_set_video_context;
613 }
614
615 static void
616 gst_kms_sink_finalize (GObject * object)
617 {
618   GstKMSSink *sink;
619
620   sink = GST_KMS_SINK (object);
621   gst_kms_sink_reset (sink);
622
623   G_OBJECT_CLASS (gst_kms_sink_parent_class)->finalize (object);
624 }
625
626 static void
627 gst_kms_sink_init (GstKMSSink * sink)
628 {
629   sink->fd = -1;
630   gst_kms_sink_reset (sink);
631 }
632
633 static void
634 gst_kms_sink_class_init (GstKMSSinkClass * klass)
635 {
636   GObjectClass *gobject_class;
637   GstElementClass *gstelement_class;
638   GstBaseSinkClass *gstbasesink_class;
639   GstVideoSinkClass *videosink_class;
640
641   gobject_class = (GObjectClass *) klass;
642   gstelement_class = (GstElementClass *) klass;
643   gstbasesink_class = (GstBaseSinkClass *) klass;
644   videosink_class = (GstVideoSinkClass *) klass;
645
646   gobject_class->finalize = gst_kms_sink_finalize;
647   gobject_class->set_property = gst_kms_sink_set_property;
648   gobject_class->get_property = gst_kms_sink_get_property;
649
650   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
651       g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
652           "When enabled, reverse caps negotiation (scaling) will respect "
653           "original aspect ratio", FALSE,
654           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
655   g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
656       g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
657           "The pixel aspect ratio of the device", "1/1",
658           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
659   g_object_class_install_property (gobject_class, PROP_SCALE,
660       g_param_spec_boolean ("scale", "Scale",
661           "When true, scale to render fullscreen", FALSE,
662           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
663   g_object_class_install_property (gobject_class, PROP_CONNECTOR,
664       g_param_spec_int ("connector", "Connector",
665           "DRM connector id", 1, G_MAXINT32, 7,
666           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
667
668   gst_element_class_set_details_simple (gstelement_class,
669       "Video sink", "Sink/Video",
670       "A video sink using the linux kernel mode setting API",
671       "Alessandro Decina <alessandro.d@gmail.com>");
672
673   gst_element_class_add_pad_template (gstelement_class,
674       gst_static_pad_template_get (&gst_kms_sink_template_factory));
675
676   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_kms_sink_setcaps);
677   gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_kms_sink_get_times);
678   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_kms_sink_event);
679   gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_kms_sink_query);
680   gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_kms_sink_start);
681   gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_kms_sink_stop);
682   gstbasesink_class->buffer_alloc =
683       GST_DEBUG_FUNCPTR (gst_kms_sink_buffer_alloc);
684   /* disable preroll as it's called before GST_CROP_EVENT has been received, so
685    * we end up configuring the wrong mode... (based on padded caps)
686    */
687   gstbasesink_class->preroll = NULL;
688   videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_kms_sink_show_frame);
689 }
690
691 static gboolean
692 plugin_init (GstPlugin * plugin)
693 {
694   if (!gst_element_register (plugin, "kmssink",
695           GST_RANK_SECONDARY, GST_TYPE_KMS_SINK))
696     return FALSE;
697
698   GST_DEBUG_CATEGORY_INIT (gst_debug_kms_sink, "kmssink", 0, "kmssink element");
699
700   return TRUE;
701 }
702
703 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
704     GST_VERSION_MINOR,
705     "kms",
706     "KMS video output element",
707     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)