msm: vidc: Add support for encoder scaling
Venus FW supports upscaling and downscaling for encoder.
The supported scaling ratios are returned from Venus FW
as part of session_init_done message. Driver needs to
make sure that the scaling ratios are within the range.
This change adds the scaling support for encoder.
Change-Id: Ibf158cf35e93c45dd89715845a549871146a8eea
Signed-off-by: Praneeth Paladugu <ppaladug@codeaurora.org>
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 5e7c84c..3582d78 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -690,8 +690,8 @@
f->fmt.pix_mp.pixelformat = fmt->fourcc;
f->fmt.pix_mp.num_planes = fmt->num_planes;
if (inst->in_reconfig == true) {
- inst->prop.height = inst->reconfig_height;
- inst->prop.width = inst->reconfig_width;
+ inst->prop.height[CAPTURE_PORT] = inst->reconfig_height;
+ inst->prop.width[CAPTURE_PORT] = inst->reconfig_width;
rc = msm_vidc_check_session_supported(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -699,13 +699,13 @@
goto exit;
}
}
- f->fmt.pix_mp.height = inst->prop.height;
- f->fmt.pix_mp.width = inst->prop.width;
- stride = inst->prop.width;
- scanlines = inst->prop.height;
+ f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
+ f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
+ stride = inst->prop.width[CAPTURE_PORT];
+ scanlines = inst->prop.height[CAPTURE_PORT];
frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
- frame_sz.width = inst->prop.width;
- frame_sz.height = inst->prop.height;
+ frame_sz.width = inst->prop.width[CAPTURE_PORT];
+ frame_sz.height = inst->prop.height[CAPTURE_PORT];
dprintk(VIDC_DBG, "width = %d, height = %d\n",
frame_sz.width, frame_sz.height);
rc = msm_comm_try_get_bufreqs(inst);
@@ -724,7 +724,8 @@
case V4L2_PIX_FMT_NV12:
call_hfi_op(hdev, get_stride_scanline,
COLOR_FMT_NV12,
- inst->prop.width, inst->prop.height,
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
&stride, &scanlines);
break;
default:
@@ -764,9 +765,9 @@
(__u16)scanlines;
} else {
f->fmt.pix_mp.plane_fmt[0].bytesperline =
- (__u16)inst->prop.width;
+ (__u16)inst->prop.width[CAPTURE_PORT];
f->fmt.pix_mp.plane_fmt[0].reserved[0] =
- (__u16)inst->prop.height;
+ (__u16)inst->prop.height[CAPTURE_PORT];
}
} else {
dprintk(VIDC_ERR,
@@ -852,6 +853,10 @@
rc = -EINVAL;
goto err_invalid_fmt;
}
+ inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
inst->fmts[fmt->type] = fmt;
ret = ret || msm_comm_try_get_bufreqs(inst);
if (ret) {
@@ -888,8 +893,10 @@
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- inst->prop.width = f->fmt.pix_mp.width;
- inst->prop.height = f->fmt.pix_mp.height;
+ inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+ inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
rc = msm_vidc_check_session_supported(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -914,8 +921,8 @@
goto err_invalid_fmt;
}
frame_sz.buffer_type = HAL_BUFFER_INPUT;
- frame_sz.width = inst->prop.width;
- frame_sz.height = inst->prop.height;
+ frame_sz.width = inst->prop.width[OUTPUT_PORT];
+ frame_sz.height = inst->prop.height[OUTPUT_PORT];
msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
max_input_size = fmt->get_frame_size(0,
@@ -1096,6 +1103,13 @@
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
inst->in_reconfig = false;
+ if (inst->capability.pixelprocess_capabilities &
+ HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)
+ rc = msm_comm_check_scaling_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR, "H/w scaling is not in valid range");
+ return -EINVAL;
+ }
rc = msm_comm_set_scratch_buffers(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -1313,8 +1327,10 @@
}
inst->fmts[OUTPUT_PORT] = &vdec_formats[1];
inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
- inst->prop.height = DEFAULT_HEIGHT;
- inst->prop.width = DEFAULT_WIDTH;
+ inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+ inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+ inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+ inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
inst->capability.height.max = DEFAULT_HEIGHT;
inst->capability.width.min = MIN_SUPPORTED_WIDTH;
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 3236b4a..240b18a 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -844,7 +844,8 @@
inst->fmts[CAPTURE_PORT]->num_planes = *num_planes;
for (i = 0; i < *num_planes; i++) {
sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
- i, inst->prop.height, inst->prop.width);
+ i, inst->prop.height[CAPTURE_PORT],
+ inst->prop.width[CAPTURE_PORT]);
}
property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
@@ -864,6 +865,8 @@
"Failed to get buffer requirements: %d\n", rc);
break;
}
+ inst->capability.pixelprocess_capabilities =
+ call_hfi_op(hdev, get_core_capabilities);
*num_planes = 1;
mutex_lock(&inst->lock);
*num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
@@ -881,7 +884,8 @@
inst->buff_req.buffer[0].buffer_count_actual);
for (i = 0; i < *num_planes; i++) {
sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
- i, inst->prop.height, inst->prop.width);
+ i, inst->prop.height[OUTPUT_PORT],
+ inst->prop.width[OUTPUT_PORT]);
}
break;
default:
@@ -897,7 +901,13 @@
int rc = 0;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
-
+ if (inst->capability.pixelprocess_capabilities &
+ HAL_VIDEO_ENCODER_SCALING_CAPABILITY)
+ rc = msm_comm_check_scaling_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR, "H/w scaling is not in valid range");
+ return -EINVAL;
+ }
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -1985,8 +1995,10 @@
}
inst->fmts[CAPTURE_PORT] = &venc_formats[1];
inst->fmts[OUTPUT_PORT] = &venc_formats[0];
- inst->prop.height = DEFAULT_HEIGHT;
- inst->prop.width = DEFAULT_WIDTH;
+ inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+ inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+ inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+ inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
inst->prop.fps = 15;
inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
@@ -2186,14 +2198,20 @@
rc = -EINVAL;
goto exit;
}
- inst->prop.width = f->fmt.pix_mp.width;
- inst->prop.height = f->fmt.pix_mp.height;
+ inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+ rc = msm_vidc_check_session_supported(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: session not supported\n", __func__);
+ goto exit;
+ }
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
struct hal_uncompressed_format_select hal_fmt = {0};
struct hal_frame_size frame_sz;
- inst->prop.width = f->fmt.pix_mp.width;
- inst->prop.height = f->fmt.pix_mp.height;
+ inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+ inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
rc = msm_vidc_check_session_supported(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -2201,8 +2219,8 @@
goto exit;
}
frame_sz.buffer_type = HAL_BUFFER_INPUT;
- frame_sz.width = inst->prop.width;
- frame_sz.height = inst->prop.height;
+ frame_sz.width = inst->prop.width[OUTPUT_PORT];
+ frame_sz.height = inst->prop.height[OUTPUT_PORT];
dprintk(VIDC_DBG, "width = %d, height = %d\n",
frame_sz.width, frame_sz.height);
rc = call_hfi_op(hdev, session_set_property, (void *)
@@ -2212,14 +2230,6 @@
"Failed to set framesize for Output port\n");
goto exit;
}
- frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
- rc = call_hfi_op(hdev, session_set_property, (void *)
- inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to set hal property for framesize\n");
- goto exit;
- }
fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
OUTPUT_PORT);
@@ -2272,8 +2282,8 @@
}
inst->capability.pixelprocess_capabilities =
call_hfi_op(hdev, get_core_capabilities);
- frame_sz.width = inst->prop.width;
- frame_sz.height = inst->prop.height;
+ frame_sz.width = inst->prop.width[CAPTURE_PORT];
+ frame_sz.height = inst->prop.height[CAPTURE_PORT];
frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
rc = call_hfi_op(hdev, session_set_property,
(void *)inst->session, HAL_PARAM_FRAME_SIZE,
@@ -2298,26 +2308,31 @@
const struct msm_vidc_format *fmt = NULL;
int rc = 0;
int i;
+ u32 height, width;
int extra_idx = 0;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
fmt = inst->fmts[CAPTURE_PORT];
- else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ height = inst->prop.height[CAPTURE_PORT];
+ width = inst->prop.width[CAPTURE_PORT];
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
fmt = inst->fmts[OUTPUT_PORT];
+ height = inst->prop.height[OUTPUT_PORT];
+ width = inst->prop.width[OUTPUT_PORT];
+ }
if (fmt) {
f->fmt.pix_mp.pixelformat = fmt->fourcc;
- f->fmt.pix_mp.height = inst->prop.height;
- f->fmt.pix_mp.width = inst->prop.width;
+ f->fmt.pix_mp.height = height;
+ f->fmt.pix_mp.width = width;
f->fmt.pix_mp.num_planes = fmt->num_planes;
for (i = 0; i < fmt->num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
- fmt->get_frame_size(i, inst->prop.height,
- inst->prop.width);
+ fmt->get_frame_size(i, height, width);
}
extra_idx = EXTRADATA_IDX(fmt->num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 780f2c4..73b5b7c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -82,6 +82,15 @@
}
return false;
}
+static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
+{
+ int height, width;
+ height = max(inst->prop.height[CAPTURE_PORT],
+ inst->prop.height[OUTPUT_PORT]);
+ width = max(inst->prop.width[CAPTURE_PORT],
+ inst->prop.width[OUTPUT_PORT]);
+ return NUM_MBS_PER_SEC(height, width, inst->prop.fps);
+}
static int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type)
@@ -98,9 +107,8 @@
inst->state >= MSM_VIDC_OPEN_DONE &&
inst->state < MSM_VIDC_STOP_DONE) {
if (!is_thumbnail_session(inst))
- num_mbs_per_sec += NUM_MBS_PER_SEC(
- inst->prop.height,
- inst->prop.width, inst->prop.fps);
+ num_mbs_per_sec +=
+ msm_comm_get_mbs_per_sec(inst);
}
mutex_unlock(&inst->lock);
}
@@ -431,6 +439,8 @@
inst->capability.height = session_init_done->height;
inst->capability.frame_rate =
session_init_done->frame_rate;
+ inst->capability.scale_x = session_init_done->scale_x;
+ inst->capability.scale_y = session_init_done->scale_y;
inst->capability.capability_set = true;
inst->capability.buffer_mode[CAPTURE_PORT] =
session_init_done->alloc_mode_out;
@@ -539,8 +549,10 @@
} else {
dprintk(VIDC_DBG,
"V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
- inst->prop.height = event_notify->height;
- inst->prop.width = event_notify->width;
+ inst->prop.height[CAPTURE_PORT] = event_notify->height;
+ inst->prop.width[CAPTURE_PORT] = event_notify->width;
+ inst->prop.height[OUTPUT_PORT] = event_notify->height;
+ inst->prop.width[OUTPUT_PORT] = event_notify->width;
}
rc = msm_vidc_check_session_supported(inst);
if (!rc) {
@@ -1571,8 +1583,8 @@
temp->state < MSM_VIDC_STOP_DONE) {
dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d\n",
temp->session_type,
- temp->prop.width,
- temp->prop.height,
+ temp->prop.width[CAPTURE_PORT],
+ temp->prop.height[CAPTURE_PORT],
temp->prop.fps);
}
mutex_unlock(&temp->lock);
@@ -1586,6 +1598,7 @@
u32 ocmem_sz = 0;
struct hfi_device *hdev;
int num_mbs_per_sec = 0;
+ int height, width;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1619,8 +1632,12 @@
goto exit;
}
if (inst->core->resources.has_ocmem) {
- ocmem_sz = get_ocmem_requirement(inst->prop.height,
- inst->prop.width);
+ height = max(inst->prop.height[CAPTURE_PORT],
+ inst->prop.height[OUTPUT_PORT]);
+ width = max(inst->prop.width[CAPTURE_PORT],
+ inst->prop.width[OUTPUT_PORT]);
+ ocmem_sz = get_ocmem_requirement(
+ height, width);
mutex_lock(&inst->core->sync_lock);
rc = msm_comm_scale_bus(inst->core, inst->session_type,
OCMEM_MEM);
@@ -2835,9 +2852,9 @@
if (inst->state == MSM_VIDC_OPEN_DONE) {
num_mbs_per_sec = msm_comm_get_load(inst->core,
- MSM_VIDC_DECODER);
+ MSM_VIDC_DECODER);
num_mbs_per_sec += msm_comm_get_load(inst->core,
- MSM_VIDC_ENCODER);
+ MSM_VIDC_ENCODER);
if (num_mbs_per_sec > inst->core->resources.max_load) {
dprintk(VIDC_ERR,
"H/w is overloaded. needed: %d max: %d\n",
@@ -2852,6 +2869,71 @@
return 0;
}
+
+int msm_comm_check_scaling_supported(struct msm_vidc_inst *inst)
+{
+ u32 x_min, x_max, y_min, y_max;
+ u32 input_height, input_width, output_height, output_width;
+
+ if (!inst->capability.scale_x.min || !inst->capability.scale_x.max ||
+ !inst->capability.scale_y.min ||
+ !inst->capability.scale_y.max) {
+ dprintk(VIDC_ERR, "%s : Invalid scaling ratios",
+ __func__);
+ return -ENOTSUPP;
+ }
+ x_min = (1 << 16) / inst->capability.scale_x.min;
+ y_min = (1 << 16) / inst->capability.scale_y.min;
+ x_max = inst->capability.scale_x.max >> 16;
+ y_max = inst->capability.scale_y.max >> 16;
+
+ input_height = inst->prop.height[OUTPUT_PORT];
+ input_width = inst->prop.width[OUTPUT_PORT];
+ output_height = inst->prop.height[CAPTURE_PORT];
+ output_width = inst->prop.width[CAPTURE_PORT];
+
+ if (!input_height || !input_width || !output_height || !output_width) {
+ dprintk(VIDC_ERR,
+ "Invalid : Input Height = %d Width = %d"
+ " Output Height = %d Width = %d",
+ input_height, input_width, output_height,
+ output_width);
+ return -ENOTSUPP;
+ }
+
+ if (input_height > output_height) {
+ if (input_height / output_height > x_min) {
+ dprintk(VIDC_ERR,
+ "Unsupported Height Downscale ratio %d Vs %d",
+ input_height/output_height, x_min);
+ return -ENOTSUPP;
+ }
+ } else {
+ if (input_height / output_height > x_max) {
+ dprintk(VIDC_ERR,
+ "Unsupported Height Upscale ratio %d Vs %d",
+ input_height/output_height, x_max);
+ return -ENOTSUPP;
+ }
+ }
+ if (input_width > output_width) {
+ if (input_width / output_width > y_min) {
+ dprintk(VIDC_ERR,
+ "Unsupported Width Downscale ratio %d Vs %d",
+ input_width/output_width, y_min);
+ return -ENOTSUPP;
+ }
+ } else {
+ if (input_width / output_width > y_max) {
+ dprintk(VIDC_ERR,
+ "Unsupported Width Upscale ratio %d Vs %d",
+ input_width/output_width, y_max);
+ return -ENOTSUPP;
+ }
+ }
+ return 0;
+}
+
int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
{
struct msm_vidc_core_capability *capability;
@@ -2869,14 +2951,16 @@
if (!rc && inst->capability.capability_set) {
rc = call_hfi_op(hdev, capability_check,
inst->fmts[OUTPUT_PORT]->fourcc,
- inst->prop.width, &capability->width.max,
+ inst->prop.width[CAPTURE_PORT], &capability->width.max,
&capability->height.max);
- if (!rc && (inst->prop.height * inst->prop.width >
+ if (!rc && (inst->prop.height[CAPTURE_PORT]
+ * inst->prop.width[CAPTURE_PORT] >
capability->width.max * capability->height.max)) {
dprintk(VIDC_ERR,
"Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)",
- inst->prop.width, inst->prop.height,
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
capability->width.max, capability->height.max);
rc = -ENOTSUPP;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index c018345..6ee773a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -46,6 +46,7 @@
#define IS_PRIV_CTRL(idx) (\
(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
V4L2_CTRL_DRIVER_PRIV(idx))
+int msm_comm_check_scaling_supported(struct msm_vidc_inst *inst);
+int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
#endif
-int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 33aede4..3f607e9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -128,8 +128,8 @@
};
struct session_prop {
- u32 width;
- u32 height;
+ u32 width[MAX_PORT_NUM];
+ u32 height[MAX_PORT_NUM];
u32 fps;
u32 bitrate;
};
@@ -180,6 +180,8 @@
struct hal_capability_supported height;
struct hal_capability_supported frame_rate;
u32 pixelprocess_capabilities;
+ struct hal_capability_supported scale_x;
+ struct hal_capability_supported scale_y;
u32 capability_set;
enum buffer_mode_type buffer_mode[MAX_PORT_NUM];
};