+
+
+static gboolean set_csc_range(GstXContext *xcontext, int set_range)
+{
+ int ret = 0;
+ static gboolean is_exist = FALSE;
+ static XvPortID current_port_id = -1;
+ Atom atom_csc_range = None;
+
+ if (xcontext == NULL) {
+ GST_WARNING("xcontext is NULL");
+ return FALSE;
+ }
+
+ /* check once per one xv_port_id */
+ if (current_port_id != xcontext->xv_port_id) {
+ /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
+ int i = 0;
+ int count = 0;
+ XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
+ xcontext->xv_port_id, &count);
+ if (attr) {
+ current_port_id = xcontext->xv_port_id;
+ for (i = 0 ; i < count ; i++) {
+ if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE")) {
+ is_exist = TRUE;
+ GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
+ break;
+ }
+ }
+ XFree(attr);
+ } else {
+ GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
+ xcontext->disp, xcontext->xv_port_id);
+ }
+ }
+
+ if (is_exist) {
+ GST_WARNING("set csc range %d", set_range);
+ atom_csc_range = XInternAtom(xcontext->disp,
+ "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", False);
+ ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
+ atom_csc_range, set_range);
+ if (ret == Success) {
+ return TRUE;
+ } else {
+ GST_WARNING("csc range[%d] set failed.", set_range);
+ }
+ } else {
+ GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CSC_RANGE is not existed");
+ }
+
+ return FALSE;
+}
+
+
+static void drm_init(GstXvImageSink *xvimagesink)
+{
+ Display *dpy;
+ int eventBase = 0;
+ int errorBase = 0;
+ int dri2Major = 0;
+ int dri2Minor = 0;
+ char *driverName = NULL;
+ char *deviceName = NULL;
+ struct drm_auth auth_arg = {0};
+
+ xvimagesink->drm_fd = -1;
+
+ dpy = XOpenDisplay(0);
+ if (!dpy) {
+ GST_ERROR("XOpenDisplay failed errno:%d", errno);
+ return;
+ }
+
+ GST_INFO("START");
+
+ /* DRI2 */
+ if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
+ GST_ERROR("DRI2QueryExtension !!");
+ goto DRM_INIT_ERROR;
+ }
+
+ if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
+ GST_ERROR("DRI2QueryVersion !!");
+ goto DRM_INIT_ERROR;
+ }
+
+ if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
+ GST_ERROR("DRI2Connect !!");
+ goto DRM_INIT_ERROR;
+ }
+
+ if (!driverName || !deviceName) {
+ GST_ERROR("driverName or deviceName is not valid");
+ goto DRM_INIT_ERROR;
+ }
+
+ GST_INFO("Open drm device : %s", deviceName);
+
+ /* get the drm_fd though opening the deviceName */
+ xvimagesink->drm_fd = open(deviceName, O_RDWR);
+ if (xvimagesink->drm_fd < 0) {
+ GST_ERROR("cannot open drm device (%s)", deviceName);
+ goto DRM_INIT_ERROR;
+ }
+
+ /* get magic from drm to authentication */
+ if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
+ GST_ERROR("cannot get drm auth magic [drm fd %d]", xvimagesink->drm_fd);
+ goto DRM_INIT_ERROR;
+ }
+
+ if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
+ GST_ERROR("cannot get drm authentication from X");
+ goto DRM_INIT_ERROR;
+ }
+
+ XCloseDisplay(dpy);
+ free(driverName);
+ free(deviceName);
+
+ xvimagesink->bufmgr = tbm_bufmgr_init(xvimagesink->drm_fd);
+ if (xvimagesink->bufmgr == NULL) {
+ GST_ERROR_OBJECT(xvimagesink, "tbm_bufmgr_init failed");
+ goto DRM_INIT_ERROR;
+ }
+
+ GST_INFO("DONE");
+
+ return;
+
+DRM_INIT_ERROR:
+ if (xvimagesink->drm_fd >= 0) {
+ close(xvimagesink->drm_fd);
+ xvimagesink->drm_fd = -1;
+ }
+ if (dpy) {
+ XCloseDisplay(dpy);
+ }
+ if (driverName) {
+ free(driverName);
+ }
+ if (deviceName) {
+ free(deviceName);
+ }
+
+ return;
+}
+
+static void drm_fini(GstXvImageSink *xvimagesink)
+{
+ GST_WARNING_OBJECT(xvimagesink, "START");
+
+ if (xvimagesink->drm_fd >= 0) {
+ int i = 0;
+ int j = 0;
+
+ /* close remained gem handle */
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
+ GST_WARNING_OBJECT(xvimagesink, "remained buffer %p, name %u %u %u, handle %u %u %u",
+ xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2],
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2]);
+
+ /* release flush buffer */
+ if (xvimagesink->flush_buffer) {
+ if (xvimagesink->flush_buffer->gem_name[0] == xvimagesink->displaying_buffers[i].gem_name[0] &&
+ xvimagesink->flush_buffer->gem_name[1] == xvimagesink->displaying_buffers[i].gem_name[1] &&
+ xvimagesink->flush_buffer->gem_name[2] == xvimagesink->displaying_buffers[i].gem_name[2]) {
+ _release_flush_buffer(xvimagesink);
+ }
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "Force Unref buffer");
+ }
+
+ for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
+ if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
+ drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
+ }
+ xvimagesink->displaying_buffers[i].gem_name[j] = 0;
+ xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
+ xvimagesink->displaying_buffers[i].bo[j] = NULL;
+ }
+
+ if (xvimagesink->displaying_buffers[i].buffer) {
+ gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
+ xvimagesink->displaying_buffers[i].buffer = NULL;
+ }
+ }
+ }
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ GST_WARNING_OBJECT(xvimagesink, "destroy tbm buffer manager");
+ tbm_bufmgr_deinit(xvimagesink->bufmgr);
+ xvimagesink->bufmgr = NULL;
+
+ GST_WARNING_OBJECT(xvimagesink, "close drm_fd %d", xvimagesink->drm_fd);
+ close(xvimagesink->drm_fd);
+ xvimagesink->drm_fd = -1;
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "DRM device is NOT opened");
+ }
+
+ GST_WARNING_OBJECT(xvimagesink, "DONE");
+}
+
+static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle)
+{
+ int ret = 0;
+
+ struct drm_prime_handle prime_arg = {0,};
+ struct drm_gem_flink flink_arg = {0,};
+
+ if (!xvimagesink || !gem_handle) {
+ GST_ERROR("handle[%p,%p] is NULL", xvimagesink, gem_handle);
+ return 0;
+ }
+
+ if (xvimagesink->drm_fd < 0) {
+ GST_ERROR("DRM is not opened");
+ return 0;
+ }
+
+ if (dmabuf_fd <= 0) {
+ GST_LOG("Ignore wrong dmabuf fd [%u]", dmabuf_fd);
+ return 0;
+ }
+
+ prime_arg.fd = dmabuf_fd;
+ ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg);
+ if (ret) {
+ GST_ERROR("DRM_IOCTL_PRIME_FD_TO_HANDLE failed. ret %d, dmabuf fd : %u [drm fd %d]",
+ ret, dmabuf_fd, xvimagesink->drm_fd);
+ return 0;
+ }
+
+ *gem_handle = prime_arg.handle;
+ flink_arg.handle = prime_arg.handle;
+ ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg);
+ if (ret) {
+ GST_ERROR("DRM_IOCTL_GEM_FLINK failed. ret %d, gem_handle %u, gem_name %u [drm fd %d]",
+ ret, *gem_handle, flink_arg.name, xvimagesink->drm_fd);
+ return 0;
+ }
+
+ return flink_arg.name;
+}
+
+static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle)
+{
+ struct drm_gem_close close_arg = {0,};
+
+ if (xvimagesink->drm_fd < 0 || !gem_handle) {
+ GST_ERROR("DRM is not opened");
+ return;
+ }
+
+ if (*gem_handle <= 0) {
+ GST_DEBUG("invalid gem handle %u", *gem_handle);
+ return;
+ }
+
+ GST_LOG("Call DRM_IOCTL_GEM_CLOSE - handle %u", *gem_handle);
+
+ close_arg.handle = *gem_handle;
+ if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
+ GST_ERROR("cannot close drm gem handle %u [drm fd %d]", *gem_handle, xvimagesink->drm_fd);
+ return;
+ }
+
+ *gem_handle = 0;
+
+ return;
+}
+
+
+static void _remove_last_buffer(GstXvImageSink *xvimagesink)
+{
+ gboolean enable_last_buffer = FALSE;
+
+ if (xvimagesink == NULL) {
+ GST_ERROR("handle is NULL");
+ return;
+ }
+
+ /* get enable-last-buffer */
+ g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
+
+ GST_WARNING_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
+
+ /* flush if enable-last-buffer is TRUE */
+ if (enable_last_buffer) {
+ g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
+ g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
+ }
+
+ return;
+}
+
+
+static void _release_flush_buffer(GstXvImageSink *xvimagesink)
+{
+ int i = 0;
+
+ if (xvimagesink == NULL ||
+ xvimagesink->flush_buffer == NULL) {
+ GST_WARNING("handle is NULL");
+ return;
+ }
+
+ GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER");
+
+ for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
+ if (xvimagesink->flush_buffer->bo[i]) {
+ tbm_bo_unref(xvimagesink->flush_buffer->bo[i]);
+ xvimagesink->flush_buffer->bo[i] = NULL;
+ }
+ }
+
+ GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER done");
+
+ free(xvimagesink->flush_buffer);
+ xvimagesink->flush_buffer = NULL;
+
+ return;
+}
+
+
+static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer)
+{
+ int i = 0;
+ int j = 0;
+
+ if (!xvimagesink || !img_data) {
+ GST_ERROR("handle is NULL %p, %p", xvimagesink, img_data);
+ return;
+ }
+
+ /* lock display buffer mutex */
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+
+ /* increase displaying buffer count */
+ xvimagesink->displaying_buffer_count++;
+
+ /* check duplicated */
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
+ if ((img_data->dmabuf_fd[0] > 0 &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
+ (img_data->bo[0] &&
+ xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
+ xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
+ xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
+ /* increase ref count */
+ xvimagesink->displaying_buffers[i].ref_count++;
+
+ /* set buffer info */
+ img_data->YBuf = xvimagesink->displaying_buffers[i].gem_name[0];
+ img_data->CbBuf = xvimagesink->displaying_buffers[i].gem_name[1];
+ img_data->CrBuf = xvimagesink->displaying_buffers[i].gem_name[2];
+
+ if (img_data->dmabuf_fd[0] > 0) {
+ GST_WARNING("already converted fd [%u %u %u] name [%u %u %u]",
+ img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2],
+ img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
+ } else {
+ GST_WARNING("already exported bo [%p %p %p] gem name [%u %u %u]",
+ img_data->bo[0], img_data->bo[1], img_data->bo[2],
+ img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
+ }
+
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+ return;
+ }
+ }
+ }
+
+ /* store buffer temporarily */
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] == 0) {
+ if (buffer) {
+ /* increase ref count of buffer */
+ gst_buffer_ref(buffer);
+ xvimagesink->displaying_buffers[i].buffer = buffer;
+ }
+
+ if (img_data->dmabuf_fd[0] > 0) {
+ /* convert fd to name */
+ img_data->YBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[0], &img_data->gem_handle[0]);
+ img_data->CbBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[1], &img_data->gem_handle[1]);
+ img_data->CrBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[2], &img_data->gem_handle[2]);
+ } else {
+ /* export bo */
+ if (img_data->bo[0]) {
+ img_data->YBuf = tbm_bo_export(img_data->bo[0]);
+ }
+ if (img_data->bo[1]) {
+ img_data->CbBuf = tbm_bo_export(img_data->bo[1]);
+ }
+ if (img_data->bo[2]) {
+ img_data->CrBuf = tbm_bo_export(img_data->bo[2]);
+ }
+ }
+
+ for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
+ xvimagesink->displaying_buffers[i].dmabuf_fd[j] = img_data->dmabuf_fd[j];
+ xvimagesink->displaying_buffers[i].gem_handle[j] = img_data->gem_handle[j];
+ xvimagesink->displaying_buffers[i].bo[j] = img_data->bo[j];
+ }
+
+ /* set buffer info */
+ xvimagesink->displaying_buffers[i].gem_name[0] = img_data->YBuf;
+ xvimagesink->displaying_buffers[i].gem_name[1] = img_data->CbBuf;
+ xvimagesink->displaying_buffers[i].gem_name[2] = img_data->CrBuf;
+
+ /* set ref count */
+ xvimagesink->displaying_buffers[i].ref_count = 1;
+
+ if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
+ GST_WARNING_OBJECT(xvimagesink, "cnt %d - add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
+ xvimagesink->displayed_buffer_count,
+ i, xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].dmabuf_fd[0],
+ xvimagesink->displaying_buffers[i].dmabuf_fd[1],
+ xvimagesink->displaying_buffers[i].dmabuf_fd[2],
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2],
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2]);
+ } else {
+ GST_DEBUG_OBJECT(xvimagesink, "add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
+ i, xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].dmabuf_fd[0],
+ xvimagesink->displaying_buffers[i].dmabuf_fd[1],
+ xvimagesink->displaying_buffers[i].dmabuf_fd[2],
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2],
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2]);
+ }
+
+ /* set last added buffer index */
+ xvimagesink->last_added_buffer_index = i;
+ GST_LOG_OBJECT(xvimagesink, "xvimagesink->last_added_buffer_index %d", i);
+
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ /* get current time */
+ gettimeofday(&xvimagesink->request_time[i], NULL);
+ return;
+ }
+ }
+
+ /* decrease displaying buffer count */
+ xvimagesink->displaying_buffer_count--;
+
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ GST_ERROR("should not be reached here. buffer slot is FULL...");
+
+ return;
+}
+
+
+static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name)
+{
+ int i = 0;
+ int j = 0;
+
+ if (!xvimagesink || !gem_name) {
+ GST_ERROR_OBJECT(xvimagesink, "handle is NULL %p, %p", xvimagesink, gem_name);
+ return;
+ }
+
+ /* lock display buffer mutex */
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+
+ if (xvimagesink->displaying_buffer_count == 0) {
+ GST_WARNING_OBJECT(xvimagesink, "there is no displaying buffer");
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+ return;
+ }
+
+ GST_DEBUG_OBJECT(xvimagesink, "gem name [%u %u %u], displaying buffer count %d",
+ gem_name[0], gem_name[1], gem_name[2],
+ xvimagesink->displaying_buffer_count);
+
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] == gem_name[0] &&
+ xvimagesink->displaying_buffers[i].gem_name[1] == gem_name[1] &&
+ xvimagesink->displaying_buffers[i].gem_name[2] == gem_name[2]) {
+ struct timeval current_time;
+
+ /* get current time to calculate displaying time */
+ gettimeofday(¤t_time, NULL);
+
+ GST_DEBUG_OBJECT(xvimagesink, "buffer return time %8d us",
+ (current_time.tv_sec - xvimagesink->request_time[i].tv_sec)*1000000 + \
+ (current_time.tv_usec - xvimagesink->request_time[i].tv_usec));
+
+ if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
+ xvimagesink->displayed_buffer_count++;
+ GST_WARNING_OBJECT(xvimagesink, "cnt %d - remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
+ xvimagesink->displayed_buffer_count,
+ i, xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2],
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2]);
+ } else {
+ GST_DEBUG_OBJECT(xvimagesink, "remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
+ i, xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2],
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2]);
+ }
+
+ /* decrease displaying buffer count */
+ xvimagesink->displaying_buffer_count--;
+
+ /* decrease ref count */
+ xvimagesink->displaying_buffers[i].ref_count--;
+
+ if (xvimagesink->displaying_buffers[i].ref_count > 0) {
+ GST_WARNING("ref count not zero[%d], skip close gem handle",
+ xvimagesink->displaying_buffers[i].ref_count);
+ break;
+ }
+
+ /* release flush buffer */
+ if (xvimagesink->flush_buffer) {
+ if (xvimagesink->flush_buffer->gem_name[0] == gem_name[0] &&
+ xvimagesink->flush_buffer->gem_name[1] == gem_name[1] &&
+ xvimagesink->flush_buffer->gem_name[2] == gem_name[2]) {
+ _release_flush_buffer(xvimagesink);
+ }
+ }
+
+ for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
+ if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
+ drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
+ }
+ xvimagesink->displaying_buffers[i].gem_name[j] = 0;
+ xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
+ xvimagesink->displaying_buffers[i].bo[j] = NULL;
+ }
+
+ /* reset last_added_buffer_index */
+ if (xvimagesink->displaying_buffer_count < 1) {
+ xvimagesink->last_added_buffer_index = -1;
+ GST_DEBUG_OBJECT(xvimagesink, "displaying_buffer_count %d",
+ xvimagesink->displaying_buffer_count);
+ }
+
+ if (xvimagesink->displaying_buffers[i].buffer) {
+ gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
+ xvimagesink->displaying_buffers[i].buffer = NULL;
+ } else {
+ GST_WARNING("no buffer to unref");
+ }
+ break;
+ }
+ }
+
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ return;
+}
+
+
+static int _is_connected_to_external_display(GstXvImageSink *xvimagesink)
+{
+ Atom type_ret = 0;
+ int i = 0;
+ int ret = 0;
+ int size_ret = 0;
+ unsigned long num_ret = 0;
+ unsigned long bytes = 0;
+ unsigned char *prop_ret = NULL;
+ unsigned int data = 0;
+ int (*handler) (Display *, XErrorEvent *) = NULL;
+ Atom atom_output_external;
+
+ atom_output_external = XInternAtom(xvimagesink->xcontext->disp,
+ "XV_OUTPUT_EXTERNAL", False);
+ if (atom_output_external != None) {
+ /* set error handler */
+ error_caught = FALSE;
+ handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
+
+ ret = XGetWindowProperty(xvimagesink->xcontext->disp,
+ xvimagesink->xwindow->win,
+ atom_output_external, 0, 0x7fffffff,
+ False, XA_CARDINAL, &type_ret, &size_ret,
+ &num_ret, &bytes, &prop_ret);
+ XSync(xvimagesink->xcontext->disp, FALSE);
+ if (ret != Success || error_caught) {
+ GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty failed");
+ if (prop_ret) {
+ XFree(prop_ret);
+ }
+ if (error_caught) {
+ GST_WARNING_OBJECT(xvimagesink, "error caught in XGetWindowProperty()");
+ }
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+ return False;
+ }
+
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+
+ if (!num_ret) {
+ GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty num_ret failed");
+ if (prop_ret) {
+ XFree(prop_ret);
+ }
+ return False;
+ }
+
+ if (prop_ret) {
+ switch (size_ret) {
+ case 8:
+ for (i = 0 ; i < num_ret ; i++) {
+ (&data)[i] = prop_ret[i];
+ }
+ break;
+ case 16:
+ for (i = 0 ; i < num_ret ; i++) {
+ ((unsigned short *)&data)[i] = ((unsigned short *)prop_ret)[i];
+ }
+ break;
+ case 32:
+ for (i = 0 ; i < num_ret ; i++) {
+ ((unsigned int *)&data)[i] = ((unsigned long *)prop_ret)[i];
+ }
+ break;
+ }
+ XFree(prop_ret);
+ prop_ret = NULL;
+
+ GST_WARNING_OBJECT(xvimagesink, "external display %d", data);
+
+ return (int)data;
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "prop_ret is NULL");
+ return False;
+ }
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "get XV_OUTPUT_EXTERNAL atom failed");
+ }
+
+ return False;
+}