mod_screenshot.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. #include "stdafx.h"
  2. #include "SpBase.h"
  3. #include "screencapture.h"
  4. #include <screencodec.h>
  5. #include "videoutil.h"
  6. #include "rvc_media_common.h"
  7. #include "mod_assistantchannel/AssistantChannel_client_g.h"
  8. using namespace AssistantChannel;
  9. #include "mod_assistantchannel/chan_protocol.h"
  10. #include "mod_assistantchannel/VideoDesc.h"
  11. // add by ly 20150514
  12. #include "jpeg2k.h"
  13. #include "ScreenShot_server_g.h"
  14. #include "cv.h"
  15. #include "highgui.h"
  16. #include "cxcore.h"
  17. #include "CommEntityUtil.hpp"
  18. #include "../include/EventCode.h"
  19. using namespace ScreenShot;
  20. // step 1 screen capture
  21. // step 2 compress using libpng
  22. // step 3 split to 56k each chunk to send out
  23. // future improvement:
  24. // 1. adding 8bit depth color options
  25. // 2. adding business zone options
  26. class CScreenCaptureEntity;
  27. class CScreenShotSession: public ScreenShotService_ServerSessionBase
  28. {
  29. public:
  30. CScreenShotSession(CScreenCaptureEntity* pEntity, int id) : m_id(id), m_pEntity(pEntity)
  31. {
  32. }
  33. virtual void Handle_StartScreenShot(SpReqAnsContext<ScreenShotService_StartScreenShot_Req, ScreenShotService_StartScreenShot_Ans>::Pointer ctx);
  34. virtual void OnClose( ErrorCodeEnum eErrorCode );
  35. private:
  36. int m_id;
  37. CScreenCaptureEntity* m_pEntity;
  38. };
  39. class ChannelClient : public ChannelService_ClientBase
  40. {
  41. public:
  42. ChannelClient(CScreenCaptureEntity *pEntity);
  43. virtual void OnMessage(ErrorCodeEnum Error, ChannelService_State_Info &Msg, CSmartPointer<IReleasable> pData);
  44. virtual void OnMessage(ErrorCodeEnum Error, ChannelService_Packet_Info &Msg, CSmartPointer<IReleasable> pData);
  45. };
  46. int RotationDown(unsigned char* src, int srcW, int srcH, int channel)
  47. {
  48. unsigned char* tempSrc = NULL;
  49. int mSize = srcW * srcH * sizeof(char) * channel;
  50. int i = 0;
  51. int j = 0;
  52. int k = 0;
  53. int desW = 0;
  54. int desH = 0;
  55. desW = srcW;
  56. desH = srcH;
  57. tempSrc = (unsigned char*)malloc(sizeof(char) * srcW * srcH * channel);
  58. memcpy(tempSrc, src, mSize);
  59. for (i = 0; i < desH; i++)
  60. {
  61. for (j = 0; j < desW; j++)
  62. {
  63. for (k = 0; k < channel; k++)
  64. {
  65. //src[(i * desW + j) * channel + k] = tempSrc[((srcH - 1 - i) * srcW + srcW - 1 - j) * channel + k];
  66. src[(i * desW + j) * channel + k] = tempSrc[((srcH - 1 - i) * srcW + j) * channel + k];
  67. }
  68. }
  69. }
  70. free(tempSrc);
  71. return 0;
  72. }
  73. class CScreenCaptureEntity : public CEntityBase,public ILogListener, public ITimerListener
  74. {
  75. public:
  76. CScreenCaptureEntity() : m_enc_session(NULL), m_id_seq(0) {}
  77. virtual ~CScreenCaptureEntity() {}
  78. virtual const char *GetEntityName() const { return "ScreenShot"; }
  79. virtual bool IsService() const { return true; }
  80. virtual CServerSessionBase *OnNewSession(const char* pszRemoteEntityName, const char * pszClass)
  81. {
  82. return new CScreenShotSession(this, m_id_seq++);
  83. }
  84. virtual void OnPreStart(CAutoArray<CSimpleStringA> strArgs,CSmartPointer<ITransactionContext> pTransactionContext)
  85. {
  86. ErrorCodeEnum Error = __OnStart(Error_Succeed);
  87. pTransactionContext->SendAnswer(Error);
  88. }
  89. virtual void OnPreClose(EntityCloseCauseEnum eCloseCause,CSmartPointer<ITransactionContext> pTransactionContext)
  90. {
  91. ErrorCodeEnum Error = __OnClose(Error_Succeed);
  92. pTransactionContext->SendAnswer(Error);
  93. }
  94. virtual void OnLog(const CAutoArray<CUUID> &SubIDs, const CUUID nLogID,const LogTypeEnum eLogType, const SeverityLevelEnum eLevel,
  95. const DWORD dwSysError,const DWORD dwUserCode,const DWORD dwEntityInstanceID, const WORD wEntityDevelID,
  96. const CAutoArray<DWORD> &Param, const char *pszEntityName, const char *pszModuleName,const char *pszMessage, const linkContext& pLinkInfo)
  97. {
  98. if (dwUserCode == LOG_EVT_MOD_ASSISCHAN_STARTED_SUCCESS)
  99. {
  100. Sleep(970);
  101. if (NULL != m_pChannelClient){
  102. m_pChannelClient->GetFunction()->CloseSession();
  103. m_pChannelClient = NULL;
  104. m_bConnectAssist = false;
  105. }
  106. if (Error_Succeed == ConnectAssistChannel()) {
  107. m_bConnectAssist = true;
  108. }
  109. else {
  110. GetFunction()->SetTimer(1, this, 3370);
  111. }
  112. }
  113. }
  114. virtual void OnSelfTest(EntityTestEnum eTestType,CSmartPointer<ITransactionContext> pTransactionContext)
  115. {
  116. if (Test_ShakeHand == eTestType)
  117. {
  118. pTransactionContext->SendAnswer(Error_Succeed);
  119. }
  120. }
  121. ErrorCodeEnum __OnStart(ErrorCodeEnum preOperationError)
  122. {
  123. CSmartPointer<IEntityFunction> pFunc = GetFunction();
  124. int i = 0;
  125. m_arrListener.Init(1);
  126. pFunc->SubscribeLog(m_arrListener[i++], this, Log_Event, Severity_None, Error_IgnoreAll, LOG_EVT_MOD_ASSISCHAN_STARTED_SUCCESS,NULL,false);
  127. if (preOperationError != Error_Succeed)
  128. return preOperationError;
  129. return Error_Succeed;
  130. }
  131. void OnStarted()
  132. {
  133. m_pChannelClient = new ChannelClient(this);
  134. if (Error_Succeed == ConnectAssistChannel()) {
  135. m_bConnectAssist = true;
  136. }
  137. else {
  138. GetFunction()->SetTimer(1, this, 3370);
  139. }
  140. }
  141. ErrorCodeEnum __OnClose(ErrorCodeEnum preOperationError)
  142. {
  143. CSmartPointer<IEntityFunction> spFunction = GetFunction();
  144. for (int i = 0; i < m_arrListener.GetCount(); ++i)
  145. {
  146. spFunction->UnsubscribeLog(m_arrListener[i]);
  147. }
  148. if (preOperationError != Error_Succeed)
  149. return preOperationError;
  150. m_pChannelClient->GetFunction()->CloseSession();
  151. m_pChannelClient = NULL;
  152. return Error_Succeed;
  153. }
  154. ErrorCodeEnum InitCapture()
  155. {
  156. if (m_enc_session) {
  157. screen_encoder_session_destroy(m_enc_session);
  158. m_enc_session = NULL;
  159. }
  160. #ifdef RVC_OS_WIN
  161. int cx = GetSystemMetrics(SM_CXSCREEN);
  162. int cy = GetSystemMetrics(SM_CYSCREEN);
  163. #else
  164. int cx, cy;
  165. getScreenSize(&cx, &cy);
  166. #endif
  167. screen_encoder_session_create(cx, cy, &m_enc_session);
  168. return Error_Succeed;
  169. }
  170. void ExitCapture()
  171. {
  172. if (m_enc_session) {
  173. screen_encoder_session_destroy(m_enc_session);
  174. m_enc_session = NULL;
  175. }
  176. }
  177. void Capture(int id)
  178. {
  179. CSystemStaticInfo SysInfo;
  180. #ifdef RVC_OS_WIN
  181. int cx = GetSystemMetrics(SM_CXSCREEN);
  182. int cy = GetSystemMetrics(SM_CYSCREEN);
  183. #else
  184. int cx, cy;
  185. getScreenSize(&cx, &cy);
  186. #endif
  187. RECT rc = {0, 0, cx, cy};
  188. int size = 0;
  189. int err = screencapture_capture(&rc, NULL, &size);
  190. if (err != 0) {
  191. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("capture screen failed! %d", err);
  192. return;
  193. }
  194. void *buf = malloc(size);
  195. err = screencapture_capture(&rc, buf, &size);
  196. if (err != 0) {
  197. free(buf);
  198. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("capture screen failed! %d", err);
  199. return;
  200. }
  201. if(SysInfo.eScreen == 1)
  202. {
  203. CSimpleStringA strValue;
  204. ErrorCodeEnum Error = GetFunction()->GetSysVar("VideoWindowInitializeParam", strValue);
  205. if (Error == Error_Succeed)
  206. {
  207. int local_view_x;
  208. int local_view_y;
  209. int local_view_cx;
  210. int local_view_cy;
  211. int remote_view_x;
  212. int remote_view_y;
  213. int remote_view_cx;
  214. int remote_view_cy;
  215. ParseVideoViewParam((LPCSTR)strValue, local_view_x, local_view_y, local_view_cx, local_view_cy,
  216. remote_view_x, remote_view_y, remote_view_cx, remote_view_cy);
  217. RECT rcs[] = {
  218. {local_view_x, cy - local_view_y - local_view_cy, local_view_x+local_view_cx, cy - local_view_y},
  219. {remote_view_x, cy - remote_view_y - remote_view_cy, remote_view_x+remote_view_cx, cy - remote_view_y},
  220. };
  221. screencapture_clipoff(cx, cy, buf, 2, rcs);
  222. }
  223. }
  224. #ifndef RVC_OS_WIN
  225. {
  226. //linux需翻转图像
  227. int width = rc.right - rc.left;
  228. int height = rc.bottom - rc.top;
  229. RotationDown((unsigned char*)buf, width, height, 3);
  230. }
  231. #endif
  232. ChannelService_Send_Info Info;
  233. Info.compress = false;
  234. Info.encrypt = false;
  235. Info.type = ACM_TYPE_SRN;
  236. Info.id = id;
  237. Info.sub_type = ACM_SRN_ANS | ACM_SRN_SNAPSHOT;
  238. Info.data.Alloc(size);
  239. screen_encoder_session_encode(m_enc_session, buf, Info.data.m_pData, &Info.data.m_iLength);
  240. (*m_pChannelClient)(EntityResource::getLink().upgradeLink())->Send(Info);
  241. #if 0
  242. int linesize = size / cy;
  243. video_frame tmp_frame;
  244. video_frame_alloc(linesize/3, cy, VIDEO_FORMAT_RGB24, &tmp_frame);
  245. video_frame_fill_black(&tmp_frame);
  246. memcpy(tmp_frame.data[0], buf, size);
  247. video_frame_save_bmpfile("screenshot_abc.bmp", &tmp_frame);
  248. video_frame_free(&tmp_frame);
  249. //video_frame_save_bmpfile("d:\\ab.bmp", &rtp_frame);
  250. #endif
  251. free(buf);
  252. //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("encode size = %d Bytes, time = %d", Info.data.m_iLength, GetTickCount());
  253. }
  254. void Capture1(int id)
  255. {
  256. CSystemStaticInfo SysInfo;
  257. #ifdef RVC_OS_WIN
  258. int cx = GetSystemMetrics(SM_CXSCREEN);
  259. int cy = GetSystemMetrics(SM_CYSCREEN);
  260. #else
  261. int cx, cy;
  262. getScreenSize(&cx, &cy);
  263. #endif
  264. RECT rc = {0, 0, cx, cy};
  265. int size = 0;
  266. int err = screencapture_capture(&rc, NULL, &size);
  267. if (err != 0) {
  268. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("capture screen failed! %d", err);
  269. return;
  270. }
  271. void *buf = malloc(size);
  272. err = screencapture_capture(&rc, buf, &size);
  273. if (err != 0) {
  274. free(buf);
  275. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("capture screen failed! %d", err);
  276. return;
  277. }
  278. if (SysInfo.eScreen == 1) {
  279. CSimpleStringA strValue;
  280. ErrorCodeEnum Error = GetFunction()->GetSysVar("VideoWindowInitializeParam", strValue);
  281. if (Error == Error_Succeed) {
  282. int local_view_x;
  283. int local_view_y;
  284. int local_view_cx;
  285. int local_view_cy;
  286. int remote_view_x;
  287. int remote_view_y;
  288. int remote_view_cx;
  289. int remote_view_cy;
  290. ParseVideoViewParam((LPCSTR)strValue, local_view_x, local_view_y, local_view_cx, local_view_cy,
  291. remote_view_x, remote_view_y, remote_view_cx, remote_view_cy);
  292. RECT rcs[] = {
  293. {local_view_x, cy - local_view_y - local_view_cy, local_view_x+local_view_cx, cy - local_view_y},
  294. {remote_view_x, cy - remote_view_y - remote_view_cy, remote_view_x+remote_view_cx, cy - remote_view_y},
  295. };
  296. screencapture_clipoff(cx, cy, buf, 2, rcs);
  297. }
  298. }
  299. #ifndef RVC_OS_WIN
  300. //linux需翻转图像
  301. int width = rc.right - rc.left;
  302. int height = rc.bottom - rc.top;
  303. //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("size = %d, 3*width*height= %d", size, 3 * width * height);
  304. RotationDown((unsigned char*)buf, width, height, 3);
  305. #endif
  306. ChannelService_Send_Info Info;
  307. Info.compress = false;
  308. Info.encrypt = false;
  309. Info.type = ACM_TYPE_SRN;
  310. Info.id = id;
  311. Info.sub_type = ACM_SRN_ANS | ACM_SRN_SNAPSHOT;
  312. Info.data.Alloc(size);
  313. screencapture_encode(cx, cy, buf, Info.data.m_pData, &Info.data.m_iLength);
  314. (*m_pChannelClient)(EntityResource::getLink().upgradeLink())->Send(Info);
  315. free(buf);
  316. //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("encode size = %d Bytes, time = %d", Info.data.m_iLength, GetTickCount());
  317. }
  318. void Capture2(RECT *lprc, CBlob &image)
  319. {
  320. int width = lprc->right-lprc->left;
  321. int height = lprc->bottom-lprc->top;
  322. int size = 0;
  323. int err = screencapture_capture(lprc, NULL, &size);
  324. if (err != 0) {
  325. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("capture screen failed! %d", err);
  326. return;
  327. }
  328. void *buf = malloc(size);
  329. err = screencapture_capture(lprc, buf, &size);
  330. if (err != 0) {
  331. free(buf);
  332. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("capture screen failed! %d", err);
  333. return;
  334. }
  335. #ifndef RVC_OS_WIN
  336. //linux需翻转图像
  337. //DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("size = %d, 3*width*height= %d", size, 3*width*height);
  338. RotationDown((unsigned char*)buf, width, height, 3);
  339. #endif
  340. // encode with jpeg2k
  341. jpeg2k_coded_image codec_image = {0};
  342. jpeg2k_raw_image raw_image;
  343. raw_image.data = (BYTE*)buf;
  344. raw_image.width = width;
  345. raw_image.height = height;
  346. raw_image.len = raw_image.width * raw_image.height * 3;
  347. int nRet = jpeg2k_encode(&raw_image, &codec_image, 30); // ratio越小质量越好
  348. if (nRet == 0 || nRet == Error_TimeOut)
  349. {
  350. size = codec_image.len;
  351. image.Alloc(size);
  352. memmove(image.m_pData, codec_image.data, size);
  353. //char tmp[MAX_PATH];
  354. //static int seq = 0;
  355. //sprintf(tmp, ".\\jietu_%08d.jp2", seq++);
  356. //FILE *fp = fopen(tmp, "wb");
  357. //if (fp) {
  358. // fwrite(codec_image.data,1,size, fp);
  359. // fclose(fp);
  360. //}
  361. image.Resize(size);
  362. jpeg2k_encode_free(&codec_image);
  363. }
  364. free(buf);
  365. }
  366. private:
  367. ErrorCodeEnum ConnectAssistChannel()
  368. {
  369. if (NULL == m_pChannelClient){
  370. m_pChannelClient = new ChannelClient(this);
  371. }
  372. ErrorCodeEnum Error = m_pChannelClient->Connect();
  373. if (Error != Error_Succeed){
  374. m_pChannelClient = NULL;
  375. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("AssistChannelClient connect fail!");
  376. return Error;
  377. }
  378. if (Error == Error_Succeed){
  379. ChannelService_BeginRecv_Sub Sub;
  380. Sub.type = ACM_TYPE_SRN;
  381. Error = (*m_pChannelClient)(EntityResource::getLink().upgradeLink())->BeginRecv(Sub);
  382. if (Error != Error_Succeed){
  383. m_pChannelClient->GetFunction()->CloseSession();
  384. m_pChannelClient = NULL;
  385. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("BeginRecv ACM_TYPE_SRN fail!");
  386. return Error;
  387. }
  388. }
  389. if (Error == Error_Succeed){
  390. ChannelService_BeginState_Sub Sub;
  391. Error = (*m_pChannelClient)(EntityResource::getLink().upgradeLink())->BeginState(Sub);
  392. if (Error != Error_Succeed){
  393. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("BeginState biz channel failed!");
  394. m_pChannelClient->GetFunction()->CloseSession();
  395. m_pChannelClient = NULL;
  396. return Error;
  397. }
  398. }
  399. return Error;
  400. }
  401. void OnTimeout(DWORD dwTimerID)
  402. {
  403. if (1 == dwTimerID)
  404. {
  405. if (!m_bConnectAssist) {
  406. if (Error_Succeed == ConnectAssistChannel()) {
  407. m_bConnectAssist = true;
  408. }
  409. }
  410. if (m_bConnectAssist) {
  411. GetFunction()->KillTimer(1);
  412. }
  413. }
  414. }
  415. private:
  416. screen_encoder_session_t *m_enc_session;
  417. ChannelClient *m_pChannelClient;
  418. CAutoArray<CUUID> m_arrListener;
  419. int m_id_seq;
  420. bool m_bConnectAssist;
  421. };
  422. void CScreenShotSession::Handle_StartScreenShot(SpReqAnsContext<ScreenShotService_StartScreenShot_Req, ScreenShotService_StartScreenShot_Ans>::Pointer ctx)
  423. {
  424. DbgToBeidou(ctx->link, __FUNCTION__)();
  425. #ifdef RVC_OS_WIN
  426. int cx = GetSystemMetrics(SM_CXSCREEN);
  427. int cy = GetSystemMetrics(SM_CYSCREEN);
  428. #else
  429. int cx, cy;
  430. getScreenSize(&cx, &cy);
  431. #endif
  432. if (ctx->Req.Left < 0 || ctx->Req.Left > cx || ctx->Req.Width <= 0 || ctx->Req.Width > cx ||
  433. ctx->Req.Top < 0 || ctx->Req.Top > cy || ctx->Req.Height <= 0 || ctx->Req.Height > cy)
  434. {
  435. ctx->Answer(Error_Unexpect);
  436. }
  437. RECT rc = {ctx->Req.Left, ctx->Req.Top, ctx->Req.Left + ctx->Req.Width, ctx->Req.Top + ctx->Req.Height};
  438. m_pEntity->Capture2(&rc, ctx->Ans.Image);
  439. if (ctx->Ans.Image.m_iLength == 0)
  440. {
  441. ctx->Answer(Error_Unexpect);
  442. }
  443. else
  444. {
  445. ctx->Answer(Error_Succeed);
  446. }
  447. }
  448. void CScreenShotSession::OnClose( ErrorCodeEnum eErrorCode )
  449. {
  450. }
  451. void ChannelClient::OnMessage(ErrorCodeEnum Error, ChannelService_State_Info &Msg, CSmartPointer<IReleasable> pData)
  452. {
  453. if (Error == Error_Succeed) {
  454. CScreenCaptureEntity *pEntity = static_cast<CScreenCaptureEntity*>(m_pEntityBase);
  455. if (Msg.state == eChannelState_Idle) {
  456. pEntity->ExitCapture();
  457. } else if (Msg.state == eChannelState_Connected) {
  458. pEntity->InitCapture();
  459. }
  460. }
  461. }
  462. void ChannelClient::OnMessage( ErrorCodeEnum Error, ChannelService_Packet_Info &Msg, CSmartPointer<IReleasable> pData )
  463. {
  464. if (Error == Error_Succeed) {
  465. CScreenCaptureEntity *pEntity = static_cast<CScreenCaptureEntity*>(m_pEntityBase);
  466. int cat = ACM_SRN_CAT(Msg.sub_type);
  467. if (cat == ACM_SRN_REQ) {
  468. //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
  469. pEntity->Capture(Msg.id);
  470. //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  471. } else {
  472. _ASSERT(0);
  473. }
  474. }
  475. }
  476. ChannelClient::ChannelClient( CScreenCaptureEntity *pEntity ) : ChannelService_ClientBase(pEntity)
  477. {
  478. }
  479. SP_BEGIN_ENTITY_MAP()
  480. SP_ENTITY(CScreenCaptureEntity)
  481. SP_END_ENTITY_MAP()