decoder: add OUTPUT flag to pictures.
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder_objects.c
1 /*
2  *  gstvaapidecoder_objects.c - VA decoder objects helpers
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *  Copyright (C) 2011-2012 Intel Corporation
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 "sysdeps.h"
24 #include <string.h>
25 #include <gst/vaapi/gstvaapicontext.h>
26 #include "gstvaapidecoder_objects.h"
27 #include "gstvaapidecoder_priv.h"
28 #include "gstvaapicompat.h"
29 #include "gstvaapiutils.h"
30
31 #define DEBUG 1
32 #include "gstvaapidebug.h"
33
34 #define GET_DECODER(obj)    GST_VAAPI_DECODER_CAST((obj)->parent_instance.codec)
35 #define GET_CONTEXT(obj)    GET_DECODER(obj)->priv->context
36 #define GET_VA_DISPLAY(obj) GET_DECODER(obj)->priv->va_display
37 #define GET_VA_CONTEXT(obj) GET_DECODER(obj)->priv->va_context
38
39 /* ------------------------------------------------------------------------- */
40 /* --- Pictures                                                          --- */
41 /* ------------------------------------------------------------------------- */
42
43 GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiPicture,
44                             gst_vaapi_picture,
45                             GST_VAAPI_TYPE_CODEC_OBJECT)
46
47 static void
48 destroy_slice_cb(gpointer data, gpointer user_data)
49 {
50     GstMiniObject * const object = data;
51
52     gst_mini_object_unref(object);
53 }
54
55 static void
56 gst_vaapi_picture_destroy(GstVaapiPicture *picture)
57 {
58     if (picture->slices) {
59         g_ptr_array_foreach(picture->slices, destroy_slice_cb, NULL);
60         g_ptr_array_free(picture->slices, TRUE);
61         picture->slices = NULL;
62     }
63
64     if (picture->iq_matrix) {
65         gst_mini_object_unref(GST_MINI_OBJECT(picture->iq_matrix));
66         picture->iq_matrix = NULL;
67     }
68
69     if (picture->bitplane) {
70         gst_mini_object_unref(GST_MINI_OBJECT(picture->bitplane));
71         picture->bitplane = NULL;
72     }
73
74     if (picture->proxy) {
75         g_object_unref(picture->proxy);
76         picture->proxy = NULL;
77     }
78     else if (picture->surface) {
79         /* Explicitly release any surface that was not bound to a proxy */
80         gst_vaapi_context_put_surface(GET_CONTEXT(picture), picture->surface);
81     }
82     picture->surface_id = VA_INVALID_ID;
83     picture->surface = NULL;
84
85     vaapi_destroy_buffer(GET_VA_DISPLAY(picture), &picture->param_id);
86     picture->param = NULL;
87 }
88
89 static gboolean
90 gst_vaapi_picture_create(
91     GstVaapiPicture                          *picture,
92     const GstVaapiCodecObjectConstructorArgs *args
93 )
94 {
95     gboolean success;
96
97     picture->surface = gst_vaapi_context_get_surface(GET_CONTEXT(picture));
98     if (!picture->surface)
99         return FALSE;
100     picture->surface_id = gst_vaapi_surface_get_id(picture->surface);
101
102     picture->proxy =
103         gst_vaapi_surface_proxy_new(GET_CONTEXT(picture), picture->surface);
104     if (!picture->proxy)
105         return FALSE;
106
107     success = vaapi_create_buffer(
108         GET_VA_DISPLAY(picture),
109         GET_VA_CONTEXT(picture),
110         VAPictureParameterBufferType,
111         args->param_size,
112         args->param,
113         &picture->param_id,
114         &picture->param
115     );
116     if (!success)
117         return FALSE;
118
119     picture->slices = g_ptr_array_new();
120     if (!picture->slices)
121         return FALSE;
122     return TRUE;
123 }
124
125 static void
126 gst_vaapi_picture_init(GstVaapiPicture *picture)
127 {
128     picture->type       = GST_VAAPI_PICTURE_TYPE_NONE;
129     picture->surface    = NULL;
130     picture->proxy      = NULL;
131     picture->surface_id = VA_INVALID_ID;
132     picture->param      = NULL;
133     picture->param_id   = VA_INVALID_ID;
134     picture->slices     = NULL;
135     picture->iq_matrix  = NULL;
136     picture->bitplane   = NULL;
137     picture->pts        = GST_CLOCK_TIME_NONE;
138 }
139
140 GstVaapiPicture *
141 gst_vaapi_picture_new(
142     GstVaapiDecoder *decoder,
143     gconstpointer    param,
144     guint            param_size
145 )
146 {
147     GstVaapiCodecObject *object;
148
149     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
150
151     object = gst_vaapi_codec_object_new(
152         GST_VAAPI_TYPE_PICTURE,
153         GST_VAAPI_CODEC_BASE(decoder),
154         param, param_size,
155         NULL, 0
156     );
157     if (!object)
158         return NULL;
159     return GST_VAAPI_PICTURE_CAST(object);
160 }
161
162 void
163 gst_vaapi_picture_add_slice(GstVaapiPicture *picture, GstVaapiSlice *slice)
164 {
165     g_return_if_fail(GST_VAAPI_IS_PICTURE(picture));
166     g_return_if_fail(GST_VAAPI_IS_SLICE(slice));
167
168     g_ptr_array_add(picture->slices, slice);
169 }
170
171 static gboolean
172 do_decode(VADisplay dpy, VAContextID ctx, VABufferID *buf_id, void **buf_ptr)
173 {
174     VAStatus status;
175
176     vaapi_unmap_buffer(dpy, *buf_id, buf_ptr);
177
178     status = vaRenderPicture(dpy, ctx, buf_id, 1);
179     if (!vaapi_check_status(status, "vaRenderPicture()"))
180         return FALSE;
181
182     /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */
183     vaapi_destroy_buffer(dpy, buf_id);
184     return TRUE;
185 }
186
187 gboolean
188 gst_vaapi_picture_decode(GstVaapiPicture *picture)
189 {
190     GstVaapiIqMatrix *iq_matrix;
191     GstVaapiBitPlane *bitplane;
192     VADisplay va_display;
193     VAContextID va_context;
194     VAStatus status;
195     guint i;
196
197     g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
198
199     va_display = GET_VA_DISPLAY(picture);
200     va_context = GET_VA_CONTEXT(picture);
201
202     GST_DEBUG("decode picture 0x%08x", picture->surface_id);
203
204     status = vaBeginPicture(va_display, va_context, picture->surface_id);
205     if (!vaapi_check_status(status, "vaBeginPicture()"))
206         return FALSE;
207
208     if (!do_decode(va_display, va_context, &picture->param_id, &picture->param))
209         return FALSE;
210
211     iq_matrix = picture->iq_matrix;
212     if (iq_matrix && !do_decode(va_display, va_context,
213                                 &iq_matrix->param_id, &iq_matrix->param))
214         return FALSE;
215
216     bitplane = picture->bitplane;
217     if (bitplane && !do_decode(va_display, va_context,
218                                &bitplane->data_id, (void **)&bitplane->data))
219         return FALSE;
220
221     for (i = 0; i < picture->slices->len; i++) {
222         GstVaapiSlice * const slice = g_ptr_array_index(picture->slices, i);
223         VABufferID va_buffers[2];
224
225         vaapi_unmap_buffer(va_display, slice->param_id, NULL);
226         va_buffers[0] = slice->param_id;
227         va_buffers[1] = slice->data_id;
228
229         status = vaRenderPicture(va_display, va_context, va_buffers, 2);
230         if (!vaapi_check_status(status, "vaRenderPicture()"))
231             return FALSE;
232
233         vaapi_destroy_buffer(va_display, &slice->param_id);
234         vaapi_destroy_buffer(va_display, &slice->data_id);
235     }
236
237     status = vaEndPicture(va_display, va_context);
238     if (!vaapi_check_status(status, "vaEndPicture()"))
239         return FALSE;
240     return TRUE;
241 }
242
243 gboolean
244 gst_vaapi_picture_output(GstVaapiPicture *picture)
245 {
246     GstVaapiSurfaceProxy *proxy;
247
248     g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
249
250     if (!picture->proxy)
251         return FALSE;
252
253     if (!GST_VAAPI_PICTURE_IS_SKIPPED(picture)) {
254         proxy = g_object_ref(picture->proxy);
255         gst_vaapi_surface_proxy_set_timestamp(proxy, picture->pts);
256         gst_vaapi_decoder_push_surface_proxy(GET_DECODER(picture), proxy);
257     }
258     GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_OUTPUT);
259     return TRUE;
260 }
261
262 /* ------------------------------------------------------------------------- */
263 /* --- Slices                                                            --- */
264 /* ------------------------------------------------------------------------- */
265
266 GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiSlice,
267                             gst_vaapi_slice,
268                             GST_VAAPI_TYPE_CODEC_OBJECT)
269
270 static void
271 gst_vaapi_slice_destroy(GstVaapiSlice *slice)
272 {
273     VADisplay const va_display = GET_VA_DISPLAY(slice);
274
275     vaapi_destroy_buffer(va_display, &slice->data_id);
276     vaapi_destroy_buffer(va_display, &slice->param_id);
277     slice->param = NULL;
278 }
279
280 static gboolean
281 gst_vaapi_slice_create(
282     GstVaapiSlice                            *slice,
283     const GstVaapiCodecObjectConstructorArgs *args
284 )
285 {
286     VASliceParameterBufferBase *slice_param;
287     gboolean success;
288
289     success = vaapi_create_buffer(
290         GET_VA_DISPLAY(slice),
291         GET_VA_CONTEXT(slice),
292         VASliceDataBufferType,
293         args->data_size,
294         args->data,
295         &slice->data_id,
296         NULL
297     );
298     if (!success)
299         return FALSE;
300
301     success = vaapi_create_buffer(
302         GET_VA_DISPLAY(slice),
303         GET_VA_CONTEXT(slice),
304         VASliceParameterBufferType,
305         args->param_size,
306         args->param,
307         &slice->param_id,
308         &slice->param
309     );
310     if (!success)
311         return FALSE;
312
313     slice_param                    = slice->param;
314     slice_param->slice_data_size   = args->data_size;
315     slice_param->slice_data_offset = 0;
316     slice_param->slice_data_flag   = VA_SLICE_DATA_FLAG_ALL;
317     return TRUE;
318 }
319
320 static void
321 gst_vaapi_slice_init(GstVaapiSlice *slice)
322 {
323     slice->param        = NULL;
324     slice->param_id     = VA_INVALID_ID;
325     slice->data_id      = VA_INVALID_ID;
326 }
327
328 GstVaapiSlice *
329 gst_vaapi_slice_new(
330     GstVaapiDecoder *decoder,
331     gconstpointer    param,
332     guint            param_size,
333     const guchar    *data,
334     guint            data_size
335 )
336 {
337     GstVaapiCodecObject *object;
338
339     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
340
341     object = gst_vaapi_codec_object_new(
342         GST_VAAPI_TYPE_SLICE,
343         GST_VAAPI_CODEC_BASE(decoder),
344         param, param_size,
345         data, data_size
346     );
347     return GST_VAAPI_SLICE_CAST(object);
348 }