History

lavc/hevcdec: simplify output logic

Current code is written around the "simple" decode API's limitation that a single input packet (AU/coded frame) triggers the output of at most one output frame. However the spec contains two cases where a coded frame may cause multiple frames to be output (cf. C.5.2.2.2): * start of a new sequence * overflowing sps_max_dec_pic_buffering The decoder currently contains rather convoluted logic to handle these cases: * decode/output/per-frame sequence counters, * HEVC_FRAME_FLAG_BUMPING * ff_hevc_bump_frame() * special clauses in ff_hevc_output_frame() However, with the receive_frame() API none of that is necessary, as we can just output multiple frames at once. Previously added ContainerFifo allows that to be done in a straightforward and efficient manner.

Anton Khirnov committed 2 years ago

Commit 4b9adb31 parent 79afc453 files · +42 −127Browse files

Unified · Split

3 files
  1. libavcodec/hevc/hevcdec.c +13 −20
  2. libavcodec/hevc/hevcdec.h +10 −22
  3. libavcodec/hevc/refs.c +19 −85
libavcodec/hevc/hevcdec.c+13−20
@@ -2908,6 +2908,7 @@ static int hevc_frame_start(HEVCContext *s) · 2907 unmodified lines
2908 const HEVCSPS *const sps = pps->sps;2908 const HEVCSPS *const sps = pps->sps;
2909 int pic_size_in_ctb = ((sps->width >> sps->log2_min_cb_size) + 1) *2909 int pic_size_in_ctb = ((sps->width >> sps->log2_min_cb_size) + 1) *
2910 ((sps->height >> sps->log2_min_cb_size) + 1);2910 ((sps->height >> sps->log2_min_cb_size) + 1);
2911 int new_sequence = IS_IDR(s) || IS_BLA(s) || s->last_eos;
2911 int ret;2912 int ret;
2912 2913
2913 ff_refstruct_replace(&s->pps, pps);2914 ff_refstruct_replace(&s->pps, pps);
@@ -2927,7 +2928,7 @@ static int hevc_frame_start(HEVCContext *s) · 13 unmodified lines
2927 return pix_fmt;2928 return pix_fmt;
2928 s->avctx->pix_fmt = pix_fmt;2929 s->avctx->pix_fmt = pix_fmt;
2929 2930
2930 s->seq_decode = (s->seq_decode + 1) & HEVC_SEQUENCE_COUNTER_MASK;2931 new_sequence = 1;
2931 }2932 }
2932 2933
2933 memset(s->horizontal_bs, 0, s->bs_width * s->bs_height);2934 memset(s->horizontal_bs, 0, s->bs_width * s->bs_height);
@@ -2936,11 +2937,8 @@ static int hevc_frame_start(HEVCContext *s) · 2 unmodified lines
2936 memset(s->is_pcm, 0, (sps->min_pu_width + 1) * (sps->min_pu_height + 1));2937 memset(s->is_pcm, 0, (sps->min_pu_width + 1) * (sps->min_pu_height + 1));
2937 memset(s->tab_slice_address, -1, pic_size_in_ctb * sizeof(*s->tab_slice_address));2938 memset(s->tab_slice_address, -1, pic_size_in_ctb * sizeof(*s->tab_slice_address));
2938 2939
2939 if ((IS_IDR(s) || IS_BLA(s))) {2940 if (IS_IDR(s))
2940 s->seq_decode = (s->seq_decode + 1) & HEVC_SEQUENCE_COUNTER_MASK;2941 ff_hevc_clear_refs(s);
2941 if (IS_IDR(s))
2942 ff_hevc_clear_refs(s);
2943 }
2944 2942
2945 s->slice_idx = 0;2943 s->slice_idx = 0;
2946 s->first_nal_type = s->nal_unit_type;2944 s->first_nal_type = s->nal_unit_type;
@@ -2964,6 +2962,12 @@ static int hevc_frame_start(HEVCContext *s) · 17 unmodified lines
2964 if (pps->tiles_enabled_flag)2962 if (pps->tiles_enabled_flag)
2965 s->local_ctx[0].end_of_tiles_x = pps->column_width[0] << sps->log2_ctb_size;2963 s->local_ctx[0].end_of_tiles_x = pps->column_width[0] << sps->log2_ctb_size;
2966 2964
2965 if (new_sequence) {
2966 ret = ff_hevc_output_frames(s, 0, 0, s->sh.no_output_of_prior_pics_flag);
2967 if (ret < 0)
2968 return ret;
2969 }
2970
2967 ret = export_stream_params_from_sei(s);2971 ret = export_stream_params_from_sei(s);
2968 if (ret < 0)2972 if (ret < 0)
2969 return ret;2973 return ret;
@@ -3016,10 +3020,8 @@ static int hevc_frame_start(HEVCContext *s) · 46 unmodified lines
3016 3020
3017 s->cur_frame->f->pict_type = 3 - s->sh.slice_type;3021 s->cur_frame->f->pict_type = 3 - s->sh.slice_type;
3018 3022
3019 if (!IS_IRAP(s))3023 ret = ff_hevc_output_frames(s, sps->temporal_layer[sps->max_sub_layers - 1].num_reorder_pics,
3020 ff_hevc_bump_frame(s);3024 sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering, 0);
3021
3022 ret = ff_hevc_output_frame(s, 0);
3023 if (ret < 0)3025 if (ret < 0)
3024 goto fail;3026 goto fail;
3025 3027
@@ -3267,8 +3269,6 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal) · 241 unmodified lines
3267 break;3269 break;
3268 case HEVC_NAL_EOS_NUT:3270 case HEVC_NAL_EOS_NUT:
3269 case HEVC_NAL_EOB_NUT:3271 case HEVC_NAL_EOB_NUT:
3270 s->seq_decode = (s->seq_decode + 1) & HEVC_SEQUENCE_COUNTER_MASK;
3271 break;
3272 case HEVC_NAL_AUD:3272 case HEVC_NAL_AUD:
3273 case HEVC_NAL_FD_NUT:3273 case HEVC_NAL_FD_NUT:
3274 case HEVC_NAL_UNSPEC62:3274 case HEVC_NAL_UNSPEC62:
@@ -3425,7 +3425,7 @@ static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame) · 150 unmodified lines
3425 av_packet_unref(avpkt);3425 av_packet_unref(avpkt);
3426 ret = ff_decode_get_packet(avctx, avpkt);3426 ret = ff_decode_get_packet(avctx, avpkt);
3427 if (ret == AVERROR_EOF) {3427 if (ret == AVERROR_EOF) {
3428 ret = ff_hevc_output_frame(s, 1);3428 ret = ff_hevc_output_frames(s, 0, 0, 0);
3429 if (ret < 0)3429 if (ret < 0)
3430 return ret;3430 return ret;
3431 goto do_output;3431 goto do_output;
@@ -3487,7 +3487,6 @@ static int hevc_ref_frame(HEVCFrame *dst, const HEVCFrame *src) · 55 unmodified lines
3487 dst->poc = src->poc;3487 dst->poc = src->poc;
3488 dst->ctb_count = src->ctb_count;3488 dst->ctb_count = src->ctb_count;
3489 dst->flags = src->flags;3489 dst->flags = src->flags;
3490 dst->sequence = src->sequence;
3491 3490
3492 ff_refstruct_replace(&dst->hwaccel_picture_private,3491 ff_refstruct_replace(&dst->hwaccel_picture_private,
3493 src->hwaccel_picture_private);3492 src->hwaccel_picture_private);
@@ -3611,8 +3610,6 @@ static int hevc_update_thread_context(AVCodecContext *dst, · 117 unmodified lines
3611 if ((ret = set_sps(s, s0->ps.sps)) < 0)3610 if ((ret = set_sps(s, s0->ps.sps)) < 0)
3612 return ret;3611 return ret;
3613 3612
3614 s->seq_decode = s0->seq_decode;
3615 s->seq_output = s0->seq_output;
3616 s->poc_tid0 = s0->poc_tid0;3613 s->poc_tid0 = s0->poc_tid0;
3617 s->eos = s0->eos;3614 s->eos = s0->eos;
3618 s->no_rasl_output_flag = s0->no_rasl_output_flag;3615 s->no_rasl_output_flag = s0->no_rasl_output_flag;
@@ -3622,10 +3619,6 @@ static int hevc_update_thread_context(AVCodecContext *dst, · 3 unmodified lines
3622 3619
3623 s->film_grain_warning_shown = s0->film_grain_warning_shown;3620 s->film_grain_warning_shown = s0->film_grain_warning_shown;
3624 3621
3625 if (s0->eos) {
3626 s->seq_decode = (s->seq_decode + 1) & HEVC_SEQUENCE_COUNTER_MASK;
3627 }
3628
3629 ret = ff_h2645_sei_ctx_replace(&s->sei.common, &s0->sei.common);3622 ret = ff_h2645_sei_ctx_replace(&s->sei.common, &s0->sei.common);
3630 if (ret < 0)3623 if (ret < 0)
3631 return ret;3624 return ret;
libavcodec/hevc/hevcdec.h+10−22
@@ -349,10 +349,7 @@ typedef struct DBParams { · 348 unmodified lines
349#define HEVC_FRAME_FLAG_OUTPUT (1 << 0)349#define HEVC_FRAME_FLAG_OUTPUT (1 << 0)
350#define HEVC_FRAME_FLAG_SHORT_REF (1 << 1)350#define HEVC_FRAME_FLAG_SHORT_REF (1 << 1)
351#define HEVC_FRAME_FLAG_LONG_REF (1 << 2)351#define HEVC_FRAME_FLAG_LONG_REF (1 << 2)
352#define HEVC_FRAME_FLAG_BUMPING (1 << 3)352#define HEVC_FRAME_FLAG_UNAVAILABLE (1 << 3)
353
354#define HEVC_SEQUENCE_COUNTER_MASK 0xff
355#define HEVC_SEQUENCE_COUNTER_INVALID (HEVC_SEQUENCE_COUNTER_MASK + 1)
356 353
357typedef struct HEVCFrame {354typedef struct HEVCFrame {
358 union {355 union {
@@ -374,12 +371,6 @@ typedef struct HEVCFrame { · 15 unmodified lines
374 371
375 void *hwaccel_picture_private; ///< RefStruct reference372 void *hwaccel_picture_private; ///< RefStruct reference
376 373
377 /**
378 * A sequence counter, so that old frames are output first
379 * after a POC reset
380 */
381 uint16_t sequence;
382
383 /**374 /**
384 * A combination of HEVC_FRAME_FLAG_*375 * A combination of HEVC_FRAME_FLAG_*
385 */376 */
@@ -518,13 +509,6 @@ typedef struct HEVCContext { · 132 unmodified lines
518 uint8_t *checksum_buf;509 uint8_t *checksum_buf;
519 int checksum_buf_size;510 int checksum_buf_size;
520 511
521 /**
522 * Sequence counters for decoded and output frames, so that old
523 * frames are output first after a POC reset
524 */
525 uint16_t seq_decode;
526 uint16_t seq_output;
527
528 /** The target for the common_cabac_state of the local contexts. */512 /** The target for the common_cabac_state of the local contexts. */
529 HEVCCABACState cabac;513 HEVCCABACState cabac;
530 514
@@ -633,12 +617,16 @@ static av_always_inline int ff_hevc_nal_is_nonref(enum HEVCNALUnitType type) · 102 unmodified lines
633}617}
634 618
635/**619/**
636 * Find next frame in output order and put a reference to it in frame.620 * Find frames in the DPB that are ready for output and either write them to the
637 * @return 1 if a frame was output, 0 otherwise621 * output FIFO or drop their output flag, depending on the value of discard.
622 *
623 * @param max_output maximum number of output-pending frames that can be
624 * present in the DPB before output is triggered
625 * @param max_dpb maximum number of any frames that can be present in the DPB
626 * before output is triggered
638 */627 */
639int ff_hevc_output_frame(HEVCContext *s, int flush);628int ff_hevc_output_frames(HEVCContext *s, unsigned max_output,
640 629 unsigned max_dpb, int discard);
641void ff_hevc_bump_frame(HEVCContext *s);
642 630
643void ff_hevc_unref_frame(HEVCFrame *frame, int flags);631void ff_hevc_unref_frame(HEVCFrame *frame, int flags);
644 632
libavcodec/hevc/refs.c+19−85
@@ -132,8 +132,7 @@ int ff_hevc_set_new_ref(HEVCContext *s, int poc) · 131 unmodified lines
132 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {132 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
133 HEVCFrame *frame = &s->DPB[i];133 HEVCFrame *frame = &s->DPB[i];
134 134
135 if (frame->f && frame->sequence == s->seq_decode &&135 if (frame->f && frame->poc == poc) {
136 frame->poc == poc) {
137 av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n",136 av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n",
138 poc);137 poc);
139 return AVERROR_INVALIDDATA;138 return AVERROR_INVALIDDATA;
@@ -153,7 +152,6 @@ int ff_hevc_set_new_ref(HEVCContext *s, int poc) · 13 unmodified lines
153 ref->flags = HEVC_FRAME_FLAG_SHORT_REF;152 ref->flags = HEVC_FRAME_FLAG_SHORT_REF;
154 153
155 ref->poc = poc;154 ref->poc = poc;
156 ref->sequence = s->seq_decode;
157 ref->f->crop_left = s->ps.sps->output_window.left_offset;155 ref->f->crop_left = s->ps.sps->output_window.left_offset;
158 ref->f->crop_right = s->ps.sps->output_window.right_offset;156 ref->f->crop_right = s->ps.sps->output_window.right_offset;
159 ref->f->crop_top = s->ps.sps->output_window.top_offset;157 ref->f->crop_top = s->ps.sps->output_window.top_offset;
@@ -166,112 +164,49 @@ static void unref_missing_refs(HEVCContext *s) · 6 unmodified lines
166{164{
167 for (int i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {165 for (int i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
168 HEVCFrame *frame = &s->DPB[i];166 HEVCFrame *frame = &s->DPB[i];
169 if (frame->sequence == HEVC_SEQUENCE_COUNTER_INVALID) {167 if (frame->flags & HEVC_FRAME_FLAG_UNAVAILABLE) {
170 ff_hevc_unref_frame(frame, ~0);168 ff_hevc_unref_frame(frame, ~0);
171 }169 }
172 }170 }
173}171}
174 172
175int ff_hevc_output_frame(HEVCContext *s, int flush)173int ff_hevc_output_frames(HEVCContext *s, unsigned max_output,
174 unsigned max_dpb, int discard)
176{175{
177 if (IS_IRAP(s) && s->no_rasl_output_flag == 1) {176 while (1) {
178 const static int mask = HEVC_FRAME_FLAG_BUMPING | HEVC_FRAME_FLAG_OUTPUT;177 int nb_dpb = 0;
179 for (int i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
180 HEVCFrame *frame = &s->DPB[i];
181 if ((frame->flags & mask) == HEVC_FRAME_FLAG_OUTPUT &&
182 frame->sequence != s->seq_decode) {
183 if (s->sh.no_output_of_prior_pics_flag == 1)
184 ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT);
185 else
186 frame->flags |= HEVC_FRAME_FLAG_BUMPING;
187 }
188 }
189 }
190 do {
191 int nb_output = 0;178 int nb_output = 0;
192 int min_poc = INT_MAX;179 int min_poc = INT_MAX;
193 int i, min_idx, ret;180 int i, min_idx, ret;
194 181
195 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {182 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
196 HEVCFrame *frame = &s->DPB[i];183 HEVCFrame *frame = &s->DPB[i];
197 if ((frame->flags & HEVC_FRAME_FLAG_OUTPUT) &&184 if (frame->flags & HEVC_FRAME_FLAG_OUTPUT) {
198 frame->sequence == s->seq_output) {
199 nb_output++;185 nb_output++;
200 if (frame->poc < min_poc || nb_output == 1) {186 if (frame->poc < min_poc || nb_output == 1) {
201 min_poc = frame->poc;187 min_poc = frame->poc;
202 min_idx = i;188 min_idx = i;
203 }189 }
204 }190 }
191 nb_dpb += !!frame->flags;
205 }192 }
206 193
207 /* wait for more frames before output */194 if (nb_output > max_output ||
208 if (!flush && s->seq_output == s->seq_decode && s->ps.sps &&195 (nb_output && nb_dpb > max_dpb)) {
209 nb_output <= s->ps.sps->temporal_layer[s->ps.sps->max_sub_layers - 1].num_reorder_pics)
210 return 0;
211
212 if (nb_output) {
213 HEVCFrame *frame = &s->DPB[min_idx];196 HEVCFrame *frame = &s->DPB[min_idx];
214 197
215 ret = ff_container_fifo_write(s->output_fifo,198 ret = discard ? 0 :
199 ff_container_fifo_write(s->output_fifo,
216 frame->needs_fg ? frame->frame_grain : frame->f);200 frame->needs_fg ? frame->frame_grain : frame->f);
217 if (frame->flags & HEVC_FRAME_FLAG_BUMPING)201 ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT);
218 ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_BUMPING);
219 else
220 ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT);
221 if (ret < 0)202 if (ret < 0)
222 return ret;203 return ret;
223 204
224 av_log(s->avctx, AV_LOG_DEBUG,205 av_log(s->avctx, AV_LOG_DEBUG, "%s frame with POC %d.\n",
225 "Output frame with POC %d.\n", frame->poc);206 discard ? "Discarded" : "Output", frame->poc);
226 return 1;207 continue;
227 }
228
229 if (s->seq_output != s->seq_decode)
230 s->seq_output = (s->seq_output + 1) & HEVC_SEQUENCE_COUNTER_MASK;
231 else
232 break;
233 } while (1);
234
235 return 0;
236}
237
238void ff_hevc_bump_frame(HEVCContext *s)
239{
240 int dpb = 0;
241 int min_poc = INT_MAX;
242 int i;
243
244 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
245 HEVCFrame *frame = &s->DPB[i];
246 if ((frame->flags) &&
247 frame->sequence == s->seq_output &&
248 frame->poc != s->poc) {
249 dpb++;
250 }
251 }
252
253 if (s->ps.sps && dpb >= s->ps.sps->temporal_layer[s->ps.sps->max_sub_layers - 1].max_dec_pic_buffering) {
254 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
255 HEVCFrame *frame = &s->DPB[i];
256 if ((frame->flags) &&
257 frame->sequence == s->seq_output &&
258 frame->poc != s->poc) {
259 if (frame->flags == HEVC_FRAME_FLAG_OUTPUT && frame->poc < min_poc) {
260 min_poc = frame->poc;
261 }
262 }
263 }
264
265 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
266 HEVCFrame *frame = &s->DPB[i];
267 if (frame->flags & HEVC_FRAME_FLAG_OUTPUT &&
268 frame->sequence == s->seq_output &&
269 frame->poc <= min_poc) {
270 frame->flags |= HEVC_FRAME_FLAG_BUMPING;
271 }
272 }208 }
273 209 return 0;
274 dpb--;
275 }210 }
276}211}
277 212
@@ -385,7 +320,7 @@ static HEVCFrame *find_ref_idx(HEVCContext *s, int poc, uint8_t use_msb) · 107 unmodified lines
385 320
386 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {321 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
387 HEVCFrame *ref = &s->DPB[i];322 HEVCFrame *ref = &s->DPB[i];
388 if (ref->f && ref->sequence == s->seq_decode) {323 if (ref->f) {
389 if ((ref->poc & mask) == poc && (use_msb || ref->poc != s->poc))324 if ((ref->poc & mask) == poc && (use_msb || ref->poc != s->poc))
390 return ref;325 return ref;
391 }326 }
@@ -428,8 +363,7 @@ static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc) · 36 unmodified lines
428 }363 }
429 364
430 frame->poc = poc;365 frame->poc = poc;
431 frame->sequence = HEVC_SEQUENCE_COUNTER_INVALID;366 frame->flags = HEVC_FRAME_FLAG_UNAVAILABLE;
432 frame->flags = 0;
433 367
434 if (s->avctx->active_thread_type == FF_THREAD_FRAME)368 if (s->avctx->active_thread_type == FF_THREAD_FRAME)
435 ff_progress_frame_report(&frame->tf, INT_MAX);369 ff_progress_frame_report(&frame->tf, INT_MAX);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t