xref: /OK3568_Linux_fs/external/gstreamer-rockchip/gst/kmssrc/gstkmssrc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2022 Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun  *     Author: Jeffy Chen <jeffy.chen@rock-chips.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This library is free software; you can redistribute it and/or
6*4882a593Smuzhiyun  * modify it under the terms of the GNU Library General Public
7*4882a593Smuzhiyun  * License as published by the Free Software Foundation; either
8*4882a593Smuzhiyun  * version 2 of the License, or (at your option) any later version.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * This library is distributed in the hope that it will be useful,
11*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13*4882a593Smuzhiyun  * Library General Public License for more details.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * You should have received a copy of the GNU Library General Public
16*4882a593Smuzhiyun  * License along with this library; if not, write to the
17*4882a593Smuzhiyun  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18*4882a593Smuzhiyun  * Boston, MA 02110-1301, USA.
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun #ifdef HAVE_CONFIG_H
22*4882a593Smuzhiyun #  include "config.h"
23*4882a593Smuzhiyun #endif
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <fcntl.h>
26*4882a593Smuzhiyun #include <unistd.h>
27*4882a593Smuzhiyun #include <sys/stat.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include <xf86drm.h>
30*4882a593Smuzhiyun #include <xf86drmMode.h>
31*4882a593Smuzhiyun #include <drm_fourcc.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include <gst/video/video.h>
34*4882a593Smuzhiyun #include <gst/base/gstpushsrc.h>
35*4882a593Smuzhiyun #include <gst/allocators/gstdmabuf.h>
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #ifndef DRM_FORMAT_NV12_10
38*4882a593Smuzhiyun #define DRM_FORMAT_NV12_10 fourcc_code('N', 'A', '1', '2')
39*4882a593Smuzhiyun #endif
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #ifndef DRM_FORMAT_NV15
42*4882a593Smuzhiyun #define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5')
43*4882a593Smuzhiyun #endif
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define DEFAULT_PROP_FRAMERATE_LIMIT 120
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun static gboolean DEFAULT_PROP_DMA_FEATURE = FALSE;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #define GST_TYPE_KMS_SRC (gst_kms_src_get_type())
50*4882a593Smuzhiyun G_DECLARE_FINAL_TYPE (GstKmsSrc, gst_kms_src, GST, KMS_SRC, GstPushSrc);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun struct _GstKmsSrc {
53*4882a593Smuzhiyun   GstBaseSrc element;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun   GstAllocator *allocator;
56*4882a593Smuzhiyun   GstVideoInfo info;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun   gchar *devname;
59*4882a593Smuzhiyun   gchar *bus_id;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun   gint fd;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun   guint crtc_id;
64*4882a593Smuzhiyun   guint encoder_id;
65*4882a593Smuzhiyun   guint connector_id;
66*4882a593Smuzhiyun   guint plane_id;
67*4882a593Smuzhiyun   guint fb_id;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun   gboolean dma_feature;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun   guint framerate_limit;
72*4882a593Smuzhiyun   guint fps_n;
73*4882a593Smuzhiyun   guint fps_d;
74*4882a593Smuzhiyun   gboolean sync_fb;
75*4882a593Smuzhiyun   gboolean sync_vblank;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun   GstPoll *poll;
78*4882a593Smuzhiyun   GstPollFD pollfd;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun   guint last_fb_id;
81*4882a593Smuzhiyun   GstClockTime last_frame_time;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun   GstClockTime start_time;
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun #define parent_class gst_kms_src_parent_class
87*4882a593Smuzhiyun G_DEFINE_TYPE (GstKmsSrc, gst_kms_src, GST_TYPE_PUSH_SRC);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun #define GST_KMS_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
90*4882a593Smuzhiyun     GST_TYPE_KMS_SRC, GstKmsSrc))
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun #define GST_CAT_DEFAULT kms_src_debug
93*4882a593Smuzhiyun GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
96*4882a593Smuzhiyun     GST_PAD_SRC,
97*4882a593Smuzhiyun     GST_PAD_ALWAYS,
98*4882a593Smuzhiyun     GST_STATIC_CAPS_ANY);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun enum
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun   PROP_DRIVER_NAME = 1,
103*4882a593Smuzhiyun   PROP_BUS_ID,
104*4882a593Smuzhiyun   PROP_CRTC_ID,
105*4882a593Smuzhiyun   PROP_ENCODER_ID,
106*4882a593Smuzhiyun   PROP_CONNECTOR_ID,
107*4882a593Smuzhiyun   PROP_PLANE_ID,
108*4882a593Smuzhiyun   PROP_FB_ID,
109*4882a593Smuzhiyun   PROP_DMA_FEATURE,
110*4882a593Smuzhiyun   PROP_FRAMERATE_LIMIT,
111*4882a593Smuzhiyun   PROP_SYNC_FB,
112*4882a593Smuzhiyun   PROP_SYNC_VBLANK,
113*4882a593Smuzhiyun   PROP_LAST,
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun struct kmssrc_fb {
117*4882a593Smuzhiyun   guint handles[4];
118*4882a593Smuzhiyun   guint pitches[4];
119*4882a593Smuzhiyun   guint offsets[4];
120*4882a593Smuzhiyun   guint width;
121*4882a593Smuzhiyun   guint height;
122*4882a593Smuzhiyun   guint fourcc;
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun static void
gst_kms_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)126*4882a593Smuzhiyun gst_kms_src_set_property (GObject * object, guint prop_id,
127*4882a593Smuzhiyun     const GValue * value, GParamSpec * pspec)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun   GstKmsSrc *self = GST_KMS_SRC (object);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun   switch (prop_id) {
132*4882a593Smuzhiyun     case PROP_DRIVER_NAME:
133*4882a593Smuzhiyun       g_free (self->devname);
134*4882a593Smuzhiyun       self->devname = g_value_dup_string (value);
135*4882a593Smuzhiyun       break;
136*4882a593Smuzhiyun     case PROP_BUS_ID:
137*4882a593Smuzhiyun       g_free (self->bus_id);
138*4882a593Smuzhiyun       self->bus_id = g_value_dup_string (value);
139*4882a593Smuzhiyun       break;
140*4882a593Smuzhiyun     case PROP_CRTC_ID:
141*4882a593Smuzhiyun       self->crtc_id = g_value_get_uint (value);
142*4882a593Smuzhiyun       break;
143*4882a593Smuzhiyun     case PROP_ENCODER_ID:
144*4882a593Smuzhiyun       self->encoder_id = g_value_get_uint (value);
145*4882a593Smuzhiyun       break;
146*4882a593Smuzhiyun     case PROP_CONNECTOR_ID:
147*4882a593Smuzhiyun       self->connector_id = g_value_get_uint (value);
148*4882a593Smuzhiyun       break;
149*4882a593Smuzhiyun     case PROP_PLANE_ID:
150*4882a593Smuzhiyun       self->plane_id = g_value_get_uint (value);
151*4882a593Smuzhiyun       break;
152*4882a593Smuzhiyun     case PROP_FB_ID:
153*4882a593Smuzhiyun       self->fb_id = g_value_get_uint (value);
154*4882a593Smuzhiyun       break;
155*4882a593Smuzhiyun     case PROP_DMA_FEATURE:
156*4882a593Smuzhiyun       self->dma_feature = g_value_get_boolean (value);
157*4882a593Smuzhiyun       break;
158*4882a593Smuzhiyun     case PROP_FRAMERATE_LIMIT:
159*4882a593Smuzhiyun       self->framerate_limit = g_value_get_uint (value);
160*4882a593Smuzhiyun       break;
161*4882a593Smuzhiyun     case PROP_SYNC_FB:
162*4882a593Smuzhiyun       self->sync_fb = g_value_get_boolean (value);
163*4882a593Smuzhiyun       break;
164*4882a593Smuzhiyun     case PROP_SYNC_VBLANK:
165*4882a593Smuzhiyun       self->sync_vblank = g_value_get_boolean (value);
166*4882a593Smuzhiyun       break;
167*4882a593Smuzhiyun     default:
168*4882a593Smuzhiyun       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
169*4882a593Smuzhiyun       break;
170*4882a593Smuzhiyun   }
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun static void
gst_kms_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)174*4882a593Smuzhiyun gst_kms_src_get_property (GObject * object, guint prop_id, GValue * value,
175*4882a593Smuzhiyun     GParamSpec * pspec)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun   GstKmsSrc *self = GST_KMS_SRC (object);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun   switch (prop_id) {
180*4882a593Smuzhiyun     case PROP_DRIVER_NAME:
181*4882a593Smuzhiyun       g_value_set_string (value, self->devname);
182*4882a593Smuzhiyun       break;
183*4882a593Smuzhiyun     case PROP_BUS_ID:
184*4882a593Smuzhiyun       g_value_set_string (value, self->bus_id);
185*4882a593Smuzhiyun       break;
186*4882a593Smuzhiyun     case PROP_CRTC_ID:
187*4882a593Smuzhiyun       g_value_set_uint (value, self->crtc_id);
188*4882a593Smuzhiyun       break;
189*4882a593Smuzhiyun     case PROP_ENCODER_ID:
190*4882a593Smuzhiyun       g_value_set_uint (value, self->encoder_id);
191*4882a593Smuzhiyun       break;
192*4882a593Smuzhiyun     case PROP_CONNECTOR_ID:
193*4882a593Smuzhiyun       g_value_set_uint (value, self->connector_id);
194*4882a593Smuzhiyun       break;
195*4882a593Smuzhiyun     case PROP_PLANE_ID:
196*4882a593Smuzhiyun       g_value_set_uint (value, self->plane_id);
197*4882a593Smuzhiyun       break;
198*4882a593Smuzhiyun     case PROP_FB_ID:
199*4882a593Smuzhiyun       g_value_set_uint (value, self->fb_id);
200*4882a593Smuzhiyun       break;
201*4882a593Smuzhiyun     case PROP_DMA_FEATURE:
202*4882a593Smuzhiyun       g_value_set_boolean (value, self->dma_feature);
203*4882a593Smuzhiyun       break;
204*4882a593Smuzhiyun     case PROP_FRAMERATE_LIMIT:
205*4882a593Smuzhiyun       g_value_set_uint (value, self->framerate_limit);
206*4882a593Smuzhiyun       break;
207*4882a593Smuzhiyun     case PROP_SYNC_FB:
208*4882a593Smuzhiyun       g_value_set_boolean (value, self->sync_fb);
209*4882a593Smuzhiyun       break;
210*4882a593Smuzhiyun     case PROP_SYNC_VBLANK:
211*4882a593Smuzhiyun       g_value_set_boolean (value, self->sync_vblank);
212*4882a593Smuzhiyun       break;
213*4882a593Smuzhiyun     default:
214*4882a593Smuzhiyun       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215*4882a593Smuzhiyun       break;
216*4882a593Smuzhiyun   }
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun static guint
gst_kms_src_get_crtc_fb(GstKmsSrc * self,guint crtc_id)220*4882a593Smuzhiyun gst_kms_src_get_crtc_fb (GstKmsSrc * self, guint crtc_id)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun   drmModeCrtcPtr crtc;
223*4882a593Smuzhiyun   guint fb_id;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun   crtc = drmModeGetCrtc (self->fd, crtc_id);
226*4882a593Smuzhiyun   if (!crtc)
227*4882a593Smuzhiyun     return 0;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun   fb_id = crtc->buffer_id;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun   drmModeFreeCrtc (crtc);
232*4882a593Smuzhiyun   return fb_id;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun static guint
gst_kms_src_get_encoder_fb(GstKmsSrc * self,guint encoder_id)236*4882a593Smuzhiyun gst_kms_src_get_encoder_fb (GstKmsSrc * self, guint encoder_id)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun   drmModeEncoderPtr encoder;
239*4882a593Smuzhiyun   guint fb_id;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun   encoder = drmModeGetEncoder (self->fd, encoder_id);
242*4882a593Smuzhiyun   if (!encoder)
243*4882a593Smuzhiyun       return 0;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun   fb_id = gst_kms_src_get_crtc_fb (self, encoder->crtc_id);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun   drmModeFreeEncoder (encoder);
248*4882a593Smuzhiyun   return fb_id;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun static guint
gst_kms_src_get_connector_fb(GstKmsSrc * self,guint connector_id)252*4882a593Smuzhiyun gst_kms_src_get_connector_fb (GstKmsSrc * self, guint connector_id)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun   drmModeConnectorPtr connector;
255*4882a593Smuzhiyun   guint fb_id;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun   connector = drmModeGetConnector (self->fd, connector_id);
258*4882a593Smuzhiyun   if (!connector)
259*4882a593Smuzhiyun     return 0;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun   fb_id = gst_kms_src_get_encoder_fb (self, connector->encoder_id);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun   drmModeFreeConnector (connector);
264*4882a593Smuzhiyun   return fb_id;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun static guint
gst_kms_src_get_plane_fb(GstKmsSrc * self,guint plane_id)268*4882a593Smuzhiyun gst_kms_src_get_plane_fb (GstKmsSrc * self, guint plane_id)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun   drmModePlanePtr plane;
271*4882a593Smuzhiyun   guint fb_id;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun   plane = drmModeGetPlane (self->fd, plane_id);
274*4882a593Smuzhiyun   if (!plane)
275*4882a593Smuzhiyun     return 0;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun   fb_id = plane->fb_id;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun   drmModeFreePlane (plane);
280*4882a593Smuzhiyun   return fb_id;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun static guint
gst_kms_src_get_fb_id(GstKmsSrc * self)284*4882a593Smuzhiyun gst_kms_src_get_fb_id (GstKmsSrc * self)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun   if (self->fb_id)
287*4882a593Smuzhiyun     return self->fb_id;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun   if (self->plane_id)
290*4882a593Smuzhiyun     return gst_kms_src_get_plane_fb (self, self->plane_id);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun   if (self->connector_id)
293*4882a593Smuzhiyun     return gst_kms_src_get_connector_fb (self, self->connector_id);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun   if (self->encoder_id)
296*4882a593Smuzhiyun     return gst_kms_src_get_encoder_fb (self, self->encoder_id);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun   if (self->crtc_id)
299*4882a593Smuzhiyun     return gst_kms_src_get_crtc_fb (self, self->crtc_id);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun   return 0;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun static guint
gst_kms_src_get_encoder_crtc(GstKmsSrc * self,guint encoder_id)305*4882a593Smuzhiyun gst_kms_src_get_encoder_crtc (GstKmsSrc * self, guint encoder_id)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun   drmModeEncoderPtr encoder;
308*4882a593Smuzhiyun   guint crtc_id;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun   encoder = drmModeGetEncoder (self->fd, encoder_id);
311*4882a593Smuzhiyun   if (!encoder)
312*4882a593Smuzhiyun       return 0;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun   crtc_id = encoder->crtc_id;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun   drmModeFreeEncoder (encoder);
317*4882a593Smuzhiyun   return crtc_id;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun static guint
gst_kms_src_get_connector_crtc(GstKmsSrc * self,guint connector_id)321*4882a593Smuzhiyun gst_kms_src_get_connector_crtc (GstKmsSrc * self, guint connector_id)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun   drmModeConnectorPtr connector;
324*4882a593Smuzhiyun   guint crtc_id;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun   connector = drmModeGetConnector (self->fd, connector_id);
327*4882a593Smuzhiyun   if (!connector)
328*4882a593Smuzhiyun     return 0;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun   crtc_id = gst_kms_src_get_encoder_crtc (self, connector->encoder_id);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun   drmModeFreeConnector (connector);
333*4882a593Smuzhiyun   return crtc_id;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun static guint
gst_kms_src_get_plane_crtc(GstKmsSrc * self,guint plane_id)337*4882a593Smuzhiyun gst_kms_src_get_plane_crtc (GstKmsSrc * self, guint plane_id)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun   drmModePlanePtr plane;
340*4882a593Smuzhiyun   guint crtc_id;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun   plane = drmModeGetPlane (self->fd, plane_id);
343*4882a593Smuzhiyun   if (!plane)
344*4882a593Smuzhiyun     return 0;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun   crtc_id = plane->crtc_id;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun   drmModeFreePlane (plane);
349*4882a593Smuzhiyun   return crtc_id;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun static guint
gst_kms_src_get_crtc_id(GstKmsSrc * self)353*4882a593Smuzhiyun gst_kms_src_get_crtc_id (GstKmsSrc * self)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun   if (self->crtc_id)
356*4882a593Smuzhiyun     return self->crtc_id;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun   if (self->plane_id)
359*4882a593Smuzhiyun     return gst_kms_src_get_plane_crtc (self, self->plane_id);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun   if (self->connector_id)
362*4882a593Smuzhiyun     return gst_kms_src_get_connector_crtc (self, self->connector_id);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun   if (self->encoder_id)
365*4882a593Smuzhiyun     return gst_kms_src_get_encoder_crtc (self, self->encoder_id);
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun   return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun static guint
gst_kms_src_get_crtc_pipe(GstKmsSrc * self,guint crtc_id)371*4882a593Smuzhiyun gst_kms_src_get_crtc_pipe (GstKmsSrc * self, guint crtc_id)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun   drmModeResPtr res;
374*4882a593Smuzhiyun   guint crtc_pipe = 0;
375*4882a593Smuzhiyun   gint i;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun   if (!crtc_id)
378*4882a593Smuzhiyun     return 0;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun   res = drmModeGetResources (self->fd);
381*4882a593Smuzhiyun   if (!res)
382*4882a593Smuzhiyun     return 0;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun   for (i = 0; i < res->count_crtcs; i++) {
385*4882a593Smuzhiyun     if (res->crtcs[i] == crtc_id) {
386*4882a593Smuzhiyun       crtc_pipe = i;
387*4882a593Smuzhiyun       break;
388*4882a593Smuzhiyun     }
389*4882a593Smuzhiyun   }
390*4882a593Smuzhiyun   drmModeFreeResources (res);
391*4882a593Smuzhiyun   return crtc_pipe;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun static void
sync_handler(gint fd,guint frame,guint sec,guint usec,gpointer data)395*4882a593Smuzhiyun sync_handler (gint fd, guint frame, guint sec, guint usec, gpointer data)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun   gboolean *waiting;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun   (void) fd;
400*4882a593Smuzhiyun   (void) frame;
401*4882a593Smuzhiyun   (void) sec;
402*4882a593Smuzhiyun   (void) usec;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun   waiting = data;
405*4882a593Smuzhiyun   *waiting = FALSE;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun static gboolean
gst_kms_src_sync_vblank(GstKmsSrc * self)409*4882a593Smuzhiyun gst_kms_src_sync_vblank (GstKmsSrc * self)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun   gboolean waiting;
412*4882a593Smuzhiyun   drmEventContext evctxt = {
413*4882a593Smuzhiyun     .version = DRM_EVENT_CONTEXT_VERSION,
414*4882a593Smuzhiyun     .vblank_handler = sync_handler,
415*4882a593Smuzhiyun   };
416*4882a593Smuzhiyun   drmVBlank vbl = {
417*4882a593Smuzhiyun     .request = {
418*4882a593Smuzhiyun           .type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
419*4882a593Smuzhiyun           .sequence = 1,
420*4882a593Smuzhiyun           .signal = (gulong) & waiting,
421*4882a593Smuzhiyun         },
422*4882a593Smuzhiyun   };
423*4882a593Smuzhiyun   guint crtc_id = gst_kms_src_get_crtc_id (self);
424*4882a593Smuzhiyun   guint crtc_pipe = gst_kms_src_get_crtc_pipe (self, crtc_id);
425*4882a593Smuzhiyun   gint ret;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun   if (crtc_pipe == 1)
428*4882a593Smuzhiyun     vbl.request.type |= DRM_VBLANK_SECONDARY;
429*4882a593Smuzhiyun   else if (crtc_pipe > 1)
430*4882a593Smuzhiyun     vbl.request.type |= crtc_pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun   waiting = TRUE;
433*4882a593Smuzhiyun   ret = drmWaitVBlank (self->fd, &vbl);
434*4882a593Smuzhiyun   if (ret)
435*4882a593Smuzhiyun     return FALSE;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun   while (waiting) {
438*4882a593Smuzhiyun     do {
439*4882a593Smuzhiyun       ret = gst_poll_wait (self->poll, 3 * GST_SECOND);
440*4882a593Smuzhiyun     } while (ret == -1 && (errno == EAGAIN || errno == EINTR));
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun     ret = drmHandleEvent (self->fd, &evctxt);
443*4882a593Smuzhiyun     if (ret)
444*4882a593Smuzhiyun       return FALSE;
445*4882a593Smuzhiyun   }
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "sync vblank with CRTC: %d(%d)", crtc_id, crtc_pipe);
448*4882a593Smuzhiyun   return TRUE;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun static guint
gst_kms_src_get_next_fb_id(GstKmsSrc * self)452*4882a593Smuzhiyun gst_kms_src_get_next_fb_id (GstKmsSrc * self)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun   GstClockTimeDiff diff;
455*4882a593Smuzhiyun   gboolean sync_fb = self->sync_fb && !self->fb_id;
456*4882a593Smuzhiyun   guint duration = 0;
457*4882a593Smuzhiyun   guint fb_id;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun   if (self->sync_vblank)
460*4882a593Smuzhiyun     gst_kms_src_sync_vblank (self);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun   if (self->fps_d && self->fps_n)
463*4882a593Smuzhiyun     duration =
464*4882a593Smuzhiyun         gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
465*4882a593Smuzhiyun   else if (self->framerate_limit)
466*4882a593Smuzhiyun     duration = GST_SECOND / self->framerate_limit;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun   while (1) {
469*4882a593Smuzhiyun     diff = GST_CLOCK_DIFF (self->last_frame_time, gst_util_get_timestamp ());
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun     fb_id = gst_kms_src_get_fb_id (self);
472*4882a593Smuzhiyun     if (!fb_id)
473*4882a593Smuzhiyun       return 0;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun     if (!sync_fb || fb_id != self->last_fb_id) {
476*4882a593Smuzhiyun       sync_fb = FALSE;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun       if (diff >= duration)
479*4882a593Smuzhiyun         return fb_id;
480*4882a593Smuzhiyun     }
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun     g_usleep (1000);
483*4882a593Smuzhiyun   }
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun   return 0;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun #ifndef HAS_DRM_CLOSE_HANDLE
489*4882a593Smuzhiyun /* From libdrm 2.4.109 : xf86drm.c */
490*4882a593Smuzhiyun static int
drmCloseBufferHandle(int fd,uint32_t handle)491*4882a593Smuzhiyun drmCloseBufferHandle(int fd, uint32_t handle)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun   struct drm_gem_close args;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun   memset(&args, 0, sizeof(args));
496*4882a593Smuzhiyun   args.handle = handle;
497*4882a593Smuzhiyun   return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun #endif
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun static void
gst_kms_src_free_fb(GstKmsSrc * self,struct kmssrc_fb * fb)502*4882a593Smuzhiyun gst_kms_src_free_fb (GstKmsSrc * self, struct kmssrc_fb * fb)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun   guint i;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun   for (i = 0; i < 4; i++) {
507*4882a593Smuzhiyun     if (fb->handles[i])
508*4882a593Smuzhiyun       drmCloseBufferHandle (self->fd, fb->handles[i]);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun     fb->handles[i] = 0;
511*4882a593Smuzhiyun   }
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun static gboolean
gst_kms_src_update_info(GstKmsSrc * self,struct kmssrc_fb * fb)515*4882a593Smuzhiyun gst_kms_src_update_info (GstKmsSrc * self, struct kmssrc_fb * fb)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun   GstVideoInfo *info = &self->info;
518*4882a593Smuzhiyun   GstVideoFormat format;
519*4882a593Smuzhiyun   guint i;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun #define KMSSRC_CASE_FOURCC(fourcc, gst) \
522*4882a593Smuzhiyun   case DRM_FORMAT_ ## fourcc: format = GST_VIDEO_FORMAT_ ## gst; break;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun   switch (fb->fourcc) {
525*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (ARGB8888, BGRA);
526*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (XRGB8888, BGRx);
527*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (ABGR8888, RGBA);
528*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (XBGR8888, RGBx);
529*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (RGB888, BGR);
530*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (BGR888, RGB);
531*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (YUV422, Y42B);
532*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (NV16, NV16);
533*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (NV61, NV61);
534*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (UYVY, UYVY);
535*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (YVYU, YVYU);
536*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (YUYV, YUY2);
537*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (YUV420, I420);
538*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (YVU420, YV12);
539*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (NV12, NV12);
540*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (NV21, NV21);
541*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (RGB565, RGB16);
542*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (BGR565, BGR16);
543*4882a593Smuzhiyun #ifdef HAVE_NV12_10LE40
544*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (NV15, NV12_10LE40);
545*4882a593Smuzhiyun     KMSSRC_CASE_FOURCC (NV12_10, NV12_10LE40);
546*4882a593Smuzhiyun #endif
547*4882a593Smuzhiyun   default:
548*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "format not supported %x", fb->fourcc);
549*4882a593Smuzhiyun     return FALSE;
550*4882a593Smuzhiyun   }
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun   gst_video_info_set_format (info, format, fb->width, fb->height);
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun   GST_VIDEO_INFO_SIZE (info) = 0;
555*4882a593Smuzhiyun   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
556*4882a593Smuzhiyun     GST_VIDEO_INFO_PLANE_STRIDE (info, i) = fb->pitches[i];
557*4882a593Smuzhiyun     GST_VIDEO_INFO_PLANE_OFFSET (info, i) = fb->offsets[i];
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun     GST_DEBUG_OBJECT (self, "plane %d, stride %d, offset %" G_GSIZE_FORMAT, i,
560*4882a593Smuzhiyun         GST_VIDEO_INFO_PLANE_STRIDE (info, i),
561*4882a593Smuzhiyun         GST_VIDEO_INFO_PLANE_OFFSET (info, i));
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun     GST_VIDEO_INFO_SIZE (info) += fb->pitches[i] * fb->height;
564*4882a593Smuzhiyun   }
565*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "size %" G_GSIZE_FORMAT, GST_VIDEO_INFO_SIZE (info));
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun   return TRUE;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun static gboolean
gst_kms_src_get_fb(GstKmsSrc * self,guint fb_id,struct kmssrc_fb * kmssrc_fb)571*4882a593Smuzhiyun gst_kms_src_get_fb (GstKmsSrc * self, guint fb_id, struct kmssrc_fb * kmssrc_fb)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun   drmModeFBPtr fb;
574*4882a593Smuzhiyun #ifdef HAS_DRM_MODE_FB2
575*4882a593Smuzhiyun   drmModeFB2Ptr fb2;
576*4882a593Smuzhiyun   guint i;
577*4882a593Smuzhiyun #endif
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun   memset (kmssrc_fb, 0, sizeof (*kmssrc_fb));
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun #ifdef HAS_DRM_MODE_FB2
582*4882a593Smuzhiyun   fb2 = drmModeGetFB2 (self->fd, fb_id);
583*4882a593Smuzhiyun   if (fb2) {
584*4882a593Smuzhiyun     for (i = 0; i < 4; i++) {
585*4882a593Smuzhiyun       kmssrc_fb->handles[i] = fb2->handles[i];
586*4882a593Smuzhiyun       kmssrc_fb->pitches[i] = fb2->pitches[i];
587*4882a593Smuzhiyun       kmssrc_fb->offsets[i] = fb2->offsets[i];
588*4882a593Smuzhiyun     }
589*4882a593Smuzhiyun     kmssrc_fb->fourcc = fb2->pixel_format;
590*4882a593Smuzhiyun     kmssrc_fb->width = fb2->width;
591*4882a593Smuzhiyun     kmssrc_fb->height = fb2->height;
592*4882a593Smuzhiyun     drmModeFreeFB2 (fb2);
593*4882a593Smuzhiyun     return TRUE;
594*4882a593Smuzhiyun   }
595*4882a593Smuzhiyun #endif
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun   fb = drmModeGetFB (self->fd, fb_id);
598*4882a593Smuzhiyun   if (!fb)
599*4882a593Smuzhiyun     return FALSE;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun   kmssrc_fb->handles[0] = fb->handle;
602*4882a593Smuzhiyun   kmssrc_fb->pitches[0] = fb->pitch;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun   switch (fb->bpp) {
605*4882a593Smuzhiyun   case 32:
606*4882a593Smuzhiyun     if (fb->depth == 32)
607*4882a593Smuzhiyun       kmssrc_fb->fourcc = DRM_FORMAT_ARGB8888;
608*4882a593Smuzhiyun     else
609*4882a593Smuzhiyun       kmssrc_fb->fourcc = DRM_FORMAT_XRGB8888;
610*4882a593Smuzhiyun     break;
611*4882a593Smuzhiyun   case 16:
612*4882a593Smuzhiyun     kmssrc_fb->fourcc = DRM_FORMAT_RGB565;
613*4882a593Smuzhiyun     break;
614*4882a593Smuzhiyun   default:
615*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "FB format unsupported");
616*4882a593Smuzhiyun     gst_kms_src_free_fb (self, kmssrc_fb);
617*4882a593Smuzhiyun     drmModeFreeFB (fb);
618*4882a593Smuzhiyun     return FALSE;
619*4882a593Smuzhiyun   }
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun   kmssrc_fb->width = fb->width;
622*4882a593Smuzhiyun   kmssrc_fb->height = fb->height;
623*4882a593Smuzhiyun   drmModeFreeFB (fb);
624*4882a593Smuzhiyun   return TRUE;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun static GstBuffer *
gst_kms_src_import_drm_fb(GstKmsSrc * self,guint fb_id)628*4882a593Smuzhiyun gst_kms_src_import_drm_fb (GstKmsSrc * self, guint fb_id)
629*4882a593Smuzhiyun {
630*4882a593Smuzhiyun   GstVideoInfo *info = &self->info;
631*4882a593Smuzhiyun   GstBuffer *buf = NULL;
632*4882a593Smuzhiyun   GstMemory *mem;
633*4882a593Smuzhiyun   struct kmssrc_fb fb;
634*4882a593Smuzhiyun   struct stat st[4];
635*4882a593Smuzhiyun   gint i, dmafd[4], size[4];
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun   if (!gst_kms_src_get_fb (self, fb_id, &fb)) {
638*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "could not get DRM FB %d", fb_id);
639*4882a593Smuzhiyun     return NULL;
640*4882a593Smuzhiyun   }
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun   if (!gst_kms_src_update_info (self, &fb))
643*4882a593Smuzhiyun     goto err;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun   buf = gst_buffer_new ();
646*4882a593Smuzhiyun   if (!buf)
647*4882a593Smuzhiyun     goto err;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun   for (i = 0; i < 4; i++) {
650*4882a593Smuzhiyun     if (!fb.handles[i])
651*4882a593Smuzhiyun       break;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun     size[i] = fb.pitches[i] * fb.height;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun     GST_DEBUG_OBJECT (self, "importing DRM handle %d(%d) for %dx%d",
656*4882a593Smuzhiyun         fb.handles[i], i, fb.pitches[i], fb.height);
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun     if (drmPrimeHandleToFD (self->fd, fb.handles[i], DRM_CLOEXEC | DRM_RDWR,
659*4882a593Smuzhiyun           &dmafd[i]) < 0) {
660*4882a593Smuzhiyun       GST_ERROR_OBJECT (self, "could not import DRM handle %d", fb.handles[i]);
661*4882a593Smuzhiyun       goto err;
662*4882a593Smuzhiyun     }
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun     fstat (dmafd[i], &st[i]);
665*4882a593Smuzhiyun     if (i && !memcmp (&st[i], &st[i - 1], sizeof (struct stat))) {
666*4882a593Smuzhiyun       /* Reuse the old fd */
667*4882a593Smuzhiyun       close (dmafd[i]);
668*4882a593Smuzhiyun       dmafd[i] = dmafd[i - 1];
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun       /* Check for contig planes */
671*4882a593Smuzhiyun       if (fb.offsets[i] == fb.offsets[i - 1] + size[i - 1]) {
672*4882a593Smuzhiyun         gsize mem_size, mem_offset;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun         mem_size = gst_memory_get_sizes (mem, &mem_offset, NULL);
675*4882a593Smuzhiyun         gst_memory_resize (mem, mem_offset, mem_size + size[i]);
676*4882a593Smuzhiyun         continue;
677*4882a593Smuzhiyun       }
678*4882a593Smuzhiyun     }
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun     mem = gst_fd_allocator_alloc (self->allocator, dmafd[i], st[i].st_size,
681*4882a593Smuzhiyun               GST_FD_MEMORY_FLAG_NONE);
682*4882a593Smuzhiyun     if (!mem) {
683*4882a593Smuzhiyun       close (dmafd[i]);
684*4882a593Smuzhiyun       goto err;
685*4882a593Smuzhiyun     }
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun     gst_memory_resize (mem, fb.offsets[i], size[i]);
688*4882a593Smuzhiyun     gst_buffer_append_memory (buf, mem);
689*4882a593Smuzhiyun   }
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun   gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
692*4882a593Smuzhiyun       GST_VIDEO_INFO_FORMAT (info),
693*4882a593Smuzhiyun       GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info),
694*4882a593Smuzhiyun       GST_VIDEO_INFO_N_PLANES (info), info->offset, info->stride);
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun   gst_kms_src_free_fb (self, &fb);
697*4882a593Smuzhiyun   return buf;
698*4882a593Smuzhiyun err:
699*4882a593Smuzhiyun   if (buf)
700*4882a593Smuzhiyun     gst_buffer_unref (buf);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun   gst_kms_src_free_fb (self, &fb);
703*4882a593Smuzhiyun   return NULL;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun static GstFlowReturn
gst_kms_src_create(GstPushSrc * src,GstBuffer ** ret)707*4882a593Smuzhiyun gst_kms_src_create (GstPushSrc * src, GstBuffer ** ret)
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun   GstKmsSrc *self = GST_KMS_SRC (src);
710*4882a593Smuzhiyun   GstBuffer *buf;
711*4882a593Smuzhiyun   guint fb_id;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "creating buffer");
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun   fb_id = gst_kms_src_get_next_fb_id (self);
716*4882a593Smuzhiyun   if (!fb_id) {
717*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "could not get valid FB");
718*4882a593Smuzhiyun     goto err;
719*4882a593Smuzhiyun   }
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "importing DRM FB %d (old: %d)",
722*4882a593Smuzhiyun       fb_id, self->last_fb_id);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun   buf = gst_kms_src_import_drm_fb (self, fb_id);
725*4882a593Smuzhiyun   if (!buf) {
726*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "could not import FB %d", fb_id);
727*4882a593Smuzhiyun     goto err;
728*4882a593Smuzhiyun   }
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun   self->last_frame_time = gst_util_get_timestamp ();
731*4882a593Smuzhiyun   self->last_fb_id = fb_id;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun   GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) =
734*4882a593Smuzhiyun       self->last_frame_time - self->start_time;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun   *ret = buf;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun   return GST_FLOW_OK;
739*4882a593Smuzhiyun err:
740*4882a593Smuzhiyun   if (self->last_fb_id)
741*4882a593Smuzhiyun     return GST_FLOW_EOS;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun   return GST_FLOW_ERROR;
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun /* Based on gst-plugins-good/sys/ximage/gstximagesrc.c */
747*4882a593Smuzhiyun static gboolean
gst_kms_src_set_caps(GstBaseSrc * basesrc,GstCaps * caps)748*4882a593Smuzhiyun gst_kms_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun   GstKmsSrc *self = GST_KMS_SRC (basesrc);
751*4882a593Smuzhiyun   GstVideoInfo *info = &self->info;
752*4882a593Smuzhiyun   GstStructure *structure;
753*4882a593Smuzhiyun   const GValue *new_fps;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun   /* The only thing that can change is the framerate downstream wants */
756*4882a593Smuzhiyun   structure = gst_caps_get_structure (caps, 0);
757*4882a593Smuzhiyun   new_fps = gst_structure_get_value (structure, "framerate");
758*4882a593Smuzhiyun   if (!new_fps)
759*4882a593Smuzhiyun     return FALSE;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun   /* Store this FPS for use when generating buffers */
762*4882a593Smuzhiyun   info->fps_n = self->fps_n = gst_value_get_fraction_numerator (new_fps);
763*4882a593Smuzhiyun   info->fps_d = self->fps_d = gst_value_get_fraction_denominator (new_fps);
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "peer wants %d/%d fps", self->fps_n, self->fps_d);
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun   if (self->framerate_limit * self->fps_d > self->fps_n)
768*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "framerate-limit ignored");
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun   if (self->sync_fb)
771*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "sync-fb enabled, framerate might be inaccurate");
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun   return TRUE;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun static GstCaps *
gst_kms_src_get_caps(GstBaseSrc * basesrc,GstCaps * filter)777*4882a593Smuzhiyun gst_kms_src_get_caps (GstBaseSrc * basesrc, GstCaps * filter)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun   GstKmsSrc *self = GST_KMS_SRC (basesrc);
780*4882a593Smuzhiyun   GstStructure *s;
781*4882a593Smuzhiyun   GstCaps *caps;
782*4882a593Smuzhiyun   struct kmssrc_fb fb;
783*4882a593Smuzhiyun   guint fb_id;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun   fb_id = gst_kms_src_get_fb_id (self);
786*4882a593Smuzhiyun   if (!fb_id)
787*4882a593Smuzhiyun     return gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (basesrc));
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun   if (!gst_kms_src_get_fb (self, fb_id, &fb)) {
790*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "could not get DRM FB %d", fb_id);
791*4882a593Smuzhiyun     return NULL;
792*4882a593Smuzhiyun   }
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun   if (!gst_kms_src_update_info (self, &fb)) {
795*4882a593Smuzhiyun     gst_kms_src_free_fb (self, &fb);
796*4882a593Smuzhiyun     return NULL;
797*4882a593Smuzhiyun   }
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun   gst_kms_src_free_fb (self, &fb);
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun   caps = gst_video_info_to_caps (&self->info);
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun   if (self->dma_feature)
804*4882a593Smuzhiyun     gst_caps_set_features (caps, 0,
805*4882a593Smuzhiyun         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun   if (filter) {
808*4882a593Smuzhiyun     GstCaps *intersection;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun     intersection =
811*4882a593Smuzhiyun       gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
812*4882a593Smuzhiyun     gst_caps_unref (caps);
813*4882a593Smuzhiyun     caps = intersection;
814*4882a593Smuzhiyun   }
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun   s = gst_caps_get_structure (caps, 0);
817*4882a593Smuzhiyun   gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT,
818*4882a593Smuzhiyun       1, NULL);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "returning caps: %" GST_PTR_FORMAT, caps);
821*4882a593Smuzhiyun   return caps;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun static gboolean
gst_kms_src_stop(GstBaseSrc * basesrc)825*4882a593Smuzhiyun gst_kms_src_stop (GstBaseSrc * basesrc)
826*4882a593Smuzhiyun {
827*4882a593Smuzhiyun   GstKmsSrc *self = GST_KMS_SRC (basesrc);
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun   gst_poll_remove_fd (self->poll, &self->pollfd);
830*4882a593Smuzhiyun   gst_poll_restart (self->poll);
831*4882a593Smuzhiyun   gst_poll_fd_init (&self->pollfd);
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun   if (self->allocator)
834*4882a593Smuzhiyun     g_object_unref (self->allocator);
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun   if (self->fd >= 0)
837*4882a593Smuzhiyun     drmClose (self->fd);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun   return TRUE;
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun static guint
gst_kms_src_find_best_crtc(GstKmsSrc * self)843*4882a593Smuzhiyun gst_kms_src_find_best_crtc (GstKmsSrc * self)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun   drmModeCrtcPtr crtc;
846*4882a593Smuzhiyun   drmModeResPtr res;
847*4882a593Smuzhiyun   guint crtc_id;
848*4882a593Smuzhiyun   gint i;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun   res = drmModeGetResources (self->fd);
851*4882a593Smuzhiyun   if (!res)
852*4882a593Smuzhiyun     return 0;
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun   for (i = 0, crtc_id = 0; i < res->count_crtcs; i++) {
855*4882a593Smuzhiyun     crtc = drmModeGetCrtc (self->fd, res->crtcs[i]);
856*4882a593Smuzhiyun     if (crtc && crtc->mode_valid) {
857*4882a593Smuzhiyun       drmModeFreeCrtc (crtc);
858*4882a593Smuzhiyun       crtc_id = res->crtcs[i];
859*4882a593Smuzhiyun       break;
860*4882a593Smuzhiyun     }
861*4882a593Smuzhiyun     drmModeFreeCrtc (crtc);
862*4882a593Smuzhiyun   }
863*4882a593Smuzhiyun   drmModeFreeResources (res);
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun   if (crtc_id)
866*4882a593Smuzhiyun     GST_DEBUG_OBJECT (self, "using best CRTC %d", crtc_id);
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun   return crtc_id;
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun static gboolean
gst_kms_src_start(GstBaseSrc * basesrc)872*4882a593Smuzhiyun gst_kms_src_start (GstBaseSrc * basesrc)
873*4882a593Smuzhiyun {
874*4882a593Smuzhiyun   GstKmsSrc *self = GST_KMS_SRC (basesrc);
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun   self->allocator = gst_dmabuf_allocator_new ();
877*4882a593Smuzhiyun   if (!self->allocator)
878*4882a593Smuzhiyun     return FALSE;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun   if (self->devname || self->bus_id)
881*4882a593Smuzhiyun     self->fd = drmOpen (self->devname, self->bus_id);
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun   if (self->fd < 0)
884*4882a593Smuzhiyun     self->fd = open ("/dev/dri/card0", O_RDWR | O_CLOEXEC);
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun   if (self->fd < 0) {
887*4882a593Smuzhiyun     GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE,
888*4882a593Smuzhiyun         ("Could not open DRM module %s", GST_STR_NULL (self->devname)),
889*4882a593Smuzhiyun         ("reason: %s (%d)", g_strerror (errno), errno));
890*4882a593Smuzhiyun     gst_kms_src_stop (basesrc);
891*4882a593Smuzhiyun     return FALSE;
892*4882a593Smuzhiyun   }
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun   if (!self->fb_id && !self->plane_id && !self->connector_id &&
895*4882a593Smuzhiyun       !self->encoder_id && !self->crtc_id) {
896*4882a593Smuzhiyun     self->crtc_id = gst_kms_src_find_best_crtc (self);
897*4882a593Smuzhiyun     if (!self->crtc_id) {
898*4882a593Smuzhiyun       GST_ERROR_OBJECT (self, "could not find a valid CRTC");
899*4882a593Smuzhiyun       gst_kms_src_stop (basesrc);
900*4882a593Smuzhiyun       return FALSE;
901*4882a593Smuzhiyun     }
902*4882a593Smuzhiyun   }
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun   self->last_fb_id = 0;
905*4882a593Smuzhiyun   self->last_frame_time = gst_util_get_timestamp ();
906*4882a593Smuzhiyun   self->start_time = gst_util_get_timestamp ();
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun   self->pollfd.fd = self->fd;
909*4882a593Smuzhiyun   gst_poll_add_fd (self->poll, &self->pollfd);
910*4882a593Smuzhiyun   gst_poll_fd_ctl_read (self->poll, &self->pollfd, TRUE);
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun   return TRUE;
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun static void
gst_kms_src_finalize(GObject * object)916*4882a593Smuzhiyun gst_kms_src_finalize (GObject * object)
917*4882a593Smuzhiyun {
918*4882a593Smuzhiyun   GstKmsSrc *self;
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun   self = GST_KMS_SRC (object);
921*4882a593Smuzhiyun   g_clear_pointer (&self->devname, g_free);
922*4882a593Smuzhiyun   g_clear_pointer (&self->bus_id, g_free);
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun   gst_poll_free (self->poll);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun   G_OBJECT_CLASS (parent_class)->finalize (object);
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun static void
gst_kms_src_init(GstKmsSrc * self)930*4882a593Smuzhiyun gst_kms_src_init (GstKmsSrc * self)
931*4882a593Smuzhiyun {
932*4882a593Smuzhiyun   self->devname = g_strdup ("rockchip");
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun   self->fd = -1;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun   self->crtc_id = 0;
937*4882a593Smuzhiyun   self->encoder_id = 0;
938*4882a593Smuzhiyun   self->connector_id = 0;
939*4882a593Smuzhiyun   self->plane_id = 0;
940*4882a593Smuzhiyun   self->fb_id = 0;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun   self->framerate_limit = DEFAULT_PROP_FRAMERATE_LIMIT;
943*4882a593Smuzhiyun   self->sync_fb = TRUE;
944*4882a593Smuzhiyun   self->sync_vblank = TRUE;
945*4882a593Smuzhiyun   self->fps_n = 0;
946*4882a593Smuzhiyun   self->fps_d = 1;
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun   gst_video_info_init (&self->info);
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun   gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
951*4882a593Smuzhiyun   gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun   gst_poll_fd_init (&self->pollfd);
954*4882a593Smuzhiyun   self->poll = gst_poll_new (TRUE);
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun static void
gst_kms_src_class_init(GstKmsSrcClass * klass)958*4882a593Smuzhiyun gst_kms_src_class_init (GstKmsSrcClass * klass)
959*4882a593Smuzhiyun {
960*4882a593Smuzhiyun   GObjectClass *gobject_class;
961*4882a593Smuzhiyun   GstElementClass *gstelement_class;
962*4882a593Smuzhiyun   GstBaseSrcClass *gstbase_src_class;
963*4882a593Smuzhiyun   GstPushSrcClass *gstpush_src_class;
964*4882a593Smuzhiyun   const gchar *env;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun   gobject_class = G_OBJECT_CLASS (klass);
967*4882a593Smuzhiyun   gstelement_class = GST_ELEMENT_CLASS (klass);
968*4882a593Smuzhiyun   gstbase_src_class = GST_BASE_SRC_CLASS (klass);
969*4882a593Smuzhiyun   gstpush_src_class = GST_PUSH_SRC_CLASS (klass);
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun   gobject_class->finalize = gst_kms_src_finalize;
972*4882a593Smuzhiyun   gobject_class->set_property = gst_kms_src_set_property;
973*4882a593Smuzhiyun   gobject_class->get_property = gst_kms_src_get_property;
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_DRIVER_NAME,
976*4882a593Smuzhiyun       g_param_spec_string ("driver-name",
977*4882a593Smuzhiyun       "device name", "DRM device driver name", NULL,
978*4882a593Smuzhiyun       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_BUS_ID,
981*4882a593Smuzhiyun       g_param_spec_string ("bus-id", "Bus ID", "DRM bus ID", NULL,
982*4882a593Smuzhiyun       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_CRTC_ID,
985*4882a593Smuzhiyun       g_param_spec_uint ("crtc-id", "DRM crtc ID",
986*4882a593Smuzhiyun           "DRM crtc ID (0 = unspecified)",
987*4882a593Smuzhiyun           0, G_MAXINT, 0,
988*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_ENCODER_ID,
991*4882a593Smuzhiyun       g_param_spec_uint ("encoder-id", "DRM plane ID",
992*4882a593Smuzhiyun           "DRM encoder ID (0 = unspecified)",
993*4882a593Smuzhiyun           0, G_MAXINT, 0,
994*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_CONNECTOR_ID,
997*4882a593Smuzhiyun       g_param_spec_uint ("connector-id", "DRM connector ID",
998*4882a593Smuzhiyun           "DRM connector ID (0 = unspecified)",
999*4882a593Smuzhiyun           0, G_MAXINT, 0,
1000*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_PLANE_ID,
1003*4882a593Smuzhiyun       g_param_spec_uint ("plane-id", "DRM plane ID",
1004*4882a593Smuzhiyun           "DRM plane ID (0 = unspecified)",
1005*4882a593Smuzhiyun           0, G_MAXINT, 0,
1006*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_FB_ID,
1009*4882a593Smuzhiyun       g_param_spec_uint ("fb-id", "DRM FB ID",
1010*4882a593Smuzhiyun           "DRM FB ID (0 = unspecified)",
1011*4882a593Smuzhiyun           0, G_MAXINT, 0,
1012*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun   env = g_getenv ("GST_KMSSRC_DMA_FEATURE");
1015*4882a593Smuzhiyun   if (env && !strcmp (env, "1"))
1016*4882a593Smuzhiyun     DEFAULT_PROP_DMA_FEATURE = TRUE;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_DMA_FEATURE,
1019*4882a593Smuzhiyun       g_param_spec_boolean ("dma-feature", "DMA feature",
1020*4882a593Smuzhiyun           "Enable GST DMA feature", DEFAULT_PROP_DMA_FEATURE,
1021*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_FRAMERATE_LIMIT,
1024*4882a593Smuzhiyun       g_param_spec_uint ("framerate-limit", "Limited framerate",
1025*4882a593Smuzhiyun           "Limited framerate",
1026*4882a593Smuzhiyun           0, G_MAXINT, DEFAULT_PROP_FRAMERATE_LIMIT,
1027*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_SYNC_FB,
1030*4882a593Smuzhiyun       g_param_spec_boolean ("sync-fb", "Sync with FB flip",
1031*4882a593Smuzhiyun           "Sync with FB flip", TRUE,
1032*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_SYNC_VBLANK,
1035*4882a593Smuzhiyun       g_param_spec_boolean ("sync-vblank", "Sync with vblank",
1036*4882a593Smuzhiyun           "Sync with vblank", TRUE,
1037*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun   gst_element_class_set_static_metadata (gstelement_class,
1040*4882a593Smuzhiyun       "KMS Video Source",
1041*4882a593Smuzhiyun       "Source/Video",
1042*4882a593Smuzhiyun       "KMS Video Source",
1043*4882a593Smuzhiyun       "Jeffy Chen <jeffy.chen@rock-chips.com>");
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun   gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun   gstbase_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_kms_src_set_caps);
1048*4882a593Smuzhiyun   gstbase_src_class->get_caps = GST_DEBUG_FUNCPTR (gst_kms_src_get_caps);
1049*4882a593Smuzhiyun   gstbase_src_class->start = GST_DEBUG_FUNCPTR (gst_kms_src_start);
1050*4882a593Smuzhiyun   gstbase_src_class->stop = GST_DEBUG_FUNCPTR (gst_kms_src_stop);
1051*4882a593Smuzhiyun   gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_kms_src_create);
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun static gboolean
plugin_init(GstPlugin * plugin)1055*4882a593Smuzhiyun plugin_init (GstPlugin * plugin)
1056*4882a593Smuzhiyun {
1057*4882a593Smuzhiyun   if (!gst_element_register (plugin, "kmssrc", GST_RANK_NONE,
1058*4882a593Smuzhiyun           gst_kms_src_get_type ()))
1059*4882a593Smuzhiyun     return FALSE;
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "kmssrc", 0, "KmsSrc");
1062*4882a593Smuzhiyun   return TRUE;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1066*4882a593Smuzhiyun     GST_VERSION_MINOR,
1067*4882a593Smuzhiyun     kmssrc,
1068*4882a593Smuzhiyun     "KMS Src Plugin",
1069*4882a593Smuzhiyun     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
1070