Commit 48568b0c authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

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: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 3799eca5
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "vicodec-codec.h" #include "vicodec-codec.h"
#define ALL_ZEROS 15 #define ALL_ZEROS 15
#define DEADZONE_WIDTH 20
static const uint8_t zigzag[64] = { static const uint8_t zigzag[64] = {
0, 0,
...@@ -164,7 +163,7 @@ static const int quant_table_p[] = { ...@@ -164,7 +163,7 @@ static const int quant_table_p[] = {
3, 3, 3, 6, 6, 9, 9, 10, 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; const int *quant = quant_table;
int i, j; int i, j;
...@@ -172,8 +171,7 @@ static void quantize_intra(s16 *coeff, s16 *de_coeff) ...@@ -172,8 +171,7 @@ static void quantize_intra(s16 *coeff, s16 *de_coeff)
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) { for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) {
*coeff >>= *quant; *coeff >>= *quant;
if (*coeff >= -DEADZONE_WIDTH && if (*coeff >= -qp && *coeff <= qp)
*coeff <= DEADZONE_WIDTH)
*coeff = *de_coeff = 0; *coeff = *de_coeff = 0;
else else
*de_coeff = *coeff << *quant; *de_coeff = *coeff << *quant;
...@@ -191,7 +189,7 @@ static void dequantize_intra(s16 *coeff) ...@@ -191,7 +189,7 @@ static void dequantize_intra(s16 *coeff)
*coeff <<= *quant; *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; const int *quant = quant_table_p;
int i, j; int i, j;
...@@ -199,8 +197,7 @@ static void quantize_inter(s16 *coeff, s16 *de_coeff) ...@@ -199,8 +197,7 @@ static void quantize_inter(s16 *coeff, s16 *de_coeff)
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) { for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) {
*coeff >>= *quant; *coeff >>= *quant;
if (*coeff >= -DEADZONE_WIDTH && if (*coeff >= -qp && *coeff <= qp)
*coeff <= DEADZONE_WIDTH)
*coeff = *de_coeff = 0; *coeff = *de_coeff = 0;
else else
*de_coeff = *coeff << *quant; *de_coeff = *coeff << *quant;
...@@ -639,13 +636,15 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, ...@@ -639,13 +636,15 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
deltablock, width, input_step); deltablock, width, input_step);
if (is_intra || blocktype == IBLOCK) { if (is_intra || blocktype == IBLOCK) {
fwht(input, cf->coeffs, width, input_step, 1); 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; blocktype = IBLOCK;
} else { } else {
/* inter code */ /* inter code */
encoding |= FRAME_PCODED; encoding |= FRAME_PCODED;
fwht16(deltablock, cf->coeffs, 8, 0); 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) { if (!next_is_intra) {
ifwht(cf->de_coeffs, cf->de_fwht, blocktype); ifwht(cf->de_coeffs, cf->de_fwht, blocktype);
......
...@@ -103,6 +103,8 @@ struct cframe_hdr { ...@@ -103,6 +103,8 @@ struct cframe_hdr {
struct cframe { struct cframe {
unsigned int width, height; unsigned int width, height;
u16 i_frame_qp;
u16 p_frame_qp;
__be16 *rlc_data; __be16 *rlc_data;
s16 coeffs[8 * 8]; s16 coeffs[8 * 8];
s16 de_coeffs[8 * 8]; s16 de_coeffs[8 * 8];
......
...@@ -96,9 +96,10 @@ struct vicodec_ctx { ...@@ -96,9 +96,10 @@ struct vicodec_ctx {
spinlock_t *lock; spinlock_t *lock;
struct v4l2_ctrl_handler hdl; struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *ctrl_gop_size;
unsigned int gop_size; unsigned int gop_size;
unsigned int gop_cnt; unsigned int gop_cnt;
u16 i_frame_qp;
u16 p_frame_qp;
/* Abort requested by m2m */ /* Abort requested by m2m */
int aborting; int aborting;
...@@ -191,13 +192,15 @@ static void encode(struct vicodec_ctx *ctx, ...@@ -191,13 +192,15 @@ static void encode(struct vicodec_ctx *ctx,
cf.width = q_data->width; cf.width = q_data->width;
cf.height = q_data->height; 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)); cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
encoding = encode_frame(&rf, &ctx->ref_frame, &cf, !ctx->gop_cnt, encoding = encode_frame(&rf, &ctx->ref_frame, &cf, !ctx->gop_cnt,
ctx->gop_cnt == ctx->gop_size - 1); ctx->gop_cnt == ctx->gop_size - 1);
if (encoding != FRAME_PCODED) if (encoding != FRAME_PCODED)
ctx->gop_cnt = 0; ctx->gop_cnt = 0;
if (++ctx->gop_cnt == ctx->gop_size) if (++ctx->gop_cnt >= ctx->gop_size)
ctx->gop_cnt = 0; ctx->gop_cnt = 0;
p_hdr = (struct cframe_hdr *)p_out; p_hdr = (struct cframe_hdr *)p_out;
...@@ -1140,8 +1143,6 @@ static int vicodec_start_streaming(struct vb2_queue *q, ...@@ -1140,8 +1143,6 @@ static int vicodec_start_streaming(struct vb2_queue *q,
ctx->ref_frame.cr = ctx->ref_frame.cb + size / 4; ctx->ref_frame.cr = ctx->ref_frame.cb + size / 4;
ctx->last_src_buf = NULL; ctx->last_src_buf = NULL;
ctx->last_dst_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->gop_cnt = 0;
ctx->cur_buf_offset = 0; ctx->cur_buf_offset = 0;
ctx->comp_size = 0; ctx->comp_size = 0;
...@@ -1162,7 +1163,6 @@ static void vicodec_stop_streaming(struct vb2_queue *q) ...@@ -1162,7 +1163,6 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
kvfree(ctx->ref_frame.luma); kvfree(ctx->ref_frame.luma);
kvfree(ctx->compressed_frame); kvfree(ctx->compressed_frame);
v4l2_ctrl_grab(ctx->ctrl_gop_size, false);
} }
static const struct vb2_ops vicodec_qops = { static const struct vb2_ops vicodec_qops = {
...@@ -1211,6 +1211,55 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, ...@@ -1211,6 +1211,55 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
return vb2_queue_init(dst_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 * File operations
*/ */
...@@ -1239,9 +1288,10 @@ static int vicodec_open(struct file *file) ...@@ -1239,9 +1288,10 @@ static int vicodec_open(struct file *file)
ctx->dev = dev; ctx->dev = dev;
hdl = &ctx->hdl; hdl = &ctx->hdl;
v4l2_ctrl_handler_init(hdl, 4); v4l2_ctrl_handler_init(hdl, 4);
ctx->ctrl_gop_size = v4l2_ctrl_new_std(hdl, NULL, v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1, 16, 1, 10); 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) { if (hdl->error) {
rc = hdl->error; rc = hdl->error;
v4l2_ctrl_handler_free(hdl); v4l2_ctrl_handler_free(hdl);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment