LOCAL S32 playback_search_video_with_utc(DS_HANDLE_CONTEXT *ds_context, JSON_OBJPTR obj)
{
int chnIdx, evIdx;
uint32_t start_time, end_time;
EVENT_ENTRY *elem;
U32 cid;
PLAYBACK_CLIENT_INFO *client_info;
int client_seq;
JSON_OBJPTR json_playback_obj = NULL;
JSON_OBJPTR json_array = NULL;
JSON_OBJPTR json_obj = NULL;
JSON_OBJPTR json_sub_obj = NULL;
int start_index, end_index, total_events;
char sresult_chn[32];
int result_index;
uint64_t event_type_val = 0;
uint8_t event_type_bit = 0;
uint32_t result_start_time = 0;
uint32_t result_end_time = 0;
uint16_t result_channel = 0;
const char *player_id = NULL;
int is_carry_player_id = 0;
int is_first_page = 0;
#ifdef DUAL_ALGO_ENABLE
JSON_OBJPTR dual_event_time_obj = NULL;
JSON_OBJPTR event_time_obj = NULL;
int last_event_channel = 0;
#endif
if (NULL == ds_context || NULL == obj || NULL == ds_context->res_obj)
{
return SLP_EINVARG;
}
if (!is_disk_available())
{
STM_ERROR("disk is not available.");
return ERROR_PLAYBACK_STORAGE_NOT_EXIST;
}
/* 获取请求中的所有参数,如果有参数缺失,返回参数错误 */
player_id = jso_obj_get_string_origin(obj, "player_id");
if (player_id != NULL)
{
is_carry_player_id = 1;
}
if (!is_carry_player_id)
{
/* id及player_id字段均未携带,返回参数错误 */
if (0 != jso_obj_get_int(obj, "id", (int*)&cid))
{
return ERROR_PLAYBACK_ARGS_ILLEGAL;
}
}
if (0 != jso_obj_get_int(obj, "channel", &chnIdx))
{
return ERROR_PLAYBACK_ARGS_ILLEGAL;
}
if (0 != jso_obj_get_int(obj, "start_index", &start_index))
{
return ERROR_PLAYBACK_ARGS_ILLEGAL;
}
if (0 != jso_obj_get_int(obj, "end_index", &end_index))
{
return ERROR_PLAYBACK_ARGS_ILLEGAL;
}
if (0 != jso_obj_get_int(obj, "start_time", (int*)&start_time))
{
return ERROR_PLAYBACK_ARGS_ILLEGAL;
}
if (0 != jso_obj_get_int(obj, "end_time", (int*)&end_time))
{
return ERROR_PLAYBACK_ARGS_ILLEGAL;
}
if (end_time <= start_time)
{
STM_ERROR("given time is invalid.");
return ERROR_PLAYBACK_TIME_INVALID;
}
/* 携带 player id */
if (is_carry_player_id)
{
int user_id = 0;
client_seq = client_id_str_to_seq(player_id);
if (0 == client_seq)
{
user_id = gen_client_id(0);
client_seq = client_id_to_seq(user_id);
if (0 != check_id(client_seq))
{
STM_ERROR("invalid id[%d] or seq[%d]", user_id, client_seq);
if (get_if_just_downloading())
{
return ERROR_PLAYBACK_ID_OCCUPIED;
}
return ERROR_PLAYBACK_ID_REACHLIMIT;
}
set_client_id_str(user_id, player_id);
}
STM_INFO("player_id(%s) user_id(%d)", player_id, user_id);
}
/* 携带 user id */
else
{
client_seq = client_id_to_seq(cid);
if (0 != check_id(client_seq))
{
STM_ERROR("invalid id %u.", cid);
return ERROR_PLAYBACK_ID_INVALID;
}
}
client_info = get_client_by_id(client_seq);
if (client_info == NULL)
{
STM_ERROR("invalid client info");
return ERROR_PLAYBACK_OUT_OF_RESOURCE;
}
client_info->task = TASK_PLAYBACK;
if (start_index == 0)
{
is_first_page = 1;
}
#ifndef DUAL_ALGO_ENABLE
int ret = stg_playback_load_playlist(client_seq, start_time, end_time, is_first_page);
#else
int ret = stg_playback_load_playlist(client_seq, start_time, end_time, is_first_page, chnIdx);
#endif
if (ret != OK)
{
return ret;
}
pthread_mutex_lock(&search_ev_mutex[client_seq - CLIENT_ID_MIN]);
total_events = client_info->ev_list.evlist.event_cnt;
result_index = 1;
/* 构造json串 */
if (NULL == (json_playback_obj = jso_new_obj()))
{
goto error_exit;
}
if (NULL == (json_array = jso_new_array()))
{
goto error_exit;
}
jso_obj_add(ds_context->res_obj, "playback", json_playback_obj);
jso_obj_add(json_playback_obj, "search_video_results", json_array);
for (evIdx = start_index; evIdx <= end_index; evIdx++)
{
if (evIdx >= total_events || evIdx >= EVENT_OF_DAY_MAX)
{
break;
}
elem = &(client_info->ev_list.evlist.entries[evIdx]);
result_channel = elem->channel_id;
#ifdef DUAL_ALGO_ENABLE
if ((elem->start_time < result_end_time) && (result_start_time < elem->end_time)
&& last_event_channel != (int)elem->channel_id)
{
/* 若两个事件索引的时间段有交错,且不为同一路侦测,则认为同属于一个视频片段,不新起一个json_sub_obj
仅增加start time后继续遍历 */
if (NULL == (event_time_obj = jso_new_obj()))
{
goto error_exit;
}
if (NULL == dual_event_time_obj)
{
/* 虽然正常执行dual_event_time_obj不会为空,但还是判断一下 */
continue;
}
jso_obj_add(dual_event_time_obj, (0 == result_channel) ? "1" : "2", event_time_obj);
jso_add_int64(event_time_obj, "event_start_time", elem->start_time);
event_time_obj = NULL;
}
else
#endif
{
result_start_time = (elem->start_time <= start_time) ? start_time : elem->start_time;
result_end_time = (elem->end_time >= end_time) ? end_time : elem->end_time;
#ifdef DUAL_ALGO_ENABLE
last_event_channel = (int)elem->channel_id;
#endif
if (NULL == (json_obj = jso_new_obj()))
{
goto error_exit;
}
if (NULL == (json_sub_obj = jso_new_obj()))
{
goto error_exit;
}
jso_array_add(json_array, json_obj);
memset(sresult_chn, 0, 32);
snprintf(sresult_chn, sizeof(sresult_chn), "%s_%d", "search_video_results", result_index);
jso_obj_add(json_obj, sresult_chn, json_sub_obj);
jso_add_int(json_sub_obj, "startTime", (int)result_start_time);
jso_add_int(json_sub_obj, "endTime", (int)result_end_time);
/* 为了适配类型从1开始 */
event_type_val = elem->type;
event_type_bit = 0;
while (event_type_val != 0)
{
event_type_bit++;
event_type_val = event_type_val >> 0x01;
}
if(event_type_bit > 1){
event_type_bit--;
}
/* v6版本按照video_type返回,旧版本按照之前字段vedio_type返回 */
if (is_carry_player_id)
{
if(event_type_bit == 1)
{
jso_add_string(json_sub_obj, "video_type", "1");
}
else
{
jso_add_string(json_sub_obj, "video_type", "2");
}
}
else
{
if(event_type_bit == 1)
{
jso_add_string(json_sub_obj, "vedio_type", "1");
}
else
{
jso_add_string(json_sub_obj, "vedio_type", "2");
}
}
#ifdef DUAL_ALGO_ENABLE
/* 若为多摄机型,则还需要增加每路的时间信息 */
if (NULL == (dual_event_time_obj = jso_new_obj()))
{
goto error_exit;
}
jso_obj_add(json_sub_obj, "chn_times", dual_event_time_obj);
if (NULL == (event_time_obj = jso_new_obj()))
{
goto error_exit;
}
jso_obj_add(dual_event_time_obj, (0 == result_channel) ? "1" : "2", event_time_obj);
jso_add_int64(event_time_obj, "event_start_time", result_start_time);
event_time_obj = NULL;
#endif
result_index++;
}
}
pthread_mutex_unlock(&search_ev_mutex[client_seq - CLIENT_ID_MIN]);
if ((evIdx - 1) == end_index)
{
jso_add_int(json_playback_obj, "to_be_continued", 1);
}
else
{
jso_add_int(json_playback_obj, "to_be_continued", 0);
}
#ifdef SD_RECORD_FILTER_SUPPORT
jso_add_bool(json_playback_obj, "filter_enable", TRUE);
#ifdef DUAL_ALGO_ENABLE
jso_add_bool(json_playback_obj, "filter_chn_enable", TRUE);
#endif
#endif
STM_TRACE("%s", json_object_to_json_string(ds_context->res_obj));
STM_INFO("search events done.");
return SLP_ENONE;
error_exit:
if (NULL != json_playback_obj)
{
jso_free_obj(json_playback_obj);
}
if (NULL != json_obj)
{
jso_free_obj(json_obj);
}
#ifdef DUAL_ALGO_ENABLE
if (NULL != event_time_obj)
{
jso_free_obj(event_time_obj);
}
if (NULL != dual_event_time_obj)
{
jso_free_obj(dual_event_time_obj);
}
#endif
pthread_mutex_unlock(&search_ev_mutex[client_seq - CLIENT_ID_MIN]);
return SLP_ENOMEMORY;
}
#ifndef DUAL_ALGO_ENABLE
int stg_playback_load_playlist(int client_seq, uint32_t start_time, uint32_t end_time, int is_first_page)
#else
int stg_playback_load_playlist(int client_seq, uint32_t start_time, uint32_t end_time, int is_first_page, int chn)
#endif
{
long now_time = 0;
int need_load = 0;
PLAY_LIST *play_list = NULL;
STM_SEARCH_PARAM search_param = {0};
PLAYBACK_CLIENT_INFO *client_info = NULL;
client_info = get_client_by_id(client_seq);
if (client_info == NULL)
{
STM_ERROR("invalid id %u.", client_seq);
return ERROR_PLAYBACK_ID_INVALID;
}
now_time = get_sys_uptime();
play_list = &client_info->ev_list;
pthread_mutex_lock(&search_ev_mutex[client_seq - CLIENT_ID_MIN]);
#define EVENT_LIST_UPDATE_INTERVAL 7 //事件列表更新时间频率,单位:秒
/* 是否需要加载播放列表 */
if (play_list->search_finished == FALSE
|| play_list->search_start_time != start_time
|| play_list->search_end_time != end_time
|| (play_list->last_update_time + EVENT_LIST_UPDATE_INTERVAL < now_time && is_first_page))
{
need_load = 1;
}
/* 需要加载索引 */
if (need_load)
{
search_param.disk_id = DISK_ID_ANY;
search_param.start_time = start_time;
search_param.end_time = end_time;
#ifdef DUAL_ALGO_ENABLE
search_param.channel = chn;
#endif
EVENT_BITMAP_ASSIGN(search_param.event_type, SEARCH_ANY_EVENT);
if (playback_search_events(client_seq, play_list, &search_param, STORAGE_TYPE_VIDEO, TASK_PLAYBACK) == -1)
{
pthread_mutex_unlock(&search_ev_mutex[client_seq - CLIENT_ID_MIN]);
STM_ERROR("playback_search_events fail.");
return ERROR_PLAYBACK_SEARCH_FAILED;
}
play_list->search_start_time = start_time;
play_list->search_end_time = end_time;
play_list->search_finished = TRUE;
play_list->last_update_time = now_time;
}
pthread_mutex_unlock(&search_ev_mutex[client_seq - CLIENT_ID_MIN]);
if (need_load)
{
STM_INFO("clint_seq(%d) need_load(%s) search_finished(%d) time(%u)-(%u)", client_seq, need_load?"yes":"no", play_list->search_finished, start_time, end_time);
}
return OK;
}
int playback_search_events(U32 client_id, PLAY_LIST *play_list, STM_SEARCH_PARAM *search_param, int search_type, int task)
{
if (StgDisk_IsV1())
{
return playback_search_events_v1(client_id, play_list, search_param, search_type, task);
}
int ret = playback_search_events_v2(play_list, search_param);
return ret;
}
int playback_search_events_v2(PLAY_LIST *play_list, STM_SEARCH_PARAM *search_param)
{
int ret;
StgSearchParams_S stg_param = {0};
StgSearchResult_S stg_result = {0};
if (playback_init_done == 0 || play_list == NULL)
{
return -1;
}
reset_event_list(play_list);
stg_param.search_type = eSearchType_All;
stg_param.max_nums = EVENT_OF_DAY_MAX;
stg_param.start_time = search_param->start_time;
stg_param.end_time = search_param->end_time;
#ifdef DUAL_ALGO_ENABLE
stg_param.channel = search_param->channel;
#endif
ret = StgMod_Search(&stg_param, &stg_result);
if (ret != 0)
{
STM_ERROR("search fail!");
return -1;
}
if (stg_result.nums == 0 || stg_result.buf == NULL)
{
goto search_finish;
}
EVENT_LIST *ev_list = &play_list->evlist;
ev_list->entries = (EVENT_ENTRY *)stg_result.buf;
ev_list->total_event_cnt = stg_result.nums;
ev_list->event_cnt = stg_result.nums;
search_finish:
play_list->search_finished = TRUE;
STM_INFO("search_range(%u-%u) total(%d) det(%d) tim(%d)", stg_param.start_time, stg_param.end_time, stg_result.nums, stg_result.det_nums, stg_result.tim_nums);
return 0;
}
int StgMod_Search(StgSearchParams_S *param, StgSearchResult_S *result)
{
int ret = 0;
int need_reload = 0;
if (param == NULL || result == NULL)
{
return -1;
}
if (param->start_time <= 0 || param->start_time >= param->end_time || (param->end_time - param->start_time >= SNAPSHOT_SEARCH_MAX_TIMESPAN))
{
return -1;
}
//上锁
pthread_mutex_lock(&g_search_lock);
if (!g_search_buf.is_init || param->start_time != g_search_buf.start_time || param->end_time != g_search_buf.end_time)
{
need_reload = 1;
}
uint32_t uptime_s = stg_sys_uptime_s();
if (g_search_buf.last_update_time + 10 < uptime_s && (param->search_type == eSearchType_All || (param->indx_start == 0 && param->search_type == eSearchType_Det)))
{
need_reload = 1;
}
if (need_reload)
{
StgDisk_RefcntAdd();
ret = StgSearchBuf_Load(param->start_time, param->end_time);
StgDisk_RefcntDec();
if (ret != 0)
{
STM_ERROR("StgSearchBuf_Load fail");
goto exit;
}
}
int event_nums = 0;
int buf_size = 0;
if (param->search_type == eSearchType_All)
{
event_nums = g_search_buf.total_nums;
buf_size = event_nums * sizeof(EVENT_ENTRY);
}
else if (param->search_type == eSearchType_Tim)
{
event_nums = g_search_buf.tim_nums;
buf_size = event_nums * sizeof(EventEntry_S);
}
else
{
event_nums = (param->indx_end - param->indx_start + 1);
if (event_nums > g_search_buf.det_nums)
{
event_nums = g_search_buf.det_nums;
}
buf_size = event_nums * sizeof(EventEntry_S);
}
STM_INFO("search_type(%d) event_nums(%d) buf_size(%d)", param->search_type, event_nums, buf_size);
memset(result, 0, sizeof(StgSearchResult_S));
if (event_nums == 0)
{
ret = 0;
goto exit;
}
void *event_buf = malloc(buf_size);
if (event_buf == NULL)
{
ret = -1;
STM_ERROR("malloc fail");
goto exit;
}
memset(event_buf, 0, buf_size);
result->total_nums = 0;
result->det_nums = 0;
result->nums = 0;
int i;
int idx = 0;
int idx_start = 0;
int result_nums = 0;
EventEntry_S *ev_src;
for (i = 0; i < g_search_buf.total_nums; i++)
{
idx = i;
if (param->indx_order)
{
idx = g_search_buf.total_nums - i - 1;
}
if (idx >= g_search_buf.total_nums)
{
break;
}
ev_src = &g_search_buf.event_buf[idx];
#ifdef DUAL_ALGO_ENABLE
/* 设备本地存储时,chn以0,1保存,但云端下发按照1,2下发,0表示全都要
所以此处判断非0 & 通道号是否不匹配*/
if ((0 != param->channel) && ((param->channel - 1) != ev_src->channel_id))
{
continue;
}
#endif
// 1.eSearchType_All
if (param->search_type == eSearchType_All)
{
EVENT_ENTRY *ev_dst = (EVENT_ENTRY *)event_buf + result_nums;
event_transform(ev_src, ev_dst);
result_nums++;
continue;
}
// 2.eSearchType_Tim
if (param->search_type == eSearchType_Tim)
{
if (ev_src->event_flag == eEventType_Tim)
{
memcpy(event_buf + result_nums*sizeof(EventEntry_S), ev_src, sizeof(EventEntry_S));
result_nums++;
}
continue;
}
// 3.eSearchType_Det
if (ev_src->event_flag == eEventType_Det)
{
if (idx_start >= param->indx_start)
{ // 录像事件转为侦测事件
memcpy(event_buf + result_nums*sizeof(EventEntry_S), ev_src, sizeof(EventEntry_S));
result_nums++;
}
idx_start++;
if (idx_start > param->indx_end || result_nums >= event_nums)
{
break;
}
}
}
result->search_type = param->search_type;
result->total_nums = g_search_buf.total_nums;
result->tim_nums = g_search_buf.tim_nums;
result->det_nums = g_search_buf.det_nums;
result->max_nums = event_nums;
result->nums = result_nums;
if (result_nums == 0)
{
result->buf = NULL;
free(event_buf);
}
else
{
result->buf = event_buf;
}
exit:
//解锁
pthread_mutex_unlock(&g_search_lock);
return ret;
}
static int StgSearchBuf_Load(uint32_t start_time, uint32_t end_time)
{
int ret;
IndxMemSearch_S search;
StgSearchBuf_Free();
#ifdef DUAL_ALGO_ENABLE
/* 枪球机型每日的事件上限为 ((24*60*60) / 60) * 2 = 2880,故需要提高事件上限以免加载时丢失 */
if (IndxMemSearch_Init(&search, 2880) != 0)
#else
if (IndxMemSearch_Init(&search, 2048) != 0)
#endif
{
STM_ERROR("init search buf fail!");
return -1;
}
ret = IndxMemSearch_Load(&g_mem_idx, &search, start_time, end_time);
if (ret != 0)
{
STM_ERROR("Load search buf fail!");
goto exit;
}
if (search.nums == 0)
{
STM_INFO("search nums = 0!");
goto exit;
}
StgSearchBuf_S *sbuf = &g_search_buf;
sbuf->event_buf = (EventEntry_S *)malloc(search.nums * sizeof(EventEntry_S));
if (sbuf->event_buf == NULL)
{
STM_ERROR("malloc fail");
ret = -1;
goto exit;
}
int i;
EventNode_S *head = search.head;
for (i = 0; i < search.nums; i++)
{
if (head == NULL)
{
break;
}
EventEntry_S *ev = &sbuf->event_buf[sbuf->total_nums];
memcpy(ev, &head->event, sizeof(EventEntry_S));
sbuf->total_nums += 1;
if (ev->event_flag)
{
sbuf->tim_nums += 1;
}
else
{
sbuf->det_nums += 1;
}
head = head->next;
}
sbuf->start_time = start_time;
sbuf->end_time = end_time;
sbuf->last_update_time = stg_sys_uptime_s();
sbuf->is_init = 1;
STM_INFO("search range(%u-%u) total(%u) det(%u) tim(%u)", sbuf->start_time, sbuf->end_time, sbuf->total_nums, sbuf->det_nums, sbuf->tim_nums);
exit:
IndxMemSearch_DeInit(&search);
return ret;
}
static int IndxMemSearch_Load(MemIdx_S *mem_idx, IndxMemSearch_S *search, uint32_t start_time, uint32_t end_time)
{
int ret;
int i;
int fd = -1;
int file_id;
MemFile_S mem_file;
EventEntry_S *event_buf = NULL;
if (mem_idx == NULL || search == NULL || start_time >= end_time)
{
return -1;
}
if (!mem_idx->is_valid || !search->is_init)
{
STM_ERROR("memory index is not init!");
return -1;
}
/* 读数据在另外线程执行,重新打开文件 */
for (i = 0; i < 2; i++)
{
fd = Sys01Index_Open(i, O_RDONLY);
if (fd != -1)
{
break;
}
}
if (fd == -1)
{
STM_ERROR("can't open fd!");
return -1;
}
event_buf = (EventEntry_S *)malloc(mem_idx->file_entrys * sizeof(EventEntry_S));
if (event_buf == NULL)
{
close(fd);
STM_ERROR("malloc fail!");
return -1;
}
// 更新
search->nums = 0;
search->start_time = start_time;
search->end_time = end_time;
for (file_id = 0; file_id < mem_idx->file_nums; file_id++)
{
memcpy(&mem_file, &mem_idx->mem_files[file_id], sizeof(MemFile_S));
if (!mem_file.is_used || mem_file.event_nums <= 0)
{
continue;
}
if (mem_file.event_nums > mem_idx->file_entrys)
{
STM_ERROR("file_id(%d) event nums(%d) more than %d", file_id, mem_file.event_nums, mem_idx->file_entrys);
continue;
}
// 检索时间是否在范围内
if (mem_file.time_end <= start_time || mem_file.time_start >= end_time)
{
continue;
}
/* 加载文件事件 */
int file_pos = file_id * mem_idx->file_entrys;
ret = Sys01Index_Read(fd, file_pos, mem_file.event_nums, event_buf);
if (ret != 0)
{
STM_ERROR("read file_id(%d) fail!", file_id);
break;
}
// 处理读取的数据
for (i = 0; i < mem_file.event_nums; i++)
{
EventEntry_S *event = &event_buf[i];
// 检查事件时间是否在范围内
if (event->end_time <= start_time || event->start_time >= end_time)
{
continue;
}
IndxMemSearch_Add(search, event);
}
}
if (fd != -1)
{
close(fd);
}
if (event_buf)
{
free(event_buf);
}
STM_INFO("search range(%u -> %u) total_events(%d)", search->start_time, search->end_time, search->nums);
return 0;
}
分析一下上面代码的功能,给出流程图