소스 검색

video: driver: add get and set selection support

Add support to get and set selection to update
crop and compose values in driver.

Change-Id: I1f38ac6a4f3ceac64d08d66f30b422efd79959a9
Signed-off-by: Maheshwar Ajja <[email protected]>
Maheshwar Ajja 4 년 전
부모
커밋
e48a514a89

+ 2 - 0
driver/vidc/inc/msm_vdec.h

@@ -16,6 +16,8 @@ int msm_vdec_start_output(struct msm_vidc_inst *inst);
 int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2);
 int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
 int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_vdec_s_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s);
+int msm_vdec_g_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s);
 int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f);
 int msm_vdec_inst_init(struct msm_vidc_inst *inst);
 int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst);

+ 2 - 0
driver/vidc/inc/msm_venc.h

@@ -16,6 +16,8 @@ int msm_venc_start_output(struct msm_vidc_inst *inst);
 int msm_venc_process_cmd(struct msm_vidc_inst *inst, u32 cmd);
 int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
 int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f);
+int msm_venc_s_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s);
+int msm_venc_g_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s);
 int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f);
 int msm_venc_inst_init(struct msm_vidc_inst *inst);
 

+ 2 - 0
driver/vidc/inc/msm_vidc.h

@@ -21,6 +21,8 @@ int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
 int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
 int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
 int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_s_selection(void* instance, struct v4l2_selection* s);
+int msm_vidc_g_selection(void* instance, struct v4l2_selection* s);
 int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
 int msm_vidc_g_ext_ctrl(void *instance, struct v4l2_ext_controls *a);

+ 2 - 1
driver/vidc/inc/msm_vidc_inst.h

@@ -100,7 +100,8 @@ struct msm_vidc_inst {
 	struct msm_vidc_inst_cap_entry     firmware;
 	bool                               request;
 	struct vb2_queue                   vb2q[MAX_PORT];
-	struct msm_vidc_crop               crop;
+	struct msm_vidc_rectangle          crop;
+	struct msm_vidc_rectangle          compose;
 	struct msm_vidc_properties         prop;
 	enum msm_vidc_stage_type           stage;
 	enum msm_vidc_pipe_type            pipe;

+ 1 - 1
driver/vidc/inc/msm_vidc_internal.h

@@ -545,7 +545,7 @@ struct msm_vidc_color_info {
 	u32 quantization;
 };
 
-struct msm_vidc_crop {
+struct msm_vidc_rectangle {
 	u32 left;
 	u32 top;
 	u32 width;

+ 4 - 0
driver/vidc/inc/msm_vidc_v4l2.h

@@ -22,6 +22,10 @@ int msm_v4l2_s_fmt(struct file *file, void *fh,
 		struct v4l2_format *f);
 int msm_v4l2_g_fmt(struct file *file, void *fh,
 		struct v4l2_format *f);
+int msm_v4l2_s_selection(struct file* file, void* fh,
+		struct v4l2_selection* s);
+int msm_v4l2_g_selection(struct file* file, void* fh,
+		struct v4l2_selection* s);
 int msm_v4l2_s_ctrl(struct file *file, void *fh,
 		struct v4l2_control *a);
 int msm_v4l2_g_ctrl(struct file *file, void *fh,

+ 39 - 2
driver/vidc/src/msm_vdec.c

@@ -5,6 +5,7 @@
 
 #include <media/v4l2_vidc_extensions.h>
 #include <media/msm_media_info.h>
+#include <linux/v4l2-common.h>
 
 #include "msm_vdec.h"
 #include "msm_vidc_core.h"
@@ -1477,7 +1478,6 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 	struct msm_vidc_core *core;
 	struct v4l2_format *fmt;
 
-	d_vpr_h("%s()\n", __func__);
 	if (!inst || !inst->core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
@@ -1652,7 +1652,6 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 	int rc = 0;
 	int port;
 
-	d_vpr_h("%s()\n", __func__);
 	if (!inst) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
@@ -1667,6 +1666,44 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 	return rc;
 }
 
+int msm_vdec_s_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s)
+{
+	if (!inst || !s) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	s_vpr_e(inst->sid, "%s: unsupported\n", __func__);
+	return -EINVAL;
+}
+
+int msm_vdec_g_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s)
+{
+	if (!inst || !s) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+	default:
+		s->r.left = inst->crop.left;
+		s->r.top = inst->crop.top;
+		s->r.width = inst->crop.width;
+		s->r.height = inst->crop.height;
+		break;
+	}
+	s_vpr_h(inst->sid, "%s: type %d target %d, r [%d, %d, %d, %d]\n",
+		__func__, s->type, s->target, s->r.top, s->r.left,
+		s->r.width, s->r.height);
+	return 0;
+}
+
 int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
 {
 	int rc = 0;

+ 180 - 20
driver/vidc/src/msm_venc.c

@@ -877,6 +877,7 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 	int rc = 0;
 	struct msm_vidc_core *core;
 	struct v4l2_format *fmt;
+	u32 codec_align;
 
 	d_vpr_h("%s()\n", __func__);
 	if (!inst || !inst->core) {
@@ -899,12 +900,10 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 		fmt->type = INPUT_MPLANE;
 		fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat;
 		fmt->fmt.pix_mp.width = VENUS_Y_STRIDE(
-			v4l2_colorformat_to_media(fmt->fmt.pix_mp.pixelformat,
-			__func__),
+			v4l2_colorformat_to_media(fmt->fmt.pix_mp.pixelformat, __func__),
 			f->fmt.pix_mp.width);
 		fmt->fmt.pix_mp.height = VENUS_Y_SCANLINES(
-			v4l2_colorformat_to_media(fmt->fmt.pix_mp.pixelformat,
-			__func__),
+			v4l2_colorformat_to_media(fmt->fmt.pix_mp.pixelformat, __func__),
 			f->fmt.pix_mp.height);
 
 		fmt->fmt.pix_mp.num_planes = 1;
@@ -926,6 +925,33 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 		inst->buffers.input.size =
 			fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
 
+		codec_align = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat ==
+			V4L2_PIX_FMT_HEVC ? 32 : 16;
+		/* check if resolution changed */
+		if (inst->fmts[OUTPUT_PORT].fmt.pix_mp.width !=
+				ALIGN(f->fmt.pix_mp.width, codec_align) ||
+			inst->fmts[OUTPUT_PORT].fmt.pix_mp.height !=
+				ALIGN(f->fmt.pix_mp.height, codec_align)) {
+			/* reset bitstream port with updated resolution */
+			inst->fmts[OUTPUT_PORT].fmt.pix_mp.width =
+				ALIGN(f->fmt.pix_mp.width, codec_align);
+			inst->fmts[OUTPUT_PORT].fmt.pix_mp.height =
+				ALIGN(f->fmt.pix_mp.height, codec_align);
+			inst->fmts[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage =
+				call_session_op(core, buffer_size,
+					inst, MSM_VIDC_BUF_OUTPUT);
+
+			/* reset crop dimensions with updated resolution */
+			inst->crop.top = inst->crop.left = 0;
+			inst->crop.width = f->fmt.pix_mp.width;
+			inst->crop.height = f->fmt.pix_mp.height;
+
+			/* reset compose dimensions with updated resolution */
+			inst->compose.top = inst->crop.left = 0;
+			inst->compose.width = f->fmt.pix_mp.width;
+			inst->compose.height = f->fmt.pix_mp.height;
+		}
+
 		//rc = msm_vidc_check_session_supported(inst);
 		if (rc)
 			goto err_invalid_fmt;
@@ -979,17 +1005,12 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 				goto err_invalid_fmt;
 		}
 		fmt->type = OUTPUT_MPLANE;
-		if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_HEVC) {
-			fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width,
-					H265_BITSTREM_ALIGNMENT);
-			fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height,
-					H265_BITSTREM_ALIGNMENT);
-		} else {
-			fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width,
-					DEFAULT_BITSTREM_ALIGNMENT);
-			fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height,
-					DEFAULT_BITSTREM_ALIGNMENT);
-		}
+
+		codec_align = f->fmt.pix_mp.pixelformat ==
+				V4L2_PIX_FMT_HEVC ? 32 : 16;
+		/* width, height is readonly for client */
+		fmt->fmt.pix_mp.width = ALIGN(inst->crop.width, codec_align);
+		fmt->fmt.pix_mp.height = ALIGN(inst->crop.height, codec_align);
 		fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat;
 		fmt->fmt.pix_mp.num_planes = 1;
 		fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
@@ -1013,11 +1034,6 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 		if (rc)
 			goto err_invalid_fmt;
 
-		/* update crop dimensions */
-		inst->crop.left = inst->crop.top = 0;
-		inst->crop.width = f->fmt.pix_mp.width;
-		inst->crop.height = f->fmt.pix_mp.height;
-
 		//update_log_ctxt(inst->sid, inst->session_type,
 		//	mplane->pixelformat);
 
@@ -1080,6 +1096,150 @@ int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 	return rc;
 }
 
+int msm_venc_s_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s)
+{
+	int rc = 0;
+	u32 codec_align;
+
+	if (!inst || !s) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	if (s->type != INPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		s_vpr_e(inst->sid, "%s: invalid type %d\n", __func__, s->type);
+		return -EINVAL;
+	}
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP:
+		codec_align = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat ==
+			V4L2_PIX_FMT_HEVC ? 32 : 16;
+		if (s->r.left || s->r.top) {
+			s_vpr_h(inst->sid, "%s: unsupported top %d or left %d\n",
+				__func__, s->r.left, s->r.top);
+			s->r.left = s->r.top = 0;
+		}
+		if (s->r.width > inst->fmts[OUTPUT_PORT].fmt.pix_mp.width ||
+			ALIGN(s->r.width, codec_align) != inst->fmts[OUTPUT_PORT].fmt.pix_mp.width) {
+			s_vpr_h(inst->sid, "%s: unsupported width %d, fmt width %d\n",
+				__func__, s->r.width,
+				inst->fmts[OUTPUT_PORT].fmt.pix_mp.width);
+			s->r.width = inst->fmts[OUTPUT_PORT].fmt.pix_mp.width;
+		}
+		if (s->r.height > inst->fmts[OUTPUT_PORT].fmt.pix_mp.height ||
+			ALIGN(s->r.height, codec_align) != inst->fmts[OUTPUT_PORT].fmt.pix_mp.height) {
+			s_vpr_h(inst->sid, "%s: unsupported height %d, fmt height %d\n",
+				__func__, s->r.height,
+				inst->fmts[OUTPUT_PORT].fmt.pix_mp.height);
+			s->r.height = inst->fmts[OUTPUT_PORT].fmt.pix_mp.height;
+		}
+
+		inst->crop.left = s->r.left;
+		inst->crop.top = s->r.top;
+		inst->crop.width = s->r.width;
+		inst->crop.height = s->r.height;
+		/* adjust compose such that it is within crop */
+		if (inst->compose.left < inst->crop.left)
+			inst->compose.left = inst->crop.left;
+		if (inst->compose.top < inst->crop.top)
+			inst->compose.top = inst->crop.top;
+		if (inst->compose.width > inst->crop.width)
+			inst->compose.width = inst->crop.width;
+		if (inst->compose.height > inst->crop.height)
+			inst->compose.height = inst->crop.height;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+		if (s->r.left < inst->crop.left) {
+			s_vpr_e(inst->sid,
+				"%s: compose left (%d) less than crop left (%d)\n",
+				__func__, s->r.left, inst->crop.left);
+			s->r.left = inst->crop.left;
+		}
+		if (s->r.top < inst->crop.top) {
+			s_vpr_e(inst->sid,
+				"%s: compose top (%d) less than crop top (%d)\n",
+				__func__, s->r.top, inst->crop.top);
+			s->r.top = inst->crop.top;
+		}
+		if (s->r.width > inst->crop.width) {
+			s_vpr_e(inst->sid,
+				"%s: compose width (%d) greate than crop width (%d)\n",
+				__func__, s->r.width, inst->crop.width);
+			s->r.width = inst->crop.width;
+		}
+		if (s->r.height > inst->crop.height) {
+			s_vpr_e(inst->sid,
+				"%s: compose height (%d) greate than crop height (%d)\n",
+				__func__, s->r.height, inst->crop.height);
+			s->r.height = inst->crop.height;
+		}
+		inst->compose.left = s->r.left;
+		inst->compose.top = s->r.top;
+		inst->compose.width = s->r.width;
+		inst->compose.height= s->r.height;
+		break;
+	default:
+		s_vpr_e(inst->sid, "%s: invalid target %d\n",
+				__func__, s->target);
+		rc = -EINVAL;
+		break;
+	}
+	if (!rc)
+		s_vpr_h(inst->sid, "%s: target %d, r [%d, %d, %d, %d]\n",
+			__func__, s->target, s->r.top, s->r.left,
+			s->r.width, s->r.height);
+	return rc;
+}
+
+int msm_venc_g_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s)
+{
+	int rc = 0;
+
+	if (!inst || !s) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+	if (s->type != INPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		s_vpr_e(inst->sid, "%s: invalid type %d\n", __func__, s->type);
+		return -EINVAL;
+	}
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP:
+		s->r.left = inst->crop.left;
+		s->r.top = inst->crop.top;
+		s->r.width = inst->crop.width;
+		s->r.height = inst->crop.height;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+		s->r.left = inst->compose.left;
+		s->r.top = inst->compose.top;
+		s->r.width = inst->compose.width;
+		s->r.height = inst->compose.height;
+		break;
+	default:
+		s_vpr_e(inst->sid, "%s: invalid target %d\n",
+			__func__, s->target);
+		rc = -EINVAL;
+		break;
+	}
+	if (!rc)
+		s_vpr_h(inst->sid, "%s: target %d, r [%d, %d, %d, %d]\n",
+			__func__, s->target, s->r.top, s->r.left,
+			s->r.width, s->r.height);
+	return rc;
+}
+
 int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
 {
 	int rc = 0;

+ 38 - 0
driver/vidc/src/msm_vidc.c

@@ -266,6 +266,44 @@ int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
 }
 EXPORT_SYMBOL(msm_vidc_g_fmt);
 
+int msm_vidc_s_selection(void* instance, struct v4l2_selection* s)
+{
+	int rc = 0;
+	struct msm_vidc_inst* inst = instance;
+
+	if (!inst || !s) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_s_selection(inst, s);
+	if (is_encode_session(inst))
+		rc = msm_venc_s_selection(inst, s);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_s_selection);
+
+int msm_vidc_g_selection(void* instance, struct v4l2_selection* s)
+{
+	int rc = 0;
+	struct msm_vidc_inst* inst = instance;
+
+	if (!inst || !s) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (is_decode_session(inst))
+		rc = msm_vdec_g_selection(inst, s);
+	if (is_encode_session(inst))
+		rc = msm_venc_g_selection(inst, s);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_g_selection);
+
 int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
 {
 	struct msm_vidc_inst *inst = instance;

+ 2 - 0
driver/vidc/src/msm_vidc_platform.c

@@ -39,6 +39,8 @@ static struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
 	.vidioc_g_fmt_vid_out_mplane    = msm_v4l2_g_fmt,
 	.vidioc_g_fmt_meta_out          = msm_v4l2_g_fmt,
 	.vidioc_g_fmt_meta_cap          = msm_v4l2_g_fmt,
+	.vidioc_g_selection             = msm_v4l2_g_selection,
+	.vidioc_s_selection             = msm_v4l2_s_selection,
 	.vidioc_reqbufs                 = msm_v4l2_reqbufs,
 	.vidioc_qbuf                    = msm_v4l2_qbuf,
 	.vidioc_dqbuf                   = msm_v4l2_dqbuf,

+ 16 - 0
driver/vidc/src/msm_vidc_v4l2.c

@@ -88,6 +88,22 @@ int msm_v4l2_g_fmt(struct file *file, void *fh,
 	return msm_vidc_g_fmt((void *)vidc_inst, f);
 }
 
+int msm_v4l2_s_selection(struct file* file, void* fh,
+					struct v4l2_selection* s)
+{
+	struct msm_vidc_inst* vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_s_selection((void*)vidc_inst, s);
+}
+
+int msm_v4l2_g_selection(struct file* file, void* fh,
+					struct v4l2_selection* s)
+{
+	struct msm_vidc_inst* vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_g_selection((void*)vidc_inst, s);
+}
+
 int msm_v4l2_s_ctrl(struct file *file, void *fh,
 					struct v4l2_control *a)
 {