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