diff --git a/driver/vidc/inc/msm_vdec.h b/driver/vidc/inc/msm_vdec.h index cd9c631a11..ffe3471c12 100644 --- a/driver/vidc/inc/msm_vdec.h +++ b/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); diff --git a/driver/vidc/inc/msm_venc.h b/driver/vidc/inc/msm_venc.h index 05d2794448..11efcd853b 100644 --- a/driver/vidc/inc/msm_venc.h +++ b/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); diff --git a/driver/vidc/inc/msm_vidc.h b/driver/vidc/inc/msm_vidc.h index ba432ed066..ede165d584 100644 --- a/driver/vidc/inc/msm_vidc.h +++ b/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); diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index 350bf3c4c6..8e9248ccfa 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/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; diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 019185413e..d0a396809d 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/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; diff --git a/driver/vidc/inc/msm_vidc_v4l2.h b/driver/vidc/inc/msm_vidc_v4l2.h index 63ed122365..0cd9ecdefc 100644 --- a/driver/vidc/inc/msm_vidc_v4l2.h +++ b/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, diff --git a/driver/vidc/src/msm_vdec.c b/driver/vidc/src/msm_vdec.c index a1c8ae7331..bc65738752 100644 --- a/driver/vidc/src/msm_vdec.c +++ b/driver/vidc/src/msm_vdec.c @@ -5,6 +5,7 @@ #include #include +#include #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; diff --git a/driver/vidc/src/msm_venc.c b/driver/vidc/src/msm_venc.c index 5f3473dba8..9a390c8591 100644 --- a/driver/vidc/src/msm_venc.c +++ b/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; diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index 36899dfea4..6c77b18b4b 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/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; diff --git a/driver/vidc/src/msm_vidc_platform.c b/driver/vidc/src/msm_vidc_platform.c index cb32c4fc2d..fcb69eb38b 100644 --- a/driver/vidc/src/msm_vidc_platform.c +++ b/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, diff --git a/driver/vidc/src/msm_vidc_v4l2.c b/driver/vidc/src/msm_vidc_v4l2.c index e40738f78d..d5f15f22da 100644 --- a/driver/vidc/src/msm_vidc_v4l2.c +++ b/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) {