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