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