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