国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

在網絡上進行攝像頭視頻通訊

2019-11-18 18:07:47
字體:
來源:轉載
供稿:網友

    文章分類:網絡、視頻,聊天
   
文章作者:廖長科
    (轉貼請注明原創作者)

    筆者序:也許在寫這編文章時,有很多朋友正被老板要求做類似QQ一樣的視頻聊天軟件,在這里,我把自己的一些經驗和代碼寫出來與大家一起分享,高手不要笑我哈!看了這編文章后,你也可以自己做一個簡單的網絡視頻通訊軟件,如果自己家里上了網,就可以在公司和家人進行可視通訊了,多爽,不用給電話費了。

      本例子使用的是簡的老技術(VFW),開發起來相對簡單,以下是Delphi代碼,你需要先加入VFW.PAS文件,沒有這個文件你可以在網上找一下。作者從Delphi4就開始編程,其實Delphi可以做很多事情,只是太多Delphi程序員沒有深專技術和思想,沒有超越自己,Delphi只是一個開發工具,代碼思想是的設計的精髓。
      下面讓我們一起來講解一下:

      在程序的開始,你需要用capCreateCaptureWindow來創建一個攝像頭句柄,
      CapWnd := capCreateCaptureWindow('預覽窗口',WS_VISIBLE or WS_CHILD,0,0,320,240,PRevWnd,1);
      在后面的參數:PrevWnd代表預覽窗口的句柄,你可以指定一個Panel的句柄;320和240代表了窗口的長寬。
    
      if CapWnd = 0 then exit;
      capDriverConnect(CapWnd,0);   //連接攝像頭設備

      capDlgVideoFormat(CapWnd);  //顯示視頻設置對話框,進行配置視頻的大小、顏色位數等。
      capGetVideoFormat(CapWnd,@BmpInInfo,sizeof(BITMAPINFO));  //取得視頻圖像數據頭,后面壓縮時需要用到

      capPreviewRate(CapWnd, 33);  //設置預覽視頻的頻率,33代表第秒30幀。
      capPreview(CapWnd, TRUE);

      capSetCallbackOnFrame(CapWnd,FrameCallBack); 
     
      InitCaptureParams;
     
      最后一句是設置視頻壓縮參數, 后面會進行說明。其中的capSetCallbackOnFrame(CapWnd,FrameCallBack)是設置每幀視頻數據的回調函數,我們就可以將回調時的視頻數據通過網絡進行傳輸,這樣的就實現了視頻聊天的核心了。

    回調函數如下的格式:

    function  FrameCallBack(hWnd: HWND; lpVHdr: PVIDEOHDR): DWord; stdcall;
    var
       bKeyFrame : BOOL ;
       Buf : PBYTE;
       VideoData : TVIDEO_DATA;
       OutActSize : dword;
       i : integer;
    begin
       OutActSize := BmpInInfo.bmiHeader.biSizeImage;
       Buf := ICSeqCompressFrame(@CapVar,0,lpVHdr.lpData,@bKeyFrame,@OutActSize);
      
       //在這里, OutActSize代表壓縮后的視頻數據大小
       //  form1.Label3.Caption := 'Compressed size:'+inttostr(OutActSize);


       //我用的是UDP方式, 因為UDP數據包大小限制, 所以我控制了數據大小, 超出的數據會發生丟幀
       if (OutActSize <= sizeof(videodata.Buf) ) then
       begin
         zeromemory(@VideoData ,sizeof(TVIDEO_DATA));
        
         //記錄是否為關鍵幀
         VideoData.bKeyFrame:=bKeyFrame;


         copymemory(@VideoData.Buf, Buf, OutActSize);
        
         VideoData.SampleNum:=SampleNum; //我們可以記錄下幀數, 可以做擴展用
         VideoData.BufSize:=OutActSize;  //記錄數據大小, 傳輸時用
        
         //在這里, 你可以用你喜歡的網絡方式傳輸視頻數據,
        
         //cc1.SendBuffer(VideoData,sizeof(TVIDEO_DATA)-SendBufferSize+Outactsize);

         inc(SampleNum);
       end;     
       result := 0;
    end;

    其中,PVIDEOHDR類型可以從VFW中看到其定義:
    TVIDEOHDR               = record
        lpData              : PBYTE;  // 視頻數據buffer
        dwBufferLength      : DWORD;  // 數據buffer長度
        dwBytesUsed         : DWORD;               
        dwTimeCaptured      : DWORD;  // 時間長度(毫秒)
        dwUser              : DWORD;               
        dwFlags             : DWORD;               
        dwReserved          : array[0..3] of DWORD;
    end;
    
    在回調函數中, 只用到了視頻函數: ICSeqCompressFrame,可以看到此函數傳入了CapVar參數,這個參數是由我們先前看到的InitCaptureParams函數產生,下面代碼來實現:
    function InitCaptureParams : boolean;
    begin
      result := False;
 
      //初始化CapVar
      zeromemory(@CapVar,sizeof(TCOMPVARS));

      CapVar.cbSize:=sizeof(CapVar); //必須指定cbSize為TCOMPVARS結構大小
      CapVar.dwFlags:=ICMF_COMPVARS_VALID;

      CapVar.cbState:=0;
 
      //fccHandler代表壓縮編碼類型,我們使用的是DIVX的編碼器
      CapVar.fccHandler:=mmioFOURCC('d','i','v','x');
      CapVar.fccType:=ICTYPE_VIDEO;

     
      //正式連接編碼器
      CapVar.hic:=ICOpen(ICTYPE_VIDEO, CapVar.fccHandler, ICMODE_COMPRESS);
    
      if (CapVar.hic>0) then
      begin

        OutFormatSize:=ICCompressGetFormatSize(CapVar.hic,@BmpInInfo.bmiHeader);
        getmem(BmpOutInfo,OutFormatSize);
        
        //我們可以通過初始化時得到的BmpInInfo來獲取壓縮傳出圖像頭BmpOutInfo
        ICCompressGetFormat(CapVar.hic,@BmpInInfo.bmiHeader,@BmpOutInfo^.bmiHeader);
        OutBufferSize:=ICCompressGetSize(CapVar.hic,@BmpInInfo.bmiHeader,@BmpOutInfo^.bmiHeader);
        ICSeqCompressFrameStart(@CapVar, @BmpInInfo);
        result := True;
      end
      else
      begin
        ShowMsg('請先安裝視頻壓縮編碼器');
        Exit;
      end
    end;

    使用之后,如果要斷開編碼器連接,是這樣調用的:
    if (CapVar.hic > 0) then
    begin
       ICSeqCompressFrameEnd(@CapVar);
       ICCompressorFree(@CapVar);
       ICClose(CapVar.hic);
    end;

    于是,服務端的攝像頭數據捕捉連接就完成了,那么對于客戶端是乍樣進行視頻數據解壓呢?這個問題當然還是通過IC函數解決,但你必須先把服務端上的BmpOutinfo和CapVar傳輸到客戶端才行。
   
    接著,一起來看看客戶端的圖像顯示過程:
    //先用取得的CapVar來連接視頻編碼器
    CapVar.hic := ICOpen(CapVar.fccType,CapVar.fccHandler,ICMODE_DECOMPRESS);
   
    //成功后,用服務器傳來的BmpOutInfo當作客戶端的BmpInInfo來取得解壓輸出的圖像頭BmpOutInfo

    OutFormatSize:=ICDecompressGetFormatSize(CapVar.hic,@BmpInInfo.bmiHeader);
    GetMem(BmpOutInfo,OutFormatSize);
    zeromemory(BmpOutInfo,OutFormatSize);

    ICDecompressGetFormat(CapVar.hic, @BmpInInfo.bmiHeader, @BmpOutInfo^.bmiHeader);

    OutBufferSize:=BmpOutInfo^.bmiHeader.biSizeImage;
    getmem(OutBuffer,OutBufferSize);

    zeromemory(OutBuffer,OutBufferSize);
    ICDecompressBegin(CapVar.hic,@BmpInInfo.bmiHeader, @BmpOutInfo^.bmiHeader);


    最后,當然是視頻數據的解壓過程

    if VIDEO_DATA.bKeyFrame then
       Result:=ICDecompress(CapVar.hic,0,@BmpInInfo,@VIDEO_DATA.Buf,
                   @BmpOutInfo.bmiHeader,OutBuffer)
    else
       Result:=ICDecompress(CapVar.hic,ICDECOMPRESS_NOTKEYFRAME,@BmpInInfo,@VIDEO_DATA.Buf,
                   @BmpOutInfo.bmiHeader,OutBuffer);
    if (Result=ICERR_OK) then
    begin
       SetDIBitsToDevice(Canvas.Handle,0,0,bmptmp.Width,bmptmp.Height,0,0,0,BmpOutInfo^.bmiHeader.biHeight ,
                  OutBuffer,BmpOutInfo^,DIB_RGB_COLORS);
    end;

    這樣,傳送過來的視頻數據變直接畫到了Canvas.Handle上了。
    還忘記了服務端關閉攝像頭的方法,調用capDriverDisconnect(CapWnd) 就OK了。

    全文就Over了,jasonke還要說的就是,這個方法是用的微軟的老函數,不過實現起來很簡單,相信會點API的都能開發出來,還有一種方法當然是用DirectShow了喲,這需要你開發Filter,要搞明白微軟的幾個接口,你可以看看DShowNetwork例子。這個方法也有很多C++的兄弟在痛苦的實現,想一想DirectShow的功能真是強大喲,哈哈。

歡迎大家光臨《黑雨共享軟件》,謝謝大家對中國共享軟件的支持

http://brsoft.0033.cn 
http://brsoft.008.net


上一篇:制作從屏幕右下角逐漸彈出的消息提示框

下一篇:如何減小應用程序(EXE)的大小?

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

主站蜘蛛池模板: 大悟县| 石楼县| 长宁区| 垦利县| 时尚| 堆龙德庆县| 隆德县| 泰和县| 姜堰市| 罗城| 共和县| 吴旗县| 和田县| 阿拉善左旗| 甘洛县| 伊金霍洛旗| 卓资县| 江阴市| 普陀区| 黔西县| 肇东市| 南皮县| 渝中区| 平昌县| 土默特左旗| 泸水县| 滦平县| 辽宁省| 绥芬河市| 黄陵县| 六枝特区| 云南省| 鹤壁市| 保康县| 肥东县| 九龙城区| 沂水县| 天祝| 柳河县| 太仓市| 崇明县|