DirectShow一次实作笔记

转载请注明出处:http://blog.csdn.net/horkychen  一篇早期写的资料。

Day 1:

我是个DirectShow新手,我基于CCaptureVideo类,写了一个简单的测试程序,界面如下图,代码在这个Group的SkyDriver/Codes目录里,使用DirectX SDK9 2004 Summer Update编译通过。

 

 

今天主要做了两件事:

一. 加了Video Capture时间长短控制:

   a.在CCaptureVideo中定义了一个m_MaxTime,和一个成员函数SetTimeLimitation来接受UI的设定,以秒为单位,然后在IMediaControl呼叫Run之前设定时间:
if(m_MaxTime>0)
  {
   // Control the video capture stream. 
   REFERENCE_TIME rtStop = 10000000 * m_MaxTime;
   const WORD wStartCookie = 1, wStopCookie = 2;  // Arbitrary values.
   hr = m_pCapture->ControlStream(
    &PIN_CATEGORY_CAPTURE, // Pin category.
    &MEDIATYPE_Video,      // Media type.
    m_pBF,                 // Capture filter.
    NULL, &rtStop,     // Start and stop times.
    wStartCookie, wStopCookie  // Values for the start and stop events.
    );    if(FAILED(hr))
   {
    AfxMessageBox(_T("Couldn’t control the graph!"));
   }   }

 

经过在PC上实验,如果设定n秒,则录制的Video时间为n-1秒,大家可以再试试看!

 

二.加了时间限制后,当录制结束,文件写入已经停止,但UI并没有回复正常,所以还要监测结束事件。于是有了BindMessageWindow函数,从Init函数传入两个句柄:

 HRESULT  Init(int iDeviceID, HWND hPreviewWnd, HWND hBaseWnd)

   hPreviewWnd代表预览窗口

   hBaseWnd代表主消息窗口

然后使用IMediaEventEx将消息绑定到主窗口之上(WM_GRAPHNOTIFY),这些都是DirectShow MSDN上所说明的方法:

HRESULT CCaptureVideo::BindMessageWindow()
{
  HRESULT hr = S_OK;
  if(m_hBaseWnd)
  {
 hr = m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pEvent);
 if (FAILED(hr))return hr;
 m_pEvent->SetNotifyWindow((OAHWND)m_hBaseWnd,WM_GRAPHNOTIFY,0);
  }
  return S_OK;
}

然后在主窗口上,使用其WndProc函数来侦听,得到WM_GRAPHNOTIFY后使用IMediaEventEx的GetEvent方法(我把它包在long CCaptureVideo::GetCurrentEvent()函数中了),如果发现事件是EC_STREAM_CONTROL_STOPPED,表示已经结束录制了,就呼叫STOP的Click事件处理程序,来结束录制。

LRESULT CCameraCaptureDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
 // TODO: Add your specialized code here and/or call the base class
    if( WM_GRAPHNOTIFY == message)
 {
  HandleGraphEvent();
 }
 return CDialog::WindowProc(message, wParam, lParam);
}

void CCameraCaptureDlg::HandleGraphEvent()
{
 long eventCode = m_cap.GetCurrentEvent();
 TCHAR str[256] = {0};
 wsprintf(str,_T("Get Event:%d"),eventCode);
 m_ListLog.AddString(str);
 switch(eventCode)
 {
   case EC_STREAM_CONTROL_STOPPED:
    if(GetDlgItem(IDC_STOP)->IsWindowEnabled())
   OnCommand(IDC_STOP,NULL);
  break;
   default:
    break;
 }

}

 

这些就是今天DirectShow的进展!

 

Day 2:

今天原本要写个File Writer测试,后来才发现一直使用AVI进行测试,并不能代表录制ASF时有相同的问题,并且录制ASF时使用的是WM ASF Writer,所以实现了ASF录制功能。遇到如下几个问题:

  1.需要安装Windows Media SDK. (我用了Windows Media SDK 9),主要是CLSID_WMAsfWriter之类的定义。当然也要引用WMVCORE.lib

  2.在PC下,ASF的录制必须安装Audio Capture Filter,否则会出现"Unspecified Error! 0x80004005"!

    Audio Filter的安装包括两步: a. Bind the filter  b.Call RenderStream for Audio Filter.

    详见代码中的BindFilter和Init函数的修改!

   因为ASF文件包含很多的profile,可以使用DirectShow带的Profile Emulator来查看。其中也有(No Audio)的profile,可以不使用Audio Capture Filter,而单独录制视频! 所以它的行为和指定的Profile有很大的关系!

  3.在PC下,ASF的录制是会自动增长的。所以并没有实质解决G2为什么没有自动增长的问题! 我在PC上也遇到一个问题,我必须选中输出的文件,才能看到文件大小的改变。G2或许有一样的问题!

完成后的Graph应当有如下的Filters,其中的Renderer是用来作为Preview的。

完整的代码,也已经传到本组的SkyDrive的Codes目录下,也包括展开后的Windows Media SDK.

下面附上一段,没有使用到代码,用来选择相应的profile,但对于其第一个参数从何而来,还不清楚!

HRESULT CCaptureVideo::MapProfileIdToProfile(int iProfile, IWMProfile **ppProfile)

{

    DWORD cProfiles;

    if (!ppProfile)

        return E_POINTER;

        

    *ppProfile = 0;

    

    CComPtr <IWMProfileManager> pIWMProfileManager;

    HRESULT hr = WMCreateProfileManager( &pIWMProfileManager );

    if(FAILED(hr)) 

    {

        printf("MapProfile: Failed to create profile manager!  hr=0x%x\n", hr);

        return hr;

    }

    // We only use 7_0 profiles

    CComQIPtr<IWMProfileManager2, &IID_IWMProfileManager2> pIPM2(pIWMProfileManager);

    if(!pIPM2) 

    {

        printf("MapProfile: Failed to QI IWMProfileManager2!\n");

        return E_UNEXPECTED;

    }

    hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );

    if(FAILED(hr))

    {

        printf("MapProfile: Failed to set system profile version!  hr=0x%x\n", hr);

        return hr;

    }

    hr = pIWMProfileManager->GetSystemProfileCount( &cProfiles );

    if(FAILED(hr))

    {

        printf("MapProfile: Failed to get system profile count!  hr=0x%x\n", hr);

        return hr;

    }

    // Invalid profile requested?

    if( (DWORD)iProfile >= cProfiles ) 

    {

        printf("Invalid profile: %d\n", iProfile);

        return E_INVALIDARG;

    }

    return (pIWMProfileManager->LoadSystemProfile( iProfile, ppProfile ));

}

 

Day 3:

在写入ASF文件时,有两种创建Graph的方式:
1.手动创建File Writer和FileSink

    hr = CoCreateInstance(CLSID_WMAsfWriter, NULL,  CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&m_pMux);
    if(FAILED(hr))
     return hr;
    hr  =  m_pGB->AddFilter(m_pMux,  L"WM ASF Writer");

    m_pMux->QueryInterface(IID_IFileSinkFilter,(void**) &m_pSink);
    hr=m_pSink->SetFileName(L"C:\\test.wmv",NULL);
    SAFE_RELEASE(m_pSink);

2.调用ICaptureGraphBuilder的SetOutputFileName方法

    hr = m_pCapture->SetOutputFileName(
     &MEDIASUBTYPE_Asf, // File type.
     _T("c:\\test.wmv"),     // File name, as a wide-character string.
     &m_pMux,             // Receives a pointer to the multiplexer.
     &m_pSink);             // Receives a pointer to the file writer.

 

两者生成的Graph是不同的。前者会使用WM ASF Writer写入文件,而后则使用MUX混合音频和视频后,使用File Writer来写入文件。

 

另外在使用<<DirectShow实务指南>>第2章的AVCap时,发现在公司的机器上,视频被分成5段,在家里则是正常,分析了一下,发现是启用DMR产生的问题,如下:

      VMR(Video Mixing Renderer)是DirectShow的新一代Video Renderer。VMR有两个版本:VMR-7和VMR-9。前者采用了DirectDraw 7技术,仅仅在Windows XP操作系统下可以获得,并且是XP上默认的用于视频显示的Renderer(代替传统的Video Renderer);后者采用了Direct3D 9的技术,是随DirectX9.0一起发布的,但任何时候都不是默认的Renderer。
       安装了DirectX9.0以后,就有4个Video Renderer可供选择使用:传统的Video Renderer、Overlay Mixer、VMR-7和CMR-9。
       VMR主要利用了显卡专有的图形处理能力(VMR做视频的合成和显示时并不占用系统的CPU资源),它能够表现的性能对于硬件的依赖性很高。

在MSDN有更为详细的解析,MSDN: http://msdn.microsoft.com/en-us/library/dd407295(VS.85).aspx

 

这和咱们的最终目的关系不大,不再深入。但它引出一个问题,我们的Camera的输出是什么格式的数据? 我在程序中加入了枚举输出格式的检测(CCaptureVideo::EnumVideoMediaType函数,参考CAnalogInputFilter的相应函数)。

 

发现在公司的摄像头仅支持YUY2 (通用驱动),而家里则支持RGB24和AYUV(厂商提供的驱动),这些格式对于后面写Encoder十分重要,应当需要了解:

 权威网站: http://www.fourcc.org/yuv.php
      AYUV   Combined YUV and alpha
      YUY2   YUV 4:2:2 as for UYVY but with different component ordering within the u_int32 macropixel.
  有了YUV数据,再转成MPEG,似乎是一套比较成熟的技术, ffmpeg是支持的。

*今天的代码还加入了对Video Caputer Filter的Property Page的显示! 还得了一篇有关如何写Filter的文章,我也放到SkyDrive里分享。希望对大家有用,我在这里抛砖,可能抛不了多久了,欢迎多多讨论!

时间: 2024-09-26 06:43:01

DirectShow一次实作笔记的相关文章

DirectShow学习笔记总结

DirectShow是微软公司在ActiveMovie和Video for Windows的基础上推出的新一代基于COM(Component Object Model)的流媒体处理的开发包,9.0之前与DirectX开发包一起发布,之后包含在windows SDK中..DirectShow使用一种叫Filter Graph的模型来管理整个数据流的处理过程,运用DirectShow,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中.这样使在多媒体数据库

我的Android进阶之旅------&amp;gt;Android中编解码学习笔记

编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放license收费等等.最近因为项目的关系,需要理清媒体的codec,比较搞的是,在豆丁网上看运营商的规范 标准,同一运营商同样的业务在不同文档中不同的要求,而且有些要求就我看来应当是历史的延续,也就是现在已经很少采用了.所以豆丁上看不出所以然,从 wiki上查.中文的wiki信息量有限,很短,而wiki的英文内容内多,

APACHE安装笔记

apache|笔记 作者:车东 摘要: WEB应用容量规划:根据硬件配置和WEB应用的特点进行WEB服务的规划及一些简单的估算公式: APACHE安装过程:apache的通用的简化安装选项,方便以后的应用的模块化配置:修改 HARD_SERVER_LIMIT:vi /path/to/apache_src/src/include/httpd.h#define HARD_SERVER_LIMIT 2560 <===将原来的 HARD_SERVER_LIMIT 256 后面加个"0"a

JetSpeed学习笔记(一)

笔记 JetSpeed学习笔记(一) fuweilin 2005-4-7 前言 参加了公司的portal的兴趣小组,今天对portal进行学习.首先上网看了看一些portal的资料,对portal.portlet.portlet container以及JSR168等概念有个基本的了解.决定进一步实战的方式感受portal,于是学习JetSpeed.     1.  JetSpeed介绍JetSpeed是Apache组织开发的一个采用Java和XML的开放源代码的企业信息门户的实现.门户可以让终端

安装配置bugzilla笔记

因为自己在安装配置的时候走了些弯路,所以一方面自己提个醒,另一方面可以让有这方面需要的朋友做个参考 bugzilla是一个可以发布bug以及跟踪报告bug进展情况的开源软件,有关的官方文档可以查看:http://www.bugzilla.org/docs/ 本人是在RH9上安装配置成功bugzilla-2.18rc3的,事先也成功安装配置过2.16.7,后来发现在2.18中加入了图表的功能,觉得蛮有意思的,所以升级了一下.在安装前先确定自己机器上一些软件版本的情况:perl(5.6 or abo

Nutch 笔记(一):Quick Start

最近用到了nutch,目的是针对指定的一些网站抓取其内容,然后做分析用. nutch 笔记是我使用nutch过程一系列总结,写下自己的学习经过和大家一起分享,也希望能得到大家的指点 好了,废话少说,言归正传,第一篇:Quick Start,我们的目标是快速的能跑起来,能检索出我们想要的结果. 首先要明白nutch是什么? nutch是一个基于lucene的开源搜索引擎,它包括了所有你想要的东西,是一个完整的解决方案 . 一:安装JDK 如果你已经安装了JDK,并且已经设置了JAVA_HOME,那

Akka笔记之日志及测试

英文原文链接,译文链接,原文作者:Arun Manivannan ,译者:有孚 在前两篇笔记中(第一篇,第二篇),我们简单地介绍了一下Actor以及它的消息传递是如何工作的.在本篇中,我们将看下如何解决TeacherActor的日志打印及测试的问题. 简单回顾 前面我们的Actor是这样的: class TeacherActor extends Actor { val quotes = List( "Moderation is for cowards", "Anything

DirectShow中写push模式的source filter流程 + 源代码(内附详细注释)

虽然网上已有很多关于DirectShow写source filter的资料,不过很多刚开始学的朋友总说讲的不是很清楚(可能其中作者省略了许多他认为简 单的过程),读者总希望看到象第一步怎么做,第二步怎么做....这样的demo.其实写你的第一个filter是有一定难度的,只要过了这关以后 就容易多了.由于最近需要自己写一个push推模式的source filter,加上刚激活了Blog,不好意思Blog上没有一篇文章,所以将写这个filter的过程写下来 ,为了照顾刚开始学的朋友,我采用第一步第

git笔记:通过给grunt-inline打tag看tag操作

晚上review了下grunt-inline的issues,看到有个兄弟pull request,修正了0.3.0版本的一个bug.于是就merge了下,然后发布了0.3.1版本(这里). npm publish后,突然想到一个问题,发布了这么多个版本了,但好像都没有打过tag,这个不利于版本回溯以及bug trace.svn版本管理里有tag的概念,git里八九不离十也有,虽然还没用过.就简单百度了下,打完tag后顺便做下笔记: 查看tag git tag 比如我在grunt-inline的项