<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[服务器开发(Server Development)]]></title> 
<link>http://www.doserver.net/index.php</link> 
<description><![CDATA[服务器开发 UDP服务器开发 TCP服务器开发 游戏服务器开发 IOCP 服务器设计]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[服务器开发(Server Development)]]></copyright>
<item>
<link>http://www.doserver.net/post/easyenenrgy.php</link>
<title><![CDATA[关注新能源行业，欢迎访问易源科技]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[生活]]></category>
<pubDate>Wed, 07 Oct 2009 06:07:06 +0000</pubDate> 
<guid>http://www.doserver.net/post/easyenenrgy.php</guid> 
<description>
<![CDATA[ 
	<a href="http://www.yienergy.com" target="_blank">吉林省易源科技有限公司</a>: http://www.yienergy.com<br/><br/>http://www.yienergy.com<br/><br/>太阳能，风能，液流电池，燃料电池，混合动力，核能，风能，其他。<br/>Tags - <a href="http://www.doserver.net/go.php/tags/%25E6%2598%2593%25E6%25BA%2590%25E7%25A7%2591%25E6%258A%2580/" rel="tag">易源科技</a>
]]>
</description>
</item><item>
<link>http://www.doserver.net/post/windows-ce-5-vs2005-net-compact-framework.php</link>
<title><![CDATA[Arm9嵌入式windows ce 5.0系统中基于VS2005的C#程序开发]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[Windows CE]]></category>
<pubDate>Sun, 09 Aug 2009 12:36:53 +0000</pubDate> 
<guid>http://www.doserver.net/post/windows-ce-5-vs2005-net-compact-framework.php</guid> 
<description>
<![CDATA[ 
	最近项目中涉及到了基于Arm9芯片的windows ce 5.0的系统开发.net compact framework 2.0的程序，一些心得以及个别依然在探索的问题。这里分享一下，希望能对搜索到的朋友有所帮助。<br/><br/>基本的步骤如下：<br/><br/>1：单板电脑同计算机相连的时候，会提示需要USB驱动，安装即可。<br/>2：安装microsoft activesync同步软件。<br/>3：wince Arm9硬件特性包，这个如果购买相应的单板电脑，公司会提供。这里是WQ_2440_V02<br/><br/>注意一下：链接的时候，经常不稳定，这个不知道什么原因，偶尔会无故断掉，也会造成机器死机，暂时没有找到相关说明，也不知道是哪里不稳定造成的？但是并不是很影响开发。<br/><br/><br/>创建应用步骤：<br/>1：<br/><a href="http://www.doserver.net/attachment.php?fid=189" target="_blank"><img src="http://www.doserver.net/attachment.php?fid=189" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>2：<br/><a href="http://www.doserver.net/attachment.php?fid=190" target="_blank"><img src="http://www.doserver.net/attachment.php?fid=190" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>3：<br/><a href="http://www.doserver.net/attachment.php?fid=191" target="_blank"><img src="http://www.doserver.net/attachment.php?fid=191" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>4：<br/><a href="http://www.doserver.net/attachment.php?fid=192" target="_blank"><img src="http://www.doserver.net/attachment.php?fid=192" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>同步即可。<br/><br/>此时如果Activesync同单板电脑连接成功，系统会将编译成功的文件送到单板电脑内存中运行。<br/>一些注意的问题，就是部署的问题。<br/><br/>1：单板电脑不安装.net compact framework 2.0也可以同步<br/>2：程序直接拷贝到单板电脑是无法执行的，需要目标单板电脑安装.net compact framework 2.0<br/>3：具体安装.net compact framework 2.0库的方法视单板电脑的厂家不同而不同。<br/><br/><br/>相关的一些资料：<br/><a href="http://hi.baidu.com/span_cookies/blog/item/7104344adf45e82b08f7ef75.html" target="_blank">将VS2005(C#)程序部署到WINCE－zq</a><br/><a href="http://www.microsoft.com/china/msdn/events/webcasts/shared/webcast/consyscourse/WindowsCE.aspx" target="_blank">Windows嵌入式开发系列课程</a><br/><a href="http://www.hzlitai.com.cn/contact/step-by-step.html" target="_blank">相关专业公司</a><br/>Tags - <a href="http://www.doserver.net/go.php/tags/vs2005/" rel="tag">vs2005</a> , <a href="http://www.doserver.net/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.doserver.net/go.php/tags/windowsce/" rel="tag">windowsce</a> , <a href="http://www.doserver.net/go.php/tags/cf2.0/" rel="tag">cf2.0</a>
]]>
</description>
</item><item>
<link>http://www.doserver.net/read.php/2036.htm</link>
<title><![CDATA[团队管理：项目交接]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[服务器开发]]></category>
<pubDate>Sat, 08 Aug 2009 07:12:10 +0000</pubDate> 
<guid>http://www.doserver.net/read.php/2036.htm</guid> 
<description>
<![CDATA[ 
	1：交接内容<br/>&nbsp;&nbsp;1：任务交接<br/>&nbsp;&nbsp;&nbsp;&nbsp;每天汇总一次剩下问题以及处理过问题，形成word报告，提交给上级负责人。<br/>&nbsp;&nbsp;&nbsp;&nbsp;同时必须有进度计划<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;紧急问题，必须在可控制范围内解决。<br/>&nbsp;&nbsp;2：人员安排交接<br/>&nbsp;&nbsp;&nbsp;&nbsp;之前参与项目中各人负责的部分，要指明，以备将来出现问题，继续由谁来调试负责<br/>&nbsp;&nbsp;&nbsp;&nbsp;服务器更新要求，必须本地处理完毕，才更新，对于其他队员更改的代码，也必须本地测试过，才可以服务器上传。<br/>&nbsp;&nbsp;&nbsp;&nbsp;修复试运行都是很小的细节工作，负责人交接要重点说明职责并非负责人要把这些工作做完，而是安排下面的队员完成。项目负责人的交接是对下一个负责人很大的锻炼，必须使得下一任负责人明白，他们的职责所在。<br/>&nbsp;&nbsp;3：客户需求交接<br/>&nbsp;&nbsp;&nbsp;&nbsp;出现需要商妥的问题时候，应该联系何人？同时以何种方式口吻同客户交涉？<br/><br/>Tags - <a href="http://www.doserver.net/go.php/tags/%25E5%259B%25A2%25E9%2598%259F%25E7%25AE%25A1%25E7%2590%2586/" rel="tag">团队管理</a>
]]>
</description>
</item><item>
<link>http://www.doserver.net/post/IDS-uEye-CSharp-Record-AVI.php</link>
<title><![CDATA[uEYE Activex控件在C#环境中如何录制视频]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[.NET]]></category>
<pubDate>Thu, 02 Jul 2009 05:25:16 +0000</pubDate> 
<guid>http://www.doserver.net/post/IDS-uEye-CSharp-Record-AVI.php</guid> 
<description>
<![CDATA[ 
	在一个最近的项目中，由于设备使用了德国IDS公司的镜头设备，在C#没有相关的录制视频的功能，但在VC的开放代码中提供了，另外从uEye中国代理公司获取了一些帮助，感谢这位同仁。<br/><br/>相关知识：<br/>1：需用使用uEye_tools.cs中的代码包含到工程中<br/>2：需要参考uEye Tools Software Interface的帮助<br/><a href="http://www.doserver.net/attachment.php?fid=188" target="_blank"><img src="http://www.doserver.net/attachment.php?fid=188" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>3：上图是程序使用的流程图<br/><br/>下面看相关代码：<br/><br/>相关定义：<br/>[codes=c#]<br/><br/>public uEye_tools tools = null;<br/>tools = new uEye_tools();<br/>[/codes]<br/>开始录制函数：<br/>[codes=c#]<br/>public void StartVideo()<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (flagframe == false)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DateTime dt = DateTime.Now;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string times = string.Format("&#123;0:yyyyMMdd--HHmmss&#125;", dt);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string path = Application.StartupPath + @"&#92;Video&#92;" +&nbsp;&nbsp;times + ".avi";<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LogWrite(textBox1, path + " 录制开始");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.Delete(path);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;axuEyeCam.EnableEvent(0, 1);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flagframe = true;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int e = tools.InitAVI(axuEyeCam.GetCameraID());<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这里一定要注意，帮助上面写的是不对的，帮助上面要求使用Handle，而经过测试要是用CameraID<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int posx = 0, posy = 0;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int nwidth = 0, nheight = 0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int nbits = 0, npitch = 0;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;axuEyeCam.InquireImageMem(ref nwidth, ref nheight, ref nbits, ref npitch);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;axuEyeCam.GetImagePosition(ref posx, ref posy);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int ppitchs = npitch / nbits * 8;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int navix = 0, naviy = 0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;axuEyeCam.GetImageSize(ref navix, ref naviy);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int mode = axuEyeCam.GetColorMode();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tools.SetImageSize(mode, navix, naviy, posx, posy, ppitchs - navix);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int error = tools.OpenAVI(Encoding.ASCII.GetBytes(path));<br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;textBox1.Text += error.ToString();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tools.SetImageQuality(75);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tools.SetFrameRate(axuEyeCam.GetFrameRate());<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;error = tools.StartAVI();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>[/codes]<br/><br/>停止录制函数：<br/>[codes=c#]<br/> public void StopVideo()<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (flagframe == true)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tools.StopAVI();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tools.ExitAVI();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flagframe = false;<br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LogWrite(textBox1," 录制结束");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>[/codes]<br/><br/>下面是关键函数：<br/>[codes=c#]<br/>private int m_MemAddr;<br/> private void axuEyeCam_EventOnFrame(object sender, AxuEyeCamLib._DuEyeCamEvents_EventOnFrameEvent e)<br/>&#123;<br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (flagframe == true)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_MemAddr = System.Convert.ToInt32(axuEyeCam.GetImageMem());<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int ex = tools.AddFrame(new IntPtr(m_MemAddr));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//一定要注意这里的转换<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&#125;<br/>[/codes]<br/>Tags - <a href="http://www.doserver.net/go.php/tags/ids/" rel="tag">ids</a> , <a href="http://www.doserver.net/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.doserver.net/go.php/tags/ueye/" rel="tag">ueye</a>
]]>
</description>
</item><item>
<link>http://www.doserver.net/post/php-5-3.php</link>
<title><![CDATA[PHP5.3发布，Closures and scoping功能]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[PHP]]></category>
<pubDate>Thu, 02 Jul 2009 05:06:30 +0000</pubDate> 
<guid>http://www.doserver.net/post/php-5-3.php</guid> 
<description>
<![CDATA[ 
	PHP5.3的发布修复了5.2版本中所有的bug,同时增加了几个有意思的功能，如namespace,closures，namespace个人觉得不是很喜欢，但是Closure很好玩，以下代码摘自php.net<br/><br/>[codes=php]<br/><?php<br/>// A basic shopping cart which contains a list of added products<br/>// and the quantity of each product. Includes a method which<br/>// calculates the total price of the items in the cart using a<br/>// closure as a callback.<br/>class Cart<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;const PRICE_BUTTER&nbsp;&nbsp;= 1.00;<br/>&nbsp;&nbsp;&nbsp;&nbsp;const PRICE_MILK&nbsp;&nbsp;&nbsp;&nbsp;= 3.00;<br/>&nbsp;&nbsp;&nbsp;&nbsp;const PRICE_EGGS&nbsp;&nbsp;&nbsp;&nbsp;= 6.95;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;&nbsp; $products = array();<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public function add($product, $quantity)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this->products[$product] = $quantity;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public function getQuantity($product)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return isset($this->products[$product]) ? $this->products[$product] :<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FALSE;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public function getTotal($tax)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$total = 0.00;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$callback =<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function ($quantity, $product) use ($tax, &$total)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pricePerItem = constant(__CLASS__ . "::PRICE_" .<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strtoupper($product));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这里很妙，特殊的方式去获取了每个Item的Const值&nbsp;&nbsp;const PRICE_EGGS&nbsp;&nbsp;&nbsp;&nbsp;= 6.95;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$total += ($pricePerItem * $quantity) * ($tax + 1.0);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array_walk($this->products, $callback);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return round($total, 2);;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/><br/>$my_cart = new Cart;<br/><br/>// Add some items to the cart<br/>$my_cart->add('butter', 1);<br/>$my_cart->add('milk', 3);<br/>$my_cart->add('eggs', 6);<br/><br/>// Print the total with a 5% sales tax.<br/>print $my_cart->getTotal(0.05) . "&#92;n";<br/>// The result is 54.29<br/>?> <br/>[/codes]<br/>Tags - <a href="http://www.doserver.net/go.php/tags/php/" rel="tag">php</a>
]]>
</description>
</item><item>
<link>http://www.doserver.net/post/windows-nginx-fastcgi-config.php</link>
<title><![CDATA[windows下配置Nginx和fastcgi应该注意的地方]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[windows]]></category>
<pubDate>Wed, 03 Jun 2009 05:18:17 +0000</pubDate> 
<guid>http://www.doserver.net/post/windows-nginx-fastcgi-config.php</guid> 
<description>
<![CDATA[ 
	上一次配置时候能解析phpinfo()，但是我的网站无法解析，以为配置失败了，便暂时作罢了。这次服务器到位了，也重新检查上次的错误。之后我将贴上所有的配置文件，并解析需要注意的地方。<br/><a href="attachment.php?fid=187">点击这里下载文件</a><br/><br/>相关文件说明：<br/><span style="font-size: 18px;">nginx.conf 是nginx主配置文件<br/>fastcgi_params是fastcgi配置文件<br/>RunHiddenConsole.exe是以服务方式后台启动程序所用，主要用于php-cgi.exe启动<br/>startcgi.bat 是用来启动fastcgi的批处理文件</span><br/>为了能够检测错误，请打开php.ini,设置<br/>[codes=c]<br/>display_errors = On<br/>[/codes]<br/><br/>上次只所以解析网站失败，也是因为这里关闭，没有看出来错误。重新输入网址：<br/>出现错误：<br/><br/>[codes=c]<br/>Fatal error: Call to undefined function mysql_connect() in G:&#92;xampp&#92;htdocs&#92;caeupload&#92;libs&#92;mysql&#92;db_mysql.php on line 7<br/>[/codes]<br/><br/>从错误中，我们可以很明显猜测，应该是mysql的dll在php中配置没有开。<br/>找到<br/>[codes=c]<br/>;extension=php_mysql.dll<br/>[/codes]<br/>打开配置<br/>[codes=c]<br/>extension=php_mysql.dll<br/>[/codes]<br/><br/>解析成功。<br/>下面来看一下全部的配置文件：<br/><br/><span style="font-size: 18px;">nginx.conf文件配置如下：</span><br/>[codes=c]<br/>#user&nbsp;&nbsp;nobody;<br/>worker_processes&nbsp;&nbsp;1;<br/><br/>#error_log&nbsp;&nbsp;logs/error.log;<br/>#error_log&nbsp;&nbsp;logs/error.log&nbsp;&nbsp;notice; <br/>#error_log&nbsp;&nbsp;logs/error.log&nbsp;&nbsp;info;<br/><br/>#pid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logs/nginx.pid;<br/><br/>events &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;worker_connections&nbsp;&nbsp;1024;<br/>&#125;<br/><br/><br/>http &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mime.types;<br/>&nbsp;&nbsp;&nbsp;&nbsp;default_type&nbsp;&nbsp;application/octet-stream;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;sendfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;on;<br/>&nbsp;&nbsp;&nbsp;&nbsp;keepalive_timeout&nbsp;&nbsp;65;<br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;server &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listen&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8080;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server_name&nbsp;&nbsp;localhost;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;charset utf-8;&nbsp;&nbsp;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#access_log&nbsp;&nbsp;logs/host.access.log&nbsp;&nbsp;main;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location / &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp; /cygdrive/g/xampp/htdocs/caeupload;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#非常重要，注意是/cygdrive/g 表示G盘<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;&nbsp;index.html index.htm index.php;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#error_page&nbsp;&nbsp;404&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/404.html;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# redirect server error pages to the static page /50x.html<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;error_page&nbsp;&nbsp; 500 502 503 504&nbsp;&nbsp;/50x.html;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location = /50x.html &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp; html;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location ~ &#92;.php$ &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /cygdrive/g/xampp/htdocs/caeupload;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #这里也注意，和上面一样<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fastcgi_pass&nbsp;&nbsp; 127.0.0.1:9000;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fastcgi_index&nbsp;&nbsp;index.php;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fastcgi_param&nbsp;&nbsp;SCRIPT_FILENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; G:/xampp/htdocs/caeupload$fastcgi_script_name; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #这里注意<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fastcgi_params;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/><br/>&#125;<br/>[/codes]<br/><br/><br/>请特别注意<br/>[codes=c]<br/>root&nbsp;&nbsp; /cygdrive/g/xampp/htdocs/caeupload;&nbsp;&nbsp;#非常重要，注意是/cygdrive/g 表示G盘<br/>[/codes]<br/><br/>以及这两个地方<br/>[codes=c]<br/>location ~ &#92;.php$ &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /cygdrive/g/xampp/htdocs/caeupload;#这里也注意，和上面一样<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fastcgi_pass&nbsp;&nbsp; 127.0.0.1:9000;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fastcgi_index&nbsp;&nbsp;index.php;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fastcgi_param&nbsp;&nbsp;SCRIPT_FILENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; G:/xampp/htdocs/caeupload$fastcgi_script_name; #这里注意<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fastcgi_params;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>[/codes]<br/><br/><span style="font-size: 18px;">fastcgi_params的配置如下：</span><br/>[codes=c]<br/><br/>fastcgi_param&nbsp;&nbsp;QUERY_STRING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $query_string;<br/>fastcgi_param&nbsp;&nbsp;REQUEST_METHOD&nbsp;&nbsp;&nbsp;&nbsp; $request_method;<br/>fastcgi_param&nbsp;&nbsp;CONTENT_TYPE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $content_type;<br/>fastcgi_param&nbsp;&nbsp;CONTENT_LENGTH&nbsp;&nbsp;&nbsp;&nbsp; $content_length;<br/><br/>fastcgi_param&nbsp;&nbsp;SCRIPT_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fastcgi_script_name;<br/>fastcgi_param&nbsp;&nbsp;REQUEST_URI&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$request_uri;<br/>fastcgi_param&nbsp;&nbsp;DOCUMENT_URI&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $document_uri;<br/>fastcgi_param&nbsp;&nbsp;DOCUMENT_ROOT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$document_root;<br/>fastcgi_param&nbsp;&nbsp;SERVER_PROTOCOL&nbsp;&nbsp;&nbsp;&nbsp;$server_protocol;<br/><br/>fastcgi_param&nbsp;&nbsp;GATEWAY_INTERFACE&nbsp;&nbsp;CGI/1.1;<br/>fastcgi_param&nbsp;&nbsp;SERVER_SOFTWARE&nbsp;&nbsp;&nbsp;&nbsp;nginx/$nginx_version;<br/><br/>fastcgi_param&nbsp;&nbsp;REMOTE_ADDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$remote_addr;<br/>fastcgi_param&nbsp;&nbsp;REMOTE_PORT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$remote_port;<br/>fastcgi_param&nbsp;&nbsp;SERVER_ADDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$server_addr;<br/>fastcgi_param&nbsp;&nbsp;SERVER_PORT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$server_port;<br/>fastcgi_param&nbsp;&nbsp;SERVER_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$server_name;<br/><br/># PHP only, required if PHP was built with --enable-force-cgi-redirect<br/>fastcgi_param&nbsp;&nbsp;REDIRECT_STATUS&nbsp;&nbsp;&nbsp;&nbsp;200;<br/><br/>[/codes]<br/>Tags - <a href="http://www.doserver.net/go.php/tags/windows/" rel="tag">windows</a> , <a href="http://www.doserver.net/go.php/tags/nginx/" rel="tag">nginx</a> , <a href="http://www.doserver.net/go.php/tags/fastcgi/" rel="tag">fastcgi</a>
]]>
</description>
</item><item>
<link>http://www.doserver.net/read.php/2031.htm</link>
<title><![CDATA[用Directshow进行视频开发的一些技术[zz]]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[开发语言]]></category>
<pubDate>Sun, 31 May 2009 06:25:50 +0000</pubDate> 
<guid>http://www.doserver.net/read.php/2031.htm</guid> 
<description>
<![CDATA[ 
	原文地址：http://blog.csdn.net/aoosang/archive/2005/05/26/381148.aspx<br/>可惜所有图片丢失，我四处搜索才找到原文，另外代码我特殊处理了一下，稍微好看一点，感谢作者的精彩文章<br/><br/>本篇文档主要描述关于用Directshow进行视频开发的一些技术<br/>主要包括下面内容<br/><br/><span style="color: #FF0000;">1关于视频捕捉（About Video Capture in Dshow） <br/>2选择一个视频捕捉设备（Select capture device） <br/>3预览视频（Previewing Video） <br/>4如何捕捉视频流并保存到文件（Capture video to File） <br/>5将设备从系统中移走时的事件通知（Device remove Notify） <br/>6如何控制Capture Graph（Controlling Capture Graph） <br/>7如何配置一个视频捕捉设备 <br/>8从静止图像pin中捕捉图片 </span><br/><br/><br/><br/><span style="color: #0000FF;">1关于视频捕捉（About Video Capture in Dshow）</span><br/><br/>1视频捕捉Graph的构建<br/>一个能够捕捉音频或者视频的graph图都称之为捕捉graph图。捕捉graph图比一般的文件回放graph图要复杂许多，dshow提供了一个Capture Graph Builder COM组件使得捕捉graph图的生成更加简单。Capture Graph Builder提供了一个ICaptureGraphBuilder2接口，这个接口提供了一些方法用来构建和控制捕捉graph。<br/>首先创建一个Capture Graph Builder对象和一个graph manger对象，然后用filter graph manager 作参数，调用ICaptureGraphBuilder2::SetFiltergraph来初始化Capture Graph Builder。看下面的代码把<br/>[codes=c]<br/>HRESULT InitCaptureGraphBuilder(<br/>IGraphBuilder **ppGraph, // Receives the pointer.<br/>ICaptureGraphBuilder2 **ppBuild // Receives the pointer.<br/>)<br/>&#123;<br/>if (!ppGraph &#124;&#124; !ppBuild)<br/>&#123;<br/>return E_POINTER;<br/>&#125;<br/>IGraphBuilder *pGraph = NULL;<br/>ICaptureGraphBuilder2 *pBuild = NULL;<br/> // Create the Capture Graph Builder.<br/>&nbsp;&nbsp;HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, <br/>&nbsp;&nbsp;CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pGraph);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Create the Filter Graph Manager.<br/>&nbsp;&nbsp;hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,<br/>&nbsp;&nbsp;IID_IGraphBuilder, (void**)&pGraph);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Initialize the Capture Graph Builder.<br/>&nbsp;&nbsp;pBuild->SetFiltergraph(pGraph);<br/> // Return both interface pointers to the caller.<br/>&nbsp;&nbsp;*ppBuild = pBuild;<br/>&nbsp;&nbsp;*ppGraph = pGraph; // The caller must release both interfaces.<br/>&nbsp;&nbsp;return S_OK;<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;pBuild->Release();<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;return hr; // Failed<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/><span style="color: #0000FF;">2视频捕捉的设备</span><br/>现在许多新的视频捕捉设备都采用的是WDM驱动方法，在WDM机制中，微软提供了一个独立于硬件设备的驱动，称为类驱动程序。驱动程序的供应商提供的驱动程序称为minidrivers。Minidrivers提供了直接和硬件打交道的函数，在这些函数中调用了类驱动。<br/>在directshow的filter图表中，任何一个WDM捕捉设备都是做为一个WDM Video Capture<br/>过滤器（Filter）出现。WDM Video Capture过滤器根据驱动程序的特征构建自己的filter <br/><br/>下面是陆其明的一篇有关于dshow和硬件的文章，可以拿来参考一下<br/><br/>//陆文章开始 <br/>大家知道，为了提高系统的稳定性，Windows操作系统对硬件操作进行了隔离；应用程序一般不能直接访问硬件。DirectShow Filter工作在用户模式（User mode，操作系统特权级别为Ring 3），而硬件工作在内核模式（Kernel mode，操作系统特权级别为Ring 0），那么它们之间怎么协同工作呢？<br/><br/>DirectShow解决的方法是，为这些硬件设计包装Filter；这种Filter能够工作在用户模式下，外观、控制方法跟普通Filter一样，而包装Filter内部完成与硬件驱动程序的交互。这样的设计，使得编写DirectShow应用程序的开发人员，从为支持硬件而需做出的特殊处理中解脱出来。DirectShow已经集成的包装Filter，包括Audio Capture Filter（qcap.dll）、VfW Capture Filter（qcap.dll，Filter的Class Id为CLSID_VfwCapture）、TV Tuner Filter（KSTVTune.ax，Filter的Class Id为CLSID_CTVTunerFilter）、Analog Video Crossbar Filter（ksxbar.ax）、TV Audio Filter（Filter的Class Id为CLSID_TVAudioFilter）等；另外，DirectShow为采用WDM驱动程序的硬件设计了KsProxy Filter（Ksproxy.ax,）。我们来看一下结构图：<br/><br/><span style="color: #FF4500;">图已经丢失</span> <br/>从上图中，我们可以看出，Ksproxy.ax、Kstune.ax、Ksxbar.ax这些包装Filter跟其它普通的DirectShow Filter处于同一个级别，可以协同工作；用户模式下的Filter通过Stream Class控制硬件的驱动程序minidriver（由硬件厂商提供的实现对硬件控制功能的DLL）；Stream Class和minidriver一起向上层提供系统底层级别的服务。值得注意的是，这里的Stream Class是一种驱动模型，它负责调用硬件的minidriver；另外，Stream Class的功能还在于协调minidriver之间的工作，使得一些数据可以直接在Kernel mode下从一个硬件传输到另一个硬件（或同一个硬件上的不同功能模块），提高了系统的工作效率。（更多的关于底层驱动程序的细节，请读者参阅Windows DDK。）<br/><br/>下面，我们分别来看一下几种常见的硬件。<br/>VfW视频采集卡。这类硬件在市场上已经处于一种淘汰的趋势；新生产的视频采集卡一般采用WDM驱动模型。但是，DirectShow为了保持向后兼容，还是专门提供了一个包装Filter支持这种硬件。和其他硬件的包装Filter一样，这种包装Filter的创建不是像普通Filter一样使用CoCreateInstance，而要通过系统枚举，然后BindToObject。<br/><br/>音频采集卡（声卡）。声卡的采集功能也是通过包装Filter来实现的；而且现在的声卡大部分都有混音的功能。这个Filter一般有几个Input pin，每个pin都代表一个输入，如Line In、Microphone、CD、MIDI等。值得注意的是，这些pin代表的是声卡上的物理输入端子，在Filter Graph中是永远不会连接到其他Filter上的。声卡的输出功能，可以有两个Filter供选择：DirectSound Renderer Filter和Audio Renderer (WaveOut) Filter。注意，这两个Filter不是上述意义上的包装Filter，它们能够同硬件交互，是因为它们使用了API函数：前者使用了DirectSound API，后者使用了waveOut API。这两个Filter的区别，还在于后者输出音频的同时不支持混音。（顺便说明一下，Video Renderer Filter能够访问显卡，也是因为使用了GDI、DirectDraw或Direct3D API。）如果你的机器上有声卡的话，你可以通过GraphEdit，在Audio Capture Sources目录下看到这个声卡的包装Filter。<br/><br/>WDM驱动的硬件（包括视频捕捉卡、硬件解压卡等）。这类硬件都使用Ksproxy.ax这个包装Filter。Ksproxy.ax实现了很多功能，所以有“瑞士军刀”的美誉；它还被称作为“变色龙Filter”，因为该Filter上定义了统一的接口，而接口的实现因具体的硬件驱动程序而异。在Filter Graph中，Ksproxy Filter显示的名字为硬件的Friendly name（一般在驱动程序的.inf文件中定义）。我们可以通过GraphEdit，在WDM Streaming开头的目录中找到本机系统中安装的WDM硬件。因为KsProxy.ax能够代表各种WDM的音视频设备，所以这个包装Filter的工作流程有点复杂。这个Filter不会预先知道要代表哪种类型的设备，它必须首先访问驱动程序的属性集，然后动态配置Filter上应该实现的接口。当Ksproxy Filter上的接口方法被应用程序或其他Filter调用时，它会将调用方法以及参数传递给驱动程序，由驱动程序最终完成指定功能。除此以外，WDM硬件还支持内核流（Kernel Streaming），即内核模式下的数据传输，而无需经过到用户模式的转换。因为内核模式与用户模式之间的相互转换，需要花费很大的计算量。如果使用内核流，不仅可以避免大量的计算，还避免了内核数据与主机内存之间的拷贝过程。在这种情况下，用户模式的Filter Graph中，即使pin之间是连接的，也不会有实际的数据流动。典型的情况，如带有Video Port Pin的视频捕捉卡，Preview时显示的图像就是在内核模式下直接传送到显卡的显存的。所以，你也休想在VP Pin后面截获数据流。<br/><br/>讲到这里，我想大家应该对DirectShow对硬件的支持问题有了一个总体的认识。对于应用程序开发人员来说，这方面的内容不用研究得太透，而只需作为背景知识了解一下就好了。其实，大量繁琐的工作DirectShow已经帮我们做好了。<br/>//陆其明文章结束 <br/><br/>Direcshow中视频捕捉的Filter<br/>Pin的种类<br/>捕捉Filter一般都有两个或多个输出pin，他们输出的媒体类型都一样，比如预览pin和捕捉pin，因此根据媒体类型就不能很好的区别这些pin。此时就要根据pin的功能来区别每个pin了，每个pin都有一个GUID，称为pin的种类。<br/>如果想仔细的了解pin的种类，请看后面的相关内容Working with Pin Categories。对于大多数的应用来说，ICaptureGraphBuilder2提供了一些函数可以自动确定pin的种类。<br/>预览pin和捕捉pin<br/>视频捕捉Filter都提供了预览和捕捉的输出pin，预览pin用来将视频流在屏幕上显示，捕捉pin用来将视频流写入文件。<br/>预览pin和输出pin有下面的区别：<br/>1 为了保证捕捉pin对视频桢流量，预览pin必要的时候可以停止。<br/>2 经过捕捉pin的视频桢都有时间戳，但是预览pin的视频流没有时间戳。<br/>预览pin的视频流之所以没有时间戳的原因在于filter图表管理器在视频流里加一个很小的latency，如果捕捉时间被认为就是render时间的话，视频renderFilter就认为视频流有一个小小的延迟，如果此时render filter试图连续播放的时候，就会丢桢。去掉时间戳就保证了视频桢来了就可以播放，不用等待，也不丢桢。<br/>预览pin的种类GUID为PIN_CATEGORY_PREVIEW<br/>捕捉pin的种类GUID为PIN_CATEGORY_CAPTURE<br/>Video Port pin<br/>Video Port是一个介于视频设备（TV）和视频卡之间的硬件设备。同过Video Port，视频数据可以直接发送到图像卡上，通过硬件的覆盖，视频可以直接在屏幕显示出来。Video Port就是连接两个设备的。<br/>使用Video Port的最大好处是，不用CPU的任何工作，视频流直接写入内存中。当然它也有下面的缺点drawbacks：<br/>略<br/>如果捕捉设备使用了Video Port，捕捉Filter就用一个video port pin代替预览pin。<br/>video port pin的种类GUID为PIN_CATEGORY_VIDEOPORT<br/>一个捕捉filter至少有一个Capture pin，另外，它可能有一个预览pin 和一个video port pin<br/>，或者两者都没有，也许filter有很多的capture pin，和预览pin，每一个pin都代表一种媒体类型，因此一个filter可以有一个视频capture pin，视频预览pin，音频捕捉pin，音频预览pin。<br/>Upstream WDM Filters<br/>在捕捉Filter之上，WDM设备可能需要额外的filters，下面就是这些filter<br/>TV Tuner Filter<br/>TV Audio Filter.<br/>Analog Video Crossbar Filter<br/>尽管这些都是一些独立的filter，但是他们可能代表的是同一个硬件设备，每个filter都控制设备的不同函数，这些filter通过pin连接起来，但是在pin中没有数据流动。因此，这些pin 的连接和媒体类型无关。他们使用一个GUID值来定义一个给定设备的minidriver，例如：TV tuner Filter 和video capture filter都支持同一种medium。<br/>在实际应用中，如果你使用ICaptureGraphBuilder2来创建你的capture graphs，这些filters就会自动被添加到你的graph中。更多的详细资料，可以参考WDM Class Driver Filters<br/><br/><span style="color: #0000FF;">2选择一个视频捕捉设备（Select capture device）</span><br/><br/>如何选择一个视频捕捉设备，可以采用系统设备枚举，详细资料参见Using the System Device Enumerator 。enumerator可以根据filter的种类返回一个设备的monikers。Moniker是一个com对象，可以参见IMoniker的SDK。<br/>对于捕捉设备，下面两种类是相关的。<br/>CLSID_AudioInputDeviceCategory 音频设备<br/>CLSID_VideoInputDeviceCategory 视频设备<br/>下面的代码演示了如何枚举一个视频捕捉设备<br/><br/>[codes=c]<br/>&nbsp;&nbsp;ICreateDevEnum *pDevEnum = NULL;<br/>&nbsp;&nbsp;IEnumMoniker *pEnum = NULL;<br/>// Create the System Device Enumerator.<br/>&nbsp;&nbsp;HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,<br/>&nbsp;&nbsp;CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, <br/>&nbsp;&nbsp;reinterpret_cast<void**>(&pDevEnum));<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;//创建一个枚举器，枚举视频设备<br/>&nbsp;&nbsp;hr = pDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,<br/>&nbsp;&nbsp;&pEnum, 0);<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/>IEnumMoniker接口pEnum返回一个IMoniker接口的列表，代表一系列的moniker，你可以显示所有的设备，然后让用户选择一个。<br/>采用IMoniker::BindToStorage方法，返回一个IPropertyBag接口指针。然后调用IPropertyBag::Read读取moniker的属性。下面看看都包含什么属性<br/>1 FriendlyName 是设备的名字<br/>2 Description 属性仅仅适用于DV和D-VHS/MPEG摄象机，如果这个属性可用，这个属性更详细的描述了设备的资料<br/>3DevicePath 这个属性是不可读的，但是每个设备都有一个独一无二的。你可以用这个属性来区别同一个设备的不同实例<br/>下面的代码演示了如何显示遍历设备的名称 ，接上面的代码<br/>[codes=c]<br/>HWND hList; // Handle to the list box.<br/>&nbsp;&nbsp;IMoniker *pMoniker = NULL;<br/>&nbsp;&nbsp;while (pEnum->Next(1, &pMoniker, NULL) == S_OK)<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;IPropertyBag *pPropBag;<br/>&nbsp;&nbsp;hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, <br/>&nbsp;&nbsp;(void**)(&pPropBag));<br/>&nbsp;&nbsp;if (FAILED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;pMoniker->Release();<br/>&nbsp;&nbsp;continue; // Skip this one, maybe the next one will work.<br/>&nbsp;&nbsp;&#125; <br/>&nbsp;&nbsp;// Find the description or friendly name.<br/>&nbsp;&nbsp;VARIANT varName;<br/>&nbsp;&nbsp;VariantInit(&varName);<br/>&nbsp;&nbsp;hr = pPropBag->Read(L"Description", &varName, 0);<br/>&nbsp;&nbsp;if (FAILED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;hr = pPropBag->Read(L"FriendlyName", &varName, 0);<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Add it to the application's list box.<br/>&nbsp;&nbsp;USES_CONVERSION;<br/>&nbsp;&nbsp;(long)SendMessage(hList, LB_ADDSTRING, 0, <br/>&nbsp;&nbsp;(LPARAM)OLE2T(varName.bstrVal));<br/>&nbsp;&nbsp;VariantClear(&varName); <br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;pPropBag->Release();<br/>&nbsp;&nbsp;pMoniker->Release();<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/>如果用户选中了一个设备调用IMoniker::BindToObject为设备生成filter，然后将filter加入到graph中。<br/>[codes=c]<br/>IBaseFilter *pCap = NULL;<br/>&nbsp;&nbsp;hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;hr = m_pGraph->AddFilter(pCap, L"Capture Filter");<br/>&nbsp;&nbsp;&#125;<br/><br/>[/codes]<br/><span style="color: #0000FF;">3预览视频（Previewing Video）</span><br/><br/>为了创建可以预览视频的graph，可以调用下面的代码<br/>[codes=c]<br/>ICaptureGraphBuilder2 *pBuild; // Capture Graph Builder<br/>&nbsp;&nbsp;// Initialize pBuild (not shown).<br/>IBaseFilter *pCap; // Video capture filter.<br/>&nbsp;&nbsp;/* Initialize pCap and add it to the filter graph (not shown). */<br/>hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, <br/>&nbsp;&nbsp;pCap, NULL, NULL);<br/><br/>[/codes]<br/><span style="color: #0000FF;">4如何捕捉视频流并保存到文件（Capture video to File）</span><br/><br/>1 将视频流保存到AVI文件<br/>下面的图表显示了graph图<br/><br/>图2<br/>AVI Mux filter接收从capture pin过来的视频流，然后将其打包成AVI流。音频流也可以连接到AVI Mux Filter上，这样mux filter就将视频流和视频流合成AVI流。File writer将AVI流写入到文件中。<br/>可以像下面这样构建graph图<br/>[codes=c]<br/>IBaseFilter *pMux;<br/>&nbsp;&nbsp;hr = pBuild->SetOutputFileName(<br/>&nbsp;&nbsp;&MEDIASUBTYPE_Avi, // Specifies AVI for the target file.<br/>&nbsp;&nbsp;L"C:&#92;&#92;Example.avi", // File name.<br/>&nbsp;&nbsp;&pMux, // Receives a pointer to the mux.<br/>&nbsp;&nbsp;NULL); // (Optional) Receives a pointer to the file sink.<br/>[/codes]<br/>第一个参数表明文件的类型，这里表明是AVI，第二个参数是制定文件的名称。对于AVI文件，SetOutputFileName函数会创建一个AVI mux Filter 和一个 File writer Filter ，并且将两个filter添加到graph图中，在这个函数中，通过File Writer Filter 请求IFileSinkFilter接口，然后调用IFileSinkFilter::SetFileName方法，设置文件的名称。然后将两个filter连接起来。第三个参数返回一个指向 AVI Mux的指针，同时，它也通过第四个参数返回一个IFileSinkFilter参数，如果你不需要这个参数，你可以将这个参数设置成NULL。<br/>然后，你应该调用下面的函数将capture filter 和AVI Mux连接起来。<br/>[codes=c]<br/>hr = pBuild->RenderStream(<br/>&nbsp;&nbsp;&PIN_CATEGORY_CAPTURE, // Pin category.<br/>&nbsp;&nbsp;&MEDIATYPE_Video, // Media type.<br/>&nbsp;&nbsp;pCap, // Capture filter.<br/>&nbsp;&nbsp;NULL, // Intermediate filter (optional).<br/>&nbsp;&nbsp;pMux); // Mux or file sink filter.<br/>&nbsp;&nbsp;// Release the mux filter.<br/>&nbsp;&nbsp;pMux->Release();<br/>[/codes]<br/>第5个参数就是使用的上面函数返回的pMux指针。<br/>当捕捉音频的时候，媒体类型要设置为MEDIATYPE_Audio，如果你从两个不同的设备捕捉视频和音频，你最好将音频设置成主流，这样可以防止两个数据流间drift，因为avi mux filter为同步音频，会调整视频的播放速度的。为了设置master 流，调用IConfigAviMux::SetMasterStream方法，可以采用如下的代码：<br/>[codes=c]<br/>IConfigAviMux *pConfigMux = NULL;<br/>&nbsp;&nbsp;hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;pConfigMux->SetMasterStream(1);<br/>&nbsp;&nbsp;pConfigMux->Release();<br/>[/codes]<br/>&nbsp;&nbsp;&#125;SetMasterStream的参数指的是数据流的数目，这个是由调用RenderStream的次序决定的。例如，如果你调用RenderStream首先用于视频流，然后是音频，那么视频流就是0，音频流就是1。<br/>添加编码filter<br/>[codes=c]<br/>&nbsp;&nbsp;IBaseFilter *pEncoder;<br/>&nbsp;&nbsp;/* Create the encoder filter (not shown). */<br/>&nbsp;&nbsp;// Add it to the filter graph.<br/>&nbsp;&nbsp;pGraph->AddFilter(pEncoder, L"Encoder);<br/>/* Call SetOutputFileName as shown previously. */<br/>// Render the stream.<br/>&nbsp;&nbsp;hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, <br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;pCap, pEncoder, pMux);<br/>&nbsp;&nbsp;pEncoder->Release();<br/>[/codes]<br/>2将视频流保存成wmv格式的文件<br/>为了将视频流保存成并编码成windows media video （WMV）格式的文件，将capture pin连到WM ASF Writer filter。<br/><br/>图已经丢失<br/>构建graph图最简单的方法就是将在ICaptureGraphBuilder2::SetOutputFileName方法中指定MEDIASUBTYPE_Asf的filter。如下<br/>[codes=c]<br/> IBaseFilter* pASFWriter = 0;<br/>&nbsp;&nbsp;hr = pBuild->SetOutputFileName(<br/>&nbsp;&nbsp;&MEDIASUBTYPE_Asf, // Create a Windows Media file.<br/>&nbsp;&nbsp;L"C:&#92;&#92;VidCap.wmv", // File name.<br/>&nbsp;&nbsp;&pASFWriter, // Receives a pointer to the filter.<br/>&nbsp;&nbsp;NULL); // Receives an IFileSinkFilter interface pointer (optional).<br/>[/codes]<br/>&nbsp;&nbsp;参数MEDIASUBTYPE_Asf 告诉graph builder，要使用wm asf writer作为文件接收器，于是，pbuild 就创建这个filter，将其添加到graph图中，然后调用IFileSinkFilter::SetFileName来设置输出文件的名字。第三个参数用来返回一个ASF writer指针，第四个参数用来返回文件的指针。<br/>在将任何pin连接到WM ASF Writer之前，一定要对WM ASF Writer进行一下设置，你可以同过WM ASF Writer的IConfigAsfWriter接口指针来进行设置。<br/>[codes=c]<br/> IConfigAsfWriter *pConfig = 0;<br/>&nbsp;&nbsp;hr = pASFWriter->QueryInterface(IID_IConfigAsfWriter, (void**)&pConfig);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Configure the ASF Writer filter.<br/>&nbsp;&nbsp;pConfig->Release();<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/>然后调用ICaptureGraphBuilder2::RenderStream将capture Filter 和 ASF writer连接起来。<br/>[codes=c]<br/> hr = pBuild->RenderStream(<br/>&nbsp;&nbsp;&PIN_CATEGORY_CAPTURE, // Capture pin.<br/>&nbsp;&nbsp;&MEDIATYPE_Video, // Video. Use MEDIATYPE_Audio for audio.<br/>&nbsp;&nbsp;pCap, // Pointer to the capture filter. <br/>&nbsp;&nbsp;0, <br/>&nbsp;&nbsp;pASFWriter); // Pointer to the sink filter (ASF Writer).<br/>[/codes]<br/>3保存成自定义的文件格式<br/>如果你想将文件保存成自己的格式，你必须有自己的 file writer。看下面的代码<br/>[codes=c]<br/> IBaseFilter *pMux = 0;<br/>&nbsp;&nbsp;IFileSinkFilter *pSink = 0;<br/>&nbsp;&nbsp;hr = pBuild->SetOutputFileName(<br/>&nbsp;&nbsp;&CLSID_MyCustomMuxFilter, //自己开发的Filter<br/>&nbsp;&nbsp;L"C:&#92;&#92;VidCap.avi", &pMux, &pSink);<br/>[/codes]<br/>4如何将视频流保存进多个文件<br/>当你将视频流保存进一个文件后，如果你想开始保存第二个文件，这时，你应该首先将graph停止，然后通过IFileSinkFilter::SetFileName改变 File Writer 的文件名称。注意，IFileSinkFilter指针你可以在SetOutputFileName时通过第四个参数返回的。<br/>看看保存多个文件的代码吧<br/>[codes=c]<br/> IBaseFilter *pMux;<br/>&nbsp;&nbsp;IFileSinkFilter *pSink<br/>&nbsp;&nbsp;hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi, L"C:&#92;&#92;YourFileName.avi", <br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&pMux, &pSink);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, <br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;pCap, NULL, pMux);<br/> if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;pControl->Run();<br/>&nbsp;&nbsp;/* Wait awhile, then stop the graph. */<br/>&nbsp;&nbsp;pControl->Stop();<br/>&nbsp;&nbsp;// Change the file name and run the graph again.<br/>&nbsp;&nbsp;pSink->SetFileName(L"YourFileName02.avi", 0);<br/>&nbsp;&nbsp;pControl->Run();<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;pMux->Release();<br/>&nbsp;&nbsp;pSink->Release();<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/><span style="color: #0000FF;">5组合视频的捕捉和预览</span><br/>如果想组建一个既可以预览视频，又可以将视频保存成文件的graph，只需要两次调用ICaptureGraphBuilder2::RenderStream即可。代码如下：<br/>[codes=c]<br/> // Render the preview stream to the video renderer.<br/>&nbsp;&nbsp;hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, <br/>&nbsp;&nbsp;pCap, NULL, NULL);<br/>// Render the capture stream to the mux.<br/>&nbsp;&nbsp;hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, <br/>&nbsp;&nbsp;pCap, NULL, pMux);<br/>[/codes]<br/>在上面的代码中，graph builder 其实隐藏了下面的细节。<br/>1 如果capture Filter既有preview pin 也有captrue pin，那么RenderStream仅仅将两个pin和render filter接起来。如下图<br/><br/>图丢失<br/>2如果caprture Filter只有一个capture pin，那么Capture Graph Builder就采用一个Smart Tee Filter将视频流分流，graph图如下<br/><br/>图丢失<br/><br/><span style="color: #0000FF;">5如何控制Capture Graph（Controlling Capture Graph）</span><br/><br/>Filter图表管理器可以通过IMediaControl接口控制整个graph的运行，停止和暂停。但是当一个graph有捕捉和预览两个数据流的时候，如果我们想单独的控制其中的一个数据流话，我们可以通过ICaptureGraphBuilder2::ControlStream 。<br/>下面讲一下如何来单独控制捕捉和预览数据流。<br/>1 控制捕捉视频流<br/>下面的代码，让捕捉数据流在graph开始运行1秒后开始，允运行4秒后结束。<br/>[codes=c]<br/> // Control the video capture stream. <br/>&nbsp;&nbsp;REFERENCE_TIME rtStart = 1000 0000, rtStop = 5000 0000;<br/>&nbsp;&nbsp;const WORD wStartCookie = 1, wStopCookie = 2; // Arbitrary values.<br/>&nbsp;&nbsp;hr = pBuild->ControlStream(<br/>&nbsp;&nbsp;&PIN_CATEGORY_CAPTURE, // Pin category.<br/>&nbsp;&nbsp;&MEDIATYPE_Video, // Media type.<br/>&nbsp;&nbsp;pCap, // Capture filter.<br/>&nbsp;&nbsp;&rtStart, &rtStop, // Start and stop times.<br/>&nbsp;&nbsp;wStartCookie, wStopCookie // Values for the start and stop events.<br/>&nbsp;&nbsp;);<br/>&nbsp;&nbsp;pControl->Run();<br/>[/codes]<br/>第一个参数表明需要控制的数据流，一般采用的是pin种类GUID，<br/>第二个参数表明了媒体类型。<br/>第三个参数指明了捕捉的filter。如果想要控制graph图中的所有捕捉filter，第二个和第三个参数都要设置成NULL。<br/>第四和第五个参数表明了流开始和结束的时间，这是一个相对于graph开始的时间。<br/>只有你调用IMediaControl::Run以后，这个函数才有作用。如果graph正在运行，这个设置立即生效。<br/>最后的两个参数用来设置当数据流停止，开始能够得到的事件通知。对于任何一个运用此方法的数据流，graph当流开始的时候，会发送EC_STREAM_CONTROL_STARTED通知，在流结束的时候，要发送EC_STREAM_CONTROL_STOPPED通知。wStartCookie和wStopCookie是作为第二个参数的。<br/>看看事件通知处理过程吧<br/>[codes=c]<br/> while (hr = pEvent->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;switch (evCode)<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;case EC_STREAM_CONTROL_STARTED: <br/>&nbsp;&nbsp;// param2 == wStartCookie<br/>&nbsp;&nbsp;break;<br/> case EC_STREAM_CONTROL_STOPPED: <br/>&nbsp;&nbsp;// param2 == wStopCookie<br/>&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&#125; <br/>&nbsp;&nbsp;pEvent->FreeEventParams(evCode, param1, param2);<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/>ControlStream还定义了一些特定的值来表示开始和停止的时间。<br/>MAXLONGLONG 从不开始，只有在graph停止的时候才停止<br/>NULL， 立即开始和停止<br/>例如，下面的代码立即停止捕捉流。<br/>[codes=c]<br/> pBuild->ControlStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pCap,<br/>&nbsp;&nbsp;0, 0, // Start and stop times.<br/>&nbsp;&nbsp;wStartCookie, wStopCookie); <br/>[/codes]<br/>2控制预览视频流<br/>只要给ControlStream第一个参数设置成PIN_CATEGORY_PREVIEW就可以控制预览pin，整个函数的使用和控制捕捉流一样，但是唯一区别是在这里你没法设置开始和结束时间了，因为预览的视频流没有时间戳，因此你必须使用NULL或者MAXLONGLONG。例子<br/><br/> Use NULL to start the preview stream:<br/>[codes=c]<br/>&nbsp;&nbsp;pBuild->ControlStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap,<br/>&nbsp;&nbsp;NULL, // Start now.<br/>&nbsp;&nbsp;0, // (Don't care.)<br/>&nbsp;&nbsp;wStartCookie, wStopCookie); <br/>&nbsp;&nbsp;Use MAXLONGLONG to stop the preview stream:<br/>&nbsp;&nbsp;pBuild->ControlStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap,<br/>&nbsp;&nbsp;0, // (Don't care.)<br/>&nbsp;&nbsp;MAXLONGLONG, // Stop now.<br/>&nbsp;&nbsp;wStartCookie, wStopCookie); <br/>[/codes]<br/>3关于数据流的控制<br/>Pin的缺省的行为是传递sample，例如，如果你对PIN_CATEGORY_CAPTURE使用了ControlStream，但是对于PIN_CATEGORY_PREVIEW没有使用该函数，因此，当你run graph的时候，preview 流会立即运行起来，而capture 流则要等到你设置的时间运行。<br/><br/><span style="color: #0000FF;">6如何配置一个视频捕捉设备</span><br/><br/>1显示VFW驱动的视频设备对话框<br/>如果视频捕捉设备采用的仍然是VFW方式的驱动程序，则必须支持下面三个对话框，用来设置视频设备。<br/>1 Video Source <br/>用来选择视频输入设备并且调整设备的设置，比如亮度和对比度。<br/>2Video Format<br/>用来设置桢的大小和位<br/>3Video Display<br/>用来设置视频的显示参数<br/>为了显示上面的三个对话框，你可以do the following<br/>1 停止graph。<br/>2向捕捉filter请求IAMVfwCaptureDialogs接口，如果成功，表明设备支持VFW驱动。<br/>3调用IAMVfwCaptureDialogs::HasDialog来检查驱动程序是否支持你请求的对话框，如果支持，返回S_OK,否则返回S_FALSE。注意不要用SUCCEDED宏。<br/>4如果驱动支持该对话框，调用IAMVfwCaptureDialogs::ShowDialog显示该对话框。<br/>5 重新运行graph<br/>代码如下<br/>[codes=c]<br/> pControl->Stop(); // Stop the graph.<br/>&nbsp;&nbsp;// Query the capture filter for the IAMVfwCaptureDialogs interface.<br/>&nbsp;&nbsp;IAMVfwCaptureDialogs *pVfw = 0;<br/>&nbsp;&nbsp;hr = pCap->QueryInterface(IID_IAMVfwCaptureDialogs, (void**)&pVfw);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Check if the device supports this dialog box.<br/>&nbsp;&nbsp;if (S_OK == pVfw->HasDialog(VfwCaptureDialog_Source))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Show the dialog box.<br/>&nbsp;&nbsp;hr = pVfw->ShowDialog(VfwCaptureDialog_Source, hwndParent);<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;pControl->Run();<br/>[/codes]<br/>2 调整视频的质量<br/>WDM驱动的设备支持一些属性可以用来调整视频的质量，比如亮度，对比度，饱和度，等要向调整视频的质量，do the following<br/>1 从捕捉filter上请求IAMVideoProcAmp接口<br/>2 对于你想调整的任何一个属性，调用IAMVideoProcAmp::GetRange可以返回这个属性赋值的范围，缺省值，最小的增量值。IAMVideoProcAmp::Get返回当前正在使用的值。VideoProcAmpProperty枚举每个属性定义的标志。<br/>3调用IAMVideoProcAmp::Set来设置这个属性值。设置属性的时候，不用停止graph。<br/>看看下面的代码是如何调整视频的质量的<br/>[codes=c]<br/>HWND hTrackbar; // Handle to the trackbar control. <br/>&nbsp;&nbsp;// Initialize hTrackbar (not shown).<br/>// Query the capture filter for the IAMVideoProcAmp interface.<br/>&nbsp;&nbsp;IAMVideoProcAmp *pProcAmp = 0;<br/>&nbsp;&nbsp;hr = pCap->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);<br/>&nbsp;&nbsp;if (FAILED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// The device does not support IAMVideoProcAmp, so disable the control.<br/>&nbsp;&nbsp;EnableWindow(hTrackbar, FALSE);<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;long Min, Max, Step, Default, Flags, Val;<br/> // Get the range and default value. <br/>&nbsp;&nbsp;hr = m_pProcAmp->GetRange(VideoProcAmp_Brightness, &Min, &Max, &Step,<br/>&nbsp;&nbsp;&Default, &Flags);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Get the current value.<br/>&nbsp;&nbsp;hr = m_pProcAmp->Get(VideoProcAmp_Brightness, &Val, &Flags);<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Set the trackbar range and position.<br/>&nbsp;&nbsp;SendMessage(hTrackbar, TBM_SETRANGE, TRUE, MAKELONG(Min, Max));<br/>&nbsp;&nbsp;SendMessage(hTrackbar, TBM_SETPOS, TRUE, Val);<br/>&nbsp;&nbsp;EnableWindow(hTrackbar, TRUE);<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// This property is not supported, so disable the control.<br/>&nbsp;&nbsp;EnableWindow(hTrackbar, FALSE);<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/>3调整视频输出格式<br/>我们知道视频流可以有多种输出格式，一个设备可以支持16-bit RGB, 32-bit RGB, and YUYV，在每一种格式下，设备还可以调整视频桢的大小。<br/>在WDM驱动设备上，IAMStreamConfig 接口用来报告设备输出视频的格式的，VFW设备，可以采用对话框的方式来设置，参见前面的内容。<br/>捕捉Filter的捕捉pin和预览pin都支持IAMStreamConfig 接口，可以通过ICaptureGraphBuilder2::FindInterface获得IAMStreamConfig接口。<br/>[codes=c]<br/> IAMStreamConfig *pConfig = NULL;<br/>&nbsp;&nbsp;hr = pBuild->FindInterface(<br/>&nbsp;&nbsp;&PIN_CATEGORY_PREVIEW, // Preview pin.<br/>&nbsp;&nbsp;0, // Any media type.<br/>&nbsp;&nbsp;pCap, // Pointer to the capture filter.<br/>&nbsp;&nbsp;IID_IAMStreamConfig, (void**)&pConfig);<br/>[/codes]<br/>设备还支持一系列的媒体类型，对于每一个媒体类型，设备都要支持一系列的属性，比如，桢的大小，图像如何缩放，桢率的范围等。<br/>通过IAMStreamConfig::GetNumberOfCapabilities获得设备所支持的媒体类型的数量。这个方法返回两个值，一个是媒体类型的数量，二是属性所需结构的大小。<br/>这个结构的大小很重要，因为这个方法是用于视频和音频的，视频采用的是VIDEO_STREAM_CONFIG_CAPS结构，音频用AUDIO_STREAM_CONFIG_CAPS结构。<br/>通过函数IAMStreamConfig::GetStreamCaps来枚举媒体类型，要给这个函数传递一个序号作为参数，这个函数返回媒体类型和相应的属性结构体。看代码把<br/>[codes=c]<br/> int iCount = 0, iSize = 0;<br/>&nbsp;&nbsp;hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);<br/>// Check the size to make sure we pass in the correct structure.<br/>&nbsp;&nbsp;if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Use the video capabilities structure.<br/>&nbsp;&nbsp;for (int iFormat = 0; iFormat < iCount; iFormat++)<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;VIDEO_STREAM_CONFIG_CAPS scc;<br/>&nbsp;&nbsp;AM_MEDIA_TYPE *pmtConfig;<br/>&nbsp;&nbsp;hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;/* Examine the format, and possibly use it. */<br/>&nbsp;&nbsp;// Delete the media type when you are done.<br/>&nbsp;&nbsp;hr = pConfig->SetFormat(pmtConfig);//重新设置视频格式<br/>&nbsp;&nbsp;DeleteMediaType(pmtConfig);<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/>你可以调用IAMStreamConfig::SetFormat设置新的媒体类型<br/>hr = pConfig->SetFormat(pmtConfig);<br/>如果pin没有连接，当连接的时候就试图用新的格式，如果pin已经在连接了，它就会用的新的媒体格式重新连接。在任何一种情况下，下游的filter都有可能拒绝新的媒体格式。<br/>在SetFormat前你可以修改VIDEO_STREAM_CONFIG_CAPS结构来重新设置媒体类型。<br/>例如：<br/>如果GetStreamCaps返回的是24-bit RGB format，桢的大小是320 x 240 像素，你可以通过检查媒体类型的major type，subtpye，和format等值<br/>[codes=c]<br/> if ((pmtConfig.majortype == MEDIATYPE_Video) &&<br/>&nbsp;&nbsp;(pmtConfig.subtype == MEDIASUBTYPE_RGB24) &&<br/>&nbsp;&nbsp;(pmtConfig.formattype == FORMAT_VideoInfo) &&<br/>&nbsp;&nbsp;(pmtConfig.cbFormat >= sizeof (VIDEOINFOHEADER)) &&<br/>&nbsp;&nbsp;(pmtConfig.pbFormat != NULL))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig.pbFormat;<br/>&nbsp;&nbsp;// pVih contains the detailed format information.<br/>&nbsp;&nbsp;LONG lWidth = pVih->bmiHeader.biWidth;<br/>&nbsp;&nbsp;LONG lHeight = pVih->bmiHeader.biHeight;<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/>VIDEO_STREAM_CONFIG_CAPS结构里包含了该媒体类型的视频长度和宽度的最大值和最小值，还有递增的幅度值，就是每次调整视频size的幅度，例如，设备可能返回如下的值<br/>? MinOutputSize: 160 x 120 <br/>? MaxOutputSize: 320 x 240 <br/>? OutputGranularityX: 8 pixels (horizontal step size) <br/>? OutputGranularityY: 8 pixels (vertical step size) <br/>这样你可以在(160, 168, 176, ... 304, 312, 320) 范围内设置宽度，在 (120, 128, 136, ... 104, 112, 120).设置高度值，<br/><br/>图丢失<br/>如果想设置新的值，直接修改在GetStreamCaps函数中返回的值即可，<br/>[codes=c]<br/> pVih->bmiHeader.biWidth = 160;<br/>&nbsp;&nbsp;pVih->bmiHeader.biHeight = 120;<br/>&nbsp;&nbsp;pVih->bmiHeader.biSizeImage = DIBSIZE(pVih->bmiHeader);<br/>[/codes]<br/>然后将媒体类型传递给SetFormat函数，就可修改视频格式了。<br/><br/><span style="color: #0000FF;">7将设备从系统中移走时的事件通知（Device remove Notify）</span><br/><br/>如果用户将一个graph正在使用的即插即用型的设备从系统中去掉，filter图表管理器就会发送一个EC_DEVICE_LOST事件通知，如果该设备又可以使用了，filter图表管理器就发送另外的一个EC_DEVICE_LOST通知，但是先前组建的捕捉filter graph图就没法用了，用户必须重新组建graph图。<br/>当系统中有新的设备添加时，dshow是不会发送任何通知的，所以，应用程序如果想要知道系统中何时添加新的设备，应用程序可以监控WM_DEVICECHANGE消息。<br/><br/><span style="color: #0000FF;">8从静止图像pin中捕捉图片</span><br/><br/>有些照相机，摄像头除了可以捕获视频流以外还可以捕获单张的，静止的图片。通常，静止的图片的质量要比流的质量要高。摄像头一般都一个按钮来触发，或者是支持软件触发。支持输出静态图片的摄像头一般都要提供一个静态图片pin，这个pin的种类是PIN_CATEGORY_STILL。<br/>从设备中获取静态图片，我们一般推荐使用windows Image Acquisition (WIA) APIs。当然，你也可以用dshow来获取图片。<br/>在graph运行的时候利用IAMVideoControl::SetMode来触发静态的pin。代码如下<br/>[codes=c]<br/> pControl->Run(); // Run the graph.<br/>&nbsp;&nbsp;IAMVideoControl *pAMVidControl = NULL;<br/>&nbsp;&nbsp;hr = pCap->QueryInterface(IID_IAMVideoControl, (void**)&pAMVidControl);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Find the still pin.<br/>&nbsp;&nbsp;IPin *pPin = 0;<br/>&nbsp;&nbsp;hr = pBuild->FindPin(pCap, PINDIR_OUTPUT, &PIN_CATEGORY_STILL, 0,<br/>&nbsp;&nbsp;FALSE, 0, &pPin);<br/>&nbsp;&nbsp;if (SUCCEEDED(hr))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;hr = pAMVidControl->SetMode(pPin, VideoControlFlag_Trigger);<br/>&nbsp;&nbsp;pPin->Release();<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;pAMVidControl->Release();<br/>&nbsp;&nbsp;&#125;<br/>[/codes]<br/>首先向capture Filter 请求IAMVideoContol，如果支持该接口，就调用ICaptureGraphBuilder2::FindPin请求指向静止pin 的指针，然后调用pin的put_Mode方法。<br/>根据不同的摄像头，你可能静态pin连接前要render 该pin。<br/>捕捉静态图片常用的filter是Sample Grabber filter，Sample Grabber使用了一个用户定义的回调汗水来处理图片。关于这个filter的详细用法，参见Using the Sample Grabber.。<br/>下面的例子假设静态pin传递的是没有压缩的RGB图片。首先定义一个类，从ISampleGrabberCB继承。<br/>[codes=c]<br/> // Class to hold the callback function for the Sample Grabber filter.<br/>&nbsp;&nbsp;class SampleGrabberCallback : public ISampleGrabberCB<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;// Implementation is described later.<br/>&nbsp;&nbsp;&#125;<br/>// Global instance of the class.<br/>&nbsp;&nbsp;SampleGrabberCallback g_StillCapCB;<br/>[/codes]<br/>然后将捕捉filter的静态pin连接到Sample Grabber，将Sample Grabber连接到Null Renderer filter。Null Renderer仅仅是将她接收到的sample丢弃掉。实际的工作都是在回调函数里进行，连接Null Renderer 仅仅是为了给Sample Grabber's 输出pin上连接点东西。具体见下面的代码<br/>[codes=c]<br/>&nbsp;&nbsp;// Add the Sample Grabber filter to the graph.<br/>&nbsp;&nbsp;IBaseFilter *pSG_Filter;<br/>&nbsp;&nbsp;hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,<br/>&nbsp;&nbsp;IID_IBaseFilter, (void**)&pSG_Filter);<br/>&nbsp;&nbsp;hr = pGraph->AddFilter(pSG_Filter, L"SampleGrab");<br/>// Add the Null Renderer filter to the graph.<br/>&nbsp;&nbsp;IBaseFilter *pNull;<br/>&nbsp;&nbsp;hr = CoCreateInstance(CLSID_NullRendere, NULL, CLSCTX_INPROC_SERVER,<br/>&nbsp;&nbsp;IID_IBaseFilter, (void**)&pNull);<br/>&nbsp;&nbsp;hr = pGraph->AddFilter(pSG_Filter, L"NullRender");<br/>[/codes]<br/>然后通过RenderStream将still pin ，sample grabber ，null Renderer连接起来<br/>[codes=c]<br/> hr = pBuild->RenderStream(<br/>&nbsp;&nbsp;&PIN_CATEGORY_STILL, // Connect this pin ...<br/>&nbsp;&nbsp;&MEDIATYPE_Video, // with this media type ...<br/>&nbsp;&nbsp;pCap, // on this filter ...<br/>&nbsp;&nbsp;pSG_Filter, // to the Sample Grabber ...<br/>&nbsp;&nbsp;pNull); // ... and finally to the Null Renderer.<br/>[/codes]<br/>然后调用ISampleGrabber指针，来通过这个指针可以分配内存。<br/>[codes=c]<br/>&nbsp;&nbsp;// Configure the Sample Grabber.<br/>&nbsp;&nbsp;ISampleGrabber *pSG;<br/>&nbsp;&nbsp;hr = pSG_Filter->QueryInterface(IID_ISampleGrabber, (void**)&pSG);<br/>&nbsp;&nbsp;pSG->SetOneShot(FALSE);<br/>&nbsp;&nbsp;pSG->SetBufferSamples(TRUE);<br/>[/codes]<br/>设置你的回调对象<br/>[codes=c]<br/> pSG->SetCallback(&g_StillCapCB, 0); // 0 = Use the SampleCB callback method<br/>获取静态pin和sample grabber之间连接所用的媒体类型<br/>[codes=c]<br/> // Store the media type for later use.<br/>&nbsp;&nbsp;AM_MEDIA_TYPE g_StillMediaType;<br/>&nbsp;&nbsp;hr = pSG->GetConnectedMediaType(&g_StillMediaType);<br/>&nbsp;&nbsp;pSG->Release();<br/>[/codes]<br/>媒体类型包含一个BITMAPINFOHEADER结构来定义图片的格式，在程序退出前一定要释放媒体类型<br/>[codes=c]<br/> // On exit, remember to release the media type.<br/>&nbsp;&nbsp;FreeMediaType(g_StillMediaType);<br/>[/codes]<br/>看看下面的回调类吧。这个类从ISampleGrabber接口派生，但是它没有保持引用计数，因为应用程序在堆上创建这个对象，在整个graph的生存周期它都存在。<br/>所有的工作都在BufferCB函数里完成，当有一个新的sample到来的时候，这个函数就会被sample Grabber调用到。在下面的例子里，bitmap被写入到一个文件中<br/>[codes=c]<br/> class SampleGrabberCallback : public ISampleGrabberCB<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;public:<br/>&nbsp;&nbsp;// Fake referance counting.<br/>&nbsp;&nbsp;STDMETHODIMP_(ULONG) AddRef() &#123; return 1; &#125;<br/>&nbsp;&nbsp;STDMETHODIMP_(ULONG) Release() &#123; return 2; &#125;<br/> STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;if (NULL == ppvObject) return E_POINTER;<br/>&nbsp;&nbsp;if (riid == __uuidof(IUnknown))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;*ppvObject = static_cast<IUnknown*>(this);<br/>&nbsp;&nbsp;return S_OK;<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;if (riid == __uuidof(ISampleGrabberCB))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;*ppvObject = static_cast<ISampleGrabberCB*>(this);<br/>&nbsp;&nbsp;return S_OK;<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;return E_NOTIMPL;<br/>&nbsp;&nbsp;&#125;<br/> STDMETHODIMP SampleCB(double Time, IMediaSample *pSample)<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;return E_NOTIMPL;<br/>&nbsp;&nbsp;&#125;<br/> STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen)<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;if ((g_StillMediaType.majortype != MEDIATYPE_Video) &#124;&#124;<br/>&nbsp;&nbsp;(g_StillMediaType.formattype != FORMAT_VideoInfo) &#124;&#124;<br/>&nbsp;&nbsp;(g_StillMediaType.cbFormat < sizeof(VIDEOINFOHEADER)) &#124;&#124;<br/>&nbsp;&nbsp;(g_StillMediaType.pbFormat == NULL))<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;return VFW_E_INVALIDMEDIATYPE;<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;HANDLE hf = CreateFile("C:&#92;&#92;Example.bmp", GENERIC_WRITE, <br/>&nbsp;&nbsp;FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);<br/>&nbsp;&nbsp;if (hf == INVALID_HANDLE_VALUE)<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;return E_FAIL;<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;long cbBitmapInfoSize = g_StillMediaType.cbFormat - SIZE_PREHEADER;<br/>&nbsp;&nbsp;VIDEOINFOHEADER *pVideoHeader =<br/>&nbsp;&nbsp;(VIDEOINFOHEADER*)g_StillMediaType.pbFormat;<br/> BITMAPFILEHEADER bfh;<br/>&nbsp;&nbsp;ZeroMemory(&bfh, sizeof(bfh));<br/>&nbsp;&nbsp;bfh.bfType = 'MB'; // Little-endian for "MB".<br/>&nbsp;&nbsp;bfh.bfSize = sizeof( bfh ) + BufferLen + cbBitmapInfoSize;<br/>&nbsp;&nbsp;bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + cbBitmapInfoSize;<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;// Write the file header.<br/>&nbsp;&nbsp;DWORD dwWritten = 0;<br/>&nbsp;&nbsp;WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );<br/>&nbsp;&nbsp;WriteFile(hf, HEADER(pVideoHeader), cbBitmapInfoSize, &dwWritten, NULL); <br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;WriteFile( hf, pBuffer, BufferLen, &dwWritten, NULL );<br/>&nbsp;&nbsp;CloseHandle( hf );<br/>&nbsp;&nbsp;return S_OK;<br/> &#125;<br/>&nbsp;&nbsp;&#125;;<br/>[/codes]
]]>
</description>
</item><item>
<link>http://www.doserver.net/read.php/2030.htm</link>
<title><![CDATA[图像处理网络资源( zz）]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[开发语言]]></category>
<pubDate>Sun, 31 May 2009 06:16:59 +0000</pubDate> 
<guid>http://www.doserver.net/read.php/2030.htm</guid> 
<description>
<![CDATA[ 
	本次zz http://blog.csdn.net/dankes/archive/2005/07/31/443122.aspx<br/>原文已经无考证，作者提到，转自阿须数码，STONE 原创 http://www.assuredigit.com/<br/><br/>图像处理方面的研究工作，最重要的两个问题：其一是要把握住国际上最前沿的内容；其二是所作工作要具备很高的实用背景。解决第一个问题的办法就是找出这个方向公认最牛的几个超级大拿(看看他们都在作什么)和最权威的出版物(阅读上面最新的文献)，解决第二个问题的办法是你最好能够找到一个<br/><br/>实际应用的项目，边做边写文章。&nbsp;&nbsp;<br/>做好这几点的途径之一就是充分利用网络资源，特别是权威网站和大拿们的个人主页。下面是我收集的一些资源，希望对大家有用。(这里我要感谢MTH AI版的alamarik和Graphics版的faintt) <br/><br/>导航栏： <br/><br/>[1]研究群体<br/>[2]大拿主页<br/>[3]前沿期刊<br/>[4]GPL软件资源<br/>[5]搜索引擎<br/><br/><br/>一、研究群体<br/>http://www-2.cs.cmu.edu/~cil/vision.html<br/>这是卡奈基梅隆大学的计算机视觉研究组的主页，上面提供很全的资料，从发表文章的下载到演示程序、测试图像、常用链接、相关软硬件，甚至还有一个搜索引擎。 <br/><br/>http://www.cmis.csiro.au/IAP/zimage.htm <br/>这是一个侧重图像分析的站点，一般。但是提供一个Image Analysis环境---ZIMAGE and SZIMAGE。 <br/><br/>http://www.via.cornell.edu/<br/>康奈尔大学的计算机视觉和图像分析研究组，好像是电子和计算机工程系的。侧重医学方面的研究，但是在上面有相当不错资源，关键是它正在建设中，能够跟踪一些信息。 <br/><br/>http://www2.parc.com/istl/groups/did/didoverview.shtml<br/>有一个很有意思的项目：DID(文档图像解码)。 <br/><br/>http://www-cs-students.stanford.edu/<br/>斯坦福大学计算机系主页，自己找吧:( <br/><br/>http://www.fmrib.ox.ac.uk/analysis/<br/>主要研究：Brain Extraction Tool,Nonlinear noise reduction,Linear Image Registration,Automated Segmentation,Structural brain change analysis,motion correction,etc. <br/><br/><br/>http://www.cse.msu.edu/prip/<br/>这是密歇根州立大学计算机和电子工程系的模式识别--图像处理研究组，它的FTP上有许多的文章(NEW)。 <br/><br/>http://pandora.inf.uni-jena.de/p/e/index.html<br/>德国的一个数字图像处理研究小组，在其上面能找到一些不错的链接资源。 <br/><br/>http://www-staff.it.uts.edu.au/~sean/CVCC.dir/home.html <br/>CVIP(used to be CVCC for Computer Vision and Cluster Computing) is a research group focusing on cluster-based computer vision within the Spiral Architecture. <br/><br/><br/>http://cfia.gmu.edu/<br/>The mission of the Center for Image Analysis is to foster multi-disciplinary research in image, multimedia and related technologies by establishing links between academic institutes, industry and government agencies, and to transfer key technologies to <br/><br/>help industry build next generation commercial and military imaging and multimedia systems. <br/><br/>http://peipa.essex.ac.uk/info/groups.html <br/>可以通过它来搜索全世界各地的知名的计算机视觉研究组(CV Groups)，极力推荐。 <br/><br/>二、图像处理GPL库<br/>http://www.ph.tn.tudelft.nl/~klamer/cppima.html<br/>Cppima 是一个图像处理的C++函数库。这里有一个较全面介绍它的库函数的文档，当然你也可以下载压缩的GZIP包，里面包含TexInfo格式的文档。 <br/><br/><br/>http://iraf.noao.edu/<br/>Welcome to the IRAF Homepage! IRAF is the Image Reduction and Analysis Facility, a general purpose software system for the reduction and analysis of astronomical data. <br/><br/><br/>http://entropy.brni-jhu.org/tnimage.html <br/>一个非常不错的Unix系统的图像处理工具，看看它的截图。你可以在此基础上构建自己的专用图像处理工具包。 <br/><br/>http://sourceforge.net/projects/<br/>这是GPL软件集散地，到这里找你想要得到的IP库吧。 <br/><br/><br/>三、搜索资源<br/>当然这里基本的搜索引擎还是必须要依靠的，比如Google等，可以到我常用的链接看看。下面的链接可能会节省你一些时间： <br/><br/>http://sal.kachinatech.com/<br/>http://cheminfo.pku.edu.cn/mirrors/SAL/index.shtml<br/>四、大拿网页<br/>http://www.ai.mit.edu/people/wtf/<br/>这位可是MIT人工智能实验室的BILL FREEMAN。大名鼎鼎！专长是：理解--贝叶斯模型。 <br/><br/><br/>http://www.merl.com/people/brand/<br/>MERL(Mitsubishi Electric Research Laboratory)中的擅长“Style Machine”高手。 <br/><br/><br/>http://research.microsoft.com/~ablake/<br/>CV界极有声望的A.Blake 1977年毕业于剑桥大学三一学院并或数学与电子科学学士学位。之后在MIT，Edinburgh，Oxford先后组建过研究小组并成为Oxford的教授，直到1999年进入微软剑桥研究中心。主要工作领域是计算机视觉。 <br/><br/>http://www-2.cs.cmu.edu/afs/cs.cmu.edu/user/har/Web/home.html <br/>这位牛人好像正在学习汉语，并且搜集了诸如“两只老虎(Two Tigers)”的歌曲，嘿嘿:)<br/>他的主页上面还有几个牛：Shumeet Baluja, Takeo Kanade。他们的Face Detection作的绝对是世界一流。他毕业于卡奈基梅隆大学的计算机科学系，兴趣是计算机视觉。 <br/><br/>http://www.ifp.uiuc.edu/yrui_ifp_home/html/huang_frame.html<br/>这位老牛在1963年就获得了MIT的博士学位！他领导的Image Lab比较出名的是指纹识别。 <br/><br/><br/>--------------------------------------------------------------------------------<br/><br/>下面这些是我搜集的牛群(大部分是如日中天的Ph.D们)，可以学习的是他们的Study Ways! <br/><br/><br/>Finn Lindgren(Sweden):Statistical image analysis&nbsp;&nbsp;&nbsp;&nbsp;http://www.maths.lth.se/matstat/staff/finn/<br/>Pavel Paclik(Prague):statistical pattern recognition&nbsp;&nbsp; http://www.ph.tn.tudelft.nl/~pavel/<br/>Dr. Mark Burge:machine learning and graph theory&nbsp;&nbsp; http://cs.armstrong.edu/burge/<br/>yalin Wang:Document Image Analysis&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://students.washington.edu/~ylwang/<br/>Geir Storvik: Image analysis&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://www.math.uio.no/~geirs/<br/>Heidorn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://alexia.lis.uiuc.edu/~heidorn/<br/>Joakim Lindblad:Digital Image Cytometry&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://www.cb.uu.se/~joakim/index_eng.html<br/>S.Lavirotte:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://www-sop.inria.fr/cafe/Stephane.Lavirotte/<br/>Sporring:scale-space techniques&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.lab3d.odont.ku.dk/~sporring/<br/>Mark Jenkinson:Reduction of MR Artefacts&nbsp;&nbsp;&nbsp;&nbsp; http://www.fmrib.ox.ac.uk/~mark/<br/>Justin K. Romberg:digital signal processing&nbsp;&nbsp;&nbsp;&nbsp; http://www-dsp.rice.edu/~jrom/<br/>Fauqueur:Image retrieval by regions of interest&nbsp;&nbsp;&nbsp;&nbsp;http://www-rocq.inria.fr/~fauqueur/<br/>James J. Nolan:Computer Vision&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://cs.gmu.edu/~jnolan/<br/>Daniel X. Pape:Information&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://www.bucho.org/~dpape/<br/>Drew Pilant:remote sensing technology&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.geo.mtu.edu/~anpilant/index.html<br/><br/><br/>五、前沿期刊(TOP10)<br/>这里的期刊大部分都可以通过上面的大拿们的主页间接找到，在这列出主要是为了节省直接想找期刊投稿的兄弟的时间:) <br/><br/><br/>IEEE Trans. On PAMI&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://www.computer.org/tpami/index.htm<br/>IEEE Transactionson Image Processing&nbsp;&nbsp;http://www.ieee.org/organizations/pubs/transactions/tip.htm<br/>Pattern Recognition&nbsp;&nbsp;&nbsp;&nbsp; http://www.elsevier.com/locate/issn/00313203<br/>Pattern Recognition Letters&nbsp;&nbsp;&nbsp;&nbsp;http://www.elsevier.com/locate/issn/01678655<br/><br/><br/>
]]>
</description>
</item><item>
<link>http://www.doserver.net/read.php/2029.htm</link>
<title><![CDATA[[zz]Mapinfo多线程更新MapControl的方法]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[CADCAECAM]]></category>
<pubDate>Tue, 26 May 2009 07:53:27 +0000</pubDate> 
<guid>http://www.doserver.net/read.php/2029.htm</guid> 
<description>
<![CDATA[ 
	原文：http://www.mygis.com.cn/articles/23-12682-12682.htm,<br/>1、问题的提出<br/>在桌面应用中，经常需要用后台线程处理数据，然后将数据更新到地图上显示。<br/>由于MapInfo.Engine内部线程管理机制，从主线程（也就是创建MapControl控件实例的线程）之外的线程不能直接调用MapInfo.Engine.Session.Current.Catalog来获取地图的编录。<br/><br/>2、解决方法<br/> 利用 mapControl1.InvokeRequired 检测是否需要通过Invoke机制更新mapContrl1控件。当对mapControl1更新的调用方位于创建mapControl1控件所在的线程以外的线程时mapControl1.InvokeRequired&nbsp;&nbsp;= true<br/><br/>3、示例<br/>[codes=c#]<br/>-------------------------------------------------------------<br/>后台线程：采集GPS定位信息并更新地图<br/>-------------------------------------------------------------<br/>/// <summary><br/>/// 采集 GPS 定位信息的类<br/>/// </summary><br/>public class GPS<br/>&#123;<br/> public delegate void OnNewPositionInfoHandler( float lati, float longti);<br/> public event NewPositionInfoHandler&nbsp;&nbsp;OnNewPositionInfo;<br/>&nbsp;&nbsp;<br/> private int m_interval;<br/><br/> /// <summary><br/> /// 构造函数<br/> /// </summary><br/> /// <param name="interval">定时更新时间间隔(毫秒)</param><br/> public GPS(int interval)<br/> &#123;<br/>&nbsp;&nbsp;m_interval = interval;<br/>&nbsp;&nbsp;Thread t = new Thread(new ThreadStart(WorkThread));<br/>&nbsp;&nbsp;t.IsBackground = true;<br/>&nbsp;&nbsp;t.Start();<br/> &#125;<br/><br/>&nbsp;&nbsp;<br/> /// <summary><br/> /// 后台线程。接收并处理来自GPS的定位信息并更新地图<br/> /// </summary><br/> private void WorkThread()<br/> &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(true)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.Sleep(m_interval);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这里只是模拟采集到来自GPS的定位信息<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float longi = 32.120201010;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float lati = 118.39312781;<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 引发事件更新地图<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(OnNewNewPositionInfo != null) <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OnNewPositionInfo( lati, longti);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/> &#125;<br/>&#125;<br/><br/><br/>-------------------------------------------------------------<br/>//在Windows窗体代理中<br/>-------------------------------------------------------------<br/><br/>private GPS gps = null;<br/>public delegate UpdateInfoHandler( float lati, float longti);<br/><br/>private void Form1_Load(object sender, System.EventArgs e)<br/>&#123;<br/>&nbsp;&nbsp;gps = new GPS( 1000 );&nbsp;&nbsp;// 1秒钟更新一次<br/>&nbsp;&nbsp;&nbsp;&nbsp;gps.OnNewPositionInfo +=new GPS.OnNewPositionInfo(Form1_OnNewNewPositionInfo );<br/>&#125;<br/><br/>private void Form1_OnNewPositionInfo( float lati, float longti)<br/>&#123;<br/>&nbsp;&nbsp; if(mapControl1.InvokeRequired)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;object[] para = &#123;lati, longti&#125;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mapControl1.BeginInvoke( new UpdateInfoHandler(UpdateInfo), para);<br/>&nbsp;&nbsp; &#125;<br/>&nbsp;&nbsp;else<br/>&nbsp;&nbsp;&nbsp;&nbsp; UpdateInfo( lati, longti);<br/>&#125; <br/><br/><br/>void UpdateInfo( float lati, float longti)<br/>&#123;<br/>&nbsp;&nbsp; MIConnection cnx =&nbsp;&nbsp;new MIConnection();<br/>&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp; cnx.Open();<br/>&nbsp;&nbsp;&nbsp;&nbsp;MICommand cmd = cnx.CreateCommand();<br/>&nbsp;&nbsp; cmd.CommandText =&nbsp;&nbsp; string.Format("update s3064 set latitude = &#123;0&#125;, longtitude=&#123;1&#125;&nbsp;&nbsp;", lati, longti);<br/>&nbsp;&nbsp; cmd.ExecuteNonQuery();<br/>&nbsp;&nbsp; mapControl1.Map.Layers[0].Invalidate();<br/>&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;catch&#123;&#125;<br/>&nbsp;&nbsp;finally<br/>&nbsp;&nbsp;&#123;<br/> cnx.Close();<br/>&nbsp;&nbsp;&#125;<br/>&#125;<br/>[/codes]
]]>
</description>
</item><item>
<link>http://www.doserver.net/read.php/2028.htm</link>
<title><![CDATA[请大家购买BTMaster的系统的时候慎重]]></title> 
<author>huzhangyou2002 &lt;huzhangyou2002@gmail.com&gt;</author>
<category><![CDATA[点评]]></category>
<pubDate>Sat, 23 May 2009 05:46:39 +0000</pubDate> 
<guid>http://www.doserver.net/read.php/2028.htm</guid> 
<description>
<![CDATA[ 
	最近朋友让我去看看他买的一个系统，是BTMaster.cn的BT系统，让我很无语。一个用XBT_Tracker架设系统您做成收费我的倒不反对您，但是您的态度应该更正态一些。<br/>1：服务态度非常不好，甚至是恶劣<br/>2：购买的标准版，写的功能都能用，确被他加入非常多的限制<br/>可以参考 http://www.btmaster.cn/price.php<br/>3：动辄对客户说给你拉入黑名单，看朋友和他的聊天记录，我都快崩溃了，您要不就别接待客户，要不就好好说，不管如何，人家也是您系统的付费用户。<br/><br/>4：朋友无奈，只好让我重新设计开发了。<br/><br/>写此小文，本是无意，只是希望大家以后注意一点。借助我博客的访问量，希望可以让更多的人注意一下。<br/><br/>另外，我也正在开发这套系统，到时候，一定开源出来，大家免费下载配置，可以自己修改。感谢大家支持了。
]]>
</description>
</item>
</channel>
</rss>