1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-11-21 10:55:51 +02:00

vaapi_encode_h265: Support more complex reference structures

The reference picture sets are now constructed directly from the DPB
information.
This commit is contained in:
Mark Thompson 2018-12-20 20:39:59 +00:00
parent 25c0ede93b
commit 362992e94b

View File

@ -42,6 +42,16 @@ enum {
SEI_CONTENT_LIGHT_LEVEL = 0x10,
};
typedef struct VAAPIEncodeH265Picture {
int pic_order_cnt;
int64_t last_idr_frame;
int slice_nal_unit;
int slice_type;
int pic_type;
} VAAPIEncodeH265Picture;
typedef struct VAAPIEncodeH265Context {
VAAPIEncodeContext common;
@ -58,14 +68,6 @@ typedef struct VAAPIEncodeH265Context {
int fixed_qp_p;
int fixed_qp_b;
// Stream state.
int64_t last_idr_frame;
int pic_order_cnt;
int slice_nal_unit;
int slice_type;
int pic_type;
// Writer structures.
H265RawAUD raw_aud;
H265RawVPS raw_vps;
@ -361,8 +363,8 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
}
vps->vps_sub_layer_ordering_info_present_flag = 0;
vps->vps_max_dec_pic_buffering_minus1[0] = (ctx->b_per_p > 0) + 1;
vps->vps_max_num_reorder_pics[0] = (ctx->b_per_p > 0);
vps->vps_max_dec_pic_buffering_minus1[0] = ctx->max_b_depth + 1;
vps->vps_max_num_reorder_pics[0] = ctx->max_b_depth;
vps->vps_max_latency_increase_plus1[0] = 0;
vps->vps_max_layer_id = 0;
@ -673,41 +675,54 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
VAAPIEncodePicture *pic)
{
VAAPIEncodeContext *ctx = avctx->priv_data;
VAAPIEncodeH265Context *priv = avctx->priv_data;
VAAPIEncodeH265Picture *hpic = pic->priv_data;
VAAPIEncodePicture *prev = pic->prev;
VAAPIEncodeH265Picture *hprev = prev ? prev->priv_data : NULL;
VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params;
int i;
if (pic->type == PICTURE_TYPE_IDR) {
av_assert0(pic->display_order == pic->encode_order);
priv->last_idr_frame = pic->display_order;
hpic->last_idr_frame = pic->display_order;
priv->slice_nal_unit = HEVC_NAL_IDR_W_RADL;
priv->slice_type = HEVC_SLICE_I;
priv->pic_type = 0;
hpic->slice_nal_unit = HEVC_NAL_IDR_W_RADL;
hpic->slice_type = HEVC_SLICE_I;
hpic->pic_type = 0;
} else {
av_assert0(pic->encode_order > priv->last_idr_frame);
av_assert0(prev);
hpic->last_idr_frame = hprev->last_idr_frame;
if (pic->type == PICTURE_TYPE_I) {
priv->slice_nal_unit = HEVC_NAL_CRA_NUT;
priv->slice_type = HEVC_SLICE_I;
priv->pic_type = 0;
hpic->slice_nal_unit = HEVC_NAL_CRA_NUT;
hpic->slice_type = HEVC_SLICE_I;
hpic->pic_type = 0;
} else if (pic->type == PICTURE_TYPE_P) {
av_assert0(pic->refs[0]);
priv->slice_nal_unit = HEVC_NAL_TRAIL_R;
priv->slice_type = HEVC_SLICE_P;
priv->pic_type = 1;
hpic->slice_nal_unit = HEVC_NAL_TRAIL_R;
hpic->slice_type = HEVC_SLICE_P;
hpic->pic_type = 1;
} else {
VAAPIEncodePicture *irap_ref;
av_assert0(pic->refs[0] && pic->refs[1]);
if (pic->refs[1]->type == PICTURE_TYPE_I)
priv->slice_nal_unit = HEVC_NAL_RASL_N;
else
priv->slice_nal_unit = HEVC_NAL_TRAIL_N;
priv->slice_type = HEVC_SLICE_B;
priv->pic_type = 2;
for (irap_ref = pic; irap_ref; irap_ref = irap_ref->refs[1]) {
if (irap_ref->type == PICTURE_TYPE_I)
break;
}
if (pic->b_depth == ctx->max_b_depth) {
hpic->slice_nal_unit = irap_ref ? HEVC_NAL_RASL_N
: HEVC_NAL_TRAIL_N;
} else {
hpic->slice_nal_unit = irap_ref ? HEVC_NAL_RASL_R
: HEVC_NAL_TRAIL_R;
}
hpic->slice_type = HEVC_SLICE_B;
hpic->pic_type = 2;
}
}
priv->pic_order_cnt = pic->display_order - priv->last_idr_frame;
hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame;
if (priv->aud) {
priv->aud_needed = 1;
@ -717,7 +732,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
.nuh_layer_id = 0,
.nuh_temporal_id_plus1 = 1,
},
.pic_type = priv->pic_type,
.pic_type = hpic->pic_type,
};
} else {
priv->aud_needed = 0;
@ -797,17 +812,20 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
vpic->decoded_curr_pic = (VAPictureHEVC) {
.picture_id = pic->recon_surface,
.pic_order_cnt = priv->pic_order_cnt,
.pic_order_cnt = hpic->pic_order_cnt,
.flags = 0,
};
for (i = 0; i < pic->nb_refs; i++) {
VAAPIEncodePicture *ref = pic->refs[i];
VAAPIEncodePicture *ref = pic->refs[i];
VAAPIEncodeH265Picture *href;
av_assert0(ref && ref->encode_order < pic->encode_order);
href = ref->priv_data;
vpic->reference_frames[i] = (VAPictureHEVC) {
.picture_id = ref->recon_surface,
.pic_order_cnt = ref->display_order - priv->last_idr_frame,
.pic_order_cnt = href->pic_order_cnt,
.flags = (ref->display_order < pic->display_order ?
VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) |
(ref->display_order > pic->display_order ?
@ -823,7 +841,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
vpic->coded_buf = pic->output_buffer;
vpic->nal_unit_type = priv->slice_nal_unit;
vpic->nal_unit_type = hpic->slice_nal_unit;
switch (pic->type) {
case PICTURE_TYPE_IDR:
@ -857,8 +875,8 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
VAAPIEncodePicture *pic,
VAAPIEncodeSlice *slice)
{
VAAPIEncodeContext *ctx = avctx->priv_data;
VAAPIEncodeH265Context *priv = avctx->priv_data;
VAAPIEncodeH265Picture *hpic = pic->priv_data;
const H265RawSPS *sps = &priv->raw_sps;
const H265RawPPS *pps = &priv->raw_pps;
H265RawSliceHeader *sh = &priv->raw_slice.header;
@ -867,7 +885,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
int i;
sh->nal_unit_header = (H265RawNALUnitHeader) {
.nal_unit_type = priv->slice_nal_unit,
.nal_unit_type = hpic->slice_nal_unit,
.nuh_layer_id = 0,
.nuh_temporal_id_plus1 = 1,
};
@ -877,64 +895,74 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
sh->first_slice_segment_in_pic_flag = slice->index == 0;
sh->slice_segment_address = slice->block_start;
sh->slice_type = priv->slice_type;
sh->slice_type = hpic->slice_type;
sh->slice_pic_order_cnt_lsb = priv->pic_order_cnt &
sh->slice_pic_order_cnt_lsb = hpic->pic_order_cnt &
(1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1;
if (pic->type != PICTURE_TYPE_IDR) {
H265RawSTRefPicSet *rps;
VAAPIEncodePicture *st;
int used;
int rps_poc[MAX_DPB_SIZE];
int rps_used[MAX_DPB_SIZE];
int i, j, poc, rps_pics;
sh->short_term_ref_pic_set_sps_flag = 0;
rps = &sh->short_term_ref_pic_set;
memset(rps, 0, sizeof(*rps));
for (st = ctx->pic_start; st; st = st->next) {
if (st->encode_order >= pic->encode_order) {
// Not yet in DPB.
rps_pics = 0;
for (i = 0; i < pic->nb_dpb_pics; i++) {
VAAPIEncodeH265Picture *strp;
if (pic->dpb[i] == pic)
continue;
strp = pic->dpb[i]->priv_data;
rps_poc[rps_pics] = strp->pic_order_cnt;
rps_used[rps_pics] = 0;
for (j = 0; j < pic->nb_refs; j++)
if (pic->dpb[i] == pic->refs[j])
rps_used[rps_pics] = 1;
++rps_pics;
}
for (i = 1; i < rps_pics; i++) {
for (j = i; j > 0; j--) {
if (rps_poc[j] > rps_poc[j - 1])
break;
av_assert0(rps_poc[j] != rps_poc[j - 1]);
FFSWAP(int, rps_poc[j], rps_poc[j - 1]);
FFSWAP(int, rps_used[j], rps_used[j - 1]);
}
used = 0;
for (i = 0; i < pic->nb_refs; i++) {
if (pic->refs[i] == st)
used = 1;
}
if (!used) {
// Usually each picture always uses all of the others in the
// DPB as references. The one case we have to treat here is
// a non-IDR IRAP picture, which may need to hold unused
// references across itself to be used for the decoding of
// following RASL pictures. This looks for such an RASL
// picture, and keeps the reference if there is one.
VAAPIEncodePicture *rp;
for (rp = ctx->pic_start; rp; rp = rp->next) {
if (rp->encode_order < pic->encode_order)
continue;
if (rp->type != PICTURE_TYPE_B)
continue;
if (rp->refs[0] == st && rp->refs[1] == pic)
break;
}
if (!rp)
continue;
}
// This only works for one instance of each (delta_poc_sN_minus1
// is relative to the previous frame in the list, not relative to
// the current frame directly).
if (st->display_order < pic->display_order) {
rps->delta_poc_s0_minus1[rps->num_negative_pics] =
pic->display_order - st->display_order - 1;
rps->used_by_curr_pic_s0_flag[rps->num_negative_pics] = used;
++rps->num_negative_pics;
} else {
rps->delta_poc_s1_minus1[rps->num_positive_pics] =
st->display_order - pic->display_order - 1;
rps->used_by_curr_pic_s1_flag[rps->num_positive_pics] = used;
++rps->num_positive_pics;
}
}
av_log(avctx, AV_LOG_DEBUG, "RPS for POC %d:",
hpic->pic_order_cnt);
for (i = 0; i < rps_pics; i++) {
av_log(avctx, AV_LOG_DEBUG, " (%d,%d)",
rps_poc[i], rps_used[i]);
}
av_log(avctx, AV_LOG_DEBUG, "\n");
for (i = 0; i < rps_pics; i++) {
av_assert0(rps_poc[i] != hpic->pic_order_cnt);
if (rps_poc[i] > hpic->pic_order_cnt)
break;
}
rps->num_negative_pics = i;
poc = hpic->pic_order_cnt;
for (j = i - 1; j >= 0; j--) {
rps->delta_poc_s0_minus1[i - 1 - j] = poc - rps_poc[j] - 1;
rps->used_by_curr_pic_s0_flag[i - 1 - j] = rps_used[j];
poc = rps_poc[j];
}
rps->num_positive_pics = rps_pics - i;
poc = hpic->pic_order_cnt;
for (j = i; j < rps_pics; j++) {
rps->delta_poc_s1_minus1[j - i] = rps_poc[j] - poc - 1;
rps->used_by_curr_pic_s1_flag[j - i] = rps_used[j];
poc = rps_poc[j];
}
sh->num_long_term_sps = 0;
@ -1084,10 +1112,13 @@ static const VAAPIEncodeType vaapi_encode_type_h265 = {
.flags = FLAG_SLICE_CONTROL |
FLAG_B_PICTURES |
FLAG_B_PICTURE_REFERENCES |
FLAG_NON_IDR_KEY_PICTURES,
.configure = &vaapi_encode_h265_configure,
.picture_priv_data_size = sizeof(VAAPIEncodeH265Picture),
.sequence_params_size = sizeof(VAEncSequenceParameterBufferHEVC),
.init_sequence_params = &vaapi_encode_h265_init_sequence_params,