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