Add VA surface pool (lazy allocator).
[vaapi:gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapisurfacepool.c
1 /*
2  *  gstvaapisurfacepool.c - Gst VA surface pool
3  *
4  *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "gstvaapisurfacepool.h"
23
24 #define DEBUG 1
25 #include "vaapi_debug.h"
26
27 G_DEFINE_TYPE(GstVaapiSurfacePool, gst_vaapi_surface_pool, G_TYPE_OBJECT);
28
29 #define GST_VAAPI_SURFACE_POOL_GET_PRIVATE(obj)                 \
30     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
31                                  GST_VAAPI_TYPE_SURFACE_POOL,   \
32                                  GstVaapiSurfacePoolPrivate))
33
34 struct _GstVaapiSurfacePoolPrivate {
35     GstVaapiDisplay    *display;
36     GQueue              free_surfaces;
37     GList              *used_surfaces;
38     GstCaps            *caps;
39     GstVaapiChromaType  chroma_type;
40     guint               width;
41     guint               height;
42 };
43
44 enum {
45     PROP_0,
46
47     PROP_DISPLAY,
48     PROP_CAPS,
49 };
50
51 static void
52 gst_vaapi_surface_pool_clear(GstVaapiSurfacePool *pool)
53 {
54     GstVaapiSurfacePoolPrivate * const priv = pool->priv;
55     GstVaapiSurface *surface;
56     GList *list, *next;
57
58     for (list = priv->used_surfaces; list; list = next) {
59         next = list->next;
60         g_object_unref(list->data);
61         g_list_free_1(list);
62     }
63     priv->used_surfaces = NULL;
64
65     while ((surface = g_queue_pop_head(&priv->free_surfaces)))
66         g_object_unref(surface);
67 }
68
69 static void
70 gst_vaapi_surface_pool_destroy(GstVaapiSurfacePool *pool)
71 {
72     GstVaapiSurfacePoolPrivate * const priv = pool->priv;
73
74     gst_vaapi_surface_pool_clear(pool);
75
76     if (priv->caps) {
77         gst_caps_unref(priv->caps);
78         priv->caps = NULL;
79     }
80
81     if (priv->display) {
82         g_object_unref(priv->display);
83         priv->display = NULL;
84     }
85 }
86
87 static void
88 gst_vaapi_surface_pool_finalize(GObject *object)
89 {
90     gst_vaapi_surface_pool_destroy(GST_VAAPI_SURFACE_POOL(object));
91
92     G_OBJECT_CLASS(gst_vaapi_surface_pool_parent_class)->finalize(object);
93 }
94
95 static void
96 gst_vaapi_surface_pool_set_property(
97     GObject      *object,
98     guint         prop_id,
99     const GValue *value,
100     GParamSpec   *pspec
101 )
102 {
103     GstVaapiSurfacePool * const pool = GST_VAAPI_SURFACE_POOL(object);
104
105     switch (prop_id) {
106     case PROP_DISPLAY:
107         pool->priv->display = g_object_ref(g_value_get_object(value));
108         break;
109     case PROP_CAPS:
110         gst_vaapi_surface_pool_set_caps(pool, g_value_get_pointer(value));
111         break;
112     default:
113         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
114         break;
115     }
116 }
117
118 static void
119 gst_vaapi_surface_pool_get_property(
120     GObject    *object,
121     guint       prop_id,
122     GValue     *value,
123     GParamSpec *pspec
124 )
125 {
126     GstVaapiSurfacePool * const pool = GST_VAAPI_SURFACE_POOL(object);
127
128     switch (prop_id) {
129     case PROP_DISPLAY:
130         g_value_set_object(value, pool->priv->display);
131         break;
132     case PROP_CAPS:
133         g_value_set_pointer(value, gst_vaapi_surface_pool_get_caps(pool));
134         break;
135     default:
136         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
137         break;
138     }
139 }
140
141 static void
142 gst_vaapi_surface_pool_class_init(GstVaapiSurfacePoolClass *klass)
143 {
144     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
145
146     g_type_class_add_private(klass, sizeof(GstVaapiSurfacePoolPrivate));
147
148     object_class->finalize      = gst_vaapi_surface_pool_finalize;
149     object_class->set_property  = gst_vaapi_surface_pool_set_property;
150     object_class->get_property  = gst_vaapi_surface_pool_get_property;
151
152     g_object_class_install_property
153         (object_class,
154          PROP_DISPLAY,
155          g_param_spec_object("display",
156                              "display",
157                              "Gstreamer/VA display",
158                              GST_VAAPI_TYPE_DISPLAY,
159                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
160
161     g_object_class_install_property
162         (object_class,
163          PROP_CAPS,
164          g_param_spec_pointer("caps",
165                               "surface caps",
166                               "Surface caps",
167                               G_PARAM_READWRITE));
168 }
169
170 static void
171 gst_vaapi_surface_pool_init(GstVaapiSurfacePool *pool)
172 {
173     GstVaapiSurfacePoolPrivate *priv = GST_VAAPI_SURFACE_POOL_GET_PRIVATE(pool);
174
175     pool->priv          = priv;
176     priv->display       = NULL;
177     priv->used_surfaces = NULL;
178     priv->caps          = NULL;
179     priv->chroma_type   = 0;
180     priv->width         = 0;
181     priv->height        = 0;
182
183     g_queue_init(&priv->free_surfaces);
184 }
185
186 GstVaapiSurfacePool *
187 gst_vaapi_surface_pool_new(GstVaapiDisplay *display, GstCaps *caps)
188 {
189     return g_object_new(GST_VAAPI_TYPE_SURFACE_POOL,
190                         "display", display,
191                         "caps",    caps,
192                         NULL);
193 }
194
195 GstCaps *
196 gst_vaapi_surface_pool_get_caps(GstVaapiSurfacePool *pool)
197 {
198     g_return_val_if_fail(GST_VAAPI_IS_SURFACE_POOL(pool), NULL);
199
200     return pool->priv->caps;
201 }
202
203 void
204 gst_vaapi_surface_pool_set_caps(GstVaapiSurfacePool *pool, GstCaps *caps)
205 {
206     GstVaapiSurfacePoolPrivate *priv;
207     GstStructure *structure;
208     gint width, height;
209
210     g_return_if_fail(GST_VAAPI_IS_SURFACE_POOL(pool));
211     g_return_if_fail(GST_IS_CAPS(caps));
212
213     priv = pool->priv;
214
215     structure = gst_caps_get_structure(caps, 0);
216     gst_structure_get_int(structure, "width", &width);
217     gst_structure_get_int(structure, "height", &height);
218
219     /* Don't do anything if caps have not changed */
220     if (width == priv->width && height == priv->height)
221         return;
222
223     gst_vaapi_surface_pool_clear(pool);
224
225     priv->caps          = gst_caps_ref(caps);
226     priv->chroma_type   = GST_VAAPI_CHROMA_TYPE_YUV420;
227     priv->width         = width;
228     priv->height        = height;
229 }
230
231 GstVaapiSurface *
232 gst_vaapi_surface_pool_new_surface(GstVaapiSurfacePool *pool)
233 {
234     GstVaapiSurfacePoolPrivate *priv;
235     GstVaapiSurface *surface;
236
237     g_return_val_if_fail(GST_VAAPI_IS_SURFACE_POOL(pool), NULL);
238
239     priv = pool->priv;
240
241     surface = g_queue_pop_head(&priv->free_surfaces);
242     if (!surface) {
243         surface = gst_vaapi_surface_new(
244             priv->display,
245             priv->chroma_type,
246             priv->width,
247             priv->height
248         );
249         if (!surface)
250             return NULL;
251     }
252
253     priv->used_surfaces = g_list_prepend(priv->used_surfaces, surface);
254     return g_object_ref(surface);
255 }
256
257 void
258 gst_vaapi_surface_pool_free_surface(
259     GstVaapiSurfacePool *pool,
260     GstVaapiSurface     *surface
261 )
262 {
263     GstVaapiSurfacePoolPrivate *priv;
264     GList *list;
265
266     g_return_if_fail(GST_VAAPI_IS_SURFACE_POOL(pool));
267     g_return_if_fail(GST_VAAPI_IS_SURFACE(surface));
268
269     priv = pool->priv;
270     list = g_list_find(priv->used_surfaces, surface);
271     if (!list)
272         return;
273
274     g_object_unref(surface);
275     priv->used_surfaces = g_list_delete_link(priv->used_surfaces, list);
276     g_queue_push_tail(&priv->free_surfaces, surface);
277 }