msm: vidc: support encoder auto dynamic fps

Encoder calculate fps based on timestamp,
if fps changes and stable for 2 frames,
set to firmware to facilitate rate control.
Use closest rounding instead of floor rounding
when calculate fps.

Change-Id: Id2420729a309378107ff6f7830515fae31512ddd
Signed-off-by: Qiwei Liu <qiweil@codeaurora.org>
This commit is contained in:
Qiwei Liu 2020-05-21 23:34:50 +08:00 • committed by Gerrit - the friendly Code Review server
commit 930011097f
7 changed files with 93 additions and 6 deletions

View file

@ -47,6 +47,7 @@
#define MIN_NUM_ENC_OUTPUT_BUFFERS 4
#define MIN_NUM_ENC_CAPTURE_BUFFERS 5
#define VENC_MAX_TIMESTAMP_LIST_SIZE 2
static const char *const mpeg_video_rate_control[] = {
"VBR",
@ -1653,6 +1654,7 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
if (rc)
s_vpr_e(sid, "%s: set frame rate failed\n",
__func__);
msm_comm_release_timestamps(inst);
}
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
@ -2112,6 +2114,72 @@ int msm_venc_set_frame_rate(struct msm_vidc_inst *inst)
return rc;
}
int msm_venc_store_timestamp(struct msm_vidc_inst *inst, u64 timestamp_us)
{
struct msm_vidc_timestamps *entry, *node, *prev = NULL;
int count = 0;
int rc = 0;
if (!inst || !inst->core) {
d_vpr_e("%s: invalid parameters\n", __func__);
return -EINVAL;
}
if (!inst->core->resources.enc_auto_dynamic_fps ||
is_image_session(inst))
return rc;
mutex_lock(&inst->timestamps.lock);
list_for_each_entry(node, &inst->timestamps.list, list) {
count++;
if (timestamp_us <= node->timestamp_us) {
s_vpr_e(inst->sid, "%s: invalid ts %llu, exist %llu\n",
__func__, timestamp_us, node->timestamp_us);
goto unlock;
}
}
/* Maintain a sliding window */
entry = NULL;
if (count >= VENC_MAX_TIMESTAMP_LIST_SIZE) {
entry = list_first_entry(&inst->timestamps.list,
struct msm_vidc_timestamps, list);
list_del_init(&entry->list);
}
if (!entry) {
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
s_vpr_e(inst->sid, "%s: ts malloc failure\n",
__func__);
rc = -ENOMEM;
goto unlock;
}
}
entry->timestamp_us = timestamp_us;
entry->framerate = inst->clk_data.frame_rate;
prev = list_last_entry(&inst->timestamps.list,
struct msm_vidc_timestamps, list);
list_add_tail(&entry->list, &inst->timestamps.list);
if (!count)
goto unlock;
entry->framerate = msm_comm_calc_framerate(inst,
timestamp_us, prev->timestamp_us);
/* if framerate changed and stable for 2 frames, set to firmware */
if (entry->framerate == prev->framerate &&
entry->framerate != inst->clk_data.frame_rate) {
inst->clk_data.frame_rate = entry->framerate;
msm_venc_set_frame_rate(inst);
}
unlock:
mutex_unlock(&inst->timestamps.lock);
return rc;
}
int msm_venc_set_color_format(struct msm_vidc_inst *inst)
{
int rc = 0;

View file

@ -24,6 +24,7 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst,
int msm_venc_set_properties(struct msm_vidc_inst *inst);
int msm_venc_set_extradata(struct msm_vidc_inst *inst);
int msm_venc_set_frame_rate(struct msm_vidc_inst *inst);
int msm_venc_store_timestamp(struct msm_vidc_inst *inst, u64 timestamp_us);
int msm_venc_set_bitrate(struct msm_vidc_inst *inst);
int msm_venc_set_layer_bitrate(struct msm_vidc_inst *inst);
int msm_venc_set_operating_rate(struct msm_vidc_inst *inst);

View file

@ -420,18 +420,27 @@ int msm_vidc_qbuf(void *instance, struct media_device *mdev,
if (is_grid_session(inst) && b->type == INPUT_MPLANE)
b->flags |= V4L2_BUF_FLAG_PERF_MODE;
timestamp_us = (u64)((b->timestamp.tv_sec * 1000000ULL) +
b->timestamp.tv_usec);
if (is_decode_session(inst) && b->type == INPUT_MPLANE) {
if (inst->flush_timestamps)
msm_comm_release_timestamps(inst);
inst->flush_timestamps = false;
timestamp_us = (u64)((b->timestamp.tv_sec * 1000000ULL) +
b->timestamp.tv_usec);
rc = msm_comm_store_timestamp(inst, timestamp_us);
if (rc)
return rc;
inst->clk_data.frame_rate = msm_comm_get_max_framerate(inst);
}
if (is_encode_session(inst) && b->type == INPUT_MPLANE) {
if (inst->flush_timestamps)
msm_comm_release_timestamps(inst);
inst->flush_timestamps = false;
rc = msm_venc_store_timestamp(inst, timestamp_us);
if (rc)
return rc;
}
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {

View file

@ -5596,7 +5596,7 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
* flush is issued, before adding the next buffer's timestamp
* to the list.
*/
if (is_decode_session(inst) && inst->in_flush) {
if (!is_image_session(inst) && inst->in_flush) {
inst->flush_timestamps = true;
s_vpr_h(inst->sid,
"Setting flush variable to clear timestamp list: %d\n",
@ -7610,7 +7610,7 @@ int msm_comm_store_timestamp(struct msm_vidc_inst *inst, u64 timestamp_us)
goto unlock;
}
entry->timestamp_us = timestamp_us;
entry->framerate = DEFAULT_FPS << 16;
entry->framerate = inst->clk_data.frame_rate;
entry->is_valid = true;
/* add new entry into the list in sorted order */
@ -7661,14 +7661,16 @@ unlock:
u32 msm_comm_calc_framerate(struct msm_vidc_inst *inst,
u64 timestamp_us, u64 prev_ts)
{
u32 framerate = DEFAULT_FPS << 16;
u32 framerate = inst->clk_data.frame_rate;
u32 interval;
if (timestamp_us <= prev_ts) {
s_vpr_e(inst->sid, "%s: invalid ts %lld, prev ts %lld\n",
__func__, timestamp_us, prev_ts);
return framerate;
}
framerate = (1000000 / (timestamp_us - prev_ts)) << 16;
interval = (u32)(timestamp_us - prev_ts);
framerate = ((1000000 + interval / 2) / interval) << 16;
return framerate;
}

View file

@ -453,6 +453,10 @@ static struct msm_vidc_common_data lahaina_common_data[] = {
.key = "qcom,vpp_delay_supported",
.value = 1,
},
{
.key = "qcom,enc_auto_dynamic_fps",
.value = 1,
},
};
static struct msm_vidc_common_data bengal_common_data_v0[] = {

View file

@ -826,6 +826,8 @@ int read_platform_resources_from_drv_data(
"qcom,ubwc_stats_in_fbd");
res->has_vpp_delay = find_key_value(platform_data,
"qcom,vpp_delay_supported");
res->enc_auto_dynamic_fps = find_key_value(platform_data,
"qcom,enc_auto_dynamic_fps");
res->csc_coeff_data = &platform_data->csc_data;

View file

@ -205,6 +205,7 @@ struct msm_vidc_platform_resources {
struct cx_ipeak_client *cx_ipeak_context;
uint32_t ubwc_stats_in_fbd;
uint32_t has_vpp_delay;
bool enc_auto_dynamic_fps;
};
static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)