1 /* GStreamer
2 * Copyright (C) 2021 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "gstvasurfacecopy.h"
22
23 #include "gstvaallocator.h"
24 #include "gstvadisplay_priv.h"
25 #include "gstvafilter.h"
26 #include "vasurfaceimage.h"
27
28 #define GST_CAT_DEFAULT gst_va_memory_debug
29 GST_DEBUG_CATEGORY_EXTERN (gst_va_memory_debug);
30
31 struct _GstVaSurfaceCopy
32 {
33 GstVaDisplay *display;
34
35 GstVideoInfo info;
36 gboolean has_copy;
37
38 GRecMutex lock;
39 GstVaFilter *filter;
40 };
41
42 static gboolean
_has_copy(GstVaDisplay * display)43 _has_copy (GstVaDisplay * display)
44 {
45 #if VA_CHECK_VERSION (1, 12, 0)
46 VADisplay dpy;
47 VADisplayAttribute attr = {
48 .type = VADisplayAttribCopy,
49 .flags = VA_DISPLAY_ATTRIB_GETTABLE,
50 };
51 VAStatus status;
52
53 dpy = gst_va_display_get_va_dpy (display);
54
55 gst_va_display_lock (display);
56 status = vaGetDisplayAttributes (dpy, &attr, 1);
57 gst_va_display_unlock (display);
58 if (status != VA_STATUS_SUCCESS) {
59 GST_INFO ("vaGetDisplayAttribures: %s", vaErrorStr (status));
60 return FALSE;
61 }
62
63 return TRUE;
64 #else
65 return FALSE;
66 #endif
67 }
68
69 GstVaSurfaceCopy *
gst_va_surface_copy_new(GstVaDisplay * display,GstVideoInfo * vinfo)70 gst_va_surface_copy_new (GstVaDisplay * display, GstVideoInfo * vinfo)
71 {
72 GstVaSurfaceCopy *self;
73
74 g_return_val_if_fail (GST_IS_VA_DISPLAY (display), NULL);
75 g_return_val_if_fail (vinfo != NULL, NULL);
76
77 self = g_slice_new (GstVaSurfaceCopy);
78 self->display = gst_object_ref (display);
79 self->has_copy = _has_copy (display);
80 self->info = *vinfo;
81 self->filter = NULL;
82 g_rec_mutex_init (&self->lock);
83
84 if (gst_va_display_has_vpp (display)) {
85 self->filter = gst_va_filter_new (display);
86 if (!(gst_va_filter_open (self->filter)
87 && gst_va_filter_set_video_info (self->filter, vinfo, vinfo)))
88 gst_clear_object (&self->filter);
89 }
90
91 return self;
92 }
93
94 void
gst_va_surface_copy_free(GstVaSurfaceCopy * self)95 gst_va_surface_copy_free (GstVaSurfaceCopy * self)
96 {
97 g_return_if_fail (self && GST_IS_VA_DISPLAY (self->display));
98
99 gst_clear_object (&self->display);
100 if (self->filter) {
101 gst_va_filter_close (self->filter);
102 gst_clear_object (&self->filter);
103 }
104
105 g_rec_mutex_clear (&self->lock);
106
107 g_slice_free (GstVaSurfaceCopy, self);
108 }
109
110 static gboolean
_vpp_copy_surface(GstVaSurfaceCopy * self,VASurfaceID dst,VASurfaceID src)111 _vpp_copy_surface (GstVaSurfaceCopy * self, VASurfaceID dst, VASurfaceID src)
112 {
113 gboolean ret;
114
115 GstVaSample gst_src = {
116 .surface = src,
117 };
118 GstVaSample gst_dst = {
119 .surface = dst,
120 };
121
122 g_rec_mutex_lock (&self->lock);
123 ret = gst_va_filter_process (self->filter, &gst_src, &gst_dst);
124 g_rec_mutex_unlock (&self->lock);
125
126 return ret;
127 }
128
129 gboolean
gst_va_surface_copy(GstVaSurfaceCopy * self,VASurfaceID dst,VASurfaceID src)130 gst_va_surface_copy (GstVaSurfaceCopy * self, VASurfaceID dst, VASurfaceID src)
131 {
132 VAImage image = {.image_id = VA_INVALID_ID, };
133 gboolean ret;
134
135 g_return_val_if_fail (self && GST_IS_VA_DISPLAY (self->display), FALSE);
136
137 if (self->has_copy && va_copy_surface (self->display, dst, src)) {
138 GST_LOG ("GPU copy of %#x to %#x", src, dst);
139 return TRUE;
140 }
141
142 if (self->filter && _vpp_copy_surface (self, dst, src)) {
143 GST_LOG ("VPP copy of %#x to %#x", src, dst);
144 return TRUE;
145 }
146
147 if (!va_ensure_image (self->display, src, &self->info, &image, FALSE))
148 return FALSE;
149
150 if ((ret = va_put_image (self->display, dst, &image)))
151 GST_LOG ("shallow copy of %#x to %#x", src, dst);
152
153 va_unmap_buffer (self->display, image.buf);
154 va_destroy_image (self->display, image.image_id);
155
156 return ret;
157 }
158