summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSom Qin <som.qin@starfivetech.com>2023-12-13 11:47:11 +0300
committerSom Qin <som.qin@starfivetech.com>2023-12-13 11:47:11 +0300
commit5fb451c271eb68c4c6a5db702449f31c779eb527 (patch)
treea42bbde69731daf33d5889820f5336ab54ee50a0
parentb19c9481d505aea3a3b91d48f6379f38972b58d0 (diff)
downloadlinux-5fb451c271eb68c4c6a5db702449f31c779eb527.tar.xz
Media:Wave5: Fix timestamping issue in the decoder
Signed-off-by: Som Qin <som.qin@starfivetech.com>
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c61
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuapi.h14
2 files changed, 72 insertions, 3 deletions
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
index c9eda6136e95..b5ee9f270343 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
@@ -181,6 +181,8 @@ static void wave5_handle_bitstream_buffer(struct vpu_instance *inst)
static void wave5_handle_src_buffer(struct vpu_instance *inst)
{
struct vb2_v4l2_buffer *src_buf;
+ int i, j, ret;
+ u64 flag;
src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx);
if (src_buf) {
@@ -189,7 +191,33 @@ static void wave5_handle_src_buffer(struct vpu_instance *inst)
if (vpu_buf->consumed) {
dev_dbg(inst->dev->dev, "%s: already consumed buffer\n", __func__);
src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx);
- inst->timestamp = src_buf->vb2_buf.timestamp;
+
+ if (!inst->monotonic_timestamp && !src_buf->vb2_buf.timestamp) {
+ inst->timestamp_zero_cnt++;
+ if (inst->timestamp_zero_cnt > 1) {
+ inst->monotonic_timestamp = TRUE;
+ }
+ }
+
+ if(!inst->monotonic_timestamp) {
+ ret = mutex_lock_interruptible(&inst->time_stamp.lock);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: lock err\n", __func__);
+ return;
+ }
+ inst->time_stamp.buf[inst->time_stamp.cnt] = src_buf->vb2_buf.timestamp;
+ inst->time_stamp.cnt++;
+
+ for (i = 1; i < inst->time_stamp.cnt; i++) {
+ flag = inst->time_stamp.buf[i];
+ for (j = i - 1; j >= 0 && inst->time_stamp.buf[j] < flag ; j--) {
+ inst->time_stamp.buf[j + 1] = inst->time_stamp.buf[j];
+ }
+ inst->time_stamp.buf[j + 1] = flag;
+ }
+ mutex_unlock(&inst->time_stamp.lock);
+ }
+
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
}
}
@@ -346,7 +374,18 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst)
((stride / 2) * (height / 2)));
}
- dst_buf->vb2_buf.timestamp = inst->timestamp_cnt++ * inst->codec_info->dec_info.initial_info.ns_per_frame;
+ if (!inst->monotonic_timestamp) {
+ ret = mutex_lock_interruptible(&inst->time_stamp.lock);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: lock err\n", __func__);
+ return;
+ }
+ dst_buf->vb2_buf.timestamp = inst->time_stamp.buf[inst->time_stamp.cnt - 1];
+ inst->time_stamp.cnt--;
+ mutex_unlock(&inst->time_stamp.lock);
+ } else {
+ dst_buf->vb2_buf.timestamp = inst->timestamp_cnt++ * inst->codec_info->dec_info.initial_info.ns_per_frame;
+ }
dst_buf->field = V4L2_FIELD_NONE;
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
@@ -381,7 +420,19 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst)
vb2_plane_size(&dst_buf->vb2_buf, 2));
}
- dst_buf->vb2_buf.timestamp = inst->timestamp;
+ if (!inst->monotonic_timestamp) {
+ ret = mutex_lock_interruptible(&inst->time_stamp.lock);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: lock err\n", __func__);
+ return;
+ }
+ dst_buf->vb2_buf.timestamp = inst->time_stamp.buf[inst->time_stamp.cnt - 1];
+ inst->time_stamp.cnt--;
+ mutex_unlock(&inst->time_stamp.lock);
+ } else {
+ dst_buf->vb2_buf.timestamp = inst->timestamp_cnt++ * inst->codec_info->dec_info.initial_info.ns_per_frame;
+ }
+
dst_buf->flags |= V4L2_BUF_FLAG_LAST;
dst_buf->field = V4L2_FIELD_NONE;
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
@@ -952,6 +1003,10 @@ static int wave5_vpu_dec_start_streaming_open(struct vpu_instance *inst)
struct dec_initial_info initial_info;
int ret = 0;
+ inst->time_stamp.cnt = 0;
+ mutex_init(&inst->time_stamp.lock);
+ memset(&inst->time_stamp.buf, 0, sizeof(MAX_TIMESTAMP_CIR_BUF));
+
memset(&initial_info, 0, sizeof(struct dec_initial_info));
ret = wave5_vpu_dec_issue_seq_init(inst);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
index 10f20a283592..d7b5717fd9c1 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
@@ -43,6 +43,8 @@ enum vpu_instance_state {
#define MAX_REG_FRAME (WAVE5_MAX_FBS * 2)
+#define MAX_TIMESTAMP_CIR_BUF 30
+
#define WAVE5_DEC_HEVC_BUF_SIZE(_w, _h) (DIV_ROUND_UP(_w, 64) * DIV_ROUND_UP(_h, 64) * 256 + 64)
#define WAVE5_DEC_AVC_BUF_SIZE(_w, _h) ((((ALIGN(_w, 256) / 16) * (ALIGN(_h, 16) / 16)) + 16) * 80)
#define WAVE5_DEC_VP9_BUF_SIZE(_w, _h) (((ALIGN(_w, 64) * ALIGN(_h, 64)) >> 2))
@@ -1038,6 +1040,15 @@ struct vpu_instance_ops {
void (*finish_process)(struct vpu_instance *inst);
};
+/* for support GStreamer ver 1.20 over
+ * too old frame, eos sent too early
+ */
+struct timestamp_circ_buf {
+ u64 buf[MAX_TIMESTAMP_CIR_BUF];
+ struct mutex lock;
+ int cnt;
+};
+
struct vpu_instance {
struct list_head list;
struct v4l2_fh v4l2_fh;
@@ -1075,7 +1086,10 @@ struct vpu_instance {
u32 conf_win_width;
u32 conf_win_height;
u64 timestamp;
+ struct timestamp_circ_buf time_stamp;
u64 timestamp_cnt;
+ u32 timestamp_zero_cnt;
+ bool monotonic_timestamp;
bool cbcr_interleave;
bool nv21;
bool eos;