Rockchip: add bitrate rate control for encoder
Add bit-rate control module for both h264 and vp8
encoder.
Change-Id: Ie6bed0382579cacefc35042b4098d066b2097c4c
Signed-off-by: Alpha Lin <alpha.lin@rock-chips.com>
Reviewed-on: https://chromium-review.googlesource.com/375846
Commit-Ready: Kuang-che Wu <kcwu@chromium.org>
Tested-by: Kuang-che Wu <kcwu@chromium.org>
Reviewed-by: Kuang-che Wu <kcwu@chromium.org>
diff --git a/libv4l-rockchip_v2/Makefile.am b/libv4l-rockchip_v2/Makefile.am
index 69f0239..335e41d 100644
--- a/libv4l-rockchip_v2/Makefile.am
+++ b/libv4l-rockchip_v2/Makefile.am
@@ -10,7 +10,9 @@
libv4l-encplugin-rockchip.c \
libvepu/rk_vepu.c \
libvepu/rk_vepu_debug.c \
+ libvepu/common/rk_venc_rate_control.c \
libvepu/h264e/h264e.c \
+ libvepu/h264e/h264e_rate_control.c \
libvepu/vp8e/vp8e.c \
libvepu/vp8e/boolhuff.c \
libvepu/vp8e/vp8e_bitstream.c \
diff --git a/libv4l-rockchip_v2/libvepu/common/rk_venc.h b/libv4l-rockchip_v2/libvepu/common/rk_venc.h
index ddd329e..caaaf82 100644
--- a/libv4l-rockchip_v2/libvepu/common/rk_venc.h
+++ b/libv4l-rockchip_v2/libvepu/common/rk_venc.h
@@ -23,6 +23,8 @@
#include "../rk_vepu_interface.h"
+#include "rk_venc_rate_control.h"
+
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
@@ -67,6 +69,7 @@
struct rk_venc_ops *ops;
struct rk_vepu_runtime_param runtime_param;
+ struct v4l2_plugin_rate_control rc;
enum ENC_FORMAT fmt;
};
diff --git a/libv4l-rockchip_v2/libvepu/common/rk_venc_rate_control.c b/libv4l-rockchip_v2/libvepu/common/rk_venc_rate_control.c
new file mode 100644
index 0000000..8d856a8
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/common/rk_venc_rate_control.c
@@ -0,0 +1,601 @@
+/*
+ * Copyright 2016 Rockchip Electronics Co. LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rk_venc_rate_control.h"
+
+#include <assert.h>
+#include <memory.h>
+#include <stdio.h>
+
+#include "rk_venc.h"
+#include "libvepu/rk_vepu_debug.h"
+
+#define I32_MAX 2147483647 /* 2 ^ 31 - 1 */
+#define QP_DELTA 4
+#define QP_DELTA_LIMIT 10
+#define DRIFT_MAX 0x1FFFFFFF
+#define DRIFT_MIN -0x1FFFFFFF
+
+static const int32_t h264_q_step[] = {
+ 3, 3, 3, 4, 4, 5, 5, 6, 7, 7,
+ 8, 9, 10, 11, 13, 14, 16, 18, 20, 23,
+ 25, 28, 32, 36, 40, 45, 51, 57, 64, 72,
+ 80, 90, 101, 114, 128, 144, 160, 180, 203, 228,
+ 256, 288, 320, 360, 405, 456, 513, 577, 640, 720,
+ 810, 896
+};
+
+#define QINDEX_RANGE 128
+static const int32_t vp8_ac_lookup[QINDEX_RANGE] = {
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 60, 62, 64, 66, 68,
+ 70, 72, 74, 76, 78, 80, 82, 84, 86, 88,
+ 90, 92, 94, 96, 98, 100, 102, 104, 106, 108,
+ 110, 112, 114, 116, 119, 122, 125, 128, 131, 134,
+ 137, 140, 143, 146, 149, 152, 155, 158, 161, 164,
+ 167, 170, 173, 177, 181, 185, 189, 193, 197, 201,
+ 205, 209, 213, 217, 221, 225, 229, 234, 239, 245,
+ 249, 254, 259, 264, 269, 274, 279, 284
+};
+
+static int32_t get_gop_avg_qp(struct v4l2_plugin_rate_control *rc)
+{
+ int32_t qp_aver = rc->qp_last;
+
+ if (rc->acc_inter_qp && rc->acc_inter_cnt)
+ qp_aver = DIV(rc->acc_inter_qp, rc->acc_inter_cnt);
+
+ rc->acc_inter_qp = 0;
+ rc->acc_inter_cnt = 0;
+
+ return qp_aver;
+}
+
+static int32_t get_avg_bits(struct bits_statistic *p, int32_t n)
+{
+ int32_t i;
+ int32_t sum = 0;
+ int32_t pos = p->pos;
+
+ if (!p->len)
+ return 0;
+
+ if (n == -1 || n > p->len)
+ n = p->len;
+
+ i = n;
+ while (i--) {
+ if (pos)
+ pos--;
+ else
+ pos = p->len - 1;
+ sum += p->bits[pos];
+ if (sum < 0) {
+ return I32_MAX / (n - i);
+ }
+ }
+ return DIV(sum, n);
+}
+
+static int32_t axb_div_c(int32_t a, int32_t b, int32_t c)
+{
+ uint32_t left = 32;
+ uint32_t right = 0;
+ uint32_t shift;
+ int32_t sign = 1;
+ int32_t tmp;
+
+ if (a == 0 || b == 0)
+ return 0;
+ else if ((a * b / b) == a && c != 0)
+ return (a * b / c);
+
+ if (a < 0) {
+ sign = -1;
+ a = -a;
+ }
+ if (b < 0) {
+ sign *= -1;
+ b = -b;
+ }
+ if (c < 0) {
+ sign *= -1;
+ c = -c;
+ }
+
+ if (c == 0)
+ return 0x7FFFFFFF * sign;
+
+ if (b > a) {
+ tmp = b;
+ b = a;
+ a = tmp;
+ }
+
+ for (--left; (((uint32_t)a << left) >> left) != (uint32_t)a; --left)
+ ;
+
+ left--;
+
+ while (((uint32_t)b >> right) > (uint32_t)c)
+ right++;
+
+ if (right > left) {
+ return 0x7FFFFFFF * sign;
+ } else {
+ shift = left - right;
+ return (int32_t)((((uint32_t)a << shift) /
+ (uint32_t)c * (uint32_t)b) >> shift) * sign;
+ }
+}
+
+static inline void reset_statistic(struct bits_statistic *p)
+{
+ memset(p, 0, sizeof(*p));
+}
+
+static inline void reset_linear_model(struct linear_model *p, int32_t qp)
+{
+ memset(p, 0, sizeof(*p));
+ p->qp_last = qp;
+}
+
+static void update_statitistic(struct bits_statistic *p, int32_t bits)
+{
+ const int32_t clen = STATISTIC_TABLE_LENGTH;
+
+ p->bits[p->pos] = bits;
+
+ if (++p->pos >= clen) {
+ p->pos = 0;
+ }
+ if (p->len < clen) {
+ p->len++;
+ }
+}
+
+/*
+ * store previous intra frame bits / gop bits, and used for next gop intra frame
+ * bit compensation
+ */
+static void save_intra_frm_ratio(struct v4l2_plugin_rate_control *rc)
+{
+ if (rc->acc_bits_cnt) {
+ int32_t intra_frm_ratio =
+ axb_div_c(get_avg_bits(&rc->intra, 1),
+ rc->mb_per_pic, 256) * 100;
+ intra_frm_ratio = DIV(intra_frm_ratio, rc->acc_bits_cnt);
+ intra_frm_ratio = MIN(99, intra_frm_ratio);
+
+ update_statitistic(&rc->gop, intra_frm_ratio);
+ }
+ rc->acc_bits_cnt = 0;
+}
+
+static void update_pid_ctrl(struct bits_statistic *p, int32_t bits)
+{
+ p->len = 3;
+
+ p->bits[0] = bits - p->bits[2]; /* Derivative */
+ if ((bits > 0) && (bits + p->bits[1] > p->bits[1]))
+ p->bits[1] = bits + p->bits[1]; /* Integral */
+ if ((bits < 0) && (bits + p->bits[1] < p->bits[1]))
+ p->bits[1] = bits + p->bits[1]; /* Integral */
+ p->bits[2] = bits; /* Proportional */
+ VPU_PLG_DBG("P %d I %d D %d\n", p->bits[2], p->bits[1], p->bits[0]);
+}
+
+static inline int32_t get_pid_ctrl_value(struct bits_statistic *p)
+{
+ return DIV(p->bits[2] * 40 + p->bits[1] * 60 + p->bits[0] * 1, 1000);
+}
+
+/*
+ * according to linear formula 'R * Q * Q = b * Q + a'
+ * now give the target R, calculate a Qp value using
+ * approximation
+ */
+static int32_t calculate_qp_using_linear_model(
+ struct v4l2_plugin_rate_control *rc,
+ struct linear_model *model,
+ int64_t r)
+{
+ int32_t qp = model->qp_last;
+ int64_t estimate_r = 0;
+ int64_t diff = 0;
+ int64_t diff_min = I32_MAX;
+ int64_t qp_best = qp;
+ int32_t tmp;
+
+ VPU_PLG_DBG("a %lld b %lld\n", model->a, model->b);
+
+ if (model->b == 0 && model->a == 0) {
+ return qp_best;
+ }
+
+ if (r <= 0) {
+ qp = CLIP3(qp_best + QP_DELTA, rc->qp_min, rc->qp_max);
+ return qp;
+ }
+
+ do {
+ int64_t qstep = rc->qstep[qp];
+ estimate_r =
+ DIV(model->b, qstep) + DIV(model->a, qstep * qstep);
+ diff = estimate_r - r;
+ if (ABS(diff) < diff_min) {
+ diff_min = ABS(diff);
+ qp_best = qp;
+ if (diff > 0) {
+ qp++;
+ } else {
+ qp--;
+ }
+ } else {
+ break;
+ }
+ } while (qp <= rc->qp_max && qp >= rc->qp_min);
+
+ tmp = qp_best - model->qp_last;
+ if (tmp > QP_DELTA) {
+ qp_best = model->qp_last + QP_DELTA;
+ /*
+ * when there is a bit gap between requirement and actual bits,
+ * delta qp cannot quickly catch the requirement.
+ */
+ if (tmp > QP_DELTA_LIMIT)
+ qp_best = model->qp_last + QP_DELTA * 2;
+ } else if (tmp < -QP_DELTA) {
+ qp_best = model->qp_last - QP_DELTA;
+ }
+
+ model->qp_last = qp_best;
+
+ return qp_best;
+}
+
+/* determine qp for current picture */
+void calculate_pic_qp(struct v4l2_plugin_rate_control *rc)
+{
+ int32_t target_bits;
+ int32_t norm_bits;
+
+ if (rc->pic_rc_en != true) {
+ rc->qp = rc->qp_fixed;
+ return;
+ }
+
+ if (rc->cur_frmtype == INTRA_FRAME) {
+ /*
+ * when there are no intra statistic information, we calcuate
+ * intra qp using previous gop inter frame average qp.
+ */
+ rc->qp = get_gop_avg_qp(rc);
+ save_intra_frm_ratio(rc);
+ /*
+ * if all frames are intra we calculate qp
+ * using intra frame statistic info.
+ */
+ if (rc->pre_frmtype == INTRA_FRAME) {
+ target_bits = rc->target_bits -
+ get_pid_ctrl_value(&rc->pid_intra);
+
+ norm_bits = axb_div_c(target_bits, 256, rc->mb_per_pic);
+ rc->qp = calculate_qp_using_linear_model(rc,
+ &rc->intra_frames,
+ norm_bits);
+ }
+ } else {
+ /*
+ * calculate qp by matching to previous
+ * inter frames R-Q curve
+ */
+ target_bits = rc->target_bits -
+ get_pid_ctrl_value(&rc->pid_inter);
+
+ norm_bits = axb_div_c(target_bits, 256, rc->mb_per_pic);
+ rc->qp = calculate_qp_using_linear_model(rc, &rc->inter_frames,
+ norm_bits);
+ }
+}
+
+static void store_linear_x_y(struct linear_model *model, int32_t r, int32_t qstep)
+{
+ model->qp[model->i] = qstep;
+ model->r[model->i] = r;
+ model->y[model->i] = r * qstep * qstep;
+
+ model->n++;
+ model->n = MIN(model->n, LINEAR_MODEL_STATISTIC_COUNT);
+
+ model->i++;
+ model->i %= LINEAR_MODEL_STATISTIC_COUNT;
+}
+
+/*
+ * This function want to calculate coefficient 'b' 'a' using ordinary
+ * least square.
+ * y = b * x + a
+ * b_n = accumulate(x * y) - n * (average(x) * average(y))
+ * a_n = accumulate(x * x) * accumulate(y) - accumulate(x) * accumulate(x * y)
+ * denom = accumulate(x * x) - n * (square(average(x))
+ * b = b_n / denom
+ * a = a_n / denom
+ */
+static void calculate_linear_coefficient(struct linear_model *model)
+{
+ int i = 0;
+ int n;
+ int64_t acc_xy = 0;
+ int64_t acc_x = 0;
+ int64_t acc_y = 0;
+ int64_t acc_sq_x = 0;
+
+ int64_t b_num = 0;
+ int64_t denom = 0;
+
+ int64_t *x = model->qp;
+ int64_t *y = model->y;
+
+ n = model->n;
+ i = n;
+
+ while (i--) {
+ acc_xy += x[i] * y[i];
+ acc_x += x[i];
+ acc_y += y[i];
+ acc_sq_x += x[i] * x[i];
+ }
+
+ b_num = n * acc_xy - acc_x * acc_y;
+ denom = n * acc_sq_x - acc_x * acc_x;
+
+ model->b = DIV(b_num, denom);
+ model->a = DIV(acc_y, n) - DIV(acc_x * model->b, n);
+}
+
+/*
+ * in the beginning of rate control, we should get a estimate qp value using
+ * experience point.
+ */
+static int32_t caluate_qp_by_bits_est(int32_t bits, int32_t pels,
+ const int32_t qp_tbl[2][11])
+{
+ const int32_t upscale = 8000;
+ int32_t i = -1;
+
+ /* prevents overflow */
+ if (bits > 1000000)
+ return qp_tbl[1][10];
+
+ /* make room for multiplication */
+ pels >>= 8;
+ bits >>= 5;
+
+ /* adjust the bits value for the current resolution */
+ bits *= pels + 250;
+ assert(pels > 0);
+ assert(bits > 0);
+ bits /= 350 + (3 * pels) / 4;
+ bits = axb_div_c(bits, upscale, pels << 6);
+
+ while (qp_tbl[0][++i] < bits);
+
+ return qp_tbl[1][i];
+}
+
+static int32_t get_drift_bits(struct virt_buffer *vb,
+ int32_t time_inc)
+{
+ int32_t drift, target;
+
+ /*
+ * saturate actual_bits, this is to prevent overflows caused by much
+ * greater bitrate setting than is really possible to reach.
+ */
+ vb->actual_bits = CLIP3(vb->actual_bits, DRIFT_MIN, DRIFT_MAX);
+
+ vb->pic_time_inc += time_inc;
+ vb->virt_bits_cnt += axb_div_c(vb->bit_rate, time_inc, vb->time_scale);
+ target = vb->virt_bits_cnt - vb->actual_bits;
+
+ /* saturate target, prevents rc going totally out of control.
+ This situation should never happen. */
+ target = CLIP3(target, DRIFT_MIN, DRIFT_MAX);
+
+ /* picture time inc must be in range of [0, time_scale) */
+ while (vb->pic_time_inc >= vb->time_scale) {
+ vb->pic_time_inc -= vb->time_scale;
+ vb->virt_bits_cnt -= vb->bit_rate;
+ vb->actual_bits -= vb->bit_rate;
+ }
+
+ drift = axb_div_c(vb->bit_rate, vb->pic_time_inc, vb->time_scale);
+ drift -= vb->virt_bits_cnt;
+ vb->virt_bits_cnt += drift;
+
+ return target;
+}
+
+void rk_venc_recalc_parameter(struct v4l2_plugin_rate_control *rc)
+{
+ rc->vb.bits_per_pic = axb_div_c(rc->vb.bit_rate,
+ rc->fps_denom, rc->fps_num);
+}
+
+bool rk_venc_init_pic_rc(struct v4l2_plugin_rate_control *rc,
+ const int32_t qp_tbl[2][11])
+{
+ struct rk_venc *enc = container_of(rc, struct rk_venc, rc);
+ struct virt_buffer *vb = &rc->vb;
+
+ switch (enc->fmt) {
+ case ENC_FORMAT_H264:
+ rc->qstep = h264_q_step;
+ rc->qstep_size = sizeof(h264_q_step) / sizeof(int32_t);
+ break;
+ case ENC_FORMAT_VP8:
+ rc->qstep = vp8_ac_lookup;
+ rc->qstep_size = sizeof(vp8_ac_lookup) / sizeof(int32_t);
+ break;
+ default:
+ VPU_PLG_ERR("unsupport encoder format %d\n", (int)enc->fmt);
+ return false;
+ }
+
+ if (rc->qp == -1) {
+ int32_t tmp = axb_div_c(vb->bit_rate, rc->fps_denom, rc->fps_num);
+ rc->qp = caluate_qp_by_bits_est(tmp, rc->mb_per_pic * 16 * 16, qp_tbl);
+ }
+
+ rc->qp = CLIP3(rc->qp, rc->qp_min, rc->qp_max);
+
+ rc->cur_frmtype = INTRA_FRAME;
+ rc->pre_frmtype = INTER_FRAME;
+
+ rc->qp_last = rc->qp;
+ rc->qp_fixed = rc->qp;
+
+ vb->bits_per_pic = axb_div_c(vb->bit_rate, rc->fps_denom, rc->fps_num);
+
+ reset_statistic(&rc->pid_inter);
+ reset_statistic(&rc->pid_intra);
+ reset_statistic(&rc->intra);
+ reset_statistic(&rc->gop);
+
+ reset_linear_model(&rc->intra_frames, rc->qp);
+ reset_linear_model(&rc->inter_frames, rc->qp);
+
+ rc->acc_inter_qp = 0;
+ rc->acc_inter_cnt = 0;
+ rc->acc_bits_cnt = 0;
+
+ rc->window_len = rc->gop_len;
+ vb->window_rem = rc->gop_len;
+ rc->intra_interval_ctrl = rc->intra_interval = rc->gop_len;
+ rc->target_bits = 0;
+
+ return true;
+}
+
+void rk_venc_after_pic_rc(struct v4l2_plugin_rate_control *rc,
+ uint32_t bytes)
+{
+ struct virt_buffer *vb = &rc->vb;
+ int32_t bits = (int32_t)bytes * 8;
+ int32_t norm_bits = 0;
+
+ VPU_PLG_INF("get actual bits %d\n", bits);
+
+ rc->acc_bits_cnt += bits;
+
+ /* store the error between target and actual frame size */
+ if (rc->cur_frmtype != INTRA_FRAME) {
+ /* saturate the error to avoid inter frames with
+ * mostly intra MBs to affect too much */
+ update_pid_ctrl(&rc->pid_inter,
+ MIN(bits - rc->target_bits, 2 * rc->target_bits));
+ } else {
+ update_pid_ctrl(&rc->pid_intra, bits - rc->target_bits);
+ }
+
+ norm_bits = axb_div_c(bits, 256, rc->mb_per_pic);
+
+ /* update number of bits used for residual, inter or intra */
+ if (rc->cur_frmtype != INTRA_FRAME) {
+ store_linear_x_y(&rc->inter_frames, norm_bits, rc->qstep[rc->qp]);
+ calculate_linear_coefficient(&rc->inter_frames);
+ } else {
+ update_statitistic(&rc->intra, norm_bits);
+
+ store_linear_x_y(&rc->intra_frames, norm_bits, rc->qstep[rc->qp]);
+ calculate_linear_coefficient(&rc->intra_frames);
+ }
+
+ vb->bucket_fullness += bits;
+ vb->actual_bits += bits;
+}
+
+void rk_venc_before_pic_rc(struct v4l2_plugin_rate_control *rc,
+ uint32_t timeInc, enum FRAME_TYPE frmtype)
+{
+ struct virt_buffer *vb = &rc->vb;
+ int32_t rcWindow, intraBits = 0, tmp = 0;
+
+ rc->cur_frmtype = frmtype;
+
+ tmp = get_drift_bits(&rc->vb, (int32_t)timeInc);
+
+ if (vb->window_rem == 0) {
+ vb->window_rem = rc->window_len - 1;
+ reset_statistic(&rc->pid_inter);
+ if (rc->cur_frmtype != rc->pre_frmtype)
+ reset_statistic(&rc->pid_intra);
+ } else {
+ vb->window_rem--;
+ }
+
+ if (rc->cur_frmtype != INTRA_FRAME &&
+ rc->intra_interval > 1) {
+ intraBits = vb->bits_per_pic * rc->intra_interval *
+ get_avg_bits(&rc->gop, 10) / 100;
+ intraBits -= vb->bits_per_pic;
+ intraBits /= (rc->intra_interval - 1);
+ intraBits = MAX(0, intraBits);
+ }
+
+ /* Compensate for intra "stealing" bits from inters. */
+ tmp += intraBits * (rc->intra_interval - rc->intra_interval_ctrl);
+
+ rcWindow = MAX(1, rc->window_len);
+ rc->target_bits = vb->bits_per_pic - intraBits + DIV(tmp, rcWindow);
+ rc->target_bits = MAX(0, rc->target_bits);
+
+ VPU_PLG_INF("require target bits %d\n", rc->target_bits);
+ calculate_pic_qp(rc);
+
+ rc->qp = CLIP3(rc->qp, rc->qp_min, rc->qp_max);
+ rc->qp_last = rc->qp;
+
+ if (rc->cur_frmtype == INTRA_FRAME) {
+ /*
+ * if there is not a all intra coding, we prefer a better intra
+ * frame to get a better psnr.
+ */
+ if (rc->pre_frmtype != INTRA_FRAME)
+ rc->qp += rc->intra_qp_delta;
+
+ rc->qp = CLIP3(rc->qp, rc->qp_min, rc->qp_max);
+ if (rc->intra_interval_ctrl > 1)
+ rc->intra_interval = rc->intra_interval_ctrl;
+ rc->intra_interval_ctrl = 1;
+ } else {
+ rc->acc_inter_qp += rc->qp;
+ rc->acc_inter_cnt++;
+ rc->intra_interval_ctrl++;
+
+ if (rc->intra_interval_ctrl > rc->intra_interval)
+ rc->intra_interval = rc->intra_interval_ctrl;
+ }
+
+ rc->pre_frmtype = rc->cur_frmtype;
+
+ VPU_PLG_INF("get qp %d\n", rc->qp);
+}
diff --git a/libv4l-rockchip_v2/libvepu/common/rk_venc_rate_control.h b/libv4l-rockchip_v2/libvepu/common/rk_venc_rate_control.h
new file mode 100644
index 0000000..2ee5bf2
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/common/rk_venc_rate_control.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2016 Rockchip Electronics Co. LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _V4L2_PLUGIN_RK_VENC_RATE_CONTROL_H_
+#define _V4L2_PLUGIN_RK_VENC_RATE_CONTROL_H_
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#define STATISTIC_TABLE_LENGTH 10
+
+enum FRAME_TYPE {
+ INTRA_FRAME = 0,
+ INTER_FRAME = 1
+};
+
+struct bits_statistic {
+ int32_t bits[STATISTIC_TABLE_LENGTH];
+ int32_t pos;
+ int32_t len;
+};
+
+#define LINEAR_MODEL_STATISTIC_COUNT 15
+
+struct linear_model {
+ int32_t n; /* elements count */
+ int32_t i; /* elements index for store */
+
+ int64_t b; /* coefficient */
+ int64_t a;
+
+ int64_t qp[LINEAR_MODEL_STATISTIC_COUNT]; /* x */
+ int64_t r[LINEAR_MODEL_STATISTIC_COUNT];
+ int64_t y[LINEAR_MODEL_STATISTIC_COUNT]; /* y = qp*qp*r */
+
+ int32_t qp_last; /* qp value in last calculate */
+};
+
+/* Virtual buffer */
+struct virt_buffer {
+ int32_t bit_rate;
+ int32_t bits_per_pic;
+ int32_t pic_time_inc;
+ int32_t time_scale;
+ int32_t virt_bits_cnt;
+ int32_t actual_bits;
+ int32_t bucket_fullness;
+ int32_t gop_rem;
+ int32_t window_rem;
+};
+
+struct v4l2_plugin_rate_control {
+ bool pic_rc_en;
+ int32_t mb_per_pic;
+ enum FRAME_TYPE cur_frmtype;
+ enum FRAME_TYPE pre_frmtype;
+ int32_t qp_fixed;
+ int32_t qp;
+ int32_t qp_min;
+ int32_t qp_max;
+ int32_t qp_last;
+ int32_t fps_num;
+ int32_t fps_denom;
+ struct virt_buffer vb;
+ struct bits_statistic pid_inter;
+ int32_t target_bits;
+ int32_t acc_inter_qp;
+ int32_t acc_inter_cnt;
+ int32_t gop_len;
+ int32_t intra_qp_delta;
+
+ struct bits_statistic intra;
+ struct bits_statistic pid_intra;
+ struct bits_statistic gop;
+
+ struct linear_model intra_frames;
+ struct linear_model inter_frames;
+
+ /* accumulate bits count for current gop */
+ int32_t acc_bits_cnt;
+
+ /* bitrate window which tries to match target */
+ int32_t window_len;
+ int32_t intra_interval;
+ int32_t intra_interval_ctrl;
+
+ const int32_t *qstep;
+ int32_t qstep_size;
+
+ bool initiated;
+};
+
+void rk_venc_recalc_parameter(struct v4l2_plugin_rate_control *rc);
+bool rk_venc_init_pic_rc(struct v4l2_plugin_rate_control *rc,
+ const int32_t qp_tbl[2][11]);
+void rk_venc_after_pic_rc(struct v4l2_plugin_rate_control *rc,
+ uint32_t byteCnt);
+void rk_venc_before_pic_rc(struct v4l2_plugin_rate_control *rc,
+ uint32_t timeInc, enum FRAME_TYPE frmtype);
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e.c b/libv4l-rockchip_v2/libvepu/h264e/h264e.c
index 775098d..d21ec96 100644
--- a/libv4l-rockchip_v2/libvepu/h264e/h264e.c
+++ b/libv4l-rockchip_v2/libvepu/h264e/h264e.c
@@ -20,6 +20,8 @@
#include <stdio.h>
#include "h264e.h"
+#include "h264e_rate_control.h"
+#include "../common/rk_venc_rate_control.h"
#include "../rk_vepu_debug.h"
const int32_t h264e_qp_tbl[2][11] = {
@@ -107,6 +109,40 @@
slice->slice_beta_offset_div2 = 0;
}
+static void h264e_init_rc(struct rk_venc *ictx)
+{
+ struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+ struct mb_qpctrl *qpCtrl = &ctx->mbrc.qp_ctrl;
+ struct v4l2_plugin_rate_control *rc = &ictx->rc;
+
+ memset(qpCtrl, 0, sizeof(*qpCtrl));
+
+ ctx->mbrc.mb_rc_en = true;
+ qpCtrl->check_points = MIN(ctx->sps.pic_height_in_map_units - 1,
+ CHECK_POINTS_MAX);
+ qpCtrl->chkptr_distance =
+ MB_PER_PIC(ctx) / (qpCtrl->check_points + 1);
+
+ rc->pic_rc_en = true;
+ rc->fps_num = 30;
+ rc->fps_denom = 1;
+ rc->vb.bit_rate = 1000000;
+ rc->vb.actual_bits = 0;
+ rc->vb.time_scale = rc->fps_num;
+ rc->vb.virt_bits_cnt = 0;
+ rc->vb.bucket_fullness = 0;
+ rc->vb.pic_time_inc = 0;
+ rc->gop_len = 150;
+ rc->qp_min = 10;
+ rc->qp_max = 51;
+ rc->mb_per_pic = MB_PER_PIC(ctx);
+ rc->intra_qp_delta = -3;
+ rc->qp = -1;
+ rc->initiated = false;
+
+ rk_venc_init_pic_rc(&ctx->venc.rc, h264e_qp_tbl);
+}
+
static int h264e_init(struct rk_venc *ictx,
struct rk_vepu_init_param *param)
{
@@ -135,6 +171,8 @@
ctx->sps.pic_height_in_map_units * 16 - ctx->height;
}
+ h264e_init_rc(ictx);
+
if (ctx->sps.level_idc >= H264ENC_LEVEL_3_1)
ctx->h264_inter4x4_disabled = 1;
else
@@ -156,6 +194,9 @@
static int h264e_begin_picture(struct rk_venc *ictx)
{
struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+ int i;
+ enum FRAME_TYPE frmtype = INTER_FRAME;
+ int timeInc = 1;
struct rk3288_h264e_reg_params *hw_info = &ctx->hw_info;
if (ictx->runtime_param.keyframe_request) {
@@ -170,8 +211,13 @@
ctx->slice.idr_pic_id %= 16;
ctx->slice.frame_num = 0;
hw_info->frame_coding_type = FRAME_CODING_TYPE_INTRA;
+ frmtype = INTRA_FRAME;
+ timeInc = 0;
}
+ rk_venc_before_pic_rc(&ctx->venc.rc, timeInc, frmtype);
+ h264e_before_mb_rate_control(&ctx->mbrc);
+
hw_info->pic_init_qp = ctx->pps.pic_init_qp_minus26 + 26;
hw_info->transform8x8_mode = ctx->pps.transform_8x8_mode_flag;
hw_info->enable_cabac = ctx->pps.entropy_coding_mode_flag != 0;
@@ -187,13 +233,22 @@
hw_info->slice_size_mb_rows = ctx->slice_size_mb_rows;
hw_info->cabac_init_idc = ctx->slice.cabac_init_idc;
- hw_info->qp = 30;
+ hw_info->qp = ctx->venc.rc.qp;
hw_info->mad_qp_delta = 0;
hw_info->mad_threshold = 0;
- hw_info->qp_min = 10;
- hw_info->qp_max = 51;
- hw_info->cp_distance_mbs = 0;
+ hw_info->qp_min = ctx->venc.rc.qp_min;
+ hw_info->qp_max = ctx->venc.rc.qp_max;
+ hw_info->cp_distance_mbs = ctx->mbrc.qp_ctrl.chkptr_distance;
+
+ for (i = 0; i < ctx->mbrc.qp_ctrl.check_points; i++) {
+ hw_info->cp_target[i] = ctx->mbrc.qp_ctrl.word_cnt_target[i];
+ }
+
+ for (i = 0; i < CTRL_LEVELS; i++) {
+ hw_info->target_error[i] = ctx->mbrc.qp_ctrl.word_error[i];
+ hw_info->delta_qp[i] = ctx->mbrc.qp_ctrl.qp_delta[i];
+ }
hw_info->h264_inter4x4_disabled = ctx->h264_inter4x4_disabled;
@@ -207,9 +262,17 @@
uint32_t outputStreamSize)
{
struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+ struct v4l2_plugin_h264_feedback *feedback = &ctx->feedback;
+ int i;
+
+ for (i = 0; i < CHECK_POINTS_MAX; i++)
+ ctx->mbrc.qp_ctrl.word_cnt_prev[i] = feedback->cp[i];
+ h264e_after_mb_rate_control(&ctx->mbrc, outputStreamSize,
+ feedback->rlcCount, feedback->qpSum);
+ rk_venc_after_pic_rc(&ctx->venc.rc, outputStreamSize);
ctx->frm_in_gop++;
- ctx->frm_in_gop %= 150;
+ ctx->frm_in_gop %= ctx->venc.rc.gop_len;
ctx->slice.frame_num++;
ctx->slice.frame_num %=
@@ -233,10 +296,32 @@
static void h264e_apply_param(struct rk_venc *ictx)
{
struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+ struct rk_vepu_runtime_param *param = &ictx->runtime_param;
+ bool reinit = false;
assert(ctx);
- /* todo, apply parameters to rate control */
+ if (param->bitrate != 0) {
+ ctx->venc.rc.vb.bit_rate = param->bitrate;
+ reinit = true;
+ }
+
+ if (param->framerate_numer != 0 && param->framerate_denom != 0) {
+ ctx->venc.rc.fps_num = param->framerate_numer;
+ ctx->venc.rc.fps_denom = param->framerate_denom;
+ ictx->rc.vb.time_scale = param->framerate_numer;
+ reinit = true;
+ }
+
+ if (reinit) {
+ if (!ictx->rc.initiated) {
+ ictx->rc.qp = -1;
+ rk_venc_init_pic_rc(&ictx->rc, h264e_qp_tbl);
+ ictx->rc.initiated = true;
+ } else {
+ rk_venc_recalc_parameter(&ictx->rc);
+ }
+ }
}
static void h264e_get_payloads(struct rk_venc *ictx, size_t *num, uint32_t **ids,
diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e.h b/libv4l-rockchip_v2/libvepu/h264e/h264e.h
index d62443e..817bb4e 100644
--- a/libv4l-rockchip_v2/libvepu/h264e/h264e.h
+++ b/libv4l-rockchip_v2/libvepu/h264e/h264e.h
@@ -23,6 +23,8 @@
#include "../rk_vepu_interface.h"
#include "h264e_common.h"
+#include "h264e_rate_control.h"
+
#include "../common/rk_venc.h"
#define H264E_NUM_CTRLS 1
@@ -35,6 +37,8 @@
struct rk3288_h264e_reg_params hw_info;
struct v4l2_plugin_h264_feedback feedback;
+ struct h264_mb_rate_control mbrc;
+
int width;
int height;
diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e_rate_control.c b/libv4l-rockchip_v2/libvepu/h264e/h264e_rate_control.c
new file mode 100644
index 0000000..48908d8
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/h264e/h264e_rate_control.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory.h>
+#include <assert.h>
+
+#include "h264e.h"
+#include "h264e_common.h"
+#include "h264e_rate_control.h"
+#include "../rk_vepu_debug.h"
+
+#define WORD_CNT_MAX 65535
+
+static void calculate_mb_model_using_linear_model(
+ struct h264_mb_rate_control *rc,
+ int32_t non_zero_target)
+{
+ struct rk_h264_encoder *enc =
+ container_of(rc, struct rk_h264_encoder, mbrc);
+ const int32_t sscale = 256;
+ struct mb_qpctrl *qc = &rc->qp_ctrl;
+ int32_t scaler;
+ int32_t i;
+ int32_t tmp;
+ int32_t mb_per_pic = MB_COUNT(enc->width) * MB_COUNT(enc->height);
+ int32_t chk_ptr_cnt = MIN(MB_COUNT(enc->height), CHECK_POINTS_MAX);
+ int32_t chk_ptr_distance = mb_per_pic / (chk_ptr_cnt + 1);
+ int32_t bits_per_pic = enc->venc.rc.vb.bits_per_pic;
+
+ assert(non_zero_target < (0x7FFFFFFF / sscale));
+
+ if(non_zero_target > 0) {
+ /* scaler is non-zero coefficent count per macro-block
+ plus 256 */
+ scaler = DIV(non_zero_target * sscale, mb_per_pic);
+ } else {
+ return;
+ }
+
+ for(i = 0; i < chk_ptr_cnt; i++) {
+ /* tmp is non-zero coefficient count target for i-th
+ check point */
+ tmp = (scaler * (chk_ptr_distance * (i + 1) + 1)) / sscale;
+ tmp = MIN(WORD_CNT_MAX, tmp / 32 + 1);
+ if (tmp < 0) tmp = WORD_CNT_MAX; /* Detect overflow */
+ qc->word_cnt_target[i] = tmp; /* div32 for regs */
+ }
+
+ /* calculate nz count for avg. bits per frame */
+ /* tmp is target non-zero coefficient count for average size pic */
+ tmp = DIV(bits_per_pic * 256, rc->bits_per_non_zero_coef);
+
+ /* ladder 'non-zero coefficent count target' - 'non-zero coefficient
+ actual' of check point */
+ qc->word_error[0] = -tmp * 3;
+ qc->qp_delta[0] = -3;
+ qc->word_error[1] = -tmp * 2;
+ qc->qp_delta[1] = -2;
+ qc->word_error[2] = -tmp * 1;
+ qc->qp_delta[2] = -1;
+ qc->word_error[3] = tmp * 1;
+ qc->qp_delta[3] = 0;
+ qc->word_error[4] = tmp * 2;
+ qc->qp_delta[4] = 1;
+ qc->word_error[5] = tmp * 3;
+ qc->qp_delta[5] = 2;
+ qc->word_error[6] = tmp * 4;
+ qc->qp_delta[6] = 3;
+
+ for(i = 0; i < CTRL_LEVELS; i++)
+ qc->word_error[i] = CLIP3(qc->word_error[i] / 4, -32768, 32767);
+}
+
+static void calculate_mb_model_using_adaptive_model(
+ struct h264_mb_rate_control *rc,
+ int32_t non_zero_target)
+{
+ struct rk_h264_encoder *enc =
+ container_of(rc, struct rk_h264_encoder, mbrc);
+ const int32_t sscale = 256;
+ struct mb_qpctrl *qc = &rc->qp_ctrl;
+ int32_t i;
+ int32_t tmp;
+ int32_t scaler;
+ int32_t chk_ptr_cnt = MIN(MB_COUNT(enc->height), CHECK_POINTS_MAX);
+ int32_t bits_per_pic = enc->venc.rc.vb.bits_per_pic;
+
+ assert(non_zero_target < (0x7FFFFFFF / sscale));
+
+ if((non_zero_target > 0) && (rc->non_zero_cnt > 0))
+ scaler = DIV(non_zero_target * sscale, rc->non_zero_cnt);
+ else
+ return;
+
+ for(i = 0; i < chk_ptr_cnt; i++) {
+ tmp = (int32_t)(qc->word_cnt_prev[i] * scaler) / sscale;
+ tmp = MIN(WORD_CNT_MAX, tmp / 32 + 1);
+ if (tmp < 0) tmp = WORD_CNT_MAX; /* Detect overflow */
+ qc->word_cnt_target[i] = tmp; /* div32 for regs */
+ }
+
+ /* calculate nz count for avg. bits per frame */
+ tmp = DIV(bits_per_pic * 256, (rc->bits_per_non_zero_coef * 3));
+
+ qc->word_error[0] = -tmp * 3;
+ qc->qp_delta[0] = -3;
+ qc->word_error[1] = -tmp * 2;
+ qc->qp_delta[1] = -2;
+ qc->word_error[2] = -tmp * 1;
+ qc->qp_delta[2] = -1;
+ qc->word_error[3] = tmp * 1;
+ qc->qp_delta[3] = 0;
+ qc->word_error[4] = tmp * 2;
+ qc->qp_delta[4] = 1;
+ qc->word_error[5] = tmp * 3;
+ qc->qp_delta[5] = 2;
+ qc->word_error[6] = tmp * 4;
+ qc->qp_delta[6] = 3;
+
+ for(i = 0; i < CTRL_LEVELS; i++)
+ qc->word_error[i] =
+ CLIP3(qc->word_error[i] / 4, -32768, 32767);
+}
+
+static void calculate_mb_model(struct h264_mb_rate_control *rc,
+ int32_t target_bits)
+{
+ struct rk_h264_encoder *enc =
+ container_of(rc, struct rk_h264_encoder, mbrc);
+ int32_t non_zero_target;
+ int32_t mb_per_pic = MB_COUNT(enc->width) * MB_COUNT(enc->height);
+ int32_t coeff_cnt_max = mb_per_pic * 24 * 16;
+
+ /* Disable macroblock rate control for intra frame,
+ because coefficient target will be wrong */
+ if(enc->frm_in_gop == 0 || rc->bits_per_non_zero_coef == 0)
+ return;
+
+ /* Required zero cnt */
+ non_zero_target = DIV(target_bits * 256, rc->bits_per_non_zero_coef);
+ non_zero_target = CLIP3(non_zero_target, 0, coeff_cnt_max);
+
+ non_zero_target = MIN(0x7FFFFFFFU / 1024U, (uint32_t)non_zero_target);
+
+ VPU_PLG_INF("mb rc target non-zero coefficient count %d\n",
+ non_zero_target);
+
+ /* Use linear model when previous frame can't be used for prediction */
+ if (enc->frm_in_gop != 0 || rc->non_zero_cnt == 0)
+ calculate_mb_model_using_linear_model(rc, non_zero_target);
+ else
+ calculate_mb_model_using_adaptive_model(rc, non_zero_target);
+}
+
+void h264e_before_mb_rate_control(struct h264_mb_rate_control *rc)
+{
+ struct rk_h264_encoder *enc =
+ container_of(rc, struct rk_h264_encoder, mbrc);
+
+ memset(rc->qp_ctrl.word_cnt_target, 0,
+ sizeof(rc->qp_ctrl.word_cnt_target));
+
+ if (enc->venc.rc.cur_frmtype == INTER_FRAME &&
+ enc->venc.rc.pre_frmtype == INTER_FRAME &&
+ rc->mb_rc_en)
+ calculate_mb_model(rc, enc->venc.rc.target_bits);
+}
+
+void h264e_after_mb_rate_control(struct h264_mb_rate_control *rc,
+ uint32_t bytes, uint32_t non_zero_cnt, uint32_t qp_sum)
+{
+ struct rk_h264_encoder *enc = container_of(rc, struct rk_h264_encoder,
+ mbrc);
+ int32_t bits = bytes * 8;
+
+ VPU_PLG_INF("mb rc get actual non-zero coefficient count %u\n",
+ non_zero_cnt);
+
+ if (enc->frm_in_gop != 0) {
+ rc->bits_per_non_zero_coef = DIV(bits * 256, non_zero_cnt);
+ rc->non_zero_cnt = non_zero_cnt;
+ }
+}
diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e_rate_control.h b/libv4l-rockchip_v2/libvepu/h264e/h264e_rate_control.h
new file mode 100644
index 0000000..2b6b0ac
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/h264e/h264e_rate_control.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H264_RATE_CONTROL_H
+#define H264_RATE_CONTROL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "../common/rk_venc_rate_control.h"
+
+#define CTRL_LEVELS 7
+#define CHECK_POINTS_MAX 10
+
+struct mb_qpctrl {
+ int32_t word_error[CTRL_LEVELS]; /* Check point error bit */
+ int32_t qp_delta[CTRL_LEVELS]; /* Check point qp difference */
+ int32_t word_cnt_target[CHECK_POINTS_MAX]; /* Required bit count */
+ int32_t word_cnt_prev[CHECK_POINTS_MAX]; /* Real bit count */
+ int32_t chkptr_distance;
+ int32_t check_points;
+};
+
+struct h264_mb_rate_control {
+ bool mb_rc_en;
+ int32_t bits_per_non_zero_coef;
+ int32_t non_zero_cnt;
+ struct mb_qpctrl qp_ctrl;
+};
+
+void h264e_before_mb_rate_control(struct h264_mb_rate_control *rc);
+void h264e_after_mb_rate_control(struct h264_mb_rate_control *rc, uint32_t coded_bytes,
+ uint32_t non_zero_cnt, uint32_t qp_sum);
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/vp8e.c b/libv4l-rockchip_v2/libvepu/vp8e/vp8e.c
index c0d8360..80d7a4d 100644
--- a/libv4l-rockchip_v2/libvepu/vp8e/vp8e.c
+++ b/libv4l-rockchip_v2/libvepu/vp8e/vp8e.c
@@ -23,6 +23,35 @@
#include "vp8e_bitstream.h"
#include "../rk_vepu_debug.h"
+const int32_t vp8e_qp_tbl[2][11] = {
+ { 47, 57, 73, 93, 122, 155, 214, 294, 373, 506, 0x7FFFFFFF },
+ { 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20}};
+
+static void vp8e_init_rc(struct rk_venc *ictx)
+{
+ struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+ struct v4l2_plugin_rate_control *rc = &ictx->rc;
+
+ rc->pic_rc_en = true;
+ rc->fps_num = 30;
+ rc->fps_denom = 1;
+ rc->vb.bit_rate = 1000000;
+ rc->vb.actual_bits = 0;
+ rc->vb.time_scale = rc->fps_num;
+ rc->vb.virt_bits_cnt = 0;
+ rc->vb.bucket_fullness = 0;
+ rc->vb.pic_time_inc = 0;
+ rc->gop_len = 150;
+ rc->qp_min = 30;
+ rc->qp_max = 127;
+ rc->mb_per_pic = MB_COUNT(ctx->width) * MB_COUNT(ctx->height);
+ rc->intra_qp_delta = -3;
+ rc->qp = -1;
+ rc->initiated = false;
+
+ rk_venc_init_pic_rc(&ctx->venc.rc, vp8e_qp_tbl);
+}
+
static int vp8e_init(struct rk_venc *ictx,
struct rk_vepu_init_param *param)
{
@@ -51,6 +80,8 @@
ctx->hw_info.filter_sharpness = 0;
ctx->hw_info.filter_level = 26; /* 0 ~ 63 */
+ vp8e_init_rc(ictx);
+
ctx->priv_data = (struct vp8_hw_privdata *)calloc(1, sizeof(*ctx->priv_data));
if (ctx->priv_data == NULL) {
VPU_PLG_ERR("allocate private data buffer failed\n");
@@ -75,6 +106,8 @@
{
struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
struct rk3399_vp8e_reg_params *hw_info = &ctx->hw_info;
+ int time_inc = 1;
+ enum FRAME_TYPE frmtype = INTER_FRAME;
VPU_PLG_ENTER();
@@ -89,9 +122,13 @@
if (ctx->frm_in_gop == 0) {
hw_info->is_intra = 1;
hw_info->filter_level = 48;
+ time_inc = 0;
+ frmtype = INTRA_FRAME;
}
- hw_info->qp = 80;
+ rk_venc_before_pic_rc(&ctx->venc.rc, time_inc, frmtype);
+
+ hw_info->qp = ictx->rc.qp;
prepare_prob(&ctx->probs);
@@ -125,10 +162,12 @@
VPU_PLG_ENTER();
+ rk_venc_after_pic_rc(&ctx->venc.rc, outputStreamSize);
+
ctx->last_frm_intra = ctx->hw_info.is_intra;
ctx->frm_in_gop++;
- ctx->frm_in_gop %= 150;
+ ctx->frm_in_gop %= ictx->rc.gop_len;
ctx->frame_cnt++;
@@ -152,10 +191,33 @@
static void vp8e_apply_param(struct rk_venc *ictx)
{
struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+ struct rk_vepu_runtime_param *param = &ictx->runtime_param;
+ bool reinit = false;
assert(ctx);
- /* todo, apply parameters to rate control */
+ if (param->bitrate != 0) {
+ ctx->venc.rc.vb.bit_rate = param->bitrate;
+ reinit = true;
+ }
+
+ if (param->framerate_numer != 0 && param->framerate_denom != 0) {
+ ctx->venc.rc.fps_num = param->framerate_numer;
+ ctx->venc.rc.fps_denom = param->framerate_denom;
+ ictx->rc.vb.time_scale = param->framerate_numer;
+
+ reinit = true;
+ }
+
+ if (reinit) {
+ if (!ictx->rc.initiated) {
+ ictx->rc.qp = -1;
+ rk_venc_init_pic_rc(&ictx->rc, vp8e_qp_tbl);
+ ictx->rc.initiated = true;
+ } else {
+ rk_venc_recalc_parameter(&ictx->rc);
+ }
+ }
}
static void vp8e_get_payloads(struct rk_venc *ictx, size_t *num, uint32_t **ids,