surfaceproxy: drop accessors to obsolete attributes.
[vaapi: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, gst_vaapi_picture);
44
45 enum {
46     GST_VAAPI_CREATE_PICTURE_FLAG_CLONE = 1 << 0,
47     GST_VAAPI_CREATE_PICTURE_FLAG_FIELD = 1 << 1,
48 };
49
50 static void
51 destroy_slice_cb(gpointer data, gpointer user_data)
52 {
53     GstVaapiMiniObject * const object = data;
54
55     gst_vaapi_mini_object_unref(object);
56 }
57
58 void
59 gst_vaapi_picture_destroy(GstVaapiPicture *picture)
60 {
61     if (picture->slices) {
62         g_ptr_array_foreach(picture->slices, destroy_slice_cb, NULL);
63         g_ptr_array_free(picture->slices, TRUE);
64         picture->slices = NULL;
65     }
66
67     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)&picture->iq_matrix,
68         NULL);
69     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)&picture->huf_table,
70         NULL);
71     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)&picture->bitplane,
72         NULL);
73
74     if (picture->proxy) {
75         gst_vaapi_surface_proxy_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     if (picture->frame) {
89         gst_video_codec_frame_unref(picture->frame);
90         picture->frame = NULL;
91     }
92 }
93
94 gboolean
95 gst_vaapi_picture_create(
96     GstVaapiPicture                          *picture,
97     const GstVaapiCodecObjectConstructorArgs *args
98 )
99 {
100     gboolean success;
101
102     if (args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_CLONE) {
103         GstVaapiPicture * const parent_picture = GST_VAAPI_PICTURE(args->data);
104
105         picture->proxy   = gst_vaapi_surface_proxy_ref(parent_picture->proxy);
106         picture->surface = gst_vaapi_surface_proxy_get_surface(picture->proxy);
107         picture->type    = parent_picture->type;
108         picture->pts     = parent_picture->pts;
109         picture->poc     = parent_picture->poc;
110
111         // Copy all picture flags but "output"
112         GST_VAAPI_PICTURE_FLAG_SET(
113             picture,
114             GST_VAAPI_PICTURE_FLAGS(parent_picture) &
115             (GST_VAAPI_PICTURE_FLAG_SKIPPED     |
116              GST_VAAPI_PICTURE_FLAG_REFERENCE   |
117              GST_VAAPI_PICTURE_FLAG_INTERLACED  |
118              GST_VAAPI_PICTURE_FLAG_FF          |
119              GST_VAAPI_PICTURE_FLAG_TFF)
120         );
121
122         picture->structure = parent_picture->structure;
123         if ((args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_FIELD) &&
124             GST_VAAPI_PICTURE_IS_INTERLACED(picture)) {
125             switch (picture->structure) {
126             case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
127                 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
128                 break;
129             case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
130                 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
131                 break;
132             }
133             GST_VAAPI_PICTURE_FLAG_UNSET(picture, GST_VAAPI_PICTURE_FLAG_FF);
134         }
135     }
136     else {
137         picture->type = GST_VAAPI_PICTURE_TYPE_NONE;
138         picture->pts  = GST_CLOCK_TIME_NONE;
139
140         picture->surface = gst_vaapi_context_get_surface(GET_CONTEXT(picture));
141         if (!picture->surface)
142             return FALSE;
143
144         picture->proxy =
145             gst_vaapi_surface_proxy_new(GET_CONTEXT(picture), picture->surface);
146         if (!picture->proxy)
147             return FALSE;
148
149         picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
150         GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_FF);
151     }
152     picture->surface_id = gst_vaapi_surface_get_id(picture->surface);
153
154     picture->param_id = VA_INVALID_ID;
155     success = vaapi_create_buffer(
156         GET_VA_DISPLAY(picture),
157         GET_VA_CONTEXT(picture),
158         VAPictureParameterBufferType,
159         args->param_size,
160         args->param,
161         &picture->param_id,
162         &picture->param
163     );
164     if (!success)
165         return FALSE;
166     picture->param_size = args->param_size;
167
168     picture->slices = g_ptr_array_new();
169     if (!picture->slices)
170         return FALSE;
171
172     picture->frame = gst_video_codec_frame_ref(
173         GST_VAAPI_DECODER_CODEC_FRAME(GET_DECODER(picture)));
174     return TRUE;
175 }
176
177 GstVaapiPicture *
178 gst_vaapi_picture_new(
179     GstVaapiDecoder *decoder,
180     gconstpointer    param,
181     guint            param_size
182 )
183 {
184     GstVaapiCodecObject *object;
185
186     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
187
188     object = gst_vaapi_codec_object_new(
189         &GstVaapiPictureClass,
190         GST_VAAPI_CODEC_BASE(decoder),
191         param, param_size,
192         NULL, 0,
193         0
194     );
195     if (!object)
196         return NULL;
197     return GST_VAAPI_PICTURE_CAST(object);
198 }
199
200 GstVaapiPicture *
201 gst_vaapi_picture_new_field(GstVaapiPicture *picture)
202 {
203     GstVaapiDecoder * const decoder = GET_DECODER(picture);
204     GstVaapiCodecObject *object;
205
206     object = gst_vaapi_codec_object_new(
207         gst_vaapi_codec_object_get_class(&picture->parent_instance),
208         GST_VAAPI_CODEC_BASE(decoder),
209         NULL, picture->param_size,
210         picture, 0,
211         (GST_VAAPI_CREATE_PICTURE_FLAG_CLONE|
212          GST_VAAPI_CREATE_PICTURE_FLAG_FIELD)
213     );
214     if (!object)
215         return NULL;
216     return GST_VAAPI_PICTURE_CAST(object);
217 }
218
219 void
220 gst_vaapi_picture_add_slice(GstVaapiPicture *picture, GstVaapiSlice *slice)
221 {
222     g_return_if_fail(GST_VAAPI_IS_PICTURE(picture));
223     g_return_if_fail(GST_VAAPI_IS_SLICE(slice));
224
225     g_ptr_array_add(picture->slices, slice);
226 }
227
228 static gboolean
229 do_decode(VADisplay dpy, VAContextID ctx, VABufferID *buf_id, void **buf_ptr)
230 {
231     VAStatus status;
232
233     vaapi_unmap_buffer(dpy, *buf_id, buf_ptr);
234
235     status = vaRenderPicture(dpy, ctx, buf_id, 1);
236     if (!vaapi_check_status(status, "vaRenderPicture()"))
237         return FALSE;
238
239     /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */
240     vaapi_destroy_buffer(dpy, buf_id);
241     return TRUE;
242 }
243
244 gboolean
245 gst_vaapi_picture_decode(GstVaapiPicture *picture)
246 {
247     GstVaapiIqMatrix *iq_matrix;
248     GstVaapiBitPlane *bitplane;
249     GstVaapiHuffmanTable *huf_table;
250     VADisplay va_display;
251     VAContextID va_context;
252     VAStatus status;
253     guint i;
254
255     g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
256
257     va_display = GET_VA_DISPLAY(picture);
258     va_context = GET_VA_CONTEXT(picture);
259
260     GST_DEBUG("decode picture 0x%08x", picture->surface_id);
261
262     status = vaBeginPicture(va_display, va_context, picture->surface_id);
263     if (!vaapi_check_status(status, "vaBeginPicture()"))
264         return FALSE;
265
266     if (!do_decode(va_display, va_context, &picture->param_id, &picture->param))
267         return FALSE;
268
269     iq_matrix = picture->iq_matrix;
270     if (iq_matrix && !do_decode(va_display, va_context,
271                                 &iq_matrix->param_id, &iq_matrix->param))
272         return FALSE;
273
274     bitplane = picture->bitplane;
275     if (bitplane && !do_decode(va_display, va_context,
276                                &bitplane->data_id, (void **)&bitplane->data))
277         return FALSE;
278
279     huf_table = picture->huf_table;
280     if (huf_table && !do_decode(va_display, va_context,
281                                 &huf_table->param_id,
282                                 (void **)&huf_table->param))
283         return FALSE;
284
285     for (i = 0; i < picture->slices->len; i++) {
286         GstVaapiSlice * const slice = g_ptr_array_index(picture->slices, i);
287         VABufferID va_buffers[2];
288
289         vaapi_unmap_buffer(va_display, slice->param_id, NULL);
290         va_buffers[0] = slice->param_id;
291         va_buffers[1] = slice->data_id;
292
293         status = vaRenderPicture(va_display, va_context, va_buffers, 2);
294         if (!vaapi_check_status(status, "vaRenderPicture()"))
295             return FALSE;
296
297         vaapi_destroy_buffer(va_display, &slice->param_id);
298         vaapi_destroy_buffer(va_display, &slice->data_id);
299     }
300
301     status = vaEndPicture(va_display, va_context);
302     if (!vaapi_check_status(status, "vaEndPicture()"))
303         return FALSE;
304     return TRUE;
305 }
306
307 gboolean
308 gst_vaapi_picture_output(GstVaapiPicture *picture)
309 {
310     GstVaapiSurfaceProxy *proxy;
311     GstVideoCodecFrame *out_frame;
312
313     g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
314
315     if (!picture->proxy)
316         return FALSE;
317
318     out_frame = gst_video_codec_frame_ref(picture->frame);
319
320     proxy = gst_vaapi_surface_proxy_ref(picture->proxy);
321     gst_video_codec_frame_set_user_data(out_frame,
322         proxy, (GDestroyNotify)gst_vaapi_mini_object_unref);
323
324     if (!GST_CLOCK_TIME_IS_VALID(out_frame->pts))
325         out_frame->pts = picture->pts;
326     if (GST_VAAPI_PICTURE_IS_SKIPPED(picture))
327         GST_VIDEO_CODEC_FRAME_FLAG_SET(out_frame,
328             GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
329     if (GST_VAAPI_PICTURE_IS_TFF(picture))
330         GST_VIDEO_CODEC_FRAME_FLAG_SET(out_frame,
331             GST_VIDEO_CODEC_FRAME_FLAG_TFF);
332
333     gst_vaapi_decoder_push_frame(GET_DECODER(picture), out_frame);
334
335     GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_OUTPUT);
336     return TRUE;
337 }
338
339 /* ------------------------------------------------------------------------- */
340 /* --- Slices                                                            --- */
341 /* ------------------------------------------------------------------------- */
342
343 GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiSlice, gst_vaapi_slice);
344
345 void
346 gst_vaapi_slice_destroy(GstVaapiSlice *slice)
347 {
348     VADisplay const va_display = GET_VA_DISPLAY(slice);
349
350     vaapi_destroy_buffer(va_display, &slice->data_id);
351     vaapi_destroy_buffer(va_display, &slice->param_id);
352     slice->param = NULL;
353 }
354
355 gboolean
356 gst_vaapi_slice_create(
357     GstVaapiSlice                            *slice,
358     const GstVaapiCodecObjectConstructorArgs *args
359 )
360 {
361     VASliceParameterBufferBase *slice_param;
362     gboolean success;
363
364     slice->data_id = VA_INVALID_ID;
365     success = vaapi_create_buffer(
366         GET_VA_DISPLAY(slice),
367         GET_VA_CONTEXT(slice),
368         VASliceDataBufferType,
369         args->data_size,
370         args->data,
371         &slice->data_id,
372         NULL
373     );
374     if (!success)
375         return FALSE;
376
377     slice->param_id = VA_INVALID_ID;
378     success = vaapi_create_buffer(
379         GET_VA_DISPLAY(slice),
380         GET_VA_CONTEXT(slice),
381         VASliceParameterBufferType,
382         args->param_size,
383         args->param,
384         &slice->param_id,
385         &slice->param
386     );
387     if (!success)
388         return FALSE;
389
390     slice_param                    = slice->param;
391     slice_param->slice_data_size   = args->data_size;
392     slice_param->slice_data_offset = 0;
393     slice_param->slice_data_flag   = VA_SLICE_DATA_FLAG_ALL;
394     return TRUE;
395 }
396
397 GstVaapiSlice *
398 gst_vaapi_slice_new(
399     GstVaapiDecoder *decoder,
400     gconstpointer    param,
401     guint            param_size,
402     const guchar    *data,
403     guint            data_size
404 )
405 {
406     GstVaapiCodecObject *object;
407
408     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
409
410     object = gst_vaapi_codec_object_new(
411         &GstVaapiSliceClass,
412         GST_VAAPI_CODEC_BASE(decoder),
413         param, param_size,
414         data, data_size,
415         0
416     );
417     return GST_VAAPI_SLICE_CAST(object);
418 }