plugins: allow builds without GLX enabled for GStreamer 1.2.
[platform/upstream/gstreamer-vaapi.git] / gst / vaapi / gstvaapivideobufferpool.c
1 /*
2  *  gstvaapivideobufferpool.c - Gstreamer/VA video buffer pool
3  *
4  *  Copyright (C) 2013 Intel Corporation
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22
23 #include "gst/vaapi/sysdeps.h"
24 #include "gstvaapivideobufferpool.h"
25 #include "gstvaapivideobuffer.h"
26 #include "gstvaapivideomemory.h"
27 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
28 #include "gstvaapivideometa_texture.h"
29 #endif
30
31 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapivideopool);
32 #define GST_CAT_DEFAULT gst_debug_vaapivideopool
33
34 G_DEFINE_TYPE(GstVaapiVideoBufferPool,
35               gst_vaapi_video_buffer_pool,
36               GST_TYPE_BUFFER_POOL)
37
38 enum {
39     PROP_0,
40
41     PROP_DISPLAY,
42 };
43
44 struct _GstVaapiVideoBufferPoolPrivate {
45     GstVideoInfo        video_info[2];
46     guint               video_info_index;
47     GstAllocator       *allocator;
48     GstVaapiDisplay    *display;
49     guint               has_video_meta          : 1;
50     guint               has_texture_upload_meta : 1;
51 };
52
53 #define GST_VAAPI_VIDEO_BUFFER_POOL_GET_PRIVATE(obj)    \
54     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                 \
55         GST_VAAPI_TYPE_VIDEO_BUFFER_POOL,               \
56         GstVaapiVideoBufferPoolPrivate))
57
58 static void
59 gst_vaapi_video_buffer_pool_finalize(GObject *object)
60 {
61     GstVaapiVideoBufferPoolPrivate * const priv =
62         GST_VAAPI_VIDEO_BUFFER_POOL(object)->priv;
63
64     G_OBJECT_CLASS(gst_vaapi_video_buffer_pool_parent_class)->finalize(object);
65
66     gst_vaapi_display_replace(&priv->display, NULL);
67     g_clear_object(&priv->allocator);
68 }
69
70 static void
71 gst_vaapi_video_buffer_pool_set_property(GObject *object, guint prop_id,
72     const GValue *value, GParamSpec *pspec)
73 {
74     GstVaapiVideoBufferPoolPrivate * const priv =
75         GST_VAAPI_VIDEO_BUFFER_POOL(object)->priv;
76
77     switch (prop_id) {
78     case PROP_DISPLAY:
79         priv->display = gst_vaapi_display_ref(g_value_get_pointer(value));
80         break;
81     default:
82         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
83         break;
84     }
85 }
86
87 static void
88 gst_vaapi_video_buffer_pool_get_property(GObject *object, guint prop_id,
89     GValue *value, GParamSpec *pspec)
90 {
91     GstVaapiVideoBufferPoolPrivate * const priv =
92         GST_VAAPI_VIDEO_BUFFER_POOL(object)->priv;
93
94     switch (prop_id) {
95     case PROP_DISPLAY:
96         g_value_set_pointer(value, priv->display);
97         break;
98     default:
99         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
100         break;
101     }
102 }
103
104 static const gchar **
105 gst_vaapi_video_buffer_pool_get_options(GstBufferPool *pool)
106 {
107     static const gchar *g_options[] = {
108         GST_BUFFER_POOL_OPTION_VIDEO_META,
109         GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META,
110         GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META,
111         NULL,
112     };
113     return g_options;
114 }
115
116 static gboolean
117 gst_vaapi_video_buffer_pool_set_config(GstBufferPool *pool,
118     GstStructure *config)
119 {
120     GstVaapiVideoBufferPoolPrivate * const priv =
121         GST_VAAPI_VIDEO_BUFFER_POOL(pool)->priv;
122     GstCaps *caps = NULL;
123     GstVideoInfo * const cur_vip = &priv->video_info[priv->video_info_index];
124     GstVideoInfo * const new_vip = &priv->video_info[!priv->video_info_index];
125     GstAllocator *allocator;
126     gboolean changed_caps;
127
128     if (!gst_buffer_pool_config_get_params(config, &caps, NULL, NULL, NULL))
129         goto error_invalid_config;
130     if (!caps || !gst_video_info_from_caps(new_vip, caps))
131         goto error_no_caps;
132
133     changed_caps = !priv->allocator ||
134         GST_VIDEO_INFO_FORMAT(cur_vip) != GST_VIDEO_INFO_FORMAT(new_vip) ||
135         GST_VIDEO_INFO_WIDTH(cur_vip)  != GST_VIDEO_INFO_WIDTH(new_vip) ||
136         GST_VIDEO_INFO_HEIGHT(cur_vip) != GST_VIDEO_INFO_HEIGHT(new_vip);
137
138     if (changed_caps) {
139         allocator = gst_vaapi_video_allocator_new(priv->display, new_vip);
140         if (!allocator)
141             goto error_create_allocator;
142         gst_object_replace((GstObject **)&priv->allocator,
143             GST_OBJECT_CAST(allocator));
144         gst_object_unref(allocator);
145         priv->video_info_index ^= 1;
146     }
147
148     if (!gst_buffer_pool_config_has_option(config,
149             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META))
150         goto error_no_vaapi_video_meta_option;
151
152     priv->has_video_meta = gst_buffer_pool_config_has_option(config,
153         GST_BUFFER_POOL_OPTION_VIDEO_META);
154
155     priv->has_texture_upload_meta = gst_buffer_pool_config_has_option(config,
156         GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
157
158     return GST_BUFFER_POOL_CLASS(gst_vaapi_video_buffer_pool_parent_class)->
159         set_config(pool, config);
160
161     /* ERRORS */
162 error_invalid_config:
163     {
164         GST_ERROR("invalid config");
165         return FALSE;
166     }
167 error_no_caps:
168     {
169         GST_ERROR("no valid caps in config");
170         return FALSE;
171     }
172 error_create_allocator:
173     {
174         GST_ERROR("failed to create GstVaapiVideoAllocator object");
175         return FALSE;
176     }
177 error_no_vaapi_video_meta_option:
178     {
179         GST_ERROR("no GstVaapiVideoMeta option");
180         return FALSE;
181     }
182 }
183
184 static GstFlowReturn
185 gst_vaapi_video_buffer_pool_alloc_buffer(GstBufferPool *pool,
186     GstBuffer **out_buffer_ptr, GstBufferPoolAcquireParams *params)
187 {
188     GstVaapiVideoBufferPoolPrivate * const priv =
189         GST_VAAPI_VIDEO_BUFFER_POOL(pool)->priv;
190     GstVaapiVideoMeta *meta;
191     GstMemory *mem;
192     GstBuffer *buffer;
193
194     if (!priv->allocator)
195         goto error_no_allocator;
196
197     meta = gst_vaapi_video_meta_new(priv->display);
198     if (!meta)
199         goto error_create_meta;
200
201     buffer = gst_vaapi_video_buffer_new(meta);
202     if (!buffer)
203         goto error_create_buffer;
204
205     mem = gst_vaapi_video_memory_new(priv->allocator, meta);
206     if (!mem)
207         goto error_create_memory;
208     gst_vaapi_video_meta_unref(meta);
209     gst_buffer_append_memory(buffer, mem);
210
211     if (priv->has_video_meta) {
212         GstVideoInfo * const vip =
213             &GST_VAAPI_VIDEO_ALLOCATOR_CAST(priv->allocator)->image_info;
214         GstVideoMeta *vmeta;
215
216         vmeta = gst_buffer_add_video_meta_full(buffer, 0,
217             GST_VIDEO_INFO_FORMAT(vip), GST_VIDEO_INFO_WIDTH(vip),
218             GST_VIDEO_INFO_HEIGHT(vip), GST_VIDEO_INFO_N_PLANES(vip),
219             &GST_VIDEO_INFO_PLANE_OFFSET(vip, 0),
220             &GST_VIDEO_INFO_PLANE_STRIDE(vip, 0));
221         vmeta->map = gst_video_meta_map_vaapi_memory;
222         vmeta->unmap = gst_video_meta_unmap_vaapi_memory;
223     }
224
225 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
226     if (priv->has_texture_upload_meta)
227         gst_buffer_add_texture_upload_meta(buffer);
228 #endif
229
230     *out_buffer_ptr = buffer;
231     return GST_FLOW_OK;
232
233     /* ERRORS */
234 error_no_allocator:
235     {
236         GST_ERROR("no GstAllocator in buffer pool");
237         return GST_FLOW_ERROR;
238     }
239 error_create_meta:
240     {
241         GST_ERROR("failed to allocate vaapi video meta");
242         return GST_FLOW_ERROR;
243     }
244 error_create_buffer:
245     {
246         GST_ERROR("failed to create video buffer");
247         gst_vaapi_video_meta_unref(meta);
248         return GST_FLOW_ERROR;
249     }
250 error_create_memory:
251     {
252         GST_ERROR("failed to create video memory");
253         gst_buffer_unref(buffer);
254         gst_vaapi_video_meta_unref(meta);
255         return GST_FLOW_ERROR;
256     }
257 }
258
259 static void
260 gst_vaapi_video_buffer_pool_reset_buffer(GstBufferPool *pool, GstBuffer *buffer)
261 {
262     GstMemory * const mem = gst_buffer_peek_memory(buffer, 0);
263
264     /* Release the underlying surface proxy */
265     gst_vaapi_video_memory_reset_surface(GST_VAAPI_VIDEO_MEMORY_CAST(mem));
266
267     GST_BUFFER_POOL_CLASS(gst_vaapi_video_buffer_pool_parent_class)->
268         reset_buffer(pool, buffer);
269 }
270
271 static void
272 gst_vaapi_video_buffer_pool_class_init(GstVaapiVideoBufferPoolClass *klass)
273 {
274     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
275     GstBufferPoolClass * const pool_class = GST_BUFFER_POOL_CLASS(klass);
276
277     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapivideopool,
278         "vaapivideopool", 0, "VA-API video pool");
279
280     g_type_class_add_private(klass, sizeof(GstVaapiVideoBufferPoolPrivate));
281
282     object_class->finalize      = gst_vaapi_video_buffer_pool_finalize;
283     object_class->set_property  = gst_vaapi_video_buffer_pool_set_property;
284     object_class->get_property  = gst_vaapi_video_buffer_pool_get_property;
285     pool_class->get_options     = gst_vaapi_video_buffer_pool_get_options;
286     pool_class->set_config      = gst_vaapi_video_buffer_pool_set_config;
287     pool_class->alloc_buffer    = gst_vaapi_video_buffer_pool_alloc_buffer;
288     pool_class->reset_buffer    = gst_vaapi_video_buffer_pool_reset_buffer;
289
290     /**
291      * GstVaapiVideoBufferPool:display:
292      *
293      * The #GstVaapiDisplay this object is bound to.
294      */
295     g_object_class_install_property
296         (object_class,
297          PROP_DISPLAY,
298          g_param_spec_pointer("display",
299                              "Display",
300                              "The GstVaapiDisplay to use for this video pool",
301                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
302 }
303
304 static void
305 gst_vaapi_video_buffer_pool_init(GstVaapiVideoBufferPool *pool)
306 {
307     GstVaapiVideoBufferPoolPrivate * const priv =
308         GST_VAAPI_VIDEO_BUFFER_POOL_GET_PRIVATE(pool);
309
310     pool->priv = priv;
311
312     gst_video_info_init(&priv->video_info[0]);
313     gst_video_info_init(&priv->video_info[1]);
314 }
315
316 GstBufferPool *
317 gst_vaapi_video_buffer_pool_new(GstVaapiDisplay *display)
318 {
319     return g_object_new(GST_VAAPI_TYPE_VIDEO_BUFFER_POOL,
320         "display", display, NULL);
321 }