MLK-24960: [8QM_MEK/8QXP_MEK]mxc:vpu_malone: move timestamp manager to

firmware

move timestamp to firmware, it will make our driver more easy to
upstream

Signed-off-by: Ming Qian <ming.qian@nxp.com>
This commit is contained in:
Ming Qian 2020-11-03 16:16:53 +08:00
parent bf67b06529
commit 21929af532
8 changed files with 120 additions and 1128 deletions

View File

@ -11,7 +11,6 @@ vpu-malone-objs = vpu_b0.o \
vpu_rpc.o \
insert_startcode.o \
vpu_debug_log.o \
vpu_ts.o \
vpu_mu.o \
vpu_pm.o

View File

@ -174,6 +174,7 @@ typedef enum {
VID_API_CMD_DBG_DUMP_LOG = 0x1F,
/* Begin Encode CMDs */
VID_API_CMD_YUV_READY = 0x20,
VID_API_CMD_TS = 0x21,
VID_API_CMD_FIRM_RESET = 0x40,
@ -684,8 +685,13 @@ typedef struct {
u_int32 uFWOffset;
u_int32 uMaxDecoderStreams;
MediaIPFW_Video_DbgLogDesc DbgLogDesc;
MediaIPFW_Video_FrameBuffer StreamFrameBuffer[VID_API_NUM_STREAMS];
MediaIPFW_Video_FrameBuffer StreamDCPBuffer[VID_API_NUM_STREAMS];
union {
struct {
MediaIPFW_Video_FrameBuffer StreamFrameBuffer[VID_API_NUM_STREAMS];
MediaIPFW_Video_FrameBuffer StreamDCPBuffer[VID_API_NUM_STREAMS];
};
BUFFER_DESCRIPTOR_TYPE StreamApiCmdBufferDesc[VID_API_NUM_STREAMS];
};
MediaIPFW_Video_UData UDataBuffer[VID_API_NUM_STREAMS];
MediaIPFW_Video_BufDesc DebugBufferDesc;
MediaIPFW_Video_BufDesc EngAccessBufferDesc[VID_API_NUM_STREAMS];

View File

@ -45,12 +45,18 @@
#include "vpu_b0.h"
#include "insert_startcode.h"
#include "vpu_debug_log.h"
#include "vpu_ts.h"
#include "vpu_pm.h"
#include "vpu_mu.h"
#ifndef TSM_TIMESTAMP_NONE
#define TSM_TIMESTAMP_NONE -1L
#endif
#ifndef TSM_TS_IS_VALID
#define TSM_TS_IS_VALID(ts) ((ts) >= 0)
#endif
unsigned int vpu_dbg_level_decoder = LVL_WARN;
static int vpu_frm_depth = INVALID_FRAME_DEPTH;
static int vpu_frm_depth = VPU_FRAME_DEPTH_DEFAULT;
static int vpu_log_depth = DEFAULT_LOG_DEPTH;
static int vpu_max_bufsize = MAX_BUFFER_SIZE;
static int vpu_frmdbg_ena = DEFAULT_FRMDBG_ENABLE;
@ -59,9 +65,6 @@ static int vpu_frmdbg_raw = 1;
static int vpu_dbe_num = 1;
static int vpu_frmcrcdump_ena;
static int stream_buffer_threshold = 0x10000;
static int tsm_mode = MODE_AI;
static int tsm_buffer_size = 1024;
static int tsm_use_consumed_length = 1;
static int precheck_show_bytes;
static int vpu_show_perf_ena;
static int vpu_show_perf_idx = (1 << VPU_MAX_NUM_STREAMS) - 1;
@ -133,6 +136,7 @@ static char *cmd2str[] = {
"VID_API_CMD_DBG_STOP_LOG",
"VID_API_CMD_DBG_DUMP_LOG",
"VID_API_CMD_YUV_READY", /*0x20*/
"VID_API_CMD_TS",
};
static char *event2str[] = {
@ -279,7 +283,7 @@ static void count_cmd(struct vpu_statistic *statistic, u32 cmdid)
if (cmdid < ARRAY_SIZE(cmd2str))
statistic->cmd[cmdid]++;
else
statistic->cmd[VID_API_CMD_YUV_READY + 1]++;
statistic->cmd[VID_API_CMD_TS + 1]++;
statistic->current_cmd = cmdid;
ktime_get_raw_ts64(&statistic->ts_cmd);
}
@ -1528,7 +1532,8 @@ static void vpu_dec_receive_ts(struct vpu_ctx *ctx,
int size)
{
struct vb2_v4l2_buffer *vbuf;
TSM_TIMESTAMP input_ts;
s64 input_ts;
u32 data[3];
if (!ctx || !vb)
return;
@ -1548,31 +1553,25 @@ static void vpu_dec_receive_ts(struct vpu_ctx *ctx,
if (TSM_TS_IS_VALID(input_ts) && input_ts > ctx->output_ts)
ctx->output_ts = input_ts;
if (down_interruptible(&ctx->tsm_lock)) {
vpu_err("%s() get tsm lock fail\n", __func__);
return;
}
if (is_codec_config_data(vb) && !TSM_TS_IS_VALID(input_ts)) {
vpu_dbg(LVL_BIT_TS, "[INPUT TS]codec data\n");
ctx->extra_size += size;
up(&ctx->tsm_lock);
return;
}
if (ctx->tsm_sync_flag) {
vpu_dbg(LVL_BIT_TS, "resyncTSManager\n");
resyncTSManager(ctx->tsm, input_ts, tsm_mode);
ctx->tsm_sync_flag = false;
}
size += ctx->extra_size;
ctx->extra_size = 0;
vpu_dbg(LVL_BIT_TS, "[INPUT TS]%32lld\n", input_ts);
TSManagerReceive2(ctx->tsm, input_ts, size);
ctx->total_ts_bytes += size;
vpu_dbg(LVL_BIT_FRAME_BYTES, "[%d]receive bytes : %8d / %16ld\n",
ctx->str_index, size, ctx->total_ts_bytes);
up(&ctx->tsm_lock);
if (input_ts < 0) {
data[0] = (u32)-1;
data[1] = 0;
} else {
data[0] = input_ts / NSEC_PER_SEC;
data[1] = input_ts % NSEC_PER_SEC;
}
data[2] = size;
v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_TS, 3, data);
}
static int v4l2_ioctl_qbuf(struct file *file,
@ -1618,74 +1617,6 @@ static int v4l2_ioctl_qbuf(struct file *file,
return ret;
}
static void vpu_dec_send_ts(struct vpu_ctx *ctx, struct v4l2_buffer *buf)
{
TSM_TIMESTAMP ts;
struct timespec64 ts64;
if (down_interruptible(&ctx->tsm_lock)) {
vpu_err("%s() get tsm lock fail\n", __func__);
return;
}
ts = TSManagerSend2(ctx->tsm, NULL);
if (TSM_TS_IS_VALID(ts) && ts < ctx->capture_ts) {
vpu_dbg(LVL_BIT_TS, "revise timestamp: %32lld -> %32lld\n",
ts, ctx->capture_ts);
ts = ctx->capture_ts;
}
vpu_dbg(LVL_BIT_TS, "[OUTPUT TS]%32lld (%lld)\n",
ts, getTSManagerFrameInterval(ctx->tsm));
ts64 = ns_to_timespec64(ts);
buf->timestamp.tv_sec = ts64.tv_sec;
buf->timestamp.tv_usec = ts64.tv_nsec / NSEC_PER_USEC;
buf->flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY;
up(&ctx->tsm_lock);
if (TSM_TS_IS_VALID(ts))
ctx->capture_ts = ts;
}
static void vpu_dec_valid_ts(struct vpu_ctx *ctx,
u32 consumed_pic_bytesused,
struct vb2_data_req *p_data_req)
{
WARN_ON(!ctx || !ctx->tsm);
if (down_interruptible(&ctx->tsm_lock)) {
vpu_err("%s() get tsm lock fail\n", __func__);
return;
}
vpu_dbg(LVL_BIT_FRAME_BYTES, "[%d]Valid bytes : %8d / %16ld\n",
ctx->str_index, consumed_pic_bytesused,
ctx->total_consumed_bytes);
TSManagerValid2(ctx->tsm,
consumed_pic_bytesused,
p_data_req ? p_data_req->vb2_buf : NULL);
up(&ctx->tsm_lock);
}
static void vpu_dec_skip_ts(struct vpu_ctx *ctx)
{
TSM_TIMESTAMP ts;
WARN_ON(!ctx || !ctx->tsm);
if (down_interruptible(&ctx->tsm_lock)) {
vpu_err("%s() get tsm lock fail\n", __func__);
return;
}
ts = TSManagerSend2(ctx->tsm, NULL);
up(&ctx->tsm_lock);
vpu_dbg(LVL_BIT_TS, "[SKIP TS]%32lld\n", ts);
}
static int v4l2_ioctl_dqbuf(struct file *file,
void *fh,
struct v4l2_buffer *buf
@ -1719,8 +1650,6 @@ static int v4l2_ioctl_dqbuf(struct file *file,
if (!V4L2_TYPE_IS_OUTPUT(buf->type) && is_10bit_format(ctx))
buf->reserved = 1;
if (!V4L2_TYPE_IS_OUTPUT(buf->type))
vpu_dec_send_ts(ctx, buf);
if (V4L2_TYPE_IS_OUTPUT(buf->type))
buf->flags &= ~V4L2_NXP_BUF_MASK_FLAGS;
@ -1967,32 +1896,6 @@ static int vpu_dec_v4l2_ioctl_g_parm(struct file *file, void *fh,
return 0;
}
static void vpu_dec_set_tsm_frame_rate(struct vpu_ctx *ctx)
{
u32 numerator;
u32 denominator;
WARN_ON(!ctx || !ctx->tsm);
if (down_interruptible(&ctx->tsm_lock)) {
vpu_err("%s() get tsm lock fail\n", __func__);
return;
}
numerator = ctx->fixed_frame_interval.numerator;
denominator = ctx->fixed_frame_interval.denominator;
if (numerator && denominator) {
setTSManagerFrameRate(ctx->tsm, denominator, numerator);
goto exit;
}
numerator = ctx->frame_interval.numerator;
denominator = ctx->frame_interval.denominator;
if (numerator && denominator)
setTSManagerFrameRate(ctx->tsm, denominator, numerator);
exit:
up(&ctx->tsm_lock);
}
static int vpu_dec_v4l2_ioctl_s_parm(struct file *file, void *fh,
struct v4l2_streamparm *parm)
{
@ -2012,7 +1915,6 @@ static int vpu_dec_v4l2_ioctl_s_parm(struct file *file, void *fh,
parm->parm.capture.timeperframe.numerator / gcd;
ctx->fixed_frame_interval.denominator =
parm->parm.capture.timeperframe.denominator / gcd;
vpu_dec_set_tsm_frame_rate(ctx);
mutex_unlock(&ctx->instance_mutex);
return 0;
@ -2128,8 +2030,8 @@ static struct v4l2_ctrl_config vpu_custom_s_cfg[] = {
.id = V4L2_CID_USER_FRAME_DEPTH,
.name = "frame depth ctrl",
.type = V4L2_CTRL_TYPE_INTEGER,
.min = -1,
.max = 999,
.min = 1,
.max = VPU_FRAME_DEPTH_MAX,
.step = 1,
},
{
@ -2497,6 +2399,8 @@ static void update_wptr(struct vpu_ctx *ctx,
length = (wptr + size - pStrBufDesc->wptr) % size;
ctx->total_write_bytes += length;
vpu_dbg(LVL_BIT_FRAME_BYTES, "[%d]receive bytes : %8d / %16ld\n",
ctx->str_index, length, ctx->total_write_bytes);
vpu_dbg(LVL_BIT_WPTR, "ctx[%d] wptr : 0x%08x -> 0x%08x\n",
ctx->str_index, pStrBufDesc->wptr, wptr);
pStrBufDesc->wptr = wptr;
@ -2776,6 +2680,8 @@ static void vpu_dec_send_cmd(struct vpu_dev *dev, u32 idx, u32 cmdid,
{
WARN_ON(!dev || idx >= VPU_MAX_NUM_STREAMS);
if (!rpc_check_is_ready(&dev->shared_mem, idx))
vpu_err("[%d] is not ready\n", idx);
mutex_lock(&dev->cmd_mutex);
rpc_send_cmd_buf(&dev->shared_mem, idx, cmdid, cmdnum, local_cmddata);
mb();
@ -3014,7 +2920,6 @@ static int send_start_cmd(struct vpu_ctx *ctx)
pStrBufDesc->start = ctx->stream_buffer.dma_phy;
pStrBufDesc->end = ctx->stream_buffer.dma_phy + ctx->stream_buffer.dma_size;
pStrBufDesc->LWM = 0x01;
ctx->pre_pic_end_addr = pStrBufDesc->start;
ctx->beginning = pStrBufDesc->start;
pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx] =
@ -3046,7 +2951,6 @@ static int send_start_cmd(struct vpu_ctx *ctx)
v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_START, 0, NULL);
ctx->firmware_stopped = false;
ctx->tsm_sync_flag = true;
ctx->first_data_flag = true;
vpu_calculate_performance(ctx, 0xff, "send start cmd");
@ -3358,8 +3262,6 @@ static void fill_stream_buffer_info(struct vpu_ctx *ctx)
buffer_info->stream_buffer_threshold = frame_threshold[idx];
else
buffer_info->stream_buffer_threshold = 0;
buffer_info->stream_pic_input_count = ctx->frm_total_num;
}
static void set_pic_end_flag(struct vpu_ctx *ctx)
@ -3386,9 +3288,6 @@ static bool vpu_dec_stream_is_ready(struct vpu_ctx *ctx)
if (ctx->fifo_low)
return true;
if (ctx->tsm_sync_flag)
return true;
pStrBufDesc = get_str_buffer_desc(ctx);
stream_size = got_used_space(pStrBufDesc->wptr,
pStrBufDesc->rptr,
@ -3402,15 +3301,11 @@ static bool vpu_dec_stream_is_ready(struct vpu_ctx *ctx)
/*
*frame depth need to be set by user and then the condition works
*/
if (vpu_frm_depth != INVALID_FRAME_DEPTH &&
ctx->stream_input_mode == FRAME_LVL) {
if ((getTSManagerPreBufferCnt(ctx->tsm)) >= vpu_frm_depth)
if (vpu_frm_depth > 0 && ctx->stream_input_mode == FRAME_LVL) {
if (ctx->frm_dec_delay >= vpu_frm_depth)
return false;
}
if ((getTSManagerPreBufferCnt(ctx->tsm)) >= (tsm_buffer_size * 9 / 10))
return false;
if (ctx->ts_threshold > 0 &&
TSM_TS_IS_VALID(ctx->output_ts) &&
TSM_TS_IS_VALID(ctx->capture_ts)) {
@ -3569,11 +3464,14 @@ static void report_buffer_done(struct vpu_ctx *ctx, void *frame_info)
u_int32 *FrameInfo = (u_int32 *)frame_info;
u_int32 fs_id = FrameInfo[0x0];
uint32_t stride = FrameInfo[3];
s64 timestamp = ((s32)FrameInfo[9] * NSEC_PER_SEC) + FrameInfo[10];
bool b10BitFormat = is_10bit_format(ctx);
int buffer_id;
vpu_dbg(LVL_BIT_FUNC, "%s() fs_id=%d, ulFsLumaBase[0]=%x, stride=%d, b10BitFormat=%d, ctx->seqinfo.uBitDepthLuma=%d\n",
__func__, fs_id, FrameInfo[1], stride, b10BitFormat, ctx->seqinfo.uBitDepthLuma);
vpu_dbg(LVL_BIT_TS, "[OUTPUT TS]%32lld\n", timestamp);
ctx->capture_ts = timestamp;
v4l2_update_stream_addr(ctx, 0);
buffer_id = find_buffer_id(ctx, FrameInfo[1]);
@ -3590,7 +3488,6 @@ static void report_buffer_done(struct vpu_ctx *ctx, void *frame_info)
set_data_req_status(p_data_req, FRAME_SKIP);
up(&This->drv_q_lock);
vpu_dec_skip_ts(ctx);
send_skip_event(ctx);
ctx->frm_dis_delay--;
return;
@ -3613,6 +3510,7 @@ static void report_buffer_done(struct vpu_ctx *ctx, void *frame_info)
if (p_data_req->vb2_buf) {
p_data_req->vb2_buf->planes[0].bytesused = This->sizeimage[0];
p_data_req->vb2_buf->planes[1].bytesused = This->sizeimage[1];
p_data_req->vb2_buf->timestamp = timestamp;
if (p_data_req->vb2_buf->state == VB2_BUF_STATE_ACTIVE)
vb2_buffer_done(p_data_req->vb2_buf,
VB2_BUF_STATE_DONE);
@ -3733,69 +3631,6 @@ static void add_buffer_to_queue(struct queue_data *q_data, struct vb2_data_req *
data_req->queued = true;
}
static u32 correct_consumed_length(struct vpu_ctx *ctx,
u32 consumed_pic_bytesused)
{
long total_read_bytes;
long delta;
u32 circle_count;
u32 stream_size;
pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
pStrBufDesc = get_str_buffer_desc(ctx);
stream_size = got_used_space(pStrBufDesc->wptr,
pStrBufDesc->rptr,
pStrBufDesc->start,
pStrBufDesc->end);
total_read_bytes = ctx->total_write_bytes - stream_size;
delta = total_read_bytes - ctx->total_consumed_bytes;
if (delta < ctx->stream_buffer.dma_size)
return consumed_pic_bytesused;
circle_count = delta / ctx->stream_buffer.dma_size;
vpu_dbg(LVL_BIT_FRAME_BYTES,
"ctx[%d] cross over %d circles\n",
ctx->str_index, circle_count);
consumed_pic_bytesused += ctx->stream_buffer.dma_size * circle_count;
ctx->total_consumed_bytes += ctx->stream_buffer.dma_size * circle_count;
return consumed_pic_bytesused;
}
static u32 get_consumed_pic_bytesused(struct vpu_ctx *ctx,
u32 pic_start_addr,
u32 pic_end_addr)
{
u32 consumed_pic_bytesused;
u32 pic_size;
consumed_pic_bytesused = pic_end_addr +
+ ctx->stream_buffer.dma_size
- ctx->pre_pic_end_addr;
consumed_pic_bytesused %= ctx->stream_buffer.dma_size;
pic_size = pic_end_addr + ctx->stream_buffer.dma_size - pic_start_addr;
pic_size %= ctx->stream_buffer.dma_size;
ctx->total_consumed_bytes += consumed_pic_bytesused;
consumed_pic_bytesused = correct_consumed_length(ctx,
consumed_pic_bytesused);
vpu_dbg(LVL_BIT_PIC_ADDR, "<0x%08x 0x%08x>, %8d, %8d\n",
pic_start_addr, pic_end_addr, pic_size, consumed_pic_bytesused);
if (consumed_pic_bytesused < pic_size)
vpu_err("ErrorAddr:[%d] Start(0x%x), End(0x%x), preEnd(0x%x)\n",
ctx->str_index,
pic_start_addr,
pic_end_addr,
ctx->pre_pic_end_addr);
ctx->pre_pic_end_addr = pic_end_addr;
return consumed_pic_bytesused;
}
static int parse_frame_interval_from_seqinfo(struct vpu_ctx *ctx,
MediaIPFW_Video_SeqInfo *seq_info)
{
@ -3814,10 +3649,6 @@ static int parse_frame_interval_from_seqinfo(struct vpu_ctx *ctx,
ctx->frame_interval.numerator /= gcd;
ctx->frame_interval.denominator /= gcd;
mutex_lock(&ctx->instance_mutex);
vpu_dec_set_tsm_frame_rate(ctx);
mutex_unlock(&ctx->instance_mutex);
return 0;
}
@ -4326,12 +4157,11 @@ static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32
int buffer_id;
u_int32 uDecFrmId = event_data[7];
u_int32 uPicStartAddr = event_data[10];
u_int32 uPicEndAddr = event_data[12];
struct queue_data *This = &ctx->q_data[V4L2_DST];
u_int32 uDpbmcCrc;
size_t wr_size;
u32 consumed_pic_bytesused = 0;
struct vb2_data_req *p_data_req = NULL;
u32 consumed_count = event_data[13];
if (This->vdec_std == VPU_VIDEO_HEVC)
uDpbmcCrc = pPerfDcpInfo->uDBEDpbCRC[0];
@ -4351,20 +4181,10 @@ static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32
event_data[0], uPicStartAddr, pQMeterInfo, pPicInfo,
pDispInfo, pPerfInfo, pPerfDcpInfo);
down(&ctx->q_data[V4L2_SRC].drv_q_lock);
if (tsm_use_consumed_length)
consumed_pic_bytesused = get_consumed_pic_bytesused(ctx,
uPicStartAddr,
uPicEndAddr);
up(&ctx->q_data[V4L2_SRC].drv_q_lock);
buffer_id = find_buffer_id(ctx, event_data[0]);
if (buffer_id == -1) {
vpu_err("error: %s() ctx[%d] not find buffer id: %d, addr: 0x%x\n",
__func__, ctx->str_index, uDecFrmId, event_data[0]);
vpu_dec_valid_ts(ctx,
consumed_pic_bytesused,
NULL);
break;
}
@ -4375,18 +4195,20 @@ static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32
else
p_data_req->bfield = true;
vpu_dec_valid_ts(ctx, consumed_pic_bytesused, p_data_req);
This->process_count++;
}
if (ctx->statistic.event[VID_API_EVENT_PIC_DECODED] == 1)
vpu_calculate_performance(ctx, uEvent, "first decoded");
else
vpu_calculate_performance(ctx, uEvent, NULL);
ctx->frm_dec_delay--;
if (ctx->frm_dec_delay >= consumed_count)
ctx->frm_dec_delay -= consumed_count;
else
ctx->frm_dec_delay = 0;
ctx->fifo_low = false;
ctx->frame_decoded = true;
v4l2_update_stream_addr(ctx, 0);
}
break;
case VID_API_EVENT_SEQ_HDR_FOUND: {
MediaIPFW_Video_SeqInfo *pSeqInfo = (MediaIPFW_Video_SeqInfo *)dev->shared_mem.seq_mem_vir;
@ -4522,10 +4344,8 @@ static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32
vpu_dbg(LVL_INFO, "warning: normal release and previous status %s, frame not for display, queue the buffer to list again\n",
bufstat[p_data_req->status]);
if (p_data_req->status == FRAME_DECODED) {
vpu_dec_skip_ts(ctx);
if (p_data_req->status == FRAME_DECODED)
send_skip_event(ctx);
}
}
if (p_data_req->status != FRAME_ALLOC) {
set_data_req_status(p_data_req, FRAME_RELEASE);
@ -4607,20 +4427,14 @@ static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32
queue->qbuf_count,
queue->dqbuf_count);
vpu_dbg(LVL_BIT_FRAME_BYTES,
"[%d]total bytes: %ld, %ld, %ld, %ld\n",
"[%d]total bytes: %ld, %ld\n",
ctx->str_index,
ctx->total_qbuf_bytes,
ctx->total_ts_bytes,
ctx->total_write_bytes,
ctx->total_consumed_bytes);
ctx->total_write_bytes);
update_wptr(ctx, pStrBufDesc, pStrBufDesc->rptr);
ctx->pre_pic_end_addr = pStrBufDesc->rptr;
ctx->beginning = pStrBufDesc->rptr;
ctx->total_qbuf_bytes = 0;
ctx->total_write_bytes = 0;
ctx->total_consumed_bytes = 0;
ctx->total_ts_bytes = 0;
ctx->tsm_sync_flag = true;
up(&queue->drv_q_lock);
ctx->frm_dis_delay = 0;
@ -5438,7 +5252,7 @@ static ssize_t show_instance_command_info(struct device *dev,
statistic = &ctx->statistic;
num += scnprintf(buf + num, PAGE_SIZE - num, "command number:\n");
for (i = VID_API_CMD_NULL; i < VID_API_CMD_YUV_READY + 1; i++) {
for (i = VID_API_CMD_NULL; i < VID_API_CMD_TS + 1; i++) {
size = scnprintf(buf + num, PAGE_SIZE - num,
"\t%40s(%2d):%16ld\n",
cmd2str[i], i, statistic->cmd[i]);
@ -5446,7 +5260,7 @@ static ssize_t show_instance_command_info(struct device *dev,
}
num += scnprintf(buf + num, PAGE_SIZE - num, "\t%40s :%16ld\n",
"UNKNOWN COMMAND", statistic->cmd[VID_API_CMD_YUV_READY + 1]);
"UNKNOWN COMMAND", statistic->cmd[VID_API_CMD_TS + 1]);
num += scnprintf(buf + num, PAGE_SIZE - num, "current command:\n");
num += scnprintf(buf + num, PAGE_SIZE - num,
@ -5572,9 +5386,6 @@ static ssize_t show_instance_buffer_info(struct device *dev,
num += scnprintf(buf + num, PAGE_SIZE - num,
"\t%40s:%16d\n", "total frame number",
ctx->frm_total_num);
num += scnprintf(buf + num, PAGE_SIZE - num,
"\t%40s:%16d\n", "timestamp delay frame",
getTSManagerPreBufferCnt(ctx->tsm));
num += scnprintf(buf + num, PAGE_SIZE - num,
"\t%40s:%16lld\n", "timestamp threshold(ms)",
ctx->ts_threshold);
@ -6159,12 +5970,6 @@ static int v4l2_open(struct file *filp)
ctx->quantization = V4L2_QUANTIZATION_LIM_RANGE;
INIT_LIST_HEAD(&ctx->cmd_q);
INIT_LIST_HEAD(&ctx->perf_q);
ctx->tsm = createTSManager(tsm_buffer_size);
if (!ctx->tsm)
goto err_create_tsm;
sema_init(&ctx->tsm_lock, 1);
resyncTSManager(ctx->tsm, 0, tsm_mode);
ctx->tsm_sync_flag = false;
ctx->output_ts = TSM_TIMESTAMP_NONE;
ctx->capture_ts = TSM_TIMESTAMP_NONE;
create_instance_file(ctx);
@ -6201,6 +6006,7 @@ static int v4l2_open(struct file *filp)
create_fwlog_file(ctx->dev);
create_dbglog_file(ctx->dev);
mutex_unlock(&dev->dev_mutex);
rpc_init_instance(&dev->shared_mem, ctx->str_index);
rpc_set_stream_cfg_value(dev->shared_mem.pSharedInterface, ctx->str_index, vpu_dbe_num);
init_vpu_buffer(ctx);
@ -6218,10 +6024,6 @@ err_firmware_load:
if (vpu_frmcrcdump_ena)
close_crc_file(ctx);
err_open_crc:
if (ctx->tsm)
destroyTSManager(ctx->tsm);
ctx->tsm = NULL;
err_create_tsm:
remove_instance_file(ctx);
dev->ctx[idx] = NULL;
err_init_kfifo:
@ -6315,10 +6117,6 @@ static int v4l2_release(struct file *filp)
if (ctx->instance_wq)
destroy_workqueue(ctx->instance_wq);
if (ctx->tsm) {
destroyTSManager(ctx->tsm);
ctx->tsm = NULL;
}
if (vpu_frmcrcdump_ena)
close_crc_file(ctx);
ctrls_delete_decoder(ctx);
@ -7039,12 +6837,6 @@ module_param(vpu_frmcrcdump_ena, int, 0644);
MODULE_PARM_DESC(vpu_frmcrcdump_ena, "enable frame crc dump(0-1)");
module_param(stream_buffer_threshold, int, 0644);
MODULE_PARM_DESC(stream_buffer_threshold, "stream buffer threshold");
module_param(tsm_mode, int, 0644);
MODULE_PARM_DESC(tsm_mode, "timestamp manager mode(0 : ai, 1 : fifo)");
module_param(tsm_buffer_size, int, 0644);
MODULE_PARM_DESC(tsm_buffer_size, "timestamp manager buffer size");
module_param(tsm_use_consumed_length, int, 0644);
MODULE_PARM_DESC(tsm_use_consumed_length, "timestamp manager use consumed length");
module_param(precheck_show_bytes, int, 0644);
MODULE_PARM_DESC(precheck_show_bytes, "show the beginning of content");
module_param(vpu_show_perf_ena, int, 0644);

View File

@ -68,7 +68,8 @@ extern unsigned int vpu_dbg_level_decoder;
#define VPU_DISABLE_BITS (0x7)
#define V4L2_PIX_FMT_NV12_10BIT v4l2_fourcc('N', 'T', '1', '2') /* Y/CbCr 4:2:0 for 10bit */
#define INVALID_FRAME_DEPTH -1
#define VPU_FRAME_DEPTH_MAX 512
#define VPU_FRAME_DEPTH_DEFAULT 256
#define DECODER_NODE_NUMBER 12 // use /dev/video12 as vpu decoder
#define DEFAULT_LOG_DEPTH 20
#define DEFAULT_FRMDBG_ENABLE 0
@ -342,7 +343,7 @@ struct vpu_dev {
};
struct vpu_statistic {
unsigned long cmd[VID_API_CMD_YUV_READY + 2];
unsigned long cmd[VID_API_CMD_TS + 2];
unsigned long event[VID_API_EVENT_DEC_CFG_INFO + 2];
unsigned long current_cmd;
unsigned long current_event;
@ -462,15 +463,9 @@ struct vpu_ctx {
int frm_dec_delay;
int frm_total_num;
void *tsm;
bool tsm_sync_flag;
u32 pre_pic_end_addr;
long total_qbuf_bytes;
long total_write_bytes;
long total_consumed_bytes;
long total_ts_bytes;
u32 extra_size;
struct semaphore tsm_lock;
s64 output_ts;
s64 capture_ts;
s64 ts_threshold;

View File

@ -54,6 +54,7 @@
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include "vpu_rpc.h"
void rpc_init_shared_memory(struct shared_addr *This,
@ -331,6 +332,7 @@ void rpc_send_cmd_buf(struct shared_addr *This,
{
pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
MediaIPFW_Video_BufDesc *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
BUFFER_DESCRIPTOR_TYPE *desc = NULL;
u_int32 *cmddata;
u_int32 i;
u_int32 *cmdword = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->uWrPtr - pCmdDesc->uStart);
@ -358,6 +360,12 @@ void rpc_send_cmd_buf(struct shared_addr *This,
*cmddata = local_cmddata[i];
rpc_update_cmd_buffer_ptr(pCmdDesc);
}
if (cmdid != VID_API_CMD_FIRM_RESET) {
desc = &pSharedInterface->StreamApiCmdBufferDesc[idx];
desc->wptr++;
if (desc->wptr >= desc->end)
desc->wptr = desc->start;
}
}
u_int32 rpc_MediaIPFW_Video_message_check(struct shared_addr *This)
@ -424,3 +432,56 @@ void rpc_receive_msg_buf(struct shared_addr *This, struct event_msg *msg)
rpc_update_msg_buffer_ptr(pMsgDesc);
}
}
static bool check_is_ready(struct shared_addr *This, u32 idx)
{
pDEC_RPC_HOST_IFACE pSharedInterface = NULL;
BUFFER_DESCRIPTOR_TYPE *desc = NULL;
u32 size;
u32 rptr;
u32 wptr;
u32 used;
if (!This || !This->shared_mem_vir || idx >= VID_API_NUM_STREAMS)
return false;
pSharedInterface = This->shared_mem_vir;
desc = &pSharedInterface->StreamApiCmdBufferDesc[idx];
size = desc->end - desc->start;
rptr = desc->rptr;
wptr = desc->wptr;
used = (wptr + size - rptr) % size;
if (!size || used < size / 2)
return true;
return false;
}
bool rpc_check_is_ready(struct shared_addr *This, u32 idx)
{
u32 cnt = 0;
if (!This || !This->shared_mem_vir || idx >= VID_API_NUM_STREAMS)
return false;
while (!check_is_ready(This, idx)) {
if (cnt > 30)
return false;
mdelay(1);
cnt++;
}
return true;
}
void rpc_init_instance(struct shared_addr *This, u32 idx)
{
pDEC_RPC_HOST_IFACE pSharedInterface = NULL;
BUFFER_DESCRIPTOR_TYPE *desc = NULL;
if (!This || !This->shared_mem_vir || idx >= VID_API_NUM_STREAMS)
return;
pSharedInterface = This->shared_mem_vir;
desc = &pSharedInterface->StreamApiCmdBufferDesc[idx];
desc->wptr = desc->rptr;
if (desc->wptr >= desc->end)
desc->wptr = desc->start;
}

View File

@ -118,5 +118,7 @@ void rpc_send_cmd_buf(struct shared_addr *This,
u_int32 *local_cmddata);
void rpc_receive_msg_buf(struct shared_addr *This, struct event_msg *msg);
u_int32 rpc_MediaIPFW_Video_message_check(struct shared_addr *This);
bool rpc_check_is_ready(struct shared_addr *This, u32 idx);
void rpc_init_instance(struct shared_addr *This, u32 idx);
#endif

View File

@ -1,612 +0,0 @@
/*
* Copyright 2018-2019 NXP
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* Module Name: TimeStamp.c
*
* Description: include TimeStamp stratege for VPU / SW video decoder plugin
*
* Portability: This code is written for Linux OS and Gstreamer
*/
#include <linux/slab.h>
#include <linux/string.h>
#include "vpu_ts.h"
int debug_level;
static void tsm_free_received_entry(TSMRecivedCtl *rctl,
TSMReceivedEntry *entry)
{
entry->next = rctl->free;
rctl->free = entry;
}
static TSMReceivedEntry *tsm_new_received_entry(TSMRecivedCtl *rctl)
{
TSMReceivedEntry *ret = NULL;
if (rctl->free) {
ret = rctl->free;
rctl->free = ret->next;
} else {
TSMReceivedEntryMemory *p = kzalloc(sizeof(TSMReceivedEntryMemory), GFP_KERNEL);
if (p) {
int i;
for (i = 1; i < TSM_RECEIVED_NUNBER; i++) {
TSMReceivedEntry *e = &p->entrys[i];
tsm_free_received_entry(rctl, e);
};
p->next = rctl->memory;
rctl->memory = p;
ret = p->entrys;
}
}
return ret;
}
void TSManagerReceive2(void *handle, TSM_TIMESTAMP timestamp, int size)
{
#define CLEAR_TSM_RENTRY(entry)\
do { \
(entry)->used = 0; \
(entry)->next = NULL; \
} while (0)
TSManager *tsm = (TSManager *) handle;
TSM_VERBOSE("receive2 %u:%02u:%02u.%09u size %d\n",
TSM_TIME_H(timestamp),
TSM_TIME_M(timestamp),
TSM_TIME_S(timestamp),
TSM_TIME_NS(timestamp),
size);
if (tsm) {
if (size > 0) {
TSMRecivedCtl *rctl = &tsm->rctl;
TSMReceivedEntry *e = tsm_new_received_entry(rctl);
if (e) {
CLEAR_TSM_RENTRY(e);
e->ts = timestamp;
e->size = size;
if (rctl->tail) {
rctl->tail->next = e;
rctl->tail = e;
} else
rctl->head = rctl->tail = e;
}
rctl->cnt++;
} else
TSManagerReceive(handle, timestamp);
}
}
static TSM_TIMESTAMP TSManagerGetLastTimeStamp(TSMRecivedCtl *rctl,
int size, int use)
{
TSM_TIMESTAMP ts = TSM_TIMESTAMP_NONE;
TSMReceivedEntry *e;
while ((size > 0) && (e = rctl->head)) {
if (TSM_TS_IS_VALID(e->ts))
ts = ((e->used) ? (TSM_TIMESTAMP_NONE) : (e->ts));
TSM_VERBOSE("ts get: %u:%02u:%02u.%09u\n",
TSM_TIME_H(ts),
TSM_TIME_M(ts),
TSM_TIME_S(ts),
TSM_TIME_NS(ts));
if (use)
e->used = 1;
if (size >= e->size) {
rctl->head = e->next;
if (rctl->head == NULL)
rctl->tail = NULL;
size -= e->size;
rctl->cnt--;
tsm_free_received_entry(rctl, e);
} else {
e->size -= size;
size = 0;
}
}
return ts;
}
void TSManagerFlush2(void *handle, int size)
{
TSManager *tsm = (TSManager *) handle;
if (tsm)
TSManagerGetLastTimeStamp(&tsm->rctl, size, 0);
}
/*======================================================================================
FUNCTION: mfw_gst_receive_ts
DESCRIPTION: Check timestamp and do frame dropping if enabled
ARGUMENTS PASSED: pTimeStamp_Object - TimeStamp Manager to handle related timestamp
timestamp - time stamp of the input buffer which has video data.
RETURN VALUE: None
PRE-CONDITIONS: None
POST-CONDITIONS: None
IMPORTANT NOTES: None
=======================================================================================*/
static void _TSManagerReceive(void *handle, TSM_TIMESTAMP timestamp, void *key)
{
TSManager *tsm = (TSManager *) handle;
if (tsm) {
if (TSM_TS_IS_VALID(timestamp) && (tsm->rx_cnt))
tsm->valid_ts_received = 1;
tsm->rx_cnt++;
if (tsm->cnt < tsm->ts_buf_size - 1) {
tsm->cnt++;
if (tsm->mode == MODE_AI) {
if (TSM_TS_IS_VALID(timestamp)) {
if (tsm->first_rx) {
tsm->last_ts_received = timestamp;
tsm->first_rx = 0;
} else {
if (tsm->suspicious_ts) {
if (timestamp >= tsm->suspicious_ts)
tsm->last_ts_received = timestamp;
tsm->suspicious_ts = 0;
}
if ((timestamp > tsm->last_ts_received)
&& (timestamp - tsm->last_ts_received > tsm->discont_threshold)) {
tsm->suspicious_ts = timestamp;
timestamp = TSM_TIMESTAMP_NONE;
}
}
}
if (TSM_TS_IS_VALID(timestamp)) { // && (TSM_ABS(timestamp, tsm->last_ts_sent)<TSM_SECOND*10))
tsm->ts_buf[tsm->rx].ts = timestamp;
tsm->ts_buf[tsm->rx].age = tsm->age + TSM_PLUS_AGE(tsm);
tsm->ts_buf[tsm->rx].key = key;
tsm->last_ts_received = timestamp;
#ifdef DEBUG
//printf("age should %lld %lld\n", tsm->age, tsm->ts_buf[tsm->rx].age);
//printf("++++++ distance = %d tx=%d, rx=%d, invalid count=%d\n", TSM_DISTANCE(tsm), tsm->tx, tsm->rx,tsm->invalid_ts_count);
#endif
tsm->rx = ((tsm->rx + 1) % tsm->ts_buf_size);
} else
tsm->invalid_ts_count++;
} else if (tsm->mode == MODE_FIFO) {
tsm->ts_buf[tsm->rx].ts = timestamp;
tsm->rx = ((tsm->rx + 1) % tsm->ts_buf_size);
}
TSM_LOG("++Receive %d:%u:%02u:%02u.%09u, invalid:%d, size:%d key %p\n",
tsm->rx_cnt,
TSM_TIME_H(timestamp),
TSM_TIME_M(timestamp),
TSM_TIME_S(timestamp),
TSM_TIME_NS(timestamp),
tsm->invalid_ts_count,
tsm->cnt,
key);
} else
TSM_ERROR("Too many timestamps recieved!! (cnt=%d)\n", tsm->cnt);
}
}
void TSManagerValid2(void *handle, int size, void *key)
{
TSManager *tsm = (TSManager *) handle;
TSM_VERBOSE("valid2 size %d\n", size);
if (tsm) {
TSM_TIMESTAMP ts;
ts = TSManagerGetLastTimeStamp(&tsm->rctl, size, 1);
TSM_VERBOSE("TSManagerGetLastTimeStamp: %u:%02u:%02u.%09u\n",
TSM_TIME_H(ts),
TSM_TIME_M(ts),
TSM_TIME_S(ts),
TSM_TIME_NS(ts));
_TSManagerReceive(tsm, ts, key);
}
}
void TSManagerReceive(void *handle, TSM_TIMESTAMP timestamp)
{
_TSManagerReceive(handle, timestamp, TSM_KEY_NONE);
}
/*======================================================================================
FUNCTION: TSManagerSend
DESCRIPTION: Check timestamp and do frame dropping if enabled
ARGUMENTS PASSED: pTimeStamp_Object - TimeStamp Manager to handle related timestamp
ptimestamp - returned timestamp to use at render
RETURN VALUE: None
PRE-CONDITIONS: None
POST-CONDITIONS: None
IMPORTANT NOTES: None
=======================================================================================*/
static TSM_TIMESTAMP _TSManagerSend2(void *handle, void *key, int send)
{
TSManager *tsm = (TSManager *) handle;
int i;
int index = -1;
int isValidTs = 0;
TSM_TIMESTAMP ts0 = 0, tstmp = TSM_TIMESTAMP_NONE;
unsigned long long age = 0;
TSM_TIMESTAMP half_interval;
if (tsm == NULL)
return tstmp;
i = tsm->tx;
half_interval = TSM_ADAPTIVE_INTERVAL (tsm) >> 1;
if (tsm) {
if (send)
tsm->tx_cnt++;
else {
tsm->cnt++;
tsm->invalid_ts_count++;
}
if (tsm->cnt > 0) {
if (send)
tsm->cnt--;
if (tsm->mode == MODE_AI) {
if (tsm->first_tx == 0)
tstmp = tsm->last_ts_sent + TSM_ADAPTIVE_INTERVAL(tsm);
else
tstmp = tsm->last_ts_sent;
while (i != tsm->rx) {
if (index >= 0) {
if (tsm->ts_buf[i].ts < ts0) {
ts0 = tsm->ts_buf[i].ts;
age = tsm->ts_buf[i].age;
index = i;
}
} else {
ts0 = tsm->ts_buf[i].ts;
age = tsm->ts_buf[i].age;
index = i;
}
if ((TSM_KEY_IS_VALID(key)) && (key == tsm->ts_buf[i].key))
break;
i = ((i + 1) % tsm->ts_buf_size);
}
if (index >= 0) {
if ((tsm->invalid_ts_count) && (ts0 >= ((tstmp) + half_interval))
&& (age > tsm->age)) {
/* use calculated ts0 */
if (send)
tsm->invalid_ts_count--;
} else {
if (send) {
if (index != tsm->tx)
tsm->ts_buf[index] = tsm->ts_buf[tsm->tx];
tsm->tx = ((tsm->tx + 1) % tsm->ts_buf_size);
}
#if 0
if (ts0 >= ((tstmp) + half_interval))
tstmp = tstmp;
else
tstmp = ts0;
#else
tstmp = ts0;
#endif
isValidTs = 1;
}
} else {
if (send)
tsm->invalid_ts_count--;
}
if (tsm->first_tx == 0) {
if (tstmp > tsm->last_ts_sent)
ts0 = (tstmp - tsm->last_ts_sent);
else {
ts0 = 0;
//reset the timestamp to last frame only when new frames's timestamp is earlier than one frame.
if (tstmp + TSM_ADAPTIVE_INTERVAL(tsm) * 3 / 2 < tsm->last_ts_sent)
tstmp = tsm->last_ts_sent;
}
if (ts0 > TSM_ADAPTIVE_INTERVAL(tsm) * 3 / 2) {
TSM_WARNING("Jitter1:%u:%02u:%02u.%09u %u:%02u:%02u.%09u\n",
TSM_TIME_H(ts0),
TSM_TIME_M(ts0),
TSM_TIME_S(ts0),
TSM_TIME_NS(ts0),
TSM_TIME_H(TSM_ADAPTIVE_INTERVAL(tsm) * 3 / 2),
TSM_TIME_M(TSM_ADAPTIVE_INTERVAL(tsm) * 3 / 2),
TSM_TIME_S(TSM_ADAPTIVE_INTERVAL(tsm) * 3 / 2),
TSM_TIME_NS(TSM_ADAPTIVE_INTERVAL(tsm) * 3 / 2));
} else if (ts0 == 0)
TSM_WARNING("Jitter:%u:%02u:%02u.%09u\n",
TSM_TIME_H(ts0),
TSM_TIME_M(ts0),
TSM_TIME_S(ts0),
TSM_TIME_NS(ts0));
if (send) {
if (isValidTs && ts0 > TSM_ADAPTIVE_INTERVAL(tsm) * 2)
ts0 = TSM_ADAPTIVE_INTERVAL(tsm) * 2;
if ((ts0 <= TSM_ADAPTIVE_INTERVAL(tsm) * 2) || (tsm->big_cnt > 3)) {
tsm->big_cnt = 0;
tsm->dur_history_total -=
tsm->dur_history_buf[tsm->dur_history_tx];
tsm->dur_history_buf[tsm->dur_history_tx] = ts0;
tsm->dur_history_tx =
((tsm->dur_history_tx + 1) % TSM_HISTORY_SIZE);
tsm->dur_history_total += ts0;
} else
tsm->big_cnt++;
}
}
if (send) {
tsm->last_ts_sent = tstmp;
tsm->age++;
tsm->first_tx = 0;
}
} else if (tsm->mode == MODE_FIFO) {
tstmp = tsm->ts_buf[tsm->tx].ts;
if (send)
tsm->tx = ((tsm->tx + 1) % tsm->ts_buf_size);
ts0 = tstmp - tsm->last_ts_sent;
if (send)
tsm->last_ts_sent = tstmp;
}
if (send) {
TSM_LOG("--Send %d:%u:%02u:%02u.%09u, int:%u:%02u:%02u.%09u, avg:%u:%02u:%02u.%09u inkey %p\n",
tsm->tx_cnt,
TSM_TIME_H(tstmp),
TSM_TIME_M(tstmp),
TSM_TIME_S(tstmp),
TSM_TIME_NS(tstmp),
TSM_TIME_H(ts0),
TSM_TIME_M(ts0),
TSM_TIME_S(ts0),
TSM_TIME_NS(ts0),
TSM_TIME_H(TSM_ADAPTIVE_INTERVAL(tsm)),
TSM_TIME_M(TSM_ADAPTIVE_INTERVAL(tsm)),
TSM_TIME_S(TSM_ADAPTIVE_INTERVAL(tsm)),
TSM_TIME_NS(TSM_ADAPTIVE_INTERVAL(tsm)),
key);
}
} else {
if (tsm->valid_ts_received == 0) {
if (tsm->first_tx)
tstmp = tsm->last_ts_sent;
else
tstmp = tsm->last_ts_sent + TSM_ADAPTIVE_INTERVAL(tsm);
if (send) {
tsm->first_tx = 0;
tsm->last_ts_sent = tstmp;
}
}
TSM_ERROR("Too many timestamps send!!\n");
}
if (send == 0) {
tsm->cnt--;
tsm->invalid_ts_count--;
}
}
return tstmp;
}
TSM_TIMESTAMP TSManagerSend2(void *handle, void *key)
{
return _TSManagerSend2(handle, key, 1);
}
TSM_TIMESTAMP TSManagerQuery2(void *handle, void *key)
{
return _TSManagerSend2(handle, key, 0);
}
TSM_TIMESTAMP TSManagerSend(void *handle)
{
return TSManagerSend2(handle, TSM_KEY_NONE);
}
TSM_TIMESTAMP TSManagerQuery(void *handle)
{
return TSManagerQuery2(handle, TSM_KEY_NONE);
}
void resyncTSManager(void *handle, TSM_TIMESTAMP synctime, TSMGR_MODE mode)
{
TSManager *tsm = (TSManager *) handle;
if (tsm) {
TSMRecivedCtl *rctl = &tsm->rctl;
TSMReceivedEntry *e = rctl->head;
while ((e = rctl->head)) {
rctl->head = e->next;
tsm_free_received_entry(rctl, e);
};
rctl->cnt = 0;
rctl->tail = NULL;
tsm->first_tx = 1;
tsm->first_rx = 1;
tsm->suspicious_ts = 0;
if (TSM_TS_IS_VALID(synctime))
tsm->last_ts_sent = synctime;
tsm->tx = tsm->rx = 0;
tsm->invalid_ts_count = 0;
tsm->mode = mode;
tsm->age = 0;
tsm->rx_cnt = tsm->tx_cnt = tsm->cnt = 0;
tsm->valid_ts_received = 0;
tsm->big_cnt = 0;
}
}
/*======================================================================================
FUNCTION: mfw_gst_init_ts
DESCRIPTION: alloc and initialize timestamp strcture
ARGUMENTS PASSED: ppTimeStamp_Object - pointer of TimeStamp Manager to handle related timestamp
RETURN VALUE: TimeStamp structure pointer
PRE-CONDITIONS: None
POST-CONDITIONS: None
IMPORTANT NOTES: None
=======================================================================================*/
void *createTSManager(int ts_buf_size)
{
TSManager *tsm = (TSManager *) kzalloc(sizeof(TSManager), GFP_KERNEL);
if (tsm) {
memset(tsm, 0, sizeof(TSManager));
if (ts_buf_size <= 0)
ts_buf_size = TSM_DEFAULT_TS_BUFFER_SIZE;
tsm->ts_buf_size = ts_buf_size;
tsm->ts_buf = kzalloc(sizeof(TSMControl) * ts_buf_size, GFP_KERNEL);
if (tsm->ts_buf == NULL)
goto fail;
resyncTSManager(tsm, (TSM_TIMESTAMP) 0, MODE_AI);
tsm->dur_history_tx = 0;
TSM_BUFFER_SET(tsm->dur_history_buf, TSM_DEFAULT_INTERVAL,
TSM_HISTORY_SIZE);
tsm->dur_history_total = TSM_DEFAULT_INTERVAL << TSM_HISTORY_POWER;
tsm->discont_threshold = 10000000000LL; // 10s
}
return tsm;
fail:
if (tsm) {
if (tsm->ts_buf)
kfree(tsm->ts_buf);
kfree(tsm);
tsm = NULL;
}
return tsm;
}
void destroyTSManager(void *handle)
{
TSManager *tsm = (TSManager *) handle;
if (tsm) {
TSMRecivedCtl *rctl = &tsm->rctl;
TSMReceivedEntryMemory *rmem;
if (tsm->ts_buf)
kfree(tsm->ts_buf);
while ((rmem = rctl->memory)) {
rctl->memory = rmem->next;
kfree(rmem);
}
kfree(tsm);
tsm = NULL;
}
}
void setTSManagerFrameRate(void *handle, int fps_n, int fps_d)
//void setTSManagerFrameRate(void * handle, float framerate)
{
TSManager *tsm = (TSManager *) handle;
TSM_TIMESTAMP ts;
if ((fps_n > 0) && (fps_d > 0) && (fps_n / fps_d <= 80))
ts = TSM_SECOND * fps_d / fps_n;
else
ts = TSM_DEFAULT_INTERVAL;
// TSM_TIMESTAMP ts = TSM_SECOND / framerate;
if (tsm) {
TSM_BUFFER_SET(tsm->dur_history_buf, ts, TSM_HISTORY_SIZE);
tsm->dur_history_total = (ts << TSM_HISTORY_POWER);
TSM_LOG("Set frame intrval:%u:%02u:%02u.%09u\n",
TSM_TIME_H(ts),
TSM_TIME_M(ts),
TSM_TIME_S(ts),
TSM_TIME_NS(ts));
}
}
TSM_TIMESTAMP getTSManagerFrameInterval(void *handle)
{
TSManager *tsm = (TSManager *) handle;
TSM_TIMESTAMP ts = 0;
if (tsm)
ts = TSM_ADAPTIVE_INTERVAL(tsm);
return ts;
}
TSM_TIMESTAMP getTSManagerPosition(void *handle)
{
TSManager *tsm = (TSManager *) handle;
TSM_TIMESTAMP ts = 0;
if (tsm)
ts = tsm->last_ts_sent;
return ts;
}
int getTSManagerPreBufferCnt(void *handle)
{
int i = 0;
TSManager *tsm = (TSManager *) handle;
if (tsm)
i = tsm->rctl.cnt;
return i;
}

View File

@ -1,251 +0,0 @@
/*
* Copyright 2018-2019 NXP
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* Module Name: TimeStamp.h
*
* Description: include TimeStamp stratege for VPU / SW video decoder plugin
*
* Portability: This code is written for Linux OS and Gstreamer
*/
#ifndef _TIMESTAMP_H_
#define _TIMESTAMP_H_
/**
* GST_CLOCK_TIME_NONE:
*
* Constant to define an undefined clock time.
*/
typedef long long TSM_TIMESTAMP;
typedef enum {
MODE_AI,
MODE_FIFO,
} TSMGR_MODE;
#define TSM_TIMESTAMP_NONE ((long long)(-1))
#define TSM_KEY_NONE ((void *)0)
enum {
DEBUG_LEVEL_ERROR = 1,
DEBUG_LEVEL_WARNING,
DEBUG_LEVEL_LOG,
DEBUG_LEVEL_VERBOSE,
};
#define TSM_MESSAGE(level, fmt, ...) \
do { \
if (debug_level >= (level)) { \
pr_info("TSM:"fmt, ##__VA_ARGS__); \
} \
} while (0)
#define TSM_ERROR(...) TSM_MESSAGE(DEBUG_LEVEL_ERROR, ##__VA_ARGS__)
#define TSM_WARNING(...) TSM_MESSAGE(DEBUG_LEVEL_WARNING, ##__VA_ARGS__)
#define TSM_LOG(...) TSM_MESSAGE(DEBUG_LEVEL_LOG, ##__VA_ARGS__)
#define TSM_VERBOSE(...) TSM_MESSAGE(DEBUG_LEVEL_VERBOSE, ##__VA_ARGS__)
#define TSM_HISTORY_POWER 5
#define TSM_HISTORY_SIZE (1 << TSM_HISTORY_POWER)
#define TSM_ADAPTIVE_INTERVAL(tsm) \
(tsm->dur_history_total >> TSM_HISTORY_POWER)
#define TSM_SECOND ((TSM_TIMESTAMP)1000000000)
#define TSM_DEFAULT_INTERVAL (TSM_SECOND/30)
#define TSM_DEFAULT_TS_BUFFER_SIZE (128)
#define TSM_TS_IS_VALID(ts) \
((ts) != TSM_TIMESTAMP_NONE)
#define TSM_KEY_IS_VALID(key) \
((key) != TSM_KEY_NONE)
#define TSM_DISTANCE(tsm)\
(((tsm->rx) >= (tsm->tx))?((tsm->rx)-(tsm->tx)):(tsm->ts_buf_size-(tsm->tx)+(tsm->rx)))
#define TSM_PLUS_AGE(tsm)\
(TSM_DISTANCE(tsm)+tsm->invalid_ts_count+2)
#define TSM_ABS(ts0, ts1)\
(((ts0) > (ts1))?((ts0)-(ts1)):((ts1)-(ts0)))
#define TSM_TIME_H(t) \
(TSM_TS_IS_VALID(t) ? \
(unsigned int) (((TSM_TIMESTAMP)(t)) / (TSM_SECOND * 60 * 60)) : 99)
#define TSM_TIME_M(t) \
(TSM_TS_IS_VALID(t) ? \
(unsigned int) ((((TSM_TIMESTAMP)(t)) / (TSM_SECOND * 60)) % 60) : 99)
#define TSM_TIME_S(t) \
(TSM_TS_IS_VALID(t) ? \
(unsigned int) ((((TSM_TIMESTAMP)(t)) / TSM_SECOND) % 60) : 99)
#define TSM_TIME_NS(t) \
(TSM_TS_IS_VALID(t) ? \
(unsigned int) (((TSM_TIMESTAMP)(t)) % TSM_SECOND) : 999999999)
#define TSM_BUFFER_SET(buf, value, size) \
do { \
int i; \
for (i = 0; i < (size); i++) { \
(buf)[i] = (value); \
} \
} while (0)
#define TSM_RECEIVED_NUNBER 512
typedef struct {
TSM_TIMESTAMP ts;
unsigned long long age;
void *key;
} TSMControl;
typedef struct _TSMReceivedEntry {
TSM_TIMESTAMP ts;
struct _TSMReceivedEntry *next;
unsigned int used:1;
int size;
} TSMReceivedEntry;
typedef struct _TSMReceivedEntryMemory {
struct _TSMReceivedEntryMemory *next;
TSMReceivedEntry entrys[TSM_RECEIVED_NUNBER];
} TSMReceivedEntryMemory;
typedef struct {
TSMReceivedEntry *head;
TSMReceivedEntry *tail;
TSMReceivedEntry *free;
TSMReceivedEntryMemory *memory;
int cnt;
} TSMRecivedCtl;
typedef struct _TSManager {
int first_tx;
int first_rx;
int rx; //timestamps received
int tx; //timestamps transferred
TSM_TIMESTAMP last_ts_sent; //last time stamp sent
TSM_TIMESTAMP last_ts_received;
TSM_TIMESTAMP suspicious_ts;
TSM_TIMESTAMP discont_threshold;
unsigned int invalid_ts_count;
TSMGR_MODE mode;
int ts_buf_size;
int dur_history_tx;
TSM_TIMESTAMP dur_history_total;
TSM_TIMESTAMP dur_history_buf[TSM_HISTORY_SIZE];
TSMControl *ts_buf;
unsigned long long age;
int tx_cnt;
int rx_cnt;
int cnt;
unsigned int valid_ts_received:1;
int big_cnt;
TSMRecivedCtl rctl;
} TSManager;
/**
* GST_CLOCK_TIME_IS_VALID:
* @time: clock time to validate
*
* Tests if a given #GstClockTime represents a valid defined time.
*/
/*!
* This function receive timestamp into timestamp manager.
*
* @param handle handle of timestamp manager.
*
* @param timestamp timestamp received
*
* @return
*/
void TSManagerReceive(void *handle, TSM_TIMESTAMP timestamp);
void TSManagerReceive2(void *handle, TSM_TIMESTAMP timestamp, int size);
void TSManagerFlush2(void *handle, int size);
void TSManagerValid2(void *handle, int size, void *key);
/*!
* This function send the timestamp for next output frame.
*
* @param handle handle of timestamp manager.
*
* @return timestamp for next output frame.
*/
TSM_TIMESTAMP TSManagerSend(void *handle);
TSM_TIMESTAMP TSManagerSend2(void *handle, void *key);
TSM_TIMESTAMP TSManagerQuery2(void *handle, void *key);
TSM_TIMESTAMP TSManagerQuery(void *handle);
/*!
* This function resync timestamp handler when reset and seek
*
* @param handle handle of timestamp manager.
*
* @param synctime the postion time needed to set, if value invalid, position keeps original
*
* @param mode playing mode (AI or FIFO)
*
* @return
*/
void resyncTSManager(void *handle, TSM_TIMESTAMP synctime, TSMGR_MODE mode);
/*!
* This function create and reset timestamp handler
*
* @param ts_buf_size time stamp queue buffer size
*
* @return
*/
void *createTSManager(int ts_buf_size);
/*!
* This function destroy timestamp handler
*
* @param handle handle of timestamp manager.
*
* @return
*/
void destroyTSManager(void *handle);
/*!
* This function set history buffer frame interval by fps_n and fps_d
*
* @param handle handle of timestamp manager.
*
* @param framerate the framerate to be set
*
* @return
*/
void setTSManagerFrameRate(void *handle, int fps_n, int fps_d);
// void setTSManagerFrameRate(void * handle, float framerate);
/*!
* This function set the current calculated Frame Interval
*
* @param handle handle of timestamp manager.
*
* @return
*/
TSM_TIMESTAMP getTSManagerFrameInterval(void *handle);
/*!
* This function get the current time stamp postion
*
* @param handle handle of timestamp manager.
*
* @return
*/
TSM_TIMESTAMP getTSManagerPosition(void *handle);
int getTSManagerPreBufferCnt(void *handle);
#endif /*_TIMESTAMP_H_ */