Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder_dpb.c
1 /*
2  *  gstvaapidecoder_dpb.c - Decoded Picture Buffer
3  *
4  *  Copyright (C) 2012 Intel Corporation
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21
22 #include "sysdeps.h"
23 #include "gstvaapidecoder_dpb.h"
24
25 #define DEBUG 1
26 #include "gstvaapidebug.h"
27
28 /* ------------------------------------------------------------------------- */
29 /* --- Common Decoded Picture Buffer utilities                           --- */
30 /* ------------------------------------------------------------------------- */
31
32 static GstVaapiDpb *
33 dpb_new(GType type, guint max_pictures)
34 {
35     GstMiniObject *obj;
36     GstVaapiDpb *dpb;
37
38     g_return_val_if_fail(max_pictures > 0, NULL);
39
40     obj = gst_mini_object_new(type);
41     if (!obj)
42         return NULL;
43
44     dpb = GST_VAAPI_DPB_CAST(obj);
45     dpb->pictures = g_new0(GstVaapiPicture *, max_pictures);
46     if (!dpb->pictures)
47         goto error;
48     dpb->max_pictures = max_pictures;
49     return dpb;
50
51 error:
52     gst_mini_object_unref(obj);
53     return NULL;
54 }
55
56 static gint
57 dpb_get_oldest(GstVaapiDpb *dpb, gboolean output)
58 {
59     gint i, lowest_pts_index;
60
61     for (i = 0; i < dpb->num_pictures; i++) {
62         if ((GST_VAAPI_PICTURE_IS_OUTPUT(dpb->pictures[i]) ^ output) == 0)
63             break;
64     }
65     if (i == dpb->num_pictures)
66         return -1;
67
68     lowest_pts_index = i++;
69     for (; i < dpb->num_pictures; i++) {
70         GstVaapiPicture * const picture = dpb->pictures[i];
71         if ((GST_VAAPI_PICTURE_IS_OUTPUT(picture) ^ output) != 0)
72             continue;
73         if (picture->poc < dpb->pictures[lowest_pts_index]->poc)
74             lowest_pts_index = i;
75     }
76     return lowest_pts_index;
77 }
78
79 static void
80 dpb_remove_index(GstVaapiDpb *dpb, guint index)
81 {
82     GstVaapiPicture ** const pictures = dpb->pictures;
83     guint num_pictures = --dpb->num_pictures;
84
85     if (index != num_pictures)
86         gst_vaapi_picture_replace(&pictures[index], pictures[num_pictures]);
87     gst_vaapi_picture_replace(&pictures[num_pictures], NULL);
88 }
89
90 static inline gboolean
91 dpb_output(GstVaapiDpb *dpb, GstVaapiPicture *picture)
92 {
93     return gst_vaapi_picture_output(picture);
94 }
95
96 static gboolean
97 dpb_bump(GstVaapiDpb *dpb)
98 {
99     gint index;
100     gboolean success;
101
102     index = dpb_get_oldest(dpb, FALSE);
103     if (index < 0)
104         return FALSE;
105
106     success = dpb_output(dpb, dpb->pictures[index]);
107     if (!GST_VAAPI_PICTURE_IS_REFERENCE(dpb->pictures[index]))
108         dpb_remove_index(dpb, index);
109     return success;
110 }
111
112 static void
113 dpb_clear(GstVaapiDpb *dpb)
114 {
115     guint i;
116
117     for (i = 0; i < dpb->num_pictures; i++)
118         gst_vaapi_picture_replace(&dpb->pictures[i], NULL);
119     dpb->num_pictures = 0;
120 }
121
122 /* ------------------------------------------------------------------------- */
123 /* --- Base Decoded Picture Buffer                                       --- */
124 /* ------------------------------------------------------------------------- */
125
126 G_DEFINE_TYPE(GstVaapiDpb, gst_vaapi_dpb, GST_TYPE_MINI_OBJECT)
127
128 static void
129 gst_vaapi_dpb_base_flush(GstVaapiDpb *dpb)
130 {
131     while (dpb_bump(dpb))
132         ;
133     dpb_clear(dpb);
134 }
135
136 static gboolean
137 gst_vaapi_dpb_base_add(GstVaapiDpb *dpb, GstVaapiPicture *picture)
138 {
139     guint i;
140
141     // Remove all unused pictures
142     i = 0;
143     while (i < dpb->num_pictures) {
144         GstVaapiPicture * const picture = dpb->pictures[i];
145         if (GST_VAAPI_PICTURE_IS_OUTPUT(picture) &&
146             !GST_VAAPI_PICTURE_IS_REFERENCE(picture))
147             dpb_remove_index(dpb, i);
148         else
149             i++;
150     }
151
152     // Store reference decoded picture into the DPB
153     if (GST_VAAPI_PICTURE_IS_REFERENCE(picture)) {
154         while (dpb->num_pictures == dpb->max_pictures) {
155             if (!dpb_bump(dpb))
156                 return FALSE;
157         }
158     }
159
160     // Store non-reference decoded picture into the DPB
161     else {
162         if (GST_VAAPI_PICTURE_IS_SKIPPED(picture))
163             return TRUE;
164         while (dpb->num_pictures == dpb->max_pictures) {
165             for (i = 0; i < dpb->num_pictures; i++) {
166                 if (!GST_VAAPI_PICTURE_IS_OUTPUT(picture) &&
167                     dpb->pictures[i]->poc < picture->poc)
168                     break;
169             }
170             if (i == dpb->num_pictures)
171                 return dpb_output(dpb, picture);
172             if (!dpb_bump(dpb))
173                 return FALSE;
174         }
175     }
176     gst_vaapi_picture_replace(&dpb->pictures[dpb->num_pictures++], picture);
177     return TRUE;
178 }
179
180 static void
181 gst_vaapi_dpb_finalize(GstMiniObject *object)
182 {
183     GstVaapiDpb * const dpb = GST_VAAPI_DPB_CAST(object);
184     GstMiniObjectClass *parent_class;
185
186     if (dpb->pictures) {
187         dpb_clear(dpb);
188         g_free(dpb->pictures);
189     }
190
191     parent_class = GST_MINI_OBJECT_CLASS(gst_vaapi_dpb_parent_class);
192     if (parent_class->finalize)
193         parent_class->finalize(object);
194 }
195
196 static void
197 gst_vaapi_dpb_init(GstVaapiDpb *dpb)
198 {
199     dpb->pictures     = NULL;
200     dpb->num_pictures = 0;
201     dpb->max_pictures = 0;
202 }
203
204 static void
205 gst_vaapi_dpb_class_init(GstVaapiDpbClass *klass)
206 {
207     GstMiniObjectClass * const object_class = GST_MINI_OBJECT_CLASS(klass);
208
209     object_class->finalize = gst_vaapi_dpb_finalize;
210     klass->flush           = gst_vaapi_dpb_base_flush;
211     klass->add             = gst_vaapi_dpb_base_add;
212 }
213
214 void
215 gst_vaapi_dpb_flush(GstVaapiDpb *dpb)
216 {
217     GstVaapiDpbClass *klass;
218
219     g_return_if_fail(GST_VAAPI_IS_DPB(dpb));
220
221     klass = GST_VAAPI_DPB_GET_CLASS(dpb);
222     if (G_UNLIKELY(!klass || !klass->add))
223         return;
224     klass->flush(dpb);
225 }
226
227 gboolean
228 gst_vaapi_dpb_add(GstVaapiDpb *dpb, GstVaapiPicture *picture)
229 {
230     GstVaapiDpbClass *klass;
231
232     g_return_val_if_fail(GST_VAAPI_IS_DPB(dpb), FALSE);
233     g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
234
235     klass = GST_VAAPI_DPB_GET_CLASS(dpb);
236     if (G_UNLIKELY(!klass || !klass->add))
237         return FALSE;
238     return klass->add(dpb, picture);
239 }
240
241 guint
242 gst_vaapi_dpb_size(GstVaapiDpb *dpb)
243 {
244     g_return_val_if_fail(GST_VAAPI_IS_DPB(dpb), 0);
245
246     return dpb->num_pictures;
247 }
248
249 /* ------------------------------------------------------------------------- */
250 /* --- MPEG-2 Decoded Picture Buffer                                     --- */
251 /* ------------------------------------------------------------------------- */
252
253 /* At most two reference pictures for MPEG-2 */
254 #define MAX_MPEG2_REFERENCES 2
255
256 G_DEFINE_TYPE(GstVaapiDpbMpeg2, gst_vaapi_dpb_mpeg2, GST_VAAPI_TYPE_DPB)
257
258 static gboolean
259 gst_vaapi_dpb_mpeg2_add(GstVaapiDpb *dpb, GstVaapiPicture *picture)
260 {
261     GstVaapiPicture *ref_picture;
262     gint index = -1;
263
264     g_return_val_if_fail(GST_VAAPI_IS_DPB_MPEG2(dpb), FALSE);
265
266     /*
267      * Purpose: only store reference decoded pictures into the DPB
268      *
269      * This means:
270      * - non-reference decoded pictures are output immediately
271      * - ... thus causing older reference pictures to be output, if not already
272      * - the oldest reference picture is replaced with the new reference picture
273      */
274     if (G_LIKELY(dpb->num_pictures == MAX_MPEG2_REFERENCES)) {
275         index = (dpb->pictures[0]->poc > dpb->pictures[1]->poc);
276         ref_picture = dpb->pictures[index];
277         if (!GST_VAAPI_PICTURE_IS_OUTPUT(ref_picture)) {
278             if (!dpb_output(dpb, ref_picture))
279                 return FALSE;
280         }
281     }
282
283     if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture))
284         return dpb_output(dpb, picture);
285
286     if (index < 0)
287         index = dpb->num_pictures++;
288     gst_vaapi_picture_replace(&dpb->pictures[index], picture);
289     return TRUE;
290 }
291
292 static void
293 gst_vaapi_dpb_mpeg2_init(GstVaapiDpbMpeg2 *dpb)
294 {
295 }
296
297 static void
298 gst_vaapi_dpb_mpeg2_class_init(GstVaapiDpbMpeg2Class *klass)
299 {
300     GstVaapiDpbClass * const dpb_class = GST_VAAPI_DPB_CLASS(klass);
301
302     dpb_class->add = gst_vaapi_dpb_mpeg2_add;
303 }
304
305 GstVaapiDpb *
306 gst_vaapi_dpb_mpeg2_new(void)
307 {
308     return dpb_new(GST_VAAPI_TYPE_DPB_MPEG2, MAX_MPEG2_REFERENCES);
309 }
310
311 void
312 gst_vaapi_dpb_mpeg2_get_references(
313     GstVaapiDpb        *dpb,
314     GstVaapiPicture    *picture,
315     GstVaapiPicture   **prev_picture_ptr,
316     GstVaapiPicture   **next_picture_ptr
317 )
318 {
319     GstVaapiPicture *ref_picture, *ref_pictures[MAX_MPEG2_REFERENCES];
320     GstVaapiPicture **picture_ptr;
321     guint i, index;
322
323     g_return_if_fail(GST_VAAPI_IS_DPB_MPEG2(dpb));
324     g_return_if_fail(GST_VAAPI_IS_PICTURE(picture));
325
326     ref_pictures[0] = NULL;
327     ref_pictures[1] = NULL;
328     for (i = 0; i < dpb->num_pictures; i++) {
329         ref_picture = dpb->pictures[i];
330         index       = ref_picture->poc > picture->poc;
331         picture_ptr = &ref_pictures[index];
332         if (!*picture_ptr || ((*picture_ptr)->poc > ref_picture->poc) == index)
333             *picture_ptr = ref_picture;
334     }
335
336     if (prev_picture_ptr)
337         *prev_picture_ptr = ref_pictures[0];
338     if (next_picture_ptr)
339         *next_picture_ptr = ref_pictures[1];
340 }