diff options
author | Anton Khirnov <anton@khirnov.net> | 2016-06-12 14:22:50 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2016-07-15 15:33:54 +0200 |
commit | 4a9bab3db0d9ec449ebc8b5e823374d1d1df7761 (patch) | |
tree | 496394aa8226d1b340b40104f34ff8bb57f1d715 /libavcodec/h264_slice.c | |
parent | f450cc7bc595155bacdb9f5d2414a076ccf81b4a (diff) |
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.
Diffstat (limited to 'libavcodec/h264_slice.c')
-rw-r--r-- | libavcodec/h264_slice.c | 129 |
1 files changed, 82 insertions, 47 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; } |