diff --git a/msm/vidc/msm_venc.c b/msm/vidc/msm_venc.c index 5eeb51464593..c7f16dfe3c72 100644 --- a/msm/vidc/msm_venc.c +++ b/msm/vidc/msm_venc.c @@ -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; diff --git a/msm/vidc/msm_venc.h b/msm/vidc/msm_venc.h index 43b56bc21788..bb5a651f3da9 100644 --- a/msm/vidc/msm_venc.h +++ b/msm/vidc/msm_venc.h @@ -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); diff --git a/msm/vidc/msm_vidc.c b/msm/vidc/msm_vidc.c index 30fa43deeb02..bf40eeef23a8 100644 --- a/msm/vidc/msm_vidc.c +++ b/msm/vidc/msm_vidc.c @@ -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) { diff --git a/msm/vidc/msm_vidc_common.c b/msm/vidc/msm_vidc_common.c index fa25d14376a3..b49b654f4cd1 100644 --- a/msm/vidc/msm_vidc_common.c +++ b/msm/vidc/msm_vidc_common.c @@ -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; } diff --git a/msm/vidc/msm_vidc_platform.c b/msm/vidc/msm_vidc_platform.c index f86c1d0f8013..ddf55e190a6b 100644 --- a/msm/vidc/msm_vidc_platform.c +++ b/msm/vidc/msm_vidc_platform.c @@ -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[] = { diff --git a/msm/vidc/msm_vidc_res_parse.c b/msm/vidc/msm_vidc_res_parse.c index c565ee6ec708..ff6df21c3d36 100644 --- a/msm/vidc/msm_vidc_res_parse.c +++ b/msm/vidc/msm_vidc_res_parse.c @@ -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; diff --git a/msm/vidc/msm_vidc_resources.h b/msm/vidc/msm_vidc_resources.h index c8f20b258ac2..d7c8ee88b887 100644 --- a/msm/vidc/msm_vidc_resources.h +++ b/msm/vidc/msm_vidc_resources.h @@ -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)