summaryrefslogtreecommitdiffstats
path: root/libavcodec
diff options
context:
space:
mode:
authorClément Bœsch <u@pkh.me>2017-01-17 15:26:38 +0100
committerClément Bœsch <u@pkh.me>2017-01-24 16:13:03 +0100
commit744801989099df26e90b00062c645969c5347533 (patch)
tree776f86b3709a4355e967712065866fb89297be19 /libavcodec
parent1033f56b074d0aaf95fe2a0c356cd63cbb7f31aa (diff)
parent38efff92f1ef81f3de20ff0460ec7b70c253d714 (diff)
downloadffmpeg-streaming-744801989099df26e90b00062c645969c5347533.zip
ffmpeg-streaming-744801989099df26e90b00062c645969c5347533.tar.gz
Merge commit '38efff92f1ef81f3de20ff0460ec7b70c253d714'
* commit '38efff92f1ef81f3de20ff0460ec7b70c253d714': FATE: add a test for H.264 with two fields per packet h264: fix decoding multiple fields per packet with slice threads This merge includes two commits because the FATE test was useful in order to make proper testing. The merge gets rid of the now unused: - SLICE_SINGLETHREAD and SLICE_SKIPED macros - max_contexts - "again" label in decode_nal_units() This commit also includes the fix from d3e4d406b. Thanks to wm4 and Michael Niedermayer for their testing. Merged-by: Clément Bœsch <u@pkh.me> Merged-by: Matthieu Bouron <matthieu.bouron@gmail.com>
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/h264_slice.c260
-rw-r--r--libavcodec/h264dec.c67
-rw-r--r--libavcodec/h264dec.h27
3 files changed, 171 insertions, 183 deletions
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index ad7a75f..6b555ab 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 41e6ce4..31db1db 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 fa5c98e..5f868b7 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);
OpenPOWER on IntegriCloud