static void gst_vdp_sink_window_update_geometry (VdpSink * vdp_sink, GstVdpWindow * window) { XWindowAttributes attr; g_return_if_fail (window != NULL); g_return_if_fail (GST_IS_VDP_SINK (vdp_sink)); /* Update the window geometry */ g_mutex_lock (vdp_sink->x_lock); XGetWindowAttributes (vdp_sink->device->display, window->win, &attr); window->width = attr.width; window->height = attr.height; g_mutex_unlock (vdp_sink->x_lock); }
static void gst_vdp_device_clear (VdpSink * vdp_sink) { g_return_if_fail (GST_IS_VDP_SINK (vdp_sink)); GST_OBJECT_LOCK (vdp_sink); if (vdp_sink->device == NULL) { GST_OBJECT_UNLOCK (vdp_sink); return; } GST_OBJECT_UNLOCK (vdp_sink); g_mutex_lock (vdp_sink->x_lock); g_object_unref (vdp_sink->device); vdp_sink->device = NULL; g_mutex_unlock (vdp_sink->x_lock); }
static gpointer gst_vdp_sink_event_thread (VdpSink * vdp_sink) { g_return_val_if_fail (GST_IS_VDP_SINK (vdp_sink), NULL); GST_OBJECT_LOCK (vdp_sink); while (vdp_sink->running) { GST_OBJECT_UNLOCK (vdp_sink); if (vdp_sink->window) { gst_vdp_sink_handle_xevents (vdp_sink); } g_usleep (100000); GST_OBJECT_LOCK (vdp_sink); } GST_OBJECT_UNLOCK (vdp_sink); return NULL; }
/* This function destroys a GstVdpWindow */ static void gst_vdp_sink_window_destroy (VdpSink * vdp_sink, GstVdpWindow * window) { g_return_if_fail (window != NULL); g_return_if_fail (GST_IS_VDP_SINK (vdp_sink)); g_mutex_lock (vdp_sink->x_lock); /* If we did not create that window we just free the GC and let it live */ if (window->internal) XDestroyWindow (vdp_sink->device->display, window->win); else XSelectInput (vdp_sink->device->display, window->win, 0); XSync (vdp_sink->device->display, FALSE); g_mutex_unlock (vdp_sink->x_lock); g_free (window); }
static GstFlowReturn gst_vdp_sink_show_frame (GstBaseSink * bsink, GstBuffer * outbuf) { VdpSink *vdp_sink = GST_VDP_SINK (bsink); VdpStatus status; GstVdpDevice *device; g_return_val_if_fail (GST_IS_VDP_SINK (vdp_sink), FALSE); /* We take the flow_lock. If expose is in there we don't want to run concurrently from the data flow thread */ g_mutex_lock (vdp_sink->flow_lock); if (G_UNLIKELY (vdp_sink->window == NULL)) { g_mutex_unlock (vdp_sink->flow_lock); return GST_FLOW_ERROR; } device = vdp_sink->device; if (vdp_sink->cur_image) { VdpOutputSurface surface = GST_VDP_OUTPUT_BUFFER (vdp_sink->cur_image)->surface; VdpPresentationQueueStatus queue_status; VdpTime pres_time; g_mutex_lock (vdp_sink->x_lock); status = device->vdp_presentation_queue_query_surface_status (vdp_sink-> window->queue, surface, &queue_status, &pres_time); g_mutex_unlock (vdp_sink->x_lock); if (queue_status == VDP_PRESENTATION_QUEUE_STATUS_QUEUED) { g_mutex_unlock (vdp_sink->flow_lock); return GST_FLOW_OK; } } /* Expose sends a NULL image, we take the latest frame */ if (!outbuf) { if (vdp_sink->cur_image) { outbuf = vdp_sink->cur_image; } else { g_mutex_unlock (vdp_sink->flow_lock); return GST_FLOW_OK; } } gst_vdp_sink_window_update_geometry (vdp_sink, vdp_sink->window); g_mutex_lock (vdp_sink->x_lock); status = device->vdp_presentation_queue_display (vdp_sink->window->queue, GST_VDP_OUTPUT_BUFFER (outbuf)->surface, 0, 0, 0); if (status != VDP_STATUS_OK) { GST_ELEMENT_ERROR (vdp_sink, RESOURCE, READ, ("Could not display frame"), ("Error returned from vdpau was: %s", device->vdp_get_error_string (status))); g_mutex_unlock (vdp_sink->x_lock); g_mutex_unlock (vdp_sink->flow_lock); return GST_FLOW_ERROR; } if (!vdp_sink->cur_image) vdp_sink->cur_image = gst_buffer_ref (outbuf); else if (vdp_sink->cur_image != outbuf) { gst_buffer_unref (vdp_sink->cur_image); vdp_sink->cur_image = gst_buffer_ref (outbuf); } XSync (vdp_sink->device->display, FALSE); g_mutex_unlock (vdp_sink->x_lock); g_mutex_unlock (vdp_sink->flow_lock); return GST_FLOW_OK; }
/* This function handles XEvents that might be in the queue. It generates GstEvent that will be sent upstream in the pipeline to handle interactivity and navigation.*/ static void gst_vdp_sink_handle_xevents (VdpSink * vdp_sink) { XEvent e; guint pointer_x = 0, pointer_y = 0; gboolean pointer_moved = FALSE; gboolean exposed = FALSE, configured = FALSE; g_return_if_fail (GST_IS_VDP_SINK (vdp_sink)); /* Then we get all pointer motion events, only the last position is interesting. */ g_mutex_lock (vdp_sink->flow_lock); g_mutex_lock (vdp_sink->x_lock); while (XCheckWindowEvent (vdp_sink->device->display, vdp_sink->window->win, PointerMotionMask, &e)) { g_mutex_unlock (vdp_sink->x_lock); g_mutex_unlock (vdp_sink->flow_lock); switch (e.type) { case MotionNotify: pointer_x = e.xmotion.x; pointer_y = e.xmotion.y; pointer_moved = TRUE; break; default: break; } g_mutex_lock (vdp_sink->flow_lock); g_mutex_lock (vdp_sink->x_lock); } if (pointer_moved) { g_mutex_unlock (vdp_sink->x_lock); g_mutex_unlock (vdp_sink->flow_lock); GST_DEBUG ("vdp_sink pointer moved over window at %d,%d", pointer_x, pointer_y); gst_navigation_send_mouse_event (GST_NAVIGATION (vdp_sink), "mouse-move", 0, pointer_x, pointer_y); g_mutex_lock (vdp_sink->flow_lock); g_mutex_lock (vdp_sink->x_lock); } /* We get all remaining events on our window to throw them upstream */ while (XCheckWindowEvent (vdp_sink->device->display, vdp_sink->window->win, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, &e)) { KeySym keysym; /* We lock only for the X function call */ g_mutex_unlock (vdp_sink->x_lock); g_mutex_unlock (vdp_sink->flow_lock); switch (e.type) { case ButtonPress: /* Mouse button pressed/released over our window. We send upstream events for interactivity/navigation */ GST_DEBUG ("vdp_sink button %d pressed over window at %d,%d", e.xbutton.button, e.xbutton.x, e.xbutton.x); gst_navigation_send_mouse_event (GST_NAVIGATION (vdp_sink), "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y); break; case ButtonRelease: GST_DEBUG ("vdp_sink button %d release over window at %d,%d", e.xbutton.button, e.xbutton.x, e.xbutton.x); gst_navigation_send_mouse_event (GST_NAVIGATION (vdp_sink), "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y); break; case KeyPress: case KeyRelease: /* Key pressed/released over our window. We send upstream events for interactivity/navigation */ GST_DEBUG ("vdp_sink key %d pressed over window at %d,%d", e.xkey.keycode, e.xkey.x, e.xkey.x); g_mutex_lock (vdp_sink->x_lock); keysym = XKeycodeToKeysym (vdp_sink->device->display, e.xkey.keycode, 0); g_mutex_unlock (vdp_sink->x_lock); if (keysym != NoSymbol) { char *key_str = NULL; g_mutex_lock (vdp_sink->x_lock); key_str = XKeysymToString (keysym); g_mutex_unlock (vdp_sink->x_lock); gst_navigation_send_key_event (GST_NAVIGATION (vdp_sink), e.type == KeyPress ? "key-press" : "key-release", key_str); } else { gst_navigation_send_key_event (GST_NAVIGATION (vdp_sink), e.type == KeyPress ? "key-press" : "key-release", "unknown"); } break; default: GST_DEBUG_OBJECT (vdp_sink, "vdp_sink unhandled X event (%d)", e.type); } g_mutex_lock (vdp_sink->flow_lock); g_mutex_lock (vdp_sink->x_lock); } while (XCheckWindowEvent (vdp_sink->device->display, vdp_sink->window->win, ExposureMask | StructureNotifyMask, &e)) { switch (e.type) { case Expose: exposed = TRUE; break; case ConfigureNotify: configured = TRUE; break; default: break; } } if (vdp_sink->handle_expose && (exposed || configured)) { g_mutex_unlock (vdp_sink->x_lock); g_mutex_unlock (vdp_sink->flow_lock); gst_vdp_sink_expose (GST_X_OVERLAY (vdp_sink)); g_mutex_lock (vdp_sink->flow_lock); g_mutex_lock (vdp_sink->x_lock); } /* Handle Display events */ while (XPending (vdp_sink->device->display)) { XNextEvent (vdp_sink->device->display, &e); switch (e.type) { case ClientMessage:{ Atom wm_delete; wm_delete = XInternAtom (vdp_sink->device->display, "WM_DELETE_WINDOW", False); if (wm_delete == (Atom) e.xclient.data.l[0]) { /* Handle window deletion by posting an error on the bus */ GST_ELEMENT_ERROR (vdp_sink, RESOURCE, NOT_FOUND, ("Output window was closed"), (NULL)); g_mutex_unlock (vdp_sink->x_lock); gst_vdp_sink_window_destroy (vdp_sink, vdp_sink->window); vdp_sink->window = NULL; g_mutex_lock (vdp_sink->x_lock); } break; } default: break; } } g_mutex_unlock (vdp_sink->x_lock); g_mutex_unlock (vdp_sink->flow_lock); }
/* This function handles a GstVdpWindow creation */ static GstVdpWindow * gst_vdp_sink_window_new (VdpSink * vdp_sink, gint width, gint height) { GstVdpWindow *window = NULL; GstVdpDevice *device = vdp_sink->device; Window root; gint screen_num; gulong black; VdpStatus status; VdpColor color = { 0, }; g_return_val_if_fail (GST_IS_VDP_SINK (vdp_sink), NULL); window = g_new0 (GstVdpWindow, 1); window->width = width; window->height = height; window->internal = TRUE; g_mutex_lock (vdp_sink->x_lock); screen_num = DefaultScreen (device->display); root = DefaultRootWindow (device->display); black = XBlackPixel (device->display, screen_num); window->win = XCreateSimpleWindow (vdp_sink->device->display, root, 0, 0, window->width, window->height, 0, 0, black); /* We have to do that to prevent X from redrawing the background on ConfigureNotify. This takes away flickering of video when resizing. */ XSetWindowBackgroundPixmap (vdp_sink->device->display, window->win, None); /* set application name as a title */ gst_vdp_sink_window_set_title (vdp_sink, window, NULL); if (vdp_sink->handle_events) { Atom wm_delete; XSelectInput (vdp_sink->device->display, window->win, ExposureMask | StructureNotifyMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); /* Tell the window manager we'd like delete client messages instead of * being killed */ wm_delete = XInternAtom (vdp_sink->device->display, "WM_DELETE_WINDOW", False); (void) XSetWMProtocols (vdp_sink->device->display, window->win, &wm_delete, 1); } XMapRaised (vdp_sink->device->display, window->win); XSync (vdp_sink->device->display, FALSE); g_mutex_unlock (vdp_sink->x_lock); gst_vdp_sink_window_decorate (vdp_sink, window); status = device->vdp_presentation_queue_target_create_x11 (device->device, window->win, &window->target); if (status != VDP_STATUS_OK) { GST_ELEMENT_ERROR (vdp_sink, RESOURCE, READ, ("Could not create presentation target"), ("Error returned from vdpau was: %s", device->vdp_get_error_string (status))); } status = device->vdp_presentation_queue_create (device->device, window->target, &window->queue); if (status != VDP_STATUS_OK) { GST_ELEMENT_ERROR (vdp_sink, RESOURCE, READ, ("Could not create presentation queue"), ("Error returned from vdpau was: %s", device->vdp_get_error_string (status))); } status = device->vdp_presentation_queue_set_background_color (window->queue, &color); if (status != VDP_STATUS_OK) { GST_ELEMENT_ERROR (vdp_sink, RESOURCE, READ, ("Could not set background color"), ("Error returned from vdpau was: %s", device->vdp_get_error_string (status))); } gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (vdp_sink), window->win); return window; }
/* This function handles a GstVdpWindow creation */ static GstVdpWindow * gst_vdp_sink_window_new (VdpSink * vdp_sink, gint width, gint height) { GstVdpDevice *device = vdp_sink->device; GstVdpWindow *window = NULL; Window root; gint screen_num; gulong black; g_return_val_if_fail (GST_IS_VDP_SINK (vdp_sink), NULL); window = g_new0 (GstVdpWindow, 1); window->width = width; window->height = height; window->internal = TRUE; g_mutex_lock (vdp_sink->x_lock); screen_num = DefaultScreen (device->display); root = DefaultRootWindow (device->display); black = XBlackPixel (device->display, screen_num); window->win = XCreateSimpleWindow (vdp_sink->device->display, root, 0, 0, window->width, window->height, 0, 0, black); /* We have to do that to prevent X from redrawing the background on ConfigureNotify. This takes away flickering of video when resizing. */ XSetWindowBackgroundPixmap (vdp_sink->device->display, window->win, None); /* set application name as a title */ gst_vdp_sink_window_set_title (vdp_sink, window, NULL); if (vdp_sink->handle_events) { Atom wm_delete; XSelectInput (vdp_sink->device->display, window->win, ExposureMask | StructureNotifyMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); /* Tell the window manager we'd like delete client messages instead of * being killed */ wm_delete = XInternAtom (vdp_sink->device->display, "WM_DELETE_WINDOW", False); (void) XSetWMProtocols (vdp_sink->device->display, window->win, &wm_delete, 1); } XMapRaised (vdp_sink->device->display, window->win); XSync (vdp_sink->device->display, FALSE); g_mutex_unlock (vdp_sink->x_lock); gst_vdp_sink_window_decorate (vdp_sink, window); gst_vdp_sink_window_setup_vdpau (vdp_sink, window); gst_x_overlay_got_window_handle (GST_X_OVERLAY (vdp_sink), (guintptr) window->win); return window; }