diff options
-rw-r--r-- | libavcodec/h264_slice.c | 260 | ||||
-rw-r--r-- | libavcodec/h264dec.c | 67 | ||||
-rw-r--r-- | libavcodec/h264dec.h | 27 | ||||
-rw-r--r-- | tests/fate/h264.mak | 4 | ||||
-rw-r--r-- | tests/ref/fate/h264-twofields-packet | 35 |
5 files changed, 210 insertions, 183 deletions
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index ad7a75fa2e..6b555ab4c5 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1849,119 +1849,12 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, 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; - int first_slice = sl == h->slice_ctx && !h->current_slice; - - ret = h264_slice_header_parse(h, sl, nal); - if (ret < 0) - return ret; - - // discard redundant pictures - if (sl->redundant_pic_count > 0) - return 0; - - if (sl->first_mb_addr == 0 || !h->current_slice) { - if (h->setup_finished) { - av_log(h->avctx, AV_LOG_ERROR, "Too many fields\n"); - return AVERROR_INVALIDDATA; - } - } - - if (sl->first_mb_addr == 0) { // FIXME better field boundary detection - if (h->current_slice) { - if (h->max_contexts > 1) { - if (!h->single_decode_warning) { - av_log(h->avctx, AV_LOG_WARNING, "Cannot decode multiple access units as slice threads\n"); - h->single_decode_warning = 1; - } - h->max_contexts = 1; - return SLICE_SINGLETHREAD; - } - - if (h->cur_pic_ptr && FIELD_PICTURE(h) && h->first_field) { - ret = ff_h264_field_end(h, h->slice_ctx, 1); - if (ret < 0) - return ret; - } else if (h->cur_pic_ptr && !FIELD_PICTURE(h) && !h->first_field && h->nal_unit_type == H264_NAL_IDR_SLICE) { - av_log(h, AV_LOG_WARNING, "Broken frame packetizing\n"); - ret = ff_h264_field_end(h, h->slice_ctx, 1); - ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 0); - ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 1); - h->cur_pic_ptr = NULL; - if (ret < 0) - return ret; - } else - return AVERROR_INVALIDDATA; - } - - 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) - av_assert0(sl == h->slice_ctx); - - if (h->current_slice == 0 && !h->first_field) { - if ( - (h->avctx->skip_frame >= AVDISCARD_NONREF && !h->nal_ref_idc) || - (h->avctx->skip_frame >= AVDISCARD_BIDIR && sl->slice_type_nos == AV_PICTURE_TYPE_B) || - (h->avctx->skip_frame >= AVDISCARD_NONINTRA && sl->slice_type_nos != AV_PICTURE_TYPE_I) || - (h->avctx->skip_frame >= AVDISCARD_NONKEY && h->nal_unit_type != H264_NAL_IDR_SLICE && h->sei.recovery_point.recovery_frame_cnt < 0) || - h->avctx->skip_frame >= AVDISCARD_ALL) { - return SLICE_SKIPED; - } - } - - if (!first_slice) { - const PPS *pps = (const PPS*)h->ps.pps_list[sl->pps_id]->data; - - if (h->ps.pps->sps_id != pps->sps_id || - h->ps.pps->transform_8x8_mode != pps->transform_8x8_mode /*|| - (h->setup_finished && h->ps.pps != pps)*/) { - av_log(h->avctx, AV_LOG_ERROR, "PPS changed between slices\n"); - return AVERROR_INVALIDDATA; - } - if (h->ps.sps != (const SPS*)h->ps.sps_list[h->ps.pps->sps_id]->data) { - av_log(h->avctx, AV_LOG_ERROR, - "SPS changed in the middle of the frame\n"); - return AVERROR_INVALIDDATA; - } - } - - if (h->current_slice == 0) { - ret = h264_field_start(h, sl, nal, first_slice); - if (ret < 0) - return ret; - } else { - if (h->picture_structure != sl->picture_structure || - h->droppable != (nal->ref_idc == 0)) { - av_log(h->avctx, AV_LOG_ERROR, - "Changing field mode (%d -> %d) between slices is not allowed\n", - h->picture_structure, sl->picture_structure); - return AVERROR_INVALIDDATA; - } else if (!h->cur_pic_ptr) { - av_log(h->avctx, AV_LOG_ERROR, - "unset cur_pic_ptr on slice %d\n", - h->current_slice + 1); - return AVERROR_INVALIDDATA; - } - } if (h->picture_idr && nal->type != H264_NAL_IDR_SLICE) { av_log(h->avctx, AV_LOG_ERROR, "Invalid mix of IDR and non-IDR slices\n"); @@ -2009,7 +1902,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, nal->ref_idc == 0)) sl->deblocking_filter = 0; - if (sl->deblocking_filter == 1 && h->max_contexts > 1) { + if (sl->deblocking_filter == 1 && h->nb_slice_ctx > 1) { if (h->avctx->flags2 & AV_CODEC_FLAG2_FAST) { /* Cheat slightly for speed: * Do not bother to deblock across slices. */ @@ -2093,6 +1986,129 @@ 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 first_slice = sl == h->slice_ctx && !h->current_slice; + int ret; + + sl->gb = nal->gb; + + ret = h264_slice_header_parse(h, sl, nal); + if (ret < 0) + return ret; + + // discard redundant pictures + if (sl->redundant_pic_count > 0) + return 0; + + if (sl->first_mb_addr == 0 || !h->current_slice) { + if (h->setup_finished) { + av_log(h->avctx, AV_LOG_ERROR, "Too many fields\n"); + return AVERROR_INVALIDDATA; + } + } + + if (sl->first_mb_addr == 0) { // FIXME better field boundary detection + if (h->current_slice) { + // 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->cur_pic_ptr && FIELD_PICTURE(h) && h->first_field) { + ret = ff_h264_field_end(h, h->slice_ctx, 1); + if (ret < 0) + return ret; + } else if (h->cur_pic_ptr && !FIELD_PICTURE(h) && !h->first_field && h->nal_unit_type == H264_NAL_IDR_SLICE) { + av_log(h, AV_LOG_WARNING, "Broken frame packetizing\n"); + ret = ff_h264_field_end(h, h->slice_ctx, 1); + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 0); + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 1); + h->cur_pic_ptr = NULL; + if (ret < 0) + return ret; + } else + return AVERROR_INVALIDDATA; + } + + 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) + av_assert0(sl == h->slice_ctx); + + if (h->current_slice == 0 && !h->first_field) { + if ( + (h->avctx->skip_frame >= AVDISCARD_NONREF && !h->nal_ref_idc) || + (h->avctx->skip_frame >= AVDISCARD_BIDIR && sl->slice_type_nos == AV_PICTURE_TYPE_B) || + (h->avctx->skip_frame >= AVDISCARD_NONINTRA && sl->slice_type_nos != AV_PICTURE_TYPE_I) || + (h->avctx->skip_frame >= AVDISCARD_NONKEY && h->nal_unit_type != H264_NAL_IDR_SLICE && h->sei.recovery_point.recovery_frame_cnt < 0) || + h->avctx->skip_frame >= AVDISCARD_ALL) { + return 0; + } + } + + if (!first_slice) { + const PPS *pps = (const PPS*)h->ps.pps_list[sl->pps_id]->data; + + if (h->ps.pps->sps_id != pps->sps_id || + h->ps.pps->transform_8x8_mode != pps->transform_8x8_mode /*|| + (h->setup_finished && h->ps.pps != pps)*/) { + av_log(h->avctx, AV_LOG_ERROR, "PPS changed between slices\n"); + return AVERROR_INVALIDDATA; + } + if (h->ps.sps != (const SPS*)h->ps.sps_list[h->ps.pps->sps_id]->data) { + av_log(h->avctx, AV_LOG_ERROR, + "SPS changed in the middle of the frame\n"); + return AVERROR_INVALIDDATA; + } + } + + if (h->current_slice == 0) { + ret = h264_field_start(h, sl, nal, first_slice); + if (ret < 0) + return ret; + } else { + if (h->picture_structure != sl->picture_structure || + h->droppable != (nal->ref_idc == 0)) { + av_log(h->avctx, AV_LOG_ERROR, + "Changing field mode (%d -> %d) between slices is not allowed\n", + h->picture_structure, sl->picture_structure); + return AVERROR_INVALIDDATA; + } else if (!h->cur_pic_ptr) { + av_log(h->avctx, AV_LOG_ERROR, + "unset cur_pic_ptr on slice %d\n", + h->current_slice + 1); + return AVERROR_INVALIDDATA; + } + } + + ret = h264_slice_init(h, sl, nal); + if (ret < 0) + return ret; + + h->nb_slice_ctx_queued++; + + return 0; +} + int ff_h264_get_slice_type(const H264SliceContext *sl) { switch (sl->slice_type) { @@ -2678,33 +2694,35 @@ 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; - av_assert0(context_count && h->slice_ctx[context_count - 1].mb_y < h->mb_height); - h->slice_ctx[0].next_slice_idx = INT_MAX; - if (h->avctx->hwaccel + if (h->avctx->hwaccel || context_count < 1 #if FF_API_CAP_VDPAU || h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU #endif ) return 0; + + av_assert0(context_count && h->slice_ctx[context_count - 1].mb_y < h->mb_height); + 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 { av_assert0(context_count > 0); for (i = 0; i < context_count; i++) { @@ -2759,5 +2777,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 41e6ce458c..31db1db076 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -602,7 +602,6 @@ static void debug_green_metadata(const H264SEIGreenMetaData *gm, void *logctx) 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 idr_cleared=0; int i, ret = 0; @@ -610,7 +609,6 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) h->has_slice = 0; h->nal_unit_type= 0; - h->max_contexts = h->nb_slice_ctx; if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS)) { h->current_slice = 0; if (!h->first_field) @@ -640,14 +638,12 @@ 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) continue; -again: // FIXME these should stop being context-global variables h->nal_ref_idc = nal->ref_idc; h->nal_unit_type = nal->type; @@ -672,13 +668,9 @@ again: idr_cleared = 1; h->has_recovery_point = 1; case H264_NAL_SLICE: - sl->gb = nal->gb; h->has_slice = 1; - 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 (h->current_slice == 1) { @@ -698,14 +690,14 @@ again: #endif } - if (avctx->hwaccel) { - ret = avctx->hwaccel->decode_slice(avctx, - nal->raw_data, - nal->raw_size); - if (ret < 0) - goto end; + max_slice_ctx = avctx->hwaccel ? 1 : h->nb_slice_ctx; + if (h->nb_slice_ctx_queued == max_slice_ctx) { + if (h->avctx->hwaccel) { + ret = avctx->hwaccel->decode_slice(avctx, nal->raw_data, nal->raw_size); + h->nb_slice_ctx_queued = 0; + } else #if FF_API_CAP_VDPAU - } else if (CONFIG_H264_VDPAU_DECODER && + if (CONFIG_H264_VDPAU_DECODER && h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) { ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0], start_code, @@ -713,9 +705,13 @@ again: ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0], nal->raw_data, nal->raw_size); -#endif + ret = 0; } else - context_count++; +#endif + ret = ff_h264_execute_decode_slices(h); + if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) + goto end; + } break; case H264_NAL_DPA: case H264_NAL_DPB: @@ -765,34 +761,14 @@ FF_ENABLE_DEPRECATION_WARNINGS nal->type, nal->size_bits); } - if (context_count == h->max_contexts) { - 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 || err == SLICE_SKIPED) { - 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; - } else if (err == SLICE_SINGLETHREAD) { - if (context_count > 0) { - ret = ff_h264_execute_decode_slices(h, context_count); - if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) - goto end; - context_count = 0; - } - /* Slice could not be decoded in parallel mode, restart. */ - sl = &h->slice_ctx[0]; - goto again; + if (err < 0) { + av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n"); } } - 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: @@ -1013,6 +989,7 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data, h->flags = avctx->flags; h->setup_finished = 0; + h->nb_slice_ctx_queued = 0; if (h->backup_width != -1) { avctx->width = h->backup_width; diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index fa5c98ee90..5f868b76cb 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -353,6 +353,7 @@ typedef struct H264Context { H264SliceContext *slice_ctx; int nb_slice_ctx; + int nb_slice_ctx_queued; H2645Packet pkt; @@ -491,20 +492,6 @@ typedef struct H264Context { */ int current_slice; - /** - * Max number of threads / contexts. - * This is equal to AVCodecContext.thread_count unless - * multithreaded decoding is impossible, in which case it is - * reduced to 1. - */ - int max_contexts; - - /** - * 1 if the single thread fallback warning has already been - * displayed, 0 otherwise. - */ - int single_decode_warning; - /** @} */ /** @@ -848,10 +835,14 @@ void ff_h264_draw_horiz_band(const H264Context *h, H264SliceContext *sl, int y, int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, const H2645NAL *nal); -#define SLICE_SINGLETHREAD 1 -#define SLICE_SKIPED 2 - -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); diff --git a/tests/fate/h264.mak b/tests/fate/h264.mak index 1f6e5f3947..52b6a98785 100644 --- a/tests/fate/h264.mak +++ b/tests/fate/h264.mak @@ -215,6 +215,9 @@ FATE_H264-$(call DEMDEC, MOV, H264) += fate-h264-mixed-nal-coding # this sample has invalid extradata that is not escaped FATE_H264-$(call DEMDEC, MOV, H264) += fate-h264-unescaped-extradata +# this sample contains field-coded frames, with both fields in a single packet +FATE_H264-$(call DEMDEC, MOV, H264) += fate-h264-twofields-packet + FATE_H264-$(call ALLYES, MOV_DEMUXER H264_MP4TOANNEXB_BSF H264_MUXER) += fate-h264-bsf-mp4toannexb FATE_H264-$(call DEMDEC, MATROSKA, H264) += fate-h264-direct-bff FATE_H264-$(call DEMDEC, FLV, H264) += fate-h264-brokensps-2580 @@ -431,6 +434,7 @@ fate-h264-intra-refresh-recovery: CMD = framecrc -i $(TARGET_SAM fate-h264-invalid-ref-mod: CMD = framecrc -i $(TARGET_SAMPLES)/h264/h264refframeregression.mp4 -an -frames 10 -pix_fmt yuv420p10le fate-h264-lossless: CMD = framecrc -i $(TARGET_SAMPLES)/h264/lossless.h264 fate-h264-mixed-nal-coding: CMD = framecrc -i $(TARGET_SAMPLES)/h264/mixed-nal-coding.mp4 +fate-h264-twofields-packet: CMD = framecrc -i $(TARGET_SAMPLES)/h264/twofields_packet.mp4 -an -frames 30 fate-h264-unescaped-extradata: CMD = framecrc -i $(TARGET_SAMPLES)/h264/unescaped_extradata.mp4 -an -frames 10 fate-h264-3386: CMD = framecrc -i $(TARGET_SAMPLES)/h264/bbc2.sample.h264 fate-h264-missing-frame: CMD = framecrc -i $(TARGET_SAMPLES)/h264/nondeterministic_cut.h264 diff --git a/tests/ref/fate/h264-twofields-packet b/tests/ref/fate/h264-twofields-packet new file mode 100644 index 0000000000..4cff0a15bd --- /dev/null +++ b/tests/ref/fate/h264-twofields-packet @@ -0,0 +1,35 @@ +#tb 0: 1001/30000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 1/1 +0, 0, 0, 1, 3110400, 0x40d65f69 +0, 1, 1, 1, 3110400, 0xdcbc50bf +0, 2, 2, 1, 3110400, 0x73a2276a +0, 3, 3, 1, 3110400, 0x84a2b3c6 +0, 4, 4, 1, 3110400, 0x7cf3b570 +0, 5, 5, 1, 3110400, 0xa2d1e03a +0, 6, 6, 1, 3110400, 0x03220fb1 +0, 7, 7, 1, 3110400, 0x89cd526a +0, 8, 8, 1, 3110400, 0xbb4b7531 +0, 9, 9, 1, 3110400, 0x0a69f053 +0, 10, 10, 1, 3110400, 0x0187994b +0, 11, 11, 1, 3110400, 0x26ed49fa +0, 12, 12, 1, 3110400, 0xbe8966d4 +0, 13, 13, 1, 3110400, 0x248d203c +0, 14, 14, 1, 3110400, 0x3139c754 +0, 15, 15, 1, 3110400, 0xf22380c4 +0, 16, 16, 1, 3110400, 0x3e00dcc1 +0, 17, 17, 1, 3110400, 0x8cbe2483 +0, 18, 18, 1, 3110400, 0x6951cd63 +0, 19, 19, 1, 3110400, 0x36aca4c5 +0, 20, 20, 1, 3110400, 0x4d4f6fbe +0, 21, 21, 1, 3110400, 0x997247aa +0, 22, 22, 1, 3110400, 0x0fd40e06 +0, 23, 23, 1, 3110400, 0xa10d2d67 +0, 24, 24, 1, 3110400, 0x87c481da +0, 25, 25, 1, 3110400, 0xe3dca3cd +0, 26, 26, 1, 3110400, 0x5f77b078 +0, 27, 27, 1, 3110400, 0xf1ddd098 +0, 28, 28, 1, 3110400, 0xedcd1754 +0, 29, 29, 1, 3110400, 0x14ac7153 |