media: vicodec: add QP controls
Instead of hardcoding the quantization parameter (or 'DEADZONE_WIDTH' as it was called in the codec) make this configurable through two controls: one for I frames, one for P frames. Also allow changing these parameters and the GOP_SIZE parameter while streaming. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
parent
3799eca51c
commit
48568b0c30
|
@ -13,7 +13,6 @@
|
|||
#include "vicodec-codec.h"
|
||||
|
||||
#define ALL_ZEROS 15
|
||||
#define DEADZONE_WIDTH 20
|
||||
|
||||
static const uint8_t zigzag[64] = {
|
||||
0,
|
||||
|
@ -164,7 +163,7 @@ static const int quant_table_p[] = {
|
|||
3, 3, 3, 6, 6, 9, 9, 10,
|
||||
};
|
||||
|
||||
static void quantize_intra(s16 *coeff, s16 *de_coeff)
|
||||
static void quantize_intra(s16 *coeff, s16 *de_coeff, u16 qp)
|
||||
{
|
||||
const int *quant = quant_table;
|
||||
int i, j;
|
||||
|
@ -172,8 +171,7 @@ static void quantize_intra(s16 *coeff, s16 *de_coeff)
|
|||
for (j = 0; j < 8; j++) {
|
||||
for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) {
|
||||
*coeff >>= *quant;
|
||||
if (*coeff >= -DEADZONE_WIDTH &&
|
||||
*coeff <= DEADZONE_WIDTH)
|
||||
if (*coeff >= -qp && *coeff <= qp)
|
||||
*coeff = *de_coeff = 0;
|
||||
else
|
||||
*de_coeff = *coeff << *quant;
|
||||
|
@ -191,7 +189,7 @@ static void dequantize_intra(s16 *coeff)
|
|||
*coeff <<= *quant;
|
||||
}
|
||||
|
||||
static void quantize_inter(s16 *coeff, s16 *de_coeff)
|
||||
static void quantize_inter(s16 *coeff, s16 *de_coeff, u16 qp)
|
||||
{
|
||||
const int *quant = quant_table_p;
|
||||
int i, j;
|
||||
|
@ -199,8 +197,7 @@ static void quantize_inter(s16 *coeff, s16 *de_coeff)
|
|||
for (j = 0; j < 8; j++) {
|
||||
for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) {
|
||||
*coeff >>= *quant;
|
||||
if (*coeff >= -DEADZONE_WIDTH &&
|
||||
*coeff <= DEADZONE_WIDTH)
|
||||
if (*coeff >= -qp && *coeff <= qp)
|
||||
*coeff = *de_coeff = 0;
|
||||
else
|
||||
*de_coeff = *coeff << *quant;
|
||||
|
@ -639,13 +636,15 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
|
|||
deltablock, width, input_step);
|
||||
if (is_intra || blocktype == IBLOCK) {
|
||||
fwht(input, cf->coeffs, width, input_step, 1);
|
||||
quantize_intra(cf->coeffs, cf->de_coeffs);
|
||||
quantize_intra(cf->coeffs, cf->de_coeffs,
|
||||
cf->i_frame_qp);
|
||||
blocktype = IBLOCK;
|
||||
} else {
|
||||
/* inter code */
|
||||
encoding |= FRAME_PCODED;
|
||||
fwht16(deltablock, cf->coeffs, 8, 0);
|
||||
quantize_inter(cf->coeffs, cf->de_coeffs);
|
||||
quantize_inter(cf->coeffs, cf->de_coeffs,
|
||||
cf->p_frame_qp);
|
||||
}
|
||||
if (!next_is_intra) {
|
||||
ifwht(cf->de_coeffs, cf->de_fwht, blocktype);
|
||||
|
|
|
@ -103,6 +103,8 @@ struct cframe_hdr {
|
|||
|
||||
struct cframe {
|
||||
unsigned int width, height;
|
||||
u16 i_frame_qp;
|
||||
u16 p_frame_qp;
|
||||
__be16 *rlc_data;
|
||||
s16 coeffs[8 * 8];
|
||||
s16 de_coeffs[8 * 8];
|
||||
|
|
|
@ -96,9 +96,10 @@ struct vicodec_ctx {
|
|||
spinlock_t *lock;
|
||||
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
struct v4l2_ctrl *ctrl_gop_size;
|
||||
unsigned int gop_size;
|
||||
unsigned int gop_cnt;
|
||||
u16 i_frame_qp;
|
||||
u16 p_frame_qp;
|
||||
|
||||
/* Abort requested by m2m */
|
||||
int aborting;
|
||||
|
@ -191,13 +192,15 @@ static void encode(struct vicodec_ctx *ctx,
|
|||
|
||||
cf.width = q_data->width;
|
||||
cf.height = q_data->height;
|
||||
cf.i_frame_qp = ctx->i_frame_qp;
|
||||
cf.p_frame_qp = ctx->p_frame_qp;
|
||||
cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
|
||||
|
||||
encoding = encode_frame(&rf, &ctx->ref_frame, &cf, !ctx->gop_cnt,
|
||||
ctx->gop_cnt == ctx->gop_size - 1);
|
||||
if (encoding != FRAME_PCODED)
|
||||
ctx->gop_cnt = 0;
|
||||
if (++ctx->gop_cnt == ctx->gop_size)
|
||||
if (++ctx->gop_cnt >= ctx->gop_size)
|
||||
ctx->gop_cnt = 0;
|
||||
|
||||
p_hdr = (struct cframe_hdr *)p_out;
|
||||
|
@ -1140,8 +1143,6 @@ static int vicodec_start_streaming(struct vb2_queue *q,
|
|||
ctx->ref_frame.cr = ctx->ref_frame.cb + size / 4;
|
||||
ctx->last_src_buf = NULL;
|
||||
ctx->last_dst_buf = NULL;
|
||||
v4l2_ctrl_grab(ctx->ctrl_gop_size, true);
|
||||
ctx->gop_size = v4l2_ctrl_g_ctrl(ctx->ctrl_gop_size);
|
||||
ctx->gop_cnt = 0;
|
||||
ctx->cur_buf_offset = 0;
|
||||
ctx->comp_size = 0;
|
||||
|
@ -1162,7 +1163,6 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
|
|||
|
||||
kvfree(ctx->ref_frame.luma);
|
||||
kvfree(ctx->compressed_frame);
|
||||
v4l2_ctrl_grab(ctx->ctrl_gop_size, false);
|
||||
}
|
||||
|
||||
static const struct vb2_ops vicodec_qops = {
|
||||
|
@ -1211,6 +1211,55 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
|
|||
return vb2_queue_init(dst_vq);
|
||||
}
|
||||
|
||||
#define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000)
|
||||
#define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0)
|
||||
#define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1)
|
||||
|
||||
static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct vicodec_ctx *ctx = container_of(ctrl->handler,
|
||||
struct vicodec_ctx, hdl);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
|
||||
ctx->gop_size = ctrl->val;
|
||||
return 0;
|
||||
case VICODEC_CID_I_FRAME_QP:
|
||||
ctx->i_frame_qp = ctrl->val;
|
||||
return 0;
|
||||
case VICODEC_CID_P_FRAME_QP:
|
||||
ctx->p_frame_qp = ctrl->val;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
|
||||
.s_ctrl = vicodec_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
|
||||
.ops = &vicodec_ctrl_ops,
|
||||
.id = VICODEC_CID_I_FRAME_QP,
|
||||
.name = "FWHT I-Frame QP Value",
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.min = 1,
|
||||
.max = 31,
|
||||
.def = 20,
|
||||
.step = 1,
|
||||
};
|
||||
|
||||
static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
|
||||
.ops = &vicodec_ctrl_ops,
|
||||
.id = VICODEC_CID_P_FRAME_QP,
|
||||
.name = "FWHT P-Frame QP Value",
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.min = 1,
|
||||
.max = 31,
|
||||
.def = 20,
|
||||
.step = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* File operations
|
||||
*/
|
||||
|
@ -1239,9 +1288,10 @@ static int vicodec_open(struct file *file)
|
|||
ctx->dev = dev;
|
||||
hdl = &ctx->hdl;
|
||||
v4l2_ctrl_handler_init(hdl, 4);
|
||||
ctx->ctrl_gop_size = v4l2_ctrl_new_std(hdl, NULL,
|
||||
V4L2_CID_MPEG_VIDEO_GOP_SIZE,
|
||||
1, 16, 1, 10);
|
||||
v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
|
||||
1, 16, 1, 10);
|
||||
v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
|
||||
v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
|
||||
if (hdl->error) {
|
||||
rc = hdl->error;
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
|
|
Loading…
Reference in New Issue