1 /* GStreamer
2 * Copyright (C) 2020 Intel Corporation
3 * Author: He Junyan <junyan.he@intel.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include "gstmpeg2picture.h"
26
27 GST_DEBUG_CATEGORY_EXTERN (gst_mpeg2_decoder_debug);
28 #define GST_CAT_DEFAULT gst_mpeg2_decoder_debug
29
30 GST_DEFINE_MINI_OBJECT_TYPE (GstMpeg2Picture, gst_mpeg2_picture);
31
32 static void
_gst_mpeg2_picture_free(GstMpeg2Picture * picture)33 _gst_mpeg2_picture_free (GstMpeg2Picture * picture)
34 {
35 GST_TRACE ("Free picture %p", picture);
36
37 if (picture->first_field)
38 gst_mpeg2_picture_unref (picture->first_field);
39
40 if (picture->notify)
41 picture->notify (picture->user_data);
42
43 g_free (picture);
44 }
45
46 /**
47 * gst_mpeg2_picture_new:
48 *
49 * Create new #GstMpeg2Picture
50 *
51 * Returns: a new #GstMpeg2Picture
52 *
53 * Since: 1.20
54 */
55 GstMpeg2Picture *
gst_mpeg2_picture_new(void)56 gst_mpeg2_picture_new (void)
57 {
58 GstMpeg2Picture *pic;
59
60 pic = g_new0 (GstMpeg2Picture, 1);
61
62 pic->pic_order_cnt = G_MAXINT32;
63 pic->structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME;
64
65 gst_mini_object_init (GST_MINI_OBJECT_CAST (pic), 0,
66 GST_TYPE_MPEG2_PICTURE, NULL, NULL,
67 (GstMiniObjectFreeFunction) _gst_mpeg2_picture_free);
68
69 GST_TRACE ("New picture %p", pic);
70
71 return pic;
72 }
73
74 /**
75 * gst_mpeg2_picture_set_user_data:
76 * @picture: a #GstMpeg2Picture
77 * @user_data: private data
78 * @notify: (closure user_data): a #GDestroyNotify
79 *
80 * Sets @user_data on the picture and the #GDestroyNotify that will be called when
81 * the picture is freed.
82 *
83 * If a @user_data was previously set, then the previous set @notify will be called
84 * before the @user_data is replaced.
85 *
86 * Since: 1.20
87 */
88 void
gst_mpeg2_picture_set_user_data(GstMpeg2Picture * picture,gpointer user_data,GDestroyNotify notify)89 gst_mpeg2_picture_set_user_data (GstMpeg2Picture * picture, gpointer user_data,
90 GDestroyNotify notify)
91 {
92 g_return_if_fail (GST_IS_MPEG2_PICTURE (picture));
93
94 if (picture->notify)
95 picture->notify (picture->user_data);
96
97 picture->user_data = user_data;
98 picture->notify = notify;
99 }
100
101 /**
102 * gst_mpeg2_picture_get_user_data:
103 * @picture: a #GstMpeg2Picture
104 *
105 * Gets private data set on the picture via
106 * gst_mpeg2_picture_set_user_data() previously.
107 *
108 * Returns: (transfer none): The previously set user_data
109 *
110 * Since: 1.20
111 */
112 gpointer
gst_mpeg2_picture_get_user_data(GstMpeg2Picture * picture)113 gst_mpeg2_picture_get_user_data (GstMpeg2Picture * picture)
114 {
115 return picture->user_data;
116 }
117
118 struct _GstMpeg2Dpb
119 {
120 GstMpeg2Picture *ref_pic_list[2];
121 guint num_ref_pictures;
122 /* last added picture */
123 GstMpeg2Picture *new_pic;
124 };
125
126 /**
127 * gst_mpeg2_dpb_new: (skip)
128 *
129 * Create new #GstMpeg2Dpb
130 *
131 * Returns: a new #GstMpeg2Dpb
132 *
133 * Since: 1.20
134 */
135 GstMpeg2Dpb *
gst_mpeg2_dpb_new(void)136 gst_mpeg2_dpb_new (void)
137 {
138 return g_new0 (GstMpeg2Dpb, 1);
139 }
140
141 /**
142 * gst_mpeg2_dpb_free:
143 * @dpb: a #GstMpeg2Dpb to free
144 *
145 * Free the @dpb
146 *
147 * Since: 1.20
148 */
149 void
gst_mpeg2_dpb_free(GstMpeg2Dpb * dpb)150 gst_mpeg2_dpb_free (GstMpeg2Dpb * dpb)
151 {
152 guint i;
153
154 g_return_if_fail (dpb != NULL);
155
156 gst_mpeg2_picture_clear (&dpb->new_pic);
157
158 g_assert (dpb->num_ref_pictures <= 2);
159 for (i = 0; i < dpb->num_ref_pictures; i++)
160 gst_mpeg2_picture_clear (&dpb->ref_pic_list[i]);
161
162 g_free (dpb);
163 }
164
165 /**
166 * gst_mpeg2_dpb_clear:
167 * @dpb: a #GstMpeg2Dpb
168 *
169 * Clear all stored #GstMpeg2Picture
170 *
171 * Since: 1.20
172 */
173 void
gst_mpeg2_dpb_clear(GstMpeg2Dpb * dpb)174 gst_mpeg2_dpb_clear (GstMpeg2Dpb * dpb)
175 {
176 guint i;
177
178 g_return_if_fail (dpb != NULL);
179
180 gst_mpeg2_picture_clear (&dpb->new_pic);
181
182 g_assert (dpb->num_ref_pictures <= 2);
183 for (i = 0; i < dpb->num_ref_pictures; i++)
184 gst_mpeg2_picture_clear (&dpb->ref_pic_list[i]);
185
186 dpb->num_ref_pictures = 0;
187 }
188
189 static void
_dpb_add_to_reference(GstMpeg2Dpb * dpb,GstMpeg2Picture * pic)190 _dpb_add_to_reference (GstMpeg2Dpb * dpb, GstMpeg2Picture * pic)
191 {
192 gint index = -1;
193
194 if (G_LIKELY (dpb->num_ref_pictures == 2)) {
195 index = (dpb->ref_pic_list[0]->pic_order_cnt >
196 dpb->ref_pic_list[1]->pic_order_cnt);
197
198 if (dpb->ref_pic_list[index]->pic_order_cnt > pic->pic_order_cnt)
199 return;
200 }
201
202 if (index < 0) {
203 index = dpb->num_ref_pictures;
204 dpb->num_ref_pictures++;
205 }
206
207 gst_mpeg2_picture_replace (&dpb->ref_pic_list[index], pic);
208 }
209
210 /**
211 * gst_mpeg2_dpb_add:
212 * @dpb: a #GstMpeg2Dpb
213 * @picture: (transfer full): a #GstMpeg2Picture
214 *
215 * Store the @picture
216 *
217 * Since: 1.20
218 */
219 void
gst_mpeg2_dpb_add(GstMpeg2Dpb * dpb,GstMpeg2Picture * picture)220 gst_mpeg2_dpb_add (GstMpeg2Dpb * dpb, GstMpeg2Picture * picture)
221 {
222 g_return_if_fail (dpb != NULL);
223 g_return_if_fail (GST_IS_MPEG2_PICTURE (picture));
224
225 g_assert (dpb->num_ref_pictures <= 2);
226
227 if (!GST_MPEG2_PICTURE_IS_REF (picture) || dpb->num_ref_pictures == 2) {
228 gst_mpeg2_picture_replace (&dpb->new_pic, picture);
229 } else {
230 _dpb_add_to_reference (dpb, picture);
231 }
232 }
233
234 /**
235 * gst_mpeg2_dpb_need_bump:
236 * @dpb: a #GstMpeg2Dpb
237 *
238 * Checks if @dbp has a new picture.
239 *
240 * Returns: #TRUE if @dpb needs to be bumped; otherwise, #FALSE
241 *
242 * Since: 1.20
243 */
244 gboolean
gst_mpeg2_dpb_need_bump(GstMpeg2Dpb * dpb)245 gst_mpeg2_dpb_need_bump (GstMpeg2Dpb * dpb)
246 {
247 g_return_val_if_fail (dpb != NULL, FALSE);
248 g_assert (dpb->num_ref_pictures <= 2);
249
250 if (dpb->new_pic)
251 return TRUE;
252
253 return FALSE;
254 }
255
256 /**
257 * gst_mpeg2_dpb_bump:
258 * @dpb: a #GstMpeg2Dpb
259 *
260 * Returns: (nullable) (transfer full): a #GstMpeg2Picture which is needed to be
261 * outputted
262 *
263 * Since: 1.20
264 */
265 GstMpeg2Picture *
gst_mpeg2_dpb_bump(GstMpeg2Dpb * dpb)266 gst_mpeg2_dpb_bump (GstMpeg2Dpb * dpb)
267 {
268 GstMpeg2Picture *pic = NULL;
269 guint i;
270
271 g_return_val_if_fail (dpb != NULL, FALSE);
272 g_assert (dpb->num_ref_pictures <= 2);
273
274 /* First, find the lowest poc. */
275 for (i = 0; i < 2; i++) {
276 if (!dpb->ref_pic_list[i])
277 continue;
278
279 if (dpb->ref_pic_list[i]->needed_for_output) {
280 if (!pic || pic->pic_order_cnt > dpb->ref_pic_list[i]->pic_order_cnt)
281 gst_mpeg2_picture_replace (&pic, dpb->ref_pic_list[i]);
282 }
283 }
284
285 if (dpb->new_pic && dpb->new_pic->needed_for_output &&
286 (!pic || pic->pic_order_cnt > dpb->new_pic->pic_order_cnt))
287 gst_mpeg2_picture_replace (&pic, dpb->new_pic);
288
289 /* Then, replace the reference if needed. */
290 if (dpb->new_pic && GST_MPEG2_PICTURE_IS_REF (dpb->new_pic)) {
291 _dpb_add_to_reference (dpb, dpb->new_pic);
292 gst_mpeg2_picture_clear (&dpb->new_pic);
293 }
294
295 if (pic) {
296 pic->needed_for_output = FALSE;
297 if (pic == dpb->new_pic)
298 gst_mpeg2_picture_clear (&dpb->new_pic);
299 }
300
301 return pic;
302 }
303
304 /**
305 * gst_mpeg2_dpb_get_neighbours:
306 * @dpb: a #GstMpeg2Dpb
307 * @picture: current #GstMpeg2Picture
308 * @prev_picture_ptr: (transfer none) (out) (nullable): previuous
309 * #GstMpeg2Picture in @dpb
310 * @next_picture_ptr: (transfer none) (out) (nullable): next
311 * #GstMpeg2Picture in @dpb
312 *
313 * Gets the neighbours #GstMpeg2Picture of @picture in @dpb.
314 *
315 * Since: 1.20
316 */
317 void
gst_mpeg2_dpb_get_neighbours(GstMpeg2Dpb * dpb,GstMpeg2Picture * picture,GstMpeg2Picture ** prev_picture_ptr,GstMpeg2Picture ** next_picture_ptr)318 gst_mpeg2_dpb_get_neighbours (GstMpeg2Dpb * dpb,
319 GstMpeg2Picture * picture, GstMpeg2Picture ** prev_picture_ptr,
320 GstMpeg2Picture ** next_picture_ptr)
321 {
322 GstMpeg2Picture *ref_picture, *ref_pictures[2];
323 GstMpeg2Picture **picture_ptr;
324 guint i, index;
325
326 g_return_if_fail (dpb != NULL);
327 g_return_if_fail (picture != NULL);
328 g_assert (dpb->num_ref_pictures <= 2);
329
330 ref_pictures[0] = NULL;
331 ref_pictures[1] = NULL;
332 for (i = 0; i < 2; i++) {
333 ref_picture = dpb->ref_pic_list[i];
334 if (!ref_picture)
335 continue;
336
337 index = ref_picture->pic_order_cnt > picture->pic_order_cnt;
338 picture_ptr = &ref_pictures[index];
339 if (!*picture_ptr ||
340 ((*picture_ptr)->pic_order_cnt > ref_picture->pic_order_cnt) == index)
341 *picture_ptr = ref_picture;
342 }
343
344 if (prev_picture_ptr)
345 *prev_picture_ptr = ref_pictures[0];
346 if (next_picture_ptr)
347 *next_picture_ptr = ref_pictures[1];
348 }
349