用汇编语言获得摄像头图像
相关的例子:下载>>> 作者:谢平 于2008-4-14上传 

    在开始之前,我必须为《汇编通讯》第五期上《用汇编语言写ESMTP电子邮件发送程序》致歉,可能很多的同学

已经注意到使用附件中的程序登陆不了服务器,如果认真研究过这个问题,我们可以得知服务器返回错误号为0x800CCC18

的'-ERR Not support ntlm auth method'的错误代码,由于程序没有判断服务器的返回值,所以虽然邮件没有发送成功

但是仍然提示“发送成功”。由于忘记了邮箱的密码所以我不知道是不是已经有很多人向我邮箱里抛了无数的鸡蛋和砖头。

在这里我当然要为自己“辩解”一下啦!~~

    其实我试验过了,即使是使用Outlook或者FoxMail之类的软件也是登陆不了smtp服务器的,这可能是邮件服务器为了

安全或者性能方面的因素对于某些帐户不再支持这种登陆方式,如果你对于这个问题的非常了解话,请务必告诉我,也好

同大家分享。
  
    我们进入正题,最近在 http://www.cnasm.com/view.asp?classid=51&newsid=237 看到这篇《VC-摄像头控制SDK源码》,

由于本人是标准的实用主义者,像这么实用的小程序怎么舍得放过?可能同学有以为这只是用Win32asm重写一下别人的代码而已,

哈哈,其实事情远没有如此简单!

    既然是SDK,那么MSDN肯定有相应的内容,不要告诉我你没有装这个,没有的话直接上M**soft的主页去看去

http://www.microsoft.com/msdn/

以下内容节选自MSDN:

    Video Capture
You can easily incorporate video capture capabilities into your application by using the AVICap window class.
AVICap provides applications with a simple, message-based interface to access video and waveform-audio acquisition
hardware and to control the process of streaming video capture to disk.

大意是:

    您可以轻松地把视频捕获功能集成到你的应用程序所使用avicap窗口类。 avicap规定,申请一个简单的,基于消息的接口,

以获取视频和波形音频采集硬件和控制的过程中的视频流捕获到硬盘。

关键词:基于消息。

既然是基于消息,那是不是使用SendMessage函数呢?没错的,就是这样.如果我们继续去看MSDN的话,我们会知道:对于

每一个消息,可以使用一个对应的简单的宏去实现消息的发送,注意啦,这里是宏而不是APi函数。我仿佛听见有很多蔡明在说:

为什么呢?因为Api函数往往在dll文件中被找到,而宏一般是不被定义在dll文件中。这里还有一些问题我们等下会讲到。

所以整个实现的过程就变的简单起来。

按照MSDN的步骤:

创建一个捕获窗口

hWndCap         HINSTANCE ?
invoke    capCreateCaptureWindow, NULL, WS_CHILD or WS_VISIBLE, 、
        0, 0, 640, 480, hWnd, 0
mov    hWndCap,eax
           
然后是将捕获窗同驱动器连接

invoke    SendMessage, hWndCap, WM_CAP_DRIVER_CONNECT, 0, 0

和驱动器链接之后,我们可以枚举一下已安装驱动的版本和名称,当然这个不是必须的

szDeviceName       db 80 dup(0)
szDeviceVersion    db 80 dup(0)
xor    ecx,ecx
@@:           
invoke    capGetDriverDescription, ecx, addr szDeviceName, \
        sizeof szDeviceName, addr szDeviceVersion, sizeof szDeviceVersion
.if    eax != 0
    invoke MessageBox, NULL,addr szDeviceName,addr szDeviceVersion,MB_OK
.endif
inc    ecx
cmp    ecx,10
jl    @B
                       
之后可以获得驱动器的能力,相关的信息放在结构变量CapDriverCaps中

CapDriverCaps    CAPDRIVERCAPS
invoke    SendMessage, hWndCap, WM_CAP_DRIVER_GET_CAPS, \
          sizeof CAPDRIVERCAPS, addr CapDriverCaps
           
然后设置Preview模式的显示速率
invoke    SendMessage, hWndCap, WM_CAP_SET_PREVIEWRATE, 66, 0

启动Preview模式
invoke    SendMessage, hWndCap, WM_CAP_SET_PREVIEW, TRUE, 0

检查驱动器是否有叠加能力
.if    CapDriverCaps.fHasOverlay
    ;启动Overlay模式
    invoke    SendMessage, hWndCap, WM_CAP_SET_OVERLAY, TRUE, 0
.endif
.if    CapDriverCaps.fHasDlgVideoSource
    ;Video source 对话框
    invoke    SendMessage, hWndCap, WM_CAP_DLG_VIDEOSOURCE, 0, 0
.endif
.if    CapDriverCaps.fHasDlgVideoFormat
    ;Video format 对话框
    invoke    SendMessage, hWndCap, WM_CAP_DLG_VIDEOFORMAT, 0, 0
.endif
.if CapDriverCaps.fHasDlgVideoDisplay
    ;Video display 对话框
    invoke    SendMessage, hWndCap, WM_CAP_DLG_VIDEODISPLAY, 0, 0
.endif                
           
获得驱动器的状态,相关的信息放在结构变量CapStatus中

CapStatus        CAPSTATUS
invoke    SendMessage, hWndCap, WM_CAP_GET_STATUS, sizeof CAPSTATUS, addr CapStatus

设置窗口位置和大小

invoke     SetWindowPos, hWndCap, NULL, 100, 100, \
        CapStatus.uiImageWidth, CapStatus.uiImageHeight, SWP_NOMOVE or SWP_NOSIZE
           
设定文件名,这里我们使用的是ASCII的字符串,所以要使用WM_CAP_FILE_SET_CAPTURE_FILEA消息,

如果使用的是UNICODE的话就应该使用WM_CAP_FILE_SET_CAPTURE_FILEW消息啦。

szCaptureFile    db    "CAP.AVI",0
invoke    SendMessage, hWndCap, WM_CAP_FILE_SET_CAPTURE_FILEA, 0, addr szCaptureFile
           
设定文件大小单位为BYTE
invoke    SendMessage, hWndCap, WM_CAP_FILE_ALLOCATE, 0, 1024 * 1024 * 5
           
然后开始捕获
invoke    SendMessage, hWndCap, WM_CAP_SEQUENCE, 0, 0

最后停止捕获
invoke    SendMessage, hWndCap, WM_CAP_ABORT, 0, 0
           
并断开同驱动器的连接
invoke    SendMessage, hWndCap, WM_CAP_DRIVER_DISCONNECT, 0, 0

    整个过程就是这样,在这里我选择了使用对话框作为界面(简单方便啊),在对话框的回调函数里,

我们将“停止捕获”和”断开同驱动器的连接“放在对于WM_CLOSE消息的处理代码中,剩下的全部放在

WM_INITDIALOG消息的处理中。

    细心的同学可能发现,除了capCreateCaptureWindow和capGetDriverDescription两个API,我们使用的

就只有SendMessage这个API了,但是我们之前说过发送的每一个消息都有一个对应的宏,比如WM_CAP_ABORT消息对应

capCaptureAbort宏,既然使用宏要简单一些,我们为什么放着简单的不用呢?

    哈哈,我们之前也说过这些宏在DLL文件中是不存在的,而且masm中并没有这些宏的定义!事实上,更严重的

一个问题是:在vfw32.inc中连这些消息以及涉及到的结构都是没有定义的,所以啊,我们只好做点苦力啦,自己定义试下。

在附件中的vfw32是补充后的inc文件,可以使用它替换include文件夹中的vfw32.inc,(我只是在inc文件的后面添加了

文章中需要的两个结构和一些消息定义,消息定义也不完善,不过能完成今天的试验,所以请某位自告奋勇兼毛遂自荐

完成这个光荣的任务,记得到时提供下载哦,当然最好是mail我一份,代表人民感谢你^_^)。

    然后汇编,链接成功。在这里说一下,本人受罗云彬老师的影响喜欢使用masm包编写一些程序,所以使用别的开发环境的

同学忍受一下啊,不过我尽量做到与开发环境无关了。

    然后当然是运行啦!~~

    奥,糟糕,系统提示“没有找到vfw32.dll”!

原来,在程序中我们使用include vfw32.inc includelib vfw32.lib伪指令,导入的是“vfw32.dll”,但事实上这个dll

文件是不存在的,我的OS是Windows XP SP2,不知道是否每个系统都是如此。

要解决这个问题,还得费一番波折,我解决的过程是:

1.在%system%\system32目录下搜索vfw32.dll,未找到。那会不会那个dll取了一个相似的名字呢?我们进行第二步

2.在%system%\system32目录下搜索vfw32,找到两个msvfw32.dll

那么我们怎么判别这两个是不是我们需要的呢?这里介绍一个工具,Microsoft visual stdio附带的一个叫Depends的工具,

使用它我们可以查看dll文件里的函数,实际上我们也可以自己编写一个这样的工具,在《Windows环境下32位汇编语言程序设计》

第17章有详细的介绍。我们使用这个小工具查看是否有capCreateCaptureWindow和capGetDriverDescription这个两个函数。

结果当然是没有啦。

既然在MSDN中这个叫做Video Capture,而且这两个API都有cap前缀,我们何不试试cap?

3.在%system%\system32目录下搜索cap,找到了一些,我们按照第2步中的方法,最终在avicap32.dll里找到这两个API。

既然这就是我们需要的DLL,那我们怎么使用它呢?

一个最简单的办法是将avicap32.dll复制一份并改名vfw32.dll,放在我们程序的目录中。

到此我们大功告成!当然这一共只涉及到三个API,这三个API都是很简单的一些参数,这里我就不再啰嗦啦,相信聪明的读者

肯定能自己搞定它们的,然后是程序的框架,这里我们用的是对话框而不是窗口,为什么呢?当然是因为对话框实现起来代码少啦。

关于这个框架我想同学们应该是没有问题的吧,什么那位同学你有问题,那自己看罗云彬老师的教材去!

各位同学可以充分发挥自己的想象空间和创造力,写出一个使用的软件当然是最好,鄙人这里就只起一个抛砖引玉的作用啦,

如果你成功了的话,记得到时候发一份到我的邮箱哦!~~

附件中包括vfw32.dll,vfw32.inc,video.asm,video.rc,video.exe,这是所有需要的文件。

有问题,可以联系happyxieping@msn或者happyxieping@163.com。

    【Z.t】:我试验了谢平的程序,非常好用。我用的是罗技的摄像头。程序运行结果如下:

Periodical/20080416/result.PNG (105714 字节)



欢迎访问AoGo汇编小站:http://www.aogosoft.com
下一篇>>>