• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include "gsth265picture.h"
25 
26 GST_DEBUG_CATEGORY_EXTERN (gst_h265_decoder_debug);
27 #define GST_CAT_DEFAULT gst_h265_decoder_debug
28 
29 GST_DEFINE_MINI_OBJECT_TYPE (GstH265Picture, gst_h265_picture);
30 
31 static void
_gst_h265_picture_free(GstH265Picture * picture)32 _gst_h265_picture_free (GstH265Picture * picture)
33 {
34   if (picture->notify)
35     picture->notify (picture->user_data);
36 
37   g_free (picture);
38 }
39 
40 /**
41  * gst_h265_picture_new:
42  *
43  * Create new #GstH265Picture
44  *
45  * Returns: a new #GstH265Picture
46  */
47 GstH265Picture *
gst_h265_picture_new(void)48 gst_h265_picture_new (void)
49 {
50   GstH265Picture *pic;
51 
52   pic = g_new0 (GstH265Picture, 1);
53 
54   pic->pts = GST_CLOCK_TIME_NONE;
55   pic->pic_struct = GST_H265_SEI_PIC_STRUCT_FRAME;
56   /* 0: interlaced, 1: progressive, 2: unspecified, 3: reserved, can be
57    * interpreted as 2 */
58   pic->source_scan_type = 2;
59   pic->duplicate_flag = 0;
60 
61   gst_mini_object_init (GST_MINI_OBJECT_CAST (pic), 0,
62       GST_TYPE_H265_PICTURE, NULL, NULL,
63       (GstMiniObjectFreeFunction) _gst_h265_picture_free);
64 
65   return pic;
66 }
67 
68 /**
69  * gst_h265_picture_set_user_data:
70  * @picture: a #GstH265Picture
71  * @user_data: private data
72  * @notify: (closure user_data): a #GDestroyNotify
73  *
74  * Sets @user_data on the picture and the #GDestroyNotify that will be called when
75  * the picture is freed.
76  *
77  * If a @user_data was previously set, then the previous set @notify will be called
78  * before the @user_data is replaced.
79  */
80 void
gst_h265_picture_set_user_data(GstH265Picture * picture,gpointer user_data,GDestroyNotify notify)81 gst_h265_picture_set_user_data (GstH265Picture * picture, gpointer user_data,
82     GDestroyNotify notify)
83 {
84   g_return_if_fail (GST_IS_H265_PICTURE (picture));
85 
86   if (picture->notify)
87     picture->notify (picture->user_data);
88 
89   picture->user_data = user_data;
90   picture->notify = notify;
91 }
92 
93 /**
94  * gst_h265_picture_get_user_data:
95  * @picture: a #GstH265Picture
96  *
97  * Gets private data set on the picture via
98  * gst_h265_picture_set_user_data() previously.
99  *
100  * Returns: (transfer none): The previously set user_data
101  */
102 gpointer
gst_h265_picture_get_user_data(GstH265Picture * picture)103 gst_h265_picture_get_user_data (GstH265Picture * picture)
104 {
105   return picture->user_data;
106 }
107 
108 struct _GstH265Dpb
109 {
110   GArray *pic_list;
111   gint max_num_pics;
112   gint num_output_needed;
113 };
114 
115 /**
116  * gst_h265_dpb_new: (skip)
117  *
118  * Create new #GstH265Dpb
119  *
120  * Returns: a new #GstH265Dpb
121  */
122 GstH265Dpb *
gst_h265_dpb_new(void)123 gst_h265_dpb_new (void)
124 {
125   GstH265Dpb *dpb;
126 
127   dpb = g_new0 (GstH265Dpb, 1);
128 
129   dpb->pic_list =
130       g_array_sized_new (FALSE, TRUE, sizeof (GstH265Picture *),
131       GST_H265_DPB_MAX_SIZE);
132   g_array_set_clear_func (dpb->pic_list,
133       (GDestroyNotify) gst_h265_picture_clear);
134 
135   return dpb;
136 }
137 
138 /**
139  * gst_h265_dpb_set_max_num_pics:
140  * @dpb: a #GstH265Dpb
141  * @max_num_pics: the maximum number of picture
142  *
143  * Set the number of maximum allowed pictures to store
144  */
145 void
gst_h265_dpb_set_max_num_pics(GstH265Dpb * dpb,gint max_num_pics)146 gst_h265_dpb_set_max_num_pics (GstH265Dpb * dpb, gint max_num_pics)
147 {
148   g_return_if_fail (dpb != NULL);
149 
150   dpb->max_num_pics = max_num_pics;
151 }
152 
153 /**
154  * gst_h265_dpb_get_max_num_pics:
155  * @dpb: a #GstH265Dpb
156  *
157  * Returns: the number of maximum pictures
158  */
159 gint
gst_h265_dpb_get_max_num_pics(GstH265Dpb * dpb)160 gst_h265_dpb_get_max_num_pics (GstH265Dpb * dpb)
161 {
162   g_return_val_if_fail (dpb != NULL, 0);
163 
164   return dpb->max_num_pics;
165 }
166 
167 /**
168  * gst_h265_dpb_free:
169  * @dpb: a #GstH265Dpb to free
170  *
171  * Free the @dpb
172  */
173 void
gst_h265_dpb_free(GstH265Dpb * dpb)174 gst_h265_dpb_free (GstH265Dpb * dpb)
175 {
176   g_return_if_fail (dpb != NULL);
177 
178   gst_h265_dpb_clear (dpb);
179   g_array_unref (dpb->pic_list);
180   g_free (dpb);
181 }
182 
183 /**
184  * gst_h265_dpb_clear:
185  * @dpb: a #GstH265Dpb
186  *
187  * Clear all stored #GstH265Picture
188  */
189 void
gst_h265_dpb_clear(GstH265Dpb * dpb)190 gst_h265_dpb_clear (GstH265Dpb * dpb)
191 {
192   g_return_if_fail (dpb != NULL);
193 
194   g_array_set_size (dpb->pic_list, 0);
195   dpb->num_output_needed = 0;
196 }
197 
198 /**
199  * gst_h265_dpb_add:
200  * @dpb: a #GstH265Dpb
201  * @picture: (transfer full): a #GstH265Picture
202  *
203  * Store the @picture and perform increase pic_latency_cnt as defined in
204  * "C.5.2.3 Additional bumping" process
205  */
206 void
gst_h265_dpb_add(GstH265Dpb * dpb,GstH265Picture * picture)207 gst_h265_dpb_add (GstH265Dpb * dpb, GstH265Picture * picture)
208 {
209   g_return_if_fail (dpb != NULL);
210   g_return_if_fail (GST_IS_H265_PICTURE (picture));
211 
212   if (picture->output_flag) {
213     gint i;
214 
215     for (i = 0; i < dpb->pic_list->len; i++) {
216       GstH265Picture *other =
217           g_array_index (dpb->pic_list, GstH265Picture *, i);
218 
219       if (other->needed_for_output)
220         other->pic_latency_cnt++;
221     }
222 
223     dpb->num_output_needed++;
224     picture->needed_for_output = TRUE;
225   } else {
226     picture->needed_for_output = FALSE;
227   }
228 
229   /* C.3.4 */
230   picture->ref = TRUE;
231   picture->long_term = FALSE;
232 
233   g_array_append_val (dpb->pic_list, picture);
234 }
235 
236 /**
237  * gst_h265_dpb_delete_unused:
238  * @dpb: a #GstH265Dpb
239  *
240  * Delete not needed for output and not referenced all pictures from dpb
241  */
242 void
gst_h265_dpb_delete_unused(GstH265Dpb * dpb)243 gst_h265_dpb_delete_unused (GstH265Dpb * dpb)
244 {
245   gint i;
246 
247   g_return_if_fail (dpb != NULL);
248 
249   for (i = 0; i < dpb->pic_list->len; i++) {
250     GstH265Picture *picture =
251         g_array_index (dpb->pic_list, GstH265Picture *, i);
252 
253     if (!picture->needed_for_output && !picture->ref) {
254       GST_TRACE ("remove picture %p (poc %d) from dpb",
255           picture, picture->pic_order_cnt);
256       g_array_remove_index (dpb->pic_list, i);
257       i--;
258     }
259   }
260 }
261 
262 /**
263  * gst_h265_dpb_num_ref_pictures:
264  * @dpb: a #GstH265Dpb
265  *
266  * Returns: The number of referenced pictures
267  */
268 gint
gst_h265_dpb_num_ref_pictures(GstH265Dpb * dpb)269 gst_h265_dpb_num_ref_pictures (GstH265Dpb * dpb)
270 {
271   gint i;
272   gint ret = 0;
273 
274   g_return_val_if_fail (dpb != NULL, -1);
275 
276   for (i = 0; i < dpb->pic_list->len; i++) {
277     GstH265Picture *picture =
278         g_array_index (dpb->pic_list, GstH265Picture *, i);
279 
280     if (picture->ref)
281       ret++;
282   }
283 
284   return ret;
285 }
286 
287 /**
288  * gst_h265_dpb_mark_all_non_ref:
289  * @dpb: a #GstH265Dpb
290  *
291  * Mark all pictures are not referenced
292  */
293 void
gst_h265_dpb_mark_all_non_ref(GstH265Dpb * dpb)294 gst_h265_dpb_mark_all_non_ref (GstH265Dpb * dpb)
295 {
296   gint i;
297 
298   g_return_if_fail (dpb != NULL);
299 
300   for (i = 0; i < dpb->pic_list->len; i++) {
301     GstH265Picture *picture =
302         g_array_index (dpb->pic_list, GstH265Picture *, i);
303 
304     picture->ref = FALSE;
305   }
306 }
307 
308 /**
309  * gst_h265_dpb_get_ref_by_poc:
310  * @dpb: a #GstH265Dpb
311  * @poc: a picture order count
312  *
313  * Find a short or long term reference picture which has matching poc
314  *
315  * Returns: (nullable) (transfer full): a #GstH265Picture
316  */
317 GstH265Picture *
gst_h265_dpb_get_ref_by_poc(GstH265Dpb * dpb,gint poc)318 gst_h265_dpb_get_ref_by_poc (GstH265Dpb * dpb, gint poc)
319 {
320   gint i;
321 
322   g_return_val_if_fail (dpb != NULL, NULL);
323 
324   for (i = 0; i < dpb->pic_list->len; i++) {
325     GstH265Picture *picture =
326         g_array_index (dpb->pic_list, GstH265Picture *, i);
327 
328     if (picture->ref && picture->pic_order_cnt == poc)
329       return gst_h265_picture_ref (picture);
330   }
331 
332   GST_DEBUG ("No short term reference picture for %d", poc);
333 
334   return NULL;
335 }
336 
337 /**
338  * gst_h265_dpb_get_ref_by_poc_lsb:
339  * @dpb: a #GstH265Dpb
340  * @poc_lsb: a picture order count lsb
341  *
342  * Find a short or long term reference picture which has matching poc_lsb
343  *
344  * Returns: (nullable) (transfer full): a #GstH265Picture
345  */
346 GstH265Picture *
gst_h265_dpb_get_ref_by_poc_lsb(GstH265Dpb * dpb,gint poc_lsb)347 gst_h265_dpb_get_ref_by_poc_lsb (GstH265Dpb * dpb, gint poc_lsb)
348 {
349   gint i;
350 
351   g_return_val_if_fail (dpb != NULL, NULL);
352 
353   for (i = 0; i < dpb->pic_list->len; i++) {
354     GstH265Picture *picture =
355         g_array_index (dpb->pic_list, GstH265Picture *, i);
356 
357     if (picture->ref && picture->pic_order_cnt_lsb == poc_lsb)
358       return gst_h265_picture_ref (picture);
359   }
360 
361   GST_DEBUG ("No short term reference picture for %d", poc_lsb);
362 
363   return NULL;
364 }
365 
366 /**
367  * gst_h265_dpb_get_short_ref_by_poc:
368  * @dpb: a #GstH265Dpb
369  * @poc: a picture order count
370  *
371  * Find a short term reference picture which has matching poc
372  *
373  * Returns: (nullable) (transfer full): a #GstH265Picture
374  */
375 GstH265Picture *
gst_h265_dpb_get_short_ref_by_poc(GstH265Dpb * dpb,gint poc)376 gst_h265_dpb_get_short_ref_by_poc (GstH265Dpb * dpb, gint poc)
377 {
378   gint i;
379 
380   g_return_val_if_fail (dpb != NULL, NULL);
381 
382   for (i = 0; i < dpb->pic_list->len; i++) {
383     GstH265Picture *picture =
384         g_array_index (dpb->pic_list, GstH265Picture *, i);
385 
386     if (picture->ref && !picture->long_term && picture->pic_order_cnt == poc)
387       return gst_h265_picture_ref (picture);
388   }
389 
390   GST_DEBUG ("No short term reference picture for %d", poc);
391 
392   return NULL;
393 }
394 
395 /**
396  * gst_h265_dpb_get_long_ref_by_poc:
397  * @dpb: a #GstH265Dpb
398  * @poc: a picture order count
399  *
400  * Find a long term reference picture which has matching poc
401  *
402  * Returns: (nullable) (transfer full): a #GstH265Picture
403  */
404 GstH265Picture *
gst_h265_dpb_get_long_ref_by_poc(GstH265Dpb * dpb,gint poc)405 gst_h265_dpb_get_long_ref_by_poc (GstH265Dpb * dpb, gint poc)
406 {
407   gint i;
408 
409   g_return_val_if_fail (dpb != NULL, NULL);
410 
411   for (i = 0; i < dpb->pic_list->len; i++) {
412     GstH265Picture *picture =
413         g_array_index (dpb->pic_list, GstH265Picture *, i);
414 
415     if (picture->ref && picture->long_term && picture->pic_order_cnt == poc)
416       return gst_h265_picture_ref (picture);
417   }
418 
419   GST_DEBUG ("No long term reference picture for %d", poc);
420 
421   return NULL;
422 }
423 
424 /**
425  * gst_h265_dpb_get_pictures_all:
426  * @dpb: a #GstH265Dpb
427  *
428  * Return: (element-type GstH265Picture) (transfer full): a #GArray of
429  *   #GstH265Picture stored in @dpb
430  */
431 GArray *
gst_h265_dpb_get_pictures_all(GstH265Dpb * dpb)432 gst_h265_dpb_get_pictures_all (GstH265Dpb * dpb)
433 {
434   g_return_val_if_fail (dpb != NULL, NULL);
435 
436   return g_array_ref (dpb->pic_list);
437 }
438 
439 /**
440  * gst_h265_dpb_get_size:
441  * @dpb: a #GstH265Dpb
442  *
443  * Return: the length of stored dpb array
444  */
445 gint
gst_h265_dpb_get_size(GstH265Dpb * dpb)446 gst_h265_dpb_get_size (GstH265Dpb * dpb)
447 {
448   g_return_val_if_fail (dpb != NULL, -1);
449 
450   return dpb->pic_list->len;
451 }
452 
453 /**
454  * gst_h265_dpb_get_picture:
455  * @dpb: a #GstH265Dpb
456  * @system_frame_number The system frame number
457  *
458  * Returns: (transfer full): the picture identified with the specified
459  * @system_frame_number, or %NULL if DPB does not contain a #GstH265Picture
460  * corresponding to the @system_frame_number
461  *
462  * Since: 1.20
463  */
464 GstH265Picture *
gst_h265_dpb_get_picture(GstH265Dpb * dpb,guint32 system_frame_number)465 gst_h265_dpb_get_picture (GstH265Dpb * dpb, guint32 system_frame_number)
466 {
467   gint i;
468 
469   g_return_val_if_fail (dpb != NULL, NULL);
470 
471   for (i = 0; i < dpb->pic_list->len; i++) {
472     GstH265Picture *picture =
473         g_array_index (dpb->pic_list, GstH265Picture *, i);
474 
475     if (picture->system_frame_number == system_frame_number) {
476       gst_h265_picture_ref (picture);
477       return picture;
478     }
479   }
480 
481   return NULL;
482 }
483 
484 static gboolean
gst_h265_dpb_check_latency_count(GstH265Dpb * dpb,guint32 max_latency)485 gst_h265_dpb_check_latency_count (GstH265Dpb * dpb, guint32 max_latency)
486 {
487   gint i;
488 
489   for (i = 0; i < dpb->pic_list->len; i++) {
490     GstH265Picture *picture =
491         g_array_index (dpb->pic_list, GstH265Picture *, i);
492 
493     if (!picture->needed_for_output)
494       continue;
495 
496     if (picture->pic_latency_cnt >= max_latency)
497       return TRUE;
498   }
499 
500   return FALSE;
501 }
502 
503 /**
504  * gst_h265_dpb_needs_bump:
505  * @dpb: a #GstH265Dpb
506  * @max_num_reorder_pics: sps_max_num_reorder_pics[HighestTid]
507  * @max_latency_increase: SpsMaxLatencyPictures[HighestTid]
508  * @max_dec_pic_buffering: sps_max_dec_pic_buffering_minus1[HighestTid ] + 1
509  *   or zero if this shouldn't be used for bumping decision
510  *
511  * Returns: %TRUE if bumping is required
512  *
513  * Since: 1.20
514  */
515 gboolean
gst_h265_dpb_needs_bump(GstH265Dpb * dpb,guint max_num_reorder_pics,guint max_latency_increase,guint max_dec_pic_buffering)516 gst_h265_dpb_needs_bump (GstH265Dpb * dpb, guint max_num_reorder_pics,
517     guint max_latency_increase, guint max_dec_pic_buffering)
518 {
519   g_return_val_if_fail (dpb != NULL, FALSE);
520   g_assert (dpb->num_output_needed >= 0);
521 
522   /* If DPB is full and there is no empty space to store current picture,
523    * need bumping.
524    * NOTE: current picture was added already by our decoding flow, so we
525    * need to do bumping until dpb->pic_list->len == dpb->max_num_pic
526    */
527   if (dpb->pic_list->len > dpb->max_num_pics) {
528     GST_TRACE ("No empty frame buffer, need bumping");
529     return TRUE;
530   }
531 
532   /* C.5.2.3 */
533   if (dpb->num_output_needed > max_num_reorder_pics) {
534     GST_TRACE ("num_output_needed (%d) > max_num_reorder_pics (%d)",
535         dpb->num_output_needed, max_num_reorder_pics);
536     return TRUE;
537   }
538 
539   if (dpb->num_output_needed && max_latency_increase &&
540       gst_h265_dpb_check_latency_count (dpb, max_latency_increase)) {
541     GST_TRACE ("has late picture, max_latency_increase: %d",
542         max_latency_increase);
543     return TRUE;
544   }
545 
546   /* C.5.2.2 */
547   if (max_dec_pic_buffering && dpb->pic_list->len >= max_dec_pic_buffering) {
548     GST_TRACE ("dpb size (%d) >= max_dec_pic_buffering (%d)",
549         dpb->pic_list->len, max_dec_pic_buffering);
550     return TRUE;
551   }
552 
553   return FALSE;
554 }
555 
556 static gint
gst_h265_dpb_get_lowest_output_needed_picture(GstH265Dpb * dpb,GstH265Picture ** picture)557 gst_h265_dpb_get_lowest_output_needed_picture (GstH265Dpb * dpb,
558     GstH265Picture ** picture)
559 {
560   gint i;
561   GstH265Picture *lowest = NULL;
562   gint index = -1;
563 
564   *picture = NULL;
565 
566   for (i = 0; i < dpb->pic_list->len; i++) {
567     GstH265Picture *picture =
568         g_array_index (dpb->pic_list, GstH265Picture *, i);
569 
570     if (!picture->needed_for_output)
571       continue;
572 
573     if (!lowest) {
574       lowest = picture;
575       index = i;
576       continue;
577     }
578 
579     if (picture->pic_order_cnt < lowest->pic_order_cnt) {
580       lowest = picture;
581       index = i;
582     }
583   }
584 
585   if (lowest)
586     *picture = gst_h265_picture_ref (lowest);
587 
588   return index;
589 }
590 
591 /**
592  * gst_h265_dpb_bump:
593  * @dpb: a #GstH265Dpb
594  * @drain: whether draining or not
595  *
596  * Perform bumping process as defined in C.5.2.4 "Bumping" process.
597  * If @drain is %TRUE, @dpb will remove a #GstH265Picture from internal array
598  * so that returned #GstH265Picture could hold the last reference of it
599  *
600  * Returns: (nullable) (transfer full): a #GstH265Picture which is needed to be
601  * outputted
602  *
603  * Since: 1.20
604  */
605 GstH265Picture *
gst_h265_dpb_bump(GstH265Dpb * dpb,gboolean drain)606 gst_h265_dpb_bump (GstH265Dpb * dpb, gboolean drain)
607 {
608   GstH265Picture *picture;
609   gint index;
610 
611   g_return_val_if_fail (dpb != NULL, NULL);
612 
613   /* C.5.2.4 "Bumping" process */
614   index = gst_h265_dpb_get_lowest_output_needed_picture (dpb, &picture);
615 
616   if (!picture || index < 0)
617     return NULL;
618 
619   picture->needed_for_output = FALSE;
620 
621   dpb->num_output_needed--;
622   g_assert (dpb->num_output_needed >= 0);
623 
624   if (!picture->ref || drain)
625     g_array_remove_index_fast (dpb->pic_list, index);
626 
627   return picture;
628 }
629