1 /*
2 * gstvaapisurface.c - VA surface abstraction
3 *
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6 * Copyright (C) 2011-2014 Intel Corporation
7 * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
23 */
24
25 /**
26 * SECTION:gstvaapisurface
27 * @short_description: VA surface abstraction
28 */
29
30 #include "sysdeps.h"
31 #include "gstvaapicompat.h"
32 #include "gstvaapiutils.h"
33 #include "gstvaapisurface.h"
34 #include "gstvaapisurface_priv.h"
35 #include "gstvaapicontext.h"
36 #include "gstvaapiimage.h"
37 #include "gstvaapiimage_priv.h"
38 #include "gstvaapicontext_overlay.h"
39 #include "gstvaapibufferproxy_priv.h"
40
41 #define DEBUG 1
42 #include "gstvaapidebug.h"
43
44 static gboolean
45 _gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface,
46 GstVaapiSubpicture * subpicture, const GstVaapiRectangle * src_rect,
47 const GstVaapiRectangle * dst_rect);
48
49 static gboolean
50 _gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface,
51 GstVaapiSubpicture * subpicture);
52
53 static void
destroy_subpicture_cb(gpointer subpicture,gpointer surface)54 destroy_subpicture_cb (gpointer subpicture, gpointer surface)
55 {
56 _gst_vaapi_surface_deassociate_subpicture (surface, subpicture);
57 gst_vaapi_object_unref (subpicture);
58 }
59
60 static void
gst_vaapi_surface_destroy_subpictures(GstVaapiSurface * surface)61 gst_vaapi_surface_destroy_subpictures (GstVaapiSurface * surface)
62 {
63 if (surface->subpictures) {
64 g_ptr_array_foreach (surface->subpictures, destroy_subpicture_cb, surface);
65 g_ptr_array_free (surface->subpictures, TRUE);
66 surface->subpictures = NULL;
67 }
68 }
69
70 static void
gst_vaapi_surface_destroy(GstVaapiSurface * surface)71 gst_vaapi_surface_destroy (GstVaapiSurface * surface)
72 {
73 GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface);
74 VASurfaceID surface_id;
75 VAStatus status;
76
77 surface_id = GST_VAAPI_OBJECT_ID (surface);
78 GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
79
80 gst_vaapi_surface_destroy_subpictures (surface);
81 gst_vaapi_surface_set_parent_context (surface, NULL);
82
83 if (surface_id != VA_INVALID_SURFACE) {
84 GST_VAAPI_DISPLAY_LOCK (display);
85 status = vaDestroySurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
86 &surface_id, 1);
87 GST_VAAPI_DISPLAY_UNLOCK (display);
88 if (!vaapi_check_status (status, "vaDestroySurfaces()"))
89 GST_WARNING ("failed to destroy surface %" GST_VAAPI_ID_FORMAT,
90 GST_VAAPI_ID_ARGS (surface_id));
91 GST_VAAPI_OBJECT_ID (surface) = VA_INVALID_SURFACE;
92 }
93 gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, NULL);
94 }
95
96 static gboolean
gst_vaapi_surface_create(GstVaapiSurface * surface,GstVaapiChromaType chroma_type,guint width,guint height)97 gst_vaapi_surface_create (GstVaapiSurface * surface,
98 GstVaapiChromaType chroma_type, guint width, guint height)
99 {
100 GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface);
101 VASurfaceID surface_id;
102 VAStatus status;
103 guint va_chroma_format;
104
105 va_chroma_format = from_GstVaapiChromaType (chroma_type);
106 if (!va_chroma_format)
107 goto error_unsupported_chroma_type;
108
109 GST_VAAPI_DISPLAY_LOCK (display);
110 status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
111 width, height, va_chroma_format, 1, &surface_id);
112 GST_VAAPI_DISPLAY_UNLOCK (display);
113 if (!vaapi_check_status (status, "vaCreateSurfaces()"))
114 return FALSE;
115
116 surface->format = GST_VIDEO_FORMAT_UNKNOWN;
117 surface->chroma_type = chroma_type;
118 surface->width = width;
119 surface->height = height;
120
121 GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
122 GST_VAAPI_OBJECT_ID (surface) = surface_id;
123 return TRUE;
124
125 /* ERRORS */
126 error_unsupported_chroma_type:
127 GST_ERROR ("unsupported chroma-type %u", chroma_type);
128 return FALSE;
129 }
130
131 static gboolean
gst_vaapi_surface_create_full(GstVaapiSurface * surface,const GstVideoInfo * vip,guint flags)132 gst_vaapi_surface_create_full (GstVaapiSurface * surface,
133 const GstVideoInfo * vip, guint flags)
134 {
135 GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface);
136 const GstVideoFormat format = GST_VIDEO_INFO_FORMAT (vip);
137 VASurfaceID surface_id;
138 VAStatus status;
139 guint chroma_type, va_chroma_format, i;
140 const VAImageFormat *va_format;
141 VASurfaceAttrib attribs[3], *attrib;
142 VASurfaceAttribExternalBuffers extbuf;
143 gboolean extbuf_needed = FALSE;
144
145 va_format = gst_vaapi_video_format_to_va_format (format);
146 if (!va_format)
147 goto error_unsupported_format;
148
149 chroma_type = gst_vaapi_video_format_get_chroma_type (format);
150 if (!chroma_type)
151 goto error_unsupported_format;
152
153 va_chroma_format = from_GstVaapiChromaType (chroma_type);
154 if (!va_chroma_format)
155 goto error_unsupported_format;
156
157 memset (&extbuf, 0, sizeof (extbuf));
158 extbuf.pixel_format = va_format->fourcc;
159 extbuf.width = GST_VIDEO_INFO_WIDTH (vip);
160 extbuf.height = GST_VIDEO_INFO_HEIGHT (vip);
161 if (flags & GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE) {
162 extbuf.flags &= ~VA_SURFACE_EXTBUF_DESC_ENABLE_TILING;
163 extbuf_needed = TRUE;
164 }
165
166 extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip);
167 if (flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES) {
168 for (i = 0; i < extbuf.num_planes; i++)
169 extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i);
170 extbuf_needed = TRUE;
171 }
172 if (flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS) {
173 for (i = 0; i < extbuf.num_planes; i++)
174 extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i);
175 extbuf_needed = TRUE;
176 }
177
178 attrib = attribs;
179 attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
180 attrib->type = VASurfaceAttribPixelFormat;
181 attrib->value.type = VAGenericValueTypeInteger;
182 attrib->value.value.i = va_format->fourcc;
183 attrib++;
184
185 if (extbuf_needed) {
186 attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
187 attrib->type = VASurfaceAttribMemoryType;
188 attrib->value.type = VAGenericValueTypeInteger;
189 attrib->value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
190 attrib++;
191
192 attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
193 attrib->type = VASurfaceAttribExternalBufferDescriptor;
194 attrib->value.type = VAGenericValueTypePointer;
195 attrib->value.value.p = &extbuf;
196 attrib++;
197 }
198
199 GST_VAAPI_DISPLAY_LOCK (display);
200 status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
201 va_chroma_format, extbuf.width, extbuf.height, &surface_id, 1,
202 attribs, attrib - attribs);
203 GST_VAAPI_DISPLAY_UNLOCK (display);
204 if (!vaapi_check_status (status, "vaCreateSurfaces()"))
205 return FALSE;
206
207 surface->format = format;
208 surface->chroma_type = chroma_type;
209 surface->width = extbuf.width;
210 surface->height = extbuf.height;
211
212 GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
213 GST_VAAPI_OBJECT_ID (surface) = surface_id;
214 return TRUE;
215
216 /* ERRORS */
217 error_unsupported_format:
218 GST_ERROR ("unsupported format %s",
219 gst_vaapi_video_format_to_string (format));
220 return FALSE;
221 }
222
223 static gboolean
gst_vaapi_surface_create_from_buffer_proxy(GstVaapiSurface * surface,GstVaapiBufferProxy * proxy,const GstVideoInfo * vip)224 gst_vaapi_surface_create_from_buffer_proxy (GstVaapiSurface * surface,
225 GstVaapiBufferProxy * proxy, const GstVideoInfo * vip)
226 {
227 GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface);
228 GstVideoFormat format;
229 VASurfaceID surface_id;
230 VAStatus status;
231 guint chroma_type, va_chroma_format;
232 const VAImageFormat *va_format;
233 VASurfaceAttrib attribs[2], *attrib;
234 VASurfaceAttribExternalBuffers extbuf;
235 unsigned long extbuf_handle;
236 guint i, width, height;
237
238 format = GST_VIDEO_INFO_FORMAT (vip);
239 width = GST_VIDEO_INFO_WIDTH (vip);
240 height = GST_VIDEO_INFO_HEIGHT (vip);
241
242 gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, proxy);
243
244 va_format = gst_vaapi_video_format_to_va_format (format);
245 if (!va_format)
246 goto error_unsupported_format;
247
248 chroma_type = gst_vaapi_video_format_get_chroma_type (format);
249 if (!chroma_type)
250 goto error_unsupported_format;
251
252 va_chroma_format = from_GstVaapiChromaType (chroma_type);
253 if (!va_chroma_format)
254 goto error_unsupported_format;
255
256 extbuf_handle = GST_VAAPI_BUFFER_PROXY_HANDLE (proxy);
257 extbuf.pixel_format = va_format->fourcc;
258 extbuf.width = width;
259 extbuf.height = height;
260 extbuf.data_size = GST_VAAPI_BUFFER_PROXY_SIZE (proxy);
261 extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip);
262 for (i = 0; i < extbuf.num_planes; i++) {
263 extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i);
264 extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i);
265 }
266 extbuf.buffers = (uintptr_t *) & extbuf_handle;
267 extbuf.num_buffers = 1;
268 extbuf.flags = 0;
269 extbuf.private_data = NULL;
270
271 attrib = attribs;
272 attrib->type = VASurfaceAttribExternalBufferDescriptor;
273 attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
274 attrib->value.type = VAGenericValueTypePointer;
275 attrib->value.value.p = &extbuf;
276 attrib++;
277 attrib->type = VASurfaceAttribMemoryType;
278 attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
279 attrib->value.type = VAGenericValueTypeInteger;
280 attrib->value.value.i =
281 from_GstVaapiBufferMemoryType (GST_VAAPI_BUFFER_PROXY_TYPE (proxy));
282 attrib++;
283
284 GST_VAAPI_DISPLAY_LOCK (display);
285 status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
286 va_chroma_format, width, height, &surface_id, 1, attribs,
287 attrib - attribs);
288 GST_VAAPI_DISPLAY_UNLOCK (display);
289 if (!vaapi_check_status (status, "vaCreateSurfaces()"))
290 return FALSE;
291
292 surface->format = format;
293 surface->chroma_type = chroma_type;
294 surface->width = width;
295 surface->height = height;
296
297 GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
298 GST_VAAPI_OBJECT_ID (surface) = surface_id;
299 return TRUE;
300
301 /* ERRORS */
302 error_unsupported_format:
303 GST_ERROR ("unsupported format %s",
304 gst_vaapi_video_format_to_string (format));
305 return FALSE;
306 }
307
308 #define gst_vaapi_surface_finalize gst_vaapi_surface_destroy
309 GST_VAAPI_OBJECT_DEFINE_CLASS (GstVaapiSurface, gst_vaapi_surface);
310
311 /**
312 * gst_vaapi_surface_new_from_formats:
313 * @display: a #GstVaapiDisplay
314 * @chroma_type: the surface chroma format
315 * @width: the requested surface width
316 * @height: the requested surface height
317 * @formats: the limited format list
318 *
319 * Creates a new #GstVaapiSurface with a @chroma_type valid for any
320 * format in @formats; If there aren't any, the returned surface is
321 * created forcing the passed @chroma_type.
322 *
323 * Return value: the newly allocated #GstVaapiSurface object
324 */
325 GstVaapiSurface *
gst_vaapi_surface_new_from_formats(GstVaapiDisplay * display,GstVaapiChromaType chroma_type,guint width,guint height,GArray * formats)326 gst_vaapi_surface_new_from_formats (GstVaapiDisplay * display,
327 GstVaapiChromaType chroma_type, guint width, guint height, GArray * formats)
328 {
329 GstVaapiSurface *surface;
330 guint i;
331
332 for (i = 0; i < formats->len; i++) {
333 GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
334 if (format == gst_vaapi_video_format_from_chroma (chroma_type))
335 return gst_vaapi_surface_new (display, chroma_type, width, height);
336 }
337
338 /* Fallback: if there's no format valid for the chroma type let's
339 * just use the passed chroma */
340 surface = gst_vaapi_object_new (gst_vaapi_surface_class (), display);
341 if (!surface)
342 return NULL;
343 if (!gst_vaapi_surface_create (surface, chroma_type, width, height))
344 goto error;
345
346 return surface;
347
348 /* ERRORS */
349 error:
350 {
351 gst_vaapi_object_unref (surface);
352 return NULL;
353 }
354 }
355
356 /**
357 * gst_vaapi_surface_new:
358 * @display: a #GstVaapiDisplay
359 * @chroma_type: the surface chroma format
360 * @width: the requested surface width
361 * @height: the requested surface height
362 *
363 * Creates a new #GstVaapiSurface with the specified chroma format and
364 * dimensions.
365 *
366 * Return value: the newly allocated #GstVaapiSurface object
367 */
368 GstVaapiSurface *
gst_vaapi_surface_new(GstVaapiDisplay * display,GstVaapiChromaType chroma_type,guint width,guint height)369 gst_vaapi_surface_new (GstVaapiDisplay * display,
370 GstVaapiChromaType chroma_type, guint width, guint height)
371 {
372 GstVaapiSurface *surface;
373
374 GST_DEBUG ("size %ux%u, chroma type 0x%x", width, height, chroma_type);
375
376 surface = gst_vaapi_object_new (gst_vaapi_surface_class (), display);
377 if (!surface)
378 return NULL;
379
380 /* first try a recent version of vaCreateSurface, and later use as
381 * fallback its old version */
382 {
383 GstVideoInfo vi;
384 GstVideoFormat surface_format;
385
386 surface_format = gst_vaapi_video_format_from_chroma (chroma_type);
387 gst_video_info_set_format (&vi, surface_format, width, height);
388
389 if (gst_vaapi_surface_create_full (surface, &vi, 0))
390 return surface;
391 }
392 if (!gst_vaapi_surface_create (surface, chroma_type, width, height))
393 goto error;
394 return surface;
395
396 /* ERRORS */
397 error:
398 {
399 gst_vaapi_object_unref (surface);
400 return NULL;
401 }
402 }
403
404 /**
405 * gst_vaapi_surface_new_full:
406 * @display: a #GstVaapiDisplay
407 * @vip: the pointer to a #GstVideoInfo
408 * @flags: (optional) allocation flags
409 *
410 * Creates a new #GstVaapiSurface with the specified video information
411 * and optional #GstVaapiSurfaceAllocFlags
412 *
413 * Return value: the newly allocated #GstVaapiSurface object, or %NULL
414 * if creation of VA surface with explicit pixel format is not
415 * supported or failed.
416 */
417 GstVaapiSurface *
gst_vaapi_surface_new_full(GstVaapiDisplay * display,const GstVideoInfo * vip,guint flags)418 gst_vaapi_surface_new_full (GstVaapiDisplay * display,
419 const GstVideoInfo * vip, guint flags)
420 {
421 GstVaapiSurface *surface;
422
423 GST_DEBUG ("size %ux%u, format %s, flags 0x%08x", GST_VIDEO_INFO_WIDTH (vip),
424 GST_VIDEO_INFO_HEIGHT (vip),
425 gst_vaapi_video_format_to_string (GST_VIDEO_INFO_FORMAT (vip)), flags);
426
427 surface = gst_vaapi_object_new (gst_vaapi_surface_class (), display);
428 if (!surface)
429 return NULL;
430
431 if (!gst_vaapi_surface_create_full (surface, vip, flags))
432 goto error;
433 return surface;
434
435 /* ERRORS */
436 error:
437 {
438 gst_vaapi_object_unref (surface);
439 return NULL;
440 }
441 }
442
443 /**
444 * gst_vaapi_surface_new_with_format:
445 * @display: a #GstVaapiDisplay
446 * @format: the surface format
447 * @width: the requested surface width
448 * @height: the requested surface height
449 *
450 * Creates a new #GstVaapiSurface with the specified pixel format and
451 * dimensions.
452 *
453 * Return value: the newly allocated #GstVaapiSurface object, or %NULL
454 * if creation of VA surface with explicit pixel format is not
455 * supported or failed.
456 */
457 GstVaapiSurface *
gst_vaapi_surface_new_with_format(GstVaapiDisplay * display,GstVideoFormat format,guint width,guint height)458 gst_vaapi_surface_new_with_format (GstVaapiDisplay * display,
459 GstVideoFormat format, guint width, guint height)
460 {
461 GstVideoInfo vi;
462
463 gst_video_info_set_format (&vi, format, width, height);
464 return gst_vaapi_surface_new_full (display, &vi, 0);
465 }
466
467 /**
468 * gst_vaapi_surface_new_from_buffer_proxy:
469 * @display: a #GstVaapiDisplay
470 * @proxy: a #GstVaapiBufferProxy
471 * @info: the #GstVideoInfo structure defining the layout of the buffer
472 *
473 * Creates a new #GstVaapiSurface with the supplied VA buffer proxy
474 * abstraction. The underlying VA buffer memory type could be anything
475 * that is supported by the VA driver.
476 *
477 * The resulting #GstVaapiSurface object owns an extra reference to
478 * the buffer @proxy, so the caller can safely release that handle as
479 * early as on return of this call.
480 *
481 * Return value: the newly allocated #GstVaapiSurface object, or %NULL
482 * if creation of VA surface failed or is not supported
483 */
484 GstVaapiSurface *
gst_vaapi_surface_new_from_buffer_proxy(GstVaapiDisplay * display,GstVaapiBufferProxy * proxy,const GstVideoInfo * info)485 gst_vaapi_surface_new_from_buffer_proxy (GstVaapiDisplay * display,
486 GstVaapiBufferProxy * proxy, const GstVideoInfo * info)
487 {
488 GstVaapiSurface *surface;
489
490 g_return_val_if_fail (proxy != NULL, NULL);
491 g_return_val_if_fail (info != NULL, NULL);
492
493 surface = gst_vaapi_object_new (gst_vaapi_surface_class (), display);
494 if (!surface)
495 return NULL;
496
497 if (!gst_vaapi_surface_create_from_buffer_proxy (surface, proxy, info))
498 goto error;
499 return surface;
500
501 /* ERRORS */
502 error:
503 {
504 gst_vaapi_object_unref (surface);
505 return NULL;
506 }
507 }
508
509 /**
510 * gst_vaapi_surface_get_id:
511 * @surface: a #GstVaapiSurface
512 *
513 * Returns the underlying VASurfaceID of the @surface.
514 *
515 * Return value: the underlying VA surface id
516 */
517 GstVaapiID
gst_vaapi_surface_get_id(GstVaapiSurface * surface)518 gst_vaapi_surface_get_id (GstVaapiSurface * surface)
519 {
520 g_return_val_if_fail (surface != NULL, VA_INVALID_SURFACE);
521
522 return GST_VAAPI_OBJECT_ID (surface);
523 }
524
525 /**
526 * gst_vaapi_surface_get_chroma_type:
527 * @surface: a #GstVaapiSurface
528 *
529 * Returns the #GstVaapiChromaType the @surface was created with.
530 *
531 * Return value: the #GstVaapiChromaType
532 */
533 GstVaapiChromaType
gst_vaapi_surface_get_chroma_type(GstVaapiSurface * surface)534 gst_vaapi_surface_get_chroma_type (GstVaapiSurface * surface)
535 {
536 g_return_val_if_fail (surface != NULL, 0);
537
538 return GST_VAAPI_SURFACE_CHROMA_TYPE (surface);
539 }
540
541 /**
542 * gst_vaapi_surface_get_format:
543 * @surface: a #GstVaapiSurface
544 *
545 * Returns the #GstVideoFormat the @surface was created with.
546 *
547 * Return value: the #GstVideoFormat, or %GST_VIDEO_FORMAT_ENCODED if
548 * the surface was not created with an explicit video format, or if
549 * the underlying video format could not be determined
550 */
551 GstVideoFormat
gst_vaapi_surface_get_format(GstVaapiSurface * surface)552 gst_vaapi_surface_get_format (GstVaapiSurface * surface)
553 {
554 g_return_val_if_fail (surface != NULL, 0);
555
556 /* Try to determine the underlying VA surface format */
557 if (surface->format == GST_VIDEO_FORMAT_UNKNOWN) {
558 GstVaapiImage *const image = gst_vaapi_surface_derive_image (surface);
559 if (image) {
560 surface->format = GST_VAAPI_IMAGE_FORMAT (image);
561 gst_vaapi_object_unref (image);
562 }
563 if (surface->format == GST_VIDEO_FORMAT_UNKNOWN)
564 surface->format = GST_VIDEO_FORMAT_ENCODED;
565 }
566 return GST_VAAPI_SURFACE_FORMAT (surface);
567 }
568
569 /**
570 * gst_vaapi_surface_get_width:
571 * @surface: a #GstVaapiSurface
572 *
573 * Returns the @surface width.
574 *
575 * Return value: the surface width, in pixels
576 */
577 guint
gst_vaapi_surface_get_width(GstVaapiSurface * surface)578 gst_vaapi_surface_get_width (GstVaapiSurface * surface)
579 {
580 g_return_val_if_fail (surface != NULL, 0);
581
582 return GST_VAAPI_SURFACE_WIDTH (surface);
583 }
584
585 /**
586 * gst_vaapi_surface_get_height:
587 * @surface: a #GstVaapiSurface
588 *
589 * Returns the @surface height.
590 *
591 * Return value: the surface height, in pixels.
592 */
593 guint
gst_vaapi_surface_get_height(GstVaapiSurface * surface)594 gst_vaapi_surface_get_height (GstVaapiSurface * surface)
595 {
596 g_return_val_if_fail (surface != NULL, 0);
597
598 return GST_VAAPI_SURFACE_HEIGHT (surface);
599 }
600
601 /**
602 * gst_vaapi_surface_get_size:
603 * @surface: a #GstVaapiSurface
604 * @width_ptr: return location for the width, or %NULL
605 * @height_ptr: return location for the height, or %NULL
606 *
607 * Retrieves the dimensions of a #GstVaapiSurface.
608 */
609 void
gst_vaapi_surface_get_size(GstVaapiSurface * surface,guint * width_ptr,guint * height_ptr)610 gst_vaapi_surface_get_size (GstVaapiSurface * surface,
611 guint * width_ptr, guint * height_ptr)
612 {
613 g_return_if_fail (surface != NULL);
614
615 if (width_ptr)
616 *width_ptr = GST_VAAPI_SURFACE_WIDTH (surface);
617
618 if (height_ptr)
619 *height_ptr = GST_VAAPI_SURFACE_HEIGHT (surface);
620 }
621
622 /**
623 * gst_vaapi_surface_set_parent_context:
624 * @surface: a #GstVaapiSurface
625 * @context: a #GstVaapiContext
626 *
627 * Sets new parent context, or clears any parent context if @context
628 * is %NULL. This function owns an extra reference to the context,
629 * which will be released when the surface is destroyed.
630 */
631 void
gst_vaapi_surface_set_parent_context(GstVaapiSurface * surface,GstVaapiContext * context)632 gst_vaapi_surface_set_parent_context (GstVaapiSurface * surface,
633 GstVaapiContext * context)
634 {
635 g_return_if_fail (surface != NULL);
636
637 surface->parent_context = NULL;
638 }
639
640 /**
641 * gst_vaapi_surface_get_parent_context:
642 * @surface: a #GstVaapiSurface
643 *
644 * Retrieves the parent #GstVaapiContext, or %NULL if there is
645 * none. The surface shall still own a reference to the context.
646 * i.e. the caller shall not unreference the returned context object.
647 *
648 * Return value: the parent context, if any.
649 */
650 GstVaapiContext *
gst_vaapi_surface_get_parent_context(GstVaapiSurface * surface)651 gst_vaapi_surface_get_parent_context (GstVaapiSurface * surface)
652 {
653 g_return_val_if_fail (surface != NULL, NULL);
654
655 return surface->parent_context;
656 }
657
658 /**
659 * gst_vaapi_surface_derive_image:
660 * @surface: a #GstVaapiSurface
661 *
662 * Derives a #GstVaapiImage from the @surface. This image buffer can
663 * then be mapped/unmapped for direct CPU access. This operation is
664 * only possible if the underlying implementation supports direct
665 * rendering capabilities and internal surface formats that can be
666 * represented with a #GstVaapiImage.
667 *
668 * When the operation is not possible, the function returns %NULL and
669 * the user should then fallback to using gst_vaapi_surface_get_image()
670 * or gst_vaapi_surface_put_image() to accomplish the same task in an
671 * indirect manner (additional copy).
672 *
673 * An image created with gst_vaapi_surface_derive_image() should be
674 * unreferenced when it's no longer needed. The image and image buffer
675 * data structures will be destroyed. However, the surface contents
676 * will remain unchanged until destroyed through the last call to
677 * gst_vaapi_object_unref().
678 *
679 * Return value: the newly allocated #GstVaapiImage object, or %NULL
680 * on failure
681 */
682 GstVaapiImage *
gst_vaapi_surface_derive_image(GstVaapiSurface * surface)683 gst_vaapi_surface_derive_image (GstVaapiSurface * surface)
684 {
685 GstVaapiDisplay *display;
686 VAImage va_image;
687 VAStatus status;
688 GstVaapiImage *image;
689
690 g_return_val_if_fail (surface != NULL, NULL);
691
692 display = GST_VAAPI_OBJECT_DISPLAY (surface);
693 va_image.image_id = VA_INVALID_ID;
694 va_image.buf = VA_INVALID_ID;
695
696 GST_VAAPI_DISPLAY_LOCK (display);
697 status = vaDeriveImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
698 GST_VAAPI_OBJECT_ID (surface), &va_image);
699 GST_VAAPI_DISPLAY_UNLOCK (display);
700 if (!vaapi_check_status (status, "vaDeriveImage()"))
701 return NULL;
702 if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID)
703 return NULL;
704
705 image = gst_vaapi_image_new_with_image (display, &va_image);
706 if (!image)
707 vaDestroyImage (GST_VAAPI_DISPLAY_VADISPLAY (display), va_image.image_id);
708 return image;
709 }
710
711 /**
712 * gst_vaapi_surface_get_image
713 * @surface: a #GstVaapiSurface
714 * @image: a #GstVaapiImage
715 *
716 * Retrieves surface data into a #GstVaapiImage. The @image must have
717 * a format supported by the @surface.
718 *
719 * Return value: %TRUE on success
720 */
721 gboolean
gst_vaapi_surface_get_image(GstVaapiSurface * surface,GstVaapiImage * image)722 gst_vaapi_surface_get_image (GstVaapiSurface * surface, GstVaapiImage * image)
723 {
724 GstVaapiDisplay *display;
725 VAImageID image_id;
726 VAStatus status;
727 guint width, height;
728
729 g_return_val_if_fail (surface != NULL, FALSE);
730 g_return_val_if_fail (image != NULL, FALSE);
731
732 display = GST_VAAPI_OBJECT_DISPLAY (surface);
733 if (!display)
734 return FALSE;
735
736 width = GST_VAAPI_IMAGE_WIDTH (image);
737 height = GST_VAAPI_IMAGE_HEIGHT (image);
738 if (width != surface->width || height != surface->height)
739 return FALSE;
740
741 image_id = GST_VAAPI_OBJECT_ID (image);
742 if (image_id == VA_INVALID_ID)
743 return FALSE;
744
745 GST_VAAPI_DISPLAY_LOCK (display);
746 status = vaGetImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
747 GST_VAAPI_OBJECT_ID (surface), 0, 0, width, height, image_id);
748 GST_VAAPI_DISPLAY_UNLOCK (display);
749 if (!vaapi_check_status (status, "vaGetImage()"))
750 return FALSE;
751
752 return TRUE;
753 }
754
755 /**
756 * gst_vaapi_surface_put_image:
757 * @surface: a #GstVaapiSurface
758 * @image: a #GstVaapiImage
759 *
760 * Copies data from a #GstVaapiImage into a @surface. The @image must
761 * have a format supported by the @surface.
762 *
763 * Return value: %TRUE on success
764 */
765 gboolean
gst_vaapi_surface_put_image(GstVaapiSurface * surface,GstVaapiImage * image)766 gst_vaapi_surface_put_image (GstVaapiSurface * surface, GstVaapiImage * image)
767 {
768 GstVaapiDisplay *display;
769 VAImageID image_id;
770 VAStatus status;
771 guint width, height;
772
773 g_return_val_if_fail (surface != NULL, FALSE);
774 g_return_val_if_fail (image != NULL, FALSE);
775
776 display = GST_VAAPI_OBJECT_DISPLAY (surface);
777 if (!display)
778 return FALSE;
779
780 width = GST_VAAPI_IMAGE_WIDTH (image);
781 height = GST_VAAPI_IMAGE_HEIGHT (image);
782 if (width != surface->width || height != surface->height)
783 return FALSE;
784
785 image_id = GST_VAAPI_OBJECT_ID (image);
786 if (image_id == VA_INVALID_ID)
787 return FALSE;
788
789 GST_VAAPI_DISPLAY_LOCK (display);
790 status = vaPutImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
791 GST_VAAPI_OBJECT_ID (surface), image_id, 0, 0, width, height,
792 0, 0, width, height);
793 GST_VAAPI_DISPLAY_UNLOCK (display);
794 if (!vaapi_check_status (status, "vaPutImage()"))
795 return FALSE;
796
797 return TRUE;
798 }
799
800 /**
801 * gst_vaapi_surface_associate_subpicture:
802 * @surface: a #GstVaapiSurface
803 * @subpicture: a #GstVaapiSubpicture
804 * @src_rect: the sub-rectangle of the source subpicture
805 * image to extract and process. If %NULL, the entire image will be used.
806 * @dst_rect: the sub-rectangle of the destination
807 * surface into which the image is rendered. If %NULL, the entire
808 * surface will be used.
809 *
810 * Associates the @subpicture with the @surface. The @src_rect
811 * coordinates and size are relative to the source image bound to
812 * @subpicture. The @dst_rect coordinates and size are relative to the
813 * target @surface. Note that the @surface holds an additional
814 * reference to the @subpicture.
815 *
816 * Return value: %TRUE on success
817 */
818 gboolean
gst_vaapi_surface_associate_subpicture(GstVaapiSurface * surface,GstVaapiSubpicture * subpicture,const GstVaapiRectangle * src_rect,const GstVaapiRectangle * dst_rect)819 gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface,
820 GstVaapiSubpicture * subpicture,
821 const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect)
822 {
823 gboolean success;
824
825 g_return_val_if_fail (surface != NULL, FALSE);
826 g_return_val_if_fail (subpicture != NULL, FALSE);
827
828 if (!surface->subpictures) {
829 surface->subpictures = g_ptr_array_new ();
830 if (!surface->subpictures)
831 return FALSE;
832 }
833
834 if (g_ptr_array_remove_fast (surface->subpictures, subpicture)) {
835 success = _gst_vaapi_surface_deassociate_subpicture (surface, subpicture);
836 gst_vaapi_object_unref (subpicture);
837 if (!success)
838 return FALSE;
839 }
840
841 success = _gst_vaapi_surface_associate_subpicture (surface,
842 subpicture, src_rect, dst_rect);
843 if (!success)
844 return FALSE;
845
846 g_ptr_array_add (surface->subpictures, gst_vaapi_object_ref (subpicture));
847 return TRUE;
848 }
849
850 gboolean
_gst_vaapi_surface_associate_subpicture(GstVaapiSurface * surface,GstVaapiSubpicture * subpicture,const GstVaapiRectangle * src_rect,const GstVaapiRectangle * dst_rect)851 _gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface,
852 GstVaapiSubpicture * subpicture,
853 const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect)
854 {
855 GstVaapiDisplay *display;
856 GstVaapiRectangle src_rect_default, dst_rect_default;
857 GstVaapiImage *image;
858 VASurfaceID surface_id;
859 VAStatus status;
860
861 display = GST_VAAPI_OBJECT_DISPLAY (surface);
862 if (!display)
863 return FALSE;
864
865 surface_id = GST_VAAPI_OBJECT_ID (surface);
866 if (surface_id == VA_INVALID_SURFACE)
867 return FALSE;
868
869 if (!src_rect) {
870 image = gst_vaapi_subpicture_get_image (subpicture);
871 if (!image)
872 return FALSE;
873 src_rect = &src_rect_default;
874 src_rect_default.x = 0;
875 src_rect_default.y = 0;
876 src_rect_default.width = GST_VAAPI_IMAGE_WIDTH (image);
877 src_rect_default.height = GST_VAAPI_IMAGE_HEIGHT (image);
878 }
879
880 if (!dst_rect) {
881 dst_rect = &dst_rect_default;
882 dst_rect_default.x = 0;
883 dst_rect_default.y = 0;
884 dst_rect_default.width = surface->width;
885 dst_rect_default.height = surface->height;
886 }
887
888 GST_VAAPI_DISPLAY_LOCK (display);
889 status = vaAssociateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
890 GST_VAAPI_OBJECT_ID (subpicture), &surface_id, 1,
891 src_rect->x, src_rect->y, src_rect->width, src_rect->height,
892 dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
893 from_GstVaapiSubpictureFlags (gst_vaapi_subpicture_get_flags
894 (subpicture)));
895 GST_VAAPI_DISPLAY_UNLOCK (display);
896 if (!vaapi_check_status (status, "vaAssociateSubpicture()"))
897 return FALSE;
898
899 return TRUE;
900 }
901
902 /**
903 * gst_vaapi_surface_deassociate_subpicture:
904 * @surface: a #GstVaapiSurface
905 * @subpicture: a #GstVaapiSubpicture
906 *
907 * Deassociates @subpicture from @surface. Other associations are kept.
908 *
909 * Return value: %TRUE on success
910 */
911 gboolean
gst_vaapi_surface_deassociate_subpicture(GstVaapiSurface * surface,GstVaapiSubpicture * subpicture)912 gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface,
913 GstVaapiSubpicture * subpicture)
914 {
915 gboolean success;
916
917 g_return_val_if_fail (surface != NULL, FALSE);
918 g_return_val_if_fail (subpicture != NULL, FALSE);
919
920 if (!surface->subpictures)
921 return TRUE;
922
923 /* First, check subpicture was really associated with this surface */
924 if (!g_ptr_array_remove_fast (surface->subpictures, subpicture)) {
925 GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT " was not bound to "
926 "surface %" GST_VAAPI_ID_FORMAT,
927 GST_VAAPI_ID_ARGS (GST_VAAPI_OBJECT_ID (subpicture)),
928 GST_VAAPI_ID_ARGS (GST_VAAPI_OBJECT_ID (surface)));
929 return TRUE;
930 }
931
932 success = _gst_vaapi_surface_deassociate_subpicture (surface, subpicture);
933 gst_vaapi_object_unref (subpicture);
934 return success;
935 }
936
937 gboolean
_gst_vaapi_surface_deassociate_subpicture(GstVaapiSurface * surface,GstVaapiSubpicture * subpicture)938 _gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface,
939 GstVaapiSubpicture * subpicture)
940 {
941 GstVaapiDisplay *display;
942 VASurfaceID surface_id;
943 VAStatus status;
944
945 display = GST_VAAPI_OBJECT_DISPLAY (surface);
946 if (!display)
947 return FALSE;
948
949 surface_id = GST_VAAPI_OBJECT_ID (surface);
950 if (surface_id == VA_INVALID_SURFACE)
951 return FALSE;
952
953 GST_VAAPI_DISPLAY_LOCK (display);
954 status = vaDeassociateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
955 GST_VAAPI_OBJECT_ID (subpicture), &surface_id, 1);
956 GST_VAAPI_DISPLAY_UNLOCK (display);
957 if (!vaapi_check_status (status, "vaDeassociateSubpicture()"))
958 return FALSE;
959
960 return TRUE;
961 }
962
963 /**
964 * gst_vaapi_surface_sync:
965 * @surface: a #GstVaapiSurface
966 *
967 * Blocks until all pending operations on the @surface have been
968 * completed.
969 *
970 * Return value: %TRUE on success
971 */
972 gboolean
gst_vaapi_surface_sync(GstVaapiSurface * surface)973 gst_vaapi_surface_sync (GstVaapiSurface * surface)
974 {
975 GstVaapiDisplay *display;
976 VAStatus status;
977
978 g_return_val_if_fail (surface != NULL, FALSE);
979
980 display = GST_VAAPI_OBJECT_DISPLAY (surface);
981 if (!display)
982 return FALSE;
983
984 GST_VAAPI_DISPLAY_LOCK (display);
985 status = vaSyncSurface (GST_VAAPI_DISPLAY_VADISPLAY (display),
986 GST_VAAPI_OBJECT_ID (surface));
987 GST_VAAPI_DISPLAY_UNLOCK (display);
988 if (!vaapi_check_status (status, "vaSyncSurface()"))
989 return FALSE;
990
991 return TRUE;
992 }
993
994 /**
995 * gst_vaapi_surface_query_status:
996 * @surface: a #GstVaapiSurface
997 * @pstatus: return location for the #GstVaapiSurfaceStatus
998 *
999 * Finds out any pending operations on the @surface. The
1000 * #GstVaapiSurfaceStatus flags are returned into @pstatus.
1001 *
1002 * Return value: %TRUE on success
1003 */
1004 gboolean
gst_vaapi_surface_query_status(GstVaapiSurface * surface,GstVaapiSurfaceStatus * pstatus)1005 gst_vaapi_surface_query_status (GstVaapiSurface * surface,
1006 GstVaapiSurfaceStatus * pstatus)
1007 {
1008 VASurfaceStatus surface_status;
1009 VAStatus status;
1010
1011 g_return_val_if_fail (surface != NULL, FALSE);
1012
1013 GST_VAAPI_OBJECT_LOCK_DISPLAY (surface);
1014 status = vaQuerySurfaceStatus (GST_VAAPI_OBJECT_VADISPLAY (surface),
1015 GST_VAAPI_OBJECT_ID (surface), &surface_status);
1016 GST_VAAPI_OBJECT_UNLOCK_DISPLAY (surface);
1017 if (!vaapi_check_status (status, "vaQuerySurfaceStatus()"))
1018 return FALSE;
1019
1020 if (pstatus)
1021 *pstatus = to_GstVaapiSurfaceStatus (surface_status);
1022 return TRUE;
1023 }
1024
1025 /**
1026 * gst_vaapi_surface_set_subpictures_from_composition:
1027 * @surface: a #GstVaapiSurface
1028 * @compostion: a #GstVideoOverlayCompositon
1029 * @propagate_context: a flag specifying whether to apply composition
1030 * to the parent context, if any
1031 *
1032 * Helper to update the subpictures from #GstVideoOverlayCompositon. Sending
1033 * a NULL composition will clear all the current subpictures. Note that this
1034 * method will clear existing subpictures.
1035 *
1036 * Return value: %TRUE on success
1037 */
1038 gboolean
gst_vaapi_surface_set_subpictures_from_composition(GstVaapiSurface * surface,GstVideoOverlayComposition * composition,gboolean propagate_context)1039 gst_vaapi_surface_set_subpictures_from_composition (GstVaapiSurface * surface,
1040 GstVideoOverlayComposition * composition, gboolean propagate_context)
1041 {
1042 GstVaapiDisplay *display;
1043 guint n, nb_rectangles;
1044
1045 g_return_val_if_fail (surface != NULL, FALSE);
1046
1047 if (propagate_context && surface->parent_context)
1048 return gst_vaapi_context_apply_composition (surface->parent_context,
1049 composition);
1050
1051 display = GST_VAAPI_OBJECT_DISPLAY (surface);
1052 if (!display)
1053 return FALSE;
1054
1055 /* Clear current subpictures */
1056 gst_vaapi_surface_destroy_subpictures (surface);
1057
1058 if (!composition)
1059 return TRUE;
1060
1061 nb_rectangles = gst_video_overlay_composition_n_rectangles (composition);
1062
1063 /* Overlay all the rectangles cantained in the overlay composition */
1064 for (n = 0; n < nb_rectangles; ++n) {
1065 GstVideoOverlayRectangle *rect;
1066 GstVaapiRectangle sub_rect;
1067 GstVaapiSubpicture *subpicture;
1068
1069 rect = gst_video_overlay_composition_get_rectangle (composition, n);
1070 subpicture = gst_vaapi_subpicture_new_from_overlay_rectangle (display,
1071 rect);
1072
1073 gst_video_overlay_rectangle_get_render_rectangle (rect,
1074 (gint *) & sub_rect.x, (gint *) & sub_rect.y,
1075 &sub_rect.width, &sub_rect.height);
1076
1077 /* ensure that the overlay is not bigger than the surface */
1078 sub_rect.y = MIN (sub_rect.y, surface->height);
1079 sub_rect.width = MIN (sub_rect.width, surface->width);
1080
1081 if (!gst_vaapi_surface_associate_subpicture (surface, subpicture,
1082 NULL, &sub_rect)) {
1083 GST_WARNING ("could not render overlay rectangle %p", rect);
1084 gst_vaapi_object_unref (subpicture);
1085 return FALSE;
1086 }
1087 gst_vaapi_object_unref (subpicture);
1088 }
1089 return TRUE;
1090 }
1091
1092 /**
1093 * gst_vaapi_surface_set_buffer_proxy:
1094 * @surface: a #GstVaapiSurface
1095 * @proxy: an external #GstVaapiBufferProxy
1096 *
1097 * Replaces the external buffer proxy in @surface with @proxy.
1098 *
1099 * This is useful when a dmabuf-based memory is instantiated in order
1100 * to relate the generated buffer @proxy with the processed @surface.
1101 **/
1102 void
gst_vaapi_surface_set_buffer_proxy(GstVaapiSurface * surface,GstVaapiBufferProxy * proxy)1103 gst_vaapi_surface_set_buffer_proxy (GstVaapiSurface * surface,
1104 GstVaapiBufferProxy * proxy)
1105 {
1106 gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, proxy);
1107 }
1108
1109 /**
1110 * gst_vaapi_surface_peek_buffer_proxy:
1111 * @surface: a #GstVaapiSurface
1112 *
1113 * This is useful when a dmabuf-based memory is instantiated in order
1114 * to relate the generated buffer @proxy with the processed @surface.
1115 *
1116 * Returns: (transfer none): the associated external
1117 * #GstVaapiBufferProxy
1118 **/
1119 GstVaapiBufferProxy *
gst_vaapi_surface_peek_buffer_proxy(GstVaapiSurface * surface)1120 gst_vaapi_surface_peek_buffer_proxy (GstVaapiSurface * surface)
1121 {
1122 return surface->extbuf_proxy;
1123 }
1124