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