xref: /OK3568_Linux_fs/external/gstreamer-rockchip/gst/rkximage/ximagesink.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun #ifdef HAVE_CONFIG_H
2*4882a593Smuzhiyun #include "config.h"
3*4882a593Smuzhiyun #endif
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun /* Our interfaces */
6*4882a593Smuzhiyun #include <gst/video/video.h>
7*4882a593Smuzhiyun #include <gst/allocators/gstdmabuf.h>
8*4882a593Smuzhiyun #include <gst/video/navigation.h>
9*4882a593Smuzhiyun #include <gst/video/videooverlay.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <gst/video/gstvideometa.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun /* Debugging category */
14*4882a593Smuzhiyun #include <gst/gstinfo.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /* for XkbKeycodeToKeysym */
17*4882a593Smuzhiyun #include <X11/XKBlib.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <drm.h>
20*4882a593Smuzhiyun #include <xf86drm.h>
21*4882a593Smuzhiyun #include <xf86drmMode.h>
22*4882a593Smuzhiyun #include <drm_fourcc.h>
23*4882a593Smuzhiyun #include <fcntl.h>
24*4882a593Smuzhiyun #include <string.h>
25*4882a593Smuzhiyun #include <unistd.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /* Object header */
28*4882a593Smuzhiyun #include "ximagesink.h"
29*4882a593Smuzhiyun #include "gstkmsutils.h"
30*4882a593Smuzhiyun #include "gstkmsbufferpool.h"
31*4882a593Smuzhiyun #include "gstkmsallocator.h"
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /* A random dark color */
34*4882a593Smuzhiyun #define RKXIMAGE_COLOR_KEY 0x010203
35*4882a593Smuzhiyun #define RK_COLOR_KEY_EN (1UL << 31)
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun GST_DEBUG_CATEGORY (gst_debug_x_image_sink);
38*4882a593Smuzhiyun #define GST_CAT_DEFAULT gst_debug_x_image_sink
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define EMPTY_RECT(r) !((r).x || (r).y || (r).w || (r).h)
41*4882a593Smuzhiyun #define RECT_EQUAL(r1, r2) \
42*4882a593Smuzhiyun     ((r1).x == (r2).x && (r1).y == (r2).y && \
43*4882a593Smuzhiyun      (r1).w == (r2.w) && (r1).h == (r2).h)
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun typedef struct
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun   unsigned long flags;
48*4882a593Smuzhiyun   unsigned long functions;
49*4882a593Smuzhiyun   unsigned long decorations;
50*4882a593Smuzhiyun   long input_mode;
51*4882a593Smuzhiyun   unsigned long status;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun MotifWmHints, MwmHints;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define MWM_HINTS_DECORATIONS   (1L << 1)
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun static void gst_x_image_sink_reset (GstRkXImageSink * ximagesink);
58*4882a593Smuzhiyun static void gst_x_image_sink_xwindow_update_geometry (GstRkXImageSink *
59*4882a593Smuzhiyun     ximagesink);
60*4882a593Smuzhiyun static void gst_x_image_sink_expose (GstVideoOverlay * overlay);
61*4882a593Smuzhiyun static void gst_x_image_sink_xwindow_clear (GstRkXImageSink * ximagesink,
62*4882a593Smuzhiyun     GstXWindow * xwindow);
63*4882a593Smuzhiyun static GstFlowReturn
64*4882a593Smuzhiyun gst_x_image_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun static GstStaticPadTemplate gst_x_image_sink_sink_template_factory =
67*4882a593Smuzhiyun GST_STATIC_PAD_TEMPLATE ("sink",
68*4882a593Smuzhiyun     GST_PAD_SINK,
69*4882a593Smuzhiyun     GST_PAD_ALWAYS,
70*4882a593Smuzhiyun     GST_STATIC_CAPS ("video/x-raw, "
71*4882a593Smuzhiyun         "framerate = (fraction) [ 0, MAX ], "
72*4882a593Smuzhiyun         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
73*4882a593Smuzhiyun     );
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun enum
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun   PROP_0,
78*4882a593Smuzhiyun   PROP_DISPLAY,
79*4882a593Smuzhiyun   PROP_SYNCHRONOUS,
80*4882a593Smuzhiyun   PROP_HANDLE_EVENTS,
81*4882a593Smuzhiyun   PROP_HANDLE_EXPOSE,
82*4882a593Smuzhiyun   PROP_WINDOW_WIDTH,
83*4882a593Smuzhiyun   PROP_WINDOW_HEIGHT,
84*4882a593Smuzhiyun   PROP_DRIVER_NAME,
85*4882a593Smuzhiyun   PROP_BUS_ID,
86*4882a593Smuzhiyun   PROP_CONNECTOR_ID,
87*4882a593Smuzhiyun   PROP_PLANE_ID,
88*4882a593Smuzhiyun   PROP_FORCE_ASPECT_RATIO,
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun /* ============================================================= */
92*4882a593Smuzhiyun /*                                                               */
93*4882a593Smuzhiyun /*                       Public Methods                          */
94*4882a593Smuzhiyun /*                                                               */
95*4882a593Smuzhiyun /* ============================================================= */
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun /* =========================================== */
98*4882a593Smuzhiyun /*                                             */
99*4882a593Smuzhiyun /*          Object typing & Creation           */
100*4882a593Smuzhiyun /*                                             */
101*4882a593Smuzhiyun /* =========================================== */
102*4882a593Smuzhiyun static void gst_x_image_sink_navigation_init (GstNavigationInterface * iface);
103*4882a593Smuzhiyun static void gst_x_image_sink_video_overlay_init (GstVideoOverlayInterface *
104*4882a593Smuzhiyun     iface);
105*4882a593Smuzhiyun #define gst_x_image_sink_parent_class parent_class
106*4882a593Smuzhiyun G_DEFINE_TYPE_WITH_CODE (GstRkXImageSink, gst_x_image_sink, GST_TYPE_VIDEO_SINK,
107*4882a593Smuzhiyun     G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
108*4882a593Smuzhiyun         gst_x_image_sink_navigation_init);
109*4882a593Smuzhiyun     G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
110*4882a593Smuzhiyun         gst_x_image_sink_video_overlay_init));
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun /* ============================================================= */
113*4882a593Smuzhiyun /*                                                               */
114*4882a593Smuzhiyun /*                       Private Methods                         */
115*4882a593Smuzhiyun /*                                                               */
116*4882a593Smuzhiyun /* ============================================================= */
117*4882a593Smuzhiyun /*drm*/
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static int
drm_plane_get_type(int fd,drmModePlane * plane)120*4882a593Smuzhiyun drm_plane_get_type (int fd, drmModePlane * plane)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun   drmModeObjectPropertiesPtr props;
123*4882a593Smuzhiyun   drmModePropertyPtr prop;
124*4882a593Smuzhiyun   int i, type = -1;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun   props = drmModeObjectGetProperties (fd, plane->plane_id,
127*4882a593Smuzhiyun       DRM_MODE_OBJECT_PLANE);
128*4882a593Smuzhiyun   if (!props)
129*4882a593Smuzhiyun     return -1;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun   for (i = 0; i < props->count_props; i++) {
132*4882a593Smuzhiyun     prop = drmModeGetProperty (fd, props->props[i]);
133*4882a593Smuzhiyun     if (prop && !strcmp (prop->name, "type"))
134*4882a593Smuzhiyun       type = props->prop_values[i];
135*4882a593Smuzhiyun     drmModeFreeProperty (prop);
136*4882a593Smuzhiyun   }
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun   drmModeFreeObjectProperties (props);
139*4882a593Smuzhiyun   return type;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun static drmModePlane *
drm_find_plane_for_crtc_by_type(int fd,drmModeRes * res,drmModePlaneRes * pres,int crtc_id,int type)143*4882a593Smuzhiyun drm_find_plane_for_crtc_by_type (int fd, drmModeRes * res,
144*4882a593Smuzhiyun     drmModePlaneRes * pres, int crtc_id, int type)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun   int i, pipe = -1, num_primary = 0;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun   for (i = 0; i < res->count_crtcs; i++) {
149*4882a593Smuzhiyun     if (crtc_id == res->crtcs[i]) {
150*4882a593Smuzhiyun       pipe = i;
151*4882a593Smuzhiyun       break;
152*4882a593Smuzhiyun     }
153*4882a593Smuzhiyun   }
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun   if (pipe == -1)
156*4882a593Smuzhiyun     return NULL;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun   for (i = 0; i < pres->count_planes; i++) {
159*4882a593Smuzhiyun     drmModePlane *plane = drmModeGetPlane (fd, pres->planes[i]);
160*4882a593Smuzhiyun     int plane_type = drm_plane_get_type (fd, plane);
161*4882a593Smuzhiyun     int primary = plane_type == DRM_PLANE_TYPE_PRIMARY;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun     num_primary += primary;
164*4882a593Smuzhiyun     if ((plane->possible_crtcs & (1 << pipe)) && plane_type == type) {
165*4882a593Smuzhiyun       if (!primary || pipe == num_primary - 1)
166*4882a593Smuzhiyun         return plane;
167*4882a593Smuzhiyun     }
168*4882a593Smuzhiyun     drmModeFreePlane (plane);
169*4882a593Smuzhiyun   }
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun   return NULL;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun static drmModeCrtc *
drm_find_crtc_for_connector(int fd,drmModeRes * res,drmModeConnector * conn,guint * pipe)175*4882a593Smuzhiyun drm_find_crtc_for_connector (int fd, drmModeRes * res, drmModeConnector * conn,
176*4882a593Smuzhiyun     guint * pipe)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun   int i;
179*4882a593Smuzhiyun   int crtc_id;
180*4882a593Smuzhiyun   drmModeEncoder *enc;
181*4882a593Smuzhiyun   drmModeCrtc *crtc;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun   crtc_id = -1;
184*4882a593Smuzhiyun   for (i = 0; i < res->count_encoders; i++) {
185*4882a593Smuzhiyun     enc = drmModeGetEncoder (fd, res->encoders[i]);
186*4882a593Smuzhiyun     if (enc) {
187*4882a593Smuzhiyun       if (enc->encoder_id == conn->encoder_id) {
188*4882a593Smuzhiyun         crtc_id = enc->crtc_id;
189*4882a593Smuzhiyun         drmModeFreeEncoder (enc);
190*4882a593Smuzhiyun         break;
191*4882a593Smuzhiyun       }
192*4882a593Smuzhiyun       drmModeFreeEncoder (enc);
193*4882a593Smuzhiyun     }
194*4882a593Smuzhiyun   }
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun   if (crtc_id == -1)
197*4882a593Smuzhiyun     return NULL;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun   for (i = 0; i < res->count_crtcs; i++) {
200*4882a593Smuzhiyun     crtc = drmModeGetCrtc (fd, res->crtcs[i]);
201*4882a593Smuzhiyun     if (crtc) {
202*4882a593Smuzhiyun       if (crtc_id == crtc->crtc_id) {
203*4882a593Smuzhiyun         if (pipe)
204*4882a593Smuzhiyun           *pipe = i;
205*4882a593Smuzhiyun         return crtc;
206*4882a593Smuzhiyun       }
207*4882a593Smuzhiyun       drmModeFreeCrtc (crtc);
208*4882a593Smuzhiyun     }
209*4882a593Smuzhiyun   }
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun   return NULL;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun static gboolean
drm_connector_is_used(int fd,drmModeRes * res,drmModeConnector * conn)215*4882a593Smuzhiyun drm_connector_is_used (int fd, drmModeRes * res, drmModeConnector * conn)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun   gboolean result;
218*4882a593Smuzhiyun   drmModeCrtc *crtc;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun   result = FALSE;
221*4882a593Smuzhiyun   crtc = drm_find_crtc_for_connector (fd, res, conn, NULL);
222*4882a593Smuzhiyun   if (crtc) {
223*4882a593Smuzhiyun     result = crtc->buffer_id != 0;
224*4882a593Smuzhiyun     drmModeFreeCrtc (crtc);
225*4882a593Smuzhiyun   }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun   return result;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun static drmModeConnector *
drm_find_used_connector_by_type(int fd,drmModeRes * res,int type)231*4882a593Smuzhiyun drm_find_used_connector_by_type (int fd, drmModeRes * res, int type)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun   int i;
234*4882a593Smuzhiyun   drmModeConnector *conn;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun   conn = NULL;
237*4882a593Smuzhiyun   for (i = 0; i < res->count_connectors; i++) {
238*4882a593Smuzhiyun     conn = drmModeGetConnector (fd, res->connectors[i]);
239*4882a593Smuzhiyun     if (conn) {
240*4882a593Smuzhiyun       if ((conn->connector_type == type)
241*4882a593Smuzhiyun           && drm_connector_is_used (fd, res, conn))
242*4882a593Smuzhiyun         return conn;
243*4882a593Smuzhiyun       drmModeFreeConnector (conn);
244*4882a593Smuzhiyun     }
245*4882a593Smuzhiyun   }
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun   return NULL;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun static drmModeConnector *
drm_find_first_used_connector(int fd,drmModeRes * res)251*4882a593Smuzhiyun drm_find_first_used_connector (int fd, drmModeRes * res)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun   int i;
254*4882a593Smuzhiyun   drmModeConnector *conn;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun   conn = NULL;
257*4882a593Smuzhiyun   for (i = 0; i < res->count_connectors; i++) {
258*4882a593Smuzhiyun     conn = drmModeGetConnector (fd, res->connectors[i]);
259*4882a593Smuzhiyun     if (conn) {
260*4882a593Smuzhiyun       if (drm_connector_is_used (fd, res, conn))
261*4882a593Smuzhiyun         return conn;
262*4882a593Smuzhiyun       drmModeFreeConnector (conn);
263*4882a593Smuzhiyun     }
264*4882a593Smuzhiyun   }
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun   return NULL;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun static drmModeConnector *
drm_find_main_monitor(int fd,drmModeRes * res)270*4882a593Smuzhiyun drm_find_main_monitor (int fd, drmModeRes * res)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun   /* Find the LVDS and eDP connectors: those are the main screens. */
273*4882a593Smuzhiyun   static const int priority[] = { DRM_MODE_CONNECTOR_LVDS,
274*4882a593Smuzhiyun     DRM_MODE_CONNECTOR_eDP
275*4882a593Smuzhiyun   };
276*4882a593Smuzhiyun   int i;
277*4882a593Smuzhiyun   drmModeConnector *conn;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun   conn = NULL;
280*4882a593Smuzhiyun   for (i = 0; !conn && i < G_N_ELEMENTS (priority); i++)
281*4882a593Smuzhiyun     conn = drm_find_used_connector_by_type (fd, res, priority[i]);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun   /* if we didn't find a connector, grab the first one in use */
284*4882a593Smuzhiyun   if (!conn)
285*4882a593Smuzhiyun     conn = drm_find_first_used_connector (fd, res);
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun   return conn;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun static void
drm_log_version(GstRkXImageSink * self)291*4882a593Smuzhiyun drm_log_version (GstRkXImageSink * self)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun #ifndef GST_DISABLE_GST_DEBUG
294*4882a593Smuzhiyun   drmVersion *v;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun   v = drmGetVersion (self->fd);
297*4882a593Smuzhiyun   if (v) {
298*4882a593Smuzhiyun     GST_INFO_OBJECT (self, "DRM v%d.%d.%d [%s — %s — %s]", v->version_major,
299*4882a593Smuzhiyun         v->version_minor, v->version_patchlevel, GST_STR_NULL (v->name),
300*4882a593Smuzhiyun         GST_STR_NULL (v->desc), GST_STR_NULL (v->date));
301*4882a593Smuzhiyun     drmFreeVersion (v);
302*4882a593Smuzhiyun   } else {
303*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "could not get driver information: %s",
304*4882a593Smuzhiyun         GST_STR_NULL (self->devname));
305*4882a593Smuzhiyun   }
306*4882a593Smuzhiyun #endif
307*4882a593Smuzhiyun   return;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun static gboolean
drm_get_caps(GstRkXImageSink * self)311*4882a593Smuzhiyun drm_get_caps (GstRkXImageSink * self)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun   gint ret;
314*4882a593Smuzhiyun   guint64 has_dumb_buffer;
315*4882a593Smuzhiyun   guint64 has_prime;
316*4882a593Smuzhiyun   guint64 has_async_page_flip;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun   has_dumb_buffer = 0;
319*4882a593Smuzhiyun   ret = drmGetCap (self->fd, DRM_CAP_DUMB_BUFFER, &has_dumb_buffer);
320*4882a593Smuzhiyun   if (ret)
321*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "could not get dumb buffer capability");
322*4882a593Smuzhiyun   if (has_dumb_buffer == 0) {
323*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "driver cannot handle dumb buffers");
324*4882a593Smuzhiyun     return FALSE;
325*4882a593Smuzhiyun   }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun   has_prime = 0;
328*4882a593Smuzhiyun   ret = drmGetCap (self->fd, DRM_CAP_PRIME, &has_prime);
329*4882a593Smuzhiyun   if (ret)
330*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "could not get prime capability");
331*4882a593Smuzhiyun   else {
332*4882a593Smuzhiyun     self->has_prime_import = (gboolean) (has_prime & DRM_PRIME_CAP_IMPORT);
333*4882a593Smuzhiyun     self->has_prime_export = (gboolean) (has_prime & DRM_PRIME_CAP_EXPORT);
334*4882a593Smuzhiyun   }
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun   has_async_page_flip = 0;
337*4882a593Smuzhiyun   ret = drmGetCap (self->fd, DRM_CAP_ASYNC_PAGE_FLIP, &has_async_page_flip);
338*4882a593Smuzhiyun   if (ret)
339*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "could not get async page flip capability");
340*4882a593Smuzhiyun   else
341*4882a593Smuzhiyun     self->has_async_page_flip = (gboolean) has_async_page_flip;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun   GST_INFO_OBJECT (self,
344*4882a593Smuzhiyun       "prime import (%s) / prime export (%s) / async page flip (%s)",
345*4882a593Smuzhiyun       self->has_prime_import ? "✓" : "✗",
346*4882a593Smuzhiyun       self->has_prime_export ? "✓" : "✗",
347*4882a593Smuzhiyun       self->has_async_page_flip ? "✓" : "✗");
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun   return TRUE;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun static void
check_afbc(GstRkXImageSink * self,drmModePlane * plane,guint32 drmfmt,gboolean * linear,gboolean * afbc)353*4882a593Smuzhiyun check_afbc (GstRkXImageSink * self, drmModePlane * plane, guint32 drmfmt,
354*4882a593Smuzhiyun     gboolean * linear, gboolean * afbc)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun   drmModeObjectPropertiesPtr props;
357*4882a593Smuzhiyun   drmModePropertyBlobPtr blob;
358*4882a593Smuzhiyun   drmModePropertyPtr prop;
359*4882a593Smuzhiyun   drmModeResPtr res;
360*4882a593Smuzhiyun   struct drm_format_modifier_blob *header;
361*4882a593Smuzhiyun   struct drm_format_modifier *modifiers;
362*4882a593Smuzhiyun   guint32 *formats;
363*4882a593Smuzhiyun   guint64 value = 0;
364*4882a593Smuzhiyun   gint i, j;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun   *linear = *afbc = FALSE;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun   res = drmModeGetResources (self->fd);
369*4882a593Smuzhiyun   if (!res)
370*4882a593Smuzhiyun     return;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun   props = drmModeObjectGetProperties (self->fd, plane->plane_id,
373*4882a593Smuzhiyun       DRM_MODE_OBJECT_PLANE);
374*4882a593Smuzhiyun   if (!props) {
375*4882a593Smuzhiyun     drmModeFreeResources (res);
376*4882a593Smuzhiyun     return;
377*4882a593Smuzhiyun   }
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun   for (i = 0; i < props->count_props && !value; i++) {
380*4882a593Smuzhiyun     prop = drmModeGetProperty (self->fd, props->props[i]);
381*4882a593Smuzhiyun     if (!prop)
382*4882a593Smuzhiyun       continue;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun     if (!strcmp (prop->name, "IN_FORMATS"))
385*4882a593Smuzhiyun       value = props->prop_values[i];
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun     drmModeFreeProperty (prop);
388*4882a593Smuzhiyun   }
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun   drmModeFreeObjectProperties (props);
391*4882a593Smuzhiyun   drmModeFreeResources (res);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun   /* No modifiers */
394*4882a593Smuzhiyun   if (!value) {
395*4882a593Smuzhiyun     *linear = TRUE;
396*4882a593Smuzhiyun     return;
397*4882a593Smuzhiyun   }
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun   blob = drmModeGetPropertyBlob (self->fd, value);
400*4882a593Smuzhiyun   if (!blob)
401*4882a593Smuzhiyun     return;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun   header = blob->data;
404*4882a593Smuzhiyun   modifiers = (struct drm_format_modifier *)
405*4882a593Smuzhiyun     ((gchar *) header + header->modifiers_offset);
406*4882a593Smuzhiyun   formats = (guint32 *) ((gchar *) header + header->formats_offset);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun   for (i = 0; i < header->count_formats; i++) {
409*4882a593Smuzhiyun     if (formats[i] != drmfmt)
410*4882a593Smuzhiyun       continue;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun     for (j = 0; j < header->count_modifiers; j++) {
413*4882a593Smuzhiyun       struct drm_format_modifier *mod = &modifiers[j];
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun       if ((i < mod->offset) || (i > mod->offset + 63))
416*4882a593Smuzhiyun         continue;
417*4882a593Smuzhiyun       if (!(mod->formats & (1 << (i - mod->offset))))
418*4882a593Smuzhiyun         continue;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun       if (mod->modifier == DRM_AFBC_MODIFIER)
421*4882a593Smuzhiyun         *afbc = TRUE;
422*4882a593Smuzhiyun       else if (mod->modifier == DRM_FORMAT_MOD_LINEAR)
423*4882a593Smuzhiyun         *linear = TRUE;
424*4882a593Smuzhiyun     }
425*4882a593Smuzhiyun   }
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun   drmModeFreePropertyBlob(blob);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun static gboolean
drm_ensure_allowed_caps(GstRkXImageSink * self,drmModePlane * plane,drmModeRes * res)431*4882a593Smuzhiyun drm_ensure_allowed_caps (GstRkXImageSink * self, drmModePlane * plane,
432*4882a593Smuzhiyun     drmModeRes * res)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun   GstCaps *out_caps, *caps;
435*4882a593Smuzhiyun   int i;
436*4882a593Smuzhiyun   GstVideoFormat fmt;
437*4882a593Smuzhiyun   const gchar *format;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun   if (self->allowed_caps)
440*4882a593Smuzhiyun     return TRUE;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun   out_caps = gst_caps_new_empty ();
443*4882a593Smuzhiyun   if (!out_caps)
444*4882a593Smuzhiyun     return FALSE;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun   for (i = 0; i < plane->count_formats; i++) {
447*4882a593Smuzhiyun     gboolean linear = FALSE, afbc = FALSE;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun     check_afbc (self, plane, plane->formats[i], &linear, &afbc);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun     if (plane->formats[i] == DRM_FORMAT_YUV420_8BIT)
452*4882a593Smuzhiyun       fmt = GST_VIDEO_FORMAT_NV12;
453*4882a593Smuzhiyun     else if (plane->formats[i] == DRM_FORMAT_YUV420_10BIT)
454*4882a593Smuzhiyun       fmt = GST_VIDEO_FORMAT_NV12_10LE40;
455*4882a593Smuzhiyun     else if (afbc && plane->formats[i] == DRM_FORMAT_YUYV)
456*4882a593Smuzhiyun       fmt = GST_VIDEO_FORMAT_NV16;
457*4882a593Smuzhiyun       else
458*4882a593Smuzhiyun         fmt = gst_video_format_from_drm (plane->formats[i]);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun     if (fmt == GST_VIDEO_FORMAT_UNKNOWN) {
461*4882a593Smuzhiyun       GST_INFO_OBJECT (self, "ignoring format %" GST_FOURCC_FORMAT,
462*4882a593Smuzhiyun           GST_FOURCC_ARGS (plane->formats[i]));
463*4882a593Smuzhiyun       continue;
464*4882a593Smuzhiyun     }
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun     format = gst_video_format_to_string (fmt);
467*4882a593Smuzhiyun     caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, format,
468*4882a593Smuzhiyun         "width", GST_TYPE_INT_RANGE, res->min_width, res->max_width,
469*4882a593Smuzhiyun         "height", GST_TYPE_INT_RANGE, res->min_height, res->max_height,
470*4882a593Smuzhiyun         "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
471*4882a593Smuzhiyun     if (!caps)
472*4882a593Smuzhiyun       continue;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun     if (afbc) {
475*4882a593Smuzhiyun       GstCaps *afbc_caps = gst_caps_copy (caps);
476*4882a593Smuzhiyun       gst_caps_set_simple (afbc_caps, "arm-afbc", G_TYPE_INT, 1, NULL);
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun       if (linear) {
479*4882a593Smuzhiyun         gst_caps_append (caps, afbc_caps);
480*4882a593Smuzhiyun       } else {
481*4882a593Smuzhiyun         gst_caps_replace (&caps, afbc_caps);
482*4882a593Smuzhiyun         gst_caps_unref (afbc_caps);
483*4882a593Smuzhiyun       }
484*4882a593Smuzhiyun     }
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun     out_caps = gst_caps_merge (out_caps, caps);
487*4882a593Smuzhiyun   }
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun   self->allowed_caps = gst_caps_simplify (out_caps);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "allowed caps = %" GST_PTR_FORMAT,
492*4882a593Smuzhiyun       self->allowed_caps);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun   return TRUE;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun static gboolean
drm_plane_set_property(GstRkXImageSink * self,drmModePlane * plane,const char * prop_name,uint64_t prop_value)498*4882a593Smuzhiyun drm_plane_set_property (GstRkXImageSink * self, drmModePlane * plane,
499*4882a593Smuzhiyun     const char *prop_name, uint64_t prop_value)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun   drmModeObjectPropertiesPtr props;
502*4882a593Smuzhiyun   drmModePropertyPtr prop;
503*4882a593Smuzhiyun   int i, ret = -1;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun   props = drmModeObjectGetProperties (self->fd, plane->plane_id,
506*4882a593Smuzhiyun       DRM_MODE_OBJECT_PLANE);
507*4882a593Smuzhiyun   if (!props)
508*4882a593Smuzhiyun     return FALSE;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun   for (i = 0; i < props->count_props; i++) {
511*4882a593Smuzhiyun     prop = drmModeGetProperty (self->fd, props->props[i]);
512*4882a593Smuzhiyun     if (prop && !strcmp (prop->name, prop_name)) {
513*4882a593Smuzhiyun       ret = drmModeObjectSetProperty (self->fd, plane->plane_id,
514*4882a593Smuzhiyun           DRM_MODE_OBJECT_PLANE, props->props[i], prop_value);
515*4882a593Smuzhiyun     }
516*4882a593Smuzhiyun     drmModeFreeProperty (prop);
517*4882a593Smuzhiyun   }
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun   drmModeFreeObjectProperties (props);
520*4882a593Smuzhiyun   return ret < 0 ? FALSE : TRUE;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun static gboolean
drm_prepare_planes(GstRkXImageSink * self,drmModeRes * res,drmModePlaneRes * pres)524*4882a593Smuzhiyun drm_prepare_planes (GstRkXImageSink * self, drmModeRes * res,
525*4882a593Smuzhiyun     drmModePlaneRes * pres)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun   drmModePlane *plane;
528*4882a593Smuzhiyun   gboolean ret = FALSE;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun   if (drmSetClientCap (self->fd, DRM_CLIENT_CAP_ATOMIC, 1))
531*4882a593Smuzhiyun     return FALSE;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun   /* Apply colorkey to primary plane */
534*4882a593Smuzhiyun   plane = drm_find_plane_for_crtc_by_type (self->fd, res, pres,
535*4882a593Smuzhiyun       self->crtc_id, DRM_PLANE_TYPE_PRIMARY);
536*4882a593Smuzhiyun   if (!plane)
537*4882a593Smuzhiyun     return FALSE;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun   if (!drm_plane_set_property (self, plane, "colorkey",
540*4882a593Smuzhiyun           RKXIMAGE_COLOR_KEY | RK_COLOR_KEY_EN))
541*4882a593Smuzhiyun     goto out;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "applied colorkey = 0x%x to plane %d",
544*4882a593Smuzhiyun       RKXIMAGE_COLOR_KEY, plane->plane_id);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun   /* Uper primary plane */
547*4882a593Smuzhiyun   if (!drm_plane_set_property (self, plane, "ZPOS", 1) &&
548*4882a593Smuzhiyun       !drm_plane_set_property (self, plane, "zpos", 1))
549*4882a593Smuzhiyun     goto out;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun   drmModeFreePlane (plane);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun   /* Lower overlay plane */
554*4882a593Smuzhiyun   plane = drmModeGetPlane (self->fd, self->plane_id);
555*4882a593Smuzhiyun   if (!plane)
556*4882a593Smuzhiyun     goto out;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun   if (!drm_plane_set_property (self, plane, "ZPOS", 0) &&
559*4882a593Smuzhiyun       !drm_plane_set_property (self, plane, "zpos", 0))
560*4882a593Smuzhiyun     goto out;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "set plane %d zpos to 0", plane->plane_id);
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun   ret = TRUE;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun out:
567*4882a593Smuzhiyun   drmModeFreePlane (plane);
568*4882a593Smuzhiyun   return ret;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun /*kms*/
572*4882a593Smuzhiyun static void
ensure_kms_allocator(GstRkXImageSink * self)573*4882a593Smuzhiyun ensure_kms_allocator (GstRkXImageSink * self)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun   if (self->allocator)
576*4882a593Smuzhiyun     return;
577*4882a593Smuzhiyun   self->allocator = gst_kms_allocator_new (self->fd);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun static GstBufferPool *
gst_kms_sink_create_pool(GstRkXImageSink * self,GstCaps * caps,gsize size,gint min)581*4882a593Smuzhiyun gst_kms_sink_create_pool (GstRkXImageSink * self, GstCaps * caps, gsize size,
582*4882a593Smuzhiyun     gint min)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun   GstBufferPool *pool;
585*4882a593Smuzhiyun   GstStructure *config;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun   pool = gst_kms_buffer_pool_new ();
588*4882a593Smuzhiyun   if (!pool)
589*4882a593Smuzhiyun     goto pool_failed;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun   config = gst_buffer_pool_get_config (pool);
592*4882a593Smuzhiyun   gst_buffer_pool_config_set_params (config, caps, size, min, 0);
593*4882a593Smuzhiyun   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun   ensure_kms_allocator (self);
596*4882a593Smuzhiyun   gst_buffer_pool_config_set_allocator (config, self->allocator, NULL);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun   if (!gst_buffer_pool_set_config (pool, config))
599*4882a593Smuzhiyun     goto config_failed;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun   return pool;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun   /* ERRORS */
604*4882a593Smuzhiyun pool_failed:
605*4882a593Smuzhiyun   {
606*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "failed to create buffer pool");
607*4882a593Smuzhiyun     return NULL;
608*4882a593Smuzhiyun   }
609*4882a593Smuzhiyun config_failed:
610*4882a593Smuzhiyun   {
611*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "failed to set config");
612*4882a593Smuzhiyun     gst_object_unref (pool);
613*4882a593Smuzhiyun     return NULL;
614*4882a593Smuzhiyun   }
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun static gboolean
gst_kms_sink_propose_allocation(GstBaseSink * bsink,GstQuery * query)618*4882a593Smuzhiyun gst_kms_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun   GstRkXImageSink *self;
621*4882a593Smuzhiyun   GstCaps *caps;
622*4882a593Smuzhiyun   gboolean need_pool;
623*4882a593Smuzhiyun   GstVideoInfo vinfo;
624*4882a593Smuzhiyun   GstBufferPool *pool;
625*4882a593Smuzhiyun   GstStructure *s;
626*4882a593Smuzhiyun   gsize size;
627*4882a593Smuzhiyun   gint value;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun   self = GST_X_IMAGE_SINK (bsink);
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun   gst_query_parse_allocation (query, &caps, &need_pool);
632*4882a593Smuzhiyun   if (!caps)
633*4882a593Smuzhiyun     goto no_caps;
634*4882a593Smuzhiyun   if (!gst_video_info_from_caps (&vinfo, caps))
635*4882a593Smuzhiyun     goto invalid_caps;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun   s = gst_caps_get_structure (caps, 0);
638*4882a593Smuzhiyun   if (gst_structure_get_int (s, "arm-afbc", &value) && value)
639*4882a593Smuzhiyun     goto afbc_caps;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun   size = GST_VIDEO_INFO_SIZE (&vinfo);
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun   pool = NULL;
644*4882a593Smuzhiyun   if (need_pool) {
645*4882a593Smuzhiyun     pool = gst_kms_sink_create_pool (self, caps, size, 0);
646*4882a593Smuzhiyun     if (!pool)
647*4882a593Smuzhiyun       goto no_pool;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun     /* Only export for pool used upstream */
650*4882a593Smuzhiyun     if (self->has_prime_export) {
651*4882a593Smuzhiyun       GstStructure *config = gst_buffer_pool_get_config (pool);
652*4882a593Smuzhiyun       gst_buffer_pool_config_add_option (config,
653*4882a593Smuzhiyun           GST_BUFFER_POOL_OPTION_KMS_PRIME_EXPORT);
654*4882a593Smuzhiyun       gst_buffer_pool_set_config (pool, config);
655*4882a593Smuzhiyun     }
656*4882a593Smuzhiyun   }
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun   /* we need at least 2 buffer because we hold on to the last one */
659*4882a593Smuzhiyun   gst_query_add_allocation_pool (query, pool, size, 2, 0);
660*4882a593Smuzhiyun   if (pool)
661*4882a593Smuzhiyun     gst_object_unref (pool);
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
664*4882a593Smuzhiyun   gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun   return TRUE;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun   /* ERRORS */
669*4882a593Smuzhiyun no_caps:
670*4882a593Smuzhiyun   {
671*4882a593Smuzhiyun     GST_DEBUG_OBJECT (bsink, "no caps specified");
672*4882a593Smuzhiyun     return FALSE;
673*4882a593Smuzhiyun   }
674*4882a593Smuzhiyun invalid_caps:
675*4882a593Smuzhiyun   {
676*4882a593Smuzhiyun     GST_DEBUG_OBJECT (bsink, "invalid caps specified");
677*4882a593Smuzhiyun     return FALSE;
678*4882a593Smuzhiyun   }
679*4882a593Smuzhiyun afbc_caps:
680*4882a593Smuzhiyun   {
681*4882a593Smuzhiyun     GST_DEBUG_OBJECT (bsink, "no allocation for AFBC");
682*4882a593Smuzhiyun     return FALSE;
683*4882a593Smuzhiyun   }
684*4882a593Smuzhiyun no_pool:
685*4882a593Smuzhiyun   {
686*4882a593Smuzhiyun     /* Already warned in create_pool */
687*4882a593Smuzhiyun     return FALSE;
688*4882a593Smuzhiyun   }
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun static gboolean
gst_kms_sink_import_dmabuf(GstRkXImageSink * self,GstBuffer * inbuf,GstBuffer ** outbuf)692*4882a593Smuzhiyun gst_kms_sink_import_dmabuf (GstRkXImageSink * self, GstBuffer * inbuf,
693*4882a593Smuzhiyun     GstBuffer ** outbuf)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun   gint prime_fds[GST_VIDEO_MAX_PLANES] = { 0, };
696*4882a593Smuzhiyun   GstVideoMeta *meta;
697*4882a593Smuzhiyun   guint i, n_mem, n_planes;
698*4882a593Smuzhiyun   GstKMSMemory *kmsmem;
699*4882a593Smuzhiyun   guint mems_idx[GST_VIDEO_MAX_PLANES];
700*4882a593Smuzhiyun   gsize mems_skip[GST_VIDEO_MAX_PLANES];
701*4882a593Smuzhiyun   GstMemory *mems[GST_VIDEO_MAX_PLANES];
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun   if (!self->has_prime_import)
704*4882a593Smuzhiyun     return FALSE;
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun   /* This will eliminate most non-dmabuf out there */
707*4882a593Smuzhiyun   if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0)))
708*4882a593Smuzhiyun     return FALSE;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun   n_planes = GST_VIDEO_INFO_N_PLANES (&self->vinfo);
711*4882a593Smuzhiyun   n_mem = gst_buffer_n_memory (inbuf);
712*4882a593Smuzhiyun   meta = gst_buffer_get_video_meta (inbuf);
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun   GST_TRACE_OBJECT (self, "Found a dmabuf with %u planes and %u memories",
715*4882a593Smuzhiyun       n_planes, n_mem);
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun   /* We cannot have multiple dmabuf per plane */
718*4882a593Smuzhiyun   if (n_mem > n_planes)
719*4882a593Smuzhiyun     return FALSE;
720*4882a593Smuzhiyun   g_assert (n_planes != 0);
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun   /* Update video info based on video meta */
723*4882a593Smuzhiyun   if (meta) {
724*4882a593Smuzhiyun     GST_VIDEO_INFO_WIDTH (&self->vinfo) = meta->width;
725*4882a593Smuzhiyun     GST_VIDEO_INFO_HEIGHT (&self->vinfo) = meta->height;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun     for (i = 0; i < meta->n_planes; i++) {
728*4882a593Smuzhiyun       GST_VIDEO_INFO_PLANE_OFFSET (&self->vinfo, i) = meta->offset[i];
729*4882a593Smuzhiyun       GST_VIDEO_INFO_PLANE_STRIDE (&self->vinfo, i) = meta->stride[i];
730*4882a593Smuzhiyun     }
731*4882a593Smuzhiyun   }
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun   /* Find and validate all memories */
734*4882a593Smuzhiyun   for (i = 0; i < n_planes; i++) {
735*4882a593Smuzhiyun     guint length;
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun     if (!gst_buffer_find_memory (inbuf,
738*4882a593Smuzhiyun             GST_VIDEO_INFO_PLANE_OFFSET (&self->vinfo, i), 1,
739*4882a593Smuzhiyun             &mems_idx[i], &length, &mems_skip[i]))
740*4882a593Smuzhiyun       return FALSE;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun     mems[i] = gst_buffer_peek_memory (inbuf, mems_idx[i]);
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun     /* adjust for memory offset, in case data does not
745*4882a593Smuzhiyun      * start from byte 0 in the dmabuf fd */
746*4882a593Smuzhiyun     mems_skip[i] += mems[i]->offset;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun     /* And all memory found must be dmabuf */
749*4882a593Smuzhiyun     if (!gst_is_dmabuf_memory (mems[i]))
750*4882a593Smuzhiyun       return FALSE;
751*4882a593Smuzhiyun   }
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun   kmsmem = (GstKMSMemory *) gst_kms_allocator_get_cached (mems[0]);
754*4882a593Smuzhiyun   if (kmsmem) {
755*4882a593Smuzhiyun     GST_LOG_OBJECT (self, "found KMS mem %p in DMABuf mem %p with fb id = %d",
756*4882a593Smuzhiyun         kmsmem, mems[0], kmsmem->fb_id);
757*4882a593Smuzhiyun     goto wrap_mem;
758*4882a593Smuzhiyun   }
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun   for (i = 0; i < n_planes; i++)
761*4882a593Smuzhiyun     prime_fds[i] = gst_dmabuf_memory_get_fd (mems[i]);
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun   GST_LOG_OBJECT (self, "found these prime ids: %d, %d, %d, %d", prime_fds[0],
764*4882a593Smuzhiyun       prime_fds[1], prime_fds[2], prime_fds[3]);
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun   kmsmem = gst_kms_allocator_dmabuf_import (self->allocator,
767*4882a593Smuzhiyun       prime_fds, n_planes, mems_skip, &self->vinfo);
768*4882a593Smuzhiyun   if (!kmsmem)
769*4882a593Smuzhiyun     return FALSE;
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun   GST_LOG_OBJECT (self, "setting KMS mem %p to DMABuf mem %p with fb id = %d",
772*4882a593Smuzhiyun       kmsmem, mems[0], kmsmem->fb_id);
773*4882a593Smuzhiyun   gst_kms_allocator_cache (self->allocator, mems[0], GST_MEMORY_CAST (kmsmem));
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun wrap_mem:
776*4882a593Smuzhiyun   *outbuf = gst_buffer_new ();
777*4882a593Smuzhiyun   if (!*outbuf)
778*4882a593Smuzhiyun     return FALSE;
779*4882a593Smuzhiyun   gst_buffer_append_memory (*outbuf, gst_memory_ref (GST_MEMORY_CAST (kmsmem)));
780*4882a593Smuzhiyun   gst_buffer_add_parent_buffer_meta (*outbuf, inbuf);
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun   return TRUE;
783*4882a593Smuzhiyun }
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun static GstBuffer *
gst_kms_sink_copy_to_dumb_buffer(GstRkXImageSink * self,GstBuffer * inbuf)786*4882a593Smuzhiyun gst_kms_sink_copy_to_dumb_buffer (GstRkXImageSink * self, GstBuffer * inbuf)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun   GstFlowReturn ret;
789*4882a593Smuzhiyun   GstVideoFrame inframe, outframe;
790*4882a593Smuzhiyun   gboolean success;
791*4882a593Smuzhiyun   GstBuffer *buf = NULL;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun   if (GST_VIDEO_INFO_IS_AFBC (&self->vinfo)) {
794*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "unable to copy AFBC");
795*4882a593Smuzhiyun     return NULL;
796*4882a593Smuzhiyun   }
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun   if (!gst_buffer_pool_set_active (self->pool, TRUE))
799*4882a593Smuzhiyun     goto activate_pool_failed;
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun   ret = gst_buffer_pool_acquire_buffer (self->pool, &buf, NULL);
802*4882a593Smuzhiyun   if (ret != GST_FLOW_OK)
803*4882a593Smuzhiyun     goto create_buffer_failed;
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun   if (!gst_video_frame_map (&inframe, &self->vinfo, inbuf, GST_MAP_READ))
806*4882a593Smuzhiyun     goto error_map_src_buffer;
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun   if (!gst_video_frame_map (&outframe, &self->vinfo, buf, GST_MAP_WRITE))
809*4882a593Smuzhiyun     goto error_map_dst_buffer;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun   success = gst_video_frame_copy (&outframe, &inframe);
812*4882a593Smuzhiyun   gst_video_frame_unmap (&outframe);
813*4882a593Smuzhiyun   gst_video_frame_unmap (&inframe);
814*4882a593Smuzhiyun   if (!success)
815*4882a593Smuzhiyun     goto error_copy_buffer;
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun   return buf;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun bail:
820*4882a593Smuzhiyun   {
821*4882a593Smuzhiyun     if (buf)
822*4882a593Smuzhiyun       gst_buffer_unref (buf);
823*4882a593Smuzhiyun     return NULL;
824*4882a593Smuzhiyun   }
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun   /* ERRORS */
827*4882a593Smuzhiyun activate_pool_failed:
828*4882a593Smuzhiyun   {
829*4882a593Smuzhiyun     GST_ELEMENT_ERROR (self, STREAM, FAILED, ("failed to activate buffer pool"),
830*4882a593Smuzhiyun         ("failed to activate buffer pool"));
831*4882a593Smuzhiyun     return NULL;
832*4882a593Smuzhiyun   }
833*4882a593Smuzhiyun create_buffer_failed:
834*4882a593Smuzhiyun   {
835*4882a593Smuzhiyun     GST_ELEMENT_ERROR (self, STREAM, FAILED, ("allocation failed"),
836*4882a593Smuzhiyun         ("failed to create buffer"));
837*4882a593Smuzhiyun     return NULL;
838*4882a593Smuzhiyun   }
839*4882a593Smuzhiyun error_copy_buffer:
840*4882a593Smuzhiyun   {
841*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "failed to upload buffer");
842*4882a593Smuzhiyun     goto bail;
843*4882a593Smuzhiyun   }
844*4882a593Smuzhiyun error_map_dst_buffer:
845*4882a593Smuzhiyun   {
846*4882a593Smuzhiyun     gst_video_frame_unmap (&inframe);
847*4882a593Smuzhiyun     /* fall-through */
848*4882a593Smuzhiyun   }
849*4882a593Smuzhiyun error_map_src_buffer:
850*4882a593Smuzhiyun   {
851*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "failed to map buffer");
852*4882a593Smuzhiyun     goto bail;
853*4882a593Smuzhiyun   }
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun static GstBuffer *
gst_kms_sink_get_input_buffer(GstRkXImageSink * self,GstBuffer * inbuf)857*4882a593Smuzhiyun gst_kms_sink_get_input_buffer (GstRkXImageSink * self, GstBuffer * inbuf)
858*4882a593Smuzhiyun {
859*4882a593Smuzhiyun   GstMemory *mem;
860*4882a593Smuzhiyun   GstBuffer *buf = NULL;
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun   mem = gst_buffer_peek_memory (inbuf, 0);
863*4882a593Smuzhiyun   if (!mem)
864*4882a593Smuzhiyun     return NULL;
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun   if (gst_is_kms_memory (mem))
867*4882a593Smuzhiyun     return gst_buffer_ref (inbuf);
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun   if (gst_kms_sink_import_dmabuf (self, inbuf, &buf))
870*4882a593Smuzhiyun     goto done;
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun   buf = gst_kms_sink_copy_to_dumb_buffer (self, inbuf);
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun done:
875*4882a593Smuzhiyun   /* Copy all the non-memory related metas, this way CropMeta will be
876*4882a593Smuzhiyun    * available upon GstVideoOverlay::expose calls. */
877*4882a593Smuzhiyun   if (buf)
878*4882a593Smuzhiyun     gst_buffer_copy_into (buf, inbuf, GST_BUFFER_COPY_METADATA, 0, -1);
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun   return buf;
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun static void
sync_handler(gint fd,guint frame,guint sec,guint usec,gpointer data)884*4882a593Smuzhiyun sync_handler (gint fd, guint frame, guint sec, guint usec, gpointer data)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun   gboolean *waiting;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun   waiting = data;
889*4882a593Smuzhiyun   *waiting = FALSE;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun static gboolean
gst_kms_sink_sync(GstRkXImageSink * self)893*4882a593Smuzhiyun gst_kms_sink_sync (GstRkXImageSink * self)
894*4882a593Smuzhiyun {
895*4882a593Smuzhiyun   gint ret;
896*4882a593Smuzhiyun   gboolean waiting;
897*4882a593Smuzhiyun   drmEventContext evctxt = {
898*4882a593Smuzhiyun     .version = DRM_EVENT_CONTEXT_VERSION,
899*4882a593Smuzhiyun     .vblank_handler = sync_handler,
900*4882a593Smuzhiyun   };
901*4882a593Smuzhiyun   drmVBlank vbl = {
902*4882a593Smuzhiyun     .request = {
903*4882a593Smuzhiyun           .type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
904*4882a593Smuzhiyun           .sequence = 1,
905*4882a593Smuzhiyun           .signal = (gulong) & waiting,
906*4882a593Smuzhiyun         },
907*4882a593Smuzhiyun   };
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun   if (self->pipe == 1)
910*4882a593Smuzhiyun     vbl.request.type |= DRM_VBLANK_SECONDARY;
911*4882a593Smuzhiyun   else if (self->pipe > 1)
912*4882a593Smuzhiyun     vbl.request.type |= self->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun   waiting = TRUE;
915*4882a593Smuzhiyun   ret = drmWaitVBlank (self->fd, &vbl);
916*4882a593Smuzhiyun   if (ret)
917*4882a593Smuzhiyun     goto vblank_failed;
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun   while (waiting) {
920*4882a593Smuzhiyun     do {
921*4882a593Smuzhiyun       ret = gst_poll_wait (self->poll, 3 * GST_SECOND);
922*4882a593Smuzhiyun     } while (ret == -1 && (errno == EAGAIN || errno == EINTR));
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun     ret = drmHandleEvent (self->fd, &evctxt);
925*4882a593Smuzhiyun     if (ret)
926*4882a593Smuzhiyun       goto event_failed;
927*4882a593Smuzhiyun   }
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun   return TRUE;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun   /* ERRORS */
932*4882a593Smuzhiyun vblank_failed:
933*4882a593Smuzhiyun   {
934*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "drmWaitVBlank failed: %s (%d)",
935*4882a593Smuzhiyun         g_strerror (errno), errno);
936*4882a593Smuzhiyun     return FALSE;
937*4882a593Smuzhiyun   }
938*4882a593Smuzhiyun event_failed:
939*4882a593Smuzhiyun   {
940*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "drmHandleEvent failed: %s (%d)",
941*4882a593Smuzhiyun         g_strerror (errno), errno);
942*4882a593Smuzhiyun     return FALSE;
943*4882a593Smuzhiyun   }
944*4882a593Smuzhiyun }
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun static void
gst_kms_sink_drain(GstRkXImageSink * self)947*4882a593Smuzhiyun gst_kms_sink_drain (GstRkXImageSink * self)
948*4882a593Smuzhiyun {
949*4882a593Smuzhiyun   GstParentBufferMeta *parent_meta;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "draining");
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun   if (!self->last_buffer)
954*4882a593Smuzhiyun     return;
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun   /* We only need to return the last_buffer if it depends on upstream buffer.
957*4882a593Smuzhiyun    * In this case, the last_buffer will have a GstParentBufferMeta set. */
958*4882a593Smuzhiyun   parent_meta = gst_buffer_get_parent_buffer_meta (self->last_buffer);
959*4882a593Smuzhiyun   if (parent_meta) {
960*4882a593Smuzhiyun     GstBuffer *dumb_buf;
961*4882a593Smuzhiyun     dumb_buf = gst_kms_sink_copy_to_dumb_buffer (self, parent_meta->buffer);
962*4882a593Smuzhiyun     if (!dumb_buf)
963*4882a593Smuzhiyun       dumb_buf = gst_buffer_ref (self->last_buffer);
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun     gst_kms_allocator_clear_cache (self->allocator);
966*4882a593Smuzhiyun     gst_x_image_sink_show_frame (GST_VIDEO_SINK (self), dumb_buf);
967*4882a593Smuzhiyun     gst_buffer_unref (dumb_buf);
968*4882a593Smuzhiyun   }
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun static gboolean
gst_kms_sink_query(GstBaseSink * bsink,GstQuery * query)972*4882a593Smuzhiyun gst_kms_sink_query (GstBaseSink * bsink, GstQuery * query)
973*4882a593Smuzhiyun {
974*4882a593Smuzhiyun   GstRkXImageSink *self = GST_X_IMAGE_SINK (bsink);
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun   switch (GST_QUERY_TYPE (query)) {
977*4882a593Smuzhiyun     case GST_QUERY_ALLOCATION:
978*4882a593Smuzhiyun     case GST_QUERY_DRAIN:
979*4882a593Smuzhiyun     {
980*4882a593Smuzhiyun       gst_kms_sink_drain (self);
981*4882a593Smuzhiyun       break;
982*4882a593Smuzhiyun     }
983*4882a593Smuzhiyun     default:
984*4882a593Smuzhiyun       break;
985*4882a593Smuzhiyun   }
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun   return GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun /*ximagesink*/
991*4882a593Smuzhiyun static gboolean
xwindow_calculate_display_ratio(GstRkXImageSink * self,int * x,int * y,gint * window_width,gint * window_height)992*4882a593Smuzhiyun xwindow_calculate_display_ratio (GstRkXImageSink * self, int *x, int *y,
993*4882a593Smuzhiyun     gint * window_width, gint * window_height)
994*4882a593Smuzhiyun {
995*4882a593Smuzhiyun   guint dar_n, dar_d;
996*4882a593Smuzhiyun   guint video_par_n, video_par_d;
997*4882a593Smuzhiyun   guint dpy_par_n, dpy_par_d;
998*4882a593Smuzhiyun   gint video_width, video_height;
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun   video_width = GST_VIDEO_INFO_WIDTH (&self->vinfo);
1001*4882a593Smuzhiyun   video_height = GST_VIDEO_INFO_HEIGHT (&self->vinfo);
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun   video_par_n = self->par_n;
1004*4882a593Smuzhiyun   video_par_d = self->par_d;
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun   if (self->keep_aspect) {
1007*4882a593Smuzhiyun     *window_width = video_width;
1008*4882a593Smuzhiyun     *window_height = video_height;
1009*4882a593Smuzhiyun     goto out;
1010*4882a593Smuzhiyun   }
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun   gst_video_calculate_device_ratio (self->hdisplay, self->vdisplay,
1013*4882a593Smuzhiyun       self->mm_width, self->mm_height, &dpy_par_n, &dpy_par_d);
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun   if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, video_width,
1016*4882a593Smuzhiyun           video_height, video_par_n, video_par_d, dpy_par_n, dpy_par_d))
1017*4882a593Smuzhiyun     return FALSE;
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "video calculated display ratio: %d/%d", dar_n,
1020*4882a593Smuzhiyun       dar_d);
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun   /* now find a width x height that respects this display ratio.
1023*4882a593Smuzhiyun    * prefer those that have one of w/h the same as the incoming video
1024*4882a593Smuzhiyun    * using wd / hd = dar_n / dar_d */
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun   /* start with same height, because of interlaced video */
1027*4882a593Smuzhiyun   /* check hd / dar_d is an integer scale factor, and scale wd with the PAR */
1028*4882a593Smuzhiyun   video_width = gst_util_uint64_scale_int (self->xwindow->height, dar_n, dar_d);
1029*4882a593Smuzhiyun   video_height = gst_util_uint64_scale_int (self->xwindow->width, dar_d, dar_n);
1030*4882a593Smuzhiyun   if (video_width < *window_width) {
1031*4882a593Smuzhiyun     *x += (self->xwindow->width - video_width) / 2;
1032*4882a593Smuzhiyun     *window_width = video_width;
1033*4882a593Smuzhiyun     *window_height = self->xwindow->height;
1034*4882a593Smuzhiyun   } else {
1035*4882a593Smuzhiyun     *y += (self->xwindow->height - video_height) / 2;
1036*4882a593Smuzhiyun     *window_height = video_height;
1037*4882a593Smuzhiyun     *window_width = self->xwindow->width;
1038*4882a593Smuzhiyun   }
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun out:
1041*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "scaling to %dx%d", *window_width, *window_height);
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun   return TRUE;
1044*4882a593Smuzhiyun }
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun /* X11 stuff */
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun static gboolean
xwindow_get_window_position(GstRkXImageSink * ximagesink,int * x,int * y)1049*4882a593Smuzhiyun xwindow_get_window_position (GstRkXImageSink * ximagesink, int *x, int *y)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun   XWindowAttributes attr;
1052*4882a593Smuzhiyun   Window child;
1053*4882a593Smuzhiyun   int tmp_x, tmp_y;
1054*4882a593Smuzhiyun   static int last_x = 0, last_y = 0;
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun   if (x == NULL || y == NULL) {
1057*4882a593Smuzhiyun     x = &tmp_x;
1058*4882a593Smuzhiyun     y = &tmp_y;
1059*4882a593Smuzhiyun   }
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun   XGetWindowAttributes (ximagesink->xcontext->disp,
1062*4882a593Smuzhiyun       ximagesink->xwindow->win, &attr);
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun   XTranslateCoordinates (ximagesink->xcontext->disp, ximagesink->xwindow->win,
1065*4882a593Smuzhiyun       ximagesink->xcontext->root, 0, 0, x, y, &child);
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun   if (last_x != *x || last_y != *y) {
1068*4882a593Smuzhiyun     last_x = *x;
1069*4882a593Smuzhiyun     last_y = *y;
1070*4882a593Smuzhiyun     /* moved */
1071*4882a593Smuzhiyun     return TRUE;
1072*4882a593Smuzhiyun   }
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun   return FALSE;
1075*4882a593Smuzhiyun }
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun static void
xwindow_get_render_rectangle(GstRkXImageSink * ximagesink,gint * x,gint * y,gint * width,gint * height)1078*4882a593Smuzhiyun xwindow_get_render_rectangle (GstRkXImageSink * ximagesink,
1079*4882a593Smuzhiyun     gint * x, gint * y, gint * width, gint * height)
1080*4882a593Smuzhiyun {
1081*4882a593Smuzhiyun   if (ximagesink->save_rect.w != 0 && ximagesink->save_rect.h != 0) {
1082*4882a593Smuzhiyun     *width = ximagesink->save_rect.w;
1083*4882a593Smuzhiyun     *height = ximagesink->save_rect.h;
1084*4882a593Smuzhiyun     *x += ximagesink->save_rect.x;
1085*4882a593Smuzhiyun     *y += ximagesink->save_rect.y;
1086*4882a593Smuzhiyun   }
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun static void
gst_x_image_sink_xwindow_fill_key(GstRkXImageSink * ximagesink,GstXWindow * xwindow,guint32 color)1090*4882a593Smuzhiyun gst_x_image_sink_xwindow_fill_key (GstRkXImageSink * ximagesink,
1091*4882a593Smuzhiyun     GstXWindow * xwindow, guint32 color)
1092*4882a593Smuzhiyun {
1093*4882a593Smuzhiyun   XSetForeground (ximagesink->xcontext->disp, xwindow->gc, color);
1094*4882a593Smuzhiyun   XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc,
1095*4882a593Smuzhiyun       ximagesink->clip_rect.x, ximagesink->clip_rect.y,
1096*4882a593Smuzhiyun       ximagesink->clip_rect.x + ximagesink->clip_rect.w,
1097*4882a593Smuzhiyun       ximagesink->clip_rect.y + ximagesink->clip_rect.h);
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun /* We are called with the x_lock taken */
1101*4882a593Smuzhiyun static void
gst_x_image_sink_xwindow_draw_borders(GstRkXImageSink * ximagesink,GstXWindow * xwindow,GstVideoRectangle rect)1102*4882a593Smuzhiyun gst_x_image_sink_xwindow_draw_borders (GstRkXImageSink * ximagesink,
1103*4882a593Smuzhiyun     GstXWindow * xwindow, GstVideoRectangle rect)
1104*4882a593Smuzhiyun {
1105*4882a593Smuzhiyun   g_return_if_fail (GST_IS_X_IMAGE_SINK (ximagesink));
1106*4882a593Smuzhiyun   g_return_if_fail (xwindow != NULL);
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun   XSetForeground (ximagesink->xcontext->disp, xwindow->gc,
1109*4882a593Smuzhiyun       ximagesink->xcontext->black);
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun   /* Left border */
1112*4882a593Smuzhiyun   if (rect.x > 0) {
1113*4882a593Smuzhiyun     XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc,
1114*4882a593Smuzhiyun         0, 0, rect.x, xwindow->height);
1115*4882a593Smuzhiyun   }
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun   /* Right border */
1118*4882a593Smuzhiyun   if ((rect.x + rect.w) < xwindow->width) {
1119*4882a593Smuzhiyun     XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc,
1120*4882a593Smuzhiyun         rect.x + rect.w, 0, xwindow->width, xwindow->height);
1121*4882a593Smuzhiyun   }
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun   /* Top border */
1124*4882a593Smuzhiyun   if (rect.y > 0) {
1125*4882a593Smuzhiyun     XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc,
1126*4882a593Smuzhiyun         0, 0, xwindow->width, rect.y);
1127*4882a593Smuzhiyun   }
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun   /* Bottom border */
1130*4882a593Smuzhiyun   if ((rect.y + rect.h) < xwindow->height) {
1131*4882a593Smuzhiyun     XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc,
1132*4882a593Smuzhiyun         0, rect.y + rect.h, xwindow->width, xwindow->height);
1133*4882a593Smuzhiyun   }
1134*4882a593Smuzhiyun }
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun /* This function puts a GstXImageBuffer on a GstRkXImageSink's window */
1137*4882a593Smuzhiyun static gboolean
gst_x_image_sink_ximage_put(GstRkXImageSink * ximagesink,GstBuffer * buf)1138*4882a593Smuzhiyun gst_x_image_sink_ximage_put (GstRkXImageSink * ximagesink, GstBuffer * buf)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun   GstVideoCropMeta *crop;
1141*4882a593Smuzhiyun   GstVideoRectangle src = { 0, };
1142*4882a593Smuzhiyun   GstVideoRectangle result = { 0, };
1143*4882a593Smuzhiyun   GstBuffer *buffer = NULL;
1144*4882a593Smuzhiyun   gboolean draw_border = FALSE;
1145*4882a593Smuzhiyun   gboolean res = FALSE;
1146*4882a593Smuzhiyun   gboolean expose = buf == NULL;
1147*4882a593Smuzhiyun   guint32 fb_id;
1148*4882a593Smuzhiyun   gint ret;
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun   /* We take the flow_lock. If expose is in there we don't want to run
1151*4882a593Smuzhiyun      concurrently from the data flow thread */
1152*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->flow_lock);
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun   if (G_UNLIKELY (ximagesink->xwindow == NULL)) {
1155*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
1156*4882a593Smuzhiyun     return FALSE;
1157*4882a593Smuzhiyun   }
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun   /* Draw borders when displaying the first frame. After this
1160*4882a593Smuzhiyun      draw borders only on expose event or caps change (ximagesink->draw_border = TRUE). */
1161*4882a593Smuzhiyun   if (expose || !ximagesink->last_buffer || ximagesink->draw_border)
1162*4882a593Smuzhiyun     draw_border = TRUE;
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun   if (buf)
1165*4882a593Smuzhiyun     buffer = gst_kms_sink_get_input_buffer (ximagesink, buf);
1166*4882a593Smuzhiyun   else if (ximagesink->last_buffer)
1167*4882a593Smuzhiyun     buffer = gst_buffer_ref (ximagesink->last_buffer);
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun   /* Make sure buf is not used accidentally */
1170*4882a593Smuzhiyun   buf = NULL;
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun   if (!buffer)
1173*4882a593Smuzhiyun     goto buffer_invalid;
1174*4882a593Smuzhiyun   fb_id = gst_kms_memory_get_fb_id (gst_buffer_peek_memory (buffer, 0));
1175*4882a593Smuzhiyun   if (fb_id == 0)
1176*4882a593Smuzhiyun     goto buffer_invalid;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun   GST_TRACE_OBJECT (ximagesink, "displaying fb %d", fb_id);
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun   crop = gst_buffer_get_video_crop_meta (buffer);
1181*4882a593Smuzhiyun   if (crop) {
1182*4882a593Smuzhiyun     src.x = crop->x;
1183*4882a593Smuzhiyun     src.y = crop->y;
1184*4882a593Smuzhiyun     src.w = crop->width;
1185*4882a593Smuzhiyun     src.h = crop->height;
1186*4882a593Smuzhiyun     GST_LOG_OBJECT (ximagesink,
1187*4882a593Smuzhiyun         "crop %dx%d-%dx%d", crop->x, crop->y, crop->width, crop->height);
1188*4882a593Smuzhiyun   } else {
1189*4882a593Smuzhiyun     src.w = GST_VIDEO_SINK_WIDTH (ximagesink);
1190*4882a593Smuzhiyun     src.h = GST_VIDEO_SINK_HEIGHT (ximagesink);
1191*4882a593Smuzhiyun   }
1192*4882a593Smuzhiyun   result.w = ximagesink->xwindow->width;
1193*4882a593Smuzhiyun   result.h = ximagesink->xwindow->height;
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun   /* Fill color key when clip rect changed */
1198*4882a593Smuzhiyun   if (draw_border || !RECT_EQUAL (ximagesink->clip_rect, result)) {
1199*4882a593Smuzhiyun     ximagesink->clip_rect = result;
1200*4882a593Smuzhiyun     gst_x_image_sink_xwindow_fill_key (ximagesink,
1201*4882a593Smuzhiyun         ximagesink->xwindow, RKXIMAGE_COLOR_KEY);
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun     /* Do an extra repaint when handing expose */
1204*4882a593Smuzhiyun     if (expose)
1205*4882a593Smuzhiyun       memset (&ximagesink->clip_rect, 0, sizeof (GstVideoRectangle));
1206*4882a593Smuzhiyun   }
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun   if (draw_border) {
1209*4882a593Smuzhiyun     gst_x_image_sink_xwindow_draw_borders (ximagesink, ximagesink->xwindow,
1210*4882a593Smuzhiyun         result);
1211*4882a593Smuzhiyun     ximagesink->draw_border = FALSE;
1212*4882a593Smuzhiyun   }
1213*4882a593Smuzhiyun 
1214*4882a593Smuzhiyun   xwindow_get_window_position (ximagesink, &result.x, &result.y);
1215*4882a593Smuzhiyun 
1216*4882a593Smuzhiyun   xwindow_get_render_rectangle (ximagesink, &result.x, &result.y, &result.w,
1217*4882a593Smuzhiyun       &result.h);
1218*4882a593Smuzhiyun   xwindow_calculate_display_ratio (ximagesink, &result.x, &result.y, &result.w,
1219*4882a593Smuzhiyun       &result.h);
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun   if (GST_VIDEO_INFO_IS_AFBC (&ximagesink->vinfo))
1222*4882a593Smuzhiyun     /* The AFBC's width should align to 4 */
1223*4882a593Smuzhiyun     src.w &= ~3;
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun   GST_TRACE_OBJECT (ximagesink,
1226*4882a593Smuzhiyun       "drmModeSetPlane at (%i,%i) %ix%i sourcing at (%i,%i) %ix%i",
1227*4882a593Smuzhiyun       result.x, result.y, result.w, result.h, src.x, src.y, src.w, src.h);
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun   ret = drmModeSetPlane (ximagesink->fd, ximagesink->plane_id,
1230*4882a593Smuzhiyun       ximagesink->crtc_id, fb_id, 0, result.x, result.y, result.w, result.h,
1231*4882a593Smuzhiyun       /* source/cropping coordinates are given in Q16 */
1232*4882a593Smuzhiyun       src.x << 16, src.y << 16, src.w << 16, src.h << 16);
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun   if (ret) {
1235*4882a593Smuzhiyun     GST_ERROR_OBJECT (ximagesink, "drmModesetplane failed: %d", ret);
1236*4882a593Smuzhiyun     goto out;
1237*4882a593Smuzhiyun   }
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun   /* HACK: Disable vsync might cause tearing */
1241*4882a593Smuzhiyun   if (!g_getenv ("KMSSINK_DISABLE_VSYNC"))
1242*4882a593Smuzhiyun   /* Wait for the previous frame to complete redraw */
1243*4882a593Smuzhiyun   if (!gst_kms_sink_sync (ximagesink))
1244*4882a593Smuzhiyun     goto out;
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun   if (buffer != ximagesink->last_buffer)
1247*4882a593Smuzhiyun     gst_buffer_replace (&ximagesink->last_buffer, buffer);
1248*4882a593Smuzhiyun 
1249*4882a593Smuzhiyun   res = TRUE;
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun out:
1252*4882a593Smuzhiyun   if (buffer)
1253*4882a593Smuzhiyun     gst_buffer_unref (buffer);
1254*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1255*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->flow_lock);
1256*4882a593Smuzhiyun   return res;
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun buffer_invalid:
1259*4882a593Smuzhiyun   gst_x_image_sink_xwindow_clear (ximagesink, ximagesink->xwindow);
1260*4882a593Smuzhiyun   if (buffer)
1261*4882a593Smuzhiyun     gst_buffer_unref (buffer);
1262*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->flow_lock);
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun   return TRUE;
1265*4882a593Smuzhiyun }
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun static gboolean
gst_x_image_sink_xwindow_decorate(GstRkXImageSink * ximagesink,GstXWindow * window)1268*4882a593Smuzhiyun gst_x_image_sink_xwindow_decorate (GstRkXImageSink * ximagesink,
1269*4882a593Smuzhiyun     GstXWindow * window)
1270*4882a593Smuzhiyun {
1271*4882a593Smuzhiyun   Atom hints_atom = None;
1272*4882a593Smuzhiyun   MotifWmHints *hints;
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun   g_return_val_if_fail (GST_IS_X_IMAGE_SINK (ximagesink), FALSE);
1275*4882a593Smuzhiyun   g_return_val_if_fail (window != NULL, FALSE);
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun   hints_atom = XInternAtom (ximagesink->xcontext->disp, "_MOTIF_WM_HINTS",
1280*4882a593Smuzhiyun       True);
1281*4882a593Smuzhiyun   if (hints_atom == None) {
1282*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1283*4882a593Smuzhiyun     return FALSE;
1284*4882a593Smuzhiyun   }
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun   hints = g_malloc0 (sizeof (MotifWmHints));
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun   hints->flags |= MWM_HINTS_DECORATIONS;
1289*4882a593Smuzhiyun   hints->decorations = 1 << 0;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun   XChangeProperty (ximagesink->xcontext->disp, window->win,
1292*4882a593Smuzhiyun       hints_atom, hints_atom, 32, PropModeReplace,
1293*4882a593Smuzhiyun       (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun   XSync (ximagesink->xcontext->disp, FALSE);
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun   g_free (hints);
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun   return TRUE;
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun static void
gst_x_image_sink_xwindow_set_title(GstRkXImageSink * ximagesink,GstXWindow * xwindow,const gchar * media_title)1305*4882a593Smuzhiyun gst_x_image_sink_xwindow_set_title (GstRkXImageSink * ximagesink,
1306*4882a593Smuzhiyun     GstXWindow * xwindow, const gchar * media_title)
1307*4882a593Smuzhiyun {
1308*4882a593Smuzhiyun   if (media_title) {
1309*4882a593Smuzhiyun     g_free (ximagesink->media_title);
1310*4882a593Smuzhiyun     ximagesink->media_title = g_strdup (media_title);
1311*4882a593Smuzhiyun   }
1312*4882a593Smuzhiyun   if (xwindow) {
1313*4882a593Smuzhiyun     /* we have a window */
1314*4882a593Smuzhiyun     if (xwindow->internal) {
1315*4882a593Smuzhiyun       XTextProperty xproperty;
1316*4882a593Smuzhiyun       XClassHint *hint = XAllocClassHint ();
1317*4882a593Smuzhiyun       const gchar *app_name;
1318*4882a593Smuzhiyun       const gchar *title = NULL;
1319*4882a593Smuzhiyun       gchar *title_mem = NULL;
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun       /* set application name as a title */
1322*4882a593Smuzhiyun       app_name = g_get_application_name ();
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun       if (app_name && ximagesink->media_title) {
1325*4882a593Smuzhiyun         title = title_mem = g_strconcat (ximagesink->media_title, " : ",
1326*4882a593Smuzhiyun             app_name, NULL);
1327*4882a593Smuzhiyun       } else if (app_name) {
1328*4882a593Smuzhiyun         title = app_name;
1329*4882a593Smuzhiyun       } else if (ximagesink->media_title) {
1330*4882a593Smuzhiyun         title = ximagesink->media_title;
1331*4882a593Smuzhiyun       }
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun       if (title) {
1334*4882a593Smuzhiyun         if ((XStringListToTextProperty (((char **) &title), 1,
1335*4882a593Smuzhiyun                     &xproperty)) != 0) {
1336*4882a593Smuzhiyun           XSetWMName (ximagesink->xcontext->disp, xwindow->win, &xproperty);
1337*4882a593Smuzhiyun           XFree (xproperty.value);
1338*4882a593Smuzhiyun         }
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun         g_free (title_mem);
1341*4882a593Smuzhiyun       }
1342*4882a593Smuzhiyun 
1343*4882a593Smuzhiyun       if (hint) {
1344*4882a593Smuzhiyun         hint->res_name = (char *) app_name;
1345*4882a593Smuzhiyun         hint->res_class = (char *) "GStreamer";
1346*4882a593Smuzhiyun         XSetClassHint (ximagesink->xcontext->disp, xwindow->win, hint);
1347*4882a593Smuzhiyun       }
1348*4882a593Smuzhiyun       XFree (hint);
1349*4882a593Smuzhiyun     }
1350*4882a593Smuzhiyun   }
1351*4882a593Smuzhiyun }
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun /* This function handles a GstXWindow creation */
1354*4882a593Smuzhiyun static GstXWindow *
gst_x_image_sink_xwindow_new(GstRkXImageSink * ximagesink,gint width,gint height)1355*4882a593Smuzhiyun gst_x_image_sink_xwindow_new (GstRkXImageSink * ximagesink, gint width,
1356*4882a593Smuzhiyun     gint height)
1357*4882a593Smuzhiyun {
1358*4882a593Smuzhiyun   GstXWindow *xwindow = NULL;
1359*4882a593Smuzhiyun   XGCValues values;
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun   g_return_val_if_fail (GST_IS_X_IMAGE_SINK (ximagesink), NULL);
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun   xwindow = g_new0 (GstXWindow, 1);
1364*4882a593Smuzhiyun 
1365*4882a593Smuzhiyun   xwindow->width = width;
1366*4882a593Smuzhiyun   xwindow->height = height;
1367*4882a593Smuzhiyun   xwindow->internal = TRUE;
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun   xwindow->win = XCreateSimpleWindow (ximagesink->xcontext->disp,
1372*4882a593Smuzhiyun       ximagesink->xcontext->root,
1373*4882a593Smuzhiyun       0, 0, width, height, 0, 0, ximagesink->xcontext->black);
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun   /* We have to do that to prevent X from redrawing the background on
1376*4882a593Smuzhiyun      ConfigureNotify. This takes away flickering of video when resizing. */
1377*4882a593Smuzhiyun   XSetWindowBackgroundPixmap (ximagesink->xcontext->disp, xwindow->win, None);
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun   /* set application name as a title */
1380*4882a593Smuzhiyun   gst_x_image_sink_xwindow_set_title (ximagesink, xwindow, NULL);
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun   if (ximagesink->handle_events) {
1383*4882a593Smuzhiyun     Atom wm_delete;
1384*4882a593Smuzhiyun 
1385*4882a593Smuzhiyun     XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask |
1386*4882a593Smuzhiyun         StructureNotifyMask | PointerMotionMask | KeyPressMask |
1387*4882a593Smuzhiyun         KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun     /* Tell the window manager we'd like delete client messages instead of
1390*4882a593Smuzhiyun      * being killed */
1391*4882a593Smuzhiyun     wm_delete = XInternAtom (ximagesink->xcontext->disp,
1392*4882a593Smuzhiyun         "WM_DELETE_WINDOW", False);
1393*4882a593Smuzhiyun     (void) XSetWMProtocols (ximagesink->xcontext->disp, xwindow->win,
1394*4882a593Smuzhiyun         &wm_delete, 1);
1395*4882a593Smuzhiyun   }
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun   xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win,
1398*4882a593Smuzhiyun       0, &values);
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun   XMapRaised (ximagesink->xcontext->disp, xwindow->win);
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun   XSync (ximagesink->xcontext->disp, FALSE);
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1405*4882a593Smuzhiyun 
1406*4882a593Smuzhiyun   gst_x_image_sink_xwindow_decorate (ximagesink, xwindow);
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun   gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (ximagesink),
1409*4882a593Smuzhiyun       xwindow->win);
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun   return xwindow;
1412*4882a593Smuzhiyun }
1413*4882a593Smuzhiyun 
1414*4882a593Smuzhiyun /* This function destroys a GstXWindow */
1415*4882a593Smuzhiyun static void
gst_x_image_sink_xwindow_destroy(GstRkXImageSink * ximagesink,GstXWindow * xwindow)1416*4882a593Smuzhiyun gst_x_image_sink_xwindow_destroy (GstRkXImageSink * ximagesink,
1417*4882a593Smuzhiyun     GstXWindow * xwindow)
1418*4882a593Smuzhiyun {
1419*4882a593Smuzhiyun   g_return_if_fail (xwindow != NULL);
1420*4882a593Smuzhiyun   g_return_if_fail (GST_IS_X_IMAGE_SINK (ximagesink));
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun   /* clean screen */
1425*4882a593Smuzhiyun   if (ximagesink->last_fb_id) {
1426*4882a593Smuzhiyun     drmModeRmFB (ximagesink->fd, ximagesink->last_fb_id);
1427*4882a593Smuzhiyun     ximagesink->last_fb_id = 0;
1428*4882a593Smuzhiyun   }
1429*4882a593Smuzhiyun 
1430*4882a593Smuzhiyun   /* If we did not create that window we just free the GC and let it live */
1431*4882a593Smuzhiyun   if (xwindow->internal)
1432*4882a593Smuzhiyun     XDestroyWindow (ximagesink->xcontext->disp, xwindow->win);
1433*4882a593Smuzhiyun   else
1434*4882a593Smuzhiyun     XSelectInput (ximagesink->xcontext->disp, xwindow->win, 0);
1435*4882a593Smuzhiyun 
1436*4882a593Smuzhiyun   XFreeGC (ximagesink->xcontext->disp, xwindow->gc);
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun   XSync (ximagesink->xcontext->disp, FALSE);
1439*4882a593Smuzhiyun 
1440*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun   g_free (xwindow);
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun 
1445*4882a593Smuzhiyun static void
gst_x_image_sink_xwindow_update_geometry(GstRkXImageSink * ximagesink)1446*4882a593Smuzhiyun gst_x_image_sink_xwindow_update_geometry (GstRkXImageSink * ximagesink)
1447*4882a593Smuzhiyun {
1448*4882a593Smuzhiyun   XWindowAttributes attr;
1449*4882a593Smuzhiyun   gboolean reconfigure;
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun   g_return_if_fail (GST_IS_X_IMAGE_SINK (ximagesink));
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun   /* Update the window geometry */
1454*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1455*4882a593Smuzhiyun   if (G_UNLIKELY (ximagesink->xwindow == NULL)) {
1456*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1457*4882a593Smuzhiyun     return;
1458*4882a593Smuzhiyun   }
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun   XGetWindowAttributes (ximagesink->xcontext->disp,
1461*4882a593Smuzhiyun       ximagesink->xwindow->win, &attr);
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun   /* Check if we would suggest a different width/height now */
1464*4882a593Smuzhiyun   reconfigure = (ximagesink->xwindow->width != attr.width)
1465*4882a593Smuzhiyun       || (ximagesink->xwindow->height != attr.height);
1466*4882a593Smuzhiyun   ximagesink->xwindow->width = attr.width;
1467*4882a593Smuzhiyun   ximagesink->xwindow->height = attr.height;
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun   if (reconfigure)
1472*4882a593Smuzhiyun     gst_pad_push_event (GST_BASE_SINK (ximagesink)->sinkpad,
1473*4882a593Smuzhiyun         gst_event_new_reconfigure ());
1474*4882a593Smuzhiyun }
1475*4882a593Smuzhiyun 
1476*4882a593Smuzhiyun static void
gst_x_image_sink_xwindow_clear(GstRkXImageSink * ximagesink,GstXWindow * xwindow)1477*4882a593Smuzhiyun gst_x_image_sink_xwindow_clear (GstRkXImageSink * ximagesink,
1478*4882a593Smuzhiyun     GstXWindow * xwindow)
1479*4882a593Smuzhiyun {
1480*4882a593Smuzhiyun   g_return_if_fail (xwindow != NULL);
1481*4882a593Smuzhiyun   g_return_if_fail (GST_IS_X_IMAGE_SINK (ximagesink));
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun   XSetForeground (ximagesink->xcontext->disp, xwindow->gc,
1486*4882a593Smuzhiyun       ximagesink->xcontext->black);
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun   XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc,
1489*4882a593Smuzhiyun       0, 0, xwindow->width, xwindow->height);
1490*4882a593Smuzhiyun 
1491*4882a593Smuzhiyun   /* clean screen */
1492*4882a593Smuzhiyun   if (ximagesink->last_fb_id) {
1493*4882a593Smuzhiyun     drmModeRmFB (ximagesink->fd, ximagesink->last_fb_id);
1494*4882a593Smuzhiyun     ximagesink->last_fb_id = 0;
1495*4882a593Smuzhiyun   }
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1498*4882a593Smuzhiyun }
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun /* This function handles XEvents that might be in the queue. It generates
1501*4882a593Smuzhiyun    GstEvent that will be sent upstream in the pipeline to handle interactivity
1502*4882a593Smuzhiyun    and navigation.*/
1503*4882a593Smuzhiyun static void
gst_x_image_sink_handle_xevents(GstRkXImageSink * ximagesink)1504*4882a593Smuzhiyun gst_x_image_sink_handle_xevents (GstRkXImageSink * ximagesink)
1505*4882a593Smuzhiyun {
1506*4882a593Smuzhiyun   XEvent e;
1507*4882a593Smuzhiyun   guint pointer_x = 0, pointer_y = 0;
1508*4882a593Smuzhiyun   gboolean pointer_moved = FALSE;
1509*4882a593Smuzhiyun   gboolean exposed = FALSE, configured = FALSE;
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun   g_return_if_fail (GST_IS_X_IMAGE_SINK (ximagesink));
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun   /* Then we get all pointer motion events, only the last position is
1514*4882a593Smuzhiyun      interesting. */
1515*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->flow_lock);
1516*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1517*4882a593Smuzhiyun   while (XCheckWindowEvent (ximagesink->xcontext->disp,
1518*4882a593Smuzhiyun           ximagesink->xwindow->win, PointerMotionMask, &e)) {
1519*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1520*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
1521*4882a593Smuzhiyun 
1522*4882a593Smuzhiyun     switch (e.type) {
1523*4882a593Smuzhiyun       case MotionNotify:
1524*4882a593Smuzhiyun         pointer_x = e.xmotion.x;
1525*4882a593Smuzhiyun         pointer_y = e.xmotion.y;
1526*4882a593Smuzhiyun         pointer_moved = TRUE;
1527*4882a593Smuzhiyun         break;
1528*4882a593Smuzhiyun       default:
1529*4882a593Smuzhiyun         break;
1530*4882a593Smuzhiyun     }
1531*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->flow_lock);
1532*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->x_lock);
1533*4882a593Smuzhiyun   }
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun   if (pointer_moved) {
1536*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1537*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun     GST_DEBUG ("ximagesink pointer moved over window at %d,%d",
1540*4882a593Smuzhiyun         pointer_x, pointer_y);
1541*4882a593Smuzhiyun     gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink),
1542*4882a593Smuzhiyun         "mouse-move", 0, pointer_x, pointer_y);
1543*4882a593Smuzhiyun 
1544*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->flow_lock);
1545*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->x_lock);
1546*4882a593Smuzhiyun   }
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun   /* We get all remaining events on our window to throw them upstream */
1549*4882a593Smuzhiyun   while (XCheckWindowEvent (ximagesink->xcontext->disp,
1550*4882a593Smuzhiyun           ximagesink->xwindow->win,
1551*4882a593Smuzhiyun           KeyPressMask | KeyReleaseMask |
1552*4882a593Smuzhiyun           ButtonPressMask | ButtonReleaseMask, &e)) {
1553*4882a593Smuzhiyun     KeySym keysym;
1554*4882a593Smuzhiyun     const char *key_str = NULL;
1555*4882a593Smuzhiyun 
1556*4882a593Smuzhiyun     /* We lock only for the X function call */
1557*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1558*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun     switch (e.type) {
1561*4882a593Smuzhiyun       case ButtonPress:
1562*4882a593Smuzhiyun         /* Mouse button pressed/released over our window. We send upstream
1563*4882a593Smuzhiyun            events for interactivity/navigation */
1564*4882a593Smuzhiyun         GST_DEBUG ("ximagesink button %d pressed over window at %d,%d",
1565*4882a593Smuzhiyun             e.xbutton.button, e.xbutton.x, e.xbutton.x);
1566*4882a593Smuzhiyun         gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink),
1567*4882a593Smuzhiyun             "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1568*4882a593Smuzhiyun         break;
1569*4882a593Smuzhiyun       case ButtonRelease:
1570*4882a593Smuzhiyun         GST_DEBUG ("ximagesink button %d release over window at %d,%d",
1571*4882a593Smuzhiyun             e.xbutton.button, e.xbutton.x, e.xbutton.x);
1572*4882a593Smuzhiyun         gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink),
1573*4882a593Smuzhiyun             "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1574*4882a593Smuzhiyun         break;
1575*4882a593Smuzhiyun       case KeyPress:
1576*4882a593Smuzhiyun       case KeyRelease:
1577*4882a593Smuzhiyun         /* Key pressed/released over our window. We send upstream
1578*4882a593Smuzhiyun            events for interactivity/navigation */
1579*4882a593Smuzhiyun         g_mutex_lock (&ximagesink->x_lock);
1580*4882a593Smuzhiyun         keysym = XkbKeycodeToKeysym (ximagesink->xcontext->disp,
1581*4882a593Smuzhiyun             e.xkey.keycode, 0, 0);
1582*4882a593Smuzhiyun         if (keysym != NoSymbol) {
1583*4882a593Smuzhiyun           key_str = XKeysymToString (keysym);
1584*4882a593Smuzhiyun         } else {
1585*4882a593Smuzhiyun           key_str = "unknown";
1586*4882a593Smuzhiyun         }
1587*4882a593Smuzhiyun         g_mutex_unlock (&ximagesink->x_lock);
1588*4882a593Smuzhiyun         GST_DEBUG_OBJECT (ximagesink,
1589*4882a593Smuzhiyun             "key %d pressed over window at %d,%d (%s)",
1590*4882a593Smuzhiyun             e.xkey.keycode, e.xkey.x, e.xkey.y, key_str);
1591*4882a593Smuzhiyun         gst_navigation_send_key_event (GST_NAVIGATION (ximagesink),
1592*4882a593Smuzhiyun             e.type == KeyPress ? "key-press" : "key-release", key_str);
1593*4882a593Smuzhiyun         break;
1594*4882a593Smuzhiyun       default:
1595*4882a593Smuzhiyun         GST_DEBUG_OBJECT (ximagesink, "ximagesink unhandled X event (%d)",
1596*4882a593Smuzhiyun             e.type);
1597*4882a593Smuzhiyun     }
1598*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->flow_lock);
1599*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->x_lock);
1600*4882a593Smuzhiyun   }
1601*4882a593Smuzhiyun 
1602*4882a593Smuzhiyun   /* Handle Expose */
1603*4882a593Smuzhiyun   while (XCheckWindowEvent (ximagesink->xcontext->disp,
1604*4882a593Smuzhiyun           ximagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
1605*4882a593Smuzhiyun     switch (e.type) {
1606*4882a593Smuzhiyun       case Expose:
1607*4882a593Smuzhiyun         exposed = TRUE;
1608*4882a593Smuzhiyun         break;
1609*4882a593Smuzhiyun       case ConfigureNotify:
1610*4882a593Smuzhiyun         g_mutex_unlock (&ximagesink->x_lock);
1611*4882a593Smuzhiyun         gst_x_image_sink_xwindow_update_geometry (ximagesink);
1612*4882a593Smuzhiyun         g_mutex_lock (&ximagesink->x_lock);
1613*4882a593Smuzhiyun         configured = TRUE;
1614*4882a593Smuzhiyun         break;
1615*4882a593Smuzhiyun       default:
1616*4882a593Smuzhiyun         break;
1617*4882a593Smuzhiyun     }
1618*4882a593Smuzhiyun 
1619*4882a593Smuzhiyun   }
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun   if (ximagesink->handle_expose && (exposed || configured)) {
1622*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1623*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
1624*4882a593Smuzhiyun 
1625*4882a593Smuzhiyun     gst_x_image_sink_expose (GST_VIDEO_OVERLAY (ximagesink));
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->flow_lock);
1628*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->x_lock);
1629*4882a593Smuzhiyun   }
1630*4882a593Smuzhiyun 
1631*4882a593Smuzhiyun   /* Handle Display events */
1632*4882a593Smuzhiyun   while (XPending (ximagesink->xcontext->disp)) {
1633*4882a593Smuzhiyun     XNextEvent (ximagesink->xcontext->disp, &e);
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun     switch (e.type) {
1636*4882a593Smuzhiyun       case ClientMessage:{
1637*4882a593Smuzhiyun         Atom wm_delete;
1638*4882a593Smuzhiyun 
1639*4882a593Smuzhiyun         wm_delete = XInternAtom (ximagesink->xcontext->disp,
1640*4882a593Smuzhiyun             "WM_DELETE_WINDOW", False);
1641*4882a593Smuzhiyun         if (wm_delete == (Atom) e.xclient.data.l[0]) {
1642*4882a593Smuzhiyun           /* Handle window deletion by posting an error on the bus */
1643*4882a593Smuzhiyun           GST_ELEMENT_ERROR (ximagesink, RESOURCE, NOT_FOUND,
1644*4882a593Smuzhiyun               ("Output window was closed"), (NULL));
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun           g_mutex_unlock (&ximagesink->x_lock);
1647*4882a593Smuzhiyun           gst_x_image_sink_xwindow_destroy (ximagesink, ximagesink->xwindow);
1648*4882a593Smuzhiyun           ximagesink->xwindow = NULL;
1649*4882a593Smuzhiyun           g_mutex_lock (&ximagesink->x_lock);
1650*4882a593Smuzhiyun         }
1651*4882a593Smuzhiyun         break;
1652*4882a593Smuzhiyun       }
1653*4882a593Smuzhiyun       default:
1654*4882a593Smuzhiyun         break;
1655*4882a593Smuzhiyun     }
1656*4882a593Smuzhiyun   }
1657*4882a593Smuzhiyun 
1658*4882a593Smuzhiyun   /* Handle DRM display */
1659*4882a593Smuzhiyun   if (ximagesink->paused
1660*4882a593Smuzhiyun       && xwindow_get_window_position (ximagesink, NULL, NULL)) {
1661*4882a593Smuzhiyun     /* if window stop moving, redraw display */
1662*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1663*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun     gst_x_image_sink_expose (GST_VIDEO_OVERLAY (ximagesink));
1666*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->flow_lock);
1667*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->x_lock);
1668*4882a593Smuzhiyun   }
1669*4882a593Smuzhiyun 
1670*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1671*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->flow_lock);
1672*4882a593Smuzhiyun }
1673*4882a593Smuzhiyun 
1674*4882a593Smuzhiyun static gpointer
gst_x_image_sink_event_thread(GstRkXImageSink * ximagesink)1675*4882a593Smuzhiyun gst_x_image_sink_event_thread (GstRkXImageSink * ximagesink)
1676*4882a593Smuzhiyun {
1677*4882a593Smuzhiyun   g_return_val_if_fail (GST_IS_X_IMAGE_SINK (ximagesink), NULL);
1678*4882a593Smuzhiyun 
1679*4882a593Smuzhiyun   GST_OBJECT_LOCK (ximagesink);
1680*4882a593Smuzhiyun   while (ximagesink->running) {
1681*4882a593Smuzhiyun     GST_OBJECT_UNLOCK (ximagesink);
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun     if (ximagesink->xwindow) {
1684*4882a593Smuzhiyun       gst_x_image_sink_handle_xevents (ximagesink);
1685*4882a593Smuzhiyun     }
1686*4882a593Smuzhiyun     /* FIXME: do we want to align this with the framerate or anything else? */
1687*4882a593Smuzhiyun     g_usleep (G_USEC_PER_SEC / 100);
1688*4882a593Smuzhiyun 
1689*4882a593Smuzhiyun     GST_OBJECT_LOCK (ximagesink);
1690*4882a593Smuzhiyun   }
1691*4882a593Smuzhiyun   GST_OBJECT_UNLOCK (ximagesink);
1692*4882a593Smuzhiyun 
1693*4882a593Smuzhiyun   return NULL;
1694*4882a593Smuzhiyun }
1695*4882a593Smuzhiyun 
1696*4882a593Smuzhiyun static void
gst_x_image_sink_manage_event_thread(GstRkXImageSink * ximagesink)1697*4882a593Smuzhiyun gst_x_image_sink_manage_event_thread (GstRkXImageSink * ximagesink)
1698*4882a593Smuzhiyun {
1699*4882a593Smuzhiyun   GThread *thread = NULL;
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun   /* don't start the thread too early */
1702*4882a593Smuzhiyun   if (ximagesink->xcontext == NULL) {
1703*4882a593Smuzhiyun     return;
1704*4882a593Smuzhiyun   }
1705*4882a593Smuzhiyun 
1706*4882a593Smuzhiyun   GST_OBJECT_LOCK (ximagesink);
1707*4882a593Smuzhiyun   if (ximagesink->handle_expose || ximagesink->handle_events) {
1708*4882a593Smuzhiyun     if (!ximagesink->event_thread) {
1709*4882a593Smuzhiyun       /* Setup our event listening thread */
1710*4882a593Smuzhiyun       GST_DEBUG_OBJECT (ximagesink, "run xevent thread, expose %d, events %d",
1711*4882a593Smuzhiyun           ximagesink->handle_expose, ximagesink->handle_events);
1712*4882a593Smuzhiyun       ximagesink->running = TRUE;
1713*4882a593Smuzhiyun       ximagesink->event_thread = g_thread_try_new ("ximagesink-events",
1714*4882a593Smuzhiyun           (GThreadFunc) gst_x_image_sink_event_thread, ximagesink, NULL);
1715*4882a593Smuzhiyun     }
1716*4882a593Smuzhiyun   } else {
1717*4882a593Smuzhiyun     if (ximagesink->event_thread) {
1718*4882a593Smuzhiyun       GST_DEBUG_OBJECT (ximagesink, "stop xevent thread, expose %d, events %d",
1719*4882a593Smuzhiyun           ximagesink->handle_expose, ximagesink->handle_events);
1720*4882a593Smuzhiyun       ximagesink->running = FALSE;
1721*4882a593Smuzhiyun       /* grab thread and mark it as NULL */
1722*4882a593Smuzhiyun       thread = ximagesink->event_thread;
1723*4882a593Smuzhiyun       ximagesink->event_thread = NULL;
1724*4882a593Smuzhiyun     }
1725*4882a593Smuzhiyun   }
1726*4882a593Smuzhiyun   GST_OBJECT_UNLOCK (ximagesink);
1727*4882a593Smuzhiyun 
1728*4882a593Smuzhiyun   /* Wait for our event thread to finish */
1729*4882a593Smuzhiyun   if (thread)
1730*4882a593Smuzhiyun     g_thread_join (thread);
1731*4882a593Smuzhiyun 
1732*4882a593Smuzhiyun }
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun /* This function gets the X Display and global info about it. Everything is
1735*4882a593Smuzhiyun    stored in our object and will be cleaned when the object is disposed. Note
1736*4882a593Smuzhiyun    here that caps for supported format are generated without any window or
1737*4882a593Smuzhiyun    image creation */
1738*4882a593Smuzhiyun static GstXContext *
gst_x_image_sink_xcontext_get(GstRkXImageSink * ximagesink)1739*4882a593Smuzhiyun gst_x_image_sink_xcontext_get (GstRkXImageSink * ximagesink)
1740*4882a593Smuzhiyun {
1741*4882a593Smuzhiyun   GstXContext *xcontext = NULL;
1742*4882a593Smuzhiyun   XPixmapFormatValues *px_formats = NULL;
1743*4882a593Smuzhiyun   gint nb_formats = 0, i;
1744*4882a593Smuzhiyun   gint endianness;
1745*4882a593Smuzhiyun   GstVideoFormat vformat;
1746*4882a593Smuzhiyun   guint32 alpha_mask;
1747*4882a593Smuzhiyun 
1748*4882a593Smuzhiyun   g_return_val_if_fail (GST_IS_X_IMAGE_SINK (ximagesink), NULL);
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun   xcontext = g_new0 (GstXContext, 1);
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1753*4882a593Smuzhiyun 
1754*4882a593Smuzhiyun   xcontext->disp = XOpenDisplay (ximagesink->display_name);
1755*4882a593Smuzhiyun 
1756*4882a593Smuzhiyun   if (!xcontext->disp) {
1757*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1758*4882a593Smuzhiyun     g_free (xcontext);
1759*4882a593Smuzhiyun     GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
1760*4882a593Smuzhiyun         ("Could not initialise X output"), ("Could not open display"));
1761*4882a593Smuzhiyun     return NULL;
1762*4882a593Smuzhiyun   }
1763*4882a593Smuzhiyun 
1764*4882a593Smuzhiyun   xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
1765*4882a593Smuzhiyun   xcontext->screen_num = DefaultScreen (xcontext->disp);
1766*4882a593Smuzhiyun   xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
1767*4882a593Smuzhiyun   xcontext->root = DefaultRootWindow (xcontext->disp);
1768*4882a593Smuzhiyun   xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
1769*4882a593Smuzhiyun   xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
1770*4882a593Smuzhiyun   xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun   xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
1773*4882a593Smuzhiyun   xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
1774*4882a593Smuzhiyun   xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
1775*4882a593Smuzhiyun   xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
1776*4882a593Smuzhiyun 
1777*4882a593Smuzhiyun   GST_DEBUG_OBJECT (ximagesink, "X reports %dx%d pixels and %d mm x %d mm",
1778*4882a593Smuzhiyun       xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
1779*4882a593Smuzhiyun 
1780*4882a593Smuzhiyun   /* We get supported pixmap formats at supported depth */
1781*4882a593Smuzhiyun   px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun   if (!px_formats) {
1784*4882a593Smuzhiyun     XCloseDisplay (xcontext->disp);
1785*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
1786*4882a593Smuzhiyun     g_free (xcontext);
1787*4882a593Smuzhiyun     GST_ELEMENT_ERROR (ximagesink, RESOURCE, SETTINGS,
1788*4882a593Smuzhiyun         ("Could not get supported pixmap formats"), (NULL));
1789*4882a593Smuzhiyun     return NULL;
1790*4882a593Smuzhiyun   }
1791*4882a593Smuzhiyun 
1792*4882a593Smuzhiyun   /* We get bpp value corresponding to our running depth */
1793*4882a593Smuzhiyun   for (i = 0; i < nb_formats; i++) {
1794*4882a593Smuzhiyun     if (px_formats[i].depth == xcontext->depth)
1795*4882a593Smuzhiyun       xcontext->bpp = px_formats[i].bits_per_pixel;
1796*4882a593Smuzhiyun   }
1797*4882a593Smuzhiyun 
1798*4882a593Smuzhiyun   XFree (px_formats);
1799*4882a593Smuzhiyun 
1800*4882a593Smuzhiyun   endianness = (ImageByteOrder (xcontext->disp) ==
1801*4882a593Smuzhiyun       LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
1802*4882a593Smuzhiyun 
1803*4882a593Smuzhiyun   /* extrapolate alpha mask */
1804*4882a593Smuzhiyun   if (xcontext->depth == 32) {
1805*4882a593Smuzhiyun     alpha_mask = ~(xcontext->visual->red_mask
1806*4882a593Smuzhiyun         | xcontext->visual->green_mask | xcontext->visual->blue_mask);
1807*4882a593Smuzhiyun   } else {
1808*4882a593Smuzhiyun     alpha_mask = 0;
1809*4882a593Smuzhiyun   }
1810*4882a593Smuzhiyun 
1811*4882a593Smuzhiyun   vformat =
1812*4882a593Smuzhiyun       gst_video_format_from_masks (xcontext->depth, xcontext->bpp, endianness,
1813*4882a593Smuzhiyun       xcontext->visual->red_mask, xcontext->visual->green_mask,
1814*4882a593Smuzhiyun       xcontext->visual->blue_mask, alpha_mask);
1815*4882a593Smuzhiyun 
1816*4882a593Smuzhiyun   if (vformat == GST_VIDEO_FORMAT_UNKNOWN)
1817*4882a593Smuzhiyun     goto unknown_format;
1818*4882a593Smuzhiyun 
1819*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun   return xcontext;
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun   /* ERRORS */
1824*4882a593Smuzhiyun unknown_format:
1825*4882a593Smuzhiyun   {
1826*4882a593Smuzhiyun     GST_ERROR_OBJECT (ximagesink, "unknown format");
1827*4882a593Smuzhiyun     return NULL;
1828*4882a593Smuzhiyun   }
1829*4882a593Smuzhiyun }
1830*4882a593Smuzhiyun 
1831*4882a593Smuzhiyun /* This function cleans the X context. Closing the Display and unrefing the
1832*4882a593Smuzhiyun    caps for supported formats. */
1833*4882a593Smuzhiyun static void
gst_x_image_sink_xcontext_clear(GstRkXImageSink * ximagesink)1834*4882a593Smuzhiyun gst_x_image_sink_xcontext_clear (GstRkXImageSink * ximagesink)
1835*4882a593Smuzhiyun {
1836*4882a593Smuzhiyun   GstXContext *xcontext;
1837*4882a593Smuzhiyun 
1838*4882a593Smuzhiyun   g_return_if_fail (GST_IS_X_IMAGE_SINK (ximagesink));
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun   GST_OBJECT_LOCK (ximagesink);
1841*4882a593Smuzhiyun   if (ximagesink->xcontext == NULL) {
1842*4882a593Smuzhiyun     GST_OBJECT_UNLOCK (ximagesink);
1843*4882a593Smuzhiyun     return;
1844*4882a593Smuzhiyun   }
1845*4882a593Smuzhiyun 
1846*4882a593Smuzhiyun   /* Take the xcontext reference and NULL it while we
1847*4882a593Smuzhiyun    * clean it up, so that any buffer-alloced buffers
1848*4882a593Smuzhiyun    * arriving after this will be freed correctly */
1849*4882a593Smuzhiyun   xcontext = ximagesink->xcontext;
1850*4882a593Smuzhiyun   ximagesink->xcontext = NULL;
1851*4882a593Smuzhiyun 
1852*4882a593Smuzhiyun   GST_OBJECT_UNLOCK (ximagesink);
1853*4882a593Smuzhiyun 
1854*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
1855*4882a593Smuzhiyun 
1856*4882a593Smuzhiyun   XCloseDisplay (xcontext->disp);
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
1859*4882a593Smuzhiyun 
1860*4882a593Smuzhiyun   g_free (xcontext);
1861*4882a593Smuzhiyun }
1862*4882a593Smuzhiyun 
1863*4882a593Smuzhiyun /* Element stuff */
1864*4882a593Smuzhiyun 
1865*4882a593Smuzhiyun static GstCaps *
gst_x_image_sink_get_allowed_caps(GstRkXImageSink * self)1866*4882a593Smuzhiyun gst_x_image_sink_get_allowed_caps (GstRkXImageSink * self)
1867*4882a593Smuzhiyun {
1868*4882a593Smuzhiyun   if (!self->allowed_caps)
1869*4882a593Smuzhiyun     return NULL;                /* base class will return the template caps */
1870*4882a593Smuzhiyun   return gst_caps_ref (self->allowed_caps);
1871*4882a593Smuzhiyun }
1872*4882a593Smuzhiyun 
1873*4882a593Smuzhiyun static GstCaps *
gst_x_image_sink_getcaps(GstBaseSink * bsink,GstCaps * filter)1874*4882a593Smuzhiyun gst_x_image_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
1875*4882a593Smuzhiyun {
1876*4882a593Smuzhiyun   GstRkXImageSink *ximagesink;
1877*4882a593Smuzhiyun   GstCaps *caps, *out_caps;
1878*4882a593Smuzhiyun 
1879*4882a593Smuzhiyun   ximagesink = GST_X_IMAGE_SINK (bsink);
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun   caps = gst_x_image_sink_get_allowed_caps (ximagesink);
1882*4882a593Smuzhiyun   if (caps && filter) {
1883*4882a593Smuzhiyun     out_caps = gst_caps_intersect_full (caps, filter, GST_CAPS_INTERSECT_FIRST);
1884*4882a593Smuzhiyun     gst_caps_unref (caps);
1885*4882a593Smuzhiyun   } else {
1886*4882a593Smuzhiyun     out_caps = caps;
1887*4882a593Smuzhiyun   }
1888*4882a593Smuzhiyun 
1889*4882a593Smuzhiyun   return out_caps;
1890*4882a593Smuzhiyun }
1891*4882a593Smuzhiyun 
1892*4882a593Smuzhiyun static gboolean
gst_x_image_sink_setcaps(GstBaseSink * bsink,GstCaps * caps)1893*4882a593Smuzhiyun gst_x_image_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
1894*4882a593Smuzhiyun {
1895*4882a593Smuzhiyun   GstRkXImageSink *ximagesink;
1896*4882a593Smuzhiyun   GstVideoInfo info;
1897*4882a593Smuzhiyun   GstBufferPool *newpool, *oldpool;
1898*4882a593Smuzhiyun   GstStructure *s;
1899*4882a593Smuzhiyun   gint value;
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun   ximagesink = GST_X_IMAGE_SINK (bsink);
1902*4882a593Smuzhiyun 
1903*4882a593Smuzhiyun   if (!ximagesink->xcontext)
1904*4882a593Smuzhiyun     return FALSE;
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun   /* We are going to change the internal buffer pool, which means it will no
1907*4882a593Smuzhiyun    * longer be compatbile with the last_buffer size. Drain now, as we won't be
1908*4882a593Smuzhiyun    * able to do that later on. */
1909*4882a593Smuzhiyun   gst_kms_sink_drain (ximagesink);
1910*4882a593Smuzhiyun 
1911*4882a593Smuzhiyun   GST_DEBUG_OBJECT (ximagesink, "given caps %" GST_PTR_FORMAT, caps);
1912*4882a593Smuzhiyun 
1913*4882a593Smuzhiyun   if (!gst_video_info_from_caps (&info, caps))
1914*4882a593Smuzhiyun     goto invalid_format;
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun   /* parse AFBC from caps */
1917*4882a593Smuzhiyun   s = gst_caps_get_structure (caps, 0);
1918*4882a593Smuzhiyun   if (gst_structure_get_int (s, "arm-afbc", &value)) {
1919*4882a593Smuzhiyun     if (value)
1920*4882a593Smuzhiyun       GST_VIDEO_INFO_SET_AFBC (&info);
1921*4882a593Smuzhiyun     else
1922*4882a593Smuzhiyun       GST_VIDEO_INFO_UNSET_AFBC (&info);
1923*4882a593Smuzhiyun   }
1924*4882a593Smuzhiyun 
1925*4882a593Smuzhiyun   GST_VIDEO_SINK_WIDTH (ximagesink) = info.width;
1926*4882a593Smuzhiyun   GST_VIDEO_SINK_HEIGHT (ximagesink) = info.height;
1927*4882a593Smuzhiyun   ximagesink->fps_n = info.fps_n;
1928*4882a593Smuzhiyun   ximagesink->fps_d = info.fps_d;
1929*4882a593Smuzhiyun   ximagesink->par_n = info.par_n;
1930*4882a593Smuzhiyun   ximagesink->par_d = info.par_d;
1931*4882a593Smuzhiyun 
1932*4882a593Smuzhiyun   /* Notify application to set xwindow id now */
1933*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->flow_lock);
1934*4882a593Smuzhiyun   if (!ximagesink->xwindow) {
1935*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
1936*4882a593Smuzhiyun     gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (ximagesink));
1937*4882a593Smuzhiyun   } else {
1938*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
1939*4882a593Smuzhiyun   }
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun   /* Creating our window and our image */
1942*4882a593Smuzhiyun   if (GST_VIDEO_SINK_WIDTH (ximagesink) <= 0 ||
1943*4882a593Smuzhiyun       GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0)
1944*4882a593Smuzhiyun     goto invalid_size;
1945*4882a593Smuzhiyun 
1946*4882a593Smuzhiyun   /* create a new pool for the new configuration */
1947*4882a593Smuzhiyun   newpool = gst_kms_sink_create_pool (ximagesink, caps,
1948*4882a593Smuzhiyun       GST_VIDEO_INFO_SIZE (&info), 2);
1949*4882a593Smuzhiyun   if (!newpool)
1950*4882a593Smuzhiyun     goto no_pool;
1951*4882a593Smuzhiyun 
1952*4882a593Smuzhiyun   /* we don't activate the internal pool yet as it may not be needed */
1953*4882a593Smuzhiyun   oldpool = ximagesink->pool;
1954*4882a593Smuzhiyun   ximagesink->pool = newpool;
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun   if (oldpool) {
1957*4882a593Smuzhiyun     gst_buffer_pool_set_active (oldpool, FALSE);
1958*4882a593Smuzhiyun     gst_object_unref (oldpool);
1959*4882a593Smuzhiyun   }
1960*4882a593Smuzhiyun 
1961*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->flow_lock);
1962*4882a593Smuzhiyun   if (!ximagesink->xwindow) {
1963*4882a593Smuzhiyun     ximagesink->xwindow = gst_x_image_sink_xwindow_new (ximagesink,
1964*4882a593Smuzhiyun         GST_VIDEO_SINK_WIDTH (ximagesink), GST_VIDEO_SINK_HEIGHT (ximagesink));
1965*4882a593Smuzhiyun   }
1966*4882a593Smuzhiyun 
1967*4882a593Smuzhiyun   ximagesink->vinfo = info;
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun   /* Remember to draw borders for next frame */
1970*4882a593Smuzhiyun   ximagesink->draw_border = TRUE;
1971*4882a593Smuzhiyun 
1972*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->flow_lock);
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun   return TRUE;
1975*4882a593Smuzhiyun 
1976*4882a593Smuzhiyun   /* ERRORS */
1977*4882a593Smuzhiyun invalid_format:
1978*4882a593Smuzhiyun   {
1979*4882a593Smuzhiyun     GST_ERROR_OBJECT (ximagesink, "caps invalid");
1980*4882a593Smuzhiyun     return FALSE;
1981*4882a593Smuzhiyun   }
1982*4882a593Smuzhiyun invalid_size:
1983*4882a593Smuzhiyun   {
1984*4882a593Smuzhiyun     GST_ELEMENT_ERROR (ximagesink, CORE, NEGOTIATION, (NULL),
1985*4882a593Smuzhiyun         ("Invalid image size."));
1986*4882a593Smuzhiyun     return FALSE;
1987*4882a593Smuzhiyun   }
1988*4882a593Smuzhiyun no_pool:
1989*4882a593Smuzhiyun   {
1990*4882a593Smuzhiyun     /* Already warned in create_pool */
1991*4882a593Smuzhiyun     return FALSE;
1992*4882a593Smuzhiyun   }
1993*4882a593Smuzhiyun }
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun static GstStateChangeReturn
gst_x_image_sink_change_state(GstElement * element,GstStateChange transition)1996*4882a593Smuzhiyun gst_x_image_sink_change_state (GstElement * element, GstStateChange transition)
1997*4882a593Smuzhiyun {
1998*4882a593Smuzhiyun   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1999*4882a593Smuzhiyun   GstRkXImageSink *ximagesink;
2000*4882a593Smuzhiyun   GstXContext *xcontext = NULL;
2001*4882a593Smuzhiyun 
2002*4882a593Smuzhiyun   ximagesink = GST_X_IMAGE_SINK (element);
2003*4882a593Smuzhiyun 
2004*4882a593Smuzhiyun   switch (transition) {
2005*4882a593Smuzhiyun     case GST_STATE_CHANGE_NULL_TO_READY:
2006*4882a593Smuzhiyun       /* Initializing the XContext */
2007*4882a593Smuzhiyun       if (ximagesink->xcontext == NULL) {
2008*4882a593Smuzhiyun         xcontext = gst_x_image_sink_xcontext_get (ximagesink);
2009*4882a593Smuzhiyun         if (xcontext == NULL) {
2010*4882a593Smuzhiyun           ret = GST_STATE_CHANGE_FAILURE;
2011*4882a593Smuzhiyun           goto beach;
2012*4882a593Smuzhiyun         }
2013*4882a593Smuzhiyun         GST_OBJECT_LOCK (ximagesink);
2014*4882a593Smuzhiyun         if (xcontext)
2015*4882a593Smuzhiyun           ximagesink->xcontext = xcontext;
2016*4882a593Smuzhiyun         GST_OBJECT_UNLOCK (ximagesink);
2017*4882a593Smuzhiyun       }
2018*4882a593Smuzhiyun 
2019*4882a593Smuzhiyun       /* call XSynchronize with the current value of synchronous */
2020*4882a593Smuzhiyun       GST_DEBUG_OBJECT (ximagesink, "XSynchronize called with %s",
2021*4882a593Smuzhiyun           ximagesink->synchronous ? "TRUE" : "FALSE");
2022*4882a593Smuzhiyun       g_mutex_lock (&ximagesink->x_lock);
2023*4882a593Smuzhiyun       XSynchronize (ximagesink->xcontext->disp, ximagesink->synchronous);
2024*4882a593Smuzhiyun       g_mutex_unlock (&ximagesink->x_lock);
2025*4882a593Smuzhiyun       gst_x_image_sink_manage_event_thread (ximagesink);
2026*4882a593Smuzhiyun       break;
2027*4882a593Smuzhiyun     case GST_STATE_CHANGE_READY_TO_PAUSED:
2028*4882a593Smuzhiyun       ximagesink->paused = TRUE;
2029*4882a593Smuzhiyun       g_mutex_lock (&ximagesink->flow_lock);
2030*4882a593Smuzhiyun       if (ximagesink->xwindow)
2031*4882a593Smuzhiyun         gst_x_image_sink_xwindow_clear (ximagesink, ximagesink->xwindow);
2032*4882a593Smuzhiyun       g_mutex_unlock (&ximagesink->flow_lock);
2033*4882a593Smuzhiyun       break;
2034*4882a593Smuzhiyun     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2035*4882a593Smuzhiyun       ximagesink->paused = FALSE;
2036*4882a593Smuzhiyun       break;
2037*4882a593Smuzhiyun     default:
2038*4882a593Smuzhiyun       break;
2039*4882a593Smuzhiyun   }
2040*4882a593Smuzhiyun 
2041*4882a593Smuzhiyun   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2042*4882a593Smuzhiyun 
2043*4882a593Smuzhiyun   switch (transition) {
2044*4882a593Smuzhiyun     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2045*4882a593Smuzhiyun       ximagesink->paused = TRUE;
2046*4882a593Smuzhiyun       break;
2047*4882a593Smuzhiyun     case GST_STATE_CHANGE_PAUSED_TO_READY:
2048*4882a593Smuzhiyun       ximagesink->paused = FALSE;
2049*4882a593Smuzhiyun       ximagesink->fps_n = 0;
2050*4882a593Smuzhiyun       ximagesink->fps_d = 1;
2051*4882a593Smuzhiyun       GST_VIDEO_SINK_WIDTH (ximagesink) = 0;
2052*4882a593Smuzhiyun       GST_VIDEO_SINK_HEIGHT (ximagesink) = 0;
2053*4882a593Smuzhiyun       break;
2054*4882a593Smuzhiyun     case GST_STATE_CHANGE_READY_TO_NULL:
2055*4882a593Smuzhiyun       gst_x_image_sink_reset (ximagesink);
2056*4882a593Smuzhiyun       break;
2057*4882a593Smuzhiyun     default:
2058*4882a593Smuzhiyun       break;
2059*4882a593Smuzhiyun   }
2060*4882a593Smuzhiyun 
2061*4882a593Smuzhiyun beach:
2062*4882a593Smuzhiyun   return ret;
2063*4882a593Smuzhiyun }
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun static void
gst_x_image_sink_get_times(GstBaseSink * bsink,GstBuffer * buf,GstClockTime * start,GstClockTime * end)2066*4882a593Smuzhiyun gst_x_image_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
2067*4882a593Smuzhiyun     GstClockTime * start, GstClockTime * end)
2068*4882a593Smuzhiyun {
2069*4882a593Smuzhiyun   GstRkXImageSink *ximagesink;
2070*4882a593Smuzhiyun 
2071*4882a593Smuzhiyun   ximagesink = GST_X_IMAGE_SINK (bsink);
2072*4882a593Smuzhiyun 
2073*4882a593Smuzhiyun   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2074*4882a593Smuzhiyun     *start = GST_BUFFER_TIMESTAMP (buf);
2075*4882a593Smuzhiyun     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2076*4882a593Smuzhiyun       *end = *start + GST_BUFFER_DURATION (buf);
2077*4882a593Smuzhiyun     } else {
2078*4882a593Smuzhiyun       if (ximagesink->fps_n > 0) {
2079*4882a593Smuzhiyun         *end = *start +
2080*4882a593Smuzhiyun             gst_util_uint64_scale_int (GST_SECOND, ximagesink->fps_d,
2081*4882a593Smuzhiyun             ximagesink->fps_n);
2082*4882a593Smuzhiyun       }
2083*4882a593Smuzhiyun     }
2084*4882a593Smuzhiyun   }
2085*4882a593Smuzhiyun }
2086*4882a593Smuzhiyun 
2087*4882a593Smuzhiyun static GstFlowReturn
gst_x_image_sink_show_frame(GstVideoSink * vsink,GstBuffer * buf)2088*4882a593Smuzhiyun gst_x_image_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
2089*4882a593Smuzhiyun {
2090*4882a593Smuzhiyun   GstFlowReturn res = GST_FLOW_OK;
2091*4882a593Smuzhiyun   GstRkXImageSink *ximagesink;
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun   ximagesink = GST_X_IMAGE_SINK (vsink);
2094*4882a593Smuzhiyun 
2095*4882a593Smuzhiyun   if (!gst_x_image_sink_ximage_put (ximagesink, buf)) {
2096*4882a593Smuzhiyun     /* No Window available to put our image into */
2097*4882a593Smuzhiyun     GST_WARNING_OBJECT (ximagesink, "could not output image - no window");
2098*4882a593Smuzhiyun     res = GST_FLOW_ERROR;
2099*4882a593Smuzhiyun   }
2100*4882a593Smuzhiyun 
2101*4882a593Smuzhiyun   return res;
2102*4882a593Smuzhiyun }
2103*4882a593Smuzhiyun 
2104*4882a593Smuzhiyun static gboolean
gst_x_image_sink_event(GstBaseSink * sink,GstEvent * event)2105*4882a593Smuzhiyun gst_x_image_sink_event (GstBaseSink * sink, GstEvent * event)
2106*4882a593Smuzhiyun {
2107*4882a593Smuzhiyun   GstRkXImageSink *ximagesink = GST_X_IMAGE_SINK (sink);
2108*4882a593Smuzhiyun 
2109*4882a593Smuzhiyun   switch (GST_EVENT_TYPE (event)) {
2110*4882a593Smuzhiyun     case GST_EVENT_TAG:{
2111*4882a593Smuzhiyun       GstTagList *l;
2112*4882a593Smuzhiyun       gchar *title = NULL;
2113*4882a593Smuzhiyun 
2114*4882a593Smuzhiyun       gst_event_parse_tag (event, &l);
2115*4882a593Smuzhiyun       gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
2116*4882a593Smuzhiyun 
2117*4882a593Smuzhiyun       if (title) {
2118*4882a593Smuzhiyun         GST_DEBUG_OBJECT (ximagesink, "got tags, title='%s'", title);
2119*4882a593Smuzhiyun         gst_x_image_sink_xwindow_set_title (ximagesink, ximagesink->xwindow,
2120*4882a593Smuzhiyun             title);
2121*4882a593Smuzhiyun 
2122*4882a593Smuzhiyun         g_free (title);
2123*4882a593Smuzhiyun       }
2124*4882a593Smuzhiyun       break;
2125*4882a593Smuzhiyun     }
2126*4882a593Smuzhiyun     default:
2127*4882a593Smuzhiyun       break;
2128*4882a593Smuzhiyun   }
2129*4882a593Smuzhiyun 
2130*4882a593Smuzhiyun   return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
2131*4882a593Smuzhiyun }
2132*4882a593Smuzhiyun 
2133*4882a593Smuzhiyun /* Interfaces stuff */
2134*4882a593Smuzhiyun static void
gst_x_image_sink_navigation_send_event(GstNavigation * navigation,GstStructure * structure)2135*4882a593Smuzhiyun gst_x_image_sink_navigation_send_event (GstNavigation * navigation,
2136*4882a593Smuzhiyun     GstStructure * structure)
2137*4882a593Smuzhiyun {
2138*4882a593Smuzhiyun   GstRkXImageSink *ximagesink = GST_X_IMAGE_SINK (navigation);
2139*4882a593Smuzhiyun   GstEvent *event = NULL;
2140*4882a593Smuzhiyun   gint x_offset, y_offset;
2141*4882a593Smuzhiyun   gdouble x, y;
2142*4882a593Smuzhiyun   gboolean handled = FALSE;
2143*4882a593Smuzhiyun 
2144*4882a593Smuzhiyun   /* We are not converting the pointer coordinates as there's no hardware
2145*4882a593Smuzhiyun      scaling done here. The only possible scaling is done by videoscale and
2146*4882a593Smuzhiyun      videoscale will have to catch those events and tranform the coordinates
2147*4882a593Smuzhiyun      to match the applied scaling. So here we just add the offset if the image
2148*4882a593Smuzhiyun      is centered in the window.  */
2149*4882a593Smuzhiyun 
2150*4882a593Smuzhiyun   /* We take the flow_lock while we look at the window */
2151*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->flow_lock);
2152*4882a593Smuzhiyun 
2153*4882a593Smuzhiyun   if (!ximagesink->xwindow) {
2154*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
2155*4882a593Smuzhiyun     gst_structure_free (structure);
2156*4882a593Smuzhiyun     return;
2157*4882a593Smuzhiyun   }
2158*4882a593Smuzhiyun 
2159*4882a593Smuzhiyun   x_offset = ximagesink->xwindow->width - GST_VIDEO_SINK_WIDTH (ximagesink);
2160*4882a593Smuzhiyun   y_offset = ximagesink->xwindow->height - GST_VIDEO_SINK_HEIGHT (ximagesink);
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->flow_lock);
2163*4882a593Smuzhiyun 
2164*4882a593Smuzhiyun   if (x_offset > 0 && gst_structure_get_double (structure, "pointer_x", &x)) {
2165*4882a593Smuzhiyun     x -= x_offset / 2;
2166*4882a593Smuzhiyun     gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL);
2167*4882a593Smuzhiyun   }
2168*4882a593Smuzhiyun   if (y_offset > 0 && gst_structure_get_double (structure, "pointer_y", &y)) {
2169*4882a593Smuzhiyun     y -= y_offset / 2;
2170*4882a593Smuzhiyun     gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL);
2171*4882a593Smuzhiyun   }
2172*4882a593Smuzhiyun 
2173*4882a593Smuzhiyun   event = gst_event_new_navigation (structure);
2174*4882a593Smuzhiyun   if (event) {
2175*4882a593Smuzhiyun     gst_event_ref (event);
2176*4882a593Smuzhiyun     handled = gst_pad_push_event (GST_VIDEO_SINK_PAD (ximagesink), event);
2177*4882a593Smuzhiyun 
2178*4882a593Smuzhiyun     if (!handled)
2179*4882a593Smuzhiyun       gst_element_post_message (GST_ELEMENT_CAST (ximagesink),
2180*4882a593Smuzhiyun           gst_navigation_message_new_event (GST_OBJECT_CAST (ximagesink),
2181*4882a593Smuzhiyun               event));
2182*4882a593Smuzhiyun 
2183*4882a593Smuzhiyun     gst_event_unref (event);
2184*4882a593Smuzhiyun   }
2185*4882a593Smuzhiyun }
2186*4882a593Smuzhiyun 
2187*4882a593Smuzhiyun static void
gst_x_image_sink_navigation_init(GstNavigationInterface * iface)2188*4882a593Smuzhiyun gst_x_image_sink_navigation_init (GstNavigationInterface * iface)
2189*4882a593Smuzhiyun {
2190*4882a593Smuzhiyun   iface->send_event = gst_x_image_sink_navigation_send_event;
2191*4882a593Smuzhiyun }
2192*4882a593Smuzhiyun 
2193*4882a593Smuzhiyun static void
gst_x_image_sink_set_window_handle(GstVideoOverlay * overlay,guintptr id)2194*4882a593Smuzhiyun gst_x_image_sink_set_window_handle (GstVideoOverlay * overlay, guintptr id)
2195*4882a593Smuzhiyun {
2196*4882a593Smuzhiyun   XID xwindow_id = id;
2197*4882a593Smuzhiyun   GstRkXImageSink *ximagesink = GST_X_IMAGE_SINK (overlay);
2198*4882a593Smuzhiyun   GstXWindow *xwindow = NULL;
2199*4882a593Smuzhiyun 
2200*4882a593Smuzhiyun   /* We acquire the stream lock while setting this window in the element.
2201*4882a593Smuzhiyun      We are basically cleaning tons of stuff replacing the old window, putting
2202*4882a593Smuzhiyun      images while we do that would surely crash */
2203*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->flow_lock);
2204*4882a593Smuzhiyun 
2205*4882a593Smuzhiyun   /* If we already use that window return */
2206*4882a593Smuzhiyun   if (ximagesink->xwindow && (xwindow_id == ximagesink->xwindow->win)) {
2207*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
2208*4882a593Smuzhiyun     return;
2209*4882a593Smuzhiyun   }
2210*4882a593Smuzhiyun 
2211*4882a593Smuzhiyun   /* If the element has not initialized the X11 context try to do so */
2212*4882a593Smuzhiyun   if (!ximagesink->xcontext &&
2213*4882a593Smuzhiyun       !(ximagesink->xcontext = gst_x_image_sink_xcontext_get (ximagesink))) {
2214*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
2215*4882a593Smuzhiyun     /* we have thrown a GST_ELEMENT_ERROR now */
2216*4882a593Smuzhiyun     return;
2217*4882a593Smuzhiyun   }
2218*4882a593Smuzhiyun 
2219*4882a593Smuzhiyun   /* If a window is there already we destroy it */
2220*4882a593Smuzhiyun   if (ximagesink->xwindow) {
2221*4882a593Smuzhiyun     gst_x_image_sink_xwindow_destroy (ximagesink, ximagesink->xwindow);
2222*4882a593Smuzhiyun     ximagesink->xwindow = NULL;
2223*4882a593Smuzhiyun   }
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun   /* If the xid is 0 we go back to an internal window */
2226*4882a593Smuzhiyun   if (xwindow_id == 0) {
2227*4882a593Smuzhiyun     /* If no width/height caps nego did not happen window will be created
2228*4882a593Smuzhiyun        during caps nego then */
2229*4882a593Smuzhiyun     if (GST_VIDEO_SINK_WIDTH (ximagesink) && GST_VIDEO_SINK_HEIGHT (ximagesink)) {
2230*4882a593Smuzhiyun       xwindow = gst_x_image_sink_xwindow_new (ximagesink,
2231*4882a593Smuzhiyun           GST_VIDEO_SINK_WIDTH (ximagesink),
2232*4882a593Smuzhiyun           GST_VIDEO_SINK_HEIGHT (ximagesink));
2233*4882a593Smuzhiyun     }
2234*4882a593Smuzhiyun   } else {
2235*4882a593Smuzhiyun     xwindow = g_new0 (GstXWindow, 1);
2236*4882a593Smuzhiyun 
2237*4882a593Smuzhiyun     xwindow->win = xwindow_id;
2238*4882a593Smuzhiyun 
2239*4882a593Smuzhiyun     /* We set the events we want to receive and create a GC. */
2240*4882a593Smuzhiyun     g_mutex_lock (&ximagesink->x_lock);
2241*4882a593Smuzhiyun     xwindow->internal = FALSE;
2242*4882a593Smuzhiyun     if (ximagesink->handle_events) {
2243*4882a593Smuzhiyun       XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask |
2244*4882a593Smuzhiyun           StructureNotifyMask | PointerMotionMask | KeyPressMask |
2245*4882a593Smuzhiyun           KeyReleaseMask);
2246*4882a593Smuzhiyun     }
2247*4882a593Smuzhiyun 
2248*4882a593Smuzhiyun     xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win, 0, NULL);
2249*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->x_lock);
2250*4882a593Smuzhiyun   }
2251*4882a593Smuzhiyun 
2252*4882a593Smuzhiyun   if (xwindow) {
2253*4882a593Smuzhiyun     ximagesink->xwindow = xwindow;
2254*4882a593Smuzhiyun     /* Update the window geometry, possibly generating a reconfigure event. */
2255*4882a593Smuzhiyun     gst_x_image_sink_xwindow_update_geometry (ximagesink);
2256*4882a593Smuzhiyun   }
2257*4882a593Smuzhiyun 
2258*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->flow_lock);
2259*4882a593Smuzhiyun }
2260*4882a593Smuzhiyun 
2261*4882a593Smuzhiyun static void
gst_x_image_sink_expose(GstVideoOverlay * overlay)2262*4882a593Smuzhiyun gst_x_image_sink_expose (GstVideoOverlay * overlay)
2263*4882a593Smuzhiyun {
2264*4882a593Smuzhiyun   GstRkXImageSink *ximagesink = GST_X_IMAGE_SINK (overlay);
2265*4882a593Smuzhiyun 
2266*4882a593Smuzhiyun   gst_x_image_sink_xwindow_update_geometry (ximagesink);
2267*4882a593Smuzhiyun   gst_x_image_sink_ximage_put (ximagesink, NULL);
2268*4882a593Smuzhiyun }
2269*4882a593Smuzhiyun 
2270*4882a593Smuzhiyun static void
gst_x_image_sink_set_event_handling(GstVideoOverlay * overlay,gboolean handle_events)2271*4882a593Smuzhiyun gst_x_image_sink_set_event_handling (GstVideoOverlay * overlay,
2272*4882a593Smuzhiyun     gboolean handle_events)
2273*4882a593Smuzhiyun {
2274*4882a593Smuzhiyun   GstRkXImageSink *ximagesink = GST_X_IMAGE_SINK (overlay);
2275*4882a593Smuzhiyun 
2276*4882a593Smuzhiyun   ximagesink->handle_events = handle_events;
2277*4882a593Smuzhiyun 
2278*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->flow_lock);
2279*4882a593Smuzhiyun 
2280*4882a593Smuzhiyun   if (G_UNLIKELY (!ximagesink->xwindow)) {
2281*4882a593Smuzhiyun     g_mutex_unlock (&ximagesink->flow_lock);
2282*4882a593Smuzhiyun     return;
2283*4882a593Smuzhiyun   }
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->x_lock);
2286*4882a593Smuzhiyun 
2287*4882a593Smuzhiyun   if (handle_events) {
2288*4882a593Smuzhiyun     if (ximagesink->xwindow->internal) {
2289*4882a593Smuzhiyun       XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win,
2290*4882a593Smuzhiyun           ExposureMask | StructureNotifyMask | PointerMotionMask |
2291*4882a593Smuzhiyun           KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
2292*4882a593Smuzhiyun     } else {
2293*4882a593Smuzhiyun       XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win,
2294*4882a593Smuzhiyun           ExposureMask | StructureNotifyMask | PointerMotionMask |
2295*4882a593Smuzhiyun           KeyPressMask | KeyReleaseMask);
2296*4882a593Smuzhiyun     }
2297*4882a593Smuzhiyun   } else {
2298*4882a593Smuzhiyun     XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, 0);
2299*4882a593Smuzhiyun   }
2300*4882a593Smuzhiyun 
2301*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->x_lock);
2302*4882a593Smuzhiyun 
2303*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->flow_lock);
2304*4882a593Smuzhiyun }
2305*4882a593Smuzhiyun 
2306*4882a593Smuzhiyun static void
gst_x_image_sink_set_render_rectangle(GstVideoOverlay * overlay,gint x,gint y,gint width,gint height)2307*4882a593Smuzhiyun gst_x_image_sink_set_render_rectangle (GstVideoOverlay * overlay,
2308*4882a593Smuzhiyun     gint x, gint y, gint width, gint height)
2309*4882a593Smuzhiyun {
2310*4882a593Smuzhiyun   GstRkXImageSink *ximagesink = GST_X_IMAGE_SINK (overlay);
2311*4882a593Smuzhiyun   GST_DEBUG_OBJECT (ximagesink, "Set Render Rectangle"
2312*4882a593Smuzhiyun       "x %d y %d width %d height %d", x, y, width, height);
2313*4882a593Smuzhiyun 
2314*4882a593Smuzhiyun   ximagesink->save_rect.w = width;
2315*4882a593Smuzhiyun   ximagesink->save_rect.h = height;
2316*4882a593Smuzhiyun   ximagesink->save_rect.x = x;
2317*4882a593Smuzhiyun   ximagesink->save_rect.y = y;
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun   gst_x_image_sink_expose (GST_VIDEO_OVERLAY (ximagesink));
2320*4882a593Smuzhiyun }
2321*4882a593Smuzhiyun 
2322*4882a593Smuzhiyun static void
gst_x_image_sink_video_overlay_init(GstVideoOverlayInterface * iface)2323*4882a593Smuzhiyun gst_x_image_sink_video_overlay_init (GstVideoOverlayInterface * iface)
2324*4882a593Smuzhiyun {
2325*4882a593Smuzhiyun   iface->set_window_handle = gst_x_image_sink_set_window_handle;
2326*4882a593Smuzhiyun   iface->expose = gst_x_image_sink_expose;
2327*4882a593Smuzhiyun   iface->set_render_rectangle = gst_x_image_sink_set_render_rectangle;
2328*4882a593Smuzhiyun   iface->handle_events = gst_x_image_sink_set_event_handling;
2329*4882a593Smuzhiyun }
2330*4882a593Smuzhiyun 
2331*4882a593Smuzhiyun /* =========================================== */
2332*4882a593Smuzhiyun /*                                             */
2333*4882a593Smuzhiyun /*              Init & Class init              */
2334*4882a593Smuzhiyun /*                                             */
2335*4882a593Smuzhiyun /* =========================================== */
2336*4882a593Smuzhiyun 
2337*4882a593Smuzhiyun static void
gst_x_image_sink_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)2338*4882a593Smuzhiyun gst_x_image_sink_set_property (GObject * object, guint prop_id,
2339*4882a593Smuzhiyun     const GValue * value, GParamSpec * pspec)
2340*4882a593Smuzhiyun {
2341*4882a593Smuzhiyun   GstRkXImageSink *ximagesink;
2342*4882a593Smuzhiyun 
2343*4882a593Smuzhiyun   g_return_if_fail (GST_IS_X_IMAGE_SINK (object));
2344*4882a593Smuzhiyun 
2345*4882a593Smuzhiyun   ximagesink = GST_X_IMAGE_SINK (object);
2346*4882a593Smuzhiyun 
2347*4882a593Smuzhiyun   switch (prop_id) {
2348*4882a593Smuzhiyun     case PROP_DISPLAY:
2349*4882a593Smuzhiyun       ximagesink->display_name = g_strdup (g_value_get_string (value));
2350*4882a593Smuzhiyun       break;
2351*4882a593Smuzhiyun     case PROP_SYNCHRONOUS:
2352*4882a593Smuzhiyun       ximagesink->synchronous = g_value_get_boolean (value);
2353*4882a593Smuzhiyun       if (ximagesink->xcontext) {
2354*4882a593Smuzhiyun         GST_DEBUG_OBJECT (ximagesink, "XSynchronize called with %s",
2355*4882a593Smuzhiyun             ximagesink->synchronous ? "TRUE" : "FALSE");
2356*4882a593Smuzhiyun         g_mutex_lock (&ximagesink->x_lock);
2357*4882a593Smuzhiyun         XSynchronize (ximagesink->xcontext->disp, ximagesink->synchronous);
2358*4882a593Smuzhiyun         g_mutex_unlock (&ximagesink->x_lock);
2359*4882a593Smuzhiyun       }
2360*4882a593Smuzhiyun       break;
2361*4882a593Smuzhiyun     case PROP_HANDLE_EVENTS:
2362*4882a593Smuzhiyun       gst_x_image_sink_set_event_handling (GST_VIDEO_OVERLAY (ximagesink),
2363*4882a593Smuzhiyun           g_value_get_boolean (value));
2364*4882a593Smuzhiyun       gst_x_image_sink_manage_event_thread (ximagesink);
2365*4882a593Smuzhiyun       break;
2366*4882a593Smuzhiyun     case PROP_HANDLE_EXPOSE:
2367*4882a593Smuzhiyun       ximagesink->handle_expose = g_value_get_boolean (value);
2368*4882a593Smuzhiyun       gst_x_image_sink_manage_event_thread (ximagesink);
2369*4882a593Smuzhiyun       break;
2370*4882a593Smuzhiyun     case PROP_DRIVER_NAME:
2371*4882a593Smuzhiyun       g_free (ximagesink->devname);
2372*4882a593Smuzhiyun       ximagesink->devname = g_value_dup_string (value);
2373*4882a593Smuzhiyun       break;
2374*4882a593Smuzhiyun     case PROP_BUS_ID:
2375*4882a593Smuzhiyun       g_free (ximagesink->bus_id);
2376*4882a593Smuzhiyun       ximagesink->bus_id = g_value_dup_string (value);
2377*4882a593Smuzhiyun       break;
2378*4882a593Smuzhiyun     case PROP_CONNECTOR_ID:
2379*4882a593Smuzhiyun       ximagesink->conn_id = g_value_get_int (value);
2380*4882a593Smuzhiyun       break;
2381*4882a593Smuzhiyun     case PROP_PLANE_ID:
2382*4882a593Smuzhiyun       ximagesink->plane_id = g_value_get_int (value);
2383*4882a593Smuzhiyun       break;
2384*4882a593Smuzhiyun     case PROP_FORCE_ASPECT_RATIO:
2385*4882a593Smuzhiyun       ximagesink->keep_aspect = g_value_get_boolean (value);
2386*4882a593Smuzhiyun       break;
2387*4882a593Smuzhiyun     default:
2388*4882a593Smuzhiyun       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2389*4882a593Smuzhiyun       break;
2390*4882a593Smuzhiyun   }
2391*4882a593Smuzhiyun }
2392*4882a593Smuzhiyun 
2393*4882a593Smuzhiyun static void
gst_x_image_sink_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2394*4882a593Smuzhiyun gst_x_image_sink_get_property (GObject * object, guint prop_id,
2395*4882a593Smuzhiyun     GValue * value, GParamSpec * pspec)
2396*4882a593Smuzhiyun {
2397*4882a593Smuzhiyun   GstRkXImageSink *ximagesink;
2398*4882a593Smuzhiyun 
2399*4882a593Smuzhiyun   g_return_if_fail (GST_IS_X_IMAGE_SINK (object));
2400*4882a593Smuzhiyun 
2401*4882a593Smuzhiyun   ximagesink = GST_X_IMAGE_SINK (object);
2402*4882a593Smuzhiyun 
2403*4882a593Smuzhiyun   switch (prop_id) {
2404*4882a593Smuzhiyun     case PROP_DISPLAY:
2405*4882a593Smuzhiyun       g_value_set_string (value, ximagesink->display_name);
2406*4882a593Smuzhiyun       break;
2407*4882a593Smuzhiyun     case PROP_SYNCHRONOUS:
2408*4882a593Smuzhiyun       g_value_set_boolean (value, ximagesink->synchronous);
2409*4882a593Smuzhiyun       break;
2410*4882a593Smuzhiyun     case PROP_HANDLE_EVENTS:
2411*4882a593Smuzhiyun       g_value_set_boolean (value, ximagesink->handle_events);
2412*4882a593Smuzhiyun       break;
2413*4882a593Smuzhiyun     case PROP_HANDLE_EXPOSE:
2414*4882a593Smuzhiyun       g_value_set_boolean (value, ximagesink->handle_expose);
2415*4882a593Smuzhiyun       break;
2416*4882a593Smuzhiyun     case PROP_WINDOW_WIDTH:
2417*4882a593Smuzhiyun       if (ximagesink->xwindow)
2418*4882a593Smuzhiyun         g_value_set_uint64 (value, ximagesink->xwindow->width);
2419*4882a593Smuzhiyun       else
2420*4882a593Smuzhiyun         g_value_set_uint64 (value, 0);
2421*4882a593Smuzhiyun       break;
2422*4882a593Smuzhiyun     case PROP_WINDOW_HEIGHT:
2423*4882a593Smuzhiyun       if (ximagesink->xwindow)
2424*4882a593Smuzhiyun         g_value_set_uint64 (value, ximagesink->xwindow->height);
2425*4882a593Smuzhiyun       else
2426*4882a593Smuzhiyun         g_value_set_uint64 (value, 0);
2427*4882a593Smuzhiyun       break;
2428*4882a593Smuzhiyun     case PROP_DRIVER_NAME:
2429*4882a593Smuzhiyun       g_value_set_string (value, ximagesink->devname);
2430*4882a593Smuzhiyun       break;
2431*4882a593Smuzhiyun     case PROP_BUS_ID:
2432*4882a593Smuzhiyun       g_value_set_string (value, ximagesink->bus_id);
2433*4882a593Smuzhiyun       break;
2434*4882a593Smuzhiyun     case PROP_CONNECTOR_ID:
2435*4882a593Smuzhiyun       g_value_set_int (value, ximagesink->conn_id);
2436*4882a593Smuzhiyun       break;
2437*4882a593Smuzhiyun     case PROP_PLANE_ID:
2438*4882a593Smuzhiyun       g_value_set_int (value, ximagesink->plane_id);
2439*4882a593Smuzhiyun       break;
2440*4882a593Smuzhiyun     case PROP_FORCE_ASPECT_RATIO:
2441*4882a593Smuzhiyun       g_value_set_boolean (value, ximagesink->keep_aspect);
2442*4882a593Smuzhiyun       break;
2443*4882a593Smuzhiyun     default:
2444*4882a593Smuzhiyun       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2445*4882a593Smuzhiyun       break;
2446*4882a593Smuzhiyun   }
2447*4882a593Smuzhiyun }
2448*4882a593Smuzhiyun 
2449*4882a593Smuzhiyun static void
gst_x_image_sink_reset(GstRkXImageSink * ximagesink)2450*4882a593Smuzhiyun gst_x_image_sink_reset (GstRkXImageSink * ximagesink)
2451*4882a593Smuzhiyun {
2452*4882a593Smuzhiyun   GThread *thread;
2453*4882a593Smuzhiyun 
2454*4882a593Smuzhiyun   GST_OBJECT_LOCK (ximagesink);
2455*4882a593Smuzhiyun   ximagesink->running = FALSE;
2456*4882a593Smuzhiyun   /* grab thread and mark it as NULL */
2457*4882a593Smuzhiyun   thread = ximagesink->event_thread;
2458*4882a593Smuzhiyun   ximagesink->event_thread = NULL;
2459*4882a593Smuzhiyun   GST_OBJECT_UNLOCK (ximagesink);
2460*4882a593Smuzhiyun 
2461*4882a593Smuzhiyun   /* Wait for our event thread to finish before we clean up our stuff. */
2462*4882a593Smuzhiyun   if (thread)
2463*4882a593Smuzhiyun     g_thread_join (thread);
2464*4882a593Smuzhiyun 
2465*4882a593Smuzhiyun   gst_buffer_replace (&ximagesink->last_buffer, NULL);
2466*4882a593Smuzhiyun 
2467*4882a593Smuzhiyun   g_mutex_lock (&ximagesink->flow_lock);
2468*4882a593Smuzhiyun 
2469*4882a593Smuzhiyun   if (ximagesink->xwindow) {
2470*4882a593Smuzhiyun     gst_x_image_sink_xwindow_clear (ximagesink, ximagesink->xwindow);
2471*4882a593Smuzhiyun     gst_x_image_sink_xwindow_destroy (ximagesink, ximagesink->xwindow);
2472*4882a593Smuzhiyun     ximagesink->xwindow = NULL;
2473*4882a593Smuzhiyun   }
2474*4882a593Smuzhiyun   g_mutex_unlock (&ximagesink->flow_lock);
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun   gst_x_image_sink_xcontext_clear (ximagesink);
2477*4882a593Smuzhiyun }
2478*4882a593Smuzhiyun 
2479*4882a593Smuzhiyun static void
gst_x_image_sink_finalize(GObject * object)2480*4882a593Smuzhiyun gst_x_image_sink_finalize (GObject * object)
2481*4882a593Smuzhiyun {
2482*4882a593Smuzhiyun   GstRkXImageSink *ximagesink;
2483*4882a593Smuzhiyun 
2484*4882a593Smuzhiyun   ximagesink = GST_X_IMAGE_SINK (object);
2485*4882a593Smuzhiyun 
2486*4882a593Smuzhiyun   gst_x_image_sink_reset (ximagesink);
2487*4882a593Smuzhiyun 
2488*4882a593Smuzhiyun   if (ximagesink->display_name) {
2489*4882a593Smuzhiyun     g_free (ximagesink->display_name);
2490*4882a593Smuzhiyun     ximagesink->display_name = NULL;
2491*4882a593Smuzhiyun   }
2492*4882a593Smuzhiyun   g_mutex_clear (&ximagesink->x_lock);
2493*4882a593Smuzhiyun   g_mutex_clear (&ximagesink->flow_lock);
2494*4882a593Smuzhiyun 
2495*4882a593Smuzhiyun   g_free (ximagesink->media_title);
2496*4882a593Smuzhiyun 
2497*4882a593Smuzhiyun   gst_poll_free (ximagesink->poll);
2498*4882a593Smuzhiyun 
2499*4882a593Smuzhiyun   g_clear_pointer (&ximagesink->devname, g_free);
2500*4882a593Smuzhiyun   g_clear_pointer (&ximagesink->bus_id, g_free);
2501*4882a593Smuzhiyun 
2502*4882a593Smuzhiyun   G_OBJECT_CLASS (parent_class)->finalize (object);
2503*4882a593Smuzhiyun }
2504*4882a593Smuzhiyun 
2505*4882a593Smuzhiyun static void
gst_x_image_sink_init(GstRkXImageSink * ximagesink)2506*4882a593Smuzhiyun gst_x_image_sink_init (GstRkXImageSink * ximagesink)
2507*4882a593Smuzhiyun {
2508*4882a593Smuzhiyun   ximagesink->display_name = NULL;
2509*4882a593Smuzhiyun   ximagesink->xcontext = NULL;
2510*4882a593Smuzhiyun   ximagesink->xwindow = NULL;
2511*4882a593Smuzhiyun   ximagesink->last_buffer = NULL;
2512*4882a593Smuzhiyun 
2513*4882a593Smuzhiyun   ximagesink->event_thread = NULL;
2514*4882a593Smuzhiyun   ximagesink->running = FALSE;
2515*4882a593Smuzhiyun 
2516*4882a593Smuzhiyun   ximagesink->fps_n = 0;
2517*4882a593Smuzhiyun   ximagesink->fps_d = 1;
2518*4882a593Smuzhiyun 
2519*4882a593Smuzhiyun   ximagesink->keep_aspect = TRUE;
2520*4882a593Smuzhiyun 
2521*4882a593Smuzhiyun   g_mutex_init (&ximagesink->x_lock);
2522*4882a593Smuzhiyun   g_mutex_init (&ximagesink->flow_lock);
2523*4882a593Smuzhiyun 
2524*4882a593Smuzhiyun   ximagesink->synchronous = FALSE;
2525*4882a593Smuzhiyun   ximagesink->handle_events = TRUE;
2526*4882a593Smuzhiyun   ximagesink->handle_expose = TRUE;
2527*4882a593Smuzhiyun 
2528*4882a593Smuzhiyun   ximagesink->fd = -1;
2529*4882a593Smuzhiyun   ximagesink->conn_id = -1;
2530*4882a593Smuzhiyun   ximagesink->plane_id = -1;
2531*4882a593Smuzhiyun   gst_poll_fd_init (&ximagesink->pollfd);
2532*4882a593Smuzhiyun   ximagesink->poll = gst_poll_new (TRUE);
2533*4882a593Smuzhiyun   gst_video_info_init (&ximagesink->vinfo);
2534*4882a593Smuzhiyun 
2535*4882a593Smuzhiyun   ximagesink->save_rect.x = 0;
2536*4882a593Smuzhiyun   ximagesink->save_rect.y = 0;
2537*4882a593Smuzhiyun   ximagesink->save_rect.w = 0;
2538*4882a593Smuzhiyun   ximagesink->save_rect.h = 0;
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun   ximagesink->paused = FALSE;
2541*4882a593Smuzhiyun 
2542*4882a593Smuzhiyun   ximagesink->devname = g_strdup ("rockchip");
2543*4882a593Smuzhiyun }
2544*4882a593Smuzhiyun 
2545*4882a593Smuzhiyun static gboolean
gst_x_image_sink_start(GstBaseSink * bsink)2546*4882a593Smuzhiyun gst_x_image_sink_start (GstBaseSink * bsink)
2547*4882a593Smuzhiyun {
2548*4882a593Smuzhiyun   GstRkXImageSink *self;
2549*4882a593Smuzhiyun   drmModeRes *res;
2550*4882a593Smuzhiyun   drmModeConnector *conn;
2551*4882a593Smuzhiyun   drmModeCrtc *crtc;
2552*4882a593Smuzhiyun   drmModePlaneRes *pres;
2553*4882a593Smuzhiyun   drmModePlane *plane;
2554*4882a593Smuzhiyun   gboolean ret;
2555*4882a593Smuzhiyun 
2556*4882a593Smuzhiyun   self = GST_X_IMAGE_SINK (bsink);
2557*4882a593Smuzhiyun   ret = FALSE;
2558*4882a593Smuzhiyun   res = NULL;
2559*4882a593Smuzhiyun   conn = NULL;
2560*4882a593Smuzhiyun   crtc = NULL;
2561*4882a593Smuzhiyun   pres = NULL;
2562*4882a593Smuzhiyun   plane = NULL;
2563*4882a593Smuzhiyun 
2564*4882a593Smuzhiyun   if (self->devname || self->bus_id)
2565*4882a593Smuzhiyun     self->fd = drmOpen (self->devname, self->bus_id);
2566*4882a593Smuzhiyun 
2567*4882a593Smuzhiyun   if (self->fd < 0)
2568*4882a593Smuzhiyun     self->fd = open ("/dev/dri/card0", O_RDWR | O_CLOEXEC);
2569*4882a593Smuzhiyun 
2570*4882a593Smuzhiyun   if (self->fd < 0)
2571*4882a593Smuzhiyun     goto open_failed;
2572*4882a593Smuzhiyun 
2573*4882a593Smuzhiyun   drm_log_version (self);
2574*4882a593Smuzhiyun   if (!drm_get_caps (self))
2575*4882a593Smuzhiyun     goto bail;
2576*4882a593Smuzhiyun 
2577*4882a593Smuzhiyun   res = drmModeGetResources (self->fd);
2578*4882a593Smuzhiyun   if (!res)
2579*4882a593Smuzhiyun     goto resources_failed;
2580*4882a593Smuzhiyun 
2581*4882a593Smuzhiyun   if (self->conn_id == -1)
2582*4882a593Smuzhiyun     conn = drm_find_main_monitor (self->fd, res);
2583*4882a593Smuzhiyun   else
2584*4882a593Smuzhiyun     conn = drmModeGetConnector (self->fd, self->conn_id);
2585*4882a593Smuzhiyun   if (!conn)
2586*4882a593Smuzhiyun     goto connector_failed;
2587*4882a593Smuzhiyun 
2588*4882a593Smuzhiyun   crtc = drm_find_crtc_for_connector (self->fd, res, conn, &self->pipe);
2589*4882a593Smuzhiyun   if (!crtc)
2590*4882a593Smuzhiyun     goto crtc_failed;
2591*4882a593Smuzhiyun 
2592*4882a593Smuzhiyun   if (drmSetClientCap (self->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1))
2593*4882a593Smuzhiyun     goto set_cap_failed;
2594*4882a593Smuzhiyun 
2595*4882a593Smuzhiyun   pres = drmModeGetPlaneResources (self->fd);
2596*4882a593Smuzhiyun   if (!pres)
2597*4882a593Smuzhiyun     goto plane_resources_failed;
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun   if (self->plane_id == -1)
2600*4882a593Smuzhiyun     plane = drm_find_plane_for_crtc_by_type (self->fd, res, pres,
2601*4882a593Smuzhiyun         crtc->crtc_id, DRM_PLANE_TYPE_OVERLAY);
2602*4882a593Smuzhiyun   else {
2603*4882a593Smuzhiyun     plane = drmModeGetPlane (self->fd, self->plane_id);
2604*4882a593Smuzhiyun     if (drm_plane_get_type (self->fd, plane) == DRM_PLANE_TYPE_PRIMARY) {
2605*4882a593Smuzhiyun       GST_ERROR_OBJECT (self, "Not support using primary plane");
2606*4882a593Smuzhiyun       goto bail;
2607*4882a593Smuzhiyun     }
2608*4882a593Smuzhiyun   }
2609*4882a593Smuzhiyun   if (!plane)
2610*4882a593Smuzhiyun     goto plane_failed;
2611*4882a593Smuzhiyun 
2612*4882a593Smuzhiyun   /* let's get the available color formats in plane */
2613*4882a593Smuzhiyun   if (!drm_ensure_allowed_caps (self, plane, res))
2614*4882a593Smuzhiyun     goto bail;
2615*4882a593Smuzhiyun 
2616*4882a593Smuzhiyun   self->conn_id = conn->connector_id;
2617*4882a593Smuzhiyun   self->crtc_id = crtc->crtc_id;
2618*4882a593Smuzhiyun   self->plane_id = plane->plane_id;
2619*4882a593Smuzhiyun 
2620*4882a593Smuzhiyun   GST_INFO_OBJECT (self, "connector id = %d / crtc id = %d / plane id = %d",
2621*4882a593Smuzhiyun       self->conn_id, self->crtc_id, self->plane_id);
2622*4882a593Smuzhiyun 
2623*4882a593Smuzhiyun   if (g_getenv ("GST_RKXIMAGE_USE_COLORKEY"))
2624*4882a593Smuzhiyun     drm_prepare_planes (self, res, pres);
2625*4882a593Smuzhiyun 
2626*4882a593Smuzhiyun   self->hdisplay = crtc->mode.hdisplay;
2627*4882a593Smuzhiyun   self->vdisplay = crtc->mode.vdisplay;
2628*4882a593Smuzhiyun   self->buffer_id = crtc->buffer_id;
2629*4882a593Smuzhiyun 
2630*4882a593Smuzhiyun   self->mm_width = conn->mmWidth;
2631*4882a593Smuzhiyun   self->mm_height = conn->mmHeight;
2632*4882a593Smuzhiyun 
2633*4882a593Smuzhiyun   GST_INFO_OBJECT (self, "display size: pixels = %dx%d / millimeters = %dx%d",
2634*4882a593Smuzhiyun       self->hdisplay, self->vdisplay, self->mm_width, self->mm_height);
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun   self->pollfd.fd = self->fd;
2637*4882a593Smuzhiyun   gst_poll_add_fd (self->poll, &self->pollfd);
2638*4882a593Smuzhiyun   gst_poll_fd_ctl_read (self->poll, &self->pollfd, TRUE);
2639*4882a593Smuzhiyun 
2640*4882a593Smuzhiyun   ret = TRUE;
2641*4882a593Smuzhiyun 
2642*4882a593Smuzhiyun bail:
2643*4882a593Smuzhiyun   if (plane)
2644*4882a593Smuzhiyun     drmModeFreePlane (plane);
2645*4882a593Smuzhiyun   if (pres)
2646*4882a593Smuzhiyun     drmModeFreePlaneResources (pres);
2647*4882a593Smuzhiyun   if (crtc)
2648*4882a593Smuzhiyun     drmModeFreeCrtc (crtc);
2649*4882a593Smuzhiyun   if (conn)
2650*4882a593Smuzhiyun     drmModeFreeConnector (conn);
2651*4882a593Smuzhiyun   if (res)
2652*4882a593Smuzhiyun     drmModeFreeResources (res);
2653*4882a593Smuzhiyun 
2654*4882a593Smuzhiyun   if (!ret && self->fd >= 0) {
2655*4882a593Smuzhiyun     drmClose (self->fd);
2656*4882a593Smuzhiyun     self->fd = -1;
2657*4882a593Smuzhiyun   }
2658*4882a593Smuzhiyun 
2659*4882a593Smuzhiyun   return ret;
2660*4882a593Smuzhiyun 
2661*4882a593Smuzhiyun   /* ERRORS */
2662*4882a593Smuzhiyun open_failed:
2663*4882a593Smuzhiyun   {
2664*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "Could not open DRM module %s: %s",
2665*4882a593Smuzhiyun         GST_STR_NULL (self->devname), strerror (errno));
2666*4882a593Smuzhiyun     return FALSE;
2667*4882a593Smuzhiyun   }
2668*4882a593Smuzhiyun resources_failed:
2669*4882a593Smuzhiyun   {
2670*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "drmModeGetResources failed: %s (%d)",
2671*4882a593Smuzhiyun         strerror (errno), errno);
2672*4882a593Smuzhiyun     goto bail;
2673*4882a593Smuzhiyun   }
2674*4882a593Smuzhiyun 
2675*4882a593Smuzhiyun connector_failed:
2676*4882a593Smuzhiyun   {
2677*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "Could not find a valid monitor connector");
2678*4882a593Smuzhiyun     goto bail;
2679*4882a593Smuzhiyun   }
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun crtc_failed:
2682*4882a593Smuzhiyun   {
2683*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "Could not find a crtc for connector");
2684*4882a593Smuzhiyun     goto bail;
2685*4882a593Smuzhiyun   }
2686*4882a593Smuzhiyun 
2687*4882a593Smuzhiyun set_cap_failed:
2688*4882a593Smuzhiyun   {
2689*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "Could not set universal planes capability bit");
2690*4882a593Smuzhiyun     goto bail;
2691*4882a593Smuzhiyun   }
2692*4882a593Smuzhiyun 
2693*4882a593Smuzhiyun plane_resources_failed:
2694*4882a593Smuzhiyun   {
2695*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "drmModeGetPlaneResources failed: %s (%d)",
2696*4882a593Smuzhiyun         strerror (errno), errno);
2697*4882a593Smuzhiyun     goto bail;
2698*4882a593Smuzhiyun   }
2699*4882a593Smuzhiyun 
2700*4882a593Smuzhiyun plane_failed:
2701*4882a593Smuzhiyun   {
2702*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "Could not find a plane for crtc");
2703*4882a593Smuzhiyun     goto bail;
2704*4882a593Smuzhiyun   }
2705*4882a593Smuzhiyun }
2706*4882a593Smuzhiyun 
2707*4882a593Smuzhiyun static gboolean
gst_x_image_sink_stop(GstBaseSink * bsink)2708*4882a593Smuzhiyun gst_x_image_sink_stop (GstBaseSink * bsink)
2709*4882a593Smuzhiyun {
2710*4882a593Smuzhiyun   GstRkXImageSink *self;
2711*4882a593Smuzhiyun 
2712*4882a593Smuzhiyun   self = GST_X_IMAGE_SINK (bsink);
2713*4882a593Smuzhiyun 
2714*4882a593Smuzhiyun   if (!EMPTY_RECT (self->clip_rect))
2715*4882a593Smuzhiyun     gst_x_image_sink_xwindow_fill_key (self, self->xwindow, 0);
2716*4882a593Smuzhiyun 
2717*4882a593Smuzhiyun   gst_buffer_replace (&self->last_buffer, NULL);
2718*4882a593Smuzhiyun   gst_caps_replace (&self->allowed_caps, NULL);
2719*4882a593Smuzhiyun   gst_object_replace ((GstObject **) & self->pool, NULL);
2720*4882a593Smuzhiyun   gst_object_replace ((GstObject **) & self->allocator, NULL);
2721*4882a593Smuzhiyun 
2722*4882a593Smuzhiyun   gst_poll_remove_fd (self->poll, &self->pollfd);
2723*4882a593Smuzhiyun   gst_poll_restart (self->poll);
2724*4882a593Smuzhiyun   gst_poll_fd_init (&self->pollfd);
2725*4882a593Smuzhiyun 
2726*4882a593Smuzhiyun   if (self->fd >= 0) {
2727*4882a593Smuzhiyun     close (self->fd);
2728*4882a593Smuzhiyun     self->fd = -1;
2729*4882a593Smuzhiyun   }
2730*4882a593Smuzhiyun 
2731*4882a593Smuzhiyun   return TRUE;
2732*4882a593Smuzhiyun }
2733*4882a593Smuzhiyun 
2734*4882a593Smuzhiyun 
2735*4882a593Smuzhiyun static void
gst_x_image_sink_class_init(GstRkXImageSinkClass * klass)2736*4882a593Smuzhiyun gst_x_image_sink_class_init (GstRkXImageSinkClass * klass)
2737*4882a593Smuzhiyun {
2738*4882a593Smuzhiyun   GObjectClass *gobject_class;
2739*4882a593Smuzhiyun   GstElementClass *gstelement_class;
2740*4882a593Smuzhiyun   GstBaseSinkClass *gstbasesink_class;
2741*4882a593Smuzhiyun   GstVideoSinkClass *videosink_class;
2742*4882a593Smuzhiyun 
2743*4882a593Smuzhiyun   gobject_class = (GObjectClass *) klass;
2744*4882a593Smuzhiyun   gstelement_class = (GstElementClass *) klass;
2745*4882a593Smuzhiyun   gstbasesink_class = (GstBaseSinkClass *) klass;
2746*4882a593Smuzhiyun   videosink_class = (GstVideoSinkClass *) klass;
2747*4882a593Smuzhiyun 
2748*4882a593Smuzhiyun   gobject_class->finalize = gst_x_image_sink_finalize;
2749*4882a593Smuzhiyun   gobject_class->set_property = gst_x_image_sink_set_property;
2750*4882a593Smuzhiyun   gobject_class->get_property = gst_x_image_sink_get_property;
2751*4882a593Smuzhiyun 
2752*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_DISPLAY,
2753*4882a593Smuzhiyun       g_param_spec_string ("display", "Display", "X Display name",
2754*4882a593Smuzhiyun           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2755*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
2756*4882a593Smuzhiyun       g_param_spec_boolean ("synchronous", "Synchronous",
2757*4882a593Smuzhiyun           "When enabled, runs the X display in synchronous mode. "
2758*4882a593Smuzhiyun           "(unrelated to A/V sync, used only for debugging)", FALSE,
2759*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2760*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
2761*4882a593Smuzhiyun       g_param_spec_boolean ("handle-events", "Handle XEvents",
2762*4882a593Smuzhiyun           "When enabled, XEvents will be selected and handled", TRUE,
2763*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2764*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
2765*4882a593Smuzhiyun       g_param_spec_boolean ("handle-expose", "Handle expose",
2766*4882a593Smuzhiyun           "When enabled, "
2767*4882a593Smuzhiyun           "the current frame will always be drawn in response to X Expose "
2768*4882a593Smuzhiyun           "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2769*4882a593Smuzhiyun 
2770*4882a593Smuzhiyun   /**
2771*4882a593Smuzhiyun    * GstRkXImageSink:window-width
2772*4882a593Smuzhiyun    *
2773*4882a593Smuzhiyun    * Actual width of the video window.
2774*4882a593Smuzhiyun    */
2775*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
2776*4882a593Smuzhiyun       g_param_spec_uint64 ("window-width", "window-width",
2777*4882a593Smuzhiyun           "Width of the window", 0, G_MAXUINT64, 0,
2778*4882a593Smuzhiyun           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun   /**
2781*4882a593Smuzhiyun    * GstRkXImageSink:window-height
2782*4882a593Smuzhiyun    *
2783*4882a593Smuzhiyun    * Actual height of the video window.
2784*4882a593Smuzhiyun    */
2785*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
2786*4882a593Smuzhiyun       g_param_spec_uint64 ("window-height", "window-height",
2787*4882a593Smuzhiyun           "Height of the window", 0, G_MAXUINT64, 0,
2788*4882a593Smuzhiyun           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
2789*4882a593Smuzhiyun 
2790*4882a593Smuzhiyun   /**
2791*4882a593Smuzhiyun    * kmssink:driver-name:
2792*4882a593Smuzhiyun    *
2793*4882a593Smuzhiyun    * If you have a system with multiple GPUs, you can choose which GPU
2794*4882a593Smuzhiyun    * to use setting the DRM device driver name. Otherwise, the first
2795*4882a593Smuzhiyun    * one from an internal list is used.
2796*4882a593Smuzhiyun    */
2797*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_DRIVER_NAME,
2798*4882a593Smuzhiyun       g_param_spec_string ("driver-name", "device name",
2799*4882a593Smuzhiyun           "DRM device driver name", NULL,
2800*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
2801*4882a593Smuzhiyun 
2802*4882a593Smuzhiyun   /**
2803*4882a593Smuzhiyun    * kmssink:bus-id:
2804*4882a593Smuzhiyun    *
2805*4882a593Smuzhiyun    * If you have a system with multiple displays for the same driver-name,
2806*4882a593Smuzhiyun    * you can choose which display to use by setting the DRM bus ID. Otherwise,
2807*4882a593Smuzhiyun    * the driver decides which one.
2808*4882a593Smuzhiyun    */
2809*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_BUS_ID,
2810*4882a593Smuzhiyun       g_param_spec_string ("bus-id", "Bus ID", "DRM bus ID", NULL,
2811*4882a593Smuzhiyun       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
2812*4882a593Smuzhiyun 
2813*4882a593Smuzhiyun   /**
2814*4882a593Smuzhiyun    * kmssink:connector-id:
2815*4882a593Smuzhiyun    *
2816*4882a593Smuzhiyun    * A GPU has several output connectors, for example: LVDS, VGA,
2817*4882a593Smuzhiyun    * HDMI, etc. By default the first LVDS is tried, then the first
2818*4882a593Smuzhiyun    * eDP, and at the end, the first connected one.
2819*4882a593Smuzhiyun    */
2820*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_CONNECTOR_ID,
2821*4882a593Smuzhiyun       g_param_spec_int ("connector-id", "Connector ID", "DRM connector id", -1,
2822*4882a593Smuzhiyun           G_MAXINT32, -1,
2823*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
2824*4882a593Smuzhiyun 
2825*4882a593Smuzhiyun    /**
2826*4882a593Smuzhiyun    * kmssink:plane-id:
2827*4882a593Smuzhiyun    *
2828*4882a593Smuzhiyun    * There could be several planes associated with a CRTC.
2829*4882a593Smuzhiyun    * By default the first plane that's possible to use with a given
2830*4882a593Smuzhiyun    * CRTC is tried.
2831*4882a593Smuzhiyun    */
2832*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_PLANE_ID,
2833*4882a593Smuzhiyun       g_param_spec_int ("plane-id", "Plane ID", "DRM plane id", -1, G_MAXINT32,
2834*4882a593Smuzhiyun           -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
2835*4882a593Smuzhiyun 
2836*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
2837*4882a593Smuzhiyun       g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
2838*4882a593Smuzhiyun       "When enabled, scaling will respect original aspect ratio", TRUE,
2839*4882a593Smuzhiyun       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2840*4882a593Smuzhiyun 
2841*4882a593Smuzhiyun   gst_element_class_set_static_metadata (gstelement_class,
2842*4882a593Smuzhiyun       "Video sink", "Sink/Video",
2843*4882a593Smuzhiyun       "A standard X based videosink", "Julien Moutte <julien@moutte.net>");
2844*4882a593Smuzhiyun 
2845*4882a593Smuzhiyun   gst_element_class_add_static_pad_template (gstelement_class,
2846*4882a593Smuzhiyun       &gst_x_image_sink_sink_template_factory);
2847*4882a593Smuzhiyun 
2848*4882a593Smuzhiyun   gstelement_class->change_state = gst_x_image_sink_change_state;
2849*4882a593Smuzhiyun 
2850*4882a593Smuzhiyun   gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_x_image_sink_start);
2851*4882a593Smuzhiyun   gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_x_image_sink_stop);
2852*4882a593Smuzhiyun   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_x_image_sink_getcaps);
2853*4882a593Smuzhiyun   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_x_image_sink_setcaps);
2854*4882a593Smuzhiyun   gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_x_image_sink_get_times);
2855*4882a593Smuzhiyun   gstbasesink_class->propose_allocation =
2856*4882a593Smuzhiyun       GST_DEBUG_FUNCPTR (gst_kms_sink_propose_allocation);
2857*4882a593Smuzhiyun   gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_kms_sink_query);
2858*4882a593Smuzhiyun   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_x_image_sink_event);
2859*4882a593Smuzhiyun 
2860*4882a593Smuzhiyun   videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_x_image_sink_show_frame);
2861*4882a593Smuzhiyun }
2862*4882a593Smuzhiyun 
2863*4882a593Smuzhiyun static gboolean
plugin_init(GstPlugin * plugin)2864*4882a593Smuzhiyun plugin_init (GstPlugin * plugin)
2865*4882a593Smuzhiyun {
2866*4882a593Smuzhiyun   if (!gst_element_register (plugin, "rkximagesink",
2867*4882a593Smuzhiyun           GST_RANK_SECONDARY, GST_TYPE_X_IMAGE_SINK))
2868*4882a593Smuzhiyun     return FALSE;
2869*4882a593Smuzhiyun 
2870*4882a593Smuzhiyun   GST_DEBUG_CATEGORY_INIT (gst_debug_x_image_sink, "rkximagesink", 0,
2871*4882a593Smuzhiyun       "rkximagesink element");
2872*4882a593Smuzhiyun 
2873*4882a593Smuzhiyun   return TRUE;
2874*4882a593Smuzhiyun }
2875*4882a593Smuzhiyun 
2876*4882a593Smuzhiyun 
2877*4882a593Smuzhiyun GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2878*4882a593Smuzhiyun     GST_VERSION_MINOR,
2879*4882a593Smuzhiyun     rkximage,
2880*4882a593Smuzhiyun     "Rockchip X/DRM Video Sink",
2881*4882a593Smuzhiyun     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
2882