Selaa lähdekoodia

Z991239-3559 #comment 解耦远程双录图像渲染流程

80274480 3 vuotta sitten
vanhempi
sitoutus
6019b3d59b

+ 3 - 8
Module/mod_interactivecontrol/mod_interactivecontrol.cpp

@@ -2349,7 +2349,7 @@ void UIServiceSession::Handle_StartRemoteRecord(SpReqAnsContext<UIService_StartR
 		CSimpleStringA camstate;
 		m_pEntity->GetFunction()->GetSysVar("CameraState",camstate);
 		Dbg("start remote record, camstate=%s, videoname=%s.",(LPCTSTR)camstate,(LPCTSTR)CSimpleStringW2A(ctx->Req.VideoName));
-		if (camstate[0] == 'N') {
+		if (camstate[0] == 'N' || camstate[0] == 'O') {
 			LogEvent(Severity_Middle,LOG_EVT_UI_STARTREMOTERECORD,(LPCTSTR)(m_pEntity->EncryptVideoNameCarNumber(CSimpleStringW2A(ctx->Req.VideoName))));
 			ctx->Ans.ErrorCode = 0;
 			ctx->Ans.ErrorMsg = CSimpleStringA2W("");
@@ -2361,15 +2361,10 @@ void UIServiceSession::Handle_StartRemoteRecord(SpReqAnsContext<UIService_StartR
 			ctx->Ans.ErrorMsg = CSimpleStringA2W("录音录像设备正在启动,请稍后重试!");
 			LogWarn(Severity_Middle, Error_Debug, LOG_EVT_START_REMOTERECORD_FAILED, "录音录像设备正在启动,请稍后重试!");
 		}
-		else if (camstate[0] == 'E' || camstate[0] == 'O'){
+		else if (camstate[0] == 'E'){
 			ctx->Ans.ErrorCode = 0x30B81003;
 			ctx->Ans.ErrorMsg = CSimpleStringA2W("摄像头故障,请联系分行技术部!");
-			if ('E' == camstate[0]){
-				LogWarn(Severity_Middle, Error_Debug, LOG_EVT_START_REMOTERECORD_FAILED, "env 摄像头故障,启动远程双录失败");
-			} 
-			else{
-				LogWarn(Severity_Middle, Error_Debug, LOG_EVT_START_REMOTERECORD_FAILED, "opt 摄像头故障,启动远程双录失败");
-			}
+			LogWarn(Severity_Middle, Error_Debug, LOG_EVT_START_REMOTERECORD_FAILED, "env 摄像头故障,启动远程双录失败");
 		}
 		else {
 			ctx->Ans.ErrorCode = 0x30B81002;

+ 1 - 30
Module/mod_sipphone/endpoint.cpp

@@ -253,25 +253,10 @@ static void endpoint_media_update_video(endpoint_call_t *call, media_desc_t *vid
 			call->video = NULL;
 		}
 
-		int i = 0;/*
-		int local_view_x = video_desc->param[i++];
-		int local_view_y = video_desc->param[i++];
-		int local_view_cx = video_desc->param[i++];
-		int local_view_cy = video_desc->param[i++];
-		int remote_view_x = video_desc->param[i++];
-		int remote_view_y = video_desc->param[i++];
-		int remote_view_cx = video_desc->param[i++];
-		int remote_view_cy = video_desc->param[i++];*/
+		int i = 0;
 		int remote_width = video_desc->param[i++];
 		int remote_height = video_desc->param[i++];
 
-		////add by clp 20190823
-		//int local_hwd_move = video_desc->param[i++];
-		//int remote_hwd_move = video_desc->param[i++];
-
-		//int local_fresh_time = video_desc->param[i++];
-		//int remote_fresh_time = video_desc->param[i++];
-
 		video_session_conf_t video_conf = {0};
 		if (eMobilePadType == call->eDeviceType)
 		{
@@ -283,18 +268,10 @@ static void endpoint_media_update_video(endpoint_call_t *call, media_desc_t *vid
 		}
 		video_conf.local_rtp_ip = video_desc->local_ip;
 		video_conf.local_rtp_port = video_desc->local_port;
-		//video_conf.local_video_view_x = local_view_x;
-		//video_conf.local_video_view_y = local_view_y;
-		//video_conf.local_video_view_cx = local_view_cx;
-		//video_conf.local_video_view_cy = local_view_cy;
 		video_conf.mtu = ep_conf->mtu;
 		video_conf.video_quant = ep_conf->quant;
 		video_conf.remote_rtp_ip = video_desc->remote_ip;
 		video_conf.remote_rtp_port = video_desc->remote_port;
-		//video_conf.remote_video_view_x = remote_view_x;
-		//video_conf.remote_video_view_y = remote_view_y;
-		//video_conf.remote_video_view_cx = remote_view_cx;
-		//video_conf.remote_video_view_cy = remote_view_cy;
 		video_conf.remote_video_width = remote_width;
 		video_conf.remote_video_height = remote_height;
 		video_conf.ref_active_camera = call->ep->conf.ref_active_camera;
@@ -302,8 +279,6 @@ static void endpoint_media_update_video(endpoint_call_t *call, media_desc_t *vid
 		video_conf.ref_camera_state = call->ep->conf.ref_camera_state;
 		video_conf.ref_window_state = call->ep->conf.ref_window_state;
 		video_conf.ref_Is_showPersonArea = call->ep->conf.ref_Is_showPersonArea;
-		//video_conf.ref_active_img = call->ep->conf.ref_active_img;
-		//video_conf.ref_Is_ActiveInspect = call->ep->conf.ref_Is_ActiveInspect;
 		video_conf.ref_active_img = NULL;
 		video_conf.ref_Is_ActiveInspect = NULL;
 		video_conf.camera_count = call->ep->conf.camera_count;
@@ -311,14 +286,10 @@ static void endpoint_media_update_video(endpoint_call_t *call, media_desc_t *vid
 		video_conf.ref_Up_Fps = call->ep->conf.ref_Up_Fps;
 		video_conf.eDeviceType = call->eDeviceType;
 		video_conf.nCallType = call->nCallType;
-		//video_conf.local_move = local_hwd_move;
-		//video_conf.remote_move = remote_hwd_move;
 		Dbg("%s:%d video_render_cb = 0x%08x and video_render_cb->on_video_render = 0x%08x, video_render_cb->user_data = 0x%08x.", __FUNCTION__, __LINE__, cb, cb->on_video_render, cb->user_data);
 		memcpy(&video_conf.video_render_cb, cb, sizeof(rvc_video_render_callback_t));
 		video_conf.ilocal_wind_flags = VIDEOPLAYER_FLAG_PULL|VIDEOPLAYER_FLAG_CHECKTOP;
 		video_conf.iremote_wind_flags = VIDEOPLAYER_FLAG_PUSH|VIDEOPLAYER_FLAG_CHECKTOP;
-		//video_conf.ilvideo_ft = local_fresh_time;
-		//video_conf.irvideo_ft = remote_fresh_time;
 
 		if (video_conf.nCallType == MOBILETOPAD_CALLTYPE )  //如果与手机连接使用标准H264
 		{

+ 36 - 26
Module/mod_sipphone/mod_sipphone.cpp

@@ -65,7 +65,7 @@ static void __on_video_box_move(int imessagetype, int ivideotype, int ileft, int
 }
 
 
-CSIPPhoneSession::CSIPPhoneSession(CSIPEntity *pEntity) : m_pEntity(pEntity), m_pCall(NULL), m_iLastState(0),m_IsLocalPlay(0)
+CSIPPhoneSession::CSIPPhoneSession(CSIPEntity *pEntity) : m_pEntity(pEntity), m_pCall(NULL), m_iLastState(0)
 {
 
 }
@@ -133,11 +133,17 @@ static void __video_render_log(void* user_data, const char* fmt, va_list arg)
 
 static int __remote_video_render_callback(void* videoframe, void* user_data)
 {
-	LOG_FUNCTION();
 	CSIPEntity* pThis = static_cast<CSIPEntity*>(user_data);
-	rvc_start_remote_video_render(pThis->m_render, videoframe);
-	
-	return 0;
+
+	if (DOUBLERECORD_CALLTYPE == pThis->m_nCallType) {
+		if (NULL != pThis->m_render) {
+			if (pThis->m_render->remote_render_threadid > 0) {
+				rvc_stop_remote_video_render(pThis->m_render);
+			}
+		}
+	}
+
+	return rvc_start_remote_video_render(pThis->m_render, videoframe);
 }
 
 CSIPEntity::CSIPEntity() : m_pCurrentSession(NULL), m_state(INIT),m_iPickupPhoneState(ePickupMicrophoneState_Off) 
@@ -2492,26 +2498,27 @@ void CSIPPhoneSession::control_video( ControlVideoCommand *pCmd )
 			callparam.remote_width = pCmd->remote_width;
 			callparam.remote_height = pCmd->remote_height;
 
-			rvc_video_render_params_t render_param = { 0 };
-			render_param.ilocal_view_x = pCmd->local_view_x;
-			render_param.ilocal_view_y = pCmd->local_view_y;
-			render_param.ilocal_view_cx = pCmd->local_view_cx;
-			render_param.ilocal_view_cy = pCmd->local_view_cy;
-			render_param.iremote_view_x = pCmd->remote_view_x;
-			render_param.iremote_view_y = pCmd->remote_view_y;
-			render_param.iremote_view_cx = pCmd->remote_view_cx;
-			render_param.iremote_view_cy = pCmd->remote_view_cy;
-			render_param.ilocal_move = pCmd->local_hwd_move;
-			render_param.iremote_move = pCmd->remote_hwd_move;
-			render_param.ilocal_fresh_time = pCmd->local_fresh_time;
-			render_param.iremote_fresh_time = pCmd->remote_fresh_time;
-
 			rvc_video_render_callback_t t_callback = { 0 };
 			t_callback.user_data = m_pEntity;
 			t_callback.on_video_render = &__remote_video_render_callback;
 			Dbg("%s:%d video_render_cb = 0x%08x and video_render_cb->on_video_render = 0x%08x, video_render_cb->user_data = 0x%08x.", __FUNCTION__, __LINE__, &t_callback, t_callback.on_video_render, t_callback.user_data);
 			endpoint_call_start_video(m_pCall, &callparam, &t_callback);
-			start_video_render(&render_param);
+			if (DOUBLERECORD_CALLTYPE != m_pEntity->m_nCallType) {
+				rvc_video_render_params_t render_param = { 0 };
+				render_param.ilocal_view_x = pCmd->local_view_x;
+				render_param.ilocal_view_y = pCmd->local_view_y;
+				render_param.ilocal_view_cx = pCmd->local_view_cx;
+				render_param.ilocal_view_cy = pCmd->local_view_cy;
+				render_param.iremote_view_x = pCmd->remote_view_x;
+				render_param.iremote_view_y = pCmd->remote_view_y;
+				render_param.iremote_view_cx = pCmd->remote_view_cx;
+				render_param.iremote_view_cy = pCmd->remote_view_cy;
+				render_param.ilocal_move = pCmd->local_hwd_move;
+				render_param.iremote_move = pCmd->remote_hwd_move;
+				render_param.ilocal_fresh_time = pCmd->local_fresh_time;
+				render_param.iremote_fresh_time = pCmd->remote_fresh_time;
+				start_video_render(&render_param, false);
+			}
 		} 
 		else {
 			endpoint_call_stop_video(m_pCall);
@@ -2563,7 +2570,7 @@ void CSIPPhoneSession::video_render(VideoRenderCommand_t* pCmd)
 		render_param.ilocal_fresh_time = pCmd->local_fresh_time;
 		render_param.iremote_fresh_time = pCmd->remote_fresh_time;
 
-		start_video_render(&render_param);
+		start_video_render(&render_param, true);
 	}
 	else {
 		stop_video_render();
@@ -2571,24 +2578,27 @@ void CSIPPhoneSession::video_render(VideoRenderCommand_t* pCmd)
 }
 
 
-int CSIPPhoneSession::start_video_render(rvc_video_render_params_t* render_param)
+int CSIPPhoneSession::start_video_render(rvc_video_render_params_t* render_param, bool bremote)
 {
 	m_pEntity->m_render = new rvc_video_render_t();
 	videorender_callback_t t_callback = { 0 };
 	t_callback.debug = &__video_render_log;
+
 	m_pEntity->m_render->plocal_render = CreateVideoRenderObj(&t_callback);
-	Dbg("%s:%d plocal_render = 0x%8x", __FUNCTION__, __LINE__, m_pEntity->m_render->plocal_render);
 	LogWarn(Severity_Middle, Error_Debug, EVENT_MOD_SIP_LOCAL_VIDEO_RENDER_CREATE, "local video render create.");
+
 	m_pEntity->m_render->premote_render = CreateVideoRenderObj(&t_callback);
-	Dbg("%s:%d premote_render = 0x%8x", __FUNCTION__, __LINE__, m_pEntity->m_render->premote_render);
 	LogWarn(Severity_Middle, Error_Debug, EVENT_MOD_SIP_REMOTE_VIDEO_RENDER_CREATE, "remote video render create.");
+
 	memcpy(&m_pEntity->m_render->location_param, render_param, sizeof(rvc_video_render_params_t));
-	
+	m_pEntity->m_render->ui_threadid = 0;
+	m_pEntity->m_render->remote_render_threadid = 0;
+
 	rvc_video_box_move_callback_t t_render_callback = { 0 };
 	t_render_callback.on_video_box_move = &__on_video_box_move;
 	t_render_callback.user_data = this;
 
-	if (Error_Succeed == rvc_start_video_render(m_pEntity->m_render, &t_render_callback)) {
+	if (Error_Succeed == rvc_start_video_render(m_pEntity->m_render, bremote, &t_render_callback)) {
 		Dbg("start video render success.");
 	}
 

+ 0 - 2
Module/mod_sipphone/mod_sipphone.h

@@ -211,8 +211,6 @@ private:
 	SpSubscribeContext<PhoneService_BeginState_Sub, PhoneService_PhoneState_Info>::Pointer m_spCallbackContext;
 	endpoint_call_t *m_pCall;
 	CSIPEntity *m_pEntity;	
-	int m_IsLocalPlay;
-	//eShowVideoWindowType m_VideoWindowPlayType;			/*add by clp 20190903  0:only remote video window, 1:only local video window, 2:both local and remote window */
 };
 
 

+ 141 - 22
Module/mod_sipphone/video_render.cpp

@@ -4,6 +4,7 @@
 #include "../../Other/libvideoframework/videoutil.h"
 #include "../../Other/libvideoqueue/libvideoqueue.h"
 #include "../../Other/rvcmediacommon/rvc_media_common.h"
+#include "fileutil.h"
 
 extern "C"
 {
@@ -13,6 +14,8 @@ extern "C"
 }
 #include "../../Other/libvideoframework/video_common/ffmpeg_api_cpp_adapter.h"
 
+#include "cv.h"
+#include "highgui.h"
 
 static int translate_image_resolution(video_frame** dstframe, const int iwidth, const int iheight, const video_frame* psrcframe)
 {
@@ -58,6 +61,31 @@ static int get_local_video_frame(Clibvideoqueue* local_video_queue, video_frame*
 	return 0;
 }
 
+
+int rvc_start_remote_video_render(rvc_video_render_t* prender, void* videoframe)
+{
+	if (NULL != prender->premote_render) {
+		video_frame* echoframe = NULL;
+		if (0 == translate_image_resolution(&echoframe, prender->location_param.iremote_view_cx, prender->location_param.iremote_view_cy, (const video_frame*)videoframe)) {
+			prender->premote_render->RenderVideoFrame(echoframe, RVC_FLIP_VERTICAL);
+			//session->bshow_remote = true;
+			video_frame_delete(echoframe);
+			echoframe = NULL;
+		}
+		else {
+			prender->premote_render->RenderVideoFrame((video_frame*)videoframe, RVC_FLIP_VERTICAL);
+			//session->bshow_remote = true;
+		}
+	}
+
+	//if (false == session->bremoterender) {
+	//	LogWarn(Severity_Middle, Error_Debug, EVENT_MOD_SIP_REMOTE_VIDEO_RENDER_STARTED, "start remote video render.");
+	//	session->bremoterender = true;
+	//}
+
+	return 0;
+}
+
 void* rvc_videorender_func(void* arg)
 {
 	LOG_FUNCTION();
@@ -164,14 +192,103 @@ void* rvc_videorender_func(void* arg)
 	return 0;
 }
 
+
+void* rvc_remote_videorender_func(void* arg)
+{
+	LOG_FUNCTION();
+
+	rvc_video_render_t* param = (rvc_video_render_t*)arg;
+	int iremote_video_fresh_time = param->location_param.iremote_fresh_time;
+	char strImgPath[MAX_PATH] = { 0 };
+	int irecord_video_frame_width = REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_WIDTH;
+	int irecord_video_frame_heigt = REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_HEIGHT;
+
+	_snprintf(strImgPath, MAX_PATH, "%s", "./bin/agent.jpg");
+
+	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 (ExistsFile(strImgPath))
+	{
+		IplImage* img = cvLoadImage(strImgPath, 1);
+		videoq_frame* vframe = new videoq_frame;
+		if (NULL != img) {
+			Dbg("load img success");
+			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;
+			vframe = NULL;
+		}
+	}
+
+	//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);
+	//	if (rc != Error_Succeed)
+	//	{
+	//		Dbg("insert agent picture to remote video queue.");
+	//	}
+	//}
+
+	video_frame* showframe = NULL;
+	if (-1 == translate_image_resolution(&showframe, param->location_param.iremote_view_cx, param->location_param.iremote_view_cy, remote_frame)) {
+		showframe = video_frame_new(param->location_param.iremote_view_cx, param->location_param.iremote_view_cy, VIDEO_FORMAT_RGB24);
+		video_frame_fill_black(showframe);
+		video_frame_copy(showframe, remote_frame);
+	}
+
+	for (; ; ) {
+		struct timespec ts;
+		clock_gettime(CLOCK_REALTIME, &ts);
+		long unsec = ts.tv_nsec + (1000 * 1000 * iremote_video_fresh_time);
+		ts.tv_sec += (unsec / 1000000000);
+		ts.tv_nsec = (unsec % 1000000000);
+		if (0 != sem_timedwait(&param->remote_render_stop_sem, &ts) && (ETIMEDOUT == errno)){
+			rvc_start_remote_video_render(param, showframe);
+		}
+		else {
+			Dbg("%s:%d record remote video render_func exit!", __FUNCTION__, __LINE__);
+			break;
+		}
+	}
+
+	video_frame_delete(showframe);
+	showframe = NULL;
+
+	return 0;
+}
+
+
 int rvc_start_video_render(rvc_video_render_t* prender, rvc_video_box_move_callback_t* cb)
 {
-	if (0 != sem_init(&prender->ui_stop_sem, 0, 0)) {
-		Dbg("%s:%d create ui stop event failed!", __FUNCTION__, __LINE__);
+	if (0 != sem_init(&prender->ui_stop_sem, 0, 0) || 0 != sem_init(&prender->remote_render_stop_sem, 0, 0)) {
+		Dbg("%s:%d create stop sem failed!", __FUNCTION__, __LINE__);
 		return Error_Resource;
 	}
 	else {
-		Dbg("%s:%d create ui stop event success!", __FUNCTION__, __LINE__);
+		Dbg("%s:%d create stop sem success!", __FUNCTION__, __LINE__);
 	}
 
 	int err = pthread_create(&prender->ui_threadid, NULL, rvc_videorender_func, prender);
@@ -183,6 +300,15 @@ int rvc_start_video_render(rvc_video_render_t* prender, rvc_video_box_move_callb
 		return Error_Resource;
 	}
 
+	err = pthread_create(&prender->remote_render_threadid, NULL, rvc_remote_videorender_func, prender);
+	if (Error_Succeed == err) {
+		Dbg("create video render thread success, thread id is %u.", prender->ui_threadid);
+	}
+	else {
+		Dbg("create video render thread failed.");
+		return Error_Resource;
+	}
+
 	return err;
 }
 
@@ -190,6 +316,9 @@ int rvc_start_video_render(rvc_video_render_t* prender, rvc_video_box_move_callb
 int rvc_stop_video_render(rvc_video_render_t* prender)
 {
 	sem_post(&prender->ui_stop_sem);
+
+	rvc_stop_remote_video_render(prender);
+
 	if (prender->ui_threadid > 0) {
 		if (0 == pthread_join(prender->ui_threadid, NULL)) {
 			Dbg("video render thread %u pthread join success.", prender->ui_threadid);
@@ -205,29 +334,19 @@ int rvc_stop_video_render(rvc_video_render_t* prender)
 	return Error_Succeed;
 }
 
-
-int rvc_start_remote_video_render(rvc_video_render_t* prender, void* videoframe)
+int rvc_stop_remote_video_render(rvc_video_render_t* prender)
 {
-	LOG_FUNCTION();
-	if (NULL != prender->premote_render) {
-		Dbg("session plocal_render RenderVideoFrame");
-		video_frame* echoframe = NULL;
-		if (0 == translate_image_resolution(&echoframe, prender->location_param.iremote_view_cx, prender->location_param.iremote_view_cy, (const video_frame*)videoframe)) {
-			prender->premote_render->RenderVideoFrame(echoframe, RVC_FLIP_VERTICAL);
-			//session->bshow_remote = true;
-			video_frame_delete(echoframe);
-			echoframe = NULL;
+	if (prender->remote_render_threadid > 0) {
+		sem_post(&prender->remote_render_stop_sem);
+		if (0 == pthread_join(prender->remote_render_threadid, NULL)) {
+			Dbg("remote video render thread %u pthread join success.", prender->remote_render_threadid);
+			prender->remote_render_threadid = 0;
 		}
 		else {
-			prender->premote_render->RenderVideoFrame((video_frame*)videoframe, RVC_FLIP_VERTICAL);
-			//session->bshow_remote = true;
+			Dbg("remote video render thread pthread join error for %s.", strerror(errno));
 		}
+		Dbg("remote video render thread exit!");
 	}
 
-	//if (false == session->bremoterender) {
-	//	LogWarn(Severity_Middle, Error_Debug, EVENT_MOD_SIP_REMOTE_VIDEO_RENDER_STARTED, "start remote video render.");
-	//	session->bremoterender = true;
-	//}
-
-	return 0;
+	return Error_Succeed;
 }

+ 8 - 1
Module/mod_sipphone/video_render.h

@@ -3,6 +3,10 @@
 #include "../../Other/libvideorender/ivideorenderinterface.h"
 #include<semaphore.h>
 
+#ifndef MAX_PATH
+#define MAX_PATH 260
+#endif
+
 typedef struct rvc_video_box_move_callback_s {
 	void (*on_video_box_move)(int imessagetype, int ivideotype, int ileft, int ibottom, void* user_data);
 	void* user_data;
@@ -36,10 +40,13 @@ typedef struct rvc_video_render_s {
 	IVideoRender* premote_render;
 	pthread_t ui_threadid;
 	sem_t ui_stop_sem;
+	pthread_t remote_render_threadid;
+	sem_t remote_render_stop_sem;
 	rvc_video_render_params_t location_param;
 }rvc_video_render_t;
 
 
 int rvc_start_video_render(rvc_video_render_t* prender, rvc_video_box_move_callback_t* cb);
 int rvc_stop_video_render(rvc_video_render_t* prender);
-int rvc_start_remote_video_render(rvc_video_render_t* prender, void* videoframe);
+int rvc_start_remote_video_render(rvc_video_render_t* prender, void* videoframe);
+int rvc_stop_remote_video_render(rvc_video_render_t* prender);