Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+8 −9
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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];
+58 −8
Original line number Diff line number Diff line
@@ -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,
	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);