docs: fix up some more GstXOverlay -> GstVideoOverlay
[platform/upstream/gstreamer.git] / sys / xvimage / xvimagepool.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 /* Object header */
25 #include "xvimagesink.h"
26
27 /* Debugging category */
28 #include <gst/gstinfo.h>
29
30 /* Helper functions */
31 #include <gst/video/video.h>
32 #include <gst/video/gstvideometa.h>
33 #include <gst/video/gstvideopool.h>
34
35
36 GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagepool);
37 #define GST_CAT_DEFAULT gst_debug_xvimagepool
38
39
40 struct _GstXvImageBufferPoolPrivate
41 {
42   GstCaps *caps;
43   gint im_format;
44   GstVideoInfo info;
45   GstVideoAlignment align;
46   guint padded_width;
47   guint padded_height;
48   gboolean add_metavideo;
49   gboolean need_alignment;
50 };
51
52 static void gst_xvimage_meta_free (GstXvImageMeta * meta, GstBuffer * buffer);
53
54 /* xvimage metadata */
55 GType
56 gst_xvimage_meta_api_get_type (void)
57 {
58   static volatile GType type;
59   static const gchar *tags[] =
60       { "memory", "size", "colorspace", "orientation", NULL };
61
62   if (g_once_init_enter (&type)) {
63     GType _type = gst_meta_api_type_register ("GstXvImageMetaAPI", tags);
64     g_once_init_leave (&type, _type);
65   }
66   return type;
67 }
68
69 const GstMetaInfo *
70 gst_xvimage_meta_get_info (void)
71 {
72   static const GstMetaInfo *xvimage_meta_info = NULL;
73
74   if (g_once_init_enter (&xvimage_meta_info)) {
75     const GstMetaInfo *meta =
76         gst_meta_register (GST_XVIMAGE_META_API_TYPE, "GstXvImageMeta",
77         sizeof (GstXvImageMeta), (GstMetaInitFunction) NULL,
78         (GstMetaFreeFunction) gst_xvimage_meta_free,
79         (GstMetaTransformFunction) NULL);
80     g_once_init_leave (&xvimage_meta_info, meta);
81   }
82   return xvimage_meta_info;
83 }
84
85 /* X11 stuff */
86 static gboolean error_caught = FALSE;
87
88 static int
89 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
90 {
91   char error_msg[1024];
92
93   XGetErrorText (display, xevent->error_code, error_msg, 1024);
94   GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
95   error_caught = TRUE;
96   return 0;
97 }
98
99 static GstXvImageMeta *
100 gst_buffer_add_xvimage_meta (GstBuffer * buffer, GstXvImageBufferPool * xvpool)
101 {
102   GstXvImageSink *xvimagesink;
103   int (*handler) (Display *, XErrorEvent *);
104   gboolean success = FALSE;
105   GstXContext *xcontext;
106   GstXvImageMeta *meta;
107   gint width, height, im_format, align = 15, offset;
108   GstXvImageBufferPoolPrivate *priv;
109
110   priv = xvpool->priv;
111   xvimagesink = xvpool->sink;
112   xcontext = xvimagesink->xcontext;
113
114   width = priv->padded_width;
115   height = priv->padded_height;
116   im_format = priv->im_format;
117
118   meta =
119       (GstXvImageMeta *) gst_buffer_add_meta (buffer, GST_XVIMAGE_META_INFO,
120       NULL);
121 #ifdef HAVE_XSHM
122   meta->SHMInfo.shmaddr = ((void *) -1);
123   meta->SHMInfo.shmid = -1;
124 #endif
125   meta->x = priv->align.padding_left;
126   meta->y = priv->align.padding_top;
127   meta->width = priv->info.width;
128   meta->height = priv->info.height;
129   meta->sink = gst_object_ref (xvimagesink);
130   meta->im_format = im_format;
131
132   GST_DEBUG_OBJECT (xvimagesink, "creating image %p (%dx%d)", buffer,
133       width, height);
134
135   g_mutex_lock (&xvimagesink->x_lock);
136
137   /* Setting an error handler to catch failure */
138   error_caught = FALSE;
139   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
140
141 #ifdef HAVE_XSHM
142   if (xcontext->use_xshm) {
143     int expected_size;
144
145     meta->xvimage = XvShmCreateImage (xcontext->disp,
146         xcontext->xv_port_id, im_format, NULL, width, height, &meta->SHMInfo);
147     if (!meta->xvimage || error_caught) {
148       g_mutex_unlock (&xvimagesink->x_lock);
149
150       /* Reset error flag */
151       error_caught = FALSE;
152
153       /* Push a warning */
154       GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
155           ("Failed to create output image buffer of %dx%d pixels",
156               width, height),
157           ("could not XShmCreateImage a %dx%d image", width, height));
158
159       /* Retry without XShm */
160       xvimagesink->xcontext->use_xshm = FALSE;
161
162       /* Hold X mutex again to try without XShm */
163       g_mutex_lock (&xvimagesink->x_lock);
164       goto no_xshm;
165     }
166
167     /* we have to use the returned data_size for our shm size */
168     meta->size = meta->xvimage->data_size;
169     GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
170         meta->size);
171
172     /* calculate the expected size.  This is only for sanity checking the
173      * number we get from X. */
174     switch (im_format) {
175       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
176       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
177       {
178         gint pitches[3];
179         gint offsets[3];
180         guint plane;
181
182         offsets[0] = 0;
183         pitches[0] = GST_ROUND_UP_4 (width);
184         offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (height);
185         pitches[1] = GST_ROUND_UP_8 (width) / 2;
186         offsets[2] = offsets[1] + pitches[1] * GST_ROUND_UP_2 (height) / 2;
187         pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
188
189         expected_size = offsets[2] + pitches[2] * GST_ROUND_UP_2 (height) / 2;
190
191         for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
192           GST_DEBUG_OBJECT (xvimagesink,
193               "Plane %u has a expected pitch of %d bytes, " "offset of %d",
194               plane, pitches[plane], offsets[plane]);
195         }
196         break;
197       }
198       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
199       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
200         expected_size = height * GST_ROUND_UP_4 (width * 2);
201         break;
202       default:
203         expected_size = 0;
204         break;
205     }
206     if (expected_size != 0 && meta->size != expected_size) {
207       GST_WARNING_OBJECT (xvimagesink,
208           "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
209           meta->size, expected_size);
210     }
211
212     /* Be verbose about our XvImage stride */
213     {
214       guint plane;
215
216       for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
217         GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
218             "offset of %d", plane, meta->xvimage->pitches[plane],
219             meta->xvimage->offsets[plane]);
220       }
221     }
222
223     /* get shared memory */
224     meta->SHMInfo.shmid =
225         shmget (IPC_PRIVATE, meta->size + align, IPC_CREAT | 0777);
226     if (meta->SHMInfo.shmid == -1)
227       goto shmget_failed;
228
229     /* attach */
230     meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0);
231     if (meta->SHMInfo.shmaddr == ((void *) -1))
232       goto shmat_failed;
233
234     /* now we can set up the image data */
235     meta->xvimage->data = meta->SHMInfo.shmaddr;
236     meta->SHMInfo.readOnly = FALSE;
237
238     if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
239       goto xattach_failed;
240
241     XSync (xcontext->disp, FALSE);
242
243     /* Delete the shared memory segment as soon as we everyone is attached.
244      * This way, it will be deleted as soon as we detach later, and not
245      * leaked if we crash. */
246     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
247
248     GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
249         meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
250   } else
251   no_xshm:
252 #endif /* HAVE_XSHM */
253   {
254     meta->xvimage = XvCreateImage (xcontext->disp,
255         xcontext->xv_port_id, im_format, NULL, width, height);
256     if (!meta->xvimage || error_caught)
257       goto create_failed;
258
259     /* we have to use the returned data_size for our image size */
260     meta->size = meta->xvimage->data_size;
261     meta->xvimage->data = g_malloc (meta->size + align);
262
263     XSync (xcontext->disp, FALSE);
264   }
265
266   if ((offset = ((guintptr) meta->xvimage->data & align)))
267     offset = (align + 1) - offset;
268
269   GST_DEBUG_OBJECT (xvimagesink, "memory %p, align %d, offset %d",
270       meta->xvimage->data, align, offset);
271
272   /* Reset error handler */
273   error_caught = FALSE;
274   XSetErrorHandler (handler);
275
276   gst_buffer_append_memory (buffer,
277       gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->xvimage->data,
278           meta->size + align, offset, meta->size, NULL, NULL));
279
280   g_mutex_unlock (&xvimagesink->x_lock);
281
282   success = TRUE;
283
284 beach:
285   if (!success)
286     meta = NULL;
287
288   return meta;
289
290   /* ERRORS */
291 create_failed:
292   {
293     g_mutex_unlock (&xvimagesink->x_lock);
294     /* Reset error handler */
295     error_caught = FALSE;
296     XSetErrorHandler (handler);
297     /* Push an error */
298     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
299         ("Failed to create output image buffer of %dx%d pixels",
300             width, height),
301         ("could not XvShmCreateImage a %dx%d image", width, height));
302     goto beach;
303   }
304 #ifdef HAVE_XSHM
305 shmget_failed:
306   {
307     g_mutex_unlock (&xvimagesink->x_lock);
308     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
309         ("Failed to create output image buffer of %dx%d pixels",
310             width, height),
311         ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
312             meta->size));
313     goto beach;
314   }
315 shmat_failed:
316   {
317     g_mutex_unlock (&xvimagesink->x_lock);
318     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
319         ("Failed to create output image buffer of %dx%d pixels",
320             width, height), ("Failed to shmat: %s", g_strerror (errno)));
321     /* Clean up the shared memory segment */
322     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
323     goto beach;
324   }
325 xattach_failed:
326   {
327     /* Clean up the shared memory segment */
328     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
329     g_mutex_unlock (&xvimagesink->x_lock);
330
331     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
332         ("Failed to create output image buffer of %dx%d pixels",
333             width, height), ("Failed to XShmAttach"));
334     goto beach;
335   }
336 #endif
337 }
338
339 static void
340 gst_xvimage_meta_free (GstXvImageMeta * meta, GstBuffer * buffer)
341 {
342   GstXvImageSink *xvimagesink;
343
344   xvimagesink = meta->sink;
345
346   GST_DEBUG_OBJECT (xvimagesink, "free meta on buffer %p", buffer);
347
348   /* Hold the object lock to ensure the XContext doesn't disappear */
349   GST_OBJECT_LOCK (xvimagesink);
350   /* We might have some buffers destroyed after changing state to NULL */
351   if (xvimagesink->xcontext == NULL) {
352     GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
353 #ifdef HAVE_XSHM
354     /* Need to free the shared memory segment even if the x context
355      * was already cleaned up */
356     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
357       shmdt (meta->SHMInfo.shmaddr);
358     }
359 #endif
360     if (meta->xvimage)
361       XFree (meta->xvimage);
362     goto beach;
363   }
364
365   g_mutex_lock (&xvimagesink->x_lock);
366
367 #ifdef HAVE_XSHM
368   if (xvimagesink->xcontext->use_xshm) {
369     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
370       GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
371           meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
372       XShmDetach (xvimagesink->xcontext->disp, &meta->SHMInfo);
373       XSync (xvimagesink->xcontext->disp, FALSE);
374       shmdt (meta->SHMInfo.shmaddr);
375       meta->SHMInfo.shmaddr = (void *) -1;
376     }
377     if (meta->xvimage)
378       XFree (meta->xvimage);
379   } else
380 #endif /* HAVE_XSHM */
381   {
382     if (meta->xvimage) {
383       g_free (meta->xvimage->data);
384       XFree (meta->xvimage);
385     }
386   }
387
388   XSync (xvimagesink->xcontext->disp, FALSE);
389
390   g_mutex_unlock (&xvimagesink->x_lock);
391
392 beach:
393   GST_OBJECT_UNLOCK (xvimagesink);
394
395   gst_object_unref (meta->sink);
396 }
397
398 #ifdef HAVE_XSHM
399 /* This function checks that it is actually really possible to create an image
400    using XShm */
401 gboolean
402 gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink,
403     GstXContext * xcontext)
404 {
405   XvImage *xvimage;
406   XShmSegmentInfo SHMInfo;
407   size_t size;
408   int (*handler) (Display *, XErrorEvent *);
409   gboolean result = FALSE;
410   gboolean did_attach = FALSE;
411
412   g_return_val_if_fail (xcontext != NULL, FALSE);
413
414   /* Sync to ensure any older errors are already processed */
415   XSync (xcontext->disp, FALSE);
416
417   /* Set defaults so we don't free these later unnecessarily */
418   SHMInfo.shmaddr = ((void *) -1);
419   SHMInfo.shmid = -1;
420
421   /* Setting an error handler to catch failure */
422   error_caught = FALSE;
423   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
424
425   /* Trying to create a 1x1 picture */
426   GST_DEBUG ("XvShmCreateImage of 1x1");
427   xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
428       xcontext->im_format, NULL, 1, 1, &SHMInfo);
429
430   /* Might cause an error, sync to ensure it is noticed */
431   XSync (xcontext->disp, FALSE);
432   if (!xvimage || error_caught) {
433     GST_WARNING ("could not XvShmCreateImage a 1x1 image");
434     goto beach;
435   }
436   size = xvimage->data_size;
437
438   SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
439   if (SHMInfo.shmid == -1) {
440     GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
441         size);
442     goto beach;
443   }
444
445   SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
446   if (SHMInfo.shmaddr == ((void *) -1)) {
447     GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
448     /* Clean up the shared memory segment */
449     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
450     goto beach;
451   }
452
453   xvimage->data = SHMInfo.shmaddr;
454   SHMInfo.readOnly = FALSE;
455
456   if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
457     GST_WARNING ("Failed to XShmAttach");
458     /* Clean up the shared memory segment */
459     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
460     goto beach;
461   }
462
463   /* Sync to ensure we see any errors we caused */
464   XSync (xcontext->disp, FALSE);
465
466   /* Delete the shared memory segment as soon as everyone is attached.
467    * This way, it will be deleted as soon as we detach later, and not
468    * leaked if we crash. */
469   shmctl (SHMInfo.shmid, IPC_RMID, NULL);
470
471   if (!error_caught) {
472     GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
473         SHMInfo.shmseg);
474
475     did_attach = TRUE;
476     /* store whether we succeeded in result */
477     result = TRUE;
478   } else {
479     GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
480         "Not using shared memory.");
481   }
482
483 beach:
484   /* Sync to ensure we swallow any errors we caused and reset error_caught */
485   XSync (xcontext->disp, FALSE);
486
487   error_caught = FALSE;
488   XSetErrorHandler (handler);
489
490   if (did_attach) {
491     GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
492         SHMInfo.shmid, SHMInfo.shmseg);
493     XShmDetach (xcontext->disp, &SHMInfo);
494     XSync (xcontext->disp, FALSE);
495   }
496   if (SHMInfo.shmaddr != ((void *) -1))
497     shmdt (SHMInfo.shmaddr);
498   if (xvimage)
499     XFree (xvimage);
500   return result;
501 }
502 #endif /* HAVE_XSHM */
503
504 /* bufferpool */
505 static void gst_xvimage_buffer_pool_finalize (GObject * object);
506
507 #define GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE(obj)  \
508    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL, GstXvImageBufferPoolPrivate))
509
510 #define gst_xvimage_buffer_pool_parent_class parent_class
511 G_DEFINE_TYPE (GstXvImageBufferPool, gst_xvimage_buffer_pool,
512     GST_TYPE_BUFFER_POOL);
513
514 static const gchar **
515 xvimage_buffer_pool_get_options (GstBufferPool * pool)
516 {
517   static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
518     GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL
519   };
520
521   return options;
522 }
523
524 static gboolean
525 xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
526 {
527   GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
528   GstXvImageBufferPoolPrivate *priv = xvpool->priv;
529   GstVideoInfo info;
530   GstCaps *caps;
531
532   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
533     goto wrong_config;
534
535   if (caps == NULL)
536     goto no_caps;
537
538   /* now parse the caps from the config */
539   if (!gst_video_info_from_caps (&info, caps))
540     goto wrong_caps;
541
542   GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
543       caps);
544
545   priv->im_format = gst_xvimagesink_get_format_from_info (xvpool->sink, &info);
546   if (priv->im_format == -1)
547     goto unknown_format;
548
549   if (priv->caps)
550     gst_caps_unref (priv->caps);
551   priv->caps = gst_caps_ref (caps);
552
553   /* enable metadata based on config of the pool */
554   priv->add_metavideo =
555       gst_buffer_pool_config_has_option (config,
556       GST_BUFFER_POOL_OPTION_VIDEO_META);
557
558   /* parse extra alignment info */
559   priv->need_alignment = gst_buffer_pool_config_has_option (config,
560       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
561
562   if (priv->need_alignment) {
563     gst_buffer_pool_config_get_video_alignment (config, &priv->align);
564
565     GST_LOG_OBJECT (pool, "padding %u-%ux%u-%u", priv->align.padding_top,
566         priv->align.padding_left, priv->align.padding_left,
567         priv->align.padding_bottom);
568
569     /* do padding and alignment */
570     gst_video_info_align (&info, &priv->align);
571
572     /* we need the video metadata too now */
573     priv->add_metavideo = TRUE;
574   } else {
575     gst_video_alignment_reset (&priv->align);
576   }
577
578   /* add the padding */
579   priv->padded_width =
580       GST_VIDEO_INFO_WIDTH (&info) + priv->align.padding_left +
581       priv->align.padding_right;
582   priv->padded_height =
583       GST_VIDEO_INFO_HEIGHT (&info) + priv->align.padding_top +
584       priv->align.padding_bottom;
585
586   priv->info = info;
587
588   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
589
590   /* ERRORS */
591 wrong_config:
592   {
593     GST_WARNING_OBJECT (pool, "invalid config");
594     return FALSE;
595   }
596 no_caps:
597   {
598     GST_WARNING_OBJECT (pool, "no caps in config");
599     return FALSE;
600   }
601 wrong_caps:
602   {
603     GST_WARNING_OBJECT (pool,
604         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
605     return FALSE;
606   }
607 unknown_format:
608   {
609     GST_WARNING_OBJECT (xvpool->sink, "failed to get format from caps %"
610         GST_PTR_FORMAT, caps);
611     GST_ELEMENT_ERROR (xvpool->sink, RESOURCE, WRITE,
612         ("Failed to create output image buffer of %dx%d pixels",
613             priv->info.width, priv->info.height),
614         ("Invalid input caps %" GST_PTR_FORMAT, caps));
615     return FALSE;;
616   }
617 }
618
619 /* This function handles GstXImageBuffer creation depending on XShm availability */
620 static GstFlowReturn
621 xvimage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
622     GstBufferPoolAcquireParams * params)
623 {
624   GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
625   GstXvImageBufferPoolPrivate *priv = xvpool->priv;
626   GstVideoInfo *info;
627   GstBuffer *xvimage;
628   GstXvImageMeta *meta;
629
630   info = &priv->info;
631
632   xvimage = gst_buffer_new ();
633   meta = gst_buffer_add_xvimage_meta (xvimage, xvpool);
634   if (meta == NULL) {
635     gst_buffer_unref (xvimage);
636     goto no_buffer;
637   }
638
639   if (priv->add_metavideo) {
640     GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
641     gst_buffer_add_video_meta_full (xvimage, GST_VIDEO_FRAME_FLAG_NONE,
642         GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
643         GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
644         info->offset, info->stride);
645   }
646
647   *buffer = xvimage;
648
649   return GST_FLOW_OK;
650
651   /* ERROR */
652 no_buffer:
653   {
654     GST_WARNING_OBJECT (pool, "can't create image");
655     return GST_FLOW_ERROR;
656   }
657 }
658
659 GstBufferPool *
660 gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink)
661 {
662   GstXvImageBufferPool *pool;
663
664   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
665
666   pool = g_object_new (GST_TYPE_XVIMAGE_BUFFER_POOL, NULL);
667   pool->sink = gst_object_ref (xvimagesink);
668
669   GST_LOG_OBJECT (pool, "new XvImage buffer pool %p", pool);
670
671   return GST_BUFFER_POOL_CAST (pool);
672 }
673
674 static void
675 gst_xvimage_buffer_pool_class_init (GstXvImageBufferPoolClass * klass)
676 {
677   GObjectClass *gobject_class = (GObjectClass *) klass;
678   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
679
680   g_type_class_add_private (klass, sizeof (GstXvImageBufferPoolPrivate));
681
682   gobject_class->finalize = gst_xvimage_buffer_pool_finalize;
683
684   gstbufferpool_class->get_options = xvimage_buffer_pool_get_options;
685   gstbufferpool_class->set_config = xvimage_buffer_pool_set_config;
686   gstbufferpool_class->alloc_buffer = xvimage_buffer_pool_alloc;
687 }
688
689 static void
690 gst_xvimage_buffer_pool_init (GstXvImageBufferPool * pool)
691 {
692   pool->priv = GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE (pool);
693 }
694
695 static void
696 gst_xvimage_buffer_pool_finalize (GObject * object)
697 {
698   GstXvImageBufferPool *pool = GST_XVIMAGE_BUFFER_POOL_CAST (object);
699   GstXvImageBufferPoolPrivate *priv = pool->priv;
700
701   GST_LOG_OBJECT (pool, "finalize XvImage buffer pool %p", pool);
702
703   if (priv->caps)
704     gst_caps_unref (priv->caps);
705   gst_object_unref (pool->sink);
706
707   G_OBJECT_CLASS (gst_xvimage_buffer_pool_parent_class)->finalize (object);
708 }
709
710 /* This function tries to get a format matching with a given caps in the
711    supported list of formats we generated in gst_xvimagesink_get_xv_support */
712 gint
713 gst_xvimagesink_get_format_from_info (GstXvImageSink * xvimagesink,
714     GstVideoInfo * info)
715 {
716   GList *list = NULL;
717
718   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
719
720   list = xvimagesink->xcontext->formats_list;
721
722   while (list) {
723     GstXvImageFormat *format = list->data;
724
725     if (format && format->vformat == GST_VIDEO_INFO_FORMAT (info))
726       return format->format;
727
728     list = g_list_next (list);
729   }
730
731   return -1;
732 }