diff --git a/driver/platform/waipio/src/msm_vidc_waipio.c b/driver/platform/waipio/src/msm_vidc_waipio.c index 952ddeb521..ddf870c667 100644 --- a/driver/platform/waipio/src/msm_vidc_waipio.c +++ b/driver/platform/waipio/src/msm_vidc_waipio.c @@ -93,6 +93,7 @@ static struct msm_platform_core_capability core_data_waipio[] = { {DECODE_BATCH_TIMEOUT, 200}, {AV_SYNC_WINDOW_SIZE, 40}, {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 1}, }; static struct msm_platform_inst_capability instance_data_waipio[] = { diff --git a/driver/variant/iris2/src/msm_vidc_power_iris2.c b/driver/variant/iris2/src/msm_vidc_power_iris2.c index dc53085630..acbaff0fef 100644 --- a/driver/variant/iris2/src/msm_vidc_power_iris2.c +++ b/driver/variant/iris2/src/msm_vidc_power_iris2.c @@ -48,7 +48,7 @@ u64 msm_vidc_calc_freq_iris2(struct msm_vidc_inst *inst, u32 data_size) mbpf = msm_vidc_get_mbs_per_frame(inst); fps = msm_vidc_get_fps(inst); - buf_timetamps_fps = msm_vidc_calc_framerate(inst); + buf_timetamps_fps = msm_vidc_calc_window_avg_framerate(inst); /* * when buffer detected fps is more than client set value by 10%, diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index 6e3a77f96a..4ffba2d36f 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -411,7 +411,8 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst); int msm_vidc_check_core_mbps(struct msm_vidc_inst *inst); int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst); int msm_vidc_update_timestamp(struct msm_vidc_inst *inst, u64 timestamp); -int msm_vidc_calc_framerate(struct msm_vidc_inst *inst); +int msm_vidc_set_auto_framerate(struct msm_vidc_inst *inst, u64 timestamp); +int msm_vidc_calc_window_avg_framerate(struct msm_vidc_inst *inst); int msm_vidc_flush_ts(struct msm_vidc_inst *inst); const char *buf_name(enum msm_vidc_buffer_type type); void msm_vidc_free_capabililty_list(struct msm_vidc_inst *inst, diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index 67551caba9..bc21633cad 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/driver/vidc/inc/msm_vidc_inst.h @@ -147,5 +147,6 @@ struct msm_vidc_inst { u32 max_input_data_size; u32 dpb_list_payload[MAX_DPB_LIST_ARRAY_SIZE]; u32 max_map_output_count; + u32 auto_framerate; }; #endif // _MSM_VIDC_INST_H_ diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index f57e44500d..eddb52dfac 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -69,6 +69,8 @@ #define MAX_SUPPORTED_MIN_QUALITY 70 #define DCVS_WINDOW 16 +#define ENC_FPS_WINDOW 3 +#define DEC_FPS_WINDOW 10 /* Superframe can have maximum of 32 frames */ #define VIDC_SUPERFRAME_MAX 32 #define COLOR_RANGE_UNSPECIFIED (-1) @@ -327,6 +329,7 @@ enum msm_vidc_core_capability_type { AV_SYNC_WINDOW_SIZE, CLK_FREQ_THRESHOLD, NON_FATAL_FAULTS, + ENC_AUTO_FRAMERATE, CORE_CAP_MAX, }; diff --git a/driver/vidc/src/msm_venc.c b/driver/vidc/src/msm_venc.c index 6c1b94f645..01784ab76d 100644 --- a/driver/vidc/src/msm_venc.c +++ b/driver/vidc/src/msm_venc.c @@ -1604,6 +1604,7 @@ set_default: "%s: failed to set frame rate to fw\n", __func__); goto exit; } + inst->auto_framerate = q16_rate; } return 0; diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index a5599296df..fec47342b9 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/driver/vidc/src/msm_vidc.c @@ -434,6 +434,7 @@ int msm_vidc_qbuf(void *instance, struct media_device *mdev, int rc = 0; struct msm_vidc_inst *inst = instance; struct vb2_queue *q; + u64 timestamp_us = 0; if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) { d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b); @@ -445,6 +446,12 @@ int msm_vidc_qbuf(void *instance, struct media_device *mdev, rc = -EINVAL; goto exit; } + + if (is_encode_session(inst) && b->type == INPUT_MPLANE) { + timestamp_us = (u64)((b->timestamp.tv_sec * USEC_PER_SEC) + + b->timestamp.tv_usec); + msm_vidc_set_auto_framerate(inst, timestamp_us); + } inst->last_qbuf_time_ns = ktime_get_ns(); rc = vb2_qbuf(q, mdev, b); @@ -776,6 +783,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) inst->request = false; inst->ipsc_properties_set = false; inst->opsc_properties_set = false; + inst->auto_framerate = DEFAULT_FPS << 16; kref_init(&inst->kref); mutex_init(&inst->lock); msm_vidc_update_debug_str(inst); diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index a81690738d..20d274913f 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -40,8 +40,6 @@ extern struct msm_vidc_core *g_core; #define SSR_ADDR_ID 0xFFFFFFFF00000000 #define SSR_ADDR_SHIFT 32 -#define FPS_WINDOW 10 - struct msm_vidc_cap_name { enum msm_vidc_inst_capability_type cap; char *name; @@ -2019,7 +2017,67 @@ int msm_vidc_memory_unmap_completely(struct msm_vidc_inst *inst, return rc; } -int msm_vidc_calc_framerate(struct msm_vidc_inst *inst) +int msm_vidc_set_auto_framerate(struct msm_vidc_inst *inst, u64 timestamp) +{ + struct msm_vidc_core *core; + struct msm_vidc_timestamp *ts; + struct msm_vidc_timestamp *prev = NULL; + u32 counter = 0, prev_fr = 0, curr_fr = 0; + u64 ts_ms = 0; + int rc = 0; + + if (!inst || !inst->core || !inst->capabilities) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + core = inst->core; + if (!core->capabilities[ENC_AUTO_FRAMERATE].value || + is_image_session(inst) || msm_vidc_is_super_buffer(inst)) + goto exit; + + rc = msm_vidc_update_timestamp(inst, timestamp); + if (rc) + goto exit; + + list_for_each_entry(ts, &inst->timestamps.list, sort.list) { + if (prev) { + ts_ms = div_u64(ts->sort.val - prev->sort.val, 1000); + prev_fr = curr_fr; + curr_fr = ts_ms ? div_u64(MSEC_PER_SEC, ts_ms) << 16 : + inst->auto_framerate; + if (curr_fr > inst->capabilities->cap[FRAME_RATE].max) + curr_fr = inst->capabilities->cap[FRAME_RATE].max; + } + prev = ts; + counter++; + } + + if (counter < ENC_FPS_WINDOW) + goto exit; + + /* if framerate changed and stable for 2 frames, set to firmware */ + if (curr_fr == prev_fr && curr_fr != inst->auto_framerate) { + i_vpr_l(inst, "%s: updated fps to %u\n", __func__, curr_fr >> 16); + rc = venus_hfi_session_property(inst, + HFI_PROP_FRAME_RATE, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_Q16, + &curr_fr, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set auto frame rate failed\n", + __func__); + goto exit; + } + inst->auto_framerate = curr_fr; + } +exit: + return rc; +} + +int msm_vidc_calc_window_avg_framerate(struct msm_vidc_inst *inst) { struct msm_vidc_timestamp *ts; struct msm_vidc_timestamp *prev = NULL; @@ -2129,6 +2187,7 @@ int msm_vidc_update_timestamp(struct msm_vidc_inst *inst, u64 timestamp) { struct msm_vidc_timestamp *ts; int rc = 0; + u32 window_size = 0; if (!inst) { d_vpr_e("%s: Invalid params\n", __func__); @@ -2149,8 +2208,13 @@ int msm_vidc_update_timestamp(struct msm_vidc_inst *inst, u64 timestamp) return rc; inst->timestamps.count++; - /* keep sliding window of 10 ts nodes */ - if (inst->timestamps.count > FPS_WINDOW) { + if (is_encode_session(inst)) + window_size = ENC_FPS_WINDOW; + else + window_size = DEC_FPS_WINDOW; + + /* keep sliding window */ + if (inst->timestamps.count > window_size) { ts = msm_vidc_get_least_rank_ts(inst); if (!ts) { i_vpr_e(inst, "%s: least rank ts is NULL\n", __func__); diff --git a/driver/vidc/src/msm_vidc_power.c b/driver/vidc/src/msm_vidc_power.c index 9978c77e58..4d84d36e0c 100644 --- a/driver/vidc/src/msm_vidc_power.c +++ b/driver/vidc/src/msm_vidc_power.c @@ -223,7 +223,7 @@ int msm_vidc_scale_buses(struct msm_vidc_inst *inst) vote_data->lcu_size = (codec == V4L2_PIX_FMT_HEVC || codec == V4L2_PIX_FMT_VP9) ? 32 : 16; vote_data->fps = msm_vidc_get_fps(inst); - buf_ts_fps = msm_vidc_calc_framerate(inst); + buf_ts_fps = msm_vidc_calc_window_avg_framerate(inst); if (buf_ts_fps > vote_data->fps) { i_vpr_l(inst, "%s: bitstream: fps %d, client rate %u\n", __func__, buf_ts_fps, vote_data->fps); diff --git a/driver/vidc/src/venus_hfi.c b/driver/vidc/src/venus_hfi.c index 3e603e6447..c45a4a912f 100644 --- a/driver/vidc/src/venus_hfi.c +++ b/driver/vidc/src/venus_hfi.c @@ -3399,7 +3399,6 @@ int venus_hfi_queue_super_buffer(struct msm_vidc_inst *inst, /* Create yuv packet */ update_offset(hfi_buffer.addr_offset, (cnt ? frame_size : 0u)); update_timestamp(hfi_buffer.timestamp, (cnt ? ts_delta_us : 0u)); - msm_vidc_update_timestamp(inst, hfi_buffer.timestamp); rc = hfi_create_packet(inst->packet, inst->packet_size, HFI_CMD_BUFFER, @@ -3467,9 +3466,6 @@ int venus_hfi_queue_buffer(struct msm_vidc_inst *inst, if (rc) goto unlock; - if (is_encode_session(inst) && is_input_buffer(buffer->type)) - msm_vidc_update_timestamp(inst, hfi_buffer.timestamp); - rc = hfi_create_header(inst->packet, inst->packet_size, inst->session_id, core->header_id++); if (rc)