Add VA surface, image, subpicture abstractions. Ported over from Gnash.
[profile/ivi/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiimage.c
1 /*
2  *  gstvaapiimage.c - VA image abstraction
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 <string.h>
23 #include "vaapi_utils.h"
24 #include "gstvaapiimage.h"
25 #include <va/va_backend.h>
26
27 #define DEBUG 1
28 #include "vaapi_debug.h"
29
30 G_DEFINE_TYPE(GstVaapiImage, gst_vaapi_image, G_TYPE_OBJECT);
31
32 #define GST_VAAPI_IMAGE_GET_PRIVATE(obj)                \
33     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                 \
34                                  GST_VAAPI_TYPE_IMAGE,  \
35                                  GstVaapiImagePrivate))
36
37 struct _GstVaapiImagePrivate {
38     GstVaapiDisplay    *display;
39     VAImage             image;
40     guchar             *image_data;
41     guint               width;
42     guint               height;
43     GstVaapiImageFormat format;
44 };
45
46 enum {
47     PROP_0,
48
49     PROP_DISPLAY,
50     PROP_IMAGE_ID,
51     PROP_WIDTH,
52     PROP_HEIGHT,
53     PROP_FORMAT
54 };
55
56 static void
57 gst_vaapi_image_destroy(GstVaapiImage *image)
58 {
59     GstVaapiImagePrivate * const priv = image->priv;
60     VADisplay dpy = gst_vaapi_display_get_display(priv->display);
61     VAStatus status;
62
63     gst_vaapi_image_unmap(image);
64
65     if (priv->image.image_id != VA_INVALID_ID) {
66         status = vaDestroyImage(dpy, priv->image.image_id);
67         if (!vaapi_check_status(status, "vaDestroyImage()"))
68             g_warning("failed to destroy image 0x%08x\n", priv->image.image_id);
69         priv->image.image_id = VA_INVALID_ID;
70     }
71
72     if (priv->display) {
73         g_object_unref(priv->display);
74         priv->display = NULL;
75     }
76 }
77
78 static gboolean
79 gst_vaapi_image_create(GstVaapiImage *image)
80 {
81     GstVaapiImagePrivate * const priv = image->priv;
82     const VAImageFormat *format;
83     VAStatus status;
84
85     if (!gst_vaapi_display_has_image_format(priv->display, priv->format))
86         return FALSE;
87
88     format = gst_vaapi_image_format_get_va_format(priv->format);
89
90     g_return_val_if_fail(format, FALSE);
91
92     status = vaCreateImage(
93         gst_vaapi_display_get_display(priv->display),
94         (VAImageFormat *)format,
95         priv->width,
96         priv->height,
97         &priv->image
98     );
99     if (!vaapi_check_status(status, "vaCreateImage()"))
100         return FALSE;
101
102     return TRUE;
103 }
104
105 static void
106 gst_vaapi_image_finalize(GObject *object)
107 {
108     gst_vaapi_image_destroy(GST_VAAPI_IMAGE(object));
109
110     G_OBJECT_CLASS(gst_vaapi_image_parent_class)->finalize(object);
111 }
112
113 static void
114 gst_vaapi_image_set_property(
115     GObject      *object,
116     guint         prop_id,
117     const GValue *value,
118     GParamSpec   *pspec
119 )
120 {
121     GstVaapiImage        * const image = GST_VAAPI_IMAGE(object);
122     GstVaapiImagePrivate * const priv  = image->priv;
123
124     switch (prop_id) {
125     case PROP_DISPLAY:
126         priv->display = g_object_ref(g_value_get_pointer(value));
127         break;
128     case PROP_WIDTH:
129         priv->width = g_value_get_uint(value);
130         break;
131     case PROP_HEIGHT:
132         priv->height = g_value_get_uint(value);
133         break;
134     case PROP_FORMAT:
135         priv->format = g_value_get_uint(value);
136         break;
137     default:
138         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
139         break;
140     }
141 }
142
143 static void
144 gst_vaapi_image_get_property(
145     GObject    *object,
146     guint       prop_id,
147     GValue     *value,
148     GParamSpec *pspec
149 )
150 {
151     GstVaapiImage        * const image = GST_VAAPI_IMAGE(object);
152     GstVaapiImagePrivate * const priv  = image->priv;
153
154     switch (prop_id) {
155     case PROP_DISPLAY:
156         g_value_set_pointer(value, g_object_ref(priv->display));
157         break;
158     case PROP_IMAGE_ID:
159         g_value_set_uint(value, gst_vaapi_image_get_id(image));
160         break;
161     case PROP_WIDTH:
162         g_value_set_uint(value, gst_vaapi_image_get_width(image));
163         break;
164     case PROP_HEIGHT:
165         g_value_set_uint(value, gst_vaapi_image_get_height(image));
166         break;
167     case PROP_FORMAT:
168         g_value_set_uint(value, gst_vaapi_image_get_format(image));
169         break;
170     default:
171         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
172         break;
173     }
174 }
175
176 static GObject *
177 gst_vaapi_image_constructor(
178     GType                  type,
179     guint                  n_params,
180     GObjectConstructParam *params
181 )
182 {
183     GstVaapiImage *image;
184     GObjectClass *parent_class;
185     GObject *object;
186
187     D(bug("gst_vaapi_image_constructor()\n"));
188
189     parent_class = G_OBJECT_CLASS(gst_vaapi_image_parent_class);
190     object = parent_class->constructor (type, n_params, params);
191
192     if (object) {
193         image = GST_VAAPI_IMAGE(object);
194         if (!gst_vaapi_image_create(image)) {
195             gst_vaapi_image_destroy(image);
196             object = NULL;
197         }
198     }
199     return object;
200 }
201
202 static void
203 gst_vaapi_image_class_init(GstVaapiImageClass *klass)
204 {
205     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
206
207     g_type_class_add_private(klass, sizeof(GstVaapiImagePrivate));
208
209     object_class->finalize     = gst_vaapi_image_finalize;
210     object_class->set_property = gst_vaapi_image_set_property;
211     object_class->get_property = gst_vaapi_image_get_property;
212     object_class->constructor  = gst_vaapi_image_constructor;
213
214     g_object_class_install_property
215         (object_class,
216          PROP_DISPLAY,
217          g_param_spec_object("display",
218                              "display",
219                              "GStreamer Va display",
220                              GST_VAAPI_TYPE_DISPLAY,
221                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
222
223     g_object_class_install_property
224         (object_class,
225          PROP_IMAGE_ID,
226          g_param_spec_uint("id",
227                            "VA image id",
228                            "VA image id",
229                            0, G_MAXUINT32, VA_INVALID_ID,
230                            G_PARAM_READABLE));
231
232     g_object_class_install_property
233         (object_class,
234          PROP_WIDTH,
235          g_param_spec_uint("width",
236                            "width",
237                            "Image width",
238                            0, G_MAXUINT32, 0,
239                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
240
241     g_object_class_install_property
242         (object_class,
243          PROP_HEIGHT,
244          g_param_spec_uint("height",
245                            "height",
246                            "Image height",
247                            0, G_MAXUINT32, 0,
248                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
249
250     g_object_class_install_property
251         (object_class,
252          PROP_FORMAT,
253          g_param_spec_uint("format",
254                            "format",
255                            "Image format",
256                            0, G_MAXUINT32, 0,
257                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
258 }
259
260 static void
261 gst_vaapi_image_init(GstVaapiImage *image)
262 {
263     GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
264
265     D(bug("gst_vaapi_image_init()\n"));
266
267     image->priv          = priv;
268     priv->display        = NULL;
269     priv->image_data     = NULL;
270     priv->width          = 0;
271     priv->height         = 0;
272     priv->format         = 0;
273
274     memset(&priv->image, 0, sizeof(priv->image));
275     priv->image.image_id = VA_INVALID_ID;
276     priv->image.buf      = VA_INVALID_ID;
277 }
278
279 GstVaapiImage *
280 gst_vaapi_image_new(
281     GstVaapiDisplay    *display,
282     guint               width,
283     guint               height,
284     GstVaapiImageFormat format
285 )
286 {
287     D(bug("gst_vaapi_image_new(): size %ux%u, format 0x%x\n",
288           width, height, format));
289
290     return g_object_new(GST_VAAPI_TYPE_IMAGE,
291                         "display", display,
292                         "width",   width,
293                         "height",  height,
294                         "format",  format,
295                         NULL);
296 }
297
298 VAImageID
299 gst_vaapi_image_get_id(GstVaapiImage *image)
300 {
301     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), VA_INVALID_ID);
302
303     return image->priv->image.image_id;
304 }
305
306 GstVaapiDisplay *
307 gst_vaapi_image_get_display(GstVaapiImage *image)
308 {
309     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
310
311     return g_object_ref(image->priv->display);
312 }
313
314 guint
315 gst_vaapi_image_get_width(GstVaapiImage *image)
316 {
317     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
318
319     return image->priv->width;
320 }
321
322 guint
323 gst_vaapi_image_get_height(GstVaapiImage *image)
324 {
325     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
326
327     return image->priv->height;
328 }
329
330 guint
331 gst_vaapi_image_get_format(GstVaapiImage *image)
332 {
333     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
334
335     return image->priv->format;
336 }
337
338 static inline gboolean
339 _gst_vaapi_image_is_mapped(GstVaapiImage *image)
340 {
341     return image->priv->image_data != NULL;
342 }
343
344 gboolean
345 gst_vaapi_image_is_mapped(GstVaapiImage *image)
346 {
347     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
348
349     return _gst_vaapi_image_is_mapped(image);
350 }
351
352 gboolean
353 gst_vaapi_image_map(GstVaapiImage *image)
354 {
355     void *image_data;
356     VAStatus status;
357
358     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
359
360     if (_gst_vaapi_image_is_mapped(image))
361         return TRUE;
362
363     status = vaMapBuffer(
364         gst_vaapi_display_get_display(image->priv->display),
365         image->priv->image.buf,
366         &image_data
367     );
368     if (!vaapi_check_status(status, "vaMapBuffer()"))
369         return FALSE;
370
371     image->priv->image_data = image_data;
372     return TRUE;
373 }
374
375 gboolean
376 gst_vaapi_image_unmap(GstVaapiImage *image)
377 {
378     VAStatus status;
379
380     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
381
382     if (!_gst_vaapi_image_is_mapped(image))
383         return FALSE;
384
385     status = vaUnmapBuffer(
386         gst_vaapi_display_get_display(image->priv->display),
387         image->priv->image.buf
388     );
389     if (!vaapi_check_status(status, "vaUnmapBuffer()"))
390         return FALSE;
391
392     image->priv->image_data = NULL;
393     return TRUE;
394 }
395
396 guint
397 gst_vaapi_image_get_plane_count(GstVaapiImage *image)
398 {
399     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
400     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
401
402     return image->priv->image.num_planes;
403 }
404
405 guchar *
406 gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane)
407 {
408     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), NULL);
409     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), NULL);
410     g_return_val_if_fail(plane < image->priv->image.num_planes, NULL);
411
412     return image->priv->image_data + image->priv->image.offsets[plane];
413 }
414
415 guint
416 gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane)
417 {
418     g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), 0);
419     g_return_val_if_fail(_gst_vaapi_image_is_mapped(image), 0);
420     g_return_val_if_fail(plane < image->priv->image.num_planes, 0);
421
422     return image->priv->image.pitches[plane];
423 }