#include "stdafx.h" #include #include "SpBase.h" #include "video_session.h" #include "videoframework.h" #include "memutil.h" #include #include "videohorflip.h" #include "opencv2/opencv.hpp" #include "highgui.h" #include "y2k_time.h" #include "Event.h" #ifndef av_always_inline #define av_always_inline __inline #endif #ifndef inline #define inline __inline #endif #ifndef INT64_C #define INT64_C(c) (c##LL) #define UINT64_C(c) (c##UL) #endif extern "C"{ #include #include #include } #include "video_common/ffmpeg_api_cpp_adapter.h" #include #pragma comment(lib, "dbghelp.lib") HWND pg_local_hwnd = NULL; // preview window HWND pg_remote_hwnd = NULL; // remote window void* pg_local_render = NULL; // local render void* pg_remote_render = NULL; // remote render video_session_t* pg_last_session = NULL; // last used session #define WNDCLS_NAME "sipmedia_video" #ifndef MAX_PATH #define MAX_PATH 260 #endif static void __dbg(void *user_data, const char *fmt, va_list arg) { int n = _vsnprintf(NULL, 0, fmt, arg); if (n >= MAX_LOG_LEN) { char* buf = (char*)malloc((size_t)(n + 1)); _vsnprintf(buf, n + 1, fmt, arg); DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("%s", buf); free(buf); } else{ char strlog[MAX_LOG_LEN] = {0}; _vsnprintf(strlog, MAX_LOG_LEN, fmt, arg); DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("%s", strlog); } } static void __logevent(void* user_data, int itype, const char* strmessage) { if (0 == itype) { LogWarn(Severity_Low, Error_Debug, EVENT_MOD_SIP_VIDEO_RTP_CREATE, strmessage); } else { LogWarn(Severity_Low, Error_Debug, EVENT_MOD_SIP_VIDEO_RTP_DESTROY, strmessage); } } static bool __camera_error_event(bool bhaspost, int icameraid) { bool bret = false; if (false == bhaspost){ if (0 == icameraid){ LogWarn(Severity_Middle, Error_Debug, ERROR_MOD_SIP_GET_ENV_VIDEO_FAILED, "get video from env queue failed!"); } else{ LogWarn(Severity_Middle, Error_Debug, ERROR_MOD_SIP_GET_OPT_VIDEO_FAILED, "get video from opt queue failed!"); } LogEvent(Severity_Middle, EVENT_MOD_SIP_GET_VIDEO_FAILED, "connected and get video failed!"); DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM).setResultCode("RTA3119")("接通坐席后本地视频回显异常"); bret = true; } return bret; } static int translate_image_resolution(video_frame** dstframe,const int iwidth, const int iheight, const video_frame* psrcframe) { int i = -1; if (iwidth == psrcframe->width && iheight == psrcframe->height){ return i; } video_frame* pframe = video_frame_new(iwidth, iheight,VIDEO_FORMAT_RGB24); video_frame_fill_black(pframe); SwsContext* sws = sws_getCachedContext(NULL, psrcframe->width, psrcframe->height, PIX_FMT_BGR24, iwidth, iheight, PIX_FMT_BGR24, SWS_LANCZOS, NULL, NULL, NULL); sws_scale(sws, psrcframe->data, psrcframe->linesize, 0, psrcframe->height, pframe->data, pframe->linesize); sws_freeContext(sws); *dstframe = pframe; i = 0; return i; } static int calc_capture_mode(int width, int height, int *mode) { const struct { int mode; int width; int height; } modes [] = { {VIDEOCAP_FRAME_SQCIF, VIDEOCAP_SQCIF_WIDTH, VIDEOCAP_SQCIF_HEIGHT}, {VIDEOCAP_FRAME_QQVGA, VIDEOCAP_QQVGA_WIDTH, VIDEOCAP_QQVGA_HEIGHT}, {VIDEOCAP_FRAME_QCIF, VIDEOCAP_QCIF_WIDTH, VIDEOCAP_QCIF_HEIGHT}, {VIDEOCAP_FRAME_QVGA, VIDEOCAP_QVGA_WIDTH, VIDEOCAP_QVGA_HEIGHT}, {VIDEOCAP_FRAME_CIF, VIDEOCAP_CIF_WIDTH, VIDEOCAP_CIF_HEIGHT}, {VIDEOCAP_FRAME_VGA, VIDEOCAP_VGA_WIDTH, VIDEOCAP_VGA_HEIGHT}, {VIDEOCAP_FRAME_4CIF, VIDEOCAP_4CIF_WIDTH, VIDEOCAP_4CIF_HEIGHT}, {VIDEOCAP_FRAME_SVGA, VIDEOCAP_SVGA_WIDTH, VIDEOCAP_SVGA_HEIGHT}, {VIDEOCAP_FRAME_NHD, VIDEOCAP_NHD_WIDTH, VIDEOCAP_NHD_HEIGHT}, {VIDEOCAP_FRAME_SXGA, VIDEOCAP_SXGA_WIDTH, VIDEOCAP_SXGA_HEIGHT}, {VIDEOCAP_FRAME_720P, VIDEOCAP_720P_WIDTH, VIDEOCAP_720P_HEIGHT}, {VIDEOCAP_FRAME_1080P, VIDEOCAP_1080P_WIDTH, VIDEOCAP_1080P_HEIGHT}, }; int i; for (i = 0; i < array_size(modes); ++i) { if (modes[i].width == width && modes[i].height == height) { *mode = modes[i].mode; return 0; } } return Error_NotExist; } #ifdef RVC_OS_WIN static void __delete_frame(videoplayer_t *player, void *user_data, video_frame *frame) { video_frame_delete(frame); } #endif static int video_shm_enqueue(Clibvideoqueue *shm_queue, video_frame *frame, int flags, int iframeid) { videoq_frame tmp_frm; tmp_frm.data = frame->data[0]; tmp_frm.framesize = frame->width * frame->height * 3; tmp_frm.format = VIDEOQ_FORMAT_RGB24; tmp_frm.width = frame->width; tmp_frm.height = frame->height; tmp_frm.iframeid = iframeid; unsigned int nowtime = y2k_time_now(); if (!shm_queue->InsertVideo(&tmp_frm, flags,nowtime)) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("caution: shm_queue video insert shm video failed!"); return Error_Unexpect; } else { return Error_Succeed; } } static inline Clibvideoqueue *get_active_videoqueue(video_session_t *session) { int agent_option = *session->conf.ref_camera_switch; int facetracking_option = *session->conf.ref_active_camera; int camera_state = *session->conf.ref_camera_state; Clibvideoqueue *active = NULL; if (agent_option == CAMERA_TYPE_ENV) { if((camera_state!=CAMERA_TYPE_ENV)&&(camera_state!=CAMERA_TYPE_AUTO)) { active = NULL; } else { active = session->video_shm_q_env; } } else if (agent_option == CAMERA_TYPE_OPT) { if((camera_state!=CAMERA_TYPE_OPT)&&(camera_state!=CAMERA_TYPE_AUTO)) { active = NULL; } else { active = session->video_shm_q_opt; } } else if(agent_option == CAMERA_TYPE_ERROR) { active = NULL; } else { // auto if (camera_state == CAMERA_TYPE_AUTO) { if (facetracking_option == CAMERA_TYPE_ENV) { active = session->video_shm_q_env; } else { // opt active = session->video_shm_q_opt; } } else if (camera_state == CAMERA_TYPE_ENV) { active = session->video_shm_q_env; } else if (camera_state == CAMERA_TYPE_OPT) { active = session->video_shm_q_opt; } else if (camera_state == CAMERA_TYPE_ERROR) { active = NULL; } } return active; } static void local_get_frame(void *user_data, video_frame *frame) { video_session_t *session = (video_session_t*)user_data; Clibvideoqueue *q = get_active_videoqueue(session); if (q) { videoq_frame frm; frm.data = frame->data[0]; if (q->GetVideo(&frm, 0)) { //video_frame_fill_black(frame); frame->width = frm.width; frame->height = frm.height; frame->linesize[0] = frm.width * 3; } } else { //video_frame_fill_black(frame); //贴图 DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("get active cam is null, load error img."); if (session->video_error != NULL) { frame->width = session->video_error->width; frame->height = session->video_error->height; frame->linesize[0] = session->video_error->width * 3; memcpy(frame->data[0],session->video_error->data,frame->width*frame->height*3); } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("video error img is null"); } } } static void local_put_frame(void *user_data, video_frame *frame) { video_session_t *session = (video_session_t*)user_data; video_frame *tmp_frame_encode = NULL; int rc; // send out { tmp_frame_encode = video_frame_new(REC_COMMON_VIDEO_RTP_WIDTH, REC_COMMON_VIDEO_RTP_HEIGHT, VIDEO_FORMAT_I420); video_frame_fill_black(tmp_frame_encode); if (frame->width == REC_COMMON_VIDEO_RTP_ENV_WIDTH && frame->height == REC_COMMON_VIDEO_RTP_ENV_HEIGHT) { // env int offset = (REC_COMMON_VIDEO_RTP_HEIGHT - REC_COMMON_VIDEO_RTP_ENV_HEIGHT) / 2; unsigned char *dst_data[4] = {tmp_frame_encode->data[0], tmp_frame_encode->data[1], tmp_frame_encode->data[2], NULL}; dst_data[0] += offset * tmp_frame_encode->linesize[0]; dst_data[1] += offset / 2 * tmp_frame_encode->linesize[1]; dst_data[2] += offset / 2 * tmp_frame_encode->linesize[2]; sws_scale(session->local_encode_sws_ctx_env, frame->data, frame->linesize, 0, frame->height, dst_data, tmp_frame_encode->linesize); } else if (frame->width == REC_COMMON_VIDEO_RTP_OPT_WIDTH && frame->height == REC_COMMON_VIDEO_RTP_OPT_HEIGHT) { // opt video_frame tt; video_frame_alloc(REC_COMMON_VIDEO_RTP_WIDTH, REC_COMMON_VIDEO_RTP_HEIGHT, VIDEO_FORMAT_RGB24, &tt); video_frame_fill_black(&tt); { int offset = (REC_COMMON_VIDEO_RTP_WIDTH - REC_COMMON_VIDEO_RTP_OPT_WIDTH) / 2; unsigned char *dst_data[4] = {tt.data[0], 0, 0, 0}; dst_data[0] += offset * 3; IppiSize size; size.width = frame->width; size.height = frame->height; ippiCopy_8u_C3R(frame->data[0], frame->linesize[0], tt.data[0] + offset * 3, tt.linesize[0], size); } sws_scale(session->local_encode_sws_ctx_opt, tt.data, tt.linesize, 0, tt.height, tmp_frame_encode->data, tmp_frame_encode->linesize); video_frame_free(&tt); } if (session->conf.local_pt == REC_COMMON_VIDEO_PT) { videortp_send_frame(session->rtp, tmp_frame_encode); } else { videortp_send_yuvframe(session->rtp, tmp_frame_encode); } } on_error: if (tmp_frame_encode) { video_frame_delete(tmp_frame_encode); } } static int on_rx_frame(video_frame *frame, void *user_data) { video_session_t *session = (video_session_t *)user_data; int used = 0; session->irecv_frameid++; if (eGDI == session->conf.eType) { if (session->remote_player) { if(DOUBLERECORD_CALLTYPE == session->conf.nCallType){ if (eStand2sType == session->conf.eDeviceType){ //大机对远端视频进行缩放匹配 video_frame* recordframe = NULL; if(0 == translate_image_resolution(&recordframe,/*REC_COMMON_VIDEO_SSM_AGENT_WIDTH*/REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_WIDTH,/*REC_COMMON_VIDEO_SSM_AGENT_HEIGHT*/REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_HEIGHT,frame)){ int rc = video_shm_enqueue(session->video_shm_q_remote, recordframe, VIDEOQUEUE_FLAG_VERTICAL_FLIP, session->irecv_frameid); if (rc != Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("eStand2sType record call mod insert remote video to queue failed!"); } video_frame_delete(recordframe); } recordframe = NULL; } else{ int rc = video_shm_enqueue(session->video_shm_q_remote, frame, VIDEOQUEUE_FLAG_VERTICAL_FLIP, session->irecv_frameid); if (rc != Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("not eStand2sType record call mod insert remote video to queue failed!"); } } } int rc = videoplayer_queue_frame(session->remote_player, frame, &__delete_frame, NULL); if (rc == 0) { used = 1; } } } else{ if (DOUBLERECORD_CALLTYPE == session->conf.nCallType) { if (eStand2sType == session->conf.eDeviceType) { video_frame* recordframe = NULL; if (0 == translate_image_resolution(&recordframe, REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_WIDTH, REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_HEIGHT, frame)) { int rc = video_shm_enqueue(session->video_shm_q_remote, recordframe, VIDEOQUEUE_FLAG_VERTICAL_FLIP, session->irecv_frameid); if (rc != Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("eStand2sType record call mod insert remote video to queue failed."); } video_frame_delete(recordframe); recordframe = NULL; } } else { int rc = video_shm_enqueue(session->video_shm_q_remote, frame, VIDEOQUEUE_FLAG_VERTICAL_FLIP, session->irecv_frameid); if (rc != Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("not eStand2sType record call mod insert remote video to queue failed."); } } } if (NULL != session->premote_render){ //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("session plocal_render RenderVideoFrame"); video_frame* echoframe = NULL; if (0 == translate_image_resolution(&echoframe,session->conf.remote_video_view_cx,session->conf.remote_video_view_cy, frame)) { session->premote_render->RenderVideoFrame(echoframe, RVC_FLIP_VERTICAL); session->bshow_remote = true; video_frame_delete(echoframe); echoframe = NULL; } else { session->premote_render->RenderVideoFrame(frame, RVC_FLIP_VERTICAL); session->bshow_remote = true; } used = 1; } } return used; } int GetCurrentRunPath(char* pPath) { char* pBuf = new char[MAX_PATH]; if (pBuf == NULL) return -1; ZeroMemory(pBuf, MAX_PATH); GetModuleFileName(NULL, pBuf, MAX_PATH); int len = strnlen_s(pBuf, MAX_PATH); if (len <= 0) { delete[]pBuf; return -2; } char* pch; pch = strstr(pBuf, "bin"); if (pch == NULL) return -3; int lenDel = strnlen_s(pch, MAX_PATH); if (len <= 0) { delete[]pBuf; return -3; } strncpy_s(pPath, MAX_PATH, pBuf, len - lenDel); delete[]pBuf; return strnlen_s(pPath, MAX_PATH); } //远端视频窗口状态回调 static int on_remoteWinstate(videoplayer_t *player, void *user_data, video_frame **frame) { video_session_t *session = (video_session_t*)user_data; return *session->conf.ref_window_state ; } //本地回显回调 static int on_pull(videoplayer_t *player, void *user_data, video_frame **frame) { video_session_t *session = (video_session_t*)user_data; video_frame *tmp_frame_preview; int iflags = 0; //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("ref_active_img %d,ref_Is_ActiveInspect %d,ref_camera_switch %d",*session->conf.ref_active_img,*session->conf.ref_Is_ActiveInspect,*session->conf.ref_camera_switch); if((session->conf.ref_active_img == NULL)&&(session->conf.ref_Is_ActiveInspect == NULL)) { tmp_frame_preview = video_frame_new(REC_COMMON_VIDEO_PREVIEW_WIDTH, REC_COMMON_VIDEO_PREVIEW_HEIGHT, VIDEO_FORMAT_RGB24); videoq_frame frm; frm.data = tmp_frame_preview->data[0]; bool result = session->video_shm_q_preview->GetVideo(&frm, iflags); //人形框融合处理 if (result&&session->personimage!=NULL&&session->personmask!=NULL&&*session->conf.ref_Is_showPersonArea==1) { IplImage*img = cvCreateImageHeader(cvSize(frm.width,frm.height),IPL_DEPTH_8U,3); img->imageData = (char*)frm.data; if (frm.width!=session->personimage->width) { IplImage*tmp = cvCreateImage(cvSize(frm.width,frm.height),IPL_DEPTH_8U,3); IplImage*tmpmask = cvCreateImage(cvSize(frm.width,frm.height),IPL_DEPTH_8U,1); cvResize(session->personimage,tmp); cvResize(session->personmask,tmpmask); cvAdd(img,tmp,img,tmpmask); cvReleaseImage(&tmp); cvReleaseImage(&tmpmask); } else { cvAdd(img,session->personimage,img,session->personmask); } cvReleaseImageHeader(&img); } if (!result){ if (__camera_error_event(session->bcamera_error_posted, 0)){ session->bcamera_error_posted = true; } } } else { if (*session->conf.ref_active_img == 1) { tmp_frame_preview = video_frame_new(REC_COMMON_VIDEO_SNAPSHOT_WIDTH, REC_COMMON_VIDEO_SNAPSHOT_WIDTH, VIDEO_FORMAT_RGB24); video_frame_fill_black(tmp_frame_preview); if (session->video_error == NULL) { char strPath[MAX_PATH] = {0}; GetCurrentRunPath(strPath); _snprintf(strPath, MAX_PATH, "%s\\bin\\looklowerscreen.jpg", strPath); if (_access(strPath,0)!=-1) { IplImage*img = cvLoadImage(strPath,1); if (img != NULL) { session->video_error = new videoq_frame; session->video_error->format = VIDEOQ_FORMAT_RGB24; session->video_error->framesize = img->imageSize; session->video_error->height = img->width; session->video_error->width = img->height; session->video_error->data = new unsigned char[img->imageSize]; memcpy(session->video_error->data,img->imageData,img->imageSize); cvReleaseImage(&img); } } } if (session->video_error != NULL) { SwsContext*sws = sws_getContext(session->video_error->width, session->video_error->height,PIX_FMT_BGR24, REC_COMMON_VIDEO_SNAPSHOT_WIDTH, REC_COMMON_VIDEO_SNAPSHOT_WIDTH, PIX_FMT_BGR24, SWS_POINT, NULL, NULL, NULL); uint8_t *src_data[4] = {(unsigned char*)session->video_error->data+(session->video_error->height-1)*session->video_error->width*3,NULL,NULL,NULL}; int src_linesize[4] = {-session->video_error->width*3,0,0,0}; unsigned char *dst[4] = {tmp_frame_preview->data[0],NULL,NULL,NULL}; int dst_linesize[4] = {tmp_frame_preview->linesize[0],0,0,0}; sws_scale(sws, src_data, src_linesize, 0, session->video_error->height, dst, dst_linesize); sws_freeContext(sws); } } else if (*session->conf.ref_Is_ActiveInspect == 1) { tmp_frame_preview = video_frame_new(REC_COMMON_VIDEO_SNAPSHOT_WIDTH, REC_COMMON_VIDEO_SNAPSHOT_WIDTH, VIDEO_FORMAT_RGB24); video_frame_fill_black(tmp_frame_preview); if ((*session->conf.ref_camera_switch == CAMERA_TYPE_ENV)||(*session->conf.ref_camera_switch == CAMERA_TYPE_AUTO))//显示上摄像头 { if (session->video_shm_q_env) { videoq_frame frm; int offset = (REC_COMMON_VIDEO_SNAPSHOT_WIDTH - REC_COMMON_VIDEO_SNAPSHOT_HEIGHT) / 2; frm.data = tmp_frame_preview->data[0] + offset * tmp_frame_preview->linesize[0]; if (false == session->video_shm_q_env->GetVideo(&frm, VIDEOQUEUE_FLAG_VERTICAL_FLIP)){ session->bcamera_error_posted = true; } } } else if (*session->conf.ref_camera_switch == CAMERA_TYPE_OPT)//显示下摄像头 { if (session->video_shm_q_opt) { video_frame tt = {0}; int offset = (REC_COMMON_VIDEO_SNAPSHOT_WIDTH-REC_COMMON_VIDEO_SNAPSHOT_HEIGHT) / 2; tt.data[0] = tmp_frame_preview->data[0] + offset *3; tt.format = tmp_frame_preview->format; tt.linesize[0] = tmp_frame_preview->linesize[0]; tt.width = REC_COMMON_VIDEO_SNAPSHOT_HEIGHT; tt.height = REC_COMMON_VIDEO_SNAPSHOT_WIDTH; if (false == session->video_shm_q_opt->GetVideo2(&tt, VIDEOQUEUE_FLAG_VERTICAL_FLIP)){ if (__camera_error_event(session->bcamera_error_posted, 1)){ session->bcamera_error_posted = true; } } } } } else { int iwidth = REC_COMMON_VIDEO_PREVIEW_WIDTH; int iheight = REC_COMMON_VIDEO_PREVIEW_HEIGHT; session->video_shm_q_preview->GetFrameSize(iwidth, iheight); tmp_frame_preview = video_frame_new(iwidth, iheight, VIDEO_FORMAT_RGB24); videoq_frame frm; frm.data = tmp_frame_preview->data[0]; bool result = session->video_shm_q_preview->GetVideo(&frm, iflags); //人形框融合处理 if (result&&session->personimage!=NULL&&session->personmask!=NULL&&*session->conf.ref_Is_showPersonArea==1) { IplImage*img = cvCreateImageHeader(cvSize(frm.width,frm.height),IPL_DEPTH_8U,3); img->imageData = (char*)frm.data; if (frm.width!=session->personimage->width) { IplImage*tmp = cvCreateImage(cvSize(frm.width,frm.height),IPL_DEPTH_8U,3); IplImage*tmpmask = cvCreateImage(cvSize(frm.width,frm.height),IPL_DEPTH_8U,1); cvResize(session->personimage,tmp); cvResize(session->personmask,tmpmask); cvAdd(img,tmp,img,tmpmask); cvReleaseImage(&tmp); cvReleaseImage(&tmpmask); } else { cvAdd(img,session->personimage,img,session->personmask); } cvReleaseImageHeader(&img); } if (!result){ if (__camera_error_event(session->bcamera_error_posted, 0)){ session->bcamera_error_posted = true; } } } } *frame = tmp_frame_preview; return *session->conf.ref_window_state; } static void free_frame(videoplayer_t *player, void *user_data, video_frame *frame) { video_frame_delete(frame); } //视频窗口显示状态,0:正常大小显示,1:放大一倍显示,2:隐藏全部窗口,3:从隐藏状态恢复为全部显示,4:显示远程窗口,隐藏本地窗口, 5:缩放显示 int set_video_windows(video_session_t* psession, int iwindowstate) { int iret = -1; if (NULL == psession){ return iret; } if (2 == iwindowstate){ psession->plocal_render->HideVideoWindow(); psession->premote_render->HideVideoWindow(); iret = 0; } else if (3 == iwindowstate){ psession->plocal_render->ShowVideoWindow(); psession->premote_render->HideVideoWindow(); psession->premote_render->ShowVideoWindow(); iret = 0; } else if (4 == iwindowstate) { psession->plocal_render->HideVideoWindow(); iret = 0; } return iret; } //本地回显回调 static int get_local_video_frame(void* user_data, video_frame** frame) { video_session_t* session = (video_session_t*)user_data; video_frame* tmp_frame_preview = NULL; //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("ref_active_img %d,ref_Is_ActiveInspect %d,ref_camera_switch %d",*session->conf.ref_active_img,*session->conf.ref_Is_ActiveInspect,*session->conf.ref_camera_switch); if ((session->conf.ref_active_img == NULL) && (session->conf.ref_Is_ActiveInspect == NULL)) { tmp_frame_preview = video_frame_new(REC_COMMON_VIDEO_PREVIEW_WIDTH, REC_COMMON_VIDEO_PREVIEW_HEIGHT, VIDEO_FORMAT_RGB24); videoq_frame frm; frm.data = tmp_frame_preview->data[0]; bool result = session->video_shm_q_preview->GetVideo(&frm, VIDEOQUEUE_FLAG_HORIZONTAL_FLIP); //人形框融合处理 if (result){ if (session->personimage != NULL && session->personmask != NULL && *session->conf.ref_Is_showPersonArea == 1) { IplImage* img = cvCreateImageHeader(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 3); img->imageData = (char*)frm.data; if (frm.width != session->personimage->width){ IplImage* tmp = cvCreateImage(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 3); IplImage* tmpmask = cvCreateImage(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 1); cvResize(session->personimage, tmp); cvResize(session->personmask, tmpmask); cvAdd(img, tmp, img, tmpmask); cvReleaseImage(&tmp); cvReleaseImage(&tmpmask); } else{ cvAdd(img, session->personimage, img, session->personmask); } cvReleaseImageHeader(&img); } } else { video_frame_fill_black(tmp_frame_preview); } } else { if (*session->conf.ref_active_img == 1) { tmp_frame_preview = video_frame_new(REC_COMMON_VIDEO_SNAPSHOT_WIDTH, REC_COMMON_VIDEO_SNAPSHOT_WIDTH, VIDEO_FORMAT_RGB24); video_frame_fill_black(tmp_frame_preview); if (session->video_error == NULL) { char strPath[MAX_PATH] = { 0 }; _snprintf(strPath, MAX_PATH, "%s", "./bin/looklowerscreen.jpg"); if (-1 != _access(strPath,0)) { IplImage* img = cvLoadImage(strPath, 1); if (img != NULL) { session->video_error = new videoq_frame; session->video_error->format = VIDEOQ_FORMAT_RGB24; session->video_error->framesize = img->imageSize; session->video_error->height = img->width; session->video_error->width = img->height; session->video_error->data = new unsigned char[img->imageSize]; memcpy(session->video_error->data, img->imageData, img->imageSize); cvReleaseImage(&img); } } } if (session->video_error != NULL) { SwsContext* sws = sws_getContext(session->video_error->width, session->video_error->height, PIX_FMT_BGR24, REC_COMMON_VIDEO_SNAPSHOT_WIDTH, REC_COMMON_VIDEO_SNAPSHOT_WIDTH, PIX_FMT_BGR24, SWS_POINT, NULL, NULL, NULL); uint8_t* src_data[4] = { (unsigned char*)session->video_error->data + (session->video_error->height - 1) * session->video_error->width * 3,NULL,NULL,NULL }; int src_linesize[4] = { -session->video_error->width * 3,0,0,0 }; unsigned char* dst[4] = { tmp_frame_preview->data[0],NULL,NULL,NULL }; int dst_linesize[4] = { tmp_frame_preview->linesize[0],0,0,0 }; sws_scale(sws, src_data, src_linesize, 0, session->video_error->height, dst, dst_linesize); sws_freeContext(sws); } } else if (*session->conf.ref_Is_ActiveInspect == 1) { tmp_frame_preview = video_frame_new(REC_COMMON_VIDEO_SNAPSHOT_WIDTH, REC_COMMON_VIDEO_SNAPSHOT_WIDTH, VIDEO_FORMAT_RGB24); video_frame_fill_black(tmp_frame_preview); if ((*session->conf.ref_camera_switch == CAMERA_TYPE_ENV) || (*session->conf.ref_camera_switch == CAMERA_TYPE_AUTO))//显示上摄像头 { if (session->video_shm_q_env) { videoq_frame frm; int offset = (REC_COMMON_VIDEO_SNAPSHOT_WIDTH - REC_COMMON_VIDEO_SNAPSHOT_HEIGHT) / 2; frm.data = tmp_frame_preview->data[0] + offset * tmp_frame_preview->linesize[0]; session->video_shm_q_env->GetVideo(&frm, VIDEOQUEUE_FLAG_VERTICAL_FLIP); } } else if (*session->conf.ref_camera_switch == CAMERA_TYPE_OPT)//显示下摄像头 { if (session->video_shm_q_opt) { video_frame tt = { 0 }; int offset = (REC_COMMON_VIDEO_SNAPSHOT_WIDTH - REC_COMMON_VIDEO_SNAPSHOT_HEIGHT) / 2; tt.data[0] = tmp_frame_preview->data[0] + offset * 3; tt.format = tmp_frame_preview->format; tt.linesize[0] = tmp_frame_preview->linesize[0]; tt.width = REC_COMMON_VIDEO_SNAPSHOT_HEIGHT; tt.height = REC_COMMON_VIDEO_SNAPSHOT_WIDTH; session->video_shm_q_opt->GetVideo2(&tt, VIDEOQUEUE_FLAG_VERTICAL_FLIP); } } } else { tmp_frame_preview = video_frame_new(REC_COMMON_VIDEO_PREVIEW_WIDTH, REC_COMMON_VIDEO_PREVIEW_HEIGHT, VIDEO_FORMAT_RGB24); videoq_frame frm; frm.data = tmp_frame_preview->data[0]; bool result = session->video_shm_q_preview->GetVideo(&frm, VIDEOQUEUE_FLAG_HORIZONTAL_FLIP); if (result){ //人形框融合处理 if (session->personimage != NULL && session->personmask != NULL && *session->conf.ref_Is_showPersonArea == 1) { IplImage* img = cvCreateImageHeader(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 3); img->imageData = (char*)frm.data; if (frm.width != session->personimage->width) { IplImage* tmp = cvCreateImage(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 3); IplImage* tmpmask = cvCreateImage(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 1); cvResize(session->personimage, tmp); cvResize(session->personmask, tmpmask); cvAdd(img, tmp, img, tmpmask); cvReleaseImage(&tmp); cvReleaseImage(&tmpmask); } else { cvAdd(img, session->personimage, img, session->personmask); } cvReleaseImageHeader(&img); } } else { video_frame_fill_black(tmp_frame_preview); } } } *frame = tmp_frame_preview; return *session->conf.ref_window_state; } int show_agent_picture_proc(void *arg) { picture_record_t *t_record = (picture_record_t*)arg; if (NULL == t_record){ DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("show_agent_picture_proc param valid."); return -1; } SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); int iframeid = 1; for ( ; ; ) { DWORD dwRet = WaitForSingleObject(t_record->evt, 200); if (dwRet == WAIT_TIMEOUT){ if (NULL != t_record->session) { if (NULL != t_record->session->video_shm_q_remote) { int rc = video_shm_enqueue(t_record->session->video_shm_q_remote, t_record->record_frame, VIDEOQUEUE_FLAG_VERTICAL_FLIP, iframeid++); if (rc != Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("mobile mod insert remote video to queue failed."); } } video_frame* showframe = video_frame_new(t_record->show_frame->width, t_record->show_frame->height, VIDEO_FORMAT_RGB24); video_frame_fill_black(showframe); video_frame_copy(showframe, t_record->show_frame); int iused = on_rx_frame(showframe, t_record->session); if (0 == iused){ video_frame_delete(showframe); } } } else { break; } } return 0; } //坐席端图像显示线程 static unsigned int __stdcall agent_picture_show_thread(void* arg) { show_agent_picture_proc(arg); return 0; } static int agent_picture_video_start(picture_record_t* t_record) { t_record->evt = CreateEventA(NULL, FALSE, FALSE, NULL); t_record->work_thread = (HANDLE)_beginthreadex(NULL, 0, &agent_picture_show_thread, t_record, 0, NULL); return 0; } static int agent_picture_video_stop(picture_record_t* t_record) { if (t_record->evt) { SetEvent(t_record->evt); if (t_record->work_thread) { WaitForSingleObject(t_record->work_thread, INFINITE); CloseHandle(t_record->work_thread); t_record->work_thread = NULL; } CloseHandle(t_record->evt); t_record->evt = NULL; } if (t_record->record_frame){ video_frame_delete(t_record->record_frame); t_record->record_frame = NULL; } if (t_record->show_frame){ video_frame_delete(t_record->show_frame); t_record->show_frame = NULL; } return 0; } static int record_agent_picture_show_session_destory(video_session_t* session) { if (session->pic_record){ agent_picture_video_stop(session->pic_record); } if (session->video_shm_q_env) { delete session->video_shm_q_env; } if (session->video_shm_q_opt) { delete session->video_shm_q_opt; } if (session->video_error){ delete session->video_error->data; delete session->video_error; } if (session->personimage){ cvReleaseImage(&session->personimage); } if (session->personmask){ cvReleaseImage(&session->personmask); } return 0; } static void show_remote_agnet_picture(video_session_t *t_session) { char strPath[MAX_PATH]={0}; char strImgPath[MAX_PATH]={0}; int irecord_video_frame_width = REC_COMMON_VIDEO_SSM_AGENT_WIDTH; int irecord_video_frame_heigt = REC_COMMON_VIDEO_SSM_AGENT_HEIGHT; if (t_session->conf.eDeviceType == eStand2sType){ irecord_video_frame_width = REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_WIDTH; irecord_video_frame_heigt = REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_HEIGHT; } GetCurrentRunPath(strPath); _snprintf(strImgPath, MAX_PATH, "%s\\bin\\agent.jpg", strPath); video_frame* remote_frame = video_frame_new(irecord_video_frame_width, irecord_video_frame_heigt, VIDEO_FORMAT_RGB24); video_frame_fill_black(remote_frame); if (_access(strImgPath,0)!=-1) { IplImage*img = cvLoadImage(strImgPath,1); videoq_frame* vframe = new videoq_frame; if (img != NULL) { vframe->format = VIDEOQ_FORMAT_RGB24; vframe->framesize = img->imageSize; vframe->width = img->width; vframe->height = img->height; vframe->data = new unsigned char[img->imageSize]; memcpy(vframe->data,img->imageData,img->imageSize); cvReleaseImage(&img); } SwsContext*sws = sws_getContext(vframe->width, vframe->height,PIX_FMT_BGR24, irecord_video_frame_width, irecord_video_frame_heigt, PIX_FMT_BGR24, SWS_POINT, NULL, NULL, NULL); uint8_t *src_data[4] = {(unsigned char*)vframe->data+(vframe->height-1)*vframe->width*3,NULL,NULL,NULL}; int src_linesize[4] = {-vframe->width*3,0,0,0}; unsigned char *dst[4] = {remote_frame->data[0],NULL,NULL,NULL}; int dst_linesize[4] = {remote_frame->linesize[0],0,0,0}; sws_scale(sws, src_data, src_linesize, 0, vframe->height, dst, dst_linesize); sws_freeContext(sws); if (vframe){ delete vframe->data; delete vframe; } } if (NULL != t_session->video_shm_q_remote) { int rc = video_shm_enqueue(t_session->video_shm_q_remote, remote_frame, VIDEOQUEUE_FLAG_VERTICAL_FLIP, 1); if (rc != Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("insert agent picture to remote video queue failed."); } } video_frame * showframe = NULL; if (-1 == translate_image_resolution(&showframe,t_session->conf.remote_video_width,t_session->conf.remote_video_height,remote_frame)) { showframe = video_frame_new(t_session->conf.remote_video_width,t_session->conf.remote_video_height, VIDEO_FORMAT_RGB24); video_frame_fill_black(showframe); video_frame_copy(showframe, remote_frame); } t_session->pic_record = new picture_record_t(); t_session->pic_record->record_frame = remote_frame; t_session->pic_record->show_frame = showframe; t_session->pic_record->session = t_session; agent_picture_video_start(t_session->pic_record); } static int start_video_rtpsession(video_session_t* session) { int rc = -1; videortp_config_t config = { 0 }; config.fps_den = REC_COMMON_VIDEO_FPS_DEN; config.fps_num = REC_COMMON_VIDEO_FPS_NUM; config.capture_height = -1; // not use config.capture_width = -1; // not use config.dir = 3; config.tx_width = REC_COMMON_VIDEO_RTP_WIDTH; config.tx_height = REC_COMMON_VIDEO_RTP_HEIGHT; config.rx_width = session->conf.remote_video_width; config.rx_height = session->conf.remote_video_height; config.local_ip = session->conf.local_rtp_ip; config.local_pt = session->conf.local_pt; config.remote_pt = session->conf.local_pt; config.local_rtp_port = session->conf.local_rtp_port; config.mtu = session->conf.mtu; config.quant = session->conf.video_quant; config.remote_ip = session->conf.remote_rtp_ip; config.remote_rtp_port = session->conf.remote_rtp_port; config.user_data = session; config.bit_rate = session->conf.bit_rate; config.on_rx_frame = &on_rx_frame; config.dbg = &__dbg; config.logevent = &__logevent; videortp_create(&config, &session->rtp); if (eSDL == session->conf.eType){ session->premote_render->StartVideoRender(); } rc = videortp_start(session->rtp); if (rc != 0) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("start video rtp failed!"); videortp_destroy(session->rtp); session->rtp = NULL; } return rc; } static int start_local_video_clock(video_session_t* session) { int rc = -1; rc = videoclock_create(REC_COMMON_VIDEO_FPS_NUM, REC_COMMON_VIDEO_FPS_DEN, REC_COMMON_VIDEO_RTP_WIDTH, REC_COMMON_VIDEO_RTP_HEIGHT, VIDEO_FORMAT_RGB24, &local_put_frame, session, &local_get_frame, session, &session->local_clock, session->conf.ref_Up_Fps, &__dbg); if (0 == rc) { rc = videoclock_start(session->local_clock); if (rc != 0) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("start video clock failed!"); videoclock_destroy(session->local_clock); session->local_clock = NULL; } } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("create video clock failed!"); } return rc; } static int start_video(video_session_t *session) { int rc = -1; if (session->video_shm_q_env) { session->local_encode_sws_ctx_env = sws_getContext( REC_COMMON_VIDEO_RTP_ENV_WIDTH, REC_COMMON_VIDEO_RTP_ENV_HEIGHT, PIX_FMT_BGR24, REC_COMMON_VIDEO_RTP_ENV_WIDTH, REC_COMMON_VIDEO_RTP_ENV_HEIGHT, PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL); if (!session->local_encode_sws_ctx_env) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("get session->local_encode_sws_ctx_env failed."); goto on_error; } } else{ DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("session->video_shm_q_env is NULL."); } if (session->video_shm_q_opt) { session->local_encode_sws_ctx_opt = sws_getContext( REC_COMMON_VIDEO_RTP_WIDTH, REC_COMMON_VIDEO_RTP_HEIGHT, PIX_FMT_BGR24, REC_COMMON_VIDEO_RTP_WIDTH, REC_COMMON_VIDEO_RTP_HEIGHT, PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL); if (!session->local_encode_sws_ctx_opt) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("get session->local_encode_sws_ctx_opt failed."); goto on_error; } } else{ DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("session->video_shm_q_opt is NULL."); } if (eGDI == session->conf.eType){ if (DOUBLERECORD_CALLTYPE != session->conf.nCallType){ if (session->remote_hwnd) { rc = videoplayer_create(session->remote_hwnd, 0, 0, session->conf.remote_video_view_cx, session->conf.remote_video_view_cy, REC_COMMON_VIDEO_FPS_NUM, REC_COMMON_VIDEO_FPS_DEN, session->conf.remote_video_width, session->conf.remote_video_height, //*VIDEOPLAYER_FLAG_DOUBLESIZE|*/VIDEOPLAYER_FLAG_PUSH|VIDEOPLAYER_FLAG_CHECKTOP, session->conf.iremote_wind_flags, "remote", on_remoteWinstate, NULL, session, &session->remote_player); if (rc != 0) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("create remote video player failed!"); goto on_error; } } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("remote_hwnd == Null"); } } else{ if (NULL != pg_last_session){ session->remote_player = pg_last_session->remote_player; rc = 0; } } bool bIsActiveInspect = false; if (session->conf.ref_Is_ActiveInspect != NULL){ if (*session->conf.ref_Is_ActiveInspect == 1){ bIsActiveInspect = true; } else{ bIsActiveInspect = false; } } else{ bIsActiveInspect = false; } if (DOUBLERECORD_CALLTYPE != session->conf.nCallType){ int iwidth = REC_COMMON_VIDEO_PREVIEW_WIDTH; int iheight = REC_COMMON_VIDEO_PREVIEW_HEIGHT; if (session->conf.local_video_view_cx < session->conf.local_video_view_cy) { iwidth = REC_COMMON_VIDEO_PREVIEW_HEIGHT; iheight = REC_COMMON_VIDEO_PREVIEW_WIDTH; } rc = videoplayer_create(session->local_hwnd, 0, 0, session->conf.local_video_view_cx, session->conf.local_video_view_cy, REC_COMMON_VIDEO_FPS_NUM, REC_COMMON_VIDEO_FPS_DEN, bIsActiveInspect?REC_COMMON_VIDEO_SNAPSHOT_WIDTH: iwidth, bIsActiveInspect?REC_COMMON_VIDEO_SNAPSHOT_WIDTH: iheight, //*VIDEOPLAYER_FLAG_DOUBLESIZE|*/VIDEOPLAYER_FLAG_PULL|VIDEOPLAYER_FLAG_CHECKTOP, session->conf.ilocal_wind_flags, "local", on_pull, free_frame, session, &session->local_player); if (rc != 0) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("create local video player failed!"); goto on_error; } } else{ if (NULL != pg_last_session){ session->local_player = pg_last_session->local_player; DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("double record call local player reuse."); } } if (session->remote_hwnd) { if (0 != session->conf.remote_rtp_port){ if (0 != start_video_rtpsession(session)) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("start_video_rtpsession failed!"); goto on_error; } if (DOUBLERECORD_CALLTYPE == session->conf.nCallType){ if (NULL != pg_last_session){ pg_last_session->rtp = session->rtp; } } if (0 != start_local_video_clock(session)) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("start_local_video_clock failed!"); goto on_error; } } else{ pg_last_session = session; //保存session信息 show_remote_agnet_picture(session); } } } else{ if (DOUBLERECORD_CALLTYPE == session->conf.nCallType) { if (NULL != pg_last_session) { session->premote_render = pg_last_session->premote_render; session->plocal_render = pg_last_session->plocal_render; } } if (session->premote_render) { if (0 != session->conf.remote_rtp_port) { if (0 != start_video_rtpsession(session)) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("start_video_rtpsession failed!"); goto on_error; } if (DOUBLERECORD_CALLTYPE == session->conf.nCallType) { if (NULL != pg_last_session) { pg_last_session->rtp = session->rtp; } } if (0 != start_local_video_clock(session)) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("start_local_video_clock failed!"); goto on_error; } } else { show_remote_agnet_picture(session); } } } on_error: return rc; } static void stop_video(video_session_t *session) { if (eGDI == session->conf.eType){ if (session->local_clock && session->remote_hwnd){ videoclock_stop(session->local_clock); videoclock_destroy(session->local_clock); session->local_clock = NULL; pg_remote_hwnd = NULL; pg_local_hwnd = NULL; } } else{ if (session->local_clock){ videoclock_stop(session->local_clock); videoclock_destroy(session->local_clock); session->local_clock = NULL; } } if (session->rtp){ videortp_stop(session->rtp); videortp_destroy(session->rtp); session->rtp = NULL; } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("session->rtp == null"); } if (eGDI == session->conf.eType){ if (session->local_player) { videoplayer_destroy(session->local_player); session->local_player = NULL; } if (session->remote_player && session->remote_hwnd){ videoplayer_destroy(session->remote_player); session->remote_player = NULL; } } else{ session->premote_render->StopVideoRender(); if (session->plocal_render){ delete session->plocal_render; session->plocal_render = NULL; } if (session->premote_render){ delete session->premote_render; session->premote_render = NULL; } } if (session->local_encode_sws_ctx_env) { sws_freeContext(session->local_encode_sws_ctx_env); session->local_encode_sws_ctx_env = NULL; } if (session->local_encode_sws_ctx_opt) { sws_freeContext(session->local_encode_sws_ctx_opt); session->local_encode_sws_ctx_opt = NULL; } } static bool ReMoveOutOfScreenVideoWindow(HWND hWnd, RECT rect) { bool bret = false; int iScreenWidth = GetSystemMetrics(SM_CXSCREEN); int iScreenHight = GetSystemMetrics(SM_CYSCREEN); int iVideoWidth = rect.right - rect.left; int iVideoHight = rect.bottom - rect.top; if (rect.left < 0) { if (rect.bottom <= iScreenHight) { MoveWindow(hWnd, 0, rect.top, iVideoWidth, iVideoHight, TRUE); } else { MoveWindow(hWnd, 0, iScreenHight - iVideoHight, iVideoWidth, iVideoHight, TRUE); } bret = true; } if (rect.right > iScreenWidth) { if (rect.bottom <= iScreenHight) { MoveWindow(hWnd, iScreenWidth - iVideoWidth, rect.top, iVideoWidth, iVideoHight, TRUE); } else { MoveWindow(hWnd, iScreenWidth - iVideoWidth, iScreenHight - iVideoHight, iVideoWidth, iVideoHight, TRUE); } bret = true; } if (rect.bottom > iScreenHight) { if (rect.left >= 0 && rect.right <= iScreenWidth) { MoveWindow(hWnd, rect.left, iScreenHight - iVideoHight, iVideoWidth, iVideoHight, TRUE); bret = true; } } return bret; } static bool ReMoveCenterOtherVideoWindow(HWND hWnd, RECT rect, RECT otherect) { bool bret = false; int iVideoWidth = rect.right - rect.left; int iVideoHight = rect.bottom - rect.top; int iOtherVideoWidth = otherect.right - otherect.left; int iOtherVideoHight = otherect.bottom - otherect.top; if (iVideoWidth > iOtherVideoHight || iVideoHight > iOtherVideoHight) { return bret; } if (rect.left > otherect.left + iVideoWidth && rect.right < otherect.right) { if (rect.top > otherect.top && rect.bottom < otherect.bottom) { if (otherect.right - rect.right <= rect.left - otherect.left) { MoveWindow(hWnd, otherect.right - iVideoWidth, rect.top, iVideoWidth, iVideoHight, TRUE); } else { MoveWindow(hWnd, otherect.left, rect.top, iVideoWidth, iVideoHight, TRUE); } bret = true; } } if (rect.right < otherect.right - iVideoWidth && rect.left > otherect.left) { if (rect.top > otherect.top && rect.bottom < otherect.bottom) { if (otherect.right - rect.right <= rect.left - otherect.left) { MoveWindow(hWnd, otherect.right - iVideoWidth, rect.top, iVideoWidth, iVideoHight, TRUE); } else { MoveWindow(hWnd, otherect.left, rect.top, iVideoWidth, iVideoHight, TRUE); } bret = true; } } return bret; } static bool ReMoveVideoWindow(HWND hWnd, RECT rect, RECT otherect) { bool bret = false; bret = ReMoveOutOfScreenVideoWindow(hWnd, rect); bret = ReMoveCenterOtherVideoWindow(hWnd, rect, otherect); return bret; } static int HandleVideoMoveEvent(int iMessageType, HWND hWnd, video_session_t* pSession) { int iRet = -1; if (NULL == pSession || NULL == hWnd) { return iRet; } HWND hOtherWnd = NULL; //本地和远端标识 1为本地,2为远端 int iVideoType = 2; if (hWnd == pSession->local_hwnd) { iVideoType = 1; hOtherWnd = pSession->remote_hwnd; } else { hOtherWnd = pSession->local_hwnd; } if (NULL == hOtherWnd) { return iRet; } bool bMoved = false; RECT rect; GetWindowRect(hWnd, &rect); RECT otherect; GetWindowRect(hOtherWnd, &otherect); bMoved = ReMoveVideoWindow(hWnd, rect, otherect); if (bMoved) { GetWindowRect(hWnd, &rect); } if (NULL != pSession->conf.video_echo_cb && NULL != pSession->conf.video_echo_cb->on_video_box_move) { pSession->conf.video_echo_cb->on_video_box_move(iMessageType, iVideoType, rect.left, rect.bottom, pSession->conf.video_echo_cb->user_data); iRet = 0; } return iRet; } static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { video_session_t* session = (video_session_t*)GetWindowLongPtrA(hWnd, GWLP_USERDATA); switch (msg) { case WM_DESTROY: if (session->local_hwnd == hWnd) { session->local_hwnd = 0; } else if (session->remote_hwnd == hWnd) { session->remote_hwnd = 0; } if (session->local_hwnd == 0 && session->remote_hwnd == 0) { PostQuitMessage(0); } return 0; case WM_NCHITTEST: if (((session->local_hwnd == hWnd)&&(0 != session->conf.local_move)) || ((session->remote_hwnd == hWnd)&&(0 != session->conf.remote_move))){ return HTCAPTION; } else{ break; } case WM_ACTIVATE: case WM_TOUCH: case WM_GESTURE: ReleaseCapture(); return 0; #if 1 case WM_WINDOWPOSCHANGED: { LPWINDOWPOS pPos = (LPWINDOWPOS)lParam; if (pPos->hwndInsertAfter != HWND_TOPMOST && pPos->hwndInsertAfter != HWND_TOP) { //BringWindowToTop(hWnd); SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } else { return DefWindowProc(hWnd, msg, wParam, lParam); } } return 0; //return DefWindowProc(hWnd, msg, wParam, lParam); #endif case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_LBUTTONUP: if (session) { if (session->local_hwnd) { //ReleaseCapture(); } } return 0; case WM_CLOSE: stop_video(session); //SetEvent(session->ui_thread); DestroyWindow(session->local_hwnd); DestroyWindow(session->remote_hwnd); return 0; case WM_MOVE: break; case WM_ENTERSIZEMOVE: { HandleVideoMoveEvent(0, hWnd, session); } break; case WM_EXITSIZEMOVE: { HandleVideoMoveEvent(1, hWnd, session); } break; default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0; } static unsigned int __stdcall ui_proc(void *arg) { video_session_t *session = (video_session_t*)arg; WNDCLASSA wc = {0}; ATOM a = 0; HWND hWnd = NULL; MSG msg; HINSTANCE hInst = ModuleBase::GetModuleBase()->GetInstance(); bool breuse_local_wnd = false; bool breuse_remote_wnd = false; DWORD dLocal_style = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE; DWORD dRemote_style = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE; //双录两阶段视频窗口复用 if (NULL != pg_local_hwnd){ session->local_hwnd = pg_local_hwnd; //SetWindowLongPtrA(session->local_hwnd, GWLP_USERDATA, (LONG_PTR)session); breuse_local_wnd = true; } else{ if (0 != session->conf.local_move){ dLocal_style -= WS_EX_NOACTIVATE; } if (0 != session->conf.remote_move){ dRemote_style -= WS_EX_NOACTIVATE; } CoInitialize(0); wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.hCursor = NULL; wc.hIcon = NULL; wc.lpfnWndProc = &WndProc; wc.lpszClassName = WNDCLS_NAME; wc.style = CS_HREDRAW | CS_OWNDC | CS_VREDRAW; a = RegisterClassA(&wc); if (a == 0) return 0; session->local_hwnd = CreateWindowExA(dLocal_style, WNDCLS_NAME, NULL, WS_POPUP|WS_VISIBLE, session->conf.local_video_view_x, session->conf.local_video_view_y, session->conf.local_video_view_cx, session->conf.local_video_view_cy, NULL, NULL, hInst, NULL); if (session->local_hwnd) { SetWindowLongPtrA(session->local_hwnd, GWLP_USERDATA, (LONG_PTR)session); if (0 == session->conf.local_move){ SetWindowPos(session->local_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); } pg_local_hwnd = session->local_hwnd; //LogWarn(Severity_Low, Error_Debug, EVENT_MOD_SIP_LOCAL_WINDOW_CREATE_SUCCESS, "create local window success and restore local video hwnd."); } else{ char strinfo[MAX_PATH] = {0}; _snprintf(strinfo, MAX_PATH, "%s%d", "create local window failed and last error is ", GetLastError()); LogWarn(Severity_Middle, Error_Debug, EVENT_MOD_SIP_LOCAL_WINDOW_CREATE_FAILED, strinfo); //return -1; } } if(session->conf.remote_video_view_x||session->conf.remote_video_view_y||session->conf.remote_video_view_cx||session->conf.remote_video_view_cy) { if (NULL != pg_remote_hwnd){ session->remote_hwnd = pg_remote_hwnd; breuse_remote_wnd = true; if (NULL != pg_last_session){ record_agent_picture_show_session_destory(pg_last_session); } } else{ session->remote_hwnd = CreateWindowExA(dRemote_style, WNDCLS_NAME, NULL, WS_POPUP|WS_VISIBLE, session->conf.remote_video_view_x, session->conf.remote_video_view_y, session->conf.remote_video_view_cx, session->conf.remote_video_view_cy, NULL, NULL, hInst, NULL); if (session->remote_hwnd) { SetWindowLongPtrA(session->remote_hwnd, GWLP_USERDATA, (LONG_PTR)session); if (0 == session->conf.remote_move){ SetWindowPos(session->remote_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); } pg_remote_hwnd = session->remote_hwnd; //LogWarn(Severity_Low, Error_Debug, EVENT_MOD_SIP_REMOTE_WINDOW_CREATE_SUCCESS, "create remote window success and restore remote video hwnd."); } else{ char strinfo[MAX_PATH] = {0}; _snprintf(strinfo, MAX_PATH, "%s%d", "create remote window failed and last error is ", GetLastError()); LogWarn(Severity_Middle, Error_Debug, EVENT_MOD_SIP_REMOTE_WINDOW_CREATE_FAILED, strinfo); //return -1; } } } else { session->remote_hwnd = NULL; } if (session->local_hwnd/* && session->remote_hwnd*/) { int rc = 0; ShowCursor(FALSE); SetEvent(session->ui_event); rc = start_video(session); if (rc != 0) { LogWarn(Severity_Middle, Error_Debug, ERROR_MOD_SIP_START_VIDEO_FAILED, "start video failed!"); } if (!breuse_local_wnd && !breuse_remote_wnd) { while (GetMessageA(&msg, NULL, NULL, NULL)) { if (msg.message == WM_CLOSE) { } TranslateMessage(&msg); DispatchMessageA(&msg); } SetEvent(session->ui_event); } } if (a) UnregisterClassA(WNDCLS_NAME, hInst); CoUninitialize(); return 0; } static void __video_render_log(render_loglevel elevel, void* user_data, const char* fmt, va_list arg) { int n = _vsnprintf(NULL, 0, fmt, arg); if (n >= MAX_LOG_LEN) { char* buf = (char*)malloc((size_t)(n + 1)); _vsnprintf(buf, n + 1, fmt, arg); DbgWithLink((LOG_LEVEL_E)elevel, LOG_TYPE_SYSTEM)("%s", buf); free(buf); } else { char strlog[MAX_LOG_LEN] = { 0 }; _vsnprintf(strlog, MAX_LOG_LEN, fmt, arg); DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("%s", strlog); } } //void* videorender_func(void* arg) static unsigned int __stdcall videorender_func(void* arg) { video_session_t* session = (video_session_t*)arg; videorender_callback_t t_callback = { 0 }; t_callback.debug = &__video_render_log; //双录两阶段视频窗口复用 if (NULL != pg_local_render){ session->plocal_render = (IVideoRender*)pg_local_render; } else{ session->plocal_render = CreateVideoRenderObj(&t_callback); if (NULL != session->plocal_render){ videorender_param_t tparam = { 0 }; tparam.icx = session->conf.local_video_view_x; tparam.icy = session->conf.local_video_view_y; tparam.uwidth = session->conf.local_video_view_cx; tparam.uheight = session->conf.local_video_view_cy; tparam.bmoveable = (bool)session->conf.local_move; //tparam.uvideowidth = REC_COMMON_VIDEO_PREVIEW_WIDTH; //tparam.uvideoheight = REC_COMMON_VIDEO_PREVIEW_HEIGHT; tparam.ivideoformat = VIDEO_FORMAT_RGB24; if (0 == session->plocal_render->VideoRenderSetParam(&tparam)){ session->plocal_render->HideVideoWindow(); } else { return 0; } pg_local_render = session->plocal_render; } } if (session->conf.remote_video_view_x || session->conf.remote_video_view_y || session->conf.remote_video_view_cx || session->conf.remote_video_view_cy){ if (NULL != pg_local_render){ session->premote_render = (IVideoRender*)pg_remote_render; } else{ session->premote_render = CreateVideoRenderObj(&t_callback); if (session->premote_render){ videorender_param_t tparam_remote = { 0 }; tparam_remote.icx = session->conf.remote_video_view_x; tparam_remote.icy = session->conf.remote_video_view_y; tparam_remote.uwidth = session->conf.remote_video_view_cx; tparam_remote.uheight = session->conf.remote_video_view_cy; tparam_remote.bmoveable = (bool)session->conf.remote_move; //tparam_remote.uvideowidth = REC_COMMON_VIDEO_DSM_AGENT_WIDTH; //tparam_remote.uvideoheight = REC_COMMON_VIDEO_DSM_AGENT_HEIGHT; tparam_remote.ivideoformat = VIDEO_FORMAT_RGB24; if (0 == session->premote_render->VideoRenderSetParam(&tparam_remote)) { //session->premote_render->ShowVideoWindow(); } } else { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("session remote video render is null."); } pg_remote_render = session->premote_render; } } if (session->plocal_render){ start_video(session); //session->plocal_render->ShowVideoWindow(); bool bshow_local = false; bool bset = true; //session->premote_render->ShowVideoWindow(); if (DOUBLERECORD_CALLTYPE != session->conf.nCallType){ session->plocal_render->StartVideoRender(); } for (; ; ) { //struct timespec ts; //clock_gettime(CLOCK_REALTIME, &ts); //long unsec = ts.tv_nsec + (1000 * 1000 * 500); //ts.tv_sec += (unsec / 1000000000); //ts.tv_nsec = (unsec % 1000000000); //if (0 != sem_timedwait(&session->ui_stop_sem, &ts) && (ETIMEDOUT == errno)){ DWORD dwRet = WaitForSingleObject(session->ui_event, 500); if (dwRet == WAIT_TIMEOUT){ video_frame* local_video_frame = NULL; int iwindowstate = get_local_video_frame(session, &local_video_frame); if (iwindowstate != session->ilast_windstae){ set_video_windows(session, iwindowstate); session->ilast_windstae = iwindowstate; } if (NULL != local_video_frame) { video_frame* localframe = NULL; if (0 == translate_image_resolution(&localframe, session->conf.local_video_view_cx, session->conf.local_video_view_cy, local_video_frame)) { session->plocal_render->RenderVideoFrame(localframe, RVC_FLIP_VERTICAL); video_frame_delete(localframe); localframe = NULL; } else { session->plocal_render->RenderVideoFrame(local_video_frame, RVC_FLIP_VERTICAL); } bshow_local = true; video_frame_delete(local_video_frame); local_video_frame = NULL; } } else { session->plocal_render->HideVideoWindow(); break; } if (bset){ if (bshow_local && session->bshow_remote) { session->plocal_render->ShowVideoWindow(); session->premote_render->ShowVideoWindow(); bset = false; } } } session->plocal_render->StopVideoRender(); } return 0; } static int start_ui(video_session_t *session) { session->ui_event = CreateEventA(NULL, FALSE, FALSE, NULL); if (!session->ui_event) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("phonemedia_start create ui event failed!"); return Error_Resource; } if (eGDI == session->conf.eType){ session->ui_thread = (HANDLE)_beginthreadex(NULL, 0, &ui_proc, session, 0, NULL); } else{ session->ui_thread = (HANDLE)_beginthreadex(NULL, 0, &videorender_func, session, 0, NULL); } if (!session->ui_thread) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("phonemedia_start create ui thread failed!"); CloseHandle(session->ui_event); session->ui_event = NULL; return Error_Resource; } { HANDLE hs[] = {session->ui_event, session->ui_thread}; DWORD dwRet = WaitForMultipleObjects(array_size(hs), hs, FALSE, INFINITE); if (dwRet == WAIT_OBJECT_0) { // } else if (dwRet == WAIT_OBJECT_0 + 1) { // thread exit CloseHandle(session->ui_thread); session->ui_thread = NULL; CloseHandle(session->ui_event); session->ui_event = NULL; return Error_Resource; } } return 0; } static void stop_ui(video_session_t *session) { if (eGDI == session->conf.eType){ if (DOUBLERECORD_CALLTYPE == session->conf.nCallType) { if (NULL != pg_last_session) { pg_last_session->rtp = session->rtp; pg_last_session->local_clock = session->local_clock; CloseHandle(session->ui_thread); session->ui_thread = NULL; CloseHandle(session->ui_event); session->ui_event = NULL; session = pg_last_session; } } if (NULL != session->pic_record) { if (NULL != session->pic_record->work_thread) { SetEvent(session->pic_record->evt); CloseHandle(session->pic_record->work_thread); session->pic_record->work_thread = NULL; CloseHandle(session->pic_record->evt); session->pic_record->evt = NULL; } } if (session->local_hwnd) { BOOL bRet = PostMessageA(session->local_hwnd, WM_CLOSE, 0, 0); DWORD dCode = WaitForSingleObject(session->ui_thread, INFINITE); CloseHandle(session->ui_thread); session->ui_thread = NULL; CloseHandle(session->ui_event); session->ui_event = NULL; } pg_last_session = NULL; pg_local_hwnd = NULL; pg_remote_hwnd = NULL; } else{ if (DOUBLERECORD_CALLTYPE == session->conf.nCallType) { if (NULL != pg_last_session) { pg_last_session->rtp = session->rtp; pg_last_session->local_clock = session->local_clock; CloseHandle(session->ui_thread); session->ui_thread = NULL; CloseHandle(session->ui_event); session->ui_event = NULL; session = pg_last_session; } } if (NULL != session->pic_record) { if (NULL != session->pic_record->work_thread) { SetEvent(session->pic_record->evt); CloseHandle(session->pic_record->work_thread); session->pic_record->work_thread = NULL; CloseHandle(session->pic_record->evt); session->pic_record->evt = NULL; } } SetEvent(session->ui_event); DWORD dCode = WaitForSingleObject(session->ui_thread, INFINITE); CloseHandle(session->ui_thread); session->ui_thread = NULL; CloseHandle(session->ui_event); session->ui_event = NULL; pg_last_session = NULL; stop_video(session); } } int local_video_session_create(const video_session_conf_t *conf, video_session_t **p_session, const bool bremote) { video_session_t *session = ZALLOC_T(video_session_t); if (session) { memcpy(&session->conf, conf, sizeof(video_session_conf_t)); if (conf->local_video_view_cx >= conf->local_video_view_cy) { session->video_shm_q_preview = new Clibvideoqueue(REC_COMMON_VIDEO_ENV_SHM_PREVIEW_QUEUE); } else { session->video_shm_q_preview = new Clibvideoqueue(REC_COMMON_VIDEO_OPT_SHM_PREVIEW_QUEUE); } if (bremote){ session->video_shm_q_remote = new Clibvideoqueue(REC_COMMON_VIDEO_REMOTE_SHM_RTP_QUEUE); } if (conf->ref_Is_ActiveInspect != NULL) { if (*conf->ref_Is_ActiveInspect == 1) { session->video_error = NULL; session->video_shm_q_env = new Clibvideoqueue(REC_COMMON_VIDEO_ENV_SHM_SNAPSHOT_QUEUE); if (conf->camera_count == 2) { session->video_shm_q_opt = new Clibvideoqueue(REC_COMMON_VIDEO_OPT_SHM_SNAPSHOT_QUEUE); } } } session->local_clock = NULL; *p_session = session; } return 0; } int video_session_create(const video_session_conf_t *conf, video_session_t **p_session) { video_session_t *session = ZALLOC_T(video_session_t); if (session) { memcpy(&session->conf, conf, sizeof(video_session_conf_t)); session->video_shm_q_env = new Clibvideoqueue(REC_COMMON_VIDEO_ENV_SHM_RTP_QUEUE); if (DOUBLERECORD_CALLTYPE != conf->nCallType){ session->video_shm_q_remote = new Clibvideoqueue(REC_COMMON_VIDEO_REMOTE_SHM_RTP_QUEUE); session->video_shm_q_preview = new Clibvideoqueue(REC_COMMON_VIDEO_ENV_SHM_PREVIEW_QUEUE); } else{ if (NULL != pg_last_session){ session->video_shm_q_remote = (pg_last_session)->video_shm_q_remote; session->video_shm_q_preview = (pg_last_session)->video_shm_q_preview; } } char strPath[MAX_PATH]={0}; char strImgPath[MAX_PATH]={0}; GetCurrentRunPath(strPath); _snprintf(strImgPath, MAX_PATH,"%s\\bin\\error.jpg",strPath); if (_access(strImgPath,0)!=-1) { IplImage*img = cvLoadImage(strImgPath,1); if (img != NULL) { session->video_error = new videoq_frame; session->video_error->format = VIDEOQ_FORMAT_RGB24; session->video_error->framesize = 320*180*3; session->video_error->height = 180; session->video_error->width = 320; session->video_error->data = new unsigned char[320*180*3]; memcpy(session->video_error->data,img->imageData,320*180*3); cvReleaseImage(&img); } } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("Load error img Fail"); session->video_error = NULL; } //加载人形背景框 char strPersonPath[MAX_PATH] = {0}; _snprintf(strPersonPath, MAX_PATH,"%s\\bin\\rxk.jpg",strPath); if (_access(strPersonPath,0)!=-1) { if (session->personimage == NULL) { session->personimage = cvLoadImage(strPersonPath); } if (session->personmask == NULL ) { session->personmask = cvLoadImage(strPersonPath,0); } } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("Load person img Fail"); session->personimage = NULL; session->personmask = NULL; } #if 0 video_frame frame; video_frame_alloc(320, 180, VIDEO_FORMAT_RGB24, &frame); video_frame_fill_black(&frame); videoq_frame frm; frm.data = frame.data[0]; session->video_shm_q_env->GetVideo(&frm, 0); video_frame_save_bmpfile("d:\\a.bmp", &frame); #endif if (conf->camera_count == 2) { session->video_shm_q_opt = new Clibvideoqueue(REC_COMMON_VIDEO_OPT_SHM_RTP_QUEUE); } *p_session = session; } return 0; } int video_session_start(video_session_t *session) { int rc = start_ui(session); return rc; } void video_session_stop(video_session_t *session) { stop_ui(session); } void double_record_broadcast_video_session_stop() { if (NULL != pg_last_session) { if (NULL != pg_last_session->pic_record) { if (NULL != pg_last_session->pic_record->work_thread) { SetEvent(pg_last_session->pic_record->evt); CloseHandle(pg_last_session->pic_record->work_thread); pg_last_session->pic_record->work_thread = NULL; CloseHandle(pg_last_session->pic_record->evt); pg_last_session->pic_record->evt = NULL; } } if (NULL != pg_last_session) { if (eGDI == pg_last_session->conf.eType) { if (NULL != pg_last_session->local_hwnd){ BOOL bRet = PostMessageA(pg_last_session->local_hwnd, WM_CLOSE, 0, 0); } } else{ if (NULL != pg_last_session->plocal_render){ pg_last_session->plocal_render->StopVideoRender(); } } DWORD dCode = WaitForSingleObject(pg_last_session->ui_thread, INFINITE); CloseHandle(pg_last_session->ui_thread); pg_last_session->ui_thread = NULL; CloseHandle(pg_last_session->ui_event); pg_last_session->ui_event = NULL; if (eGDI == pg_last_session->conf.eType) { pg_local_hwnd = NULL; pg_remote_hwnd = NULL; } else{ pg_local_render = NULL; pg_remote_render = NULL; } pg_last_session = NULL; } } } void video_session_destroy(video_session_t *session) { if (NULL != session) { if (NULL != session->pic_record) { if (NULL != session->pic_record->work_thread) { SetEvent(session->pic_record->evt); CloseHandle(session->pic_record->work_thread); session->pic_record->work_thread = NULL; CloseHandle(session->pic_record->evt); session->pic_record->evt = NULL; } } if (session->video_shm_q_env) { delete session->video_shm_q_env; session->video_shm_q_env = NULL; } if (session->video_shm_q_opt) { delete session->video_shm_q_opt; session->video_shm_q_opt = NULL; } if (session->video_shm_q_preview) { delete session->video_shm_q_preview; session->video_shm_q_preview = NULL; } } if (session->video_error){ delete session->video_error->data; delete session->video_error; } if (session->video_shm_q_remote) { delete session->video_shm_q_remote; session->video_shm_q_remote = NULL; } if (session->personimage){ cvReleaseImage(&session->personimage); } if (session->personmask){ cvReleaseImage(&session->personmask); } free(session); } void av_log_cb(void*ptr, int level, const char*fmt, va_list arg) { //int n = _vscprintf(fmt, arg); //if (n > MAX_LOG_LEN) { // char* buf = (char*)malloc((size_t)(n + 1)); // _vsnprintf(buf, n + 1, fmt, arg); // DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("%s", buf); // free(buf); //} //else{ // char strlog[MAX_LOG_LEN] = {0}; // _vsnprintf(strlog, MAX_LOG_LEN, fmt, arg); // DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("%s", strlog); //} } int video_lib_init() { videoframework_init(); av_log_set_callback(&av_log_cb); //av_log_set_level(AV_LOG_DEBUG); av_log_set_level(AV_LOG_QUIET); return 0; } void video_lib_deinit() { //CoUninitialize(); videoframework_term(); }