video_render.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. #include "video_render.h"
  2. #include "SpBase.h"
  3. #include "Event.h"
  4. #include "videoutil.h"
  5. #include "libvideoqueue.h"
  6. #include "rvc_media_common.h"
  7. #include "fileutil.h"
  8. extern "C"{
  9. #include <libavutil/avutil.h>
  10. #include <libavcodec/avcodec.h>
  11. #include <libswscale/swscale.h>
  12. }
  13. #include "video_common/ffmpeg_api_cpp_adapter.h"
  14. #include "cv.h"
  15. #include "highgui.h"
  16. #include "y2k_time.h"
  17. static int translate_image_resolution(video_frame** dstframe, const int iwidth, const int iheight, const video_frame* psrcframe)
  18. {
  19. int i = -1;
  20. if (iwidth == psrcframe->width && iheight == psrcframe->height) {
  21. return i;
  22. }
  23. video_frame* pframe = video_frame_new(iwidth, iheight, VIDEO_FORMAT_RGB24);
  24. video_frame_fill_black(pframe);
  25. SwsContext* sws = sws_getCachedContext(NULL, psrcframe->width, psrcframe->height,
  26. PIX_FMT_BGR24,
  27. iwidth,
  28. iheight,
  29. PIX_FMT_BGR24,
  30. SWS_LANCZOS,
  31. NULL,
  32. NULL,
  33. NULL);
  34. sws_scale(sws, psrcframe->data, psrcframe->linesize, 0, psrcframe->height, pframe->data, pframe->linesize);
  35. sws_freeContext(sws);
  36. *dstframe = pframe;
  37. i = 0;
  38. return i;
  39. }
  40. static int rvc_video_shm_enqueue(Clibvideoqueue* shm_queue, video_frame* frame, int flags, int iframeid)
  41. {
  42. videoq_frame tmp_frm;
  43. tmp_frm.data = frame->data[0];
  44. tmp_frm.framesize = frame->width * frame->height * 3;
  45. tmp_frm.format = VIDEOQ_FORMAT_RGB24;
  46. tmp_frm.width = frame->width;
  47. tmp_frm.height = frame->height;
  48. tmp_frm.iframeid = iframeid;
  49. unsigned int nowtime = y2k_time_now();
  50. if (!shm_queue->InsertVideo(&tmp_frm, flags, nowtime)){
  51. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("caution: rvc render shm_queue video insert shm video failed!");
  52. return Error_Unexpect;
  53. }
  54. else
  55. {
  56. //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("video render shm_queue video insert shm video ok, and nowtime is %d, and frame id is %d.", nowtime, iframeid);
  57. return Error_Succeed;
  58. }
  59. }
  60. static int get_local_video_frame(video_frame** frame, int itype, Clibvideoqueue* local_video_queue, int iwidth, int iheight, IplImage* personimage, IplImage* personmask)
  61. {
  62. video_frame* tmp_frame_preview = NULL;
  63. tmp_frame_preview = video_frame_new(iwidth, iheight, VIDEO_FORMAT_RGB24);
  64. videoq_frame frm;
  65. frm.data = tmp_frame_preview->data[0];
  66. static bool blog = true;
  67. if (blog) {
  68. int ivideo_width = 0;
  69. int ivideo_height = 0;
  70. int isize = local_video_queue->GetFrameSize(ivideo_width, ivideo_height);
  71. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("isize = %d, ivideo_width = %d, ivideo_height = %d.", isize, ivideo_width, ivideo_height);
  72. blog = false;
  73. }
  74. //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("%s:%d, session->video_shm_q_preview = 0x%08x.", __FUNCTION__, __LINE__, local_video_queue);
  75. bool result = local_video_queue->GetVideo(&frm, VIDEOQUEUE_FLAG_HORIZONTAL_FLIP);
  76. if (result){
  77. if (1 == itype) {
  78. if (NULL != personimage && NULL != personmask)
  79. {
  80. IplImage* img = cvCreateImageHeader(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 3);
  81. img->imageData = (char*)frm.data;
  82. if (frm.width != personimage->width) {
  83. IplImage* tmp = cvCreateImage(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 3);
  84. IplImage* tmpmask = cvCreateImage(cvSize(frm.width, frm.height), IPL_DEPTH_8U, 1);
  85. cvResize(personimage, tmp);
  86. cvResize(personmask, tmpmask);
  87. cvAdd(img, tmp, img, tmpmask);
  88. cvReleaseImage(&tmp);
  89. cvReleaseImage(&tmpmask);
  90. }
  91. else {
  92. cvAdd(img, personimage, img, personmask);
  93. }
  94. cvReleaseImageHeader(&img);
  95. }
  96. }
  97. *frame = tmp_frame_preview;
  98. }
  99. return 0;
  100. }
  101. int rvc_remote_video_render(rvc_video_render_t* prender, void* videoframe)
  102. {
  103. if (NULL != prender && NULL != videoframe) {
  104. if (NULL != prender->premote_render) {
  105. video_frame* echoframe = NULL;
  106. if (0 == translate_image_resolution(&echoframe, prender->render_param.iremote_view_cx, prender->render_param.iremote_view_cy, (const video_frame*)videoframe)) {
  107. prender->premote_render->RenderVideoFrame(echoframe, RVC_FLIP_VERTICAL);
  108. video_frame_delete(echoframe);
  109. echoframe = NULL;
  110. }
  111. else {
  112. prender->premote_render->RenderVideoFrame((video_frame*)videoframe, RVC_FLIP_VERTICAL);
  113. }
  114. }
  115. }
  116. return 0;
  117. }
  118. void* rvc_videorender_func(void* arg)
  119. {
  120. rvc_video_render_t* param = (rvc_video_render_t*)arg;
  121. int ilocal_video_fresh_time = param->render_param.ilocal_fresh_time;
  122. int irender_camera = CAMERA_TYPE_ENV;
  123. if (param->render_param.ilocal_view_cx < param->render_param.ilocal_view_cy) {
  124. irender_camera = CAMERA_TYPE_OPT;
  125. }
  126. Clibvideoqueue* local_video_queue = NULL;
  127. RVC_RendererFlip renderflip = RVC_FLIP_VERTICAL;
  128. int iwidth = 0;
  129. int iheight = 0;
  130. if (CAMERA_TYPE_ENV == irender_camera) {
  131. local_video_queue = new Clibvideoqueue(REC_COMMON_VIDEO_ENV_SHM_PREVIEW_QUEUE);
  132. iwidth = REC_COMMON_VIDEO_PREVIEW_WIDTH;
  133. iheight = REC_COMMON_VIDEO_PREVIEW_HEIGHT;
  134. }
  135. else {
  136. local_video_queue = new Clibvideoqueue(REC_COMMON_VIDEO_OPT_SHM_PREVIEW_QUEUE);
  137. iwidth = REC_COMMON_VIDEO_PREVIEW_HEIGHT;
  138. iheight = REC_COMMON_VIDEO_PREVIEW_WIDTH;
  139. renderflip = RVC_FLIP_NONE;
  140. }
  141. int ivideo_width = 0;
  142. int ivideo_height = 0;
  143. int isize = local_video_queue->GetFrameSize(ivideo_width, ivideo_height);
  144. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("%s:%d isize = %d, ivideo_width = %d, ivideo_height = %d.",__FUNCTION__, __LINE__, isize, ivideo_width, ivideo_height);
  145. if (ivideo_width > 0 && ivideo_height > 0) {
  146. iwidth = ivideo_width;
  147. iheight = ivideo_height;
  148. }
  149. char strPersonPath[MAX_PATH] = { 0 };
  150. snprintf(strPersonPath, MAX_PATH, "./bin/rxk.jpg");
  151. IplImage* personimage = NULL;
  152. IplImage* personmask = NULL;
  153. if (ExistsFile(strPersonPath)){
  154. personimage = cvLoadImage(strPersonPath);
  155. personmask = cvLoadImage(strPersonPath, 0);
  156. }
  157. if (NULL != param->plocal_render) {
  158. videorender_param_t tparam = { 0 };
  159. tparam.icx = param->render_param.ilocal_view_x;
  160. tparam.icy = param->render_param.ilocal_view_y;
  161. tparam.uwidth = param->render_param.ilocal_view_cx;
  162. tparam.uheight = param->render_param.ilocal_view_cy;
  163. tparam.ivideoformat = VIDEO_FORMAT_RGB24;
  164. if (0 == param->plocal_render->VideoRenderSetParam(&tparam)) {
  165. param->plocal_render->HideVideoWindow();
  166. }
  167. else {
  168. return 0;
  169. }
  170. }
  171. if (0 != param->render_param.iremote_view_cx && 0 != param->render_param.iremote_view_cy) {
  172. if (NULL != param->premote_render) {
  173. videorender_param_t tparam_remote = { 0 };
  174. tparam_remote.icx = param->render_param.iremote_view_x;
  175. tparam_remote.icy = param->render_param.iremote_view_y;
  176. tparam_remote.uwidth = param->render_param.iremote_view_cx;
  177. tparam_remote.uheight = param->render_param.iremote_view_cy;
  178. tparam_remote.ivideoformat = VIDEO_FORMAT_RGB24;
  179. if (0 != param->premote_render->VideoRenderSetParam(&tparam_remote)) {
  180. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("video render set param failed.");
  181. }
  182. }
  183. else {
  184. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("remote video render is null.");
  185. }
  186. }
  187. if (NULL != param->plocal_render) {
  188. bool bshow_local = false;
  189. bool bset = true;
  190. param->plocal_render->StartVideoRender();
  191. ivideo_width = 0;
  192. ivideo_height = 0;
  193. isize = local_video_queue->GetFrameSize(ivideo_width, ivideo_height);
  194. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("%s:%d isize = %d, ivideo_width = %d, ivideo_height = %d.", __FUNCTION__, __LINE__, isize, ivideo_width, ivideo_height);
  195. for (; ; ) {
  196. struct timespec ts;
  197. clock_gettime(CLOCK_REALTIME, &ts);
  198. long unsec = ts.tv_nsec + (1000 * 1000 * ilocal_video_fresh_time);
  199. ts.tv_sec += (unsec / 1000000000);
  200. ts.tv_nsec = (unsec % 1000000000);
  201. if (0 != sem_timedwait(&param->local_render_stop_sem, &ts) && (ETIMEDOUT == errno))
  202. {
  203. video_frame* local_video_frame = NULL;
  204. int iwindowstate = param->cb.on_window_type(param->cb.user_data);
  205. get_local_video_frame(&local_video_frame, iwindowstate, local_video_queue, iwidth, iheight, personimage, personmask);
  206. if (NULL != local_video_frame) {
  207. video_frame* localframe = NULL;
  208. if (0 == translate_image_resolution(&localframe, param->render_param.ilocal_view_cx, param->render_param.ilocal_view_cy, local_video_frame)) {
  209. param->plocal_render->RenderVideoFrame(localframe, renderflip);
  210. video_frame_delete(localframe);
  211. localframe = NULL;
  212. }
  213. else {
  214. param->plocal_render->RenderVideoFrame(local_video_frame, renderflip);
  215. }
  216. bshow_local = true;
  217. video_frame_delete(local_video_frame);
  218. local_video_frame = NULL;
  219. }
  220. }
  221. else {
  222. param->plocal_render->HideVideoWindow();
  223. break;
  224. }
  225. if (bset) {
  226. if (bshow_local) {
  227. param->plocal_render->ShowVideoWindow();
  228. param->premote_render->ShowVideoWindow();
  229. bset = false;
  230. }
  231. }
  232. }
  233. param->plocal_render->StopVideoRender();
  234. }
  235. if (NULL != personimage) {
  236. cvReleaseImage(&personimage);
  237. }
  238. if (NULL != personmask) {
  239. cvReleaseImage(&personmask);
  240. }
  241. return 0;
  242. }
  243. void* rvc_remote_videorender_func(void* arg)
  244. {
  245. rvc_video_render_t* param = (rvc_video_render_t*)arg;
  246. int iremote_video_fresh_time = param->render_param.iremote_fresh_time;
  247. char strImgPath[MAX_PATH] = { 0 };
  248. int irecord_video_frame_width = REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_WIDTH;
  249. int irecord_video_frame_heigt = REC_COMMON_VIDEO_SNAPSHOT_PREVIEW_HEIGHT;
  250. Clibvideoqueue* video_shm_q_remote = new Clibvideoqueue(REC_COMMON_VIDEO_REMOTE_SHM_RTP_QUEUE);
  251. snprintf(strImgPath, MAX_PATH, "%s", "./bin/agent.jpg");
  252. video_frame* remote_frame = video_frame_new(irecord_video_frame_width, irecord_video_frame_heigt, VIDEO_FORMAT_RGB24);
  253. video_frame_fill_black(remote_frame);
  254. if (ExistsFile(strImgPath)){
  255. IplImage* img = cvLoadImage(strImgPath, 1);
  256. videoq_frame* vframe = new videoq_frame;
  257. if (NULL != img) {
  258. vframe->format = VIDEOQ_FORMAT_RGB24;
  259. vframe->framesize = img->imageSize;
  260. vframe->width = img->width;
  261. vframe->height = img->height;
  262. vframe->data = new unsigned char[img->imageSize];
  263. memcpy(vframe->data, img->imageData, img->imageSize);
  264. cvReleaseImage(&img);
  265. }
  266. SwsContext* sws = sws_getContext(vframe->width, vframe->height, PIX_FMT_BGR24,
  267. irecord_video_frame_width,
  268. irecord_video_frame_heigt,
  269. PIX_FMT_BGR24,
  270. SWS_POINT, NULL, NULL, NULL);
  271. uint8_t* src_data[4] = { (unsigned char*)vframe->data + (vframe->height - 1) * vframe->width * 3, NULL, NULL, NULL };
  272. int src_linesize[4] = { -vframe->width * 3, 0, 0, 0};
  273. unsigned char* dst[4] = { remote_frame->data[0],NULL,NULL,NULL };
  274. int dst_linesize[4] = { remote_frame->linesize[0], 0, 0, 0};
  275. sws_scale(sws, src_data, src_linesize, 0, vframe->height, dst, dst_linesize);
  276. sws_freeContext(sws);
  277. if (vframe) {
  278. delete vframe->data;
  279. delete vframe;
  280. vframe = NULL;
  281. }
  282. }
  283. video_frame* showframe = NULL;
  284. if (-1 == translate_image_resolution(&showframe, param->render_param.iremote_view_cx, param->render_param.iremote_view_cy, remote_frame)) {
  285. showframe = video_frame_new(param->render_param.iremote_view_cx, param->render_param.iremote_view_cy, VIDEO_FORMAT_RGB24);
  286. video_frame_fill_black(showframe);
  287. video_frame_copy(showframe, remote_frame);
  288. }
  289. int iframeid = 0;
  290. int rc = rvc_video_shm_enqueue(video_shm_q_remote, remote_frame, VIDEOQUEUE_FLAG_VERTICAL_FLIP, iframeid++);
  291. if (rc != Error_Succeed) {
  292. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("insert agent picture to remote video queue failed.");
  293. }
  294. for (; ; ) {
  295. struct timespec ts;
  296. clock_gettime(CLOCK_REALTIME, &ts);
  297. long unsec = ts.tv_nsec + (1000 * 1000 * iremote_video_fresh_time);
  298. ts.tv_sec += (unsec / 1000000000);
  299. ts.tv_nsec = (unsec % 1000000000);
  300. if (0 != sem_timedwait(&param->remote_render_stop_sem, &ts) && (ETIMEDOUT == errno)){
  301. rvc_remote_video_render(param, showframe);
  302. if (NULL != video_shm_q_remote){
  303. rc = rvc_video_shm_enqueue(video_shm_q_remote, remote_frame, VIDEOQUEUE_FLAG_VERTICAL_FLIP, iframeid++);
  304. if (rc != Error_Succeed){
  305. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("insert agent picture to remote video queue failed.");
  306. }
  307. }
  308. }
  309. else {
  310. break;
  311. }
  312. }
  313. video_frame_delete(showframe);
  314. showframe = NULL;
  315. video_frame_delete(remote_frame);
  316. remote_frame = NULL;
  317. return 0;
  318. }
  319. int rvc_start_video_render(rvc_video_render_t* prender, bool bremote, rvc_video_box_move_callback_t* cb)
  320. {
  321. if (0 != sem_init(&prender->local_render_stop_sem, 0, 0)) {
  322. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("create local stop sem failed!");
  323. return Error_Resource;
  324. }
  325. int err = pthread_create(&prender->local_render_threadid, NULL, rvc_videorender_func, prender);
  326. if (Error_Succeed != err) {
  327. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("create local video render thread failed.");
  328. return Error_Resource;
  329. }
  330. if (bremote) {
  331. if (0 != sem_init(&prender->remote_render_stop_sem, 0, 0)) {
  332. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("create remote stop sem failed!");
  333. return Error_Resource;
  334. }
  335. err = pthread_create(&prender->remote_render_threadid, NULL, rvc_remote_videorender_func, prender);
  336. if (Error_Succeed != err) {
  337. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("create remote video render thread failed.");
  338. return Error_Resource;
  339. }
  340. }
  341. return err;
  342. }
  343. int rvc_stop_video_render(rvc_video_render_t* prender)
  344. {
  345. if (NULL == prender) {
  346. return Error_Param;
  347. }
  348. sem_post(&prender->local_render_stop_sem);
  349. rvc_stop_remote_video_render(prender);
  350. if (prender->local_render_threadid > 0) {
  351. if (0 == pthread_join(prender->local_render_threadid, NULL)) {
  352. prender->local_render_threadid = 0;
  353. }
  354. else {
  355. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("video render thread pthread join error for %s.", strerror(errno));
  356. }
  357. }
  358. return Error_Succeed;
  359. }
  360. int rvc_stop_remote_video_render(rvc_video_render_t* prender)
  361. {
  362. if (prender->remote_render_threadid > 0) {
  363. sem_post(&prender->remote_render_stop_sem);
  364. if (0 == pthread_join(prender->remote_render_threadid, NULL)) {
  365. prender->remote_render_threadid = 0;
  366. }
  367. else {
  368. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("remote video render thread pthread join error for %s.", strerror(errno));
  369. }
  370. }
  371. return Error_Succeed;
  372. }