legal: add per-file authorship information.
[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  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2013 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 #include "sysdeps.h"
26 #include <string.h>
27 #include <gst/vaapi/gstvaapicontext.h>
28 #include "gstvaapidecoder_objects.h"
29 #include "gstvaapidecoder_priv.h"
30 #include "gstvaapisurfaceproxy_priv.h"
31 #include "gstvaapicompat.h"
32 #include "gstvaapiutils.h"
33
34 #define DEBUG 1
35 #include "gstvaapidebug.h"
36
37 #define GET_DECODER(obj)    GST_VAAPI_DECODER_CAST((obj)->parent_instance.codec)
38 #define GET_CONTEXT(obj)    GET_DECODER(obj)->context
39 #define GET_VA_DISPLAY(obj) GET_DECODER(obj)->va_display
40 #define GET_VA_CONTEXT(obj) GET_DECODER(obj)->va_context
41
42 static inline void
43 gst_video_codec_frame_clear(GstVideoCodecFrame **frame_ptr)
44 {
45     if (!*frame_ptr)
46         return;
47     gst_video_codec_frame_unref(*frame_ptr);
48     *frame_ptr = NULL;
49 }
50
51 /* ------------------------------------------------------------------------- */
52 /* --- Pictures                                                          --- */
53 /* ------------------------------------------------------------------------- */
54
55 GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiPicture, gst_vaapi_picture);
56
57 enum {
58     GST_VAAPI_CREATE_PICTURE_FLAG_CLONE = 1 << 0,
59     GST_VAAPI_CREATE_PICTURE_FLAG_FIELD = 1 << 1,
60 };
61
62 static void
63 destroy_slice_cb(gpointer data, gpointer user_data)
64 {
65     GstVaapiMiniObject * const object = data;
66
67     gst_vaapi_mini_object_unref(object);
68 }
69
70 void
71 gst_vaapi_picture_destroy(GstVaapiPicture *picture)
72 {
73     if (picture->slices) {
74         g_ptr_array_foreach(picture->slices, destroy_slice_cb, NULL);
75         g_ptr_array_free(picture->slices, TRUE);
76         picture->slices = NULL;
77     }
78
79     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)&picture->iq_matrix,
80         NULL);
81     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)&picture->huf_table,
82         NULL);
83     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)&picture->bitplane,
84         NULL);
85
86     if (picture->proxy) {
87         gst_vaapi_surface_proxy_unref(picture->proxy);
88         picture->proxy = NULL;
89     }
90     picture->surface_id = VA_INVALID_ID;
91     picture->surface = NULL;
92
93     vaapi_destroy_buffer(GET_VA_DISPLAY(picture), &picture->param_id);
94     picture->param = NULL;
95
96     gst_video_codec_frame_clear(&picture->frame);
97     gst_vaapi_picture_replace(&picture->parent_picture, NULL);
98 }
99
100 gboolean
101 gst_vaapi_picture_create(
102     GstVaapiPicture                          *picture,
103     const GstVaapiCodecObjectConstructorArgs *args
104 )
105 {
106     gboolean success;
107
108     picture->param_id = VA_INVALID_ID;
109
110     if (args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_CLONE) {
111         GstVaapiPicture * const parent_picture = GST_VAAPI_PICTURE(args->data);
112
113         picture->parent_picture = gst_vaapi_picture_ref(parent_picture);
114
115         picture->proxy   = gst_vaapi_surface_proxy_ref(parent_picture->proxy);
116         picture->type    = parent_picture->type;
117         picture->pts     = parent_picture->pts;
118         picture->poc     = parent_picture->poc;
119
120         // Copy all picture flags but "output"
121         GST_VAAPI_PICTURE_FLAG_SET(
122             picture,
123             GST_VAAPI_PICTURE_FLAGS(parent_picture) &
124             (GST_VAAPI_PICTURE_FLAG_SKIPPED     |
125              GST_VAAPI_PICTURE_FLAG_REFERENCE   |
126              GST_VAAPI_PICTURE_FLAG_INTERLACED  |
127              GST_VAAPI_PICTURE_FLAG_FF          |
128              GST_VAAPI_PICTURE_FLAG_TFF)
129         );
130
131         picture->structure = parent_picture->structure;
132         if ((args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_FIELD) &&
133             GST_VAAPI_PICTURE_IS_INTERLACED(picture)) {
134             switch (picture->structure) {
135             case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
136                 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
137                 break;
138             case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
139                 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
140                 break;
141             }
142             GST_VAAPI_PICTURE_FLAG_UNSET(picture, GST_VAAPI_PICTURE_FLAG_FF);
143         }
144
145         if (parent_picture->has_crop_rect) {
146             picture->has_crop_rect = TRUE;
147             picture->crop_rect = parent_picture->crop_rect;
148         }
149     }
150     else {
151         picture->type = GST_VAAPI_PICTURE_TYPE_NONE;
152         picture->pts  = GST_CLOCK_TIME_NONE;
153
154         picture->proxy =
155             gst_vaapi_context_get_surface_proxy(GET_CONTEXT(picture));
156         if (!picture->proxy)
157             return FALSE;
158
159         picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
160         GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_FF);
161     }
162     picture->surface    = GST_VAAPI_SURFACE_PROXY_SURFACE(picture->proxy);
163     picture->surface_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID(picture->proxy);
164
165     success = vaapi_create_buffer(
166         GET_VA_DISPLAY(picture),
167         GET_VA_CONTEXT(picture),
168         VAPictureParameterBufferType,
169         args->param_size,
170         args->param,
171         &picture->param_id,
172         &picture->param
173     );
174     if (!success)
175         return FALSE;
176     picture->param_size = args->param_size;
177
178     picture->slices = g_ptr_array_new();
179     if (!picture->slices)
180         return FALSE;
181
182     picture->frame = gst_video_codec_frame_ref(
183         GST_VAAPI_DECODER_CODEC_FRAME(GET_DECODER(picture)));
184     return TRUE;
185 }
186
187 GstVaapiPicture *
188 gst_vaapi_picture_new(
189     GstVaapiDecoder *decoder,
190     gconstpointer    param,
191     guint            param_size
192 )
193 {
194     GstVaapiCodecObject *object;
195
196     object = gst_vaapi_codec_object_new(
197         &GstVaapiPictureClass,
198         GST_VAAPI_CODEC_BASE(decoder),
199         param, param_size,
200         NULL, 0,
201         0
202     );
203     if (!object)
204         return NULL;
205     return GST_VAAPI_PICTURE_CAST(object);
206 }
207
208 GstVaapiPicture *
209 gst_vaapi_picture_new_field(GstVaapiPicture *picture)
210 {
211     GstVaapiDecoder * const decoder = GET_DECODER(picture);
212     GstVaapiCodecObject *object;
213
214     object = gst_vaapi_codec_object_new(
215         gst_vaapi_codec_object_get_class(&picture->parent_instance),
216         GST_VAAPI_CODEC_BASE(decoder),
217         NULL, picture->param_size,
218         picture, 0,
219         (GST_VAAPI_CREATE_PICTURE_FLAG_CLONE|
220          GST_VAAPI_CREATE_PICTURE_FLAG_FIELD)
221     );
222     if (!object)
223         return NULL;
224     return GST_VAAPI_PICTURE_CAST(object);
225 }
226
227 void
228 gst_vaapi_picture_add_slice(GstVaapiPicture *picture, GstVaapiSlice *slice)
229 {
230     g_return_if_fail(GST_VAAPI_IS_PICTURE(picture));
231     g_return_if_fail(GST_VAAPI_IS_SLICE(slice));
232
233     g_ptr_array_add(picture->slices, slice);
234 }
235
236 static gboolean
237 do_decode(VADisplay dpy, VAContextID ctx, VABufferID *buf_id, void **buf_ptr)
238 {
239     VAStatus status;
240
241     vaapi_unmap_buffer(dpy, *buf_id, buf_ptr);
242
243     status = vaRenderPicture(dpy, ctx, buf_id, 1);
244     if (!vaapi_check_status(status, "vaRenderPicture()"))
245         return FALSE;
246
247     /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */
248     vaapi_destroy_buffer(dpy, buf_id);
249     return TRUE;
250 }
251
252 gboolean
253 gst_vaapi_picture_decode(GstVaapiPicture *picture)
254 {
255     GstVaapiIqMatrix *iq_matrix;
256     GstVaapiBitPlane *bitplane;
257     GstVaapiHuffmanTable *huf_table;
258     VADisplay va_display;
259     VAContextID va_context;
260     VAStatus status;
261     guint i;
262
263     g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
264
265     va_display = GET_VA_DISPLAY(picture);
266     va_context = GET_VA_CONTEXT(picture);
267
268     GST_DEBUG("decode picture 0x%08x", picture->surface_id);
269
270     status = vaBeginPicture(va_display, va_context, picture->surface_id);
271     if (!vaapi_check_status(status, "vaBeginPicture()"))
272         return FALSE;
273
274     if (!do_decode(va_display, va_context, &picture->param_id, &picture->param))
275         return FALSE;
276
277     iq_matrix = picture->iq_matrix;
278     if (iq_matrix && !do_decode(va_display, va_context,
279                                 &iq_matrix->param_id, &iq_matrix->param))
280         return FALSE;
281
282     bitplane = picture->bitplane;
283     if (bitplane && !do_decode(va_display, va_context,
284                                &bitplane->data_id, (void **)&bitplane->data))
285         return FALSE;
286
287     huf_table = picture->huf_table;
288     if (huf_table && !do_decode(va_display, va_context,
289                                 &huf_table->param_id,
290                                 (void **)&huf_table->param))
291         return FALSE;
292
293     for (i = 0; i < picture->slices->len; i++) {
294         GstVaapiSlice * const slice = g_ptr_array_index(picture->slices, i);
295         VABufferID va_buffers[2];
296
297         huf_table = slice->huf_table;
298         if (huf_table && !do_decode(va_display, va_context,
299                 &huf_table->param_id, (void **)&huf_table->param))
300             return FALSE;
301
302         vaapi_unmap_buffer(va_display, slice->param_id, NULL);
303         va_buffers[0] = slice->param_id;
304         va_buffers[1] = slice->data_id;
305
306         status = vaRenderPicture(va_display, va_context, va_buffers, 2);
307         if (!vaapi_check_status(status, "vaRenderPicture()"))
308             return FALSE;
309
310         vaapi_destroy_buffer(va_display, &slice->param_id);
311         vaapi_destroy_buffer(va_display, &slice->data_id);
312     }
313
314     status = vaEndPicture(va_display, va_context);
315     if (!vaapi_check_status(status, "vaEndPicture()"))
316         return FALSE;
317     return TRUE;
318 }
319
320 static gboolean
321 do_output(GstVaapiPicture *picture)
322 {
323     GstVideoCodecFrame * const out_frame = picture->frame;
324     GstVaapiSurfaceProxy *proxy;
325     guint flags = 0;
326
327     if (GST_VAAPI_PICTURE_IS_OUTPUT(picture))
328         return TRUE;
329
330     if (!picture->proxy)
331         return FALSE;
332
333     proxy = gst_vaapi_surface_proxy_ref(picture->proxy);
334
335     if (picture->has_crop_rect)
336         gst_vaapi_surface_proxy_set_crop_rect(proxy, &picture->crop_rect);
337
338     gst_video_codec_frame_set_user_data(out_frame,
339         proxy, (GDestroyNotify)gst_vaapi_mini_object_unref);
340
341     out_frame->pts = picture->pts;
342
343     if (GST_VAAPI_PICTURE_IS_SKIPPED(picture))
344         GST_VIDEO_CODEC_FRAME_FLAG_SET(out_frame,
345             GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
346
347     if (GST_VAAPI_PICTURE_IS_INTERLACED(picture)) {
348         flags |= GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED;
349         if (GST_VAAPI_PICTURE_IS_TFF(picture))
350             flags |= GST_VAAPI_SURFACE_PROXY_FLAG_TFF;
351     }
352     GST_VAAPI_SURFACE_PROXY_FLAG_SET(proxy, flags);
353
354     gst_vaapi_decoder_push_frame(GET_DECODER(picture), out_frame);
355     gst_video_codec_frame_clear(&picture->frame);
356
357     GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_OUTPUT);
358     return TRUE;
359 }
360
361 gboolean
362 gst_vaapi_picture_output(GstVaapiPicture *picture)
363 {
364     g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
365
366     if (G_UNLIKELY(picture->parent_picture)) {
367         /* Emit the first field to GstVideoDecoder so that to release
368            the underlying GstVideoCodecFrame. However, mark this
369            picture as skipped so that to not display it */
370         GstVaapiPicture * const parent_picture = picture->parent_picture;
371         do {
372             if (!GST_VAAPI_PICTURE_IS_INTERLACED(parent_picture))
373                 break;
374             if (!GST_VAAPI_PICTURE_IS_FIRST_FIELD(parent_picture))
375                 break;
376             GST_VAAPI_PICTURE_FLAG_SET(parent_picture,
377                 GST_VAAPI_PICTURE_FLAG_SKIPPED);
378             if (!do_output(parent_picture))
379                 return FALSE;
380         } while (0);
381     }
382     return do_output(picture);
383 }
384
385 void
386 gst_vaapi_picture_set_crop_rect(GstVaapiPicture *picture,
387     const GstVaapiRectangle *crop_rect)
388 {
389     g_return_if_fail(GST_VAAPI_IS_PICTURE(picture));
390
391     picture->has_crop_rect = crop_rect != NULL;
392     if (picture->has_crop_rect)
393         picture->crop_rect = *crop_rect;
394 }
395
396 /* ------------------------------------------------------------------------- */
397 /* --- Slices                                                            --- */
398 /* ------------------------------------------------------------------------- */
399
400 GST_VAAPI_CODEC_DEFINE_TYPE(GstVaapiSlice, gst_vaapi_slice);
401
402 void
403 gst_vaapi_slice_destroy(GstVaapiSlice *slice)
404 {
405     VADisplay const va_display = GET_VA_DISPLAY(slice);
406
407     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)&slice->huf_table,
408         NULL);
409
410     vaapi_destroy_buffer(va_display, &slice->data_id);
411     vaapi_destroy_buffer(va_display, &slice->param_id);
412     slice->param = NULL;
413 }
414
415 gboolean
416 gst_vaapi_slice_create(
417     GstVaapiSlice                            *slice,
418     const GstVaapiCodecObjectConstructorArgs *args
419 )
420 {
421     VASliceParameterBufferBase *slice_param;
422     gboolean success;
423
424     slice->param_id = VA_INVALID_ID;
425     slice->data_id = VA_INVALID_ID;
426
427     success = vaapi_create_buffer(
428         GET_VA_DISPLAY(slice),
429         GET_VA_CONTEXT(slice),
430         VASliceDataBufferType,
431         args->data_size,
432         args->data,
433         &slice->data_id,
434         NULL
435     );
436     if (!success)
437         return FALSE;
438
439     success = vaapi_create_buffer(
440         GET_VA_DISPLAY(slice),
441         GET_VA_CONTEXT(slice),
442         VASliceParameterBufferType,
443         args->param_size,
444         args->param,
445         &slice->param_id,
446         &slice->param
447     );
448     if (!success)
449         return FALSE;
450
451     slice_param                    = slice->param;
452     slice_param->slice_data_size   = args->data_size;
453     slice_param->slice_data_offset = 0;
454     slice_param->slice_data_flag   = VA_SLICE_DATA_FLAG_ALL;
455     return TRUE;
456 }
457
458 GstVaapiSlice *
459 gst_vaapi_slice_new(
460     GstVaapiDecoder *decoder,
461     gconstpointer    param,
462     guint            param_size,
463     const guchar    *data,
464     guint            data_size
465 )
466 {
467     GstVaapiCodecObject *object;
468
469     object = gst_vaapi_codec_object_new(
470         &GstVaapiSliceClass,
471         GST_VAAPI_CODEC_BASE(decoder),
472         param, param_size,
473         data, data_size,
474         0
475     );
476     return GST_VAAPI_SLICE_CAST(object);
477 }