You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4100 lines
142 KiB
4100 lines
142 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2019. All rights reserved.
|
|
* Description: Defines drive sync interface
|
|
* Author: Hisilicon
|
|
* Create: 2012-12-22
|
|
* History:
|
|
*/
|
|
|
|
#include "drv_sync.h"
|
|
#include "drv_sync_define.h"
|
|
#include "drv_stat_ext.h"
|
|
#include "linux/huanglong/securec.h"
|
|
#include "drv_sync_fc.h"
|
|
|
|
|
|
#include "drv_ao_ext.h"
|
|
#include "drv_sync_intf.h"
|
|
#include "drv_sync_stc.h"
|
|
|
|
#ifdef __cplusplus
|
|
#if __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
#endif
|
|
|
|
#define PCR_GRADIENT_ERR_VALUE 1
|
|
#define SAMPLE_FREQ_DEFAULT_VALUE 27000 /* 27MHZ sample frequence */
|
|
#define VID_LAG_AUD_ADJUST_THRESHOLD (-300)
|
|
#define PCR_DELTA_THRESHOLD 300
|
|
#define RESET_FIRST_FRAME_DISP_TIMEOUT 1000 /* ms */
|
|
#define SYNC_VID_PTS_JUMP_VALID_MIN 5000
|
|
#define SYNC_VID_PTS_JUMP_VALID_MAX 10000
|
|
#define TIME_RATION 1000
|
|
#define VID_THD_FRAMENUM 3
|
|
#define AUD_THD_FRAMENUM 2
|
|
#define MAX_REWIND_COUNT 4
|
|
|
|
#define LOW_DELAY_SYNC_STARTREGION_ADJUST_UNIT 100
|
|
#define LOW_DELAY_SYNC_AUD_SPEED_INT_MAX 2
|
|
#define LOW_DELAY_SYNC_QUICK_AO_DELAY_MIN 200
|
|
#define LOW_DELAY_SYNC_TIME_DECIMAL_UNIT 1000
|
|
#define LOW_DELAY_SYNC_PTS_DIFF_MAX 10
|
|
#define LOW_DELAY_SYNC_PTS_DIFF_MULTIPLE 100
|
|
#define LOW_DELAY_SYNC_AUD_LOW_SPEED_LEVEL 80
|
|
|
|
#define AVPLAY_DEFAULT_START_ADJUST_TIME 90
|
|
#define AVPLAY_DEFAULT_STOP_ADJUST_TIME 70
|
|
#define AVPLAY_MULTIAUD_SYNC_START_REGION 100
|
|
#define AVPLAY_MULTIAUD_SYNC_NOVEL_REGION (3*1000)
|
|
#define SYS_TIME_MAX 0xFFFFFFFFU
|
|
|
|
typedef enum {
|
|
SYNC_PROC_TYPE_SMOOTH,
|
|
SYNC_PROC_TYPE_QUICK,
|
|
SYNC_PROC_TYPE_MAX
|
|
} sync_proc_type;
|
|
|
|
typedef struct {
|
|
td_s64 scr_local_time;
|
|
td_s64 vid_scr_diff;
|
|
td_s64 aud_scr_diff;
|
|
} sync_scr_stat_param;
|
|
|
|
#define sync_check_id_not_ret(id) do { \
|
|
if ((id) >= SYNC_MAX_NUM) { \
|
|
ext_err_sync("invalid id\n"); \
|
|
return; \
|
|
} \
|
|
if (sync_info_ctx_get(id) == TD_NULL) { \
|
|
ext_err_sync("invalid sync\n"); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define sync_check_id(id) do { \
|
|
if ((id) >= SYNC_MAX_NUM) { \
|
|
ext_err_sync("invalid id\n"); \
|
|
return SOC_ERR_SYNC_INVALID_PARA; \
|
|
} \
|
|
if (sync_info_ctx_get(id) == TD_NULL) { \
|
|
ext_err_sync("invalid sync\n"); \
|
|
return SOC_ERR_SYNC_INVALID_PARA; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define drv_sync_lock(mutex) do { \
|
|
if (osal_sem_down_interruptible(mutex)) { \
|
|
ext_fatal_sync("ERR: Sync lock error!\n"); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define drv_sync_unlock(mutex) do { \
|
|
osal_sem_up(mutex); \
|
|
} while (0)
|
|
|
|
#ifdef CONFIG_SOCT_SYNC_DEBUG_SUPPORT
|
|
static osal_semaphore g_sync_dbg_info_mtx;
|
|
|
|
static sync_dbg_info_status *sync_get_vid_dbg_node(sync_context *ctx)
|
|
{
|
|
sync_dbg_info_status *dbg_info = TD_NULL;
|
|
struct list_head *pos = TD_NULL;
|
|
struct list_head *n = TD_NULL;
|
|
td_s32 ret;
|
|
|
|
if (ctx->dbg_list_max_len == 0) {
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (ctx->dbg_list_node_cnt >= ctx->dbg_list_max_len) {
|
|
list_for_each_safe(pos, n, &ctx->dbg_info_list_head) {
|
|
/* get this node info, fill in new parameter */
|
|
dbg_info = list_entry(pos, sync_dbg_info_status, list);
|
|
|
|
/* list is full, delete first node */
|
|
list_del(pos);
|
|
ctx->dbg_list_node_cnt--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* there is not available kmalloc mem, need to malloc */
|
|
if (dbg_info == TD_NULL) {
|
|
dbg_info = (sync_dbg_info_status *)osal_kmalloc(sizeof(sync_dbg_info_status), OSAL_GFP_KERNEL);
|
|
if (dbg_info == TD_NULL) {
|
|
return TD_NULL;
|
|
}
|
|
}
|
|
|
|
ret = memset_s(dbg_info, sizeof(sync_dbg_info_status), 0x0, sizeof(sync_dbg_info_status));
|
|
if (ret != TD_SUCCESS) {
|
|
ext_err_sync("memset_s failed\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
return dbg_info;
|
|
}
|
|
|
|
static void sync_add_vid_dbg_info(sync_context *ctx)
|
|
{
|
|
sync_dbg_info_status *dbg_info = sync_get_vid_dbg_node(ctx);
|
|
if (dbg_info == TD_NULL) {
|
|
return;
|
|
}
|
|
|
|
dbg_info->aud_src_pts = ctx->aud_info.src_pts;
|
|
dbg_info->aud_pts = ctx->aud_info.pts;
|
|
dbg_info->aud_local_time = sync_get_local_time(ctx, SYNC_CHAN_AUD);
|
|
dbg_info->aud_buf_time = ctx->aud_info.buf_time;
|
|
dbg_info->aud_frame_time = ctx->aud_info.frame_time;
|
|
|
|
dbg_info->vid_src_pts = ctx->vid_info.src_pts;
|
|
dbg_info->vid_pts = ctx->vid_info.pts;
|
|
dbg_info->vid_local_time = sync_get_local_time(ctx, SYNC_CHAN_VID);
|
|
dbg_info->vid_delay_time = ctx->vid_info.delay_time;
|
|
dbg_info->vid_frame_time = ctx->vid_info.frame_time;
|
|
|
|
dbg_info->pcr_last = ctx->pcr_sync_info.pcr_last;
|
|
dbg_info->pcr_local_time = sync_get_local_time(ctx, SYNC_CHAN_PCR);
|
|
dbg_info->pcr_delta_time = ctx->pcr_sync_info.pcr_delta;
|
|
dbg_info->vid_pcr_diff = ctx->pcr_sync_info.vid_pcr_diff;
|
|
dbg_info->aud_pcr_diff = ctx->pcr_sync_info.aud_pcr_diff;
|
|
|
|
dbg_info->vid_aud_diff = ctx->vid_aud_diff;
|
|
|
|
dbg_info->disp_time = ctx->vid_info.disp_time;
|
|
|
|
dbg_info->system_time = sync_get_sys_time();
|
|
|
|
dbg_info->proc_type = ctx->vid_opt.proc;
|
|
|
|
dbg_info->idx = ctx->dbg_list_node_idx;
|
|
|
|
list_add_tail(&dbg_info->list, &ctx->dbg_info_list_head);
|
|
|
|
ctx->dbg_list_node_idx++;
|
|
ctx->dbg_list_node_cnt++;
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_release_dbg_list(sync_context *ctx)
|
|
{
|
|
struct list_head *pos = TD_NULL;
|
|
struct list_head *n = TD_NULL;
|
|
sync_dbg_info_status *dbg_info = TD_NULL;
|
|
|
|
if (list_empty(&ctx->dbg_info_list_head)) {
|
|
return;
|
|
}
|
|
|
|
list_for_each_safe(pos, n, &ctx->dbg_info_list_head) {
|
|
dbg_info = list_entry(pos, sync_dbg_info_status, list);
|
|
list_del(pos);
|
|
osal_kfree(dbg_info);
|
|
}
|
|
|
|
INIT_LIST_HEAD(&ctx->dbg_info_list_head);
|
|
ctx->dbg_list_node_idx = 0;
|
|
ctx->dbg_list_node_cnt = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
void sync_proc_debug_info(sync_context *ctx, sync_dbg_info_mode info_type, void *param)
|
|
{
|
|
if (info_type == SYNC_DBG_INFO_SYS_INIT) {
|
|
(void)osal_sem_init(&g_sync_dbg_info_mtx, 1);
|
|
return;
|
|
} else if (info_type == SYNC_DBG_INFO_SYS_DEINIT) {
|
|
osal_sem_destroy(&g_sync_dbg_info_mtx);
|
|
return;
|
|
}
|
|
|
|
drv_sync_lock(&g_sync_dbg_info_mtx);
|
|
|
|
switch (info_type) {
|
|
case SYNC_DBG_INFO_LIST_INITIAL: {
|
|
ctx->dbg_list_node_idx = 0;
|
|
ctx->dbg_list_node_cnt = 0;
|
|
|
|
INIT_LIST_HEAD(&ctx->dbg_info_list_head);
|
|
break;
|
|
}
|
|
|
|
case SYNC_DBG_INFO_LIST_SIZE: {
|
|
if (param == TD_NULL_PTR) {
|
|
ext_err_sync("para is null, sync_log_depth need less than 600\n");
|
|
break;
|
|
}
|
|
|
|
if (*(td_u32 *)param > SYNC_DBG_LIST_MAX_LEN) {
|
|
ext_err_sync("para is invalid, sync_log_depth need less than 600\n");
|
|
break;
|
|
}
|
|
|
|
ctx->dbg_list_max_len = *(td_u32 *)param;
|
|
sync_release_dbg_list(ctx);
|
|
break;
|
|
}
|
|
|
|
case SYNC_DBG_INFO_LIST_RELEASE: {
|
|
sync_release_dbg_list(ctx);
|
|
break;
|
|
}
|
|
|
|
case SYNC_DBG_INFO_LIST_VIDADD: {
|
|
sync_add_vid_dbg_info(ctx);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
drv_sync_unlock(&g_sync_dbg_info_mtx);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
td_u32 sync_get_sys_time(void)
|
|
{
|
|
td_u64 sys_time;
|
|
sys_time = osal_div_u64(osal_sched_clock(), TIME_RATE * TIME_RATE);
|
|
|
|
return (td_u32)sys_time;
|
|
}
|
|
|
|
static td_u32 sync_get_sys_time_cost(td_u32 last_sys_time)
|
|
{
|
|
td_u32 cur_sys_time;
|
|
td_u32 delta;
|
|
|
|
cur_sys_time = sync_get_sys_time();
|
|
if (cur_sys_time > last_sys_time) {
|
|
delta = cur_sys_time - last_sys_time;
|
|
} else {
|
|
delta = (SYS_TIME_MAX - last_sys_time) + 1 + cur_sys_time;
|
|
}
|
|
|
|
return delta;
|
|
}
|
|
|
|
static td_s32 sync_get_pcr_local_time(const sync_context *ctx, td_u32 *cur_local_time)
|
|
{
|
|
td_u32 cost_sys_time;
|
|
td_bool is_pcr_adjust;
|
|
|
|
if ((!ctx->pcr_sync_info.is_pcr_first_come) && (ctx->pcr_sync_info.pcr_adjust_type == SYNC_SCR_ADJUST_MAX)) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (!ctx->pcr_sync_info.is_pcr_local_time) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->pcr_sync_info.pcr_last_sys_time);
|
|
|
|
/* adjust the diff between pcr and sys time */
|
|
is_pcr_adjust = ctx->pcr_sync_info.pcr_gradient <= PERCENT_MAX_VALUE + PCR_GRADIENT_ERR_VALUE &&
|
|
ctx->pcr_sync_info.pcr_gradient >= PERCENT_MAX_VALUE - PCR_GRADIENT_ERR_VALUE;
|
|
if (is_pcr_adjust) {
|
|
cost_sys_time = cost_sys_time * PERCENT_MAX_VALUE / ctx->pcr_sync_info.pcr_gradient;
|
|
}
|
|
|
|
*cur_local_time = ctx->pcr_sync_info.pcr_last_local_time + cost_sys_time;
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_u32 sync_get_local_time(const sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
td_u32 cur_local_time = SYNC_INVALID_PTS;
|
|
td_u32 cost_sys_time;
|
|
|
|
/* In TPLAY Mode, we need video channel localtime, ignore others channel */
|
|
if ((ctx->cur_status == SYNC_STATUS_TPLAY) && (chn != SYNC_CHAN_VID)) {
|
|
return SYNC_INVALID_PTS;
|
|
}
|
|
|
|
if (chn == SYNC_CHAN_AUD) {
|
|
if (!ctx->is_aud_local_time) {
|
|
return SYNC_INVALID_PTS;
|
|
}
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->aud_last_sys_time);
|
|
cur_local_time = ctx->aud_last_local_time + cost_sys_time;
|
|
} else if (chn == SYNC_CHAN_VID) {
|
|
if (!ctx->is_vid_local_time) {
|
|
return SYNC_INVALID_PTS;
|
|
}
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->vid_last_sys_time);
|
|
cur_local_time = ctx->vid_last_local_time + cost_sys_time;
|
|
} else if (chn == SYNC_CHAN_PCR) {
|
|
if (sync_get_pcr_local_time(ctx, &cur_local_time) != TD_SUCCESS) {
|
|
return SYNC_INVALID_PTS;
|
|
}
|
|
} else if (chn == SYNC_CHAN_SCR) {
|
|
if (ctx->scr_support) {
|
|
if (!ctx->is_scr_init) {
|
|
return SYNC_INVALID_PTS;
|
|
}
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->scr_last_sys_time);
|
|
cur_local_time = ctx->scr_last_local_time + cost_sys_time;
|
|
}
|
|
}
|
|
|
|
if (cur_local_time > PCR_TIME_MAX) {
|
|
cur_local_time -= PCR_TIME_MAX;
|
|
}
|
|
|
|
return cur_local_time;
|
|
}
|
|
|
|
static void sync_set_local_time(sync_context *ctx, sync_chan_type chn, td_u32 time)
|
|
{
|
|
if (chn == SYNC_CHAN_AUD) {
|
|
ctx->aud_last_sys_time = sync_get_sys_time();
|
|
ctx->aud_last_local_time = time;
|
|
ctx->is_aud_local_time = TD_TRUE;
|
|
} else if (chn == SYNC_CHAN_VID) {
|
|
ctx->vid_last_sys_time = sync_get_sys_time();
|
|
ctx->vid_last_local_time = time;
|
|
ctx->is_vid_local_time = TD_TRUE;
|
|
} else if (chn == SYNC_CHAN_PCR) {
|
|
ctx->pcr_sync_info.pcr_last_sys_time = sync_get_sys_time();
|
|
ctx->pcr_sync_info.pcr_last_local_time = time;
|
|
ctx->pcr_sync_info.is_pcr_local_time = TD_TRUE;
|
|
} else if (chn == SYNC_CHAN_SCR) {
|
|
if (ctx->scr_support) {
|
|
ctx->scr_last_sys_time = sync_get_sys_time();
|
|
ctx->scr_last_local_time = time;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_pause_update_aud_local_time(sync_context *ctx, td_u32 time)
|
|
{
|
|
if (time == SYNC_INVALID_PTS) {
|
|
return;
|
|
}
|
|
|
|
sync_set_local_time(ctx, SYNC_CHAN_AUD, time);
|
|
ctx->aud_pause_local_time = sync_get_local_time(ctx, SYNC_CHAN_AUD);
|
|
}
|
|
|
|
static void sync_pause_update_vid_local_time(sync_context *ctx, td_u32 time)
|
|
{
|
|
if (time == SYNC_INVALID_PTS) {
|
|
return;
|
|
}
|
|
|
|
sync_set_local_time(ctx, SYNC_CHAN_VID, time);
|
|
ctx->vid_pause_local_time = sync_get_local_time(ctx, SYNC_CHAN_VID);
|
|
}
|
|
|
|
static void sync_pause_update_scr_local_time(sync_context *ctx)
|
|
{
|
|
td_s64 scr_local_time;
|
|
|
|
if (ctx->scr_support == TD_FALSE) {
|
|
return;
|
|
}
|
|
|
|
scr_local_time = sync_get_local_time(ctx, SYNC_CHAN_SCR);
|
|
if (scr_local_time == SYNC_INVALID_PTS) {
|
|
return;
|
|
}
|
|
|
|
sync_set_local_time(ctx, SYNC_CHAN_SCR, (td_u32)scr_local_time);
|
|
ctx->scr_pause_local_time = sync_get_local_time(ctx, SYNC_CHAN_SCR);
|
|
}
|
|
|
|
static void sync_update_pcr_local_time(sync_context *ctx, td_u32 time)
|
|
{
|
|
if (time == SYNC_INVALID_PTS) {
|
|
return;
|
|
}
|
|
|
|
sync_set_local_time(ctx, SYNC_CHAN_PCR, time);
|
|
|
|
if (ctx->cur_status == SYNC_STATUS_PAUSE) {
|
|
ctx->pcr_sync_info.pcr_pause_local_time = sync_get_local_time(ctx, SYNC_CHAN_PCR);
|
|
}
|
|
}
|
|
|
|
td_s32 sync_start(td_handle sync)
|
|
{
|
|
sync_context *ctx = TD_NULL;
|
|
sync_check_id(sync);
|
|
|
|
ctx = sync_info_ctx_get(sync);
|
|
/* if timeout of presync is zero or sync adjust is disabled, disable presync */
|
|
if ((!ctx->attr.pre_sync_timeout) ||
|
|
(ctx->attr.sync_ref == SYNC_REF_NONE)) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->is_buf_fund_finish = TD_TRUE;
|
|
}
|
|
|
|
/* no sync,then no buffund and audio resync */
|
|
if (ctx->attr.sync_ref == SYNC_REF_NONE) {
|
|
ctx->is_aud_resync = TD_FALSE;
|
|
ctx->is_aud_rebuf_fund = TD_FALSE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 sync_pause(td_u32 id)
|
|
{
|
|
sync_context *ctx = TD_NULL;
|
|
|
|
sync_check_id(id);
|
|
|
|
ctx = sync_info_ctx_get(id);
|
|
|
|
ctx->pcr_sync_info.pcr_pause_local_time = sync_get_local_time(ctx, SYNC_CHAN_PCR);
|
|
ctx->aud_pause_local_time = sync_get_local_time(ctx, SYNC_CHAN_AUD);
|
|
ctx->vid_pause_local_time = sync_get_local_time(ctx, SYNC_CHAN_VID);
|
|
|
|
if (ctx->scr_support) {
|
|
ctx->scr_pause_local_time = sync_get_local_time(ctx, SYNC_CHAN_SCR);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 sync_resume(td_u32 id)
|
|
{
|
|
sync_context *ctx = TD_NULL;
|
|
|
|
sync_check_id(id);
|
|
|
|
ctx = sync_info_ctx_get(id);
|
|
/* if resume after reset, the local time won't be reset */
|
|
if (ctx->pcr_sync_info.pcr_pause_local_time != SYNC_INVALID_PTS) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_PCR, ctx->pcr_sync_info.pcr_pause_local_time);
|
|
}
|
|
|
|
if (ctx->aud_pause_local_time != SYNC_INVALID_PTS) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_AUD, ctx->aud_pause_local_time);
|
|
}
|
|
|
|
if (ctx->vid_pause_local_time != SYNC_INVALID_PTS) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_VID, ctx->vid_pause_local_time);
|
|
}
|
|
|
|
if (ctx->scr_support && ctx->scr_pause_local_time != SYNC_INVALID_PTS) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_SCR, ctx->scr_pause_local_time);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 sync_get_time(td_u32 id, td_u32 *local_time, td_u32 *play_time)
|
|
{
|
|
sync_context *ctx = TD_NULL;
|
|
td_u32 aud_local_time;
|
|
td_u32 vid_local_time;
|
|
td_u32 pcr_local_time;
|
|
|
|
sync_check_id(id);
|
|
|
|
ctx = sync_info_ctx_get(id);
|
|
if (ctx->cur_status == SYNC_STATUS_PAUSE) {
|
|
aud_local_time = ctx->aud_pause_local_time;
|
|
vid_local_time = ctx->vid_pause_local_time;
|
|
pcr_local_time = ctx->pcr_sync_info.pcr_pause_local_time;
|
|
} else {
|
|
aud_local_time = sync_get_local_time(ctx, SYNC_CHAN_AUD);
|
|
vid_local_time = sync_get_local_time(ctx, SYNC_CHAN_VID);
|
|
pcr_local_time = sync_get_local_time(ctx, SYNC_CHAN_PCR);
|
|
}
|
|
|
|
if (aud_local_time <= PCR_TIME_MAX) {
|
|
*local_time = aud_local_time;
|
|
*play_time = sync_abs((td_s32)(aud_local_time - ctx->aud_first_valid_pts));
|
|
} else if (vid_local_time <= PCR_TIME_MAX) {
|
|
*local_time = vid_local_time;
|
|
*play_time = sync_abs((td_s32)(vid_local_time - ctx->vid_first_valid_src_pts));
|
|
} else if (pcr_local_time <= PCR_TIME_MAX) {
|
|
*local_time = pcr_local_time;
|
|
*play_time = sync_abs((td_s32)(pcr_local_time - ctx->pcr_sync_info.pcr_first));
|
|
} else {
|
|
*local_time = SYNC_INVALID_PTS;
|
|
*play_time = 0;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static void sync_reprocess_diff_time(const sync_context *ctx, sync_stat_param *param)
|
|
{
|
|
if (param->pcr_local_time == SYNC_INVALID_PTS) {
|
|
param->aud_pcr_diff = 0;
|
|
param->vid_pcr_diff = 0;
|
|
|
|
if ((param->aud_local_time == SYNC_INVALID_PTS) || (param->vid_local_time == SYNC_INVALID_PTS)) {
|
|
param->vid_aud_diff = 0;
|
|
} else {
|
|
param->vid_aud_diff = param->vid_local_time - param->aud_local_time +
|
|
ctx->attr.vid_pts_adjust - ctx->attr.aud_pts_adjust;
|
|
}
|
|
} else {
|
|
if ((param->aud_local_time == SYNC_INVALID_PTS) && (param->vid_local_time == SYNC_INVALID_PTS)) {
|
|
param->vid_aud_diff = 0;
|
|
param->aud_pcr_diff = 0;
|
|
param->vid_pcr_diff = 0;
|
|
} else if (param->aud_local_time == SYNC_INVALID_PTS) {
|
|
param->vid_aud_diff = 0;
|
|
param->aud_pcr_diff = 0;
|
|
param->vid_pcr_diff = param->vid_local_time - param->pcr_local_time + ctx->attr.vid_pts_adjust;
|
|
} else if (param->vid_local_time == SYNC_INVALID_PTS) {
|
|
param->vid_aud_diff = 0;
|
|
param->vid_pcr_diff = 0;
|
|
param->aud_pcr_diff = param->aud_local_time - param->pcr_local_time + ctx->attr.aud_pts_adjust;
|
|
} else {
|
|
param->vid_aud_diff = param->vid_local_time - param->aud_local_time +
|
|
ctx->attr.vid_pts_adjust - ctx->attr.aud_pts_adjust;
|
|
param->vid_pcr_diff = param->vid_local_time - param->pcr_local_time + ctx->attr.vid_pts_adjust;
|
|
param->aud_pcr_diff = param->aud_local_time - param->pcr_local_time + ctx->attr.aud_pts_adjust;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_amend_difftime(const sync_context *ctx, sync_stat_param *param,
|
|
sync_scr_stat_param *scr_param, td_u32 default_diff)
|
|
{
|
|
if (ctx->attr.sync_ref == SYNC_REF_PCR) {
|
|
if (ctx->pcr_sync_info.pcr_adjust_type != SYNC_AUD_ADJUST_SCR) {
|
|
sync_reprocess_diff_time(ctx, param);
|
|
} else {
|
|
if ((param->aud_local_time == SYNC_INVALID_PTS) || (param->vid_local_time == SYNC_INVALID_PTS)) {
|
|
param->vid_aud_diff = default_diff;
|
|
}
|
|
}
|
|
} else if (ctx->attr.sync_ref == SYNC_REF_AUDIO) {
|
|
if ((param->aud_local_time == SYNC_INVALID_PTS) || (param->vid_local_time == SYNC_INVALID_PTS)) {
|
|
param->vid_aud_diff = default_diff;
|
|
}
|
|
} else if (ctx->attr.sync_ref == SYNC_REF_SCR) {
|
|
if (scr_param->scr_local_time == SYNC_INVALID_PTS) {
|
|
scr_param->vid_scr_diff = default_diff;
|
|
scr_param->aud_scr_diff = default_diff;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sync_update_aud_play_speed(sync_context *ctx)
|
|
{
|
|
td_u32 system_time_cost;
|
|
td_u32 local_time_cost;
|
|
|
|
td_u32 aud_last_local_time = sync_get_local_time(ctx, SYNC_CHAN_AUD);
|
|
if (ctx->aud_start_sys_time == TD_INVALID_TIME ||
|
|
ctx->aud_start_local_time == TD_INVALID_TIME ||
|
|
aud_last_local_time == SYNC_INVALID_PTS) {
|
|
return;
|
|
}
|
|
|
|
if (aud_last_local_time < ctx->aud_start_local_time) {
|
|
ctx->aud_start_local_time = TD_INVALID_TIME;
|
|
ctx->aud_start_sys_time = TD_INVALID_TIME;
|
|
return;
|
|
}
|
|
|
|
system_time_cost = sync_get_sys_time_cost(ctx->aud_start_sys_time);
|
|
local_time_cost = aud_last_local_time - ctx->aud_start_local_time;
|
|
|
|
if (local_time_cost > (UINT_MAX / TIME_RATION) || system_time_cost == 0) {
|
|
ctx->aud_start_local_time = TD_INVALID_TIME;
|
|
ctx->aud_start_sys_time = TD_INVALID_TIME;
|
|
return;
|
|
}
|
|
|
|
ctx->aud_speed = (local_time_cost * TIME_RATION) / system_time_cost;
|
|
}
|
|
|
|
static void sync_update_vid_play_speed(sync_context *ctx)
|
|
{
|
|
td_u32 system_time_cost;
|
|
td_u32 local_time_cost;
|
|
|
|
td_u32 vid_last_local_time = sync_get_local_time(ctx, SYNC_CHAN_VID);
|
|
if (ctx->vid_start_sys_time == TD_INVALID_TIME ||
|
|
ctx->vid_start_local_time == TD_INVALID_TIME ||
|
|
vid_last_local_time == SYNC_INVALID_PTS) {
|
|
return;
|
|
}
|
|
|
|
if (vid_last_local_time < ctx->vid_start_local_time) {
|
|
ctx->vid_start_local_time = TD_INVALID_TIME;
|
|
ctx->vid_start_sys_time = TD_INVALID_TIME;
|
|
return;
|
|
}
|
|
|
|
system_time_cost = sync_get_sys_time_cost(ctx->vid_start_sys_time);
|
|
local_time_cost = vid_last_local_time - ctx->vid_start_local_time;
|
|
|
|
if (local_time_cost > (UINT_MAX / TIME_RATION) || system_time_cost == 0) {
|
|
ctx->aud_start_local_time = TD_INVALID_TIME;
|
|
ctx->aud_start_sys_time = TD_INVALID_TIME;
|
|
return;
|
|
}
|
|
|
|
ctx->vid_speed = (local_time_cost * TIME_RATION) / system_time_cost;
|
|
}
|
|
|
|
static void sync_update_play_speed(sync_context *ctx, td_s64 aud_local_time, td_s64 vid_local_time,
|
|
sync_chan_type chn)
|
|
{
|
|
if (ctx->vid_start_sys_time == TD_INVALID_TIME &&
|
|
ctx->vid_start_local_time == TD_INVALID_TIME &&
|
|
vid_local_time != SYNC_INVALID_PTS &&
|
|
chn == SYNC_CHAN_VID) {
|
|
ctx->vid_start_sys_time = sync_get_sys_time();
|
|
ctx->vid_start_local_time = (td_u32)vid_local_time;
|
|
}
|
|
|
|
if (ctx->aud_start_sys_time == TD_INVALID_TIME &&
|
|
ctx->aud_start_local_time == TD_INVALID_TIME &&
|
|
aud_local_time != SYNC_INVALID_PTS &&
|
|
chn == SYNC_CHAN_AUD) {
|
|
ctx->aud_start_sys_time = sync_get_sys_time();
|
|
ctx->aud_start_local_time = (td_u32)aud_local_time;
|
|
}
|
|
|
|
sync_update_aud_play_speed(ctx);
|
|
sync_update_vid_play_speed(ctx);
|
|
}
|
|
|
|
static void sync_calc_difftime(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
td_u32 cur_sys_time = sync_get_sys_time();
|
|
sync_stat_param stat_param;
|
|
sync_scr_stat_param scr_stat_param;
|
|
|
|
/* set mean value of start region as the default vid_aud_diff */
|
|
td_u32 default_diff = (ctx->attr.start_region.vid_plus_time + ctx->attr.start_region.vid_negative_time) / 2;
|
|
|
|
TD_UNUSED(cur_sys_time);
|
|
stat_param.pcr_local_time = sync_get_local_time(ctx, SYNC_CHAN_PCR);
|
|
stat_param.aud_local_time = sync_get_local_time(ctx, SYNC_CHAN_AUD);
|
|
stat_param.vid_local_time = sync_get_local_time(ctx, SYNC_CHAN_VID);
|
|
sync_update_play_speed(ctx, stat_param.aud_local_time, stat_param.vid_local_time, chn);
|
|
|
|
stat_param.aud_pcr_diff = stat_param.aud_local_time - stat_param.pcr_local_time + ctx->attr.aud_pts_adjust;
|
|
stat_param.vid_pcr_diff = stat_param.vid_local_time - stat_param.pcr_local_time + ctx->attr.vid_pts_adjust;
|
|
stat_param.vid_aud_diff = stat_param.vid_local_time - stat_param.aud_local_time +
|
|
ctx->attr.vid_pts_adjust - ctx->attr.aud_pts_adjust;
|
|
|
|
scr_stat_param.scr_local_time = sync_get_local_time(ctx, SYNC_CHAN_SCR);
|
|
scr_stat_param.aud_scr_diff = stat_param.aud_local_time - scr_stat_param.scr_local_time + ctx->attr.aud_pts_adjust;
|
|
scr_stat_param.vid_scr_diff = stat_param.vid_local_time - scr_stat_param.scr_local_time + ctx->attr.vid_pts_adjust;
|
|
|
|
sync_amend_difftime(ctx, &stat_param, &scr_stat_param, default_diff);
|
|
if (scr_stat_param.scr_local_time != SYNC_INVALID_PTS) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_SCR, (td_u32)scr_stat_param.scr_local_time);
|
|
}
|
|
|
|
/* if AudScrDiff and VidScrDiff are both too large, we reinit scr */
|
|
if ((sync_abs(scr_stat_param.aud_scr_diff) > SCR_DISCARD_THRESHOLD) &&
|
|
(sync_abs(scr_stat_param.vid_scr_diff) > SCR_DISCARD_THRESHOLD)) {
|
|
ctx->is_scr_init = TD_FALSE;
|
|
}
|
|
|
|
ext_info_sync("cur_sys_time %d aud_last_sys_time %d aud_local_time %d aud_last_pts %d, \n \
|
|
aud_last_buf_time %3d vid_local_time %d vid_last_pts %d vid_aud_diff %d\n",
|
|
cur_sys_time, ctx->aud_last_sys_time, stat_param.aud_local_time, ctx->aud_last_pts,
|
|
ctx->aud_last_buf_time, stat_param.vid_local_time, ctx->vid_last_pts, stat_param.vid_aud_diff);
|
|
|
|
if (ctx->attr.sync_ref == SYNC_REF_PCR) {
|
|
ext_info_sync("pcr_local_time %d aud_pcr_diff %d vid_pcr_diff %d\n",
|
|
stat_param.pcr_local_time, stat_param.aud_pcr_diff, stat_param.vid_pcr_diff);
|
|
}
|
|
|
|
if (ctx->scr_support && ctx->attr.sync_ref == SYNC_REF_SCR) {
|
|
ext_info_sync("scr_local_time %d aud_scr_diff %d vid_scr_diff %d\n",
|
|
scr_stat_param.scr_local_time, scr_stat_param.aud_scr_diff, scr_stat_param.vid_scr_diff);
|
|
}
|
|
|
|
ctx->pcr_sync_info.last_aud_pcr_diff = ctx->pcr_sync_info.aud_pcr_diff;
|
|
ctx->pcr_sync_info.last_vid_pcr_diff = ctx->pcr_sync_info.vid_pcr_diff;
|
|
ctx->pcr_sync_info.aud_pcr_diff = (td_s32)stat_param.aud_pcr_diff;
|
|
ctx->pcr_sync_info.vid_pcr_diff = (td_s32)stat_param.vid_pcr_diff;
|
|
|
|
ctx->last_vid_aud_diff = ctx->vid_aud_diff;
|
|
ctx->vid_aud_diff = (td_s32)stat_param.vid_aud_diff;
|
|
|
|
ctx->aud_scr_diff = (td_s32)scr_stat_param.aud_scr_diff;
|
|
ctx->vid_scr_diff = (td_s32)scr_stat_param.vid_scr_diff;
|
|
|
|
return;
|
|
}
|
|
|
|
static td_s32 sync_presync_chan_target_init(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
if ((chn == SYNC_CHAN_VID) && (!ctx->is_vid_presync_target_init)) {
|
|
if (ctx->vid_info.pts == SYNC_INVALID_PTS) {
|
|
ext_info_sync("presync vid frame src_pts is -1\n");
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD_BY_AVPLAY;
|
|
return TD_FAILURE;
|
|
} else {
|
|
ctx->vid_presync_target_time = (td_u32)ctx->vid_info.pts;
|
|
ctx->is_vid_presync_target_init = TD_TRUE;
|
|
}
|
|
}
|
|
|
|
if ((chn == SYNC_CHAN_AUD) && (!ctx->is_aud_presync_target_init)) {
|
|
if (ctx->aud_info.pts == SYNC_INVALID_PTS) {
|
|
ext_info_sync("presync aud frame src_pts = -1\n");
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
return TD_FAILURE;
|
|
} else {
|
|
ctx->aud_presync_target_time = (td_u32)ctx->aud_info.pts;
|
|
ctx->is_aud_presync_target_init = TD_TRUE;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static void sync_presync_target_init(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
td_s32 ret = sync_presync_chan_target_init(ctx, chn);
|
|
if (ret != TD_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
if (ctx->is_vid_presync_target_init && ctx->is_aud_presync_target_init) {
|
|
if (ctx->vid_presync_target_time > ctx->aud_presync_target_time) {
|
|
if (ctx->is_use_ext_presync_target && ctx->ext_presync_target_time > ctx->vid_presync_target_time) {
|
|
ctx->presync_target = SYNC_CHAN_EXT;
|
|
ctx->presync_target_time = ctx->ext_presync_target_time;
|
|
} else {
|
|
ctx->presync_target = SYNC_CHAN_VID;
|
|
ctx->presync_target_time = ctx->vid_presync_target_time;
|
|
}
|
|
} else {
|
|
if (ctx->is_use_ext_presync_target && (ctx->ext_presync_target_time > ctx->aud_presync_target_time)) {
|
|
ctx->presync_target = SYNC_CHAN_EXT;
|
|
ctx->presync_target_time = ctx->ext_presync_target_time;
|
|
} else {
|
|
ctx->presync_target = SYNC_CHAN_AUD;
|
|
ctx->presync_target_time = ctx->aud_presync_target_time;
|
|
}
|
|
}
|
|
|
|
ctx->is_use_ext_presync_target = TD_FALSE;
|
|
ctx->is_presync_target_init = TD_TRUE;
|
|
|
|
ext_info_sync("presync target %d vid pts %d aud pts %d\n",
|
|
ctx->presync_target, ctx->vid_presync_target_time, ctx->aud_presync_target_time);
|
|
} else {
|
|
if (chn == SYNC_CHAN_VID) {
|
|
ctx->vid_opt.proc = SYNC_PROC_BLOCK;
|
|
} else if (chn == SYNC_CHAN_AUD) {
|
|
ctx->aud_opt.proc = SYNC_PROC_BLOCK;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_check_pcr_timeout(const sync_context *ctx)
|
|
{
|
|
td_u32 cost_sys_time;
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->pcr_sync_info.pcr_sync_start_sys_time);
|
|
return (cost_sys_time >= PCR_TIMEOUTMS) ? TD_TRUE : TD_FALSE;
|
|
}
|
|
|
|
static td_bool sync_check_aud_timeout(const sync_context *ctx)
|
|
{
|
|
td_u32 cost_sys_time;
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->presync_start_sys_time);
|
|
return (cost_sys_time >= AUD_TIMEOUTMS) ? TD_TRUE : TD_FALSE;
|
|
}
|
|
|
|
static void sync_check_vid_pts_valid(sync_context *ctx, sync_vid_info *info)
|
|
{
|
|
td_s32 delta;
|
|
|
|
if (info->pts == SYNC_INVALID_PTS) {
|
|
ext_warn_sync("Vid pts is invalid\n");
|
|
ctx->vid_pts_series_cnt = 0;
|
|
} else if (info->pts < ctx->vid_last_pts) {
|
|
ext_warn_sync("Vid pts <= Vid vid_last_pts %d\n", ctx->vid_last_pts);
|
|
ctx->vid_pts_series_cnt = 0;
|
|
} else { /* pts jump too much */
|
|
ctx->one_more_frame = TD_FALSE;
|
|
delta = (td_s32)(info->pts - ctx->vid_last_pts);
|
|
if (ctx->is_proc_valid_pts_jump && ctx->is_aud_enable &&
|
|
ctx->cur_status != SYNC_STATUS_TPLAY && !ctx->checking_valid_pts_jump &&
|
|
delta > SYNC_VID_PTS_JUMP_VALID_MIN && delta < SYNC_VID_PTS_JUMP_VALID_MAX) {
|
|
ext_warn_sync("Vid delta %d, and need to check whether valid pts jump.\n", delta);
|
|
ctx->one_more_frame = TD_TRUE;
|
|
ctx->last_vid_info = *info;
|
|
ctx->vid_pts_series_cnt = 0;
|
|
} else if (delta > VID_PTS_GAP) {
|
|
ext_warn_sync("Vid delta %d > VID_PTS_GAP %d\n", delta, VID_PTS_GAP);
|
|
ctx->vid_pts_series_cnt = 0;
|
|
}
|
|
}
|
|
|
|
info->is_pts_valid = TD_FALSE;
|
|
ctx->vid_pts_series_cnt++;
|
|
|
|
if (ctx->vid_pts_series_cnt >= PTS_SERIES_COUNT) {
|
|
info->is_pts_valid = TD_TRUE;
|
|
}
|
|
|
|
ext_info_sync("vid is_pts_valid:%d, pts:%d\n", info->is_pts_valid, info->pts);
|
|
return;
|
|
}
|
|
|
|
static td_void sync_check_aud_pts_valid(sync_context *ctx, sync_aud_info *info)
|
|
{
|
|
td_s32 delta;
|
|
|
|
if (info->pts == SYNC_INVALID_PTS) {
|
|
ext_warn_sync("Aud pts == -1 invalid\n");
|
|
ctx->aud_pts_series_cnt = 0;
|
|
} else if (info->pts < ctx->aud_last_pts) {
|
|
/* The same audio frame may be sent to sync twice for repeating. So info->pts == ctx->aud_last_pts maybe */
|
|
ext_warn_sync("Aud pts < Aud LstPts %d\n", ctx->aud_last_pts);
|
|
ctx->aud_pts_series_cnt = 0;
|
|
} else if (info->is_aud_tplay == TD_FALSE) {
|
|
delta = (td_s32)(info->pts - ctx->aud_last_pts);
|
|
/* frame_time is approximate value */
|
|
if (delta > AUD_PTS_GAP) {
|
|
ext_warn_sync("Aud PtsDelta %d > AUD_PTS_GAP %d\n", delta, AUD_PTS_GAP);
|
|
ctx->aud_pts_series_cnt = 0;
|
|
}
|
|
}
|
|
|
|
info->is_pts_valid = TD_FALSE;
|
|
ctx->aud_pts_series_cnt++;
|
|
|
|
if (ctx->aud_pts_series_cnt >= PTS_SERIES_COUNT) {
|
|
info->is_pts_valid = TD_TRUE;
|
|
}
|
|
|
|
ext_info_sync("aud is_pts_valid:%d, pts:%d\n", info->is_pts_valid, info->pts);
|
|
return;
|
|
}
|
|
|
|
static void sync_presync_pcr(sync_context *ctx, sync_chan_type chn, td_bool *is_sync_finish)
|
|
{
|
|
td_s32 aud_pcr_diff;
|
|
td_s32 vid_pcr_diff;
|
|
td_s32 vid_aud_diff;
|
|
td_u32 pcr_local_time;
|
|
td_u32 vid_local_time;
|
|
td_u32 aud_local_time;
|
|
|
|
pcr_local_time = sync_get_local_time(ctx, SYNC_CHAN_PCR);
|
|
vid_local_time = (td_u32)(ctx->vid_info.pts + ctx->attr.vid_pts_adjust);
|
|
aud_local_time = (td_u32)(ctx->aud_info.pts + ctx->attr.aud_pts_adjust);
|
|
|
|
aud_pcr_diff = aud_local_time - pcr_local_time;
|
|
vid_pcr_diff = vid_local_time - pcr_local_time;
|
|
vid_aud_diff = vid_local_time - aud_local_time;
|
|
|
|
ctx->pcr_sync_info.vid_pcr_diff = vid_pcr_diff;
|
|
ctx->pcr_sync_info.aud_pcr_diff = aud_pcr_diff;
|
|
ctx->vid_aud_diff = vid_aud_diff;
|
|
|
|
if ((pcr_local_time == SYNC_INVALID_PTS) || ((aud_pcr_diff > 0) && (vid_pcr_diff > 0))) {
|
|
if (chn == SYNC_CHAN_VID) {
|
|
ctx->vid_opt.proc = SYNC_PROC_BLOCK;
|
|
} else if (chn == SYNC_CHAN_AUD) {
|
|
ctx->aud_opt.proc = SYNC_PROC_BLOCK;
|
|
}
|
|
|
|
*is_sync_finish = TD_FALSE;
|
|
ext_warn_sync("pcr pre sync, AudPcr %d, VidPcr %d, VidAud:%d,\n", aud_pcr_diff, vid_pcr_diff, vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
if ((aud_pcr_diff < 0) || (vid_pcr_diff < 0)) {
|
|
if (((aud_pcr_diff + PCR_SYNC_MAX_DELTA > 0) &&
|
|
(vid_pcr_diff + PCR_SYNC_MAX_DELTA > 0)) &&
|
|
(ctx->pcr_sync_info.pcr_delta + aud_pcr_diff + PCR_SYNC_MAX_DELTA > 0) &&
|
|
(ctx->pcr_sync_info.pcr_delta + vid_pcr_diff + PCR_SYNC_MAX_DELTA > 0)) {
|
|
/* adjust pcr to this one which is more behind */
|
|
ctx->pcr_sync_info.pcr_delta += (vid_aud_diff > 0) ? aud_pcr_diff : vid_pcr_diff;
|
|
}
|
|
|
|
*is_sync_finish = TD_TRUE;
|
|
ext_warn_sync("pcr pre sync, pcr_delta %d\n", ctx->pcr_sync_info.pcr_delta);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_presync_aud_lead_adjust(sync_context *ctx)
|
|
{
|
|
td_s32 vid_aud_diff;
|
|
td_s32 vid_local_time;
|
|
td_s32 aud_local_time;
|
|
td_bool is_presync_pcr_finish = TD_FALSE;
|
|
|
|
vid_local_time = (td_s32)(ctx->vid_info.pts + ctx->attr.vid_pts_adjust);
|
|
aud_local_time = (td_s32)(ctx->aud_presync_target_time + ctx->attr.aud_pts_adjust);
|
|
|
|
vid_aud_diff = vid_local_time - aud_local_time;
|
|
ctx->vid_aud_diff = vid_aud_diff;
|
|
|
|
/* the difference between video and audio is too large */
|
|
if (vid_aud_diff < (-VID_LAG_DISCARD_THRESHOLD)) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_info_sync("PreSync Giveup vid_aud_diff %d > VID_LAG_DISCARD_THRESHOLD %d\n",
|
|
vid_aud_diff, VID_LAG_DISCARD_THRESHOLD);
|
|
ext_drv_stat_event(EXT_STAT_EVENT_PRE_SYNC, 0);
|
|
return;
|
|
}
|
|
|
|
/* discard vid frame that lag aud frame more than half of start_region.vid_negative_time */
|
|
if (vid_aud_diff < ctx->attr.start_region.vid_negative_time / 2) { /* 2 is used to calculate the half */
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD_BY_AVPLAY;
|
|
return;
|
|
}
|
|
|
|
if (ctx->attr.sync_ref == SYNC_REF_PCR) {
|
|
if (ctx->pcr_sync_info.pcr_adjust_type == SYNC_PCR_ADJUST_SCR) {
|
|
sync_presync_pcr(ctx, SYNC_CHAN_VID, &is_presync_pcr_finish);
|
|
|
|
if (!is_presync_pcr_finish) {
|
|
return;
|
|
}
|
|
} else {
|
|
ctx->pcr_sync_info.pcr_adjust_type = SYNC_AUD_ADJUST_SCR; /* pcr timeout or pcr doesn't come */
|
|
}
|
|
}
|
|
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_info_sync("presync ok vid_aud_diff %d\n", vid_aud_diff);
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_PRE_SYNC, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_presync_ext_mode_adjust(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
td_s32 vid_target_diff;
|
|
td_s32 aud_target_diff;
|
|
|
|
if ((chn == SYNC_CHAN_VID) || (chn == SYNC_CHAN_AUD)) {
|
|
vid_target_diff = (td_s32)(ctx->vid_info.pts - ctx->presync_target_time);
|
|
aud_target_diff = (td_s32)(ctx->aud_info.pts - ctx->presync_target_time);
|
|
|
|
ext_info_sync("vid_target_diff %d, aud_target_diff %d\n", vid_target_diff, aud_target_diff);
|
|
|
|
if ((vid_target_diff > ctx->attr.start_region.vid_negative_time) &&
|
|
(aud_target_diff > ctx->attr.start_region.vid_negative_time)) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_PRE_SYNC, 0);
|
|
return;
|
|
} else {
|
|
if (vid_target_diff < ctx->attr.start_region.vid_negative_time) {
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD_BY_AVPLAY;
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_BLOCK;
|
|
}
|
|
|
|
if (aud_target_diff < ctx->attr.start_region.vid_negative_time) {
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
} else {
|
|
ctx->aud_opt.proc = SYNC_PROC_BLOCK;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_presync_vid_lead_adjust(sync_context *ctx)
|
|
{
|
|
td_s32 vid_aud_diff;
|
|
td_s32 vid_local_time;
|
|
td_s32 aud_local_time;
|
|
td_bool is_presync_pcr_finish = TD_FALSE;
|
|
|
|
vid_local_time = (td_s32)(ctx->vid_presync_target_time + ctx->attr.vid_pts_adjust);
|
|
aud_local_time = (td_s32)(ctx->aud_info.pts + ctx->attr.aud_pts_adjust);
|
|
|
|
vid_aud_diff = vid_local_time - aud_local_time;
|
|
ctx->vid_aud_diff = vid_aud_diff;
|
|
/* the difference between video and audio is too large */
|
|
if (vid_aud_diff > VID_LEAD_DISCARD_THRESHOLD) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_info_sync("presync vid_aud_diff %d > presync_timeoutms %d\n", vid_aud_diff, ctx->attr.pre_sync_timeout);
|
|
ext_drv_stat_event(EXT_STAT_EVENT_PRE_SYNC, 0);
|
|
return;
|
|
}
|
|
|
|
/* discard aud frame that lag vid frame more than half of start_region.vid_plus_time */
|
|
if (vid_aud_diff > ctx->attr.start_region.vid_plus_time / 2) { /* 2 is used to calculate the half */
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
return;
|
|
}
|
|
|
|
if (ctx->attr.sync_ref == SYNC_REF_PCR) {
|
|
if (ctx->pcr_sync_info.pcr_adjust_type == SYNC_PCR_ADJUST_SCR) {
|
|
sync_presync_pcr(ctx, SYNC_CHAN_AUD, &is_presync_pcr_finish);
|
|
|
|
if (!is_presync_pcr_finish) {
|
|
return;
|
|
}
|
|
} else {
|
|
ctx->pcr_sync_info.pcr_adjust_type = SYNC_AUD_ADJUST_SCR; /* pcr timeout or pcr doesn't come */
|
|
}
|
|
}
|
|
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
ext_drv_stat_event(EXT_STAT_EVENT_PRE_SYNC, 0);
|
|
|
|
ext_info_sync("presync ok vid_aud_diff %d\n", vid_aud_diff);
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_check_presync_finished(sync_context *ctx)
|
|
{
|
|
td_u32 cost_sys_time;
|
|
|
|
if (ctx->presync_start_sys_time == TD_INVALID_TIME) {
|
|
ctx->presync_start_sys_time = sync_get_sys_time();
|
|
}
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->presync_start_sys_time);
|
|
|
|
/* do not do presync if video or audio is disable */
|
|
if ((!ctx->is_aud_enable) || (!ctx->is_vid_enable)) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_PRE_SYNC, 0);
|
|
return TD_TRUE;
|
|
}
|
|
|
|
/* presync timeout */
|
|
if (cost_sys_time >= ctx->attr.pre_sync_timeout) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_PRE_SYNC, 0);
|
|
|
|
ext_info_sync("presync timeout %d aud_buf_time %d aud frame num %d vid delay time %d\n",
|
|
cost_sys_time, ctx->aud_info.buf_time, ctx->aud_info.frame_num, ctx->vid_info.delay_time);
|
|
return TD_TRUE;
|
|
}
|
|
|
|
/* video buffer or audio buffer will be blocked */
|
|
if ((ctx->cur_buf_status.vid_buf_state == SYNC_BUF_STATE_HIGH) ||
|
|
(ctx->cur_buf_status.aud_buf_state == SYNC_BUF_STATE_HIGH)) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_presync_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_PRE_SYNC, 1);
|
|
|
|
ext_info_sync("presync buf block aud %d vid %d\n",
|
|
ctx->cur_buf_status.aud_buf_state, ctx->cur_buf_status.vid_buf_state);
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_presync(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
td_bool is_presync_finish;
|
|
|
|
is_presync_finish = sync_check_presync_finished(ctx);
|
|
if (is_presync_finish == TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
/* prepare presync target */
|
|
if (!ctx->is_presync_target_init) {
|
|
sync_presync_target_init(ctx, chn);
|
|
|
|
/* presync target is not ready */
|
|
if (!ctx->is_presync_target_init) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (SYNC_CHAN_EXT == ctx->presync_target) {
|
|
sync_presync_ext_mode_adjust(ctx, chn);
|
|
} else if (chn == ctx->presync_target) {
|
|
if (SYNC_CHAN_VID == chn) {
|
|
ctx->vid_opt.proc = SYNC_PROC_BLOCK;
|
|
ctx->vid_aud_diff = (td_s32)(ctx->vid_presync_target_time - ctx->aud_info.pts);
|
|
} else {
|
|
ctx->aud_opt.proc = SYNC_PROC_BLOCK;
|
|
ctx->vid_aud_diff = (td_s32)(ctx->vid_info.pts - ctx->aud_presync_target_time);
|
|
}
|
|
} else {
|
|
/* audio wait for video */
|
|
if (chn == SYNC_CHAN_VID) {
|
|
sync_presync_aud_lead_adjust(ctx);
|
|
} else if (chn == SYNC_CHAN_AUD) { /* video wait for audio */
|
|
sync_presync_vid_lead_adjust(ctx);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_check_buf_fund_status(sync_context *ctx, td_u32 cost_sys_time)
|
|
{
|
|
/* cumulation timeout */
|
|
if (cost_sys_time > BUF_FUND_TIMEOUT) {
|
|
ctx->buf_fund_end_sys_time = sync_get_sys_time();
|
|
ctx->is_buf_fund_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_BUF_READY, SYNC_BUF_STATE_NORMAL);
|
|
ext_info_sync("buf fund timeout %d aud_buf_time %d aud frame num %d vid delay time %d\n",
|
|
cost_sys_time, ctx->aud_info.buf_time, ctx->aud_info.frame_num, ctx->vid_info.delay_time);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
/* video or audio buffer will be blocked */
|
|
if ((SYNC_BUF_STATE_HIGH == ctx->cur_buf_status.vid_buf_state) ||
|
|
(SYNC_BUF_STATE_HIGH == ctx->cur_buf_status.aud_buf_state)) {
|
|
ctx->buf_fund_end_sys_time = sync_get_sys_time();
|
|
ctx->is_buf_fund_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_BUF_READY, SYNC_BUF_STATE_HIGH);
|
|
|
|
ext_info_sync("buf fund, buf block aud %d vid %d\n",
|
|
ctx->cur_buf_status.aud_buf_state, ctx->cur_buf_status.vid_buf_state);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_buf_fund(sync_context *ctx)
|
|
{
|
|
td_u32 cost_sys_time;
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->presync_end_sys_time);
|
|
if (sync_check_buf_fund_status(ctx, cost_sys_time) == TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
if (ctx->is_vid_enable && ctx->is_aud_enable) {
|
|
if ((ctx->aud_info.buf_time + ctx->aud_info.frame_time >= AO_TRACK_AIP_START_LATENCYMS) ||
|
|
(ctx->aud_info.frame_num >= SYNC_AUD_BUF_NORMAL_FRMNUM)) {
|
|
ctx->buf_fund_end_sys_time = sync_get_sys_time();
|
|
ctx->is_buf_fund_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_BUF_READY, SYNC_BUF_STATE_LOW);
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_BLOCK;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
}
|
|
|
|
ext_info_sync("buf fund Ok %d aud buf_time %d aud frame_num %d vid delay_time %d\n",
|
|
cost_sys_time, ctx->aud_info.buf_time, ctx->aud_info.frame_num, ctx->vid_info.delay_time);
|
|
} else if (ctx->is_vid_enable && (!ctx->is_aud_enable)) {
|
|
ctx->buf_fund_end_sys_time = sync_get_sys_time();
|
|
ctx->is_buf_fund_finish = TD_TRUE;
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_BUF_READY, SYNC_BUF_STATE_LOW);
|
|
ext_info_sync("vid buf fund Ok\n");
|
|
} else if ((!ctx->is_vid_enable) && ctx->is_aud_enable) {
|
|
if ((ctx->aud_info.buf_time + ctx->aud_info.frame_time >= AO_TRACK_AIP_START_LATENCYMS) ||
|
|
(ctx->aud_info.frame_num >= SYNC_AUD_BUF_NORMAL_FRMNUM)) {
|
|
ctx->buf_fund_end_sys_time = sync_get_sys_time();
|
|
ctx->is_buf_fund_finish = TD_TRUE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_BUF_READY, SYNC_BUF_STATE_LOW);
|
|
ext_info_sync("aud buf fund Ok\n");
|
|
} else {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_check_aud_resync_finished(sync_context *ctx)
|
|
{
|
|
td_u32 cost_sys_time = sync_get_sys_time_cost(ctx->presync_start_sys_time);
|
|
/* resync timeout */
|
|
if (cost_sys_time >= AUD_RESYNC_TIMEOUT) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_aud_resync = TD_FALSE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_info_sync("aud resync cost time: %d, timeout. aud buf_time: %d, frame_num: %d\n",
|
|
cost_sys_time, ctx->aud_info.buf_time, ctx->aud_info.frame_num);
|
|
return TD_TRUE;
|
|
}
|
|
|
|
/* buffer blocked */
|
|
if (SYNC_BUF_STATE_HIGH == ctx->cur_buf_status.aud_buf_state) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_aud_resync = TD_FALSE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_info_sync("aud resync buf block\n");
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_aud_resync(sync_context *ctx)
|
|
{
|
|
td_u32 vid_local_time;
|
|
td_s32 vid_aud_diff;
|
|
|
|
if (sync_check_aud_resync_finished(ctx) == TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
/* discard the frame if pts is -1 */
|
|
if (ctx->aud_info.pts == SYNC_INVALID_PTS) {
|
|
ext_info_sync("aud resync aud pts is -1\n");
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
return;
|
|
}
|
|
|
|
vid_local_time = sync_get_local_time(ctx, SYNC_CHAN_VID);
|
|
vid_aud_diff = (td_s32)(vid_local_time - ctx->aud_info.pts + AO_TRACK_AIP_START_LATENCYMS);
|
|
/* The difference is too large */
|
|
if (sync_abs(vid_aud_diff) > AUD_RESYNC_ADJUST_THRESHOLD) {
|
|
ctx->is_aud_resync = TD_FALSE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
ext_info_sync("in aud resync vid_aud_diff %d > AUD_RESYNC_ADJUST_THRESHOLD %d\n",
|
|
vid_aud_diff, AUD_RESYNC_ADJUST_THRESHOLD);
|
|
return;
|
|
}
|
|
|
|
/* adjust into sync start range */
|
|
if ((vid_aud_diff <= ctx->attr.start_region.vid_plus_time) &&
|
|
(vid_aud_diff >= ctx->attr.start_region.vid_negative_time) &&
|
|
(sync_abs(vid_aud_diff) <= ctx->aud_info.frame_time)) {
|
|
ctx->presync_end_sys_time = sync_get_sys_time();
|
|
ctx->is_aud_resync = TD_FALSE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
ext_info_sync("is_aud_resync Ok vid_aud_diff %d\n", vid_aud_diff);
|
|
|
|
return;
|
|
}
|
|
|
|
if (vid_aud_diff > 0) {
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
ext_info_sync("aud resync is discard, vid_aud_diff: %d\n", vid_aud_diff);
|
|
} else {
|
|
ctx->aud_opt.proc = SYNC_PROC_BLOCK;
|
|
ext_info_sync("aud resync is block, vid_aud_diff: %d\n", vid_aud_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_aud_rebuf_fund(sync_context *ctx)
|
|
{
|
|
td_u32 cost_sys_time;
|
|
|
|
cost_sys_time = sync_get_sys_time_cost(ctx->presync_end_sys_time);
|
|
/* timeout */
|
|
if (cost_sys_time > BUF_FUND_TIMEOUT) {
|
|
ctx->is_aud_rebuf_fund = TD_FALSE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
ext_info_sync("aud rebuf fund cost: %d, timeout. aud buf_time: %d, frame_num: %d\n",
|
|
cost_sys_time, ctx->aud_info.buf_time, ctx->aud_info.frame_num);
|
|
return;
|
|
}
|
|
|
|
/* buffer blocked */
|
|
if (ctx->cur_buf_status.aud_buf_state == SYNC_BUF_STATE_HIGH) {
|
|
ctx->is_aud_rebuf_fund = TD_FALSE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
ext_info_sync("aud rebuf fund is buf block\n");
|
|
return;
|
|
}
|
|
|
|
if (ctx->aud_info.buf_time + ctx->aud_info.frame_time >= AO_TRACK_AIP_START_LATENCYMS) {
|
|
ctx->is_aud_rebuf_fund = TD_FALSE;
|
|
ctx->aud_opt.proc = SYNC_PROC_CONTINUE;
|
|
ext_info_sync("aud rebuf fund is Ok\n");
|
|
} else {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_proc_vid_repeat_cnt(sync_context *ctx, sync_proc_type proc_type, td_s32 vid_target_diff)
|
|
{
|
|
td_u32 repeat_count;
|
|
|
|
if (!ctx->quick_repeat_support) {
|
|
ctx->vid_repeat_cnt++;
|
|
return;
|
|
}
|
|
|
|
if (proc_type == SYNC_PROC_TYPE_SMOOTH) {
|
|
ctx->vid_opt.repeat = 1;
|
|
ctx->vid_repeat_cnt++;
|
|
return;
|
|
}
|
|
|
|
if ((proc_type == SYNC_PROC_TYPE_QUICK) && (ctx->is_vid_normal_play == TD_FALSE)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_BLOCK;
|
|
ext_warn_sync("--BLOCK FIRST FRAME---\n");
|
|
return;
|
|
}
|
|
|
|
if ((vid_target_diff >= ctx->vid_info.frame_time) && (ctx->vid_info.frame_time != 0)) {
|
|
repeat_count = (td_u32)(vid_target_diff / ctx->vid_info.frame_time);
|
|
repeat_count = (repeat_count > VID_REPEAT_MAX_COUNT) ? VID_REPEAT_MAX_COUNT : repeat_count;
|
|
|
|
ctx->vid_repeat_cnt += repeat_count;
|
|
ctx->vid_opt.repeat = repeat_count;
|
|
ext_info_sync("vid_target_diff: %d, frame_time: %d, repeat_count: %d\n",
|
|
vid_target_diff, ctx->vid_info.frame_time, repeat_count);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_smooth_repeat(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
/* repeat one frame every VID_SMOOTH_REPEAT_INTERVAL frame */
|
|
if (!(ctx->vid_repeat_play_cnt % VID_SMOOTH_REPEAT_INTERVAL)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_REPEAT;
|
|
|
|
if (chn == SYNC_CHAN_VID) {
|
|
(void)sync_proc_vid_repeat_cnt(ctx, SYNC_PROC_TYPE_SMOOTH, vid_aud_diff);
|
|
}
|
|
|
|
ext_info_vsync(chn, "vid aud diff %d smooth, vid repeat\n", vid_aud_diff);
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_vsync(chn, "vid aud diff %d smooth, vid play\n", vid_aud_diff);
|
|
}
|
|
|
|
if (chn == SYNC_CHAN_VID) {
|
|
ctx->vid_repeat_play_cnt++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_aud_sync_vid_lead_adjust_aud(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
if (vid_aud_diff > ctx->attr.novel_region.vid_plus_time) {
|
|
/* there is enough audio data in ao buffer */
|
|
if ((ctx->aud_info.buf_time >= (AO_PCM_DF_UNSTALL_THD_FRAMENUM * ctx->aud_info.frame_time)) &&
|
|
(ctx->aud_info.frame_num >= AO_PCM_MAX_UNSTALL_THD_FRAMENUM)) {
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
|
|
ext_info_async(chn, "vid lead aud %d, aud discard\n", vid_aud_diff);
|
|
}
|
|
} else {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_NORMAL;
|
|
ext_info_async(chn, "vid lead aud %d, aud play\n", vid_aud_diff);
|
|
}
|
|
}
|
|
|
|
/* refer to audio and video is ahead of audio */
|
|
static void sync_aud_sync_vid_lead_adjust(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
sync_aud_sync_vid_lead_adjust_aud(ctx, chn, vid_aud_diff);
|
|
|
|
if ((ctx->cur_buf_status.is_buf_time_need_ctrl == TD_TRUE) &&
|
|
(ctx->cur_buf_status.vid_buf_state >= SYNC_BUF_STATE_HIGH)) { /* the video buffer reach high waterline */
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_vsync(chn, "vid lead aud %d buf block, vid play\n", vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
/* there is space in video buffer */
|
|
/* is_buf_time_need_ctrl is true in the live. In the live broadcast, need to detect the buffer waterline.
|
|
* If the waterline exceeds normal, do't repeat the video frame. If the video frame is repeated,
|
|
* it may cause buffer overflow when buffer waterline is hight in the live broadcast.
|
|
*/
|
|
if (vid_aud_diff > ctx->attr.novel_region.vid_plus_time) {
|
|
if (ctx->attr.novel_region.smooth_play || ctx->vid_first_pts == SYNC_INVALID_PTS) {
|
|
sync_smooth_repeat(ctx, chn, vid_aud_diff);
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_REPEAT;
|
|
|
|
if (chn == SYNC_CHAN_VID) {
|
|
(void)sync_proc_vid_repeat_cnt(ctx, SYNC_PROC_TYPE_QUICK, vid_aud_diff);
|
|
}
|
|
|
|
ext_info_vsync(chn, "vid novel lead aud %d, vid repeat\n", vid_aud_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (ctx->attr.start_region.smooth_play || ctx->vid_first_pts == SYNC_INVALID_PTS) {
|
|
sync_smooth_repeat(ctx, chn, vid_aud_diff);
|
|
} else {
|
|
/* If smoothy is closed,video should be continues to play when audio buf is empty */
|
|
if ((ctx->cur_buf_status.aud_buf_state == SYNC_BUF_STATE_EMPTY) &&
|
|
(ctx->attr.start_region.smooth_play == TD_FALSE)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_warn_sync("aud buf is empty! vid play normally! \n");
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_REPEAT;
|
|
|
|
if (chn == SYNC_CHAN_VID) {
|
|
(void)sync_proc_vid_repeat_cnt(ctx, SYNC_PROC_TYPE_QUICK, vid_aud_diff);
|
|
}
|
|
|
|
ext_info_vsync(chn, "vid lead aud %d, vid repeat\n", vid_aud_diff);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_smooth_discard(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
/* discard one frame in every VID_SMOOTH_DISCARD_INTERVAL frame */
|
|
if (!(ctx->vid_discard_play_cnt % VID_SMOOTH_DISCARD_INTERVAL)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD;
|
|
|
|
if (chn == SYNC_CHAN_VID) {
|
|
ctx->vid_discard_cnt++;
|
|
}
|
|
|
|
ext_info_vsync(chn, "vid aud diff %d smooth, vid discard\n", vid_aud_diff);
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
ext_info_vsync(chn, "vid aud diff %d smooth, vid play\n", vid_aud_diff);
|
|
}
|
|
|
|
if (chn == SYNC_CHAN_VID) {
|
|
ctx->vid_discard_play_cnt++;
|
|
}
|
|
}
|
|
|
|
/* refer to audio and video is behind audio */
|
|
static void sync_aud_sync_vid_lag_adjust(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
if (ctx->cur_buf_status.vid_buf_state == SYNC_BUF_STATE_EMPTY) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
if (ctx->cur_buf_status.aud_buf_state != SYNC_BUF_STATE_HIGH) {
|
|
if (ctx->vid_aud_diff < VID_LAG_AUD_ADJUST_THRESHOLD) {
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_MUTE_REPEAT;
|
|
ext_info_async(chn, "vid buf low, vid_aud_diff: %d, aud mute repeat\n", vid_aud_diff);
|
|
} else {
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_DOWN;
|
|
ext_info_async(chn, "vid buf low, vid_aud_diff: %d, aud speed down\n", vid_aud_diff);
|
|
}
|
|
}
|
|
|
|
ext_info_vsync(chn, "vid buf low, vid_aud_diff: %d, vid play\n", vid_aud_diff);
|
|
return;
|
|
} else if (ctx->cur_buf_status.vid_buf_state == SYNC_BUF_STATE_LOW) {
|
|
if (ctx->cur_buf_status.aud_buf_state != SYNC_BUF_STATE_HIGH) {
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_DOWN;
|
|
ext_info_async(chn, "vid buf low, vid_aud_diff: %d, aud speed down\n", vid_aud_diff);
|
|
}
|
|
}
|
|
|
|
if (vid_aud_diff < ctx->attr.novel_region.vid_negative_time) {
|
|
if (ctx->attr.novel_region.smooth_play) {
|
|
sync_smooth_discard(ctx, chn, vid_aud_diff);
|
|
} else {
|
|
/* discard time before vdec */
|
|
ctx->vid_opt.vdec_discard_time = sync_abs(vid_aud_diff);
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD;
|
|
|
|
if (chn == SYNC_CHAN_VID) {
|
|
ctx->vid_discard_cnt++;
|
|
}
|
|
|
|
ext_info_vsync(chn, "vid novel lag aud %d, vid discard\n", vid_aud_diff);
|
|
}
|
|
} else {
|
|
if (ctx->attr.start_region.smooth_play) {
|
|
sync_smooth_discard(ctx, chn, vid_aud_diff);
|
|
} else {
|
|
/* discard time before vdec */
|
|
ctx->vid_opt.vdec_discard_time = sync_abs(vid_aud_diff);
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD;
|
|
|
|
if (chn == SYNC_CHAN_VID) {
|
|
ctx->vid_discard_cnt++;
|
|
}
|
|
|
|
ext_info_vsync(chn, "vid lag aud %d, vid discard\n", vid_aud_diff);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_is_in_start_region(const sync_context *ctx, td_s32 vid_aud_diff)
|
|
{
|
|
if ((vid_aud_diff <= ctx->attr.start_region.vid_plus_time) &&
|
|
(vid_aud_diff >= ctx->attr.start_region.vid_negative_time)) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static td_bool check_is_sync_adjust(sync_context *ctx, td_s32 vid_aud_diff)
|
|
{
|
|
if (!ctx->is_vid_sync_adjust) {
|
|
/* already in the start region */
|
|
if (sync_is_in_start_region(ctx, vid_aud_diff)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->sync_adjust_delay_frm_cnt = 0;
|
|
|
|
ext_info_sync("vid sync aud, VidAudDiff %d, Play\n", vid_aud_diff);
|
|
|
|
return TD_FALSE;
|
|
} else {
|
|
if ((ctx->sync_adjust_delay_frm_cnt < SYNC_ADJUST_DELAY_CNT) &&
|
|
(ctx->is_vid_normal_play == TD_TRUE)) {
|
|
ctx->sync_adjust_delay_frm_cnt++;
|
|
ext_info_sync("adjust delay cnt:%d VidAudDiff %d\n",
|
|
ctx->sync_adjust_delay_frm_cnt, ctx->vid_aud_diff);
|
|
return TD_FALSE;
|
|
}
|
|
|
|
ctx->sync_adjust_delay_frm_cnt = 0;
|
|
ctx->is_vid_sync_adjust = TD_TRUE;
|
|
}
|
|
}
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static td_bool is_stop_sync_adjust(sync_context *ctx, td_s32 vid_aud_diff)
|
|
{
|
|
if (sync_is_in_start_region(ctx, vid_aud_diff)) {
|
|
if ((ctx->is_use_stop_region == TD_TRUE && sync_abs(vid_aud_diff) <= ctx->vid_info.frame_time) ||
|
|
(ctx->is_use_stop_region == TD_FALSE)) {
|
|
ctx->is_vid_sync_adjust = TD_FALSE;
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
ctx->pcr_sync_info.is_pcr_aud_sync_ok = TD_TRUE;
|
|
ctx->pcr_sync_info.is_pcr_vid_sync_ok = TD_TRUE;
|
|
|
|
ext_info_sync("Vid vid_aud_diff Aud, VidAudDiff %d, Play\n", vid_aud_diff);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
}
|
|
|
|
/* video audio difference is too large */
|
|
if ((vid_aud_diff > VID_LEAD_DISCARD_THRESHOLD) || (vid_aud_diff < (-VID_LAG_DISCARD_THRESHOLD))) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
ext_info_sync("vid_aud_diff %d is too large, Play\n", vid_aud_diff);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
/* adjust referring to audio */
|
|
static void sync_aud_sync_adjust(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
if (check_is_sync_adjust(ctx, vid_aud_diff) == TD_FALSE) {
|
|
return;
|
|
}
|
|
|
|
if (is_stop_sync_adjust(ctx, vid_aud_diff) == TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
/* video is ahead of audio */
|
|
if (vid_aud_diff > 0) {
|
|
sync_aud_sync_vid_lead_adjust(ctx, chn, vid_aud_diff);
|
|
} else { /* video is behind audio */
|
|
sync_aud_sync_vid_lag_adjust(ctx, chn, vid_aud_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_vid_sync_aud_lead_adjust_vid(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
if (vid_aud_diff < ctx->attr.novel_region.vid_negative_time) {
|
|
/* there is enough video data in buffer */
|
|
if (ctx->cur_buf_status.vid_buf_state >= SYNC_BUF_STATE_HIGH &&
|
|
(ctx->vid_info.delay_time >= ctx->vid_info.frame_time * VID_THD_FRAMENUM)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD;
|
|
|
|
ext_info_async(chn, "aud lead vid %d, vid discard\n", vid_aud_diff);
|
|
} else {
|
|
sync_smooth_discard(ctx, chn, vid_aud_diff);
|
|
}
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_async(chn, "aud lead vid %d, vid play\n", vid_aud_diff);
|
|
}
|
|
}
|
|
|
|
static void sync_vid_sync_aud_lead_adjust(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
sync_vid_sync_aud_lead_adjust_vid(ctx, chn, vid_aud_diff);
|
|
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_DOWN;
|
|
ext_info_async(chn, "aud lead vid %d, aud adjust dowm play\n", vid_aud_diff);
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_vid_sync_aud_lag_adjust_vid(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
if (vid_aud_diff > ctx->attr.novel_region.vid_plus_time) {
|
|
sync_smooth_repeat(ctx, chn, vid_aud_diff);
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_async(chn, "aud lead vid %d, vid play\n", vid_aud_diff);
|
|
}
|
|
}
|
|
|
|
static void sync_vid_sync_aud_lag_adjust_set_aud_speed(sync_context *ctx, td_u32 diff_point)
|
|
{
|
|
if (diff_point < LOW_DELAY_SYNC_PTS_DIFF_MAX) {
|
|
ctx->aud_opt.speed_int = 1;
|
|
ctx->aud_opt.speed_dec = (diff_point + 1) * LOW_DELAY_SYNC_PTS_DIFF_MULTIPLE;
|
|
} else {
|
|
ctx->aud_opt.speed_int = LOW_DELAY_SYNC_AUD_SPEED_INT_MAX;
|
|
ctx->aud_opt.speed_dec = 0;
|
|
}
|
|
}
|
|
|
|
static void sync_vid_sync_aud_lag_adjust(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
td_u32 diff_point = 0;
|
|
|
|
sync_vid_sync_aud_lag_adjust_vid(ctx, chn, vid_aud_diff);
|
|
|
|
if (ctx->aud_info.buf_time - ctx->aud_info.sink_delay <= ctx->aud_info.frame_time * AUD_THD_FRAMENUM) {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_NORMAL;
|
|
ctx->aud_opt.speed_int = 1;
|
|
ctx->aud_opt.speed_dec = 0;
|
|
return;
|
|
}
|
|
|
|
if (ctx->aud_opt.speed_int == 1 && ctx->aud_opt.speed_dec == 0) {
|
|
if (vid_aud_diff > AVPLAY_DEFAULT_START_ADJUST_TIME &&
|
|
ctx->aud_info.buf_time - ctx->aud_info.sink_delay > LOW_DELAY_SYNC_AUD_LOW_SPEED_LEVEL) {
|
|
if (vid_aud_diff > ctx->aud_info.sink_delay) {
|
|
diff_point = (vid_aud_diff - ctx->aud_info.sink_delay - AVPLAY_DEFAULT_START_ADJUST_TIME) /
|
|
LOW_DELAY_SYNC_STARTREGION_ADJUST_UNIT;
|
|
} else {
|
|
diff_point = (vid_aud_diff - AVPLAY_DEFAULT_START_ADJUST_TIME) / LOW_DELAY_SYNC_STARTREGION_ADJUST_UNIT;
|
|
}
|
|
sync_vid_sync_aud_lag_adjust_set_aud_speed(ctx, diff_point);
|
|
}
|
|
} else {
|
|
if (vid_aud_diff < AVPLAY_DEFAULT_STOP_ADJUST_TIME ||
|
|
ctx->aud_info.buf_time - ctx->aud_info.sink_delay < LOW_DELAY_SYNC_AUD_LOW_SPEED_LEVEL) {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_NORMAL;
|
|
ctx->aud_opt.speed_int = 1;
|
|
ctx->aud_opt.speed_dec = 0;
|
|
return;
|
|
} else {
|
|
if (vid_aud_diff > ctx->aud_info.sink_delay) {
|
|
diff_point = (vid_aud_diff - ctx->aud_info.sink_delay - AVPLAY_DEFAULT_STOP_ADJUST_TIME) /
|
|
LOW_DELAY_SYNC_STARTREGION_ADJUST_UNIT;
|
|
} else {
|
|
diff_point = (vid_aud_diff - AVPLAY_DEFAULT_STOP_ADJUST_TIME) / LOW_DELAY_SYNC_STARTREGION_ADJUST_UNIT;
|
|
}
|
|
sync_vid_sync_aud_lag_adjust_set_aud_speed(ctx, diff_point);
|
|
}
|
|
}
|
|
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_UP;
|
|
ext_info_async(chn, "aud lag vid %d, aud adjust up play speed %d.%d\n",
|
|
vid_aud_diff, ctx->aud_opt.speed_int, ctx->aud_opt.speed_dec);
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_vid_sync_adjust(sync_context *ctx, sync_chan_type chn, td_s32 vid_aud_diff)
|
|
{
|
|
if (check_is_sync_adjust(ctx, vid_aud_diff) == TD_FALSE) {
|
|
return;
|
|
}
|
|
|
|
if (is_stop_sync_adjust(ctx, vid_aud_diff) == TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
/* audio is ahead of video */
|
|
if (vid_aud_diff < 0) {
|
|
sync_vid_sync_aud_lead_adjust(ctx, chn, vid_aud_diff);
|
|
} else { /* audio is behind video */
|
|
sync_vid_sync_aud_lag_adjust(ctx, chn, vid_aud_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_scr_sync_aud_adjust(sync_context *ctx, td_s32 vid_aud_diff, td_s32 aud_scr_diff, td_s32 vid_scr_diff)
|
|
{
|
|
/* aud is behind scr and aud_scr_diff is in novel region */
|
|
if ((aud_scr_diff >= ctx->attr.novel_region.vid_negative_time) &&
|
|
(aud_scr_diff <= ctx->attr.start_region.vid_negative_time)) {
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
ext_info_sync("aud_scr_diff: %d, discard\n", aud_scr_diff);
|
|
} else if (aud_scr_diff < ctx->attr.novel_region.vid_negative_time) {
|
|
/* aud is behind scr and aud_scr_diff is out of novel region */
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
ext_info_sync("aud_scr_diff: %d, discard\n", aud_scr_diff);
|
|
} else if ((aud_scr_diff >= ctx->attr.start_region.vid_plus_time) &&
|
|
(aud_scr_diff <= ctx->attr.novel_region.vid_plus_time)) {
|
|
/* aud is ahead scr and aud_scr_diff is in novel region */
|
|
ctx->aud_opt.proc = SYNC_PROC_REPEAT;
|
|
ext_info_sync("aud_scr_diff: %d, repeat\n", aud_scr_diff);
|
|
} else if (aud_scr_diff > ctx->attr.novel_region.vid_plus_time) {
|
|
/* aud is ahead scr and aud_scr_diff is out of novel region */
|
|
ctx->aud_opt.proc = SYNC_PROC_REPEAT;
|
|
ext_info_sync("aud_scr_diff: %d, repeat\n", aud_scr_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_vid_discard(td_bool is_smooth_play, sync_context *ctx, td_s32 vid_target_diff)
|
|
{
|
|
if (is_smooth_play) {
|
|
/* discard one frame in every VID_SMOOTH_DISCARD_INTERVAL frame */
|
|
if (!(ctx->vid_discard_play_cnt % VID_SMOOTH_DISCARD_INTERVAL)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD;
|
|
ctx->vid_discard_cnt++;
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
}
|
|
|
|
ctx->vid_discard_play_cnt++;
|
|
} else {
|
|
/* discard time before vdec */
|
|
ctx->vid_opt.vdec_discard_time = sync_abs(vid_target_diff);
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD;
|
|
ctx->vid_discard_cnt++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_scr_sync_vid_lag_adjust(sync_context *ctx, td_s32 vid_scr_diff)
|
|
{
|
|
/* vid is behind scr and VidScrDiff is in novel region */
|
|
if (vid_scr_diff >= ctx->attr.novel_region.vid_negative_time) {
|
|
sync_vid_discard(ctx->attr.start_region.smooth_play, ctx, vid_scr_diff);
|
|
} else if (vid_scr_diff < ctx->attr.novel_region.vid_negative_time) {
|
|
/* vid is behind scr and vid_scr_diff is out of novel region */
|
|
sync_vid_discard(ctx->attr.novel_region.smooth_play, ctx, vid_scr_diff);
|
|
}
|
|
if (ctx->vid_opt.proc == SYNC_PROC_PLAY) {
|
|
ext_info_sync("vid_scr_diff: %d, smooth play\n", vid_scr_diff);
|
|
} else if (ctx->vid_opt.proc == SYNC_PROC_DISCARD) {
|
|
ext_info_sync("vid_scr_diff: %d, discard\n", vid_scr_diff);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void sync_vid_repeat(td_bool is_smooth_play, sync_context *ctx, td_s32 vid_target_diff)
|
|
{
|
|
if (is_smooth_play) {
|
|
if (ctx->vid_repeat_play_cnt % VID_SMOOTH_REPEAT_INTERVAL == 0) {
|
|
ctx->vid_opt.proc = SYNC_PROC_REPEAT;
|
|
(void)sync_proc_vid_repeat_cnt(ctx, SYNC_PROC_TYPE_SMOOTH, vid_target_diff);
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
}
|
|
|
|
ctx->vid_repeat_play_cnt++;
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_REPEAT;
|
|
(void)sync_proc_vid_repeat_cnt(ctx, SYNC_PROC_TYPE_QUICK, vid_target_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_scr_sync_vid_lead_adjust(sync_context *ctx, td_s32 vid_scr_diff)
|
|
{
|
|
if (vid_scr_diff <= ctx->attr.novel_region.vid_plus_time) {
|
|
/* vid is ahead scr and VidScrDiff is in novel region */
|
|
sync_vid_repeat(ctx->attr.start_region.smooth_play, ctx, vid_scr_diff);
|
|
} else if (vid_scr_diff > ctx->attr.novel_region.vid_plus_time) {
|
|
/* vid is ahead scr and vid_scr_diff is out of novel region */
|
|
sync_vid_repeat(ctx->attr.novel_region.smooth_play, ctx, vid_scr_diff);
|
|
}
|
|
|
|
if (ctx->vid_opt.proc == SYNC_PROC_PLAY) {
|
|
ext_info_sync("vid_scr_diff: %d, smooth play\n", vid_scr_diff);
|
|
} else if (ctx->vid_opt.proc == SYNC_PROC_REPEAT) {
|
|
ext_info_sync("vid_scr_diff: %d, repeat\n", vid_scr_diff);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void sync_scr_sync_vid_adjust(sync_context *ctx, td_s32 vid_aud_diff, td_s32 aud_scr_diff, td_s32 vid_scr_diff)
|
|
{
|
|
/* VidScrDiff is already in start region */
|
|
if ((vid_scr_diff > ctx->attr.start_region.vid_negative_time) &&
|
|
(vid_scr_diff < ctx->attr.start_region.vid_plus_time)) {
|
|
/* VidAudDiff is already in start region */
|
|
if ((vid_aud_diff < ctx->attr.start_region.vid_plus_time) &&
|
|
(vid_aud_diff > ctx->attr.start_region.vid_negative_time)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_sync("vid_scr_diff: %d, play\n", vid_scr_diff);
|
|
return;
|
|
}
|
|
|
|
/* VidAudDiff is beyond start region, we adjust vid */
|
|
/* we only need adjust one or two frames, so we ignore smooth play */
|
|
if (aud_scr_diff > 0 && vid_scr_diff < 0) {
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD;
|
|
ctx->vid_discard_cnt++;
|
|
ext_info_sync("vid_scr_diff: %d, discard\n", vid_scr_diff);
|
|
}
|
|
|
|
if (aud_scr_diff < 0 && vid_scr_diff > 0) {
|
|
ctx->vid_opt.proc = SYNC_PROC_REPEAT;
|
|
ctx->vid_repeat_cnt++;
|
|
ext_info_sync("vid_scr_diff: %d, repeat\n", vid_scr_diff);
|
|
}
|
|
} else if (vid_scr_diff <= ctx->attr.start_region.vid_negative_time) { /* vid is behind scr */
|
|
sync_scr_sync_vid_lag_adjust(ctx, vid_scr_diff);
|
|
} else if (vid_scr_diff >= ctx->attr.start_region.vid_plus_time) { /* vid is ahead scr */
|
|
sync_scr_sync_vid_lead_adjust(ctx, vid_scr_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_scr_sync_adjust(sync_context *ctx, sync_chan_type chn,
|
|
td_s32 vid_aud_diff, td_s32 aud_scr_diff, td_s32 vid_scr_diff)
|
|
{
|
|
if (!ctx->scr_support) {
|
|
return;
|
|
}
|
|
|
|
/* AudScrDiff or VidScrDiff is too large, give up */
|
|
if ((sync_abs(aud_scr_diff) > SCR_DISCARD_THRESHOLD) ||
|
|
(sync_abs(vid_scr_diff) > SCR_DISCARD_THRESHOLD)) {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
ext_info_sync("aud_scr_diff %d vid_scr_diff %d > SCR_DISCARD_THRESHOLD, vid and aud play\n",
|
|
aud_scr_diff, vid_scr_diff);
|
|
return;
|
|
}
|
|
|
|
if (chn == SYNC_CHAN_AUD) {
|
|
/* already in start region */
|
|
if ((aud_scr_diff > ctx->attr.start_region.vid_negative_time) &&
|
|
(aud_scr_diff < ctx->attr.start_region.vid_plus_time)) {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_sync("aud_scr_diff: %d, play\n", aud_scr_diff);
|
|
} else {
|
|
sync_scr_sync_aud_adjust(ctx, ctx->vid_aud_diff, ctx->aud_scr_diff, ctx->vid_scr_diff);
|
|
}
|
|
} else if (chn == SYNC_CHAN_VID) {
|
|
sync_scr_sync_vid_adjust(ctx, ctx->vid_aud_diff, ctx->aud_scr_diff, ctx->vid_scr_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static sync_ref_type sync_get_sync_adjust_ref_mode(const sync_context *ctx)
|
|
{
|
|
if ((ctx->attr.sync_ref == SYNC_REF_SCR) ||
|
|
(ctx->attr.sync_ref == SYNC_REF_AUDIO && ctx->is_aud_first_come == TD_FALSE) ||
|
|
(ctx->attr.sync_ref == SYNC_REF_VIDEO && ctx->is_vid_first_come == TD_FALSE)) {
|
|
/* refer to scr or refer to audio but audio first frame does not come */
|
|
return SYNC_REF_SCR;
|
|
} else if ((ctx->attr.sync_ref == SYNC_REF_AUDIO) ||
|
|
(((ctx->attr.sync_ref == SYNC_REF_PCR) && (!ctx->pcr_sync_info.is_pcr_first_come)) ||
|
|
(ctx->pcr_sync_info.pcr_adjust_type == SYNC_AUD_ADJUST_SCR))) {
|
|
/* refer to aud or refer to pcr but pcr does not come. pcr does not come and pcr timeout */
|
|
return SYNC_REF_AUDIO;
|
|
} else if (ctx->attr.sync_ref == SYNC_REF_VIDEO) {
|
|
/* refer to video and received video */
|
|
return SYNC_REF_VIDEO;
|
|
} else if (ctx->attr.sync_ref == SYNC_REF_PCR) {
|
|
/* refer to pcr and received pcr */
|
|
return SYNC_REF_PCR;
|
|
}
|
|
|
|
return SYNC_REF_MAX;
|
|
}
|
|
|
|
/* refer to pcr and audio is ahead of pcr */
|
|
static void sync_pcr_sync_aud_lead_adjust(sync_context *ctx, td_s32 aud_pcr_diff)
|
|
{
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
if (SYNC_BUF_STATE_HIGH != ctx->cur_buf_status.aud_buf_state) {
|
|
ctx->aud_opt.proc = SYNC_PROC_REPEAT;
|
|
ctx->aud_repeat_cnt++;
|
|
ext_info_sync(">>>>Pcr Lag Aud, aud_pcr_diff %d, Aud Repeat\n", aud_pcr_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* refer to pcr and audio is behind pcr */
|
|
static void sync_pcr_sync_aud_lag_adjust(sync_context *ctx, td_s32 aud_pcr_diff)
|
|
{
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_NORMAL;
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
ctx->aud_discard_cnt++;
|
|
ext_info_sync(">>>>Pcr Lead Aud %d, discard\n", aud_pcr_diff);
|
|
|
|
return;
|
|
}
|
|
|
|
/* refer to pcr and video is ahead of pcr */
|
|
static void sync_pcr_sync_vid_lead_adjust(sync_context *ctx, td_s32 vid_target_diff)
|
|
{
|
|
/* the video buffer reach high waterline */
|
|
td_bool is_smooth_play;
|
|
if (SYNC_BUF_STATE_HIGH == ctx->cur_buf_status.vid_buf_state) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_sync("pcr lag vid %d buf block, Play\n", vid_target_diff);
|
|
return;
|
|
}
|
|
|
|
/* there is space in video buffer */
|
|
if (vid_target_diff > ctx->attr.novel_region.vid_plus_time) {
|
|
is_smooth_play = ctx->vid_first_pts == SYNC_INVALID_PTS ? TD_TRUE : ctx->attr.novel_region.smooth_play;
|
|
sync_vid_repeat(is_smooth_play, ctx, vid_target_diff);
|
|
} else {
|
|
is_smooth_play = ctx->vid_first_pts == SYNC_INVALID_PTS ? TD_TRUE : ctx->attr.start_region.smooth_play;
|
|
sync_vid_repeat(is_smooth_play, ctx, vid_target_diff);
|
|
}
|
|
|
|
if (ctx->vid_opt.proc == SYNC_PROC_PLAY) {
|
|
ext_info_sync("pcr lag vid %d, smooth play\n", vid_target_diff);
|
|
} else if (ctx->vid_opt.proc == SYNC_PROC_REPEAT) {
|
|
ext_info_sync("pcr lag vid %d, repeat\n", vid_target_diff);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* refer to pcr and video is behind pcr */
|
|
static void sync_pcr_sync_vid_lag_adjust(sync_context *ctx, td_s32 vid_target_diff)
|
|
{
|
|
if (vid_target_diff < ctx->attr.novel_region.vid_negative_time) {
|
|
sync_vid_discard(ctx->attr.novel_region.smooth_play, ctx, vid_target_diff);
|
|
} else {
|
|
sync_vid_discard(ctx->attr.start_region.smooth_play, ctx, vid_target_diff);
|
|
}
|
|
if (ctx->vid_opt.proc == SYNC_PROC_PLAY) {
|
|
ext_info_sync("pcr lead vid %d , smooth play\n", vid_target_diff);
|
|
} else if (ctx->vid_opt.proc == SYNC_PROC_DISCARD) {
|
|
ext_info_sync("pcr lead vid %d , discard\n", vid_target_diff);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void sync_pcr_aud_adjust(sync_context *ctx, td_s32 aud_pcr_diff)
|
|
{
|
|
if (sync_abs(aud_pcr_diff) > PCR_SYNC_THRESHOLD) {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->pcr_sync_info.is_pcr_aud_sync_ok = TD_FALSE;
|
|
ext_info_sync("aud_pcr_diff is too large\n");
|
|
return;
|
|
}
|
|
|
|
/* already in the stop region */
|
|
if (sync_abs(aud_pcr_diff) < PCR_LAG_STOP_THRESHOLD) {
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->pcr_sync_info.is_pcr_aud_sync_ok = TD_TRUE;
|
|
ext_info_sync("aud_pcr_diff sync finsh\n");
|
|
return;
|
|
} else {
|
|
ctx->pcr_sync_info.is_pcr_aud_sync_ok = TD_FALSE;
|
|
}
|
|
|
|
if (ctx->pcr_sync_info.aud_pcr_diff > 0) {
|
|
sync_pcr_sync_aud_lead_adjust(ctx, aud_pcr_diff);
|
|
} else {
|
|
sync_pcr_sync_aud_lag_adjust(ctx, aud_pcr_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_pcr_vid_adjust(sync_context *ctx, td_s32 vid_pcr_diff)
|
|
{
|
|
if (sync_abs(vid_pcr_diff) > PCR_SYNC_THRESHOLD) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->pcr_sync_info.is_pcr_vid_sync_ok = TD_FALSE;
|
|
ext_info_sync("vid_pcr_diff is too large :%d", vid_pcr_diff);
|
|
return;
|
|
}
|
|
|
|
/* already in the stop region, */
|
|
if (sync_abs(vid_pcr_diff) < PCR_LAG_STOP_THRESHOLD) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->pcr_sync_info.is_pcr_vid_sync_ok = TD_TRUE;
|
|
ext_info_sync("vid_pcr_diff sync finsh :%d", vid_pcr_diff);
|
|
return;
|
|
} else {
|
|
ctx->pcr_sync_info.is_pcr_vid_sync_ok = TD_FALSE;
|
|
}
|
|
|
|
if (ctx->pcr_sync_info.vid_pcr_diff > 0) {
|
|
sync_pcr_sync_vid_lead_adjust(ctx, vid_pcr_diff);
|
|
} else {
|
|
sync_pcr_sync_vid_lag_adjust(ctx, vid_pcr_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_pcr_vid_aud_adjust(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
if (SYNC_CHAN_VID == chn) {
|
|
if (ctx->vid_aud_diff > 0) {
|
|
sync_pcr_sync_vid_lead_adjust(ctx, ctx->vid_aud_diff);
|
|
} else {
|
|
sync_pcr_sync_vid_lag_adjust(ctx, ctx->vid_aud_diff);
|
|
}
|
|
}
|
|
|
|
if (SYNC_CHAN_AUD == chn) {
|
|
/* need adjust aud speed */
|
|
if (ctx->vid_aud_diff > 0) {
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_UP;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
} else {
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_DOWN;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_is_pcr_adjust_finish(const sync_context *ctx, td_s32 aud_pcr_diff, td_s32 vid_pcr_diff)
|
|
{
|
|
td_s32 lag_threshold;
|
|
td_s32 lead_threshold;
|
|
|
|
/* if only aud or vid is exist, make sure audpcrdiff or vidpcrdiff in -100~100 */
|
|
if (((ctx->is_aud_first_come) && (!ctx->is_vid_first_come)) ||
|
|
((!ctx->is_aud_first_come) && (ctx->is_vid_first_come))) {
|
|
lag_threshold = PCR_LAG_STOP_THRESHOLD;
|
|
lead_threshold = PCR_LEAD_STOP_THRESHOLD;
|
|
} else {
|
|
lag_threshold = PCR_LAG_ADJUST_THRESHOLD;
|
|
lead_threshold = PCR_LEAD_ADJUST_THRESHOLD;
|
|
}
|
|
|
|
if ((ctx->vid_aud_diff <= ctx->attr.start_region.vid_plus_time) &&
|
|
(ctx->vid_aud_diff >= ctx->attr.start_region.vid_negative_time) &&
|
|
((aud_pcr_diff <= lag_threshold) && (aud_pcr_diff + lead_threshold >= 0)) &&
|
|
((vid_pcr_diff <= lag_threshold) && (vid_pcr_diff + lead_threshold >= 0))) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_check_pcr_adjust_finish(sync_context *ctx, td_s32 aud_pcr_diff,
|
|
td_s32 vid_pcr_diff, td_bool *is_sync_finish)
|
|
{
|
|
td_bool adjust_finish = sync_is_pcr_adjust_finish(ctx, aud_pcr_diff, vid_pcr_diff);
|
|
|
|
if (!ctx->is_vid_sync_adjust) {
|
|
/* VidAudDiff is in sync start region, vidpcr and audpcr is in sync start region, don't need to adjust */
|
|
if (adjust_finish) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
ctx->pcr_sync_info.is_pcr_vid_sync_ok = TD_TRUE;
|
|
ctx->pcr_sync_info.is_pcr_aud_sync_ok = TD_TRUE;
|
|
ctx->sync_adjust_delay_frm_cnt = 0;
|
|
|
|
*is_sync_finish = TD_TRUE;
|
|
ext_info_sync("pcr sync finsh, vid_aud_diff %d\n", ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
if (ctx->sync_adjust_delay_frm_cnt < SYNC_ADJUST_DELAY_CNT) {
|
|
ctx->sync_adjust_delay_frm_cnt++;
|
|
ext_info_sync("adjust delay cnt:%d vid_aud_diff %d\n", ctx->sync_adjust_delay_frm_cnt, ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
ctx->is_vid_sync_adjust = TD_TRUE;
|
|
ctx->pcr_sync_info.is_pcr_aud_sync_ok = TD_FALSE;
|
|
ctx->pcr_sync_info.is_pcr_vid_sync_ok = TD_FALSE;
|
|
ctx->sync_adjust_delay_frm_cnt = 0;
|
|
}
|
|
|
|
/* vid_aud_diff is in sync start region, vidpcr and audpcr is in sync start region, don't need to adjust */
|
|
if (adjust_finish) {
|
|
if ((ctx->is_use_stop_region == TD_TRUE && sync_abs(ctx->vid_aud_diff) <= ctx->vid_info.frame_time) ||
|
|
(ctx->is_use_stop_region == TD_FALSE)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
ctx->pcr_sync_info.is_pcr_vid_sync_ok = TD_TRUE;
|
|
ctx->pcr_sync_info.is_pcr_aud_sync_ok = TD_TRUE;
|
|
|
|
*is_sync_finish = TD_TRUE;
|
|
ctx->is_vid_sync_adjust = TD_FALSE;
|
|
ext_warn_sync("pcr sync finsh, vid_aud_diff %d\n", ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
}
|
|
|
|
*is_sync_finish = TD_FALSE;
|
|
return;
|
|
}
|
|
|
|
static void sync_pcr_start_region_adjust(sync_context *ctx, sync_chan_type chn,
|
|
td_s32 aud_pcr_diff, td_s32 vid_pcr_diff)
|
|
{
|
|
td_bool is_sync_finish = TD_FALSE;
|
|
|
|
sync_check_pcr_adjust_finish(ctx, aud_pcr_diff, vid_pcr_diff, &is_sync_finish);
|
|
|
|
if (TD_TRUE == is_sync_finish) {
|
|
return;
|
|
}
|
|
|
|
/* adjust aud to match pcr */
|
|
if (SYNC_CHAN_AUD == chn) {
|
|
sync_pcr_aud_adjust(ctx, aud_pcr_diff);
|
|
}
|
|
|
|
/* adjust vid to match pcr */
|
|
if (SYNC_CHAN_VID == chn) {
|
|
sync_pcr_vid_adjust(ctx, vid_pcr_diff);
|
|
}
|
|
|
|
/* adjust aud and vid to match startregion */
|
|
if ((TD_TRUE == ctx->pcr_sync_info.is_pcr_aud_sync_ok) &&
|
|
(TD_TRUE == ctx->pcr_sync_info.is_pcr_vid_sync_ok)) {
|
|
sync_pcr_vid_aud_adjust(ctx, chn);
|
|
}
|
|
|
|
ext_warn_sync("is_pcr_aud_sync_ok: %d, is_pcr_vid_sync_ok: %d; \
|
|
aud_pcr_diff: %d, vid_pcr_diff: %d, vid_aud_diff: %d\n",
|
|
ctx->pcr_sync_info.is_pcr_aud_sync_ok, ctx->pcr_sync_info.is_pcr_vid_sync_ok,
|
|
ctx->pcr_sync_info.aud_pcr_diff, ctx->pcr_sync_info.vid_pcr_diff, ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
static void sync_pcr_sync_adjust(sync_context *ctx, sync_chan_type chn, td_s32 aud_pcr_diff, td_s32 vid_pcr_diff)
|
|
{
|
|
td_bool is_rewind = (ctx->is_pcr_rewind == TD_TRUE) ||
|
|
(ctx->is_vid_rewind == TD_TRUE) || (ctx->is_aud_rewind == TD_TRUE);
|
|
|
|
if (ctx->is_aud_first_come && ctx->is_vid_first_come) {
|
|
if (is_rewind) {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* if pcr is abnormal chenge syncRef to Aud */
|
|
if ((sync_abs(aud_pcr_diff) > PCR_SYNC_THRESHOLD) && (sync_abs(vid_pcr_diff) > PCR_SYNC_THRESHOLD)) {
|
|
if (sync_abs(ctx->vid_aud_diff) < PCR_SYNC_THRESHOLD) {
|
|
ctx->pcr_sync_info.pcr_adjust_type = SYNC_AUD_ADJUST_SCR;
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
ext_info_sync("change syncRef to aud\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((!ctx->is_buf_adjust) &&
|
|
(aud_pcr_diff + PCR_LEAD_ADJUST_THRESHOLD < 0) &&
|
|
(vid_pcr_diff + PCR_LEAD_ADJUST_THRESHOLD < 0)) {
|
|
if ((aud_pcr_diff + ctx->pcr_sync_info.pcr_delta + PCR_SYNC_MAX_DELTA < 0) ||
|
|
(vid_pcr_diff + ctx->pcr_sync_info.pcr_delta + PCR_SYNC_MAX_DELTA < 0)) {
|
|
ctx->pcr_sync_info.pcr_adjust_type = SYNC_AUD_ADJUST_SCR;
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
|
|
ext_info_sync("change syncRef to aud\n");
|
|
return;
|
|
}
|
|
|
|
/* adjust pcr to this one which is more behind */
|
|
if (ctx->pcr_sync_info.is_pcr_adjust_delta_ok) {
|
|
ctx->pcr_sync_info.pcr_delta += (vid_pcr_diff > aud_pcr_diff) ? aud_pcr_diff : vid_pcr_diff;
|
|
ctx->pcr_sync_info.is_pcr_adjust_delta_ok = TD_FALSE;
|
|
ext_info_sync("change pcr_delta %d\n", ctx->pcr_sync_info.pcr_delta);
|
|
}
|
|
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
return;
|
|
}
|
|
|
|
sync_pcr_start_region_adjust(ctx, chn, aud_pcr_diff, vid_pcr_diff);
|
|
return;
|
|
}
|
|
|
|
static void sync_adjust(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
sync_ref_type ref_mode;
|
|
|
|
/* do not sync when is_loop_rewind is true */
|
|
if (ctx->is_loop_rewind) {
|
|
return;
|
|
}
|
|
|
|
ref_mode = sync_get_sync_adjust_ref_mode(ctx);
|
|
|
|
switch (ref_mode) {
|
|
case SYNC_REF_SCR: {
|
|
sync_scr_sync_adjust(ctx, chn, ctx->vid_aud_diff, ctx->aud_scr_diff, ctx->vid_scr_diff);
|
|
break;
|
|
}
|
|
|
|
case SYNC_REF_AUDIO: {
|
|
sync_aud_sync_adjust(ctx, chn, ctx->vid_aud_diff);
|
|
break;
|
|
}
|
|
|
|
case SYNC_REF_VIDEO: {
|
|
sync_vid_sync_adjust(ctx, chn, ctx->vid_aud_diff);
|
|
break;
|
|
}
|
|
|
|
case SYNC_REF_PCR: {
|
|
sync_pcr_sync_adjust(ctx, chn, ctx->pcr_sync_info.aud_pcr_diff, ctx->pcr_sync_info.vid_pcr_diff);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
ext_info_sync("ref_mode 0x%x is not support\n", ref_mode);
|
|
return;
|
|
}
|
|
drv_sync_fault_check_process(ctx, chn);
|
|
|
|
return;
|
|
}
|
|
|
|
static sync_region_stat_mode sync_check_pcr_region(sync_context *ctx, td_s32 diff)
|
|
{
|
|
if ((diff < PCR_LAG_ADJUST_THRESHOLD) && (diff > -PCR_LEAD_ADJUST_THRESHOLD)) {
|
|
return SYNC_REGION_STAT_IN_START;
|
|
} else if ((diff < PCR_DISCARD_THRESHOLD) && (diff > -PCR_DISCARD_THRESHOLD)) {
|
|
return SYNC_REGION_STAT_IN_NOVEL;
|
|
} else if ((diff < VID_LEAD_DISCARD_THRESHOLD) && (diff > -VID_LEAD_DISCARD_THRESHOLD)) {
|
|
return SYNC_REGION_STAT_IN_DISCARD;
|
|
} else {
|
|
return SYNC_REGION_STAT_OUT_DISCARD;
|
|
}
|
|
}
|
|
|
|
static sync_region_stat_mode sync_check_region(sync_context *ctx, td_s32 diff)
|
|
{
|
|
if ((diff < ctx->attr.start_region.vid_plus_time) &&
|
|
(diff > ctx->attr.start_region.vid_negative_time)) {
|
|
return SYNC_REGION_STAT_IN_START;
|
|
} else if ((diff < ctx->attr.novel_region.vid_plus_time) &&
|
|
(diff > ctx->attr.novel_region.vid_negative_time)) {
|
|
return SYNC_REGION_STAT_IN_NOVEL;
|
|
} else if ((diff < VID_LEAD_DISCARD_THRESHOLD) && (diff > -VID_LAG_DISCARD_THRESHOLD)) {
|
|
return SYNC_REGION_STAT_IN_DISCARD;
|
|
} else {
|
|
return SYNC_REGION_STAT_OUT_DISCARD;
|
|
}
|
|
}
|
|
|
|
static void sync_check_vid_pts_jump_evt(sync_context *ctx)
|
|
{
|
|
td_s64 err_delta = ctx->vid_info.frame_time * SYNC_PTS_JUMP_FRM_NUM;
|
|
td_s64 vid_pts_diff;
|
|
|
|
if (SYNC_INVALID_PTS == ctx->vid_last_pts) {
|
|
return;
|
|
}
|
|
|
|
if (sync_abs(ctx->vid_info.pts - ctx->vid_last_pts) > err_delta) {
|
|
ext_info_sync("vid pts: %d, vid_last_pts: %d, vid_first_valid_src_pts: %d, err_delta: %d\n",
|
|
ctx->vid_info.pts, ctx->vid_last_pts, ctx->vid_first_valid_src_pts, err_delta);
|
|
|
|
ctx->evt.is_vid_pts_jump = TD_TRUE;
|
|
ctx->evt.vid_pts_jump_param.pts_chan = SYNC_CHAN_VID;
|
|
ctx->evt.vid_pts_jump_param.cur_pts = ctx->vid_info.pts;
|
|
ctx->evt.vid_pts_jump_param.cur_src_pts = ctx->vid_info.src_pts;
|
|
ctx->evt.vid_pts_jump_param.first_pts = ctx->vid_first_pts;
|
|
ctx->evt.vid_pts_jump_param.first_valid_pts = ctx->vid_first_valid_src_pts;
|
|
ctx->evt.vid_pts_jump_param.last_pts = ctx->vid_last_pts;
|
|
ctx->evt.vid_pts_jump_param.last_src_pts = ctx->vid_last_src_pts;
|
|
|
|
ctx->vid_pts_jump_cnt++;
|
|
if (drv_sync_pts_jump_diff_full(ctx, SYNC_CHAN_VID)) {
|
|
drv_sync_pts_jump_diff_dequeue(ctx, SYNC_CHAN_VID);
|
|
}
|
|
vid_pts_diff = ctx->vid_info.pts - ctx->vid_last_pts;
|
|
drv_sync_pts_jump_diff_enqueue(ctx, SYNC_CHAN_VID, vid_pts_diff);
|
|
|
|
/* pts is one of vid_first_dec_pts/vid_second_dec_pts/vid_first_valid_src_pts */
|
|
if ((ctx->vid_info.src_pts == ctx->vid_first_dec_pts) ||
|
|
(ctx->vid_info.src_pts == ctx->vid_second_dec_pts) ||
|
|
((ctx->vid_info.src_pts == ctx->vid_first_valid_src_pts) && (ctx->is_vid_first_valid_src_pts_come))) {
|
|
ext_info_sync("Vid pts loop rewind, src pts %u, vid_first_dec_pts %u, \
|
|
vid_second_dec_pts %u, vid_first_valid_src_pts %u!\n",
|
|
ctx->vid_info.src_pts, ctx->vid_first_dec_pts, ctx->vid_second_dec_pts, ctx->vid_first_valid_src_pts);
|
|
|
|
ctx->evt.vid_pts_jump_param.loop_back = TD_TRUE;
|
|
ctx->is_vid_pts_loop_rewind = TD_TRUE;
|
|
} else {
|
|
ctx->evt.vid_pts_jump_param.loop_back = TD_FALSE;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_check_aud_pts_jump_evt(sync_context *ctx)
|
|
{
|
|
td_s64 err_delta = ctx->aud_info.frame_time * SYNC_PTS_JUMP_FRM_NUM;
|
|
td_s64 aud_pts_diff;
|
|
|
|
if (SYNC_INVALID_PTS == ctx->aud_last_pts) {
|
|
return;
|
|
}
|
|
|
|
if (sync_abs(ctx->aud_info.pts - ctx->aud_last_pts) > err_delta) {
|
|
ext_info_sync("aud_last_pts %d, pts %d, u32FirstValid_Pts %d, err_delta %d\n",
|
|
ctx->aud_last_pts, ctx->aud_info.pts, ctx->aud_first_valid_pts, err_delta);
|
|
|
|
ctx->evt.is_aud_pts_jump = TD_TRUE;
|
|
ctx->evt.aud_pts_jump_param.pts_chan = SYNC_CHAN_AUD;
|
|
ctx->evt.aud_pts_jump_param.cur_pts = ctx->aud_info.pts;
|
|
ctx->evt.aud_pts_jump_param.cur_src_pts = ctx->aud_info.src_pts;
|
|
ctx->evt.aud_pts_jump_param.first_pts = ctx->aud_first_pts;
|
|
ctx->evt.aud_pts_jump_param.first_valid_pts = ctx->aud_first_valid_pts;
|
|
ctx->evt.aud_pts_jump_param.last_pts = ctx->aud_last_pts;
|
|
ctx->evt.aud_pts_jump_param.last_src_pts = ctx->aud_last_src_pts;
|
|
|
|
ctx->aud_pts_jump_cnt++;
|
|
if (drv_sync_pts_jump_diff_full(ctx, SYNC_CHAN_AUD)) {
|
|
drv_sync_pts_jump_diff_dequeue(ctx, SYNC_CHAN_AUD);
|
|
}
|
|
aud_pts_diff = ctx->aud_info.pts - ctx->aud_last_pts;
|
|
drv_sync_pts_jump_diff_enqueue(ctx, SYNC_CHAN_AUD, aud_pts_diff);
|
|
|
|
if (ctx->aud_info.src_pts == ctx->aud_first_valid_pts) {
|
|
ext_info_sync("aud pts loop rewind!\n");
|
|
ctx->evt.aud_pts_jump_param.loop_back = TD_TRUE;
|
|
ctx->is_aud_pts_loop_rewind = TD_TRUE;
|
|
} else {
|
|
ctx->evt.aud_pts_jump_param.loop_back = TD_FALSE;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_check_state_chg_evt(sync_context *ctx)
|
|
{
|
|
sync_region_stat_mode last_vid_aud_stat = SYNC_REGION_STAT_MAX;
|
|
sync_region_stat_mode cur_vid_aud_stat = SYNC_REGION_STAT_MAX;
|
|
sync_region_stat_mode last_vid_pcr_stat;
|
|
sync_region_stat_mode cur_vid_pcr_stat;
|
|
sync_region_stat_mode last_aud_pcr_stat;
|
|
sync_region_stat_mode cur_aud_pcr_stat;
|
|
td_bool is_state_change = TD_FALSE;
|
|
|
|
if (SYNC_REF_AUDIO == ctx->attr.sync_ref) {
|
|
last_vid_aud_stat = sync_check_region(ctx, ctx->last_vid_aud_diff);
|
|
cur_vid_aud_stat = sync_check_region(ctx, ctx->vid_aud_diff);
|
|
if (last_vid_aud_stat != cur_vid_aud_stat) {
|
|
is_state_change = TD_TRUE;
|
|
}
|
|
} else if (SYNC_REF_PCR == ctx->attr.sync_ref) {
|
|
last_aud_pcr_stat = sync_check_pcr_region(ctx, ctx->pcr_sync_info.last_aud_pcr_diff);
|
|
last_vid_pcr_stat = sync_check_pcr_region(ctx, ctx->pcr_sync_info.last_vid_pcr_diff);
|
|
last_vid_aud_stat = sync_check_region(ctx, ctx->last_vid_aud_diff);
|
|
|
|
cur_aud_pcr_stat = sync_check_pcr_region(ctx, ctx->pcr_sync_info.aud_pcr_diff);
|
|
cur_vid_pcr_stat = sync_check_pcr_region(ctx, ctx->pcr_sync_info.vid_pcr_diff);
|
|
cur_vid_aud_stat = sync_check_region(ctx, ctx->vid_aud_diff);
|
|
if ((last_aud_pcr_stat != cur_aud_pcr_stat) ||
|
|
(last_vid_pcr_stat != cur_vid_pcr_stat) ||
|
|
(last_vid_aud_stat != cur_vid_aud_stat)) {
|
|
is_state_change = TD_TRUE;
|
|
}
|
|
}
|
|
|
|
/* if sync status change, record this event */
|
|
if ((TD_TRUE == is_state_change) || (TD_TRUE == ctx->is_first_sync_state_report)) {
|
|
ext_info_sync("Sync Status change: last_vid_aud_stat %d, cur_vid_aud_stat %d!\n",
|
|
last_vid_aud_stat, cur_vid_aud_stat);
|
|
ctx->is_first_sync_state_report = TD_FALSE;
|
|
|
|
ctx->evt.is_stat_change = TD_TRUE;
|
|
ctx->evt.stat_param.vid_aud_diff = ctx->vid_aud_diff;
|
|
ctx->evt.stat_param.vid_pcr_diff = ctx->pcr_sync_info.vid_pcr_diff;
|
|
ctx->evt.stat_param.aud_pcr_diff = ctx->pcr_sync_info.aud_pcr_diff;
|
|
ctx->evt.stat_param.vid_local_time = ctx->vid_last_local_time;
|
|
ctx->evt.stat_param.aud_local_time = ctx->aud_last_local_time;
|
|
ctx->evt.stat_param.pcr_local_time = ctx->pcr_sync_info.pcr_last_local_time;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_check_evt(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
td_u32 cur_sys_time;
|
|
|
|
if (SYNC_CHAN_VID == chn) {
|
|
sync_check_vid_pts_jump_evt(ctx);
|
|
} else if (SYNC_CHAN_AUD == chn) {
|
|
sync_check_aud_pts_jump_evt(ctx);
|
|
} else { /* pcr jump check, to add */
|
|
}
|
|
|
|
sync_check_state_chg_evt(ctx);
|
|
|
|
/* do not sync when vid or aud loopback */
|
|
if (!ctx->is_loop_rewind && (ctx->is_aud_pts_loop_rewind || ctx->is_vid_pts_loop_rewind)) {
|
|
ctx->is_loop_rewind = TD_TRUE;
|
|
ctx->loop_rewind_time = sync_get_sys_time();
|
|
|
|
ext_info_sync("Change sync ref to NONE. is_aud_pts_loop_rewind: %d, is_vid_pts_loop_rewind: %d\n",
|
|
ctx->is_aud_pts_loop_rewind, ctx->is_vid_pts_loop_rewind);
|
|
}
|
|
|
|
if (ctx->is_loop_rewind) {
|
|
cur_sys_time = sync_get_sys_time();
|
|
/* recover sync when timeout or vid and aud both loopback */
|
|
if ((cur_sys_time - ctx->loop_rewind_time > PTS_LOOPBACK_TIMEOUT) ||
|
|
(ctx->is_aud_pts_loop_rewind && ctx->is_vid_pts_loop_rewind)) {
|
|
ctx->is_loop_rewind = TD_FALSE;
|
|
ctx->is_aud_pts_loop_rewind = TD_FALSE;
|
|
ctx->is_vid_pts_loop_rewind = TD_FALSE;
|
|
ext_info_sync("Change sync ref to usr set ref, is_aud_pts_loop_rewind: %d, is_vid_pts_loop_rewind: %d\n",
|
|
ctx->is_aud_pts_loop_rewind, ctx->is_vid_pts_loop_rewind);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_is_sync_ref_none(sync_context *ctx, sync_chan_type chn)
|
|
{
|
|
if (SYNC_REF_NONE != ctx->attr.sync_ref) {
|
|
return TD_FALSE;
|
|
}
|
|
|
|
if (SYNC_CHAN_AUD == chn) {
|
|
if (!ctx->is_aud_first_play) {
|
|
ctx->is_aud_first_play = TD_TRUE;
|
|
ctx->aud_first_play_time = sync_get_sys_time();
|
|
}
|
|
|
|
if (SYNC_BUF_STATE_EMPTY == ctx->cur_buf_status.aud_buf_state) {
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_DOWN;
|
|
} else {
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_NORMAL;
|
|
}
|
|
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_sync("--------Aud none sync Play Speed %d--------\n", ctx->aud_opt.speed_adjust);
|
|
}
|
|
|
|
if (SYNC_CHAN_VID == chn) {
|
|
if (!ctx->is_vid_first_play) {
|
|
ctx->is_vid_first_play = TD_TRUE;
|
|
ctx->is_vid_normal_play = TD_TRUE;
|
|
ctx->vid_first_play_time = sync_get_sys_time();
|
|
ext_drv_stat_event(EXT_STAT_EVENT_FRAME_SYNC_OK, 0);
|
|
}
|
|
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_sync("--------Vid none sync Play--------\n");
|
|
}
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static td_bool sync_is_vid_presync_finish(sync_context *ctx, const sync_vid_info *info, sync_vid_opt *opt)
|
|
{
|
|
if (ctx->is_presync_finish) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
sync_presync(ctx, SYNC_CHAN_VID);
|
|
|
|
if (ctx->vid_opt.proc != SYNC_PROC_CONTINUE) {
|
|
*opt = ctx->vid_opt;
|
|
|
|
if (ctx->is_presync_target_init) {
|
|
ext_info_sync("--------Vid PreSync vid_aud_diff %d proc %d--------\n", ctx->vid_aud_diff, opt->proc);
|
|
}
|
|
|
|
if (info->is_pts_valid) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_VID, (td_u32)info->pts);
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
if (!ctx->is_scr_init && (info->pts != SYNC_INVALID_PTS)) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_SCR, (td_u32)info->pts);
|
|
ctx->is_scr_init = TD_TRUE;
|
|
ctx->scr_first_local_time = (td_u32)info->pts;
|
|
ctx->scr_first_sys_time = sync_get_sys_time();
|
|
}
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static td_bool sync_is_vid_buf_fund_finish(sync_context *ctx, const sync_vid_info *info, sync_vid_opt *opt)
|
|
{
|
|
if (ctx->is_buf_fund_finish) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
sync_buf_fund(ctx);
|
|
|
|
if (ctx->vid_opt.proc != SYNC_PROC_CONTINUE) {
|
|
*opt = ctx->vid_opt;
|
|
ext_info_sync("--------vid buf fund proc %d--------\n", opt->proc);
|
|
return TD_FALSE;
|
|
}
|
|
|
|
if (ctx->is_aud_first_come) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_AUD, (td_u32)(ctx->aud_info.pts));
|
|
ext_info_sync("aud buf fund first set local time: %d\n", ctx->aud_info.pts);
|
|
|
|
if (ctx->pcr_sync_info.pcr_adjust_type == SYNC_AUD_ADJUST_SCR) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_PCR, (td_u32)ctx->aud_info.pts);
|
|
ext_info_sync("pcr set local time: %d by aud pts\n", ctx->aud_info.pts);
|
|
}
|
|
}
|
|
|
|
sync_set_local_time(ctx, SYNC_CHAN_VID, (td_u32)info->pts);
|
|
ext_info_sync("vid buf fund first set local time: %d\n", info->pts);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static void sync_set_vid_local_time(sync_context *ctx, const sync_vid_info *info)
|
|
{
|
|
if (info->disp_pts != SYNC_INVALID_PTS) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_VID, (td_u32)info->disp_pts);
|
|
ext_info_sync("sync_set_vid_local_time: %lld\n", info->disp_pts);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_is_vid_buf_overflow_discard_frm(sync_context *ctx, sync_vid_opt *opt)
|
|
{
|
|
if (!ctx->cur_buf_status.is_overflow_disc_frm) {
|
|
return TD_FALSE;
|
|
}
|
|
|
|
/* discard one frame in every VID_SMOOTH_DISCARD_INTERVAL frame */
|
|
if (!(ctx->vid_discard_play_cnt % VID_SMOOTH_DISCARD_INTERVAL)) {
|
|
ctx->vid_opt.proc = SYNC_PROC_DISCARD;
|
|
ext_info_sync("vid buf overflow, discard\n");
|
|
} else {
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_sync("vid bBuf overflow, play\n");
|
|
}
|
|
|
|
ctx->vid_discard_play_cnt++;
|
|
*opt = ctx->vid_opt;
|
|
ext_info_sync("--------vid sync proc %d--------\n", opt->proc);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static void sync_check_buf_adjust(const sync_buf_status *cur_stat, sync_context *ctx)
|
|
{
|
|
if ((!ctx->is_buf_adjust) && (!ctx->is_vid_sync_adjust) &&
|
|
(cur_stat->aud_buf_time > cur_stat->buf_time_max) &&
|
|
(cur_stat->vid_buf_time > cur_stat->buf_time_max)) {
|
|
if ((ctx->attr.sync_ref == SYNC_REF_PCR) &&
|
|
(ctx->pcr_sync_info.pcr_adjust_type == SYNC_PCR_ADJUST_SCR) &&
|
|
(ctx->pcr_sync_info.is_pcr_adjust_delta_ok == TD_TRUE)) {
|
|
if (cur_stat->vid_buf_time > cur_stat->aud_buf_time) {
|
|
ctx->pcr_sync_info.pcr_delta += (td_s32)(cur_stat->vid_buf_time - cur_stat->buf_time_normal);
|
|
} else {
|
|
ctx->pcr_sync_info.pcr_delta += (td_s32)(cur_stat->aud_buf_time - cur_stat->buf_time_normal);
|
|
}
|
|
|
|
ctx->pcr_sync_info.is_pcr_adjust_delta_ok = TD_FALSE;
|
|
ext_warn_sync("pcr_delta:%d\n", ctx->pcr_sync_info.pcr_delta);
|
|
}
|
|
|
|
ctx->is_buf_adjust = TD_TRUE;
|
|
}
|
|
}
|
|
|
|
static void sync_buf_adjust(sync_context *ctx)
|
|
{
|
|
sync_buf_status cur_stat = {0};
|
|
|
|
if ((!ctx->is_vid_first_come) || (!ctx->is_aud_first_come)) {
|
|
return;
|
|
}
|
|
|
|
if (memcpy_s(&cur_stat, sizeof(sync_buf_status), &ctx->cur_buf_status, sizeof(sync_buf_status)) != EOK) {
|
|
ext_err_sync("memcpy_s failed!\n");
|
|
return;
|
|
}
|
|
|
|
sync_check_buf_adjust(&cur_stat, ctx);
|
|
|
|
if (ctx->is_buf_adjust) {
|
|
if ((SYNC_REF_PCR == ctx->attr.sync_ref) &&
|
|
(SYNC_PCR_ADJUST_SCR == ctx->pcr_sync_info.pcr_adjust_type)) {
|
|
if ((cur_stat.aud_buf_time < cur_stat.buf_time_max) &&
|
|
(cur_stat.vid_buf_time < cur_stat.buf_time_max) &&
|
|
(TD_TRUE == ctx->is_vid_sync_adjust)) {
|
|
ctx->is_buf_adjust = TD_FALSE;
|
|
}
|
|
} else {
|
|
if ((cur_stat.aud_buf_time < cur_stat.buf_time_normal) ||
|
|
(cur_stat.vid_buf_time < cur_stat.buf_time_normal)) {
|
|
ctx->is_buf_adjust = TD_FALSE;
|
|
}
|
|
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
ctx->aud_discard_cnt++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sync_buf_low_proc(sync_context *ctx)
|
|
{
|
|
if ((ctx->attr.sync_ref == SYNC_REF_PCR) && (ctx->pcr_sync_info.pcr_adjust_type == SYNC_PCR_ADJUST_SCR)) {
|
|
if (ctx->pcr_sync_info.is_pcr_adjust_delta_ok == TD_TRUE) {
|
|
/* adjust pcr step by step */
|
|
ctx->pcr_sync_info.pcr_delta -= PCR_DELTA_ADJUST_STEP;
|
|
ctx->pcr_sync_info.is_pcr_adjust_delta_ok = TD_FALSE;
|
|
ext_warn_sync(">>>>buf low, change pcr_delta %d \n", ctx->pcr_sync_info.pcr_delta);
|
|
}
|
|
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
} else {
|
|
if ((ctx->vid_opt.proc == SYNC_PROC_DISCARD) &&
|
|
(ctx->cur_buf_status.vid_buf_state == SYNC_BUF_STATE_EMPTY) &&
|
|
(ctx->aud_opt.speed_adjust != SYNC_AUD_SPEED_ADJUST_MUTE_REPEAT)) {
|
|
if (ctx->vid_aud_diff + AUD_SYNC_REPEAT_THRESHOLD > 0) {
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_DOWN;
|
|
ctx->aud_opt.proc = SYNC_PROC_PLAY;
|
|
} else {
|
|
ctx->aud_opt.proc = SYNC_PROC_REPEAT;
|
|
ctx->aud_repeat_cnt++;
|
|
}
|
|
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
}
|
|
}
|
|
|
|
ext_info_sync("Aud/vid Buf Low\n");
|
|
}
|
|
|
|
static void sync_check_buf_stat(sync_context *ctx)
|
|
{
|
|
td_bool is_buf_low;
|
|
|
|
if (!ctx->is_presync_finish) {
|
|
return;
|
|
}
|
|
|
|
if (ctx->is_aud_first_come && ctx->is_vid_first_come) {
|
|
if ((ctx->attr.sync_ref == SYNC_REF_PCR) && (ctx->pcr_sync_info.pcr_adjust_type == SYNC_PCR_ADJUST_SCR)) {
|
|
if ((ctx->is_pcr_rewind == TD_TRUE) || (ctx->is_vid_rewind == TD_TRUE) || (ctx->is_aud_rewind == TD_TRUE)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ctx->cur_buf_status.is_buf_time_need_ctrl) {
|
|
sync_buf_adjust(ctx);
|
|
}
|
|
|
|
is_buf_low = ((ctx->aud_opt.proc == SYNC_PROC_DISCARD) &&
|
|
(ctx->cur_buf_status.aud_buf_state == SYNC_BUF_STATE_EMPTY)) ||
|
|
((ctx->vid_opt.proc == SYNC_PROC_DISCARD) &&
|
|
(ctx->cur_buf_status.vid_buf_state == SYNC_BUF_STATE_EMPTY));
|
|
|
|
if (is_buf_low == TD_FALSE) {
|
|
return;
|
|
}
|
|
|
|
sync_buf_low_proc(ctx);
|
|
return;
|
|
}
|
|
|
|
static td_bool proc_loopback_timeout(sync_context *ctx)
|
|
{
|
|
td_u32 time_cost;
|
|
|
|
if (ctx->loop_rewind_start_time == TD_INVALID_TIME) {
|
|
ctx->loop_rewind_start_time = sync_get_sys_time();
|
|
}
|
|
|
|
time_cost = sync_get_sys_time_cost(ctx->loop_rewind_start_time);
|
|
if (time_cost > PTS_LOOPBACK_TIMEOUT) {
|
|
ctx->is_aud_rewind = TD_FALSE;
|
|
ctx->is_pcr_rewind = TD_FALSE;
|
|
ctx->is_vid_rewind = TD_FALSE;
|
|
ctx->loop_rewind_start_time = TD_INVALID_TIME;
|
|
|
|
ext_warn_sync("loopback timeOut, Audloop: %d, Vidloop: %d, Pcrloop: %d, vid_aud_diff: %d\n",
|
|
ctx->is_aud_rewind, ctx->is_vid_rewind, ctx->is_pcr_rewind, ctx->vid_aud_diff);
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
inline td_bool is_audio_rewind_and_discard_video(sync_context *ctx)
|
|
{
|
|
if (ctx->is_vid_rewind == TD_FALSE && ctx->is_aud_rewind == TD_TRUE &&
|
|
(ctx->vid_info.pts == SYNC_INVALID_PTS ||
|
|
(ctx->vid_info.pts != SYNC_INVALID_PTS &&
|
|
ctx->aud_loop_rewind_pts != SYNC_INVALID_PTS &&
|
|
ctx->vid_info.pts > ctx->aud_loop_rewind_pts))) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_ref_aud_proc_vid_back(sync_context *ctx, sync_vid_opt *opt)
|
|
{
|
|
if ((ctx->is_aud_rewind == TD_FALSE) && (ctx->is_vid_rewind == TD_FALSE)) {
|
|
return;
|
|
}
|
|
|
|
if (proc_loopback_timeout(ctx)) {
|
|
return;
|
|
}
|
|
|
|
// audio rewind, then vid need drop frame
|
|
if (is_audio_rewind_and_discard_video(ctx) == TD_TRUE) {
|
|
opt->proc = SYNC_PROC_DISCARD_BY_AVPLAY;
|
|
ext_warn_sync("vid discard frame, Audloop: %d, Vidloop: %d, vid_aud_diff: %d\n",
|
|
ctx->is_aud_rewind, ctx->is_vid_rewind, ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
// video rewind, then vid need block to waite aud
|
|
if ((ctx->is_vid_rewind == TD_TRUE) && (ctx->is_aud_rewind == TD_FALSE)) {
|
|
opt->proc = SYNC_PROC_BLOCK;
|
|
ext_warn_sync("vid block frame, Audloop: %d, Vidloop: %d, vid_aud_diff: %d\n",
|
|
ctx->is_aud_rewind, ctx->is_vid_rewind, ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
// process back over
|
|
if ((ctx->is_vid_rewind == TD_TRUE) && (ctx->is_aud_rewind == TD_TRUE)) {
|
|
ctx->is_aud_rewind = TD_FALSE;
|
|
ctx->is_vid_rewind = TD_FALSE;
|
|
ext_warn_sync("loopback proc finsh, vid_aud_diff:%d\n", ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static td_bool sync_check_rewind_stat(const sync_context *ctx, td_bool vid_rewind,
|
|
td_bool pcr_rewind, td_bool aud_rewind)
|
|
{
|
|
if (ctx->is_vid_rewind == vid_rewind && ctx->is_pcr_rewind == pcr_rewind && ctx->is_aud_rewind == aud_rewind) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_ref_pcr_proc_vid_back(sync_context *ctx, sync_vid_opt *opt)
|
|
{
|
|
td_s64 vid_pcr_diff = ctx->vid_info.pts - ctx->pcr_sync_info.pcr_last_valid;
|
|
td_s64 aud_pcr_diff = ctx->aud_info.pts - ctx->pcr_sync_info.pcr_last_valid;
|
|
if (sync_check_rewind_stat(ctx, TD_FALSE, TD_FALSE, TD_FALSE)) {
|
|
return;
|
|
}
|
|
|
|
if (proc_loopback_timeout(ctx)) {
|
|
return;
|
|
}
|
|
|
|
do {
|
|
/* audio rewind, then video and pcr need to play */
|
|
if (sync_check_rewind_stat(ctx, TD_FALSE, TD_FALSE, TD_TRUE)) {
|
|
opt->proc = SYNC_PROC_PLAY;
|
|
break;
|
|
}
|
|
|
|
/* pcr and audio rewind, then vid need to drop frame */
|
|
if (sync_check_rewind_stat(ctx, TD_FALSE, TD_TRUE, TD_TRUE)) {
|
|
opt->proc = SYNC_PROC_DISCARD_BY_AVPLAY;
|
|
break;
|
|
}
|
|
|
|
/* video rewind, then vid need block to wait aud */
|
|
if (sync_check_rewind_stat(ctx, TD_TRUE, TD_FALSE, TD_FALSE)) {
|
|
opt->proc = SYNC_PROC_BLOCK;
|
|
break;
|
|
}
|
|
|
|
/* pcr and video rewind, then vid need block to wait aud */
|
|
if (sync_check_rewind_stat(ctx, TD_TRUE, TD_TRUE, TD_FALSE)) {
|
|
ctx->vid_opt.proc = vid_pcr_diff > 0 ? SYNC_PROC_BLOCK : SYNC_PROC_PLAY;
|
|
break;
|
|
}
|
|
|
|
/* process back over */
|
|
if (sync_check_rewind_stat(ctx, TD_TRUE, TD_TRUE, TD_TRUE)) {
|
|
ctx->vid_opt.proc = vid_pcr_diff > 0 ? SYNC_PROC_BLOCK : SYNC_PROC_PLAY;
|
|
|
|
if ((vid_pcr_diff < 0) && (aud_pcr_diff < 0)) {
|
|
ctx->is_aud_rewind = TD_FALSE;
|
|
ctx->is_pcr_rewind = TD_FALSE;
|
|
ctx->is_vid_rewind = TD_FALSE;
|
|
ctx->loop_rewind_start_time = TD_INVALID_TIME;
|
|
ext_warn_sync("loopback proc finsh, vid_aud_diff:%d\n", ctx->vid_aud_diff);
|
|
}
|
|
|
|
return;
|
|
}
|
|
} while (0);
|
|
|
|
ext_warn_sync("vid proc: %d, Audloop: %d, Vidloop: %d, Pcrloop: %d, vid_aud_diff: %d\n",
|
|
ctx->vid_opt.proc, ctx->is_aud_rewind, ctx->is_vid_rewind, ctx->is_pcr_rewind, ctx->vid_aud_diff);
|
|
}
|
|
|
|
static void sync_vid_proc_back(sync_context *ctx, sync_vid_info *info, sync_vid_opt *opt)
|
|
{
|
|
if (ctx->is_aud_first_come == TD_FALSE) {
|
|
ctx->is_vid_rewind = TD_FALSE;
|
|
ctx->is_pcr_rewind = TD_FALSE;
|
|
return;
|
|
}
|
|
|
|
if (sync_get_sync_adjust_ref_mode(ctx) == SYNC_REF_PCR) {
|
|
sync_ref_pcr_proc_vid_back(ctx, opt);
|
|
} else if (sync_get_sync_adjust_ref_mode(ctx) == SYNC_REF_AUDIO) {
|
|
sync_ref_aud_proc_vid_back(ctx, opt);
|
|
}
|
|
}
|
|
|
|
static td_bool sync_is_vid_loop_rewind(const sync_context *ctx, const sync_vid_info *info)
|
|
{
|
|
if (!info->is_pts_valid ||
|
|
ctx->is_vid_rewind == TD_TRUE ||
|
|
ctx->vid_last_valid_pts == SYNC_INVALID_PTS ||
|
|
(sync_get_sync_adjust_ref_mode(ctx) != SYNC_REF_PCR &&
|
|
sync_get_sync_adjust_ref_mode(ctx) != SYNC_REF_AUDIO)) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_check_vid_loop_rewind(sync_context *ctx, const sync_vid_info *info)
|
|
{
|
|
if (sync_is_vid_loop_rewind(ctx, info)) {
|
|
return;
|
|
}
|
|
|
|
if (ctx->vid_last_valid_pts > info->pts &&
|
|
(ctx->vid_last_valid_pts - info->pts) > PTS_LOOPBACK_THRESHOLD) {
|
|
if ((PCR_TIME_MAX - ctx->vid_last_valid_pts) < MAX_REWIND_PTS && info->pts < MAX_REWIND_PTS) {
|
|
ctx->is_vid_pts_normal_loop = TD_TRUE;
|
|
ext_warn_sync("video warps normally. last pts: %d, pts: %d\n", ctx->vid_last_valid_pts, info->pts);
|
|
} else {
|
|
ctx->vid_loop_rewind_count++;
|
|
if (ctx->vid_loop_rewind_count > MAX_REWIND_COUNT) {
|
|
ctx->vid_loop_rewind_pts = ctx->vid_last_valid_pts;
|
|
ctx->is_vid_rewind = TD_TRUE;
|
|
ext_warn_sync("vid loopback! lastpts %d, pts %d\n", ctx->vid_last_valid_pts, info->pts);
|
|
}
|
|
}
|
|
} else if ((ctx->is_aud_rewind == TD_TRUE) &&
|
|
(info->pts < ctx->aud_loop_rewind_pts) &&
|
|
((info->pts - ctx->aud_loop_rewind_pts) < (-1 * PTS_LOOPBACK_THRESHOLD))) {
|
|
if ((PCR_TIME_MAX - ctx->aud_loop_rewind_pts) < MAX_REWIND_PTS && info->pts < MAX_REWIND_PTS) {
|
|
ext_warn_sync("vid warps normally lastpts %d, pts %d\n", ctx->aud_loop_rewind_pts, info->pts);
|
|
} else {
|
|
ctx->aud_loop_rewind_pts = SYNC_INVALID_PTS;
|
|
ctx->vid_loop_rewind_pts = SYNC_INVALID_PTS;
|
|
ctx->is_vid_rewind = TD_TRUE;
|
|
ext_warn_sync("Vid loopback! lastpts %d, pts %d\n", ctx->aud_loop_rewind_pts, info->pts);
|
|
}
|
|
} else {
|
|
ctx->vid_loop_rewind_count = 0;
|
|
}
|
|
|
|
/* vid & aud pts all loopback normally then reset loop flag */
|
|
if ((ctx->is_aud_pts_normal_loop) && (ctx->is_vid_pts_normal_loop)) {
|
|
ctx->is_aud_pts_normal_loop = TD_FALSE;
|
|
ctx->is_vid_pts_normal_loop = TD_FALSE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void sync_vid_set_default_opt_val(sync_vid_opt *opt)
|
|
{
|
|
opt->proc = SYNC_PROC_PLAY;
|
|
opt->repeat = 0;
|
|
opt->discard = 0;
|
|
opt->vdec_discard_time = 0;
|
|
}
|
|
|
|
static void sync_vid_post_proc(sync_context *ctx, const sync_vid_info *info, sync_vid_opt *opt)
|
|
{
|
|
td_s32 pts_interval;
|
|
|
|
if (ctx->checking_valid_pts_jump && ctx->vid_opt.proc != SYNC_PROC_BLOCK &&
|
|
ctx->vid_opt.proc != SYNC_PROC_ACQ_NEXT_FRAME) {
|
|
ctx->vid_info.is_pts_valid = TD_TRUE;
|
|
ctx->checking_valid_pts_jump = TD_FALSE;
|
|
}
|
|
|
|
pts_interval = (td_u32)info->pts - ctx->vid_last_pts;
|
|
ctx->vid_last_pts = (td_u32)info->pts;
|
|
ctx->vid_disp_pts = (td_u32)info->disp_pts;
|
|
ctx->vid_last_src_pts = (td_u32)info->src_pts;
|
|
|
|
if (ctx->vid_info.is_pts_valid) {
|
|
ctx->vid_last_valid_pts = (td_u32)info->pts;
|
|
}
|
|
|
|
*opt = ctx->vid_opt;
|
|
|
|
#ifdef CONFIG_SOCT_SYNC_DEBUG_SUPPORT
|
|
sync_proc_debug_info(ctx, SYNC_DBG_INFO_LIST_VIDADD, TD_NULL);
|
|
#endif
|
|
|
|
ext_info_sync("--------vid sync proc: %d--------\n", opt->proc);
|
|
soc_trace_sync("handle:0x%x, src_pts:%lld, pts:%lld, interval:%d, disp_pts:%lld, disp_rate:%lld, frame_time:%lld, "
|
|
"speed:%u, presync:%d, diff:%d, proc:%d\n",
|
|
ctx->handle, info->src_pts, info->pts, pts_interval, info->disp_pts, info->disp_rate, info->frame_time,
|
|
ctx->vid_speed, ctx->is_presync_finish, ctx->vid_aud_diff, opt->proc);
|
|
}
|
|
|
|
static td_bool is_reset_first_frame_disp_timeout(sync_context *ctx, const sync_vid_info *info)
|
|
{
|
|
td_u32 time_cost;
|
|
|
|
/* The disp pts is old because avplay don't send frame to vo before presync finish */
|
|
if (ctx->cur_status == SYNC_STATUS_PAUSE || ctx->is_presync_finish == TD_FALSE) {
|
|
return TD_FALSE;
|
|
}
|
|
|
|
if (ctx->is_first_frame_disp_check_finish == TD_TRUE) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
if (ctx->reset_first_frame_disp_start_time == TD_INVALID_TIME) {
|
|
ctx->reset_first_frame_disp_start_time = sync_get_sys_time();
|
|
}
|
|
|
|
time_cost = sync_get_sys_time_cost(ctx->reset_first_frame_disp_start_time);
|
|
if (time_cost > RESET_FIRST_FRAME_DISP_TIMEOUT) {
|
|
ctx->reset_first_frame_disp_start_time = TD_INVALID_TIME;
|
|
ctx->is_first_frame_disp_check_finish = TD_TRUE;
|
|
|
|
soc_trace_sync("handle[0x%x] src_pts[%lld] pts[%lld] disp_pts[%lld] vid_first_valid_pts [%u]\n",
|
|
ctx->handle, info->src_pts, info->pts, info->disp_pts, ctx->vid_first_valid_pts);
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static td_void check_and_correct_disp_pts(sync_context *ctx, sync_vid_info *info)
|
|
{
|
|
if (is_reset_first_frame_disp_timeout(ctx, info) == TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
if (ctx->is_vid_fist_valid_pts_come == TD_FALSE && info->pts != SYNC_INVALID_PTS) {
|
|
/* The PTS of the quick output frame is not used as the synchronization reference */
|
|
if (ctx->attr.pre_sync_timeout == 0) {
|
|
ctx->vid_first_valid_pts = (td_u32)info->pts;
|
|
} else {
|
|
ctx->vid_first_valid_pts = (td_u32)(info->pts + info->frame_time);
|
|
}
|
|
|
|
ctx->is_vid_fist_valid_pts_come = TD_TRUE;
|
|
}
|
|
|
|
if (info->disp_pts == SYNC_INVALID_PTS ||
|
|
info->pts == SYNC_INVALID_PTS ||
|
|
(info->disp_pts >= ctx->vid_first_valid_pts && info->disp_pts <= info->pts)) {
|
|
return;
|
|
}
|
|
|
|
soc_trace_sync("handle[0x%x] src_pts[%lld] pts[%lld] disp_pts[%lld] vid_first_valid_pts [%u]\n",
|
|
ctx->handle, info->src_pts, info->pts, info->disp_pts, ctx->vid_first_valid_pts);
|
|
|
|
/* disp pts isn't within the valid range, it is old disp pts after reset.so it is invalid pts */
|
|
info->disp_pts = ctx->vid_info.disp_pts = SYNC_INVALID_PTS;
|
|
}
|
|
|
|
static void sync_vid_quick_output(sync_context *ctx, sync_vid_info *info, sync_vid_opt *opt)
|
|
{
|
|
ctx->is_vid_first_play = TD_TRUE;
|
|
ctx->vid_first_play_time = sync_get_sys_time();
|
|
|
|
ctx->is_vid_first_come = TD_TRUE;
|
|
ctx->vid_first_sys_time = ctx->vid_first_play_time;
|
|
ctx->vid_first_pts = (td_u32)info->pts;
|
|
|
|
check_and_correct_disp_pts(ctx, info);
|
|
|
|
ext_drv_stat_event(EXT_STAT_EVENT_FRAME_SYNC_OK, 0);
|
|
|
|
ctx->vid_opt.proc = SYNC_PROC_QUICKOUTPUT;
|
|
|
|
ext_info_sync("--------vid quickoutput proc %d--------\n", opt->proc);
|
|
ext_info_sync("first vidframe sys time: %d, pts: %d, src_pts: %d\n",
|
|
ctx->vid_first_sys_time, ctx->vid_first_pts, info->src_pts);
|
|
|
|
sync_vid_post_proc(ctx, info, opt);
|
|
}
|
|
|
|
static td_void check_and_save_vid_first_pts(sync_context *ctx, const sync_vid_info *info)
|
|
{
|
|
/* record the information and the time of the first video frame used to sync */
|
|
if (!ctx->is_vid_first_come) {
|
|
ctx->is_vid_first_come = TD_TRUE;
|
|
ctx->vid_first_sys_time = sync_get_sys_time();
|
|
ctx->vid_first_pts = (td_u32)info->pts;
|
|
ctx->is_vid_sync_adjust = TD_FALSE;
|
|
ext_info_sync("first vidframe sys time: %d, pts: %d, src_pts: %d\n",
|
|
ctx->vid_first_sys_time, ctx->vid_first_pts, info->src_pts);
|
|
}
|
|
|
|
if (!ctx->is_vid_first_valid_src_pts_come && (info->src_pts != SYNC_INVALID_PTS)) {
|
|
ctx->is_vid_first_valid_src_pts_come = TD_TRUE;
|
|
ctx->vid_first_valid_src_pts = (td_u32)info->src_pts;
|
|
|
|
if (ctx->is_aud_first_valid_come) {
|
|
ctx->is_first_sync_state_report = TD_TRUE;
|
|
}
|
|
|
|
ext_info_sync("vid_first_valid_src_pts come: %u\n", ctx->vid_first_valid_src_pts);
|
|
}
|
|
}
|
|
|
|
static td_bool sync_vid_pre_proc(sync_context *ctx, sync_vid_info *info, sync_vid_opt *opt)
|
|
{
|
|
sync_vid_set_default_opt_val(opt);
|
|
|
|
/* record the video frame information */
|
|
ctx->vid_info = *info;
|
|
ctx->vid_opt = *opt;
|
|
|
|
ext_info_sync("vid_info src_pts: %-8d, pts: %-8d, frame_time: %d, delay_time: %d,sys time: %d\n",
|
|
info->src_pts, info->pts, info->frame_time, info->delay_time, sync_get_sys_time());
|
|
|
|
/* can't do(no effect) smooth adjust when do sync without FRC(frame rate convertion) */
|
|
if (!ctx->is_use_stop_region) {
|
|
ctx->attr.start_region.smooth_play = TD_FALSE;
|
|
ctx->attr.novel_region.smooth_play = TD_FALSE;
|
|
}
|
|
|
|
/* pcr timeout, we used aud adjust scr */
|
|
if ((ctx->pcr_sync_info.pcr_adjust_type == SYNC_SCR_ADJUST_MAX) && (ctx->attr.sync_ref == SYNC_REF_PCR)) {
|
|
if (ctx->pcr_sync_info.pcr_sync_start_sys_time == TD_INVALID_TIME) {
|
|
ctx->pcr_sync_info.pcr_sync_start_sys_time = sync_get_sys_time();
|
|
}
|
|
|
|
if (sync_check_pcr_timeout(ctx) == TD_TRUE) {
|
|
ctx->pcr_sync_info.pcr_adjust_type = SYNC_AUD_ADJUST_SCR;
|
|
ext_info_sync("Pcr is timeout adjust pcr by aud_pts\n");
|
|
}
|
|
}
|
|
|
|
sync_check_vid_pts_valid(ctx, &ctx->vid_info);
|
|
sync_check_vid_loop_rewind(ctx, &ctx->vid_info);
|
|
|
|
/* quick output the first frame */
|
|
if (ctx->attr.quick_output && (!ctx->is_vid_first_play)) {
|
|
sync_vid_quick_output(ctx, info, opt);
|
|
return TD_FALSE;
|
|
}
|
|
|
|
check_and_save_vid_first_pts(ctx, info);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static td_bool sync_is_valid_pts_jump(const sync_context *ctx)
|
|
{
|
|
const sync_vid_info *info = &ctx->vid_info;
|
|
|
|
if (info->src_pts == SYNC_INVALID_PTS) {
|
|
ext_warn_sync("abnormal pts jump. process the frame as usual.\n");
|
|
return TD_FALSE;
|
|
} else if (ctx->last_vid_info.pts != SYNC_INVALID_PTS && info->pts != SYNC_INVALID_PTS) {
|
|
if (info->pts - ctx->last_vid_info.pts < 0) {
|
|
ext_warn_sync("abnormal pts jump. process the frame as usual.\n");
|
|
return TD_FALSE;
|
|
} else if (info->pts == ctx->last_vid_info.pts) {
|
|
ext_info_sync("no another new frame. process the frame as usual.\n");
|
|
return TD_FALSE;
|
|
}
|
|
}
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static td_void sync_check_vid_pts_jump(sync_context *ctx)
|
|
{
|
|
td_s32 ret;
|
|
td_s32 vid_aud_diff;
|
|
|
|
if (!ctx->is_proc_valid_pts_jump) { /* not support valid pts jump, used for debug */
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
return;
|
|
}
|
|
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
|
|
if (ctx->one_more_frame && !ctx->checking_valid_pts_jump) {
|
|
ctx->vid_opt.proc = SYNC_PROC_ACQ_NEXT_FRAME;
|
|
ctx->checking_valid_pts_jump = TD_TRUE;
|
|
ctx->one_more_frame = TD_FALSE;
|
|
ext_info_sync("pts jump and need one more frame to check whether valid pts jump.\n");
|
|
return;
|
|
}
|
|
|
|
if (!ctx->checking_valid_pts_jump) {
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
return;
|
|
}
|
|
|
|
if (!sync_is_valid_pts_jump(ctx)) {
|
|
ctx->checking_valid_pts_jump = TD_FALSE;
|
|
ret = memcpy_s(&ctx->vid_info, sizeof(ctx->vid_info), &ctx->last_vid_info, sizeof(ctx->last_vid_info));
|
|
if (ret != EOK) {
|
|
ext_err_sync("memcpy_s failed!\n");
|
|
return;
|
|
}
|
|
|
|
ctx->vid_opt.proc = SYNC_PROC_CONTINUE;
|
|
return;
|
|
}
|
|
|
|
ctx->vid_local_time_update_flag = TD_TRUE;
|
|
|
|
vid_aud_diff = (td_s32)(ctx->last_vid_info.pts - sync_get_local_time(ctx, SYNC_CHAN_AUD));
|
|
if (vid_aud_diff > ctx->vid_info.frame_time) {
|
|
ext_info_sync("valid pts jump. wait to finish play last frame. vid_aud_diff: %d, frame_time: %lld\n",
|
|
ctx->vid_aud_diff, ctx->vid_info.frame_time);
|
|
ctx->vid_opt.proc = SYNC_PROC_BLOCK;
|
|
} else {
|
|
ret = memcpy_s(&ctx->vid_info, sizeof(ctx->vid_info), &ctx->last_vid_info, sizeof(ctx->last_vid_info));
|
|
if (ret != EOK) {
|
|
ext_err_sync("memcpy_s failed!\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_update_vid_local_time(sync_context *ctx)
|
|
{
|
|
if (ctx->vid_local_time_update_flag && ctx->vid_info.disp_pts != TD_INVALID_PTS &&
|
|
ctx->vid_info.disp_pts < ctx->last_vid_info.pts) {
|
|
ext_info_sync("do not update vid local time. get vid local time:%u\n", sync_get_local_time(ctx, SYNC_CHAN_VID));
|
|
return;
|
|
} else {
|
|
sync_set_vid_local_time(ctx, &ctx->vid_info);
|
|
if (ctx->vid_local_time_update_flag) {
|
|
ctx->vid_local_time_update_flag = TD_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_s32 sync_vid_presync_proc(sync_context *ctx, const sync_vid_info *info)
|
|
{
|
|
/* presync */
|
|
if (!sync_is_vid_presync_finish(ctx, info, &ctx->vid_opt)) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
/* presync finished. cumulate video and audio data to prevent underflow */
|
|
if (!sync_is_vid_buf_fund_finish(ctx, info, &ctx->vid_opt)) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static void sync_vid_first_play(sync_context *ctx)
|
|
{
|
|
if (ctx->vid_opt.proc == SYNC_PROC_PLAY) {
|
|
if (!ctx->is_vid_first_play) {
|
|
ctx->is_vid_first_play = TD_TRUE;
|
|
ctx->is_vid_normal_play = TD_TRUE;
|
|
ctx->vid_first_play_time = sync_get_sys_time();
|
|
ext_drv_stat_event(EXT_STAT_EVENT_FRAME_SYNC_OK, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sync_vid_proc(td_handle sync, sync_vid_info *info, sync_vid_opt *opt)
|
|
{
|
|
td_u32 id = sync_get_id(sync);
|
|
sync_context *ctx = TD_NULL;
|
|
td_s32 ret;
|
|
|
|
sync_check_id_not_ret(id);
|
|
|
|
ctx = sync_info_ctx_get(id);
|
|
ctx->handle = sync;
|
|
if (sync_vid_pre_proc(ctx, info, opt) != TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
if (ctx->cur_status == SYNC_STATUS_TPLAY) {
|
|
sync_set_vid_local_time(ctx, &ctx->vid_info);
|
|
ctx->vid_opt.proc = SYNC_PROC_PLAY;
|
|
ext_info_sync("--------vid tplay--------\n");
|
|
goto out;
|
|
}
|
|
|
|
check_and_correct_disp_pts(ctx, info);
|
|
|
|
if (ctx->cur_status == SYNC_STATUS_PAUSE) {
|
|
sync_pause_update_vid_local_time(ctx, (td_u32)ctx->vid_info.pts);
|
|
sync_pause_update_scr_local_time(ctx);
|
|
goto out;
|
|
}
|
|
|
|
ret = sync_vid_presync_proc(ctx, &ctx->vid_info);
|
|
if (ret != TD_SUCCESS) {
|
|
goto out;
|
|
}
|
|
|
|
sync_check_vid_pts_jump(ctx);
|
|
if (ctx->vid_opt.proc != SYNC_PROC_CONTINUE) {
|
|
goto out;
|
|
}
|
|
|
|
sync_update_vid_local_time(ctx);
|
|
sync_calc_difftime(ctx, SYNC_CHAN_VID);
|
|
sync_check_evt(ctx, SYNC_CHAN_VID);
|
|
|
|
if (sync_is_vid_buf_overflow_discard_frm(ctx, &ctx->vid_opt)) {
|
|
goto out;
|
|
}
|
|
|
|
if (sync_is_sync_ref_none(ctx, SYNC_CHAN_VID)) {
|
|
goto out;
|
|
}
|
|
|
|
sync_adjust(ctx, SYNC_CHAN_VID);
|
|
sync_vid_proc_back(ctx, &ctx->vid_info, &ctx->vid_opt);
|
|
sync_check_buf_stat(ctx);
|
|
sync_vid_first_play(ctx);
|
|
|
|
out:
|
|
sync_vid_post_proc(ctx, info, opt);
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_is_aud_presync_finish(sync_context *ctx, const sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
if (ctx->is_presync_finish) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
sync_presync(ctx, SYNC_CHAN_AUD);
|
|
|
|
if (ctx->aud_opt.proc != SYNC_PROC_CONTINUE) {
|
|
*opt = ctx->aud_opt;
|
|
|
|
if (ctx->is_presync_target_init) {
|
|
ext_info_sync("--------aud presync vid_aud_diff: %d, proc: %d, speed: %d--------\n",
|
|
ctx->vid_aud_diff, opt->proc, opt->speed_adjust);
|
|
}
|
|
|
|
if (info->is_pts_valid) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_AUD, (td_u32)info->pts);
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
/* first set scr */
|
|
if (!ctx->is_scr_init && (info->pts != SYNC_INVALID_PTS)) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_SCR, (td_u32)info->pts);
|
|
ctx->is_scr_init = TD_TRUE;
|
|
ctx->scr_first_local_time = (td_u32)info->pts;
|
|
ctx->scr_first_sys_time = sync_get_sys_time();
|
|
}
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static td_bool sync_is_aud_buf_fund_finish(sync_context *ctx, const sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
if (ctx->is_buf_fund_finish) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
sync_buf_fund(ctx);
|
|
|
|
if (ctx->aud_opt.proc != SYNC_PROC_CONTINUE) {
|
|
*opt = ctx->aud_opt;
|
|
ext_info_sync("--------aud buf fund proc: %d, speed: %d--------\n",
|
|
opt->proc, opt->speed_adjust);
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
sync_set_local_time(ctx, SYNC_CHAN_AUD, (td_u32)info->pts);
|
|
|
|
if (ctx->pcr_sync_info.pcr_adjust_type == SYNC_AUD_ADJUST_SCR) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_PCR, (td_u32)info->pts);
|
|
ext_info_sync("Pcr set local time: %d by aud pts\n", info->pts);
|
|
}
|
|
|
|
if (ctx->is_vid_first_come) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_VID, (td_u32)ctx->vid_info.pts);
|
|
ext_info_sync("vid buf fund first set local time %d\n", ctx->vid_info.pts);
|
|
}
|
|
|
|
ext_info_sync("aud buf fund first set local time %d\n", info->pts);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static td_bool sync_is_aud_resync_finish(sync_context *ctx, const sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
/* AudDDPMode do not set audio resynchronization */
|
|
if (ctx->is_ddp_mode || !ctx->is_aud_resync) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
sync_aud_resync(ctx);
|
|
|
|
if (ctx->aud_opt.proc != SYNC_PROC_CONTINUE) {
|
|
*opt = ctx->aud_opt;
|
|
ext_info_sync("--------aud resync vid_aud_diff: %d, proc: %d, speed: %d--------\n",
|
|
ctx->vid_aud_diff, opt->proc, opt->speed_adjust);
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
static void sync_set_aud_local_time(sync_context *ctx, const sync_aud_info *info)
|
|
{
|
|
if ((info->is_pts_valid == TD_TRUE) ||
|
|
((ctx->is_aud_local_time == TD_FALSE) && (info->pts != SYNC_INVALID_PTS))) {
|
|
/* buffer time maybe larger than pts because track hardware delay */
|
|
td_u32 local_time = (info->pts > info->buf_time) ? (info->pts - info->buf_time) : 0;
|
|
sync_set_local_time(ctx, SYNC_CHAN_AUD, local_time);
|
|
|
|
if (ctx->pcr_sync_info.pcr_adjust_type == SYNC_AUD_ADJUST_SCR) {
|
|
sync_set_local_time(ctx, SYNC_CHAN_PCR, (td_u32)(info->pts - info->buf_time));
|
|
ext_info_sync("pcr set local time: %d by aud pts\n", (info->pts - info->buf_time));
|
|
}
|
|
|
|
ext_info_sync("aud set local time: %d\n", (info->pts - info->buf_time));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_is_aud_rebuf_fund_finish(sync_context *ctx, const sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
if (!ctx->is_aud_rebuf_fund) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
sync_aud_rebuf_fund(ctx);
|
|
|
|
if (ctx->aud_opt.proc != SYNC_PROC_CONTINUE) {
|
|
*opt = ctx->aud_opt;
|
|
|
|
ext_info_sync("--------aud rebuffund proc %d speed %d--------\n\n", opt->proc, opt->speed_adjust);
|
|
return TD_FALSE;
|
|
}
|
|
|
|
sync_set_aud_local_time(ctx, info);
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
inline td_bool is_video_rewind_and_discard_audio(sync_context *ctx)
|
|
{
|
|
if (ctx->is_vid_rewind == TD_TRUE && ctx->is_aud_rewind == TD_FALSE &&
|
|
(ctx->aud_info.pts == SYNC_INVALID_PTS ||
|
|
(ctx->aud_info.pts != SYNC_INVALID_PTS &&
|
|
ctx->vid_loop_rewind_pts != SYNC_INVALID_PTS &&
|
|
ctx->aud_info.pts > ctx->vid_loop_rewind_pts))) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_ref_aud_proc_aud_back(sync_context *ctx, sync_aud_opt *opt)
|
|
{
|
|
if (ctx->is_aud_rewind == TD_FALSE && ctx->is_vid_rewind == TD_FALSE) {
|
|
return;
|
|
}
|
|
|
|
if (proc_loopback_timeout(ctx)) {
|
|
return;
|
|
}
|
|
|
|
// audio rewind, then aud need block to waite vid
|
|
if (ctx->is_vid_rewind == TD_FALSE && ctx->is_aud_rewind == TD_TRUE) {
|
|
opt->proc = SYNC_PROC_BLOCK;
|
|
ext_warn_sync("aud block frame, Audloop: %d, Vidloop: %d, vid_aud_diff: %d\n",
|
|
ctx->is_aud_rewind, ctx->is_vid_rewind, ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
// video rewind, then aud need discard
|
|
if (is_video_rewind_and_discard_audio(ctx) == TD_TRUE) {
|
|
opt->proc = SYNC_PROC_DISCARD;
|
|
ext_warn_sync("vid block frame, Audloop: %d, Vidloop: %d, vid_aud_diff: %d\n",
|
|
ctx->is_aud_rewind, ctx->is_vid_rewind, ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
|
|
// process back over
|
|
if (ctx->is_vid_rewind == TD_TRUE && ctx->is_aud_rewind == TD_TRUE) {
|
|
ctx->is_aud_rewind = TD_FALSE;
|
|
ctx->is_vid_rewind = TD_FALSE;
|
|
ext_warn_sync("loopback proc finsh, vid_aud_diff:%d\n", ctx->vid_aud_diff);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void sync_ref_pcr_proc_aud_back(sync_context *ctx, sync_aud_opt *opt)
|
|
{
|
|
td_s64 vid_pcr_diff = ctx->vid_info.pts - ctx->pcr_sync_info.pcr_last_valid;
|
|
td_s64 aud_pcr_diff = ctx->aud_info.pts - ctx->pcr_sync_info.pcr_last_valid;
|
|
if (sync_check_rewind_stat(ctx, TD_FALSE, TD_FALSE, TD_FALSE)) {
|
|
return;
|
|
}
|
|
|
|
if (proc_loopback_timeout(ctx)) {
|
|
return;
|
|
}
|
|
|
|
do {
|
|
if (sync_check_rewind_stat(ctx, TD_TRUE, TD_FALSE, TD_FALSE)) {
|
|
opt->proc = SYNC_PROC_PLAY;
|
|
break;
|
|
}
|
|
|
|
if (sync_check_rewind_stat(ctx, TD_TRUE, TD_TRUE, TD_FALSE)) {
|
|
opt->proc = SYNC_PROC_DISCARD;
|
|
break;
|
|
}
|
|
|
|
if (sync_check_rewind_stat(ctx, TD_FALSE, TD_FALSE, TD_TRUE)) {
|
|
opt->proc = SYNC_PROC_BLOCK;
|
|
break;
|
|
}
|
|
|
|
if (sync_check_rewind_stat(ctx, TD_FALSE, TD_TRUE, TD_TRUE)) {
|
|
opt->proc = aud_pcr_diff > 0 ? SYNC_PROC_BLOCK : SYNC_PROC_PLAY;
|
|
break;
|
|
}
|
|
|
|
if (sync_check_rewind_stat(ctx, TD_TRUE, TD_TRUE, TD_TRUE)) {
|
|
opt->proc = aud_pcr_diff > 0 ? SYNC_PROC_BLOCK : SYNC_PROC_PLAY;
|
|
|
|
if ((vid_pcr_diff < 0) && (aud_pcr_diff < 0)) {
|
|
ctx->is_aud_rewind = TD_FALSE;
|
|
ctx->is_pcr_rewind = TD_FALSE;
|
|
ctx->is_vid_rewind = TD_FALSE;
|
|
ctx->loop_rewind_start_time = TD_INVALID_TIME;
|
|
ext_warn_sync("loopback proc finsh, vid_aud_diff:%d\n", ctx->vid_aud_diff);
|
|
}
|
|
return;
|
|
}
|
|
} while (0);
|
|
|
|
ext_warn_sync("aud proc: %d, aud loop: %d, vid loop: %d, pcr loop: %d, vid_aud_diff: %d\n",
|
|
opt->proc, ctx->is_aud_rewind, ctx->is_vid_rewind, ctx->is_pcr_rewind, ctx->vid_aud_diff);
|
|
}
|
|
|
|
static void sync_aud_proc_back(sync_context *ctx, sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
if (ctx->is_vid_first_come == TD_FALSE) {
|
|
ctx->is_aud_rewind = TD_FALSE;
|
|
ctx->is_pcr_rewind = TD_FALSE;
|
|
return;
|
|
}
|
|
|
|
if (sync_get_sync_adjust_ref_mode(ctx) == SYNC_REF_PCR) {
|
|
sync_ref_pcr_proc_aud_back(ctx, opt);
|
|
} else if (sync_get_sync_adjust_ref_mode(ctx) == SYNC_REF_AUDIO) {
|
|
sync_ref_aud_proc_aud_back(ctx, opt);
|
|
}
|
|
}
|
|
|
|
static td_bool sync_is_aud_loop_rewind(const sync_context *ctx, const sync_aud_info *info)
|
|
{
|
|
if (!info->is_pts_valid ||
|
|
ctx->is_aud_rewind == TD_TRUE ||
|
|
ctx->aud_last_valid_pts == SYNC_INVALID_PTS ||
|
|
((sync_get_sync_adjust_ref_mode(ctx) != SYNC_REF_PCR) &&
|
|
(sync_get_sync_adjust_ref_mode(ctx) != SYNC_REF_AUDIO))) {
|
|
return TD_TRUE;
|
|
}
|
|
|
|
return TD_FALSE;
|
|
}
|
|
|
|
static void sync_check_aud_loop_rewind(sync_context *ctx, const sync_aud_info *info)
|
|
{
|
|
if (sync_is_aud_loop_rewind(ctx, info)) {
|
|
return;
|
|
}
|
|
|
|
if ((ctx->aud_last_valid_pts > info->pts) &&
|
|
(ctx->aud_last_valid_pts - info->pts > PTS_LOOPBACK_THRESHOLD)) {
|
|
if ((PCR_TIME_MAX - ctx->aud_last_valid_pts < MAX_REWIND_PTS) && (info->pts < MAX_REWIND_PTS)) {
|
|
ctx->is_aud_pts_normal_loop = TD_TRUE;
|
|
ext_warn_sync("audio warps normally.lp %d,p %d\n", ctx->aud_last_valid_pts, info->pts);
|
|
} else {
|
|
ctx->aud_loop_rewind_count++;
|
|
if (ctx->aud_loop_rewind_count > MAX_REWIND_COUNT) {
|
|
ctx->aud_loop_rewind_pts = ctx->aud_last_valid_pts;
|
|
ctx->is_aud_rewind = TD_TRUE;
|
|
ext_warn_sync("Aud loop rewind! last pts: %d, pts: %d\n", ctx->aud_last_valid_pts, info->pts);
|
|
}
|
|
}
|
|
} else if ((ctx->is_vid_rewind == TD_TRUE) &&
|
|
(info->pts < ctx->vid_loop_rewind_pts) &&
|
|
(info->pts - ctx->vid_loop_rewind_pts < (-1 * PTS_LOOPBACK_THRESHOLD))) {
|
|
if ((PCR_TIME_MAX - ctx->vid_loop_rewind_pts < MAX_REWIND_PTS) && (info->pts < MAX_REWIND_PTS)) {
|
|
ext_warn_sync("audio warps normally lastpts %d, pts %d\n", ctx->aud_loop_rewind_pts, info->pts);
|
|
} else {
|
|
ctx->aud_loop_rewind_pts = SYNC_INVALID_PTS;
|
|
ctx->vid_loop_rewind_pts = SYNC_INVALID_PTS;
|
|
ctx->is_aud_rewind = TD_TRUE;
|
|
ext_warn_sync("Aud loop rewind! last pts: %d, pts: %d\n", ctx->aud_last_valid_pts, info->pts);
|
|
}
|
|
} else {
|
|
ctx->aud_loop_rewind_count = 0;
|
|
}
|
|
|
|
/* vid & aud pts all loopback normally then reset loop flag */
|
|
if ((ctx->is_aud_pts_normal_loop) && (ctx->is_vid_pts_normal_loop)) {
|
|
ctx->is_aud_pts_normal_loop = TD_FALSE;
|
|
ctx->is_vid_pts_normal_loop = TD_FALSE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void sync_ad_aud_proc(td_handle sync, const sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
td_u32 id = sync_get_id(sync);
|
|
sync_context *ctx = TD_NULL;
|
|
td_s64 ad_aud_diff = 0LL;
|
|
|
|
sync_check_id_not_ret(id);
|
|
|
|
ctx = sync_info_ctx_get(id);
|
|
opt->proc = SYNC_PROC_PLAY;
|
|
opt->speed_adjust = SYNC_AUD_SPEED_ADJUST_NORMAL;
|
|
/* record audio frame information */
|
|
ctx->ad_aud_info = *info;
|
|
ctx->ad_aud_opt = *opt;
|
|
|
|
if (ctx->aud_last_pts == SYNC_INVALID_PTS || ctx->ad_aud_info.pts == SYNC_INVALID_PTS) {
|
|
ctx->ad_aud_opt.proc = SYNC_PROC_PLAY;
|
|
goto out;
|
|
}
|
|
|
|
ad_aud_diff = ctx->ad_aud_info.pts - ctx->aud_last_pts;
|
|
if (sync_abs(ad_aud_diff) > SYNC_AD_AUD_PTS_MAX_DIFF) {
|
|
ctx->ad_aud_opt.proc = SYNC_PROC_PLAY;
|
|
goto out;
|
|
}
|
|
|
|
if (ad_aud_diff < SYNC_AD_AUD_STOP_PLUS && ad_aud_diff > SYNC_AD_AUD_STOP_NEGATIVE) {
|
|
ctx->ad_aud_opt.proc = SYNC_PROC_PLAY;
|
|
}
|
|
|
|
if (ad_aud_diff > SYNC_AD_AUD_START_PLUS) {
|
|
ctx->ad_aud_opt.proc = SYNC_PROC_REPEAT;
|
|
ext_info_sync("SYNC_PROC_REPEAT ad aud pts:%lld, target pts:%u\n", ctx->ad_aud_info.pts, ctx->aud_last_pts);
|
|
}
|
|
|
|
if (ad_aud_diff < SYNC_AD_AUD_START_NEGATIVE) {
|
|
ctx->ad_aud_opt.proc = SYNC_PROC_DISCARD;
|
|
ext_info_sync("SYNC_PROC_DISCARD ad aud pts:%lld, target pts:%u\n", ctx->ad_aud_info.pts, ctx->aud_last_pts);
|
|
}
|
|
|
|
out:
|
|
*opt = ctx->ad_aud_opt;
|
|
soc_trace_sync("[ad_aud] src_pts[%lld] pts[%lld] aud_pts[%lld] frame_time[%lld] presync[%d] diff[%lld] proc[%d]\n",
|
|
info->src_pts, info->pts, ctx->aud_last_pts, info->frame_time, ctx->is_presync_finish,
|
|
ad_aud_diff, opt->proc);
|
|
}
|
|
|
|
static void sync_aud_pre_proc(sync_context *ctx, const sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
td_u32 sys_time = sync_get_sys_time();
|
|
|
|
TD_UNUSED(sys_time);
|
|
opt->proc = SYNC_PROC_PLAY;
|
|
opt->speed_adjust = SYNC_AUD_SPEED_ADJUST_NORMAL;
|
|
|
|
/* record audio frame information */
|
|
ctx->aud_info = *info;
|
|
ctx->aud_opt = *opt;
|
|
|
|
ext_info_sync("aud info src_pts: %-8d, pts: %-8d, frame_time: %d, buf_time: %-4d, frame_num: %d, sys_time: %d\n",
|
|
info->src_pts, info->pts, info->frame_time, info->buf_time, info->frame_num, sys_time);
|
|
|
|
/* can't do(no effect) smooth adjust when do sync without FRC(frame rate convertion) */
|
|
if (!ctx->is_use_stop_region) {
|
|
ctx->attr.start_region.smooth_play = TD_FALSE;
|
|
ctx->attr.novel_region.smooth_play = TD_FALSE;
|
|
}
|
|
|
|
if ((ctx->pcr_sync_info.pcr_adjust_type == SYNC_SCR_ADJUST_MAX) &&
|
|
(ctx->attr.sync_ref == SYNC_REF_PCR)) {
|
|
if (ctx->pcr_sync_info.pcr_sync_start_sys_time == TD_INVALID_TIME) {
|
|
ctx->pcr_sync_info.pcr_sync_start_sys_time = sync_get_sys_time();
|
|
}
|
|
|
|
if (sync_check_pcr_timeout(ctx) == TD_TRUE) {
|
|
ctx->pcr_sync_info.pcr_adjust_type = SYNC_AUD_ADJUST_SCR;
|
|
ext_info_sync("Pcr is timeout adjust pcr by aud_pts\n");
|
|
}
|
|
}
|
|
|
|
sync_check_aud_pts_valid(ctx, &ctx->aud_info);
|
|
sync_check_aud_loop_rewind(ctx, &ctx->aud_info);
|
|
|
|
if (!ctx->is_aud_first_come) {
|
|
ctx->is_aud_first_come = TD_TRUE;
|
|
ctx->aud_first_sys_time = sync_get_sys_time();
|
|
ctx->aud_first_pts = (td_u32)info->pts;
|
|
ctx->aud_last_pts = (td_u32)info->pts;
|
|
ctx->aud_last_buf_time = (td_u32)info->buf_time;
|
|
|
|
ext_info_sync("first aud frame sys time: %d, pts: %d, src_pts: %d\n",
|
|
ctx->aud_first_sys_time, ctx->aud_first_pts, info->src_pts);
|
|
ctx->is_vid_sync_adjust = TD_FALSE;
|
|
}
|
|
|
|
if (!ctx->is_aud_first_valid_come && (info->src_pts != SYNC_INVALID_PTS)) {
|
|
ctx->is_aud_first_valid_come = TD_TRUE;
|
|
ctx->aud_first_valid_pts = (td_u32)info->src_pts;
|
|
|
|
if (ctx->is_vid_first_valid_src_pts_come) {
|
|
ctx->is_first_sync_state_report = TD_TRUE;
|
|
}
|
|
|
|
ext_info_sync("aud_first_valid_pts come: %u\n", ctx->aud_first_valid_pts);
|
|
}
|
|
}
|
|
|
|
static void sync_aud_post_proc(sync_context *ctx, const sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
td_s32 pts_interval;
|
|
pts_interval = (td_u32)info->pts - ctx->aud_last_pts;
|
|
ctx->aud_last_pts = (td_u32)info->pts;
|
|
ctx->aud_last_buf_time = (td_u32)info->buf_time;
|
|
|
|
if (ctx->aud_info.is_pts_valid) {
|
|
ctx->aud_last_valid_pts = (td_u32)info->pts;
|
|
}
|
|
|
|
*opt = ctx->aud_opt;
|
|
|
|
ext_warn_sync("aud proc: %d, speed: %d, aud_pcr_diff: %d, vid_pcr_diff: %d, vid_aud_diff: %d, \
|
|
aud local time: %d, pcr local time: %d, pts: %d, buf_time: %d, frame_time: %d, \
|
|
sys time: %d, pcr_last: %d, pcr_delta: %d, vid_last_pts: %d\n",
|
|
opt->proc, opt->speed_adjust, ctx->pcr_sync_info.aud_pcr_diff, ctx->pcr_sync_info.vid_pcr_diff,
|
|
ctx->vid_aud_diff, sync_get_local_time(ctx, SYNC_CHAN_AUD),
|
|
sync_get_local_time(ctx, SYNC_CHAN_PCR), info->pts, info->buf_time,
|
|
info->frame_time, sync_get_sys_time(), ctx->pcr_sync_info.pcr_last,
|
|
ctx->pcr_sync_info.pcr_delta, ctx->vid_last_pts);
|
|
|
|
soc_trace_sync("handle:0x%x, src_pts:%lld, pts:%lld, interval:%d, delay:%lld, frame_time:%lld, "
|
|
"speed:%u, presync:%d, diff:%d, proc:%d, speed_adjust:%d\n",
|
|
ctx->handle, info->src_pts, info->pts, pts_interval, info->buf_time, info->frame_time,
|
|
ctx->aud_speed, ctx->is_presync_finish, ctx->vid_aud_diff, opt->proc, opt->speed_adjust);
|
|
}
|
|
|
|
static void save_aud_first_play_time(sync_context *ctx, sync_aud_opt *opt)
|
|
{
|
|
if (opt->proc == SYNC_PROC_PLAY) {
|
|
if (!ctx->is_aud_first_play) {
|
|
ctx->is_aud_first_play = TD_TRUE;
|
|
ctx->aud_first_play_time = sync_get_sys_time();
|
|
}
|
|
}
|
|
}
|
|
|
|
static td_s32 sync_aud_presync_proc(sync_context *ctx, const sync_aud_info *info)
|
|
{
|
|
if ((info->pts == SYNC_INVALID_PTS) &&
|
|
(!ctx->is_aud_first_valid_come) && (ctx->attr.sync_ref == SYNC_REF_PCR)) {
|
|
ctx->aud_opt.proc = SYNC_PROC_DISCARD;
|
|
ctx->aud_opt.speed_adjust = SYNC_AUD_SPEED_ADJUST_NORMAL;
|
|
ext_warn_sync("aud pts is -1 ------\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (!sync_is_aud_presync_finish(ctx, info, &ctx->aud_opt)) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (!sync_is_aud_buf_fund_finish(ctx, info, &ctx->aud_opt)) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
/* audio resynchronization is needed when change audio track.StopAud->StartAud */
|
|
if (!sync_is_aud_resync_finish(ctx, info, &ctx->aud_opt)) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
/* it is needed to accumulate audio data again */
|
|
if (!sync_is_aud_rebuf_fund_finish(ctx, info, &ctx->aud_opt)) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if ((ctx->attr.sync_ref == SYNC_REF_PCR) && (!ctx->is_aud_first_play)) {
|
|
if ((ctx->is_vid_first_come == TD_FALSE) && (sync_check_aud_timeout(ctx) == TD_FALSE)) {
|
|
ctx->aud_opt.proc = SYNC_PROC_BLOCK;
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
void sync_aud_proc(td_handle sync, sync_aud_info *info, sync_aud_opt *opt)
|
|
{
|
|
td_u32 id = sync_get_id(sync);
|
|
sync_context *ctx = TD_NULL;
|
|
td_s32 ret;
|
|
|
|
sync_check_id_not_ret(id);
|
|
ctx = sync_info_ctx_get(id);
|
|
ctx->handle = sync;
|
|
|
|
sync_aud_pre_proc(ctx, info, opt);
|
|
|
|
if (ctx->cur_status == SYNC_STATUS_PAUSE) {
|
|
sync_pause_update_aud_local_time(ctx, (td_u32)ctx->aud_info.pts);
|
|
sync_pause_update_scr_local_time(ctx);
|
|
goto out;
|
|
}
|
|
|
|
ret = sync_aud_presync_proc(ctx, &ctx->aud_info);
|
|
if (ret != TD_SUCCESS) {
|
|
goto out;
|
|
}
|
|
|
|
sync_set_aud_local_time(ctx, &ctx->aud_info);
|
|
sync_calc_difftime(ctx, SYNC_CHAN_AUD);
|
|
sync_check_evt(ctx, SYNC_CHAN_AUD);
|
|
|
|
if (sync_is_sync_ref_none(ctx, SYNC_CHAN_AUD)) {
|
|
goto out;
|
|
}
|
|
|
|
sync_adjust(ctx, SYNC_CHAN_AUD);
|
|
sync_aud_proc_back(ctx, &ctx->aud_info, &ctx->aud_opt);
|
|
sync_check_buf_stat(ctx);
|
|
save_aud_first_play_time(ctx, opt);
|
|
|
|
out:
|
|
sync_aud_post_proc(ctx, info, opt);
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_check_pcr_valid(sync_context *ctx, td_u32 pcr_time, td_u32 stc_time)
|
|
{
|
|
td_s32 pcr_delta;
|
|
td_s32 stc_delta;
|
|
td_s32 diff_percent;
|
|
sync_pcr_info *info = &ctx->pcr_sync_info;
|
|
|
|
/* pts is invalid */
|
|
if (SYNC_INVALID_PTS == pcr_time) {
|
|
ext_info_sync("pcr_time == -1 invalid\n");
|
|
info->pcr_series_cnt = 0;
|
|
} else if (pcr_time < info->pcr_last) { /* pts go back */
|
|
ext_info_sync("pcr:%d < pcr Last %d\n", pcr_time, info->pcr_last);
|
|
info->pcr_series_cnt = 0;
|
|
} else {
|
|
pcr_delta = pcr_time - info->pcr_last;
|
|
stc_delta = stc_time - info->stc_info.stc_last;
|
|
|
|
diff_percent = (stc_delta == 0) ? 0 : ((pcr_delta - stc_delta) * PERCENT_MAX_VALUE / stc_delta);
|
|
|
|
if (diff_percent >= PCR_STC_DIFF_MAX_PERCENT) {
|
|
info->pcr_lead_series_cnt++;
|
|
info->pcr_lag_series_cnt = 0;
|
|
ext_info_sync("diff_percent:%d, pcr_lead_series_cnt:%d\n", diff_percent, info->pcr_lead_series_cnt);
|
|
} else if (diff_percent <= -1 * PCR_STC_DIFF_MAX_PERCENT) {
|
|
info->pcr_lag_series_cnt++;
|
|
info->pcr_lead_series_cnt = 0;
|
|
ext_info_sync("diff_percent:%d, pcr_lead_series_cnt:%d\n", diff_percent, info->pcr_lag_series_cnt);
|
|
} else {
|
|
info->pcr_lead_series_cnt = 0;
|
|
info->pcr_lag_series_cnt = 0;
|
|
}
|
|
|
|
/* pcr abnormal serise count more than PCR_ABNORMAL_MAX_SERIES_COUNT then change SyncRef to Aud */
|
|
if (info->pcr_lag_series_cnt >= PCR_ABNORMAL_MAX_SERIES_COUNT) {
|
|
ctx->pcr_sync_info.pcr_adjust_type = SYNC_AUD_ADJUST_SCR;
|
|
ext_warn_sync("pcr is abnormal change syncRef to aud\n");
|
|
}
|
|
|
|
/* pcr jump too much */
|
|
if ((pcr_delta > PCR_MAX_DELTA) && (diff_percent >= PCR_STC_DIFF_MAX_PERCENT)) {
|
|
ext_info_sync("pcr pcr_delta %d > PCR_MAX_DELTA %d\n", pcr_delta, PCR_MAX_DELTA);
|
|
info->pcr_series_cnt = 0;
|
|
}
|
|
}
|
|
|
|
info->is_pcr_valid = TD_FALSE;
|
|
info->pcr_series_cnt++;
|
|
|
|
if (info->pcr_series_cnt >= PTS_SERIES_COUNT) {
|
|
info->is_pcr_valid = TD_TRUE;
|
|
}
|
|
|
|
ext_info_sync("pcr is_pts_valid:%d, pcr_time:%d\n", info->is_pcr_valid, pcr_time);
|
|
return;
|
|
}
|
|
|
|
static void sync_check_pcr_loop_rewind(sync_context *ctx, td_u32 time)
|
|
{
|
|
sync_pcr_info *info = &ctx->pcr_sync_info;
|
|
|
|
if ((!info->is_pcr_valid) ||
|
|
(TD_TRUE == ctx->is_pcr_rewind) ||
|
|
(SYNC_INVALID_PTS == info->pcr_last_valid) ||
|
|
(SYNC_REF_PCR != sync_get_sync_adjust_ref_mode(ctx))) {
|
|
return;
|
|
}
|
|
|
|
if ((info->pcr_last_valid > time) &&
|
|
(info->pcr_last_valid - time > PTS_LOOPBACK_THRESHOLD)) {
|
|
if ((PCR_TIME_MAX - info->pcr_last_valid < MAX_REWIND_PTS) && (time < MAX_REWIND_PTS)) {
|
|
ext_warn_sync("pcr warps normally lastpts %d, pts %d\n", info->pcr_last_valid, time);
|
|
} else {
|
|
ctx->is_pcr_rewind = TD_TRUE;
|
|
ext_warn_sync("pcr loopback! lastpcr %d, pcr %d\n", info->pcr_last_valid, time);
|
|
}
|
|
} else if ((TD_TRUE == ctx->is_vid_rewind) &&
|
|
(TD_TRUE == ctx->is_aud_rewind)) {
|
|
if ((sync_abs(time - ctx->aud_last_valid_pts) < PTS_LOOPBACK_THRESHOLD) ||
|
|
(sync_abs(time - ctx->vid_last_valid_pts) < PTS_LOOPBACK_THRESHOLD)) {
|
|
ctx->is_pcr_rewind = TD_TRUE;
|
|
ext_warn_sync("pcr loopback! lastpcr %d, pcr %d\n", info->pcr_last_valid, time);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void sync_pcr_first_come(sync_context *ctx, td_u32 pcr_time)
|
|
{
|
|
if ((sync_check_pcr_timeout(ctx) == TD_FALSE) ||
|
|
(ctx->pcr_sync_info.pcr_sync_start_sys_time == TD_INVALID_TIME)) {
|
|
/* fisrt set pcr local time */
|
|
sync_update_pcr_local_time(ctx, (pcr_time + ctx->pcr_sync_info.pcr_delta));
|
|
ext_info_sync(">>>>pcr first set local time: %d\n", (pcr_time + ctx->pcr_sync_info.pcr_delta));
|
|
ctx->pcr_sync_info.is_pcr_adjust_delta_ok = TD_TRUE;
|
|
ctx->pcr_sync_info.pcr_adjust_type = SYNC_PCR_ADJUST_SCR;
|
|
}
|
|
|
|
/* second change is_pcr_first_come value to TD_TRUE */
|
|
ctx->pcr_sync_info.is_pcr_first_come = TD_TRUE;
|
|
ctx->pcr_sync_info.pcr_first_sys_time = sync_get_sys_time();
|
|
ctx->pcr_sync_info.pcr_first = pcr_time;
|
|
ctx->pcr_sync_info.pcr_last = pcr_time;
|
|
|
|
return;
|
|
}
|
|
|
|
static td_bool sync_check_pcr_delta(const sync_context *ctx, td_u32 pcr_time)
|
|
{
|
|
td_u32 local_time = sync_get_local_time(ctx, SYNC_CHAN_PCR);
|
|
/* keep pcr uniformly continuous when Network jitter occurs */
|
|
if ((sync_abs(local_time - pcr_time - ctx->pcr_sync_info.pcr_delta) < PCR_DELTA_THRESHOLD) &&
|
|
(ctx->pcr_sync_info.is_pcr_adjust_delta_ok)) {
|
|
return TD_FALSE;
|
|
}
|
|
|
|
return TD_TRUE;
|
|
}
|
|
|
|
void sync_pcr_proc(td_handle sync, td_u64 pcr, td_u64 stc)
|
|
{
|
|
td_u32 id = sync_get_id(sync);
|
|
sync_context *ctx = sync_info_ctx_get(id);
|
|
td_u32 pcr_delta = 0;
|
|
td_u32 time_cost;
|
|
|
|
/* PcrValue is sample with the freq of 27Mhz, but the sync module need the freq of 1khz
|
|
* so divide 27000 here
|
|
*/
|
|
td_u64 pcr_convert = osal_div_u64(pcr, SAMPLE_FREQ_DEFAULT_VALUE);
|
|
td_u64 stc_convert = osal_div_u64(stc, SAMPLE_FREQ_DEFAULT_VALUE);
|
|
td_u32 pcr_time = (td_u32)(pcr_convert & 0xffffffff);
|
|
td_u32 stc_time = (td_u32)(stc_convert & 0xffffffff);
|
|
|
|
sync_check_id_not_ret(id);
|
|
|
|
if (ctx->cur_status == SYNC_STATUS_STOP) {
|
|
return;
|
|
}
|
|
|
|
ctx->cur_pcr_val = pcr;
|
|
ctx->cur_stc_val = stc;
|
|
ctx->is_pcr_stc_changed = TD_TRUE;
|
|
|
|
/* first pcr */
|
|
if (!ctx->pcr_sync_info.is_pcr_first_come) {
|
|
sync_pcr_first_come(ctx, pcr_time);
|
|
return;
|
|
}
|
|
|
|
(void)sync_check_pcr_valid(ctx, pcr_time, stc_time);
|
|
(void)sync_check_pcr_loop_rewind(ctx, pcr_time);
|
|
|
|
ctx->pcr_sync_info.pcr_last = pcr_time;
|
|
ctx->pcr_sync_info.stc_info.stc_last = stc_time;
|
|
|
|
if (ctx->pcr_sync_info.is_pcr_valid == TD_TRUE) {
|
|
ctx->pcr_sync_info.pcr_last_valid = pcr_time;
|
|
}
|
|
|
|
if (ctx->stc_support) {
|
|
sync_stc_adjust(ctx, pcr, stc);
|
|
}
|
|
|
|
if (ctx->pcr_sync_info.is_pcr_valid == TD_TRUE) {
|
|
time_cost = sync_get_sys_time_cost(ctx->pcr_sync_info.pcr_last_sys_time);
|
|
if (time_cost != 0) {
|
|
pcr_delta = pcr_time - ctx->pcr_sync_info.pcr_last;
|
|
ctx->pcr_sync_info.pcr_gradient = pcr_delta * PERCENT_MAX_VALUE / time_cost;
|
|
}
|
|
|
|
if (ctx->pcr_sync_info.pcr_adjust_type == SYNC_PCR_ADJUST_SCR) {
|
|
if (sync_check_pcr_delta(ctx, pcr_time) == TD_FALSE) {
|
|
return;
|
|
}
|
|
|
|
sync_update_pcr_local_time(ctx, (pcr_time + ctx->pcr_sync_info.pcr_delta));
|
|
ctx->pcr_sync_info.is_pcr_adjust_delta_ok = TD_TRUE;
|
|
ext_info_sync(">>>>pcr time: %d, pcr_delta: %d \n", pcr_time, ctx->pcr_sync_info.pcr_delta);
|
|
ext_info_sync(">>>>pcr set local time: %d by pcr\n", (pcr_time + ctx->pcr_sync_info.pcr_delta));
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
td_s32 sync_hpll_conf_flag_set_print(td_bool is_conf)
|
|
{
|
|
ext_info_sync("stc not support\n");
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
#if __cplusplus
|
|
}
|
|
#endif
|
|
#endif
|