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