基于vfw的局域网语音聊天室系统源码论文

news2024/11/16 12:07:29
    1. 语音视频聊天
      1. UDP套接字的运用

在实现语音视频聊天时,采用的是基于UDP套接字的点对点模式,而UDP面向的是无连接的数据服务,其套接字的使用如图10所示。

 

图10 UDP套接字的使用

      1. 视频的捕获

利用VFW接口,视频捕获可以分为以下几个步骤:

  1. 建立视频采集窗口:该窗口用来接收视频捕捉驱动程序传来的数据和消息。
  2. 连接视频驱动程序:将建立的视频捕捉窗口与视频设备驱动程序相连。
  3. 视频捕获初始化。
  4. 视频捕捉设置:VFW下视频捕捉参数的设置可以通过调用函数或弹出对话框的形式来实现。一般视频驱动程序允许设置的参数包括视频源选择、视频格式、视频显示格式等。
  5. 设置回调函数:通过回调函数来通知程序视频事件的发生,比如捕捉一帧图像成功的消息,捕捉出错的消息等。
  6. 结束捕捉:结束捕捉是应该有一些清除工作。如释放分配的内存,断开捕捉窗口与视频捕捉驱动程序的连接,清除视频捕捉窗口等。

窗口类为捕获数字视频流及其相关操作提供了很大的方便,灵活编写其中的回调函数可满足实时视频传输的需要,例如应用程序可直接从缓冲中取得数字视频并对其进行压缩编码后实时地传到远端的客户端。

在VC++中,采用VFW技术,客户端通过capSetCallbackOnFrame()注册回调函数,当采集卡采集到一幅图像后,系统就会自动调用回调函数,然后再回调函数中使用ICSeqCompressFrame()函数进行压缩。然后再通过Winsock将压缩后的数据发送到另一客户端。该客户端接收完一帧以后,交给ICDecompress()解压,最后用SetDIBitsToDevice()将图像显示出来。

基本的捕获设置包括设置捕获速度(每秒捕获多少帧)、是否同时捕获声频、捕获缓冲、允许最大丢失多少帧和是否使用DOS内存,以及使用键盘的哪个键或鼠标的哪个键来终止捕获等内容,这些设置使用CAPTUREPARAMS结构来描述,capCaptureGetSetup宏来得到当前的设置,然后改变此结构的成员变量,再使用capCaptureSetSetup宏设置新的设置。

设置捕获速度,通过使用capCaptureGetSetup宏来得到当前的捕捉速度,将当前的捕捉速度保存在CAPTUREPARAMS结构的dwRequestMicroSecPerFrame成员变量中,也可以通过设置此变量来改变当前设置值。

设置终止捕获,同样通过使用capCaptureGetSetup宏来得到当前的设置,当前按键设置保存在CAPTUREPARAMS结构的vKeyAbort成员中,鼠标设置保存在fAbortLeftMouse和fAbortRightMouse成员中,通过修改可以设置新的热健或者鼠标左右键,修改完成后,使用capCaptureSetSetup宏来进行更新。

捕获的时间限制,用CAPTUREPARAMS结构中的fLimitEnabled表示捕获是否有时间的限制,wTimeLimit用来设置指示捕获最大的持续时间,其单位为秒。使用capCaptureGetSetup宏来得到当前的设置值。

下面程序为设置CAPTUREPARAMS结构的实现代码:

BOOL VideoCapture::SetCapturePara()

{

CAPTUREPARMS CapParms={0};

capCaptureGetSetup(m_capwnd,&CapParms,sizeof(CapParms));

//得到当前的捕获速度

CapParms.fAbortLeftMouse = FALSE;

CapParms.fAbortRightMouse = FALSE;

CapParms.fYield = TRUE;

CapParms.fCaptureAudio = FALSE;

CapParms.wPercentDropForError = 80;

if(!capCaptureSetSetup(m_capwnd,&CapParms,sizeof(CapParms)))

{

// log.WriteString("\n Failed to set the capture parameters ");

return FALSE;

}

// Set Video Format

capGetVideoFormat(m_capwnd,&m_bmpinfo,sizeof(m_bmpinfo));

m_bmpinfo.bmiHeader.biWidth=IMAGE_WIDTH;

m_bmpinfo.bmiHeader.biHeight=IMAGE_HEIGHT;

BOOL ret=capSetVideoFormat(m_capwnd,&m_bmpinfo,sizeof(m_bmpinfo));

// log.WriteString("\n Video parameters set properly");

return ret;

}

//终止一个捕获任务

BOOL VideoCapture::StopCapture()

{

capCaptureStop(m_capwnd);

capCaptureAbort(m_capwnd);

Sleep(500);

   return TRUE;

}

      1. 捕获窗口

在捕获前必须创建一个捕获窗口(Capture Widnow),下面介绍有关捕获窗口的情况:创建一个AVICap捕获窗口,用capCreateCaptureWindow函数并返回一个句柄。将捕获窗口连接至捕获设备,用capDriverConnect函数来使一个捕获窗口与一个捕获设备连接或关联连接上后,就可以通过捕获窗口向捕获设备发送各种消息,可以使用函数capGetDriverDescription来获得已安装的捕获设备名称及版本,将其列举在实现程序过程中。再利用capDriverGetName函数来得到捕获设备的名称将获得的版本发送到capDriverGetVersion。如果断开捕获窗口与捕获设备的连接用capDriverDisconnect。

捕获窗口的状态,用capGetStatus函数来获得当前捕获窗口的状态,得到一个CAPSTATUS结构的拷贝。该结构的内容包含了图片的尺寸、卷轴的当前位置、overlay和preview是否已设置。由于其信息是动态的,每当捕获的视频流的尺寸发生改变,程序应该在获取捕获设备的视频格式以后及时进行刷新。而捕获窗口尺寸的改变并不影响实际的捕获视频流的尺寸。该尺寸由视频捕获设备的格式和视频对话框决定。

//捕获窗口

BOOL VideoCapture::Initialize()

{

 char devname[128]={0},devversion[128]={0};

     int index=0;

     BOOL ret = TRUE, ret1 = TRUE, ret2 = TRUE, ret3 = TRUE;

     TRACE("VideoCapture::Initialize\n");

     //创建一个AVICap捕获窗口

     m_capwnd = capCreateCaptureWindow("Capture",WS_POPUP,0,0,1,1,0,0);

if(!m_capwnd)

{

return FALSE;

}

//connect callback functions

ret = capSetUserData(m_capwnd,this);

//Change destroy functions also........

    ret1 = capSetCallbackOnVideoStream(m_capwnd,OnCaptureVideo);

    //得到已安装的捕获设备的名称及版本

 ret2 = capGetDriverDescription(index,devname,100,devversion,100);

// Connect to webcam driver

//使一个捕获窗口与一个捕获设备连接或关联

ret3 = capDriverConnect(m_capwnd,index);

if(!(ret && ret1 && ret2 && ret3))

{

// Device may be open already or it may not have been

// closed properly last time.

AfxMessageBox("Unable to open Video Capture Device");

// log.WriteString("\n Unable to connect driver to the window");

m_capwnd=NULL;

return FALSE;

}

// Set the capture parameters

if(SetCapturePara()==FALSE)

{

//   log.WriteString("\n Setting capture parameters failed");

     capDriverDisconnect(m_capwnd); //使捕获窗口与一个捕获设备断开

     return FALSE;

}

return TRUE;

}

      1. 视频捕获驱动

视频捕获必须具有视频捕获驱动才能进行,其相关内容如下:

视频捕获驱动的性能,capDriverGetCap函数得到当前连接视频驱动的硬件性能,该信息保存在CAPDRIVERCAPS结构中;视频对话框,每个视频驱动能够提供4个对话框来控制视频捕获和数字化处理视频对话框定义的视频压缩率和图像品质等。视频对话框都在视频捕获驱动中定义。这个四个对话框分别为:Video Source对话框用于控制选择视频来源(capDlgVideoSource);Video Format对话框定义视频帧的尺寸和精度,以及视频捕获卡的压缩设置(capDlgVideoFormat);Video Display对话框控制在视频捕获期间相关显示器上的显示(capDlgVideoDisplay);Video Compression对话框控制压缩和图像品质(caoDlgVideoCompression)。

      1. 语音录制

在音频的录制和播放时,采用的用户界面线程来处理,是CWinThread对象,根据前面线程的介绍,一步一步的来实现。录音用的一个CWinThread对象CAudioRec来实现,部分实现代码:

LRESULT CAudioRec::OnStartRecording(WPARAM wp, LPARAM lp)

{

if(recording) return FALSE;

//打开录音设备

MMRESULT mmReturn = ::waveInOpen( &m_hRecord, WAVE_MAPPER,

              &m_WaveFormatEx, ::GetCurrentThreadId(), 0, CALLBACK_THREAD);

if(mmReturn!=MMSYSERR_NOERROR ) return FALSE;

if(mmReturn==MMSYSERR_NOERROR )

{

for(int i=0; i < MAXRECBUFFER ; i++)

{

//为录音设备准备缓存

mmReturn = ::waveInPrepareHeader(m_hRecord,

rechead[i], sizeof(WAVEHDR));

//给输入设备增加一个缓存

mmReturn = ::waveInAddBuffer(m_hRecord,

rechead[i], sizeof(WAVEHDR));

}

mmReturn = ::waveInStart(m_hRecord);   //开始录音

if(mmReturn==MMSYSERR_NOERROR ) recording=TRUE;

}

return TRUE;

}

      1. 语音回放

相对录音而言,播放就简单多了,同样用的一个CWinThread对象CAudioPlay来实现,部分实现代码:

LRESULT CAudioPlay::OnWriteSoundData(WPARAM wParam, LPARAM lParam)

{

// TRACE("CAudioPlay::OnWriteSoundData\n");

MMRESULT mmResult = FALSE;

char *p=NULL;

int length=(int) wParam;

if(Playing==FALSE) return FALSE;

if(length<=0) return FALSE;

WAVEHDR *lpHdr=new WAVEHDR;

if(!lpHdr) return FALSE;

p=new char [length];

if(!p) {delete lpHdr;

     return FALSE;}

ZeroMemory(lpHdr,sizeof(WAVEHDR));

ZeroMemory(p,length);

CopyMemory(p,(char*)lParam,length);

lpHdr->lpData=p;

lpHdr->dwBufferLength = length;

mmResult = ::waveOutPrepareHeader(m_hPlay, lpHdr, sizeof(WAVEHDR));

//为回放设备准备内存块

if(mmResult)

{

delete lpHdr;delete p;

return mmResult;

}

mmResult = ::waveOutWrite(m_hPlay, lpHdr, sizeof(WAVEHDR));//写数据(放音)

if(mmResult){delete lpHdr;delete p;

          return mmResult; }

m_Count++;

return MMSYSERR_NOERROR;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/452424.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何把数据库中的数据显示到页面

主要内容&#xff1a;使用JDBC访问数据库中数据&#xff08;Java Web数据可视化案例&#xff09; 文章目录 前期准备&#xff1a;案例&#xff1a;第一步&#xff1a;创建数据库及数据第二步&#xff1a;编写实体类第三步&#xff1a;编写Dao类第四步&#xff1a;编写Servlet代…

SpringBoot中使用redis事务

本文基于SpringBoot 2.X 事务在关系型数据库的开发中经常用到&#xff0c;其实非关系型数据库&#xff0c;比如redis也有对事务的支持&#xff0c;本文主要探讨在SpringBoot中如何使用redis事务。 事务的相关介绍可以参考&#xff1a; 0、起因 在一次线上事故中&#xff0c;我们…

与春相拥,在职读研邂逅中国人民大学与加拿大女王大学金融硕士项目何其有幸

工作几年后的你是否有冒出在职读研的想法&#xff1f;或许你为此纠结了一段时间&#xff0c;在职读研要考虑到的因素众多&#xff0c;年龄、精力分配等&#xff0c;工作几年&#xff0c;经历了职场的磨练&#xff0c;更能知道自己家想要的是什么&#xff0c;对于是否读研会有一…

红海云签约长久数科,引领汽车流通行业人力资源数字化创新

上海铂中数字科技有限公司&#xff08;以下简称“长久数科”&#xff09;是国内领先的数字化汽车供应链服务企业&#xff0c;致力于通过整合客户资源、技术资源、产业链配套资源以及地面服务资源&#xff0c;打造一站式服务的汽车生态大数据SaaS平台。 近日&#xff0c;长久数…

编译原理陈火旺第三版第六章课后题答案

下面的答案仅供参考&#xff01; 1.按照表6.1所示的属性文法&#xff0c;构造表达式(4*71) *2的附注语法树。 答&#xff1a; 首先考虑最底最左边的内部结点,它对应于产生式F→digit,相应的语义规则为F. val: digit.lexval,由于这个结点的子结点digit的属性digit . lexval的…

一文彻底理解Java 17中的新特性密封类

密封类的作用 在面向对象语言中&#xff0c;我们可以通过继承&#xff08;extend&#xff09;来实现类的能力复用、扩展与增强。但有的时候&#xff0c;有些能力我们不希望被继承了去做一些不可预知的扩展。所以&#xff0c;我们需要对继承关系有一些限制的控制手段。而密封类…

android framework-ActivityManagerService(AMS)上

一、SystemServer android-10.0.0_r41\frameworks\base\services\java\com\android\server\SystemServer.java 1.1、startOtherService AMS初始化完成后&#xff0c;会调用systemReady方法。 mActivityManagerService.systemReady(() -> {Slog.i(TAG, "Making service…

springboot +flowable,简单实现工作流基础功能的demo例子

一.简介 对于flowable是什么以及关于此框架的具体信息可以参看此项目的官方文档&#xff1a;https://www.flowable.org/docs/userguide/index.html Flowable is a light-weight business process engine written in Java.这是官网文档对此框架的完美解释&#xff1a;Flowable…

NetApp AFF C 系列全闪存存储解决方案

NetApp AFF C 系列: “C”代表“酷炫”(Cool) 采用最新的容量闪存技术&#xff0c;辅以若干一流的智能技术&#xff0c;您将获得一个经济实惠的闪存解决方案&#xff0c;它重新定义了安全性、可扩展性和可持续性。 为什么选择 AFF C 系列的容量闪存解决方案&#xff1f; 实现…

jmeter获取图片验证码-解密图片并识别

说明&#xff1a; 关于图片验证码的处理方式有三种方法&#xff1a;一是让开发屏蔽验证码&#xff0c;二是让开发后端指定一个万能验证码&#xff0c;三是使用OCR工具进行图片验证码的解密及识别&#xff0c;推荐使用前两种方法最省事&#xff1b; OCRServer工具识别图片验证码…

Netty核心源码分析(二),Netty的Server端接收请求过程源码分析

文章目录 系列文章目录一、连接请求接受过程源码分析1、事件的值2、processSelectedKeys获取事件&#xff08;1&#xff09;doReadMessages方法&#xff08;2&#xff09;pipeline的fireChannelRead方法&#xff08;3&#xff09;ServerBootstrapAcceptor的channelRead方法 3、…

关于数据挖掘和数据集成?

按照数据的生命周期&#xff0c;我们通常将大数据技术分为数据集成、数据存储、批流处理、数据查询与分析、数据调度与编排、数据开发、BI 7 个部分。 可以看到数据集成在数据生命周期最前面的位置&#xff0c;它负责将多个来自不同数据源的数据聚合存放在一个数据存储中&…

分布式任务调度框架Power-Job

分布式任务调度框架的由来及对比 在大型业务业务系统中&#xff0c;不可避免会出现一些需要定时执行需求的场景&#xff0c;例如定时同步数据&#xff0c;定时清洗数据&#xff0c;定时生成报表&#xff0c;大量机器一同执行某个任务&#xff0c;甚至有些需要分布式处理的任务…

中继器+js组件化GIS地图

虽然可以使用JavaScript注入的方式将GIS地图嵌入Axure&#xff0c;但每次使用地图都需要重复嵌入并修改代码&#xff0c;不太方便。那么&#xff0c;能不能实现组件化呢&#xff1f;我们可以使用中继器&#xff08;repeater&#xff09;将常用的地图参数提取出来&#xff0c;通…

力扣题库刷题笔记406-根据身高重建队列

1、题目如下&#xff1a; 2、个人Python代码实现 这里需要单独备注一下截图中第21行代码&#xff1a; 上图可以看到&#xff0c;已经对[5, 2]等元素进行了遍历循环&#xff0c;且[5, 2]左侧确实只存在[7, 0][6, 1]两个元素身高高于他&#xff0c;但是继续[5,0]循环完成后&#…

@Async异步线程:Spring 自带的异步解决方案

前言 在项目应用中&#xff0c;使用MQ异步调用来实现系统性能优化&#xff0c;完成服务间数据同步是常用的技术手段。如果是在同一台服务器内部&#xff0c;不涉及到分布式系统&#xff0c;单纯的想实现部分业务的异步执行&#xff0c;这里介绍一个更简单的异步方法调用。 对于…

FreeRTOS - 计数信号量

一.任务功能 1、修改按键功能&#xff0c;模拟停车位出入功能 2、当按键按下 获取车位 3、当按键抬起 释放车位 二.API接口 函数原型SemaphoreHandle_t xSemaphoreCreateCounting( ①UBaseType_t uxMaxCount,②UBaseType_t uxInitialCount );功能概述创建计数信号量&#xff0c…

详解空气质量API 使用

引言 空气污染是当今世界面临的一大环境问题&#xff0c;而空气质量监测数据是制定环境政策和公众健康计划的重要依据。通过提供空气质量查询 API&#xff0c;开发人员可以方便地获取中国境内多个城市的空气质量数据&#xff0c;从而更好地监测和管理空气质量。 本文将介绍的…

Redis入门学习笔记【一】

目录 一、redis是什么 二、Redis数据结构 2.1 Redis 的五种基本数据类型 2.1.1String&#xff08;字符串&#xff09; 2.1.2字符串列表&#xff08;lists&#xff09; 2.1.3字符串集合&#xff08;sets&#xff09; 2.1.5哈希&#xff08;hashes&#xff09; 2.2 Red…

设计模式详解-软件设计(五十六)

原创 真题详解(UML图)-软件设计&#xff08;五十五)https://blog.csdn.net/ke1ying/article/details/130311994 创建型、结构型、行为型 抽象工厂&#xff08;Abstruct Factory&#xff09; 提供一个创建系列相关或相互依赖的接口&#xff0c;无须指定他们具体的类。 适用于&…