[xvimagesink] fix deadlock issue
[platform/upstream/gst-plugins-base.git] / sys / xvimage / xvimageallocator.c
1 /* GStreamer
2  * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #ifdef HAVE_XSHM
25 #include <sys/types.h>
26 #include <sys/ipc.h>
27 #include <sys/shm.h>
28 #endif /* HAVE_XSHM */
29
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32
33 #ifdef HAVE_XSHM
34 #include <X11/extensions/XShm.h>
35 #endif /* HAVE_XSHM */
36
37 #include <string.h>
38 #include <math.h>
39
40 /* Object header */
41 #include "xvimageallocator.h"
42 #ifdef GST_EXT_XV_ENHANCEMENT
43 #include "xv_types.h"
44 #endif /* GST_EXT_XV_ENHANCEMENT */
45
46 /* Debugging category */
47 #include <gst/gstinfo.h>
48
49 /* Helper functions */
50 #include <gst/video/video.h>
51
52
53 GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimageallocator);
54 #define GST_CAT_DEFAULT gst_debug_xvimageallocator
55
56 struct _GstXvImageMemory
57 {
58   GstMemory parent;
59
60   gint im_format;
61   GstVideoRectangle crop;
62
63 #ifdef GST_EXT_XV_ENHANCEMENT
64   GstBuffer *current_buffer;
65 #endif /* GST_EXT_XV_ENHANCEMENT */
66
67   XvImage *xvimage;
68
69 #ifdef HAVE_XSHM
70   XShmSegmentInfo SHMInfo;
71 #endif                          /* HAVE_XSHM */
72 };
73
74
75 struct _GstXvImageAllocator
76 {
77   GstAllocator parent;
78
79   GstXvContext *context;
80 };
81
82 struct _GstXvImageAllocatorClass
83 {
84   GstAllocatorClass parent_class;
85 };
86
87 gboolean
88 gst_xvimage_memory_is_from_context (GstMemory * mem, GstXvContext * context)
89 {
90   GstXvImageAllocator *alloc;
91
92   if (!GST_IS_XVIMAGE_ALLOCATOR (mem->allocator))
93     return FALSE;
94
95   alloc = GST_XVIMAGE_ALLOCATOR_CAST (mem->allocator);
96
97   if (alloc->context != context)
98     return FALSE;
99
100   return TRUE;
101 }
102
103 gint
104 gst_xvimage_memory_get_format (GstXvImageMemory * xvmem)
105 {
106   g_return_val_if_fail (xvmem != NULL, FALSE);
107
108   return xvmem->im_format;
109 }
110
111 XvImage *
112 gst_xvimage_memory_get_xvimage (GstXvImageMemory * xvmem)
113 {
114   g_return_val_if_fail (xvmem != NULL, FALSE);
115
116   return xvmem->xvimage;
117 }
118
119 gboolean
120 gst_xvimage_memory_get_crop (GstXvImageMemory * xvmem, GstVideoRectangle * crop)
121 {
122   g_return_val_if_fail (xvmem != NULL, FALSE);
123
124   if (crop)
125     *crop = xvmem->crop;
126
127   return TRUE;
128 }
129
130
131 /* X11 stuff */
132 static gboolean error_caught = FALSE;
133
134 static int
135 gst_xvimage_handle_xerror (Display * display, XErrorEvent * xevent)
136 {
137   char error_msg[1024];
138
139   XGetErrorText (display, xevent->error_code, error_msg, 1024);
140   GST_DEBUG ("xvimage triggered an XError. error: %s", error_msg);
141   error_caught = TRUE;
142   return 0;
143 }
144
145 static GstMemory *
146 gst_xvimage_allocator_dummy_alloc (GstAllocator * allocator, gsize size,
147     GstAllocationParams * params)
148 {
149   return NULL;
150 }
151
152 static void
153 gst_xvimage_allocator_free (GstAllocator * allocator, GstMemory * gmem)
154 {
155   GstXvImageMemory *mem = (GstXvImageMemory *) gmem;
156   GstXvImageAllocator *alloc = (GstXvImageAllocator *) allocator;
157   GstXvContext *context;
158
159   if (gmem->parent)
160     goto sub_mem;
161
162   context = alloc->context;
163
164   GST_DEBUG_OBJECT (allocator, "free memory %p", mem);
165
166   g_mutex_lock (&context->lock);
167
168 #ifdef HAVE_XSHM
169   if (context->use_xshm) {
170     if (mem->SHMInfo.shmaddr != ((void *) -1)) {
171       GST_DEBUG_OBJECT (allocator, "XServer ShmDetaching from 0x%x id 0x%lx",
172           mem->SHMInfo.shmid, mem->SHMInfo.shmseg);
173       XShmDetach (context->disp, &mem->SHMInfo);
174       XSync (context->disp, FALSE);
175       shmdt (mem->SHMInfo.shmaddr);
176       mem->SHMInfo.shmaddr = (void *) -1;
177     }
178     if (mem->xvimage)
179       XFree (mem->xvimage);
180   } else
181 #endif /* HAVE_XSHM */
182   {
183     if (mem->xvimage) {
184       g_free (mem->xvimage->data);
185       XFree (mem->xvimage);
186     }
187   }
188
189   XSync (context->disp, FALSE);
190
191   g_mutex_unlock (&context->lock);
192
193 sub_mem:
194   g_slice_free (GstXvImageMemory, mem);
195 }
196
197 static gpointer
198 gst_xvimage_memory_map (GstXvImageMemory * mem, gsize maxsize,
199     GstMapFlags flags)
200 {
201   return mem->xvimage->data + mem->parent.offset;
202 }
203
204 static gboolean
205 gst_xvimage_memory_unmap (GstXvImageMemory * mem)
206 {
207   return TRUE;
208 }
209
210 static GstXvImageMemory *
211 gst_xvimage_memory_share (GstXvImageMemory * mem, gssize offset, gsize size)
212 {
213   GstXvImageMemory *sub;
214   GstMemory *parent;
215
216   /* We can only share the complete memory */
217   if (offset != 0)
218     return NULL;
219   if (size != -1 && size != mem->xvimage->data_size)
220     return NULL;
221
222   GST_DEBUG ("share memory %p", mem);
223
224   /* find the real parent */
225   if ((parent = mem->parent.parent) == NULL)
226     parent = (GstMemory *) mem;
227
228   if (size == -1)
229     size = mem->parent.size - offset;
230
231   /* the shared memory is always readonly */
232   sub = g_slice_new (GstXvImageMemory);
233
234   gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) |
235       GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->parent.allocator,
236       &mem->parent, mem->parent.maxsize, mem->parent.align,
237       mem->parent.offset + offset, size);
238
239   sub->im_format = mem->im_format;
240   sub->crop = mem->crop;
241   sub->xvimage = mem->xvimage;
242 #ifdef HAVE_XSHM
243   sub->SHMInfo = mem->SHMInfo;
244 #endif
245
246   return sub;
247 }
248
249 static GstXvImageMemory *
250 gst_xvimage_memory_copy (GstMemory * gmem, gssize offset, gsize size)
251 {
252   GstXvImageMemory *mem, *copy;
253
254   mem = (GstXvImageMemory *) gmem;
255
256   /* We can only copy the complete memory */
257   if (offset != 0)
258     return NULL;
259   if (size != -1 && size != mem->xvimage->data_size)
260     return NULL;
261
262   GST_DEBUG ("copy memory %p", mem);
263
264   copy = (GstXvImageMemory *)
265       gst_xvimage_allocator_alloc (GST_XVIMAGE_ALLOCATOR_CAST (gmem->allocator),
266       mem->im_format, mem->xvimage->width, mem->xvimage->height, &mem->crop,
267       NULL);
268
269   memcpy (copy->xvimage->data + copy->parent.offset,
270       mem->xvimage->data + mem->parent.offset, mem->xvimage->data_size);
271
272   return copy;
273 }
274
275 #define gst_xvimage_allocator_parent_class parent_class
276 G_DEFINE_TYPE (GstXvImageAllocator, gst_xvimage_allocator, GST_TYPE_ALLOCATOR);
277
278 static void gst_xvimage_allocator_finalize (GObject * object);
279
280 #define GST_XVIMAGE_ALLOCATOR_NAME "xvimage"
281
282 static void
283 gst_xvimage_allocator_class_init (GstXvImageAllocatorClass * klass)
284 {
285   GObjectClass *gobject_class;
286   GstAllocatorClass *allocator_class;
287
288   gobject_class = (GObjectClass *) klass;
289   allocator_class = (GstAllocatorClass *) klass;
290
291   gobject_class->finalize = gst_xvimage_allocator_finalize;
292
293   allocator_class->alloc = gst_xvimage_allocator_dummy_alloc;
294   allocator_class->free = gst_xvimage_allocator_free;
295
296   GST_DEBUG_CATEGORY_INIT (gst_debug_xvimageallocator, "xvimageallocator", 0,
297       "xvimageallocator object");
298 }
299
300 static void
301 gst_xvimage_allocator_init (GstXvImageAllocator * allocator)
302 {
303   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
304
305   alloc->mem_type = GST_XVIMAGE_ALLOCATOR_NAME;
306   alloc->mem_map = (GstMemoryMapFunction) gst_xvimage_memory_map;
307   alloc->mem_unmap = (GstMemoryUnmapFunction) gst_xvimage_memory_unmap;
308   alloc->mem_share = (GstMemoryShareFunction) gst_xvimage_memory_share;
309   alloc->mem_copy = (GstMemoryShareFunction) gst_xvimage_memory_copy;
310   /* fallback is_span */
311
312   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
313 }
314
315 static void
316 gst_xvimage_allocator_finalize (GObject * object)
317 {
318   GstXvImageAllocator *alloc = GST_XVIMAGE_ALLOCATOR (object);
319
320   GST_DEBUG_OBJECT (object, "finalize");
321
322   gst_xvcontext_unref (alloc->context);
323
324   G_OBJECT_CLASS (parent_class)->finalize (object);
325 }
326
327 GstXvImageAllocator *
328 gst_xvimage_allocator_new (GstXvContext * context)
329 {
330   GstXvImageAllocator *alloc;
331
332   g_return_val_if_fail (GST_IS_XVCONTEXT (context), NULL);
333
334   alloc = g_object_new (GST_TYPE_XVIMAGE_ALLOCATOR, NULL);
335   alloc->context = gst_xvcontext_ref (context);
336
337   return alloc;
338 }
339
340 GstXvContext *
341 gst_xvimage_allocator_peek_context (GstXvImageAllocator * allocator)
342 {
343   g_return_val_if_fail (GST_IS_XVIMAGE_ALLOCATOR (allocator), NULL);
344
345   return allocator->context;
346 }
347
348 GstMemory *
349 gst_xvimage_allocator_alloc (GstXvImageAllocator * allocator, gint im_format,
350     gint padded_width, gint padded_height, GstVideoRectangle * crop,
351     GError ** error)
352 {
353   int (*handler) (Display *, XErrorEvent *);
354   gboolean success = FALSE;
355   GstXvContext *context;
356   gint align = 15, offset;
357   GstXvImageMemory *mem;
358
359   context = allocator->context;
360
361   mem = g_slice_new (GstXvImageMemory);
362
363   mem->im_format = im_format;
364 #ifdef HAVE_XSHM
365   mem->SHMInfo.shmaddr = ((void *) -1);
366   mem->SHMInfo.shmid = -1;
367 #endif
368   mem->crop = *crop;
369
370   GST_DEBUG_OBJECT (allocator, "creating image %p (%dx%d) cropped %dx%d-%dx%d",
371       mem, padded_width, padded_height, crop->x, crop->y, crop->w, crop->h);
372
373   g_mutex_lock (&context->lock);
374
375   /* Setting an error handler to catch failure */
376   error_caught = FALSE;
377   handler = XSetErrorHandler (gst_xvimage_handle_xerror);
378
379 #ifdef HAVE_XSHM
380   if (context->use_xshm) {
381     int expected_size;
382
383     mem->xvimage = XvShmCreateImage (context->disp,
384         context->xv_port_id, im_format, NULL, padded_width, padded_height,
385         &mem->SHMInfo);
386     if (!mem->xvimage || error_caught) {
387       g_mutex_unlock (&context->lock);
388
389       /* Reset error flag */
390       error_caught = FALSE;
391
392       /* Push a warning */
393       GST_WARNING_OBJECT (allocator,
394           "could not XShmCreateImage a %dx%d image", padded_width,
395           padded_height);
396
397       /* Retry without XShm */
398       context->use_xshm = FALSE;
399
400       /* Hold X mutex again to try without XShm */
401       g_mutex_lock (&context->lock);
402       goto no_xshm;
403     }
404
405     /* we have to use the returned data_size for our shm size */
406     GST_LOG_OBJECT (allocator, "XShm image size is %d",
407         mem->xvimage->data_size);
408
409     /* calculate the expected size.  This is only for sanity checking the
410      * number we get from X. */
411     switch (im_format) {
412       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
413       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
414       {
415         gint pitches[3];
416         gint offsets[3];
417         guint plane;
418
419         offsets[0] = 0;
420         pitches[0] = GST_ROUND_UP_4 (padded_width);
421         offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (padded_height);
422         pitches[1] = GST_ROUND_UP_8 (padded_width) / 2;
423         offsets[2] =
424             offsets[1] + pitches[1] * GST_ROUND_UP_2 (padded_height) / 2;
425         pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
426
427         expected_size =
428             offsets[2] + pitches[2] * GST_ROUND_UP_2 (padded_height) / 2;
429
430         for (plane = 0; plane < mem->xvimage->num_planes; plane++) {
431           GST_DEBUG_OBJECT (allocator,
432               "Plane %u has a expected pitch of %d bytes, " "offset of %d",
433               plane, pitches[plane], offsets[plane]);
434         }
435         break;
436       }
437       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
438       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
439         expected_size = padded_height * GST_ROUND_UP_4 (padded_width * 2);
440         break;
441 #ifdef GST_EXT_XV_ENHANCEMENT
442       case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
443       case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
444       case GST_MAKE_FOURCC ('S', 'N', '2', '1'):
445       case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
446       case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
447       case GST_MAKE_FOURCC ('S', '4', '2', '0'):
448       case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
449         expected_size = sizeof(SCMN_IMGB);
450         break;
451 #endif /* GST_EXT_XV_ENHANCEMENT */
452       default:
453         expected_size = 0;
454         break;
455     }
456     if (expected_size != 0 && mem->xvimage->data_size != expected_size) {
457       GST_WARNING_OBJECT (allocator,
458           "unexpected XShm image size (got %d, expected %d)",
459           mem->xvimage->data_size, expected_size);
460     }
461     GST_INFO("expected XShm image size (got %d, expected %d)",
462           mem->xvimage->data_size, expected_size);
463     /* Be verbose about our XvImage stride */
464     {
465       guint plane;
466
467       for (plane = 0; plane < mem->xvimage->num_planes; plane++) {
468         GST_DEBUG_OBJECT (allocator, "Plane %u has a pitch of %d bytes, "
469             "offset of %d", plane, mem->xvimage->pitches[plane],
470             mem->xvimage->offsets[plane]);
471       }
472     }
473
474     /* get shared memory */
475     mem->SHMInfo.shmid =
476         shmget (IPC_PRIVATE, mem->xvimage->data_size + align, IPC_CREAT | 0777);
477     if (mem->SHMInfo.shmid == -1)
478       goto shmget_failed;
479
480     /* attach */
481     mem->SHMInfo.shmaddr = shmat (mem->SHMInfo.shmid, NULL, 0);
482     if (mem->SHMInfo.shmaddr == ((void *) -1))
483       goto shmat_failed;
484
485     /* now we can set up the image data */
486     mem->xvimage->data = mem->SHMInfo.shmaddr;
487     mem->SHMInfo.readOnly = FALSE;
488
489     if (XShmAttach (context->disp, &mem->SHMInfo) == 0)
490       goto xattach_failed;
491
492     XSync (context->disp, FALSE);
493
494     /* Delete the shared memory segment as soon as we everyone is attached.
495      * This way, it will be deleted as soon as we detach later, and not
496      * leaked if we crash. */
497     shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL);
498
499     GST_DEBUG_OBJECT (allocator, "XServer ShmAttached to 0x%x, id 0x%lx",
500         mem->SHMInfo.shmid, mem->SHMInfo.shmseg);
501   } else
502   no_xshm:
503 #endif /* HAVE_XSHM */
504   {
505     mem->xvimage = XvCreateImage (context->disp,
506         context->xv_port_id, im_format, NULL, padded_width, padded_height);
507     if (!mem->xvimage || error_caught)
508       goto create_failed;
509
510     /* we have to use the returned data_size for our image size */
511     mem->xvimage->data = g_malloc (mem->xvimage->data_size + align);
512
513     XSync (context->disp, FALSE);
514   }
515
516   if ((offset = ((guintptr) mem->xvimage->data & align)))
517     offset = (align + 1) - offset;
518
519   GST_DEBUG_OBJECT (allocator, "memory %p, align %d, offset %d",
520       mem->xvimage->data, align, offset);
521
522   /* Reset error handler */
523   error_caught = FALSE;
524   XSetErrorHandler (handler);
525
526   gst_memory_init (GST_MEMORY_CAST (mem), 0,
527       GST_ALLOCATOR_CAST (allocator), NULL, mem->xvimage->data_size + align,
528       align, offset, mem->xvimage->data_size);
529
530   g_mutex_unlock (&context->lock);
531
532   success = TRUE;
533
534 beach:
535   if (!success) {
536     g_slice_free (GstXvImageMemory, mem);
537     mem = NULL;
538   }
539
540   return GST_MEMORY_CAST (mem);
541
542   /* ERRORS */
543 create_failed:
544   {
545     g_mutex_unlock (&context->lock);
546     /* Reset error handler */
547     error_caught = FALSE;
548     XSetErrorHandler (handler);
549     /* Push an error */
550     g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE,
551         "could not XvShmCreateImage a %dx%d image", padded_width,
552         padded_height);
553     goto beach;
554   }
555 #ifdef HAVE_XSHM
556 shmget_failed:
557   {
558     g_mutex_unlock (&context->lock);
559     g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE,
560         "could not get shared memory of %d bytes", mem->xvimage->data_size);
561     goto beach;
562   }
563 shmat_failed:
564   {
565     g_mutex_unlock (&context->lock);
566     g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE,
567         "Failed to shmat: %s", g_strerror (errno));
568     /* Clean up the shared memory segment */
569     shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL);
570     goto beach;
571   }
572 xattach_failed:
573   {
574     /* Clean up the shared memory segment */
575     shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL);
576     g_mutex_unlock (&context->lock);
577
578     g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE,
579         "Failed to XShmAttach");
580     goto beach;
581   }
582 #endif
583 }
584
585 /* We are called with the x_lock taken */
586 static void
587 gst_xwindow_draw_borders (GstXWindow * window, GstVideoRectangle * rect)
588 {
589   gint t1, t2;
590   GstXvContext *context;
591
592   g_return_if_fail (window != NULL);
593   g_return_if_fail (rect != NULL);
594
595   context = window->context;
596
597   XSetForeground (context->disp, window->gc, context->black);
598
599   /* Left border */
600   if (rect->x > window->render_rect.x) {
601     XFillRectangle (context->disp, window->win, window->gc,
602         window->render_rect.x, window->render_rect.y,
603         rect->x - window->render_rect.x, window->render_rect.h);
604   }
605
606   /* Right border */
607   t1 = rect->x + rect->w;
608   t2 = window->render_rect.x + window->render_rect.w;
609   if (t1 < t2) {
610     XFillRectangle (context->disp, window->win, window->gc,
611         t1, window->render_rect.y, t2 - t1, window->render_rect.h);
612   }
613
614   /* Top border */
615   if (rect->y > window->render_rect.y) {
616     XFillRectangle (context->disp, window->win, window->gc,
617         window->render_rect.x, window->render_rect.y,
618         window->render_rect.w, rect->y - window->render_rect.y);
619   }
620
621   /* Bottom border */
622   t1 = rect->y + rect->h;
623   t2 = window->render_rect.y + window->render_rect.h;
624   if (t1 < t2) {
625     XFillRectangle (context->disp, window->win, window->gc,
626         window->render_rect.x, t1, window->render_rect.w, t2 - t1);
627   }
628 }
629
630 void
631 gst_xvimage_memory_render (GstXvImageMemory * mem, GstVideoRectangle * src_crop,
632     GstXWindow * window, GstVideoRectangle * dst_crop, gboolean draw_border)
633 {
634   GstXvContext *context;
635   XvImage *xvimage;
636 #ifdef GST_EXT_XV_ENHANCEMENT
637   int ret           = 0;
638   int (*handler) (Display *, XErrorEvent *) = NULL;
639   XV_DATA_PTR img_data = NULL;
640 #endif /* GST_EXT_XV_ENHANCEMENT */
641
642   context = window->context;
643
644   g_mutex_lock (&context->lock);
645   xvimage = gst_xvimage_memory_get_xvimage (mem);
646
647   if (draw_border) {
648     gst_xwindow_draw_borders (window, dst_crop);
649   }
650 #ifdef HAVE_XSHM
651   if (context->use_xshm) {
652     GST_LOG ("XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
653         GST_PTR_FORMAT, src_crop->w, src_crop->h,
654         window->render_rect.w, window->render_rect.h, mem);
655
656 #ifdef GST_EXT_XV_ENHANCEMENT
657     /* set error handler */
658     error_caught = FALSE;
659     handler = XSetErrorHandler(gst_xvimage_handle_xerror);
660
661     /* src input indicates the status when degree is 0 */
662     /* dst input indicates the area that src will be shown regardless of rotate */
663     if (context->xim_transparenter) {
664       GST_LOG_OBJECT( mem, "Transparent related issue." );
665       XPutImage(context->disp,
666         window->win,
667         window->gc,
668         context->xim_transparenter,
669         0, 0,
670         dst_crop->x, dst_crop->y, dst_crop->w, dst_crop->h);
671     }
672
673     g_mutex_lock(context->display_buffer_lock);
674     if (context->displaying_buffer_count > 3) {
675       GST_WARNING("too many buffers are pushed. skip this... [displaying_buffer_count %d]",
676                   context->displaying_buffer_count);
677     }
678     g_mutex_unlock(context->display_buffer_lock);
679
680     ret = XvShmPutImage (context->disp,
681       context->xv_port_id,
682       window->win,
683       window->gc, xvimage,
684       src_crop->x, src_crop->y, src_crop->w, src_crop->h,
685       dst_crop->x, dst_crop->y, dst_crop->w, dst_crop->h, FALSE);
686     GST_LOG_OBJECT( mem, "XvShmPutImage return value [%d]", ret );
687 #else /* GST_EXT_XV_ENHANCEMENT */
688     XvShmPutImage (context->disp,
689         context->xv_port_id,
690         window->win,
691         window->gc, xvimage,
692         src_crop->x, src_crop->y, src_crop->w, src_crop->h,
693         dst_crop->x, dst_crop->y, dst_crop->w, dst_crop->h, FALSE);
694 #endif /* GST_EXT_XV_ENHANCEMENT */
695   } else
696 #endif /* HAVE_XSHM */
697   {
698     XvPutImage (context->disp,
699         context->xv_port_id,
700         window->win,
701         window->gc, xvimage,
702         src_crop->x, src_crop->y, src_crop->w, src_crop->h,
703         dst_crop->x, dst_crop->y, dst_crop->w, dst_crop->h);
704   }
705   XSync (context->disp, FALSE);
706
707 #ifdef HAVE_XSHM
708 #ifdef GST_EXT_XV_ENHANCEMENT
709   if (ret || error_caught) {
710     GST_WARNING("putimage error : ret %d, error_caught %d, displaying buffer count %d",
711                 ret, error_caught, context->displaying_buffer_count);
712
713     /* release gem handle */
714     img_data = (XV_DATA_PTR) gst_xvimage_memory_get_xvimage(mem)->data;
715     unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
716     gem_name[0] = img_data->YBuf;
717     gem_name[1] = img_data->CbBuf;
718     gem_name[2] = img_data->CrBuf;
719     gst_xvcontext_remove_displaying_buffer(context, gem_name);
720   }
721
722   /* Reset error handler */
723   error_caught = FALSE;
724   XSetErrorHandler (handler);
725 #endif /* GST_EXT_XV_ENHANCEMENT */
726 #endif /* HAVE_XSHM */
727
728   g_mutex_unlock (&context->lock);
729 }
730
731 #ifdef GST_EXT_XV_ENHANCEMENT
732 GstBuffer* gst_xvimage_memory_get_buffer(GstXvImageMemory *mem) {
733     g_return_val_if_fail (mem, NULL);
734     return mem->current_buffer;
735 }
736
737 void gst_xvimage_memory_set_buffer(GstXvImageMemory *mem, GstBuffer *new_buf) {
738     g_return_if_fail (mem);
739     mem->current_buffer = new_buf;
740 }
741 #endif /* GST_EXT_XV_ENHANCEMENT */