• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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