在网络上进行摄像头视频通讯

2016-02-19 16:22 35 1 收藏

下面图老师小编要跟大家分享在网络上进行摄像头视频通讯,简单的过程中其实暗藏玄机,还是要细心学习,喜欢还请记得收藏哦!

【 tulaoshi.com - 编程语言 】


     
     
    (转贴请注明原创作者)

      笔者序:也许在写这编文章时,有很多朋友正被老板要求做类似QQ一样的视频聊天软件,在这里,我把自己的一些经验和代码写出来与大家一起分享,高手不要笑我哈!看了这编文章后,你也可以自己做一个简单的网络视频通讯软件,如果自己家里上了网,就可以在公司和家人进行可视通讯了,多爽,不用给电话费了。

        本例子使用的是简的老技术(VFW),开发起来相对简单,以下是Delphi代码,你需要先加入文件,没有这个文件你可以在网上找一下。作者从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.hic0) 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;

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

      于是,服务端的摄像头数据捕捉连接就完成了,那么对于客户端是乍样进行视频数据解压呢?这个问题当然还是通过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);

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  
      最后,当然是视频数据的解压过程

      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

来源:https://www.tulaoshi.com/n/20160219/1611832.html

延伸阅读
360魔法摄像头介绍 请从 →里打开此功能 防护再更新,安全又贴心,木马防火墙3.0新增一层防护摄像头防护2.0。 摄像头防护2.0是旧版摄像头保护的升级版。自旧版摄像头保护推出以来,用户口碑一直较好,但是也有不少用户对旧版摄像头保护提出了许多宝贵的改进建议。我们全面收集了这些用户反馈及建议后,经过安全工程师月...
标签: 电脑入门
现在给大家总结归纳下,方便大家解决类似问题,跟着我一起来操作吧! 方法/步骤 方法一:重启电脑 首先考虑到的是摄像头正在被其他程序独占,无法同时开启QQ视频。如果要使用QQ视频,应该关闭其他正在使用摄像头的程序后重试,其实最简单的方法就是重启; 方法二:检查是否是驱动问题 打开设备管理器看有没有摄像头,如果有,使用qq视...
360魔法摄像头怎么卸载 360魔法摄像头是360安全卫士集成的一款小工具,可根据用户的实际需要来进行安装,那么许多用户体验过这款工具后并不使用,感觉并不是很好玩,又该如何卸载呢?看过下文你就知道答案了。(直接卸载请直接查看4、5两个步骤) 方法/步骤 360魔法摄像头实际上是一款小工具,因此安装的时候可以在360安全卫士...
iPhone7无双摄像头   此前网上曾爆料称下一代iPhone 7将配备后置双摄像头,不过近日有日媒体表示,苹果公司即将推出的iPhone 7在机身正面尺寸和重量上和iPhone  6s相近,4.7英寸的iPhone  7确认不会配双摄像头,但是5.5英寸版本尚为确定,有可能会装备图像公司LinX(苹果于2015年收购)的双摄像头系统。 iPhone 7 ...
标签: 电脑入门
在电脑上安装了摄像头后,在好友的QQ看自己的头像就会在旁边多了一个摄像头小标志,但是这个小小的摄像头就会引来很多麻烦,如经常会接收到很多陌生人的视频聊天请求和验证请求,很麻烦,但我又不能卸载摄像头,因为我还要经常用它和MM聊天呢,有什么办法可以让别人看不见我的摄像头呢? 在最新的QQ2004版本中,我们就可以轻松来让别...

经验教程

88

收藏

42
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部