mirror of
https://git.videolan.org/git/ffmpeg.git
synced 2024-09-11 09:57:54 +02:00
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.
This commit is contained in:
parent
f450cc7bc5
commit
4a9bab3db0
@ -1699,50 +1699,13 @@ static int h264_slice_header_parse(H264SliceContext *sl, const H2645NAL *nal,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* do all the per-slice initialization needed before we can start decoding the
|
||||||
* Decode a slice header.
|
* actual MBs */
|
||||||
* This will (re)initialize the decoder and call h264_frame_start() as needed.
|
static int h264_slice_init(H264Context *h, H264SliceContext *sl,
|
||||||
*
|
const H2645NAL *nal)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
int i, j, ret = 0;
|
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->current_slice > 0) {
|
||||||
if (h->ps.pps != (const PPS*)h->ps.pps_list[sl->pps_id]->data) {
|
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");
|
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;
|
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)
|
int ff_h264_get_slice_type(const H264SliceContext *sl)
|
||||||
{
|
{
|
||||||
switch (sl->slice_type) {
|
switch (sl->slice_type) {
|
||||||
@ -2452,25 +2484,26 @@ finish:
|
|||||||
* Call decode_slice() for each context.
|
* Call decode_slice() for each context.
|
||||||
*
|
*
|
||||||
* @param h h264 master 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;
|
AVCodecContext *const avctx = h->avctx;
|
||||||
H264SliceContext *sl;
|
H264SliceContext *sl;
|
||||||
|
int context_count = h->nb_slice_ctx_queued;
|
||||||
|
int ret = 0;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if (h->avctx->hwaccel)
|
if (h->avctx->hwaccel || context_count < 1)
|
||||||
return 0;
|
return 0;
|
||||||
if (context_count == 1) {
|
if (context_count == 1) {
|
||||||
int ret;
|
|
||||||
|
|
||||||
h->slice_ctx[0].next_slice_idx = h->mb_width * h->mb_height;
|
h->slice_ctx[0].next_slice_idx = h->mb_width * h->mb_height;
|
||||||
h->postpone_filter = 0;
|
h->postpone_filter = 0;
|
||||||
|
|
||||||
ret = decode_slice(avctx, &h->slice_ctx[0]);
|
ret = decode_slice(avctx, &h->slice_ctx[0]);
|
||||||
h->mb_y = h->slice_ctx[0].mb_y;
|
h->mb_y = h->slice_ctx[0].mb_y;
|
||||||
return ret;
|
if (ret < 0)
|
||||||
|
goto finish;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < context_count; i++) {
|
for (i = 0; i < context_count; i++) {
|
||||||
int next_slice_idx = h->mb_width * h->mb_height;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
AVCodecContext *const avctx = h->avctx;
|
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 nals_needed = 0; ///< number of NALs that need decoding before the next frame thread starts
|
||||||
int i, ret = 0;
|
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++) {
|
for (i = 0; i < h->pkt.nb_nals; i++) {
|
||||||
H2645NAL *nal = &h->pkt.nals[i];
|
H2645NAL *nal = &h->pkt.nals[i];
|
||||||
H264SliceContext *sl = &h->slice_ctx[context_count];
|
int max_slice_ctx, err;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (avctx->skip_frame >= AVDISCARD_NONREF &&
|
if (avctx->skip_frame >= AVDISCARD_NONREF &&
|
||||||
nal->ref_idc == 0 && nal->type != H264_NAL_SEI)
|
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:
|
case H264_NAL_IDR_SLICE:
|
||||||
idr(h); // FIXME ensure we don't lose some frames if there is reordering
|
idr(h); // FIXME ensure we don't lose some frames if there is reordering
|
||||||
case H264_NAL_SLICE:
|
case H264_NAL_SLICE:
|
||||||
sl->gb = nal->gb;
|
if ((err = ff_h264_queue_decode_slice(h, nal)))
|
||||||
|
|
||||||
if ((err = ff_h264_decode_slice_header(h, sl, nal)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (sl->redundant_pic_count > 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (avctx->active_thread_type & FF_THREAD_FRAME && !h->avctx->hwaccel &&
|
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;
|
h->setup_finished = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((avctx->skip_frame < AVDISCARD_NONREF || nal->ref_idc) &&
|
max_slice_ctx = avctx->hwaccel ? 1 : h->nb_slice_ctx;
|
||||||
(avctx->skip_frame < AVDISCARD_BIDIR ||
|
if (h->nb_slice_ctx_queued == max_slice_ctx) {
|
||||||
sl->slice_type_nos != AV_PICTURE_TYPE_B) &&
|
if (avctx->hwaccel)
|
||||||
(avctx->skip_frame < AVDISCARD_NONKEY ||
|
|
||||||
h->cur_pic_ptr->f->key_frame) &&
|
|
||||||
avctx->skip_frame < AVDISCARD_ALL) {
|
|
||||||
if (avctx->hwaccel) {
|
|
||||||
ret = avctx->hwaccel->decode_slice(avctx, nal->raw_data, nal->raw_size);
|
ret = avctx->hwaccel->decode_slice(avctx, nal->raw_data, nal->raw_size);
|
||||||
if (ret < 0)
|
else
|
||||||
return ret;
|
ret = ff_h264_execute_decode_slices(h);
|
||||||
} else
|
if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))
|
||||||
context_count++;
|
goto end;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case H264_NAL_DPA:
|
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);
|
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) {
|
if (err < 0) {
|
||||||
av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n");
|
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);
|
ret = ff_h264_execute_decode_slices(h);
|
||||||
if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))
|
if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))
|
||||||
goto end;
|
goto end;
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
end:
|
end:
|
||||||
@ -687,6 +667,7 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data,
|
|||||||
|
|
||||||
h->flags = avctx->flags;
|
h->flags = avctx->flags;
|
||||||
h->setup_finished = 0;
|
h->setup_finished = 0;
|
||||||
|
h->nb_slice_ctx_queued = 0;
|
||||||
|
|
||||||
/* end of stream, output what is still in the buffers */
|
/* end of stream, output what is still in the buffers */
|
||||||
out:
|
out:
|
||||||
|
@ -345,6 +345,7 @@ typedef struct H264Context {
|
|||||||
|
|
||||||
H264SliceContext *slice_ctx;
|
H264SliceContext *slice_ctx;
|
||||||
int nb_slice_ctx;
|
int nb_slice_ctx;
|
||||||
|
int nb_slice_ctx_queued;
|
||||||
|
|
||||||
H2645Packet pkt;
|
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);
|
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);
|
* Submit a slice for decoding.
|
||||||
int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count);
|
*
|
||||||
|
* 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,
|
int ff_h264_update_thread_context(AVCodecContext *dst,
|
||||||
const AVCodecContext *src);
|
const AVCodecContext *src);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user