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