1 /* GStreamer
2 * Copyright (C) 2020 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:gstvadisplaydrm
23 * @title: GstVaDisplayDrm
24 * @short_description: VADisplay from a DRM device
25 * @sources:
26 * - gstvadisplay_drm.h
27 *
28 * This is a #GstVaDisplay subclass to instantiate with DRM devices.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "gstvadisplay_drm.h"
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <va/va_drm.h>
41
42 #if HAVE_LIBDRM
43 #include <xf86drm.h>
44 #endif
45
46 /**
47 * GstVaDisplayDrm:
48 * @parent: parent #GstVaDisplay
49 *
50 * Since: 1.20
51 */
52 struct _GstVaDisplayDrm
53 {
54 GstVaDisplay parent;
55
56 /* <private> */
57 gchar *path;
58 gint fd;
59 };
60
61 /**
62 * GstVaDisplayDrmClass:
63 * @parent_class: parent #GstVaDisplayClass
64 *
65 * Since: 1.20
66 */
67 struct _GstVaDisplayDrmClass
68 {
69 GstVaDisplayClass parent_class;
70 };
71
72 GST_DEBUG_CATEGORY_EXTERN (gst_va_display_debug);
73 #define GST_CAT_DEFAULT gst_va_display_debug
74
75 #define gst_va_display_drm_parent_class parent_class
76 G_DEFINE_TYPE (GstVaDisplayDrm, gst_va_display_drm, GST_TYPE_VA_DISPLAY);
77
78 enum
79 {
80 PROP_PATH = 1,
81 N_PROPERTIES
82 };
83
84 static GParamSpec *g_properties[N_PROPERTIES];
85
86 #define MAX_DEVICES 8
87
88 static void
gst_va_display_drm_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)89 gst_va_display_drm_set_property (GObject * object, guint prop_id,
90 const GValue * value, GParamSpec * pspec)
91 {
92 GstVaDisplayDrm *self = GST_VA_DISPLAY_DRM (object);
93
94 switch (prop_id) {
95 case PROP_PATH:
96 self->path = g_value_dup_string (value);
97 break;
98 default:
99 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
100 break;
101 }
102 }
103
104 static void
gst_va_display_drm_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)105 gst_va_display_drm_get_property (GObject * object, guint prop_id,
106 GValue * value, GParamSpec * pspec)
107 {
108 GstVaDisplayDrm *self = GST_VA_DISPLAY_DRM (object);
109
110 switch (prop_id) {
111 case PROP_PATH:
112 g_value_set_string (value, self->path);
113 break;
114 default:
115 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
116 break;
117 }
118 }
119
120 static void
gst_va_display_drm_finalize(GObject * object)121 gst_va_display_drm_finalize (GObject * object)
122 {
123 GstVaDisplayDrm *self = GST_VA_DISPLAY_DRM (object);
124
125 g_free (self->path);
126 if (self->fd > -1)
127 close (self->fd);
128
129 G_OBJECT_CLASS (parent_class)->finalize (object);
130 }
131
132 static gpointer
gst_va_display_drm_create_va_display(GstVaDisplay * display)133 gst_va_display_drm_create_va_display (GstVaDisplay * display)
134 {
135 int fd, saved_errno = 0;
136 GstVaDisplayDrm *self = GST_VA_DISPLAY_DRM (display);
137
138 fd = open (self->path, O_CLOEXEC | O_RDWR);
139 saved_errno = errno;
140 if (fd < 0) {
141 GST_WARNING_OBJECT (self, "Failed to open %s: %s", self->path,
142 g_strerror (saved_errno));
143 return 0;
144 }
145 #if HAVE_LIBDRM
146 {
147 drmVersion *version;
148
149 version = drmGetVersion (fd);
150 if (!version) {
151 GST_ERROR_OBJECT (self, "Device %s is not a DRM render node", self->path);
152 return 0;
153 }
154 GST_INFO_OBJECT (self, "DRM render node with kernel driver %s",
155 version->name);
156 drmFreeVersion (version);
157 }
158 #endif
159
160 self->fd = fd;
161 return vaGetDisplayDRM (self->fd);
162 }
163
164 static void
gst_va_display_drm_class_init(GstVaDisplayDrmClass * klass)165 gst_va_display_drm_class_init (GstVaDisplayDrmClass * klass)
166 {
167 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
168 GstVaDisplayClass *vadisplay_class = GST_VA_DISPLAY_CLASS (klass);
169
170 gobject_class->set_property = gst_va_display_drm_set_property;
171 gobject_class->get_property = gst_va_display_drm_get_property;
172 gobject_class->finalize = gst_va_display_drm_finalize;
173
174 vadisplay_class->create_va_display = gst_va_display_drm_create_va_display;
175
176 g_properties[PROP_PATH] =
177 g_param_spec_string ("path", "render-path", "The path of DRM device",
178 "/dev/dri/renderD128",
179 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
180
181 g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
182 }
183
184 static void
gst_va_display_drm_init(GstVaDisplayDrm * self)185 gst_va_display_drm_init (GstVaDisplayDrm * self)
186 {
187 self->fd = -1;
188 }
189
190 /**
191 * gst_va_display_drm_new_from_path:
192 * @path: the path to the DRM device
193 *
194 * Creates a new #GstVaDisplay from a DRM device . It will try to open
195 * and operate the device in @path.
196 *
197 * Returns: (transfer full): a newly allocated #GstVaDisplay if the
198 * specified DRM render device could be opened and initialized;
199 * otherwise %NULL is returned.
200 *
201 * Since: 1.20
202 **/
203 GstVaDisplay *
gst_va_display_drm_new_from_path(const gchar * path)204 gst_va_display_drm_new_from_path (const gchar * path)
205 {
206 GstVaDisplay *dpy;
207
208 g_return_val_if_fail (path, NULL);
209
210 dpy = g_object_new (GST_TYPE_VA_DISPLAY_DRM, "path", path, NULL);
211 if (!gst_va_display_initialize (dpy)) {
212 gst_object_unref (dpy);
213 return NULL;
214 }
215
216 return gst_object_ref_sink (dpy);
217 }
218