From 4a9bab3db0d9ec449ebc8b5e823374d1d1df7761 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 12 Jun 2016 14:22:50 +0200 Subject: [PATCH] h264: fix decoding multiple fields per packet with slice threads Since we only know whether a NAL unit corresponds to a new field after parsing the slice header, this requires reorganizing the calls to slice parsing, per-slice/field/frame init and actual decoding. In the previous code, the function for slice header decoding also immediately started a new field/frame as necessary, so any slices already queued for decoding would no longer be decodable. After this patch, we first parse the slice header, and if we determine that a new field needs to be started we decode all the queued slices. --- libavcodec/h264_slice.c | 129 +++++++++++++++++++++++++--------------- libavcodec/h264dec.c | 47 +++++---------- libavcodec/h264dec.h | 12 +++- 3 files changed, 105 insertions(+), 83 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 8adbe217ce..8d79740a7f 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1699,50 +1699,13 @@ static int h264_slice_header_parse(H264SliceContext *sl, const H2645NAL *nal, return 0; } -/** - * Decode a slice header. - * This will (re)initialize the decoder and call h264_frame_start() as needed. - * - * @param h h264context - * - * @return 0 if okay, <0 if an error occurred - */ -int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, - const H2645NAL *nal) +/* do all the per-slice initialization needed before we can start decoding the + * actual MBs */ +static int h264_slice_init(H264Context *h, H264SliceContext *sl, + const H2645NAL *nal) { int i, j, ret = 0; - ret = h264_slice_header_parse(sl, nal, &h->ps, h->avctx); - if (ret < 0) - return ret; - - // discard redundant pictures - if (sl->redundant_pic_count > 0) - return 0; - - if (!h->setup_finished) { - if (sl->first_mb_addr == 0) { // FIXME better field boundary detection - if (h->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) { - ff_h264_field_end(h, sl, 1); - } - - h->current_slice = 0; - if (!h->first_field) { - if (h->cur_pic_ptr && !h->droppable) { - ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, - h->picture_structure == PICT_BOTTOM_FIELD); - } - h->cur_pic_ptr = NULL; - } - } - - if (h->current_slice == 0) { - ret = h264_field_start(h, sl, nal); - if (ret < 0) - return ret; - } - } - if (h->current_slice > 0) { if (h->ps.pps != (const PPS*)h->ps.pps_list[sl->pps_id]->data) { av_log(h->avctx, AV_LOG_ERROR, "PPS changed between slices\n"); @@ -1886,6 +1849,75 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, return 0; } +int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal) +{ + H264SliceContext *sl = h->slice_ctx + h->nb_slice_ctx_queued; + int ret; + + sl->gb = nal->gb; + + ret = h264_slice_header_parse(sl, nal, &h->ps, h->avctx); + if (ret < 0) + return ret; + + // discard redundant pictures + if (sl->redundant_pic_count > 0) + return 0; + + if (!h->setup_finished) { + if (sl->first_mb_addr == 0) { // FIXME better field boundary detection + // this slice starts a new field + // first decode any pending queued slices + if (h->nb_slice_ctx_queued) { + H264SliceContext tmp_ctx; + + ret = ff_h264_execute_decode_slices(h); + if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) + return ret; + + memcpy(&tmp_ctx, h->slice_ctx, sizeof(tmp_ctx)); + memcpy(h->slice_ctx, sl, sizeof(tmp_ctx)); + memcpy(sl, &tmp_ctx, sizeof(tmp_ctx)); + sl = h->slice_ctx; + } + + if (h->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) { + ff_h264_field_end(h, sl, 1); + } + + h->current_slice = 0; + if (!h->first_field) { + if (h->cur_pic_ptr && !h->droppable) { + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, + h->picture_structure == PICT_BOTTOM_FIELD); + } + h->cur_pic_ptr = NULL; + } + } + + if (h->current_slice == 0) { + ret = h264_field_start(h, sl, nal); + if (ret < 0) + return ret; + } + } + + ret = h264_slice_init(h, sl, nal); + if (ret < 0) + return ret; + + if ((h->avctx->skip_frame < AVDISCARD_NONREF || nal->ref_idc) && + (h->avctx->skip_frame < AVDISCARD_BIDIR || + sl->slice_type_nos != AV_PICTURE_TYPE_B) && + (h->avctx->skip_frame < AVDISCARD_NONKEY || + h->cur_pic_ptr->f->key_frame) && + h->avctx->skip_frame < AVDISCARD_ALL) { + h->nb_slice_ctx_queued++; + } + + return 0; +} + int ff_h264_get_slice_type(const H264SliceContext *sl) { switch (sl->slice_type) { @@ -2452,25 +2484,26 @@ finish: * Call decode_slice() for each context. * * @param h h264 master context - * @param context_count number of contexts to execute */ -int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count) +int ff_h264_execute_decode_slices(H264Context *h) { AVCodecContext *const avctx = h->avctx; H264SliceContext *sl; + int context_count = h->nb_slice_ctx_queued; + int ret = 0; int i, j; - if (h->avctx->hwaccel) + if (h->avctx->hwaccel || context_count < 1) return 0; if (context_count == 1) { - int ret; h->slice_ctx[0].next_slice_idx = h->mb_width * h->mb_height; h->postpone_filter = 0; ret = decode_slice(avctx, &h->slice_ctx[0]); h->mb_y = h->slice_ctx[0].mb_y; - return ret; + if (ret < 0) + goto finish; } else { for (i = 0; i < context_count; i++) { int next_slice_idx = h->mb_width * h->mb_height; @@ -2520,5 +2553,7 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count) } } - return 0; +finish: + h->nb_slice_ctx_queued = 0; + return ret; } diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 3ce76eae64..1086eab8d3 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -508,7 +508,6 @@ static int get_last_needed_nal(H264Context *h) static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) { AVCodecContext *const avctx = h->avctx; - unsigned context_count = 0; int nals_needed = 0; ///< number of NALs that need decoding before the next frame thread starts int i, ret = 0; @@ -532,8 +531,7 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) for (i = 0; i < h->pkt.nb_nals; i++) { H2645NAL *nal = &h->pkt.nals[i]; - H264SliceContext *sl = &h->slice_ctx[context_count]; - int err; + int max_slice_ctx, err; if (avctx->skip_frame >= AVDISCARD_NONREF && nal->ref_idc == 0 && nal->type != H264_NAL_SEI) @@ -548,12 +546,7 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) case H264_NAL_IDR_SLICE: idr(h); // FIXME ensure we don't lose some frames if there is reordering case H264_NAL_SLICE: - sl->gb = nal->gb; - - if ((err = ff_h264_decode_slice_header(h, sl, nal))) - break; - - if (sl->redundant_pic_count > 0) + if ((err = ff_h264_queue_decode_slice(h, nal))) break; if (avctx->active_thread_type & FF_THREAD_FRAME && !h->avctx->hwaccel && @@ -562,18 +555,14 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) h->setup_finished = 1; } - if ((avctx->skip_frame < AVDISCARD_NONREF || nal->ref_idc) && - (avctx->skip_frame < AVDISCARD_BIDIR || - sl->slice_type_nos != AV_PICTURE_TYPE_B) && - (avctx->skip_frame < AVDISCARD_NONKEY || - h->cur_pic_ptr->f->key_frame) && - avctx->skip_frame < AVDISCARD_ALL) { - if (avctx->hwaccel) { + max_slice_ctx = avctx->hwaccel ? 1 : h->nb_slice_ctx; + if (h->nb_slice_ctx_queued == max_slice_ctx) { + if (avctx->hwaccel) ret = avctx->hwaccel->decode_slice(avctx, nal->raw_data, nal->raw_size); - if (ret < 0) - return ret; - } else - context_count++; + else + ret = ff_h264_execute_decode_slices(h); + if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) + goto end; } break; case H264_NAL_DPA: @@ -611,23 +600,14 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) nal->type, nal->size_bits); } - if (context_count == h->nb_slice_ctx) { - ret = ff_h264_execute_decode_slices(h, context_count); - if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) - goto end; - context_count = 0; - } - if (err < 0) { av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n"); - sl->ref_count[0] = sl->ref_count[1] = sl->list_count = 0; } } - if (context_count) { - ret = ff_h264_execute_decode_slices(h, context_count); - if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) - goto end; - } + + ret = ff_h264_execute_decode_slices(h); + if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) + goto end; ret = 0; end: @@ -687,6 +667,7 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data, h->flags = avctx->flags; h->setup_finished = 0; + h->nb_slice_ctx_queued = 0; /* end of stream, output what is still in the buffers */ out: diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 6f5ab41f52..f934fc40b8 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -345,6 +345,7 @@ typedef struct H264Context { H264SliceContext *slice_ctx; int nb_slice_ctx; + int nb_slice_ctx_queued; H2645Packet pkt; @@ -793,9 +794,14 @@ int ff_h264_slice_context_init(H264Context *h, H264SliceContext *sl); void ff_h264_draw_horiz_band(const H264Context *h, H264SliceContext *sl, int y, int height); -int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, - const H2645NAL *nal); -int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count); +/** + * Submit a slice for decoding. + * + * Parse the slice header, starting a new field/frame if necessary. If any + * slices are queued for the previous field, they are decoded. + */ +int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal); +int ff_h264_execute_decode_slices(H264Context *h); int ff_h264_update_thread_context(AVCodecContext *dst, const AVCodecContext *src);