[Libva] [PATCH] VP8 HWEnc: Add CBR Support
Zhong Li
zhong.li at intel.com
Wed Apr 22 00:47:34 PDT 2015
Signed-off-by: Zhong Li <zhong.li at intel.com>
---
src/gen6_mfc.h | 19 +++
src/gen6_mfc_common.c | 19 ---
src/gen8_mfc.c | 382 ++++++++++++++++++++++++++++++++++++++++++++++-
src/i965_drv_video.c | 1 +
src/i965_encoder_utils.c | 14 +-
src/vp8_probs.h | 48 ++++++
6 files changed, 455 insertions(+), 28 deletions(-)
diff --git a/src/gen6_mfc.h b/src/gen6_mfc.h
index b134da8..087c676 100644
--- a/src/gen6_mfc.h
+++ b/src/gen6_mfc.h
@@ -62,6 +62,25 @@ struct encode_state;
#define CMD_LEN_IN_OWORD 4
+#define BRC_CLIP(x, min, max) \
+ { \
+ x = ((x > (max)) ? (max) : ((x < (min)) ? (min) : x)); \
+ }
+
+#define BRC_P_B_QP_DIFF 4
+#define BRC_I_P_QP_DIFF 2
+#define BRC_I_B_QP_DIFF (BRC_I_P_QP_DIFF + BRC_P_B_QP_DIFF)
+
+#define BRC_PWEIGHT 0.6 /* weight if P slice with comparison to I slice */
+#define BRC_BWEIGHT 0.25 /* weight if B slice with comparison to I slice */
+
+#define BRC_QP_MAX_CHANGE 5 /* maximum qp modification */
+#define BRC_CY 0.1 /* weight for */
+#define BRC_CX_UNDERFLOW 5.
+#define BRC_CX_OVERFLOW -4.
+
+#define BRC_PI_0_5 1.5707963267948966192313216916398
+
typedef enum {
VME_V_PRED = 0,
VME_H_PRED = 1,
diff --git a/src/gen6_mfc_common.c b/src/gen6_mfc_common.c
index 2dc6ccf..9c1d294 100644
--- a/src/gen6_mfc_common.c
+++ b/src/gen6_mfc_common.c
@@ -43,25 +43,6 @@
#include "gen6_vme.h"
#include "intel_media.h"
-#define BRC_CLIP(x, min, max) \
- { \
- x = ((x > (max)) ? (max) : ((x < (min)) ? (min) : x)); \
- }
-
-#define BRC_P_B_QP_DIFF 4
-#define BRC_I_P_QP_DIFF 2
-#define BRC_I_B_QP_DIFF (BRC_I_P_QP_DIFF + BRC_P_B_QP_DIFF)
-
-#define BRC_PWEIGHT 0.6 /* weight if P slice with comparison to I slice */
-#define BRC_BWEIGHT 0.25 /* weight if B slice with comparison to I slice */
-
-#define BRC_QP_MAX_CHANGE 5 /* maximum qp modification */
-#define BRC_CY 0.1 /* weight for */
-#define BRC_CX_UNDERFLOW 5.
-#define BRC_CX_OVERFLOW -4.
-
-#define BRC_PI_0_5 1.5707963267948966192313216916398
-
#ifndef HAVE_LOG2F
#define log2f(x) (logf(x)/(float)M_LN2)
#endif
diff --git a/src/gen8_mfc.c b/src/gen8_mfc.c
index c1394eb..046986c 100644
--- a/src/gen8_mfc.c
+++ b/src/gen8_mfc.c
@@ -3216,6 +3216,345 @@ gen8_mfc_jpeg_encode_picture(VADriverContextP ctx,
return VA_STATUS_SUCCESS;
}
+static int gen8_mfc_vp8_qindex_estimate(struct encode_state *encode_state,
+ struct gen6_mfc_context *mfc_context,
+ int target_frame_size,
+ int is_key_frame)
+{
+ VAEncSequenceParameterBufferVP8 *pSequenceParameter = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
+ VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
+ unsigned int max_qindex = pic_param->clamp_qindex_high;
+ unsigned int min_qindex = pic_param->clamp_qindex_low;
+ int width_in_mbs = ALIGN(pSequenceParameter->frame_width, 16) / 16;
+ int height_in_mbs = ALIGN(pSequenceParameter->frame_height, 16) / 16;
+ int target_mb_size;
+ unsigned int last_size_gap = 0x7fffffff;
+ int per_mb_size_at_qindex;
+ int target_qindex = min_qindex, i;
+
+ /* make sure would not overflow*/
+ if (target_frame_size >= (0x7fffffff >> 9))
+ target_mb_size = (target_frame_size / width_in_mbs / height_in_mbs) << 9;
+ else
+ target_mb_size = (target_frame_size << 9) / width_in_mbs / height_in_mbs;
+
+ for (i = min_qindex; i <= max_qindex; i++) {
+ per_mb_size_at_qindex = vp8_bits_per_mb[!is_key_frame][i];
+ target_qindex = i;
+ if (per_mb_size_at_qindex <= target_mb_size) {
+ if (target_mb_size - per_mb_size_at_qindex < last_size_gap)
+ target_qindex--;
+ break;
+ }
+ else
+ last_size_gap = per_mb_size_at_qindex - target_mb_size;
+ }
+
+ return target_qindex;
+}
+
+static void
+gen8_mfc_vp8_bit_rate_control_context_init(struct encode_state *encode_state,
+ struct gen6_mfc_context *mfc_context)
+{
+ VAEncSequenceParameterBufferVP8 *pSequenceParameter = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
+ VAEncMiscParameterBuffer* pMiscParamFrameRateBuffer = (VAEncMiscParameterBuffer*)encode_state->misc_param[VAEncMiscParameterTypeFrameRate]->buffer;
+ VAEncMiscParameterFrameRate* pParameterFrameRate = (VAEncMiscParameterFrameRate*)pMiscParamFrameRateBuffer->data;
+ int width_in_mbs = ALIGN(pSequenceParameter->frame_width, 16) / 16;
+ int height_in_mbs = ALIGN(pSequenceParameter->frame_height, 16) / 16;
+ float fps = pParameterFrameRate->framerate;
+ int inter_mb_size = pSequenceParameter->bits_per_second * 1.0 / (fps+4.0) / width_in_mbs / height_in_mbs;
+ int intra_mb_size = inter_mb_size * 5.0;
+ int i;
+
+ mfc_context->bit_rate_control_context[SLICE_TYPE_I].target_mb_size = intra_mb_size;
+ mfc_context->bit_rate_control_context[SLICE_TYPE_I].target_frame_size = intra_mb_size * width_in_mbs * height_in_mbs;
+ mfc_context->bit_rate_control_context[SLICE_TYPE_P].target_mb_size = inter_mb_size;
+ mfc_context->bit_rate_control_context[SLICE_TYPE_P].target_frame_size = inter_mb_size * width_in_mbs * height_in_mbs;
+
+ for(i = 0 ; i < 2; i++) {
+ mfc_context->bit_rate_control_context[i].QpPrimeY = 26;
+ mfc_context->bit_rate_control_context[i].MaxQpNegModifier = 6;
+ mfc_context->bit_rate_control_context[i].MaxQpPosModifier = 6;
+ mfc_context->bit_rate_control_context[i].GrowInit = 6;
+ mfc_context->bit_rate_control_context[i].GrowResistance = 4;
+ mfc_context->bit_rate_control_context[i].ShrinkInit = 6;
+ mfc_context->bit_rate_control_context[i].ShrinkResistance = 4;
+
+ mfc_context->bit_rate_control_context[i].Correct[0] = 8;
+ mfc_context->bit_rate_control_context[i].Correct[1] = 4;
+ mfc_context->bit_rate_control_context[i].Correct[2] = 2;
+ mfc_context->bit_rate_control_context[i].Correct[3] = 2;
+ mfc_context->bit_rate_control_context[i].Correct[4] = 4;
+ mfc_context->bit_rate_control_context[i].Correct[5] = 8;
+ }
+
+ mfc_context->bit_rate_control_context[SLICE_TYPE_I].TargetSizeInWord = (intra_mb_size + 16)/ 16;
+ mfc_context->bit_rate_control_context[SLICE_TYPE_P].TargetSizeInWord = (inter_mb_size + 16)/ 16;
+
+ mfc_context->bit_rate_control_context[SLICE_TYPE_I].MaxSizeInWord = mfc_context->bit_rate_control_context[SLICE_TYPE_I].TargetSizeInWord * 1.5;
+ mfc_context->bit_rate_control_context[SLICE_TYPE_P].MaxSizeInWord = mfc_context->bit_rate_control_context[SLICE_TYPE_P].TargetSizeInWord * 1.5;
+}
+
+static void gen8_mfc_vp8_brc_init(struct encode_state *encode_state,
+ struct intel_encoder_context* encoder_context)
+{
+ struct gen6_mfc_context *mfc_context = encoder_context->mfc_context;
+ VAEncSequenceParameterBufferVP8 *pSequenceParameter = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
+ VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
+ VAEncMiscParameterBuffer* pMiscParamHRD = (VAEncMiscParameterBuffer*)encode_state->misc_param[VAEncMiscParameterTypeHRD]->buffer;
+ VAEncMiscParameterHRD* pParameterHRD = (VAEncMiscParameterHRD*)pMiscParamHRD->data;
+ VAEncMiscParameterBuffer* pMiscParamFrameRateBuffer = (VAEncMiscParameterBuffer*)encode_state->misc_param[VAEncMiscParameterTypeFrameRate]->buffer;
+ VAEncMiscParameterFrameRate* pParameterFrameRate = (VAEncMiscParameterFrameRate*)pMiscParamFrameRateBuffer->data;
+ double bitrate = pSequenceParameter->bits_per_second;
+ unsigned int framerate = pParameterFrameRate->framerate;
+ int inum = 1, pnum = 0;
+ int intra_period = pSequenceParameter->intra_period;
+ int is_key_frame = !pic_param->pic_flags.bits.frame_type;
+ int width_in_mbs = ALIGN(pSequenceParameter->frame_width, 16) / 16;
+ int height_in_mbs = ALIGN(pSequenceParameter->frame_height, 16) / 16;
+ int max_frame_size = (vp8_bits_per_mb[0][0] >> 9) * width_in_mbs * height_in_mbs;/* vp8_bits_per_mb table mutilpled 512 */
+
+ pnum = intra_period - 1;
+
+ mfc_context->brc.mode = encoder_context->rate_control_mode;
+
+ mfc_context->brc.target_frame_size[SLICE_TYPE_I] = (int)((double)((bitrate * intra_period)/framerate) /
+ (double)(inum + BRC_PWEIGHT * pnum ));
+ mfc_context->brc.target_frame_size[SLICE_TYPE_P] = BRC_PWEIGHT * mfc_context->brc.target_frame_size[SLICE_TYPE_I];
+
+ mfc_context->brc.gop_nums[SLICE_TYPE_I] = inum;
+ mfc_context->brc.gop_nums[SLICE_TYPE_P] = pnum;
+
+ mfc_context->brc.bits_per_frame = bitrate/framerate;
+
+ mfc_context->bit_rate_control_context[SLICE_TYPE_I].QpPrimeY = gen8_mfc_vp8_qindex_estimate(encode_state,
+ mfc_context,
+ mfc_context->brc.target_frame_size[SLICE_TYPE_I],
+ 1);
+ mfc_context->bit_rate_control_context[SLICE_TYPE_P].QpPrimeY = gen8_mfc_vp8_qindex_estimate(encode_state,
+ mfc_context,
+ mfc_context->brc.target_frame_size[SLICE_TYPE_P],
+ 0);
+
+ mfc_context->hrd.buffer_size = (double)pParameterHRD->buffer_size;
+ mfc_context->hrd.current_buffer_fullness =
+ (double)(pParameterHRD->initial_buffer_fullness < mfc_context->hrd.buffer_size)?
+ pParameterHRD->initial_buffer_fullness: mfc_context->hrd.buffer_size/2.;
+ mfc_context->hrd.target_buffer_fullness = (double)mfc_context->hrd.buffer_size/2.;
+ mfc_context->hrd.buffer_capacity = (double)mfc_context->hrd.buffer_size/max_frame_size;
+ mfc_context->hrd.violation_noted = 0;
+}
+
+static int gen8_mfc_vp8_brc_postpack(struct encode_state *encode_state,
+ struct gen6_mfc_context *mfc_context,
+ int frame_bits)
+{
+ gen6_brc_status sts = BRC_NO_HRD_VIOLATION;
+ VAEncSequenceParameterBufferVP8 *pSequenceParameter = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
+ VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
+ int is_key_frame = !pic_param->pic_flags.bits.frame_type;
+ int slicetype = (is_key_frame ? SLICE_TYPE_I : SLICE_TYPE_P);
+ int qpi = mfc_context->bit_rate_control_context[SLICE_TYPE_I].QpPrimeY;
+ int qpp = mfc_context->bit_rate_control_context[SLICE_TYPE_P].QpPrimeY;
+ int qp; // quantizer of previously encoded slice of current type
+ int qpn; // predicted quantizer for next frame of current type in integer format
+ double qpf; // predicted quantizer for next frame of current type in float format
+ double delta_qp; // QP correction
+ int target_frame_size, frame_size_next;
+ /* Notes:
+ * x - how far we are from HRD buffer borders
+ * y - how far we are from target HRD buffer fullness
+ */
+ double x, y;
+ double frame_size_alpha;
+ unsigned int max_qindex = pic_param->clamp_qindex_high;
+ unsigned int min_qindex = pic_param->clamp_qindex_low;
+
+ qp = mfc_context->bit_rate_control_context[slicetype].QpPrimeY;
+
+ target_frame_size = mfc_context->brc.target_frame_size[slicetype];
+ if (mfc_context->hrd.buffer_capacity < 5)
+ frame_size_alpha = 0;
+ else
+ frame_size_alpha = (double)mfc_context->brc.gop_nums[slicetype];
+ if (frame_size_alpha > 30) frame_size_alpha = 30;
+ frame_size_next = target_frame_size + (double)(target_frame_size - frame_bits) /
+ (double)(frame_size_alpha + 1.);
+
+ /* frame_size_next: avoiding negative number and too small value */
+ if ((double)frame_size_next < (double)(target_frame_size * 0.25))
+ frame_size_next = (int)((double)target_frame_size * 0.25);
+
+ qpf = (double)qp * target_frame_size / frame_size_next;
+ qpn = (int)(qpf + 0.5);
+
+ if (qpn == qp) {
+ /* setting qpn we round qpf making mistakes: now we are trying to compensate this */
+ mfc_context->brc.qpf_rounding_accumulator += qpf - qpn;
+ if (mfc_context->brc.qpf_rounding_accumulator > 1.0) {
+ qpn++;
+ mfc_context->brc.qpf_rounding_accumulator = 0.;
+ } else if (mfc_context->brc.qpf_rounding_accumulator < -1.0) {
+ qpn--;
+ mfc_context->brc.qpf_rounding_accumulator = 0.;
+ }
+ }
+
+ /* making sure that QP is not changing too fast */
+ if ((qpn - qp) > BRC_QP_MAX_CHANGE) qpn = qp + BRC_QP_MAX_CHANGE;
+ else if ((qpn - qp) < -BRC_QP_MAX_CHANGE) qpn = qp - BRC_QP_MAX_CHANGE;
+ /* making sure that with QP predictions we did do not leave QPs range */
+ BRC_CLIP(qpn, min_qindex, max_qindex);
+
+ /* checking wthether HRD compliance is still met */
+ sts = intel_mfc_update_hrd(encode_state, mfc_context, frame_bits);
+
+ /* calculating QP delta as some function*/
+ x = mfc_context->hrd.target_buffer_fullness - mfc_context->hrd.current_buffer_fullness;
+ if (x > 0) {
+ x /= mfc_context->hrd.target_buffer_fullness;
+ y = mfc_context->hrd.current_buffer_fullness;
+ }
+ else {
+ x /= (mfc_context->hrd.buffer_size - mfc_context->hrd.target_buffer_fullness);
+ y = mfc_context->hrd.buffer_size - mfc_context->hrd.current_buffer_fullness;
+ }
+ if (y < 0.01) y = 0.01;
+ if (x > 1) x = 1;
+ else if (x < -1) x = -1;
+
+ delta_qp = BRC_QP_MAX_CHANGE*exp(-1/y)*sin(BRC_PI_0_5 * x);
+ qpn = (int)(qpn + delta_qp + 0.5);
+
+ /* making sure that with QP predictions we did do not leave QPs range */
+ BRC_CLIP(qpn, min_qindex, max_qindex);
+
+ if (sts == BRC_NO_HRD_VIOLATION) { // no HRD violation
+ /* correcting QPs of slices of other types */
+ if (!is_key_frame) {
+ if (abs(qpn - BRC_I_P_QP_DIFF - qpi) > 4)
+ mfc_context->bit_rate_control_context[SLICE_TYPE_I].QpPrimeY += (qpn - BRC_I_P_QP_DIFF - qpi) >> 2;
+ } else {
+ if (abs(qpn + BRC_I_P_QP_DIFF - qpp) > 4)
+ mfc_context->bit_rate_control_context[SLICE_TYPE_P].QpPrimeY += (qpn + BRC_I_P_QP_DIFF - qpp) >> 2;
+ }
+ BRC_CLIP(mfc_context->bit_rate_control_context[SLICE_TYPE_I].QpPrimeY, min_qindex, max_qindex);
+ BRC_CLIP(mfc_context->bit_rate_control_context[SLICE_TYPE_P].QpPrimeY, min_qindex, max_qindex);
+ } else if (sts == BRC_UNDERFLOW) { // underflow
+ if (qpn <= qp) qpn = qp + 2;
+ if (qpn > max_qindex) {
+ qpn = max_qindex;
+ sts = BRC_UNDERFLOW_WITH_MAX_QP; //underflow with maxQP
+ }
+ } else if (sts == BRC_OVERFLOW) {
+ if (qpn >= qp) qpn = qp - 2;
+ if (qpn < min_qindex) { // < 0 (?) overflow with minQP
+ qpn = min_qindex;
+ sts = BRC_OVERFLOW_WITH_MIN_QP; // bit stuffing to be done
+ }
+ }
+
+ mfc_context->bit_rate_control_context[slicetype].QpPrimeY = qpn;
+
+ return sts;
+}
+
+static void gen8_mfc_vp8_hrd_context_init(struct encode_state *encode_state,
+ struct intel_encoder_context *encoder_context)
+{
+ struct gen6_mfc_context *mfc_context = encoder_context->mfc_context;
+ VAEncSequenceParameterBufferVP8 *pSequenceParameter = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
+ unsigned int rate_control_mode = encoder_context->rate_control_mode;
+ int target_bit_rate = pSequenceParameter->bits_per_second;
+
+ // current we only support CBR mode.
+ if (rate_control_mode == VA_RC_CBR) {
+ mfc_context->vui_hrd.i_bit_rate_value = target_bit_rate >> 10;
+ mfc_context->vui_hrd.i_cpb_size_value = (target_bit_rate * 8) >> 10;
+ mfc_context->vui_hrd.i_initial_cpb_removal_delay = mfc_context->vui_hrd.i_cpb_size_value * 0.5 * 1024 / target_bit_rate * 90000;
+ mfc_context->vui_hrd.i_cpb_removal_delay = 2;
+ mfc_context->vui_hrd.i_frame_number = 0;
+
+ mfc_context->vui_hrd.i_initial_cpb_removal_delay_length = 24;
+ mfc_context->vui_hrd.i_cpb_removal_delay_length = 24;
+ mfc_context->vui_hrd.i_dpb_output_delay_length = 24;
+ }
+
+}
+
+static void gen8_mfc_vp8_hrd_context_update(struct encode_state *encode_state,
+ struct gen6_mfc_context *mfc_context)
+{
+ mfc_context->vui_hrd.i_frame_number++;
+}
+
+/*
+ * Check whether the parameters related with CBR are updated and decide whether
+ * it needs to reinitialize the configuration related with CBR.
+ * Currently it will check the following parameters:
+ * bits_per_second
+ * frame_rate
+ * gop_configuration(intra_period, ip_period, intra_idr_period)
+ */
+static bool gen8_mfc_vp8_brc_updated_check(struct encode_state *encode_state,
+ struct intel_encoder_context *encoder_context)
+{
+ unsigned int rate_control_mode = encoder_context->rate_control_mode;
+ struct gen6_mfc_context *mfc_context = encoder_context->mfc_context;
+ double cur_fps, cur_bitrate;
+ VAEncSequenceParameterBufferVP8 *pSequenceParameter;
+ VAEncMiscParameterBuffer* pMiscParamFrameRateBuffer = (VAEncMiscParameterBuffer*)encode_state->misc_param[VAEncMiscParameterTypeFrameRate]->buffer;
+ VAEncMiscParameterFrameRate* pParameterFrameRate = (VAEncMiscParameterFrameRate*)pMiscParamFrameRateBuffer->data;
+ unsigned int framerate = pParameterFrameRate->framerate;
+
+ if (rate_control_mode != VA_RC_CBR) {
+ return false;
+ }
+
+ pSequenceParameter = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
+
+ cur_bitrate = pSequenceParameter->bits_per_second;
+ cur_fps = framerate;
+
+ if ((cur_bitrate == mfc_context->brc.saved_bps) &&
+ (cur_fps == mfc_context->brc.saved_fps) &&
+ (pSequenceParameter->intra_period == mfc_context->brc.saved_intra_period)) {
+ /* the parameters related with CBR are not updaetd */
+ return false;
+ }
+
+ mfc_context->brc.saved_intra_period = pSequenceParameter->intra_period;
+ mfc_context->brc.saved_fps = cur_fps;
+ mfc_context->brc.saved_bps = cur_bitrate;
+ return true;
+}
+
+static void gen8_mfc_vp8_brc_prepare(struct encode_state *encode_state,
+ struct intel_encoder_context *encoder_context)
+{
+ unsigned int rate_control_mode = encoder_context->rate_control_mode;
+ struct gen6_mfc_context *mfc_context = encoder_context->mfc_context;
+
+ if (rate_control_mode == VA_RC_CBR) {
+ bool brc_updated;
+ assert(encoder_context->codec != CODEC_MPEG2);
+
+ brc_updated = gen8_mfc_vp8_brc_updated_check(encode_state, encoder_context);
+
+ /*Programing bit rate control */
+ if ((mfc_context->bit_rate_control_context[SLICE_TYPE_I].MaxSizeInWord == 0) ||
+ brc_updated) {
+ gen8_mfc_vp8_bit_rate_control_context_init(encode_state, mfc_context);
+ gen8_mfc_vp8_brc_init(encode_state, encoder_context);
+ }
+
+ /*Programing HRD control */
+ if ((mfc_context->vui_hrd.i_cpb_size_value == 0) || brc_updated )
+ gen8_mfc_vp8_hrd_context_init(encode_state, encoder_context);
+ }
+}
+
static void vp8_enc_state_init(struct gen6_mfc_context *mfc_context,
VAEncPictureParameterBufferVP8 *pic_param,
VAQMatrixBufferVP8 *q_matrix)
@@ -3268,9 +3607,11 @@ static void vp8_enc_state_update(struct gen6_mfc_context *mfc_context,
extern void binarize_vp8_frame_header(VAEncSequenceParameterBufferVP8 *seq_param,
VAEncPictureParameterBufferVP8 *pic_param,
VAQMatrixBufferVP8 *q_matrix,
- struct gen6_mfc_context *mfc_context);
+ struct gen6_mfc_context *mfc_context,
+ struct intel_encoder_context *encoder_context);
-static void vp8_enc_frame_header_binarize(struct encode_state *encode_state,
+static void vp8_enc_frame_header_binarize(struct encode_state *encode_state,
+ struct intel_encoder_context *encoder_context,
struct gen6_mfc_context *mfc_context)
{
VAEncSequenceParameterBufferVP8 *seq_param = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
@@ -3278,7 +3619,7 @@ static void vp8_enc_frame_header_binarize(struct encode_state *encode_state,
VAQMatrixBufferVP8 *q_matrix = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;
unsigned char *frame_header_buffer;
- binarize_vp8_frame_header(seq_param, pic_param, q_matrix, mfc_context);
+ binarize_vp8_frame_header(seq_param, pic_param, q_matrix, mfc_context, encoder_context);
dri_bo_map(mfc_context->vp8_state.frame_header_bo, 1);
frame_header_buffer = (unsigned char *)mfc_context->vp8_state.frame_header_bo->virtual;
@@ -3441,7 +3782,7 @@ static void gen8_mfc_vp8_init(VADriverContextP ctx,
mfc_context->vp8_state.mpc_row_store_bo = bo;
vp8_enc_state_init(mfc_context, pic_param, q_matrix);
- vp8_enc_frame_header_binarize(encode_state, mfc_context);
+ vp8_enc_frame_header_binarize(encode_state, encoder_context, mfc_context);
}
static VAStatus
@@ -3610,7 +3951,7 @@ gen8_mfc_vp8_pic_state(VADriverContextP ctx,
/*update mode and token probs*/
vp8_enc_state_update(mfc_context, q_matrix);
-
+
BEGIN_BCS_BATCH(batch, 38);
OUT_BCS_BATCH(batch, MFX_VP8_PIC_STATE | (38 - 2));
OUT_BCS_BATCH(batch,
@@ -4039,7 +4380,7 @@ gen8_mfc_vp8_pipeline_programing(VADriverContextP ctx,
dri_bo_unreference(slice_batch_bo);
}
-static void gen8_mfc_calc_vp8_coded_buffer_size(VADriverContextP ctx,
+static int gen8_mfc_calc_vp8_coded_buffer_size(VADriverContextP ctx,
struct encode_state *encode_state,
struct intel_encoder_context *encoder_context)
{
@@ -4071,6 +4412,8 @@ static void gen8_mfc_calc_vp8_coded_buffer_size(VADriverContextP ctx,
struct i965_coded_buffer_segment *coded_buffer_segment = (struct i965_coded_buffer_segment *)(mfc_context->vp8_state.final_frame_bo->virtual);
coded_buffer_segment->base.size = vp8_coded_bytes;
dri_bo_unmap(mfc_context->vp8_state.final_frame_bo);
+
+ return vp8_coded_bytes;
}
static VAStatus
@@ -4078,12 +4421,31 @@ gen8_mfc_vp8_encode_picture(VADriverContextP ctx,
struct encode_state *encode_state,
struct intel_encoder_context *encoder_context)
{
+ struct gen6_mfc_context *mfc_context = encoder_context->mfc_context;
+ unsigned int rate_control_mode = encoder_context->rate_control_mode;
+ int current_frame_bits_size;
+ int sts;
+
gen8_mfc_vp8_init(ctx, encode_state, encoder_context);
intel_mfc_vp8_prepare(ctx, encode_state, encoder_context);
/*Programing bcs pipeline*/
gen8_mfc_vp8_pipeline_programing(ctx, encode_state, encoder_context);
gen8_mfc_run(ctx, encode_state, encoder_context);
- gen8_mfc_calc_vp8_coded_buffer_size(ctx, encode_state, encoder_context);
+ current_frame_bits_size = 8 * gen8_mfc_calc_vp8_coded_buffer_size(ctx, encode_state, encoder_context);
+
+ if (rate_control_mode == VA_RC_CBR /*|| rate_control_mode == VA_RC_VBR*/) {
+ sts = gen8_mfc_vp8_brc_postpack(encode_state, mfc_context, current_frame_bits_size);
+ if (sts == BRC_NO_HRD_VIOLATION) {
+ gen8_mfc_vp8_hrd_context_update(encode_state, mfc_context);
+ }
+ else if (sts == BRC_OVERFLOW_WITH_MIN_QP || sts == BRC_UNDERFLOW_WITH_MAX_QP) {
+ if (!mfc_context->hrd.violation_noted) {
+ fprintf(stderr, "Unrepairable %s!\n", (sts == BRC_OVERFLOW_WITH_MIN_QP)? "overflow": "underflow");
+ mfc_context->hrd.violation_noted = 1;
+ }
+ return VA_STATUS_SUCCESS;
+ }
+ }
return VA_STATUS_SUCCESS;
}
@@ -4239,7 +4601,11 @@ Bool gen8_mfc_context_init(VADriverContextP ctx, struct intel_encoder_context *e
encoder_context->mfc_context = mfc_context;
encoder_context->mfc_context_destroy = gen8_mfc_context_destroy;
encoder_context->mfc_pipeline = gen8_mfc_pipeline;
- encoder_context->mfc_brc_prepare = intel_mfc_brc_prepare;
+
+ if (encoder_context->codec == CODEC_VP8)
+ encoder_context->mfc_brc_prepare = gen8_mfc_vp8_brc_prepare;
+ else
+ encoder_context->mfc_brc_prepare = intel_mfc_brc_prepare;
return True;
}
diff --git a/src/i965_drv_video.c b/src/i965_drv_video.c
index d87a232..00fb95d 100644
--- a/src/i965_drv_video.c
+++ b/src/i965_drv_video.c
@@ -2025,6 +2025,7 @@ i965_create_buffer_internal(VADriverContextP ctx,
case VAProcFilterParameterBufferType:
case VAHuffmanTableBufferType:
case VAProbabilityBufferType:
+ case VAEncMacroblockMapBufferType:
/* Ok */
break;
diff --git a/src/i965_encoder_utils.c b/src/i965_encoder_utils.c
index cfa3b9d..b2c6ad2 100644
--- a/src/i965_encoder_utils.c
+++ b/src/i965_encoder_utils.c
@@ -595,12 +595,24 @@ static void binarize_qindex_delta(avc_bitstream *bs, int qindex_delta)
void binarize_vp8_frame_header(VAEncSequenceParameterBufferVP8 *seq_param,
VAEncPictureParameterBufferVP8 *pic_param,
VAQMatrixBufferVP8 *q_matrix,
- struct gen6_mfc_context *mfc_context)
+ struct gen6_mfc_context *mfc_context,
+ struct intel_encoder_context *encoder_context)
{
avc_bitstream bs;
int i, j;
int is_intra_frame = !pic_param->pic_flags.bits.frame_type;
int log2num = pic_param->pic_flags.bits.num_token_partitions;
+ int is_key_frame = !pic_param->pic_flags.bits.frame_type;
+ int slice_type = (is_key_frame ? SLICE_TYPE_I : SLICE_TYPE_P);
+ unsigned int rate_control_mode = encoder_context->rate_control_mode;
+
+ if (rate_control_mode == VA_RC_CBR) {
+ q_matrix->quantization_index[0] = mfc_context->bit_rate_control_context[slice_type].QpPrimeY;
+ for (i = 1; i < 4; i++)
+ q_matrix->quantization_index[i] = q_matrix->quantization_index[0];
+ for (i = 0; i < 5; i++)
+ q_matrix->quantization_index_delta[i] = 0;
+ }
/* modify picture paramters */
pic_param->pic_flags.bits.loop_filter_adj_enable = 1;
diff --git a/src/vp8_probs.h b/src/vp8_probs.h
index e864b68..0206699 100644
--- a/src/vp8_probs.h
+++ b/src/vp8_probs.h
@@ -288,4 +288,52 @@ static const unsigned char vp8_default_coef_probs[4][8][3][11] =
}
};
+/* Work in progress recalibration of baseline rate tables based on
+ * the assumption that bits per mb is inversely proportional to the
+ * quantizer value.
+ * Note: this table value multiplied by 512
+ */
+static const int vp8_bits_per_mb[2][128] =
+{
+ /* Intra case 450000/Qintra */
+ {
+ 1125000,900000, 750000, 642857, 562500, 500000, 450000, 450000,
+ 409090, 375000, 346153, 321428, 300000, 281250, 264705, 264705,
+ 250000, 236842, 225000, 225000, 214285, 214285, 204545, 204545,
+ 195652, 195652, 187500, 180000, 180000, 173076, 166666, 160714,
+ 155172, 150000, 145161, 140625, 136363, 132352, 128571, 125000,
+ 121621, 121621, 118421, 115384, 112500, 109756, 107142, 104651,
+ 102272, 100000, 97826, 97826, 95744, 93750, 91836, 90000,
+ 88235, 86538, 84905, 83333, 81818, 80357, 78947, 77586,
+ 76271, 75000, 73770, 72580, 71428, 70312, 69230, 68181,
+ 67164, 66176, 65217, 64285, 63380, 62500, 61643, 60810,
+ 60000, 59210, 59210, 58441, 57692, 56962, 56250, 55555,
+ 54878, 54216, 53571, 52941, 52325, 51724, 51136, 50561,
+ 49450, 48387, 47368, 46875, 45918, 45000, 44554, 44117,
+ 43269, 42452, 41666, 40909, 40178, 39473, 38793, 38135,
+ 36885, 36290, 35714, 35156, 34615, 34090, 33582, 33088,
+ 32608, 32142, 31468, 31034, 30405, 29801, 29220, 28662,
+ },
+
+ /* Inter case 285000/Qinter */
+ {
+ 712500, 570000, 475000, 407142, 356250, 316666, 285000, 259090,
+ 237500, 219230, 203571, 190000, 178125, 167647, 158333, 150000,
+ 142500, 135714, 129545, 123913, 118750, 114000, 109615, 105555,
+ 101785, 98275, 95000, 91935, 89062, 86363, 83823, 81428,
+ 79166, 77027, 75000, 73076, 71250, 69512, 67857, 66279,
+ 64772, 63333, 61956, 60638, 59375, 58163, 57000, 55882,
+ 54807, 53773, 52777, 51818, 50892, 50000, 49137, 47500,
+ 45967, 44531, 43181, 41911, 40714, 39583, 38513, 37500,
+ 36538, 35625, 34756, 33928, 33139, 32386, 31666, 30978,
+ 30319, 29687, 29081, 28500, 27941, 27403, 26886, 26388,
+ 25909, 25446, 25000, 24568, 23949, 23360, 22800, 22265,
+ 21755, 21268, 20802, 20357, 19930, 19520, 19127, 18750,
+ 18387, 18037, 17701, 17378, 17065, 16764, 16473, 16101,
+ 15745, 15405, 15079, 14766, 14467, 14179, 13902, 13636,
+ 13380, 13133, 12895, 12666, 12445, 12179, 11924, 11632,
+ 11445, 11220, 11003, 10795, 10594, 10401, 10215, 10035,
+ }
+};
+
#endif /* _VP8_PROBS_H_ */
--
1.9.1
More information about the Libva
mailing list