精华内容
下载资源
问答
  • Dshow 向导 Dshow 向导

    2011-08-05 11:12:25
    Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导Dshow向导...
  • dshow player

    2017-03-08 13:52:10
    dshow player 音视频文件播放器
  • BBSxp论坛 Dshow

    2019-12-24 16:57:25
    BBSxp论坛 Dshow
  • dshow uml图dshow uml图

    2009-07-20 00:08:04
    dshow uml图 dshow uml图 dshow uml图 dshow uml图 dshow uml图
  • dshow windowed mode

    2017-02-21 16:40:39
    dshow里面的windowed mode 其实就是把graphedt弹出的框框以windowed mode的方式嵌入到mfc的对话框中
  • DSHOW调试工具

    2016-03-29 19:01:40
    DSHOW调试工具
  • BBSxp论坛 Dshow风格

    2019-12-26 01:29:37
    BBSxp论坛 Dshow风格
  • DShow 摄像头读取

    2015-07-22 17:58:17
    DShow 读取摄像头显示,VMR9方式截图视频图片 DShow 读取摄像头显示,VMR9方式截图视频图片 DShow 读取摄像头显示,VMR9方式截图视频图片
  • dshow简易应用

    2014-09-11 17:45:38
    利用dshow的sdk开发简单的视频采集应用
  • dshow_windowless_mode

    2017-02-22 15:23:04
    dshow_windowless_mode 对应之前的winidowed mode
  • dshow_camera_capture

    2016-07-20 15:11:36
    dshow camera data capture and preview ,support rgb24 and YUY2 data format , vs2010 mfc
  • dshow-X86头文件依赖库.

    2019-05-24 11:39:21
    dshow 32位依赖库、头文件等,刚刚分享了64位的,32位的也分享一下吧
  • WinCE版DSHOW

    2012-11-27 16:12:45
    WinCE版DSHOW,欢迎下载,比较牛的人写的。我负责转载一下。
  • 使用DShow采集摄像头图像并预览,熟悉一下Filter的使用,希望对大家有用
  • 基于dshow启动摄像头拍照视频功能,有demo的完整的例子, 可以编译通过, 此编译基于dshow.h头文件, 需要下载DirectX 9 SDK的安装包. 下载DirectX 9 SDK开发包。这个现在还是比较难搞到的,可以到微软官网上去下载。...
  • 前面几篇介绍了使用相芯SDK美颜,今天不再介绍细节,直接把这个DSHOW类源码恭喜出来,可以参照着前几篇,自己整理下,不过这是我项目中使用的,有可能和你的项目及版本不太一样,需要自己提取有用的部分,仅做参考。...

    前面几篇介绍了使用相芯SDK美颜,今天不再介绍细节,直接把这个DSHOW类源码贡献出来,可以参照着前几篇,自己整理下,不过这是我项目中使用的,有可能和你的项目及版本不太一样,需要自己提取有用的部分,仅做参考。

    目录

    一、win-dshow.cpp 头文件及额外定义的函数及变量

    二、其它函数源码


    展开全文
  • dshow-001 介绍

    千次阅读 2017-02-21 16:21:08
    1 dshow是基于windows平台的一种流媒体机制 可以从基于wdm的数字/模拟设备中捕获,也可以直接从windows的视频中捕获 自动检测用户的音视频设备,自动硬件加速 2 dshow是基于com的技术,c++设计,没有管理api ...

    1 dshow是基于windows平台的一种流媒体机制
    可以从基于wdm的数字/模拟设备中捕获,也可以直接从windows的视频中捕获
    自动检测用户的音视频设备,自动硬件加速
    2 dshow是基于com的技术,c++设计,没有管理api
    dshow可以轻松完成媒体回放/格式转换/捕获任务
    3 使用dshow时对com技术要了解多少
    如果是app开发者:需要了解基本的com知识,包括com对象的初始化 访问接口 在其他接口管理引用计数
    如果是filter开发者:需要了解更多
    4 dshow没有管理api,微软也没有计划出一个管理api
    dshow和directx的关系:dshow里的音视频捕获和回放是用directx中的模块实现的,我们不需要直接用directx的api来实现一个相同功能的dshow
    dshow以前的名字叫Microsoft ActiveMovie
    5 新一代的dmos是否会取代dshow
    dmos是Microsoft DirectX Media Objects
    dshow中可以使用dmos.如果是编解码和特效,使用dmos;如果是其他目的,还是使用dshow比较合适.
    6 如何判断指定的系统中是否有dshow环境
    创建一个filter graph manager对象,如果成功就是有,失败表示没有

    7 如何在不显示属性页的情况下修改filter的设置
    一般情况下,filter都会提供接口来设置属性
    8 构建一个dshow app
    主要头文件是dshow.h 如果有需要也会包含其他头文件
    库文件主要有两个静态库:strmiids.lib主要提供类标志和接口标志 quartz.lib提供AMGetErrorText函数,如果不调用这个函数就不用包含这个
    如果要写一个自定义的filter,最好使用base class这个工程.
    运行库问题:xp sp2以后的都包含了dshow运行库 sp1之前的要自己处理.重要的是微软没有计划对这些库进行进一步开发
    9 dshow app 编程
    什么是filter:在dshow里面一个构建块就是一个filter
    一个filter就是一个软件组成块,主要负责多媒体流上执行的操作.负责接收输入和处理输出
    一系列filter合起来称为filter graph,控制这些filter的更高一级的组件称为filter graph manager,由她来负责数据流(启动和停止)
    对于app一般有3个必要的执行块:app创建一个filter graph manager; 通过manager创建一个graph,这个graph里的所有filter都会依赖于这个app;app通过manager控制graph和filter的数据流,也会响应manager的事件
    10 概览
    一般的流程是创建一个管理对象(filter graph manager),通过管理对象来创建一个filter graph,启动graph.
    对于编程来说,IGraphBuilder接口表示管理对象,她包含了两个子接口:IMediaControl和IMediaEvent,分别用于”控制流的启动和停止”,”接收管理对象返回的事件”.
    11 dshow的大致介绍
    问题:多媒体处理中的几大挑战
    数据量大,需要快速处理
    音视频同步,开始结束和播放过程中都需要有相同步调
    数据来源繁多,本地文件/网络/电视广播/采集设备
    数据格式繁多
    在高级层面,程序员不知道终端用户有什么硬件设备
    dshow的解决方案:
    为了音视频的吞吐量达到预期,使用了direct3d和directsound
    时间戳来保证同步
    不同数据源 不同格式 不同硬件设备, dshow用了模块化的体系接口,利用filter来混合匹配不同的软件组件

    12 filter的深入了解
    dshow使用的模块化结构.com对象每一个执行阶段称为一个filter.
    播放一个avi文件用到了以下几个filter:
    file source filter: 将文件的原始数据读为字节流
    avi splitter filter: 分析avi头,将字节流转换为单独的视频帧和音频样本
    decoder filter: 将视频帧解码为非压缩格式
    video renderer filter: 绘制视频帧
    sound filter: 播放音频样本
    在dshow中一系列filter称为filter graph
    filter有3中状态:running stopped paused
    filter的分类:
    source filter: graph中提供数据的filter,数据源可能是文件/网络/摄像头/各种硬件等等
    transform filter: 有一个input流,一个数据处理过程,一个output stream, 例如:编解码
    renderer fitler: graph的最后一个filter,获取数据并展示给终端用户.例如:视频显示画面,音频丢到声卡,写文件的filter丢到磁盘
    splitter filter: 一个input流,多个output流,常见的有解析一个流,同时输出多个流,看avi就是这种情况
    mux filter: 多个input流,一个output流,合并流,和上面的splitter filter的目标正好相反
    对一个filter的分类并不是绝对的,例如一个filter可以包含了source filter和renderer filter的功能.
    每一个filter都会包含一个IBaseFilter接口,所有的pin都会包含IPin接口.

    13 filter graph manager的深入了解
    前面说到了,一个filter的集合称为一个filter graph, filter graph manager对象就是用来管理graph中的filter的,她是一个com对象
    manager对象都能干些啥:
    协调各个filter之间的的状态变化:graph中的filter的状态变化有严格的顺序(不可能出现render还在进行中,而source已经停止了的情况),状态的变化是app通知的,manager作为app和filter的中间层,app只会把命令传给manager,manager再来协调各个filter的状态变化.eg: 播放时的seek.
    建立一个参考时钟(reference clock):在同一个graph中的filter都是使用同一个时钟,这个时钟称为参考时钟.参考时钟用于确保所有的流的同步.音视频帧上的时间被称为presentation time stamp(就是常说的pts),用于显示时的同步;还有一个称为dts(decoder time stamp 用于解码时的同步),pts只是相对于参考时钟的一个相对数.manager的参考时钟要么取系统时钟,要么取声卡时钟
    将一些graph事件通知给app:manager有一个event队列,通过这个evnet队列可以将graph中出现的的event通知给app.(有点类似windows的消息循环)
    提供方法让app来建立graph:app可以通过manager来想一个graph添加filter;连接两个filter或是取消filter之间的连接.
    manager的方法并不负责数据的流动,数据的流动是filter自己负责的(确切的说是通过filter的pin来完成的).manager的处理都是在单独的线程中进行的,filter和manager运行在同一线程

    14 媒体类型
    由于dshow使用的模块化设计,所以需要一个东西来描述在graph中数据每时每刻的格式,这个东西就是媒体类型 media type
    dshow中需要这么一个描述数字媒体类型,只有当两个filter协商的类型是一致时,这两个filter才能connect,不然就不行.
    dshow中的类型结构是 AM_MEDIA_TYPE, 下面是结构体中重要的成员
    Major type: 主类型, 一个guid, 分类是:音频 视频 上游的流 midi数据等
    Subtype: 子类型, 一个guid, 进一步指定类型, eg:主类型是视频, 子类型是bgr24 或是yuv
    Format block: 进一步描述数据的信息(eg:子类型是nv12,但并没有描述帧率,长宽等),成员名是pbFormat, 她是一个void*类型的指针,针对不通过的数据类型,这个指针指向不同的数据结构.加上另一个成员cbFormat就能取出结构体数据,在每次使用pbFormat指向的结构体之前,最好先检查cbFormat这个参数.

    如果我们在filter中要查看rgb24视频的信息:
    
    HRESULT CheckMediaType(AM_MEDIA_TYPE* pmt)
    {
        if (nullptr != pmt &&
            MEDIATYPE_Video == pmt->majortype &&
            MEDIASUBTYPE_RGB24 == pmt->subtype &&
            FORMAT_VideoInfo == pmt->formattype &&
            pmt->cbFormat >= sizeof (VIDEOINFOHEADER) &&
            nullptr != pmt->pbFormat)
        {
            VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->pbFormat;
            ...
    
            return S_OK;
        }
    
        return E_POINTER;
    }
    AM_MEDIA_TYPE还包含了一些其他参数,但是对于filter来说,其他参数都是用不上.
    

    15 媒体样本和分配
    filter通过pin来流通数据,从filter的output pin流想另一个filter的input pin. 在input pin上调用IMemInputPin::Receive接口来获取output pin传来的数据.
    依赖不同的filter,为媒体数据申请内存有多种方式:
    在heap上,
    在directdraw上用共享gdi内存
    或是其他分配方式
    申请内存(分配内存)的对象称为allocator 分配器. 是通过IMemAllocator接口暴露的一个com对象
    当filter的pin connect之后,必须有一个pin提供一个allocator. dshow提供了一系列方法让pin来提供allocator.
    当流开始时, allocator会创建一个缓冲池(buffer pool),在流中,上游流将数据写入,下游流来读取,期间上游流不会提供任何buffer的原始指针给下游流,相反,是利用com对象(称为media sample媒体样本)来管理这些buffer,这写media sample是通过allocator创建的.
    media sample通过IMediaSample接口暴露, 一个media sample包含下面几个元素:
    一个指向基础缓冲区的指针
    一个时间戳: 表示pts
    各种各样的flags: eg:从上个sample到这个sample,是否有中断
    一个媒体类型(可选):filter是否要改变meida type. 一般sample没有media type 表示 从上一个sample到这个sample, media type没有改变
    当一个filter使用buffer, 那么她就掌管sample的引用计数.allocator利用这个引用计数决定什么时候可以重用这个buffer.当filter释放这个sample之后,allocator就能重新利用这些缓冲了.

    16 在graph中,硬件设备是怎么玩的
    filter封装
    dshow的filter是用户态的软件组件. 如果内核态的硬件设备(eg:音视频采集卡)要加入到这个graph来耍,那么这些设备就要表现的像一个用户态的filter(eg: 音频采集filter; vfw采集filter; tv tuner filter; tv audio filter等等). dshow提供了函数来让这些设备表现(或者说封装)成一个用户态的filter. 下一个问题:dshow是如何做到的? :dshow提供了一个ksproxy filter, 所有的dwn流设备都可以用这个filter表示.硬件厂商可以通过扩展ksproxy来支持自定义功能, 说白了就是提供一个ksproxy插件.(ksproxy.ax是windows上专门处理音视频的filter)
    这些封装的的filter提供的com接口就是这些设备提供的功能. app就是通过这些接口来和filter传递信息的. filter将com接口的调用传递给设备驱动(这到了内核态了),然后将结果返回给app. tv tuner,tv audio, ksproxy filter支持使用IKsPropertySet接口来设置自定义属性,而vfw capture filter, audio capture filter不能通过这种方式扩展
    对于app来说,这些封装filter让app可以控制设备就像控制其他filter一样(换句话说:app控制封装filter和控制其他filter一样,没有额外要求).
    vfw
    vfw采集filter支持早期vfw采集卡,如果系统中存在vfw采集卡,dshow会自动检测到,并加入到graph中
    声卡
    新一代的声卡,就像麦克风上的输入插孔.一般这些声卡都可以控制每一个输入音频的音量大小/高音/低音,在dshow中声卡的输入,混音都被封装在audio capture filter中
    dwm流设备
    新一代的硬件解码和采集都遵循wdm规格,wdm比vfw功能更加强大:枚举采集格式;编程控制视频参数(色彩和亮度)等等
    为了支持dwm, dshow提供了一个ksproxy filter(ksproxy.ax 瑞士军刀),这个filter做了很多事.
    内核流
    wdm设备支持内核流
    内核流不会将数据从内核态切换到用户态(切换的这个代价太大), 内核流不会对cpu造成负担,而且数据从一个设备到另一个设备不会使用系统的主内存
    从app上看,数据是从一个filter移到另一个filter,实际上数据可能从来没有切换到用户态,(视频采集数据,在内核态直接丢到显卡),在某些场景下eg:将数据写文件时,就要把数据从内核态切换到用户态,不管怎么样数据没有必要拷贝到内存.
    一般app开发者不需要考虑内核流.

    17 graph构建组件
    dshow提供了以下方式来构建graph:
    filter graph manager: 这个对象控制着graph,支持IGraphBuilder IMediaContrl IMediaEventEx, app都会利用这个对象
    capture graph manager: 这个对象提供了额外的方式来构建graph. 她原本设计就是为了执行视频捕获,支持ICaptureGraphBuilder2
    filter mapper和system device enumerator,这些对象用于注册到用户的系统
    dvd graph builder,这个对象主要是为了dvd回放和导航,支持IDvdGraphBuilder接口
    智能连接 inteligent connect,用于智能创建全部或一部分graph.

    18 深入了解graph的构建
    如果要创建一个filter graph ,利用IDD_IGraphBuilder 参数
    filter graph支持下面几种构建graph的方法:
    IFilterGraph::ConnectDirect : 尝试直接让两个pin连接
    IGraphBuilder::Connect : 尝试让两个pin连接, 一般会直接连接,如果不能直接连接,会智能在中间添加缺失的filter
    IGraphBuilder::Render : 从output pin开始构建剩下的graph
    IGraphBuilder::RenderFile : 构建一个完整的文件回放graph
    IFilterGraph::AddFilter : 向graph中添加一个filter
    上面这些方法提供了构建graph的3中基本途径:
    manager构建整个graph
    如果需要播放一个有格式的文件(avi,mp3,wav,mpeg),使用RenderFile
    工作流程是这样的:RenderFile会从注册表查找可以解析文件的source filter, graph之后的部分也是从注册表查找,查找过程如下:
    filter的类别标志了filter的基本功能(视频filter处理视频,编码filter处理编码等)
    媒体类型描述了filter可以接收哪种数据,输出哪种数据
    还有一个优先级参数,如果有多个filter都满足上面两点,那谁的优先级高选谁的
    manager是通过filter mapper对象来搜索注册表的,filter mapper也是一个com对象,作用就是在注册表查找相关的filter
    当搜索到合适的filter之后,manager会将filter加入到graph,每个filter添加时,都会先进行pin连接, 这是一个协商过程,如果pin连接失败,就会换另一个filter来尝试.这个搜索添加的过程是一个迭代的,直到所有的stream都rendered
    manager构建部分graph
    如果要做的事并不仅仅是播放一个文件, 那app必须执行一部分graph的工作.
    eg: 视频采集app必须选择capture source filter加入到graph
    eg: 写数据到avi文件, 必须添加avi mux 和file writer filter到graph
    一般都是让manager完成整个graph.
    我们可以通过上面的Render方法来实现从一个pin中预览
    app构建整个graph
    在某些场景,app必须构建graph的每一个filter,这时可以使用上面的AddFilter方法,然后遍历filter上的pin,再将pin连接起来,连接可以使用Connect和ConnectDirect

    19 深入了解智能连接
    智能连接是manager构建graph的一种机制, 她包含了一系列相关的算法来选择filter并将她们添加到graph
    这部分适合添加filter遇到问题的读者,或是想让自己的filter可以作为智能连接的一部分的filter开发者
    后续若有需要再补齐

    20 graph中的数据流向
    app开发者不需要了解细节
    filter开发者需要理解
    后续若有需要再补齐

    21 dshow中的事件通知
    filter通过event通知告诉manager现在有一个event通知,这个event可能是流结束,也可能是render中出现错误.
    manager会自己处理一部分,剩下的会丢给app来处理
    dshow中的事件通知和windows的消息循环类似,app可以接收event,然后处理.app也可以取消dshow对某个event的默认处理,这样dshow再接到这个event,就直接丢给app去处理.

    22 app如何接收event通知
    首先manager暴露了3个接口来支持event通知
    IMediaEventSink: filter通过她来post一个event
    IMediaEvent: app通过她来接收event
    ImediaEventEx: 继承扩展IMediaEvent
    整个流程是这样的:
    filter通过IMediaEventSink::Notify方法post一个event到manager
    app通过IMedaiEvent::GetEvent方法获取一个event,这个方法是阻塞的,知道event return或超时
    event包含了哪些信息:
    一个event code:指明event type
    两个附加信息的参数,根据event code的不同,这两个参数可能是不一样的东西,指针,返回码,引用时间等等
    需要注意的是:在app使用GetEvent之后,要使用IMediaEvent::FreeEventParams来释放参数

    long evCode;
    LONG_PTR param1, param2;
    HRESULT hr;
    while (hr = pEvent->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr))
    {
        switch (evCode)
        {
            ...
        }
        hr = pEvent->FreeEventParams(evCode, param1, param2);
    }
    
    app取消manager对默写event的处理:IMediaEvent::CancleDefaultHandling
    app启用manager对默写event的处理:IMediaEvent::RestoreDefaultHandling
    当然,如果manager没有对指定event的默认处理,那么上面两个函数都是无效的
    

    23 app接收event
    除了上面说的GetEvent接收event,还可以使用windows的消息循环来实现:
    当manager接收到一个event时,发送一个消息WM_xxx
    app用windows的消息循环来处理
    后续若有需要再补齐

    24 参考时钟 reference clocks
    前面说过了:dshow的出现目的之一是为了解决同步问题,解决方式是graph里统一的参考时钟
    任何暴露IReferenceClock接口的对象都可以被当作是参考时钟,播放声音时使用的是硬件时间,回放一个文件时使用的是系统时间.
    在dshow中, 一个参考时钟的单位是100ns, 获取当前时钟使用IReferenceClock::GetTime方法, 一个单独的GetTime是没有什么实际意义的,两个GetTime的增量才是有用的.
    虽然参考时钟的精度有时是不同的(一般是100ns,实际上会小一点),但GetTime保证是递增的.
    这里有一个小问题:GetTime是递增,如果此时参考时钟使用的是硬件时钟,正好遇到了硬件时钟回跳(重新对时导致时间比前面的时间小),这时GetTime返回的一直是之前最后一次报告的时钟,直到硬件时钟增大到比她大时.

    默认的参考时钟
        如果app选择了一个时钟,就用这个
        如果graph包含了一个支持IReferenceClock的live source filter,就用这个
        如果不包含live source filter, 如果有任意一个filter支持IReferenceClock,就用这个filter.(如果有播放声音,会自动选取声卡的时钟)
        如果上面几个都不满足,那使用系统时钟,基于系统时间
    
    如何设置时钟
        app使用IMediaFilter::SetSyncSource方法来设置
        使用IMediaFilter::SetSyncSource,参数为NULL, 意思是不使用参考时钟. 某些情况下是为了尽可能快的处理样本sample
        使用IFilterGraph::SetDefaultSyncSource来重置默认时钟
        当参考时钟改变后,manager会用IMediaFilter::SetSyncSource通知所有filter, app从不会对filter直接调这个接口.
    

    25 时钟时间
    dshow里有两种相关的时钟时间: 参考时间和流时间
    参考时间 reference time, 就是参考时钟表示的绝对时间
    流时间 stream time, graph最后一次启动的时间
    当graph状态是running: 流时间等于参考时间减开始时间
    当graph状态是paused: 流时间就是暂停时的那个流时间
    当graph状态是stopped: 流时间是未定义
    在一个seek操作之后: 流时间是0
    当一个media sample 有一个时间戳, 这个时间戳的意思就是sample被rendered时的流时间,也被称为pts(presentation time stamp)
    当app调用IMediaCtrol::Run时, manager会对每个filter调用ImediaFilter::Run.

    26 time stamp
    dshow里的时间戳
    时间戳是什么:media sample的开始和结束时间,用流时间计量
    timestamp有时是指pts. 不是所有格式都用相同方式来使用时间戳:eg:在mpeg中不是所有的sample都有时间戳.
    当render filter收到一个timestamp, 她调度render是基于timestamp的.如果sample没有timestamp或是timestamp迟到了,sample会立马render;其他情况下要等待直到sample的start time.等待的接口是IReferenceClock::AdviseTime方法
    一般打时间戳都是在source filter或是parse filter里,下面是指导方针:
    文件回放: 第一个sample的时间戳是0. 后续的时间戳决定于sample长度,回放速度,格式. filter解析文件,就是要计算正确的时间戳
    音视频捕获: 每一个sample都会有时间戳,且这个时间戳等于捕获时的流时间, 相应的有以下注意事项
    从预览pin出来的视频是没有时间戳的,为什么会这样? 由于graph的潜在因素,如果视频帧打上时间戳,到达render时绝对会迟到,如果有质量控制,会导致render丢帧.不管怎样 media time是准的.
    音频捕获filter用的是自己的buffer,而不是用的音频驱动的buffer.音频驱动在固定间隔时间将数据丢到capture filter的buffer中,这个间隔取决于驱动,但不会大于10ms. audio sample 上的timestamp表示驱动将数据丢到audio capture filter缓冲的时间. 这个时间有可能有些许不准,尤其是app用了一个非常小的buffer
    mux filter: 依赖于输出格式,mux filter可能会生成timestamp,也可能不会.eg: avi文件,用了一个固定的帧率,而没有使用timestamp, 而在播放的时候,就会生成timestamp(就像上面的文件回放一样)
    给sample打timestamp,调用IMediaSample::SetTime方法
    媒体时间 media times
    这是一个可选的,filter可以给sample指定一个media time.在video stream中media time表示帧数;在audio stream中media time表示采样数
    renderer和mux 可能会根据media time来决定丢帧,不管怎么样,filter没有要求设置media time,为一个sample设置media time使用IMediaSample::SetMediaTime方法

    27 了解live sources
    实时数据源,也称为push source. eg:视频采集和网络广播.一般地,live source不能控制数据到达的速率
    一个filter怎么才能被称为live source?
    需要满足以下条件之一即可
    调用IAMFilterMiscFlags::GetMiscFlags方法返回AM_FILTER_MISC_FLAGS_IS_SOURCE,且至少有一个output pin暴露了IAMPushSource接口
    暴露了IKsPropertySet接口,且有一个捕获pin(PIN_GATEGORY_CAPTURE)
    如果live source提供了时钟,那么manager会使用这个时钟作为参考时钟, 就像上面说的那样
    延时 latency
    filter的延时主要是处理sample花的时间.对于live sources来说,延时由sample的buffer大小决定
    eg: 经过graph, 视频延时33ms,音频延时500ms,那每一帧视频到达video render要比响应的audio sample要早470ms, 除非graph来补偿,否则音视频永远不同步
    live source 同步的接口是IAMPushSource. manager要同步live source,除非先调用IAMGraphAtreams::SyncUsingStreamOffset来启动同步模式.如果开启同步,manager会对每个filter调用IAMPushSource. 如果filter支持IAMPushSource,manager可以通过IAMLatency::GetLatency方法来获取filter的延时,manager知道每个filter的延时之后,就知道了整个graph的延时,之后调用IAMPushSource::SsetStreamOffset让每个source filter知道offset,更具体一点就是告诉打时间戳的filter.
    上面音视频的同步主要用于预览, 值得注意的是:预览pin中出来的sample没有时间戳,因此如果要用上面的音视频同步策略,就必须用capter pin出来的数据.
    IAMPushSource接口已经支持vfw 和 audio filter
    速率匹配 rate matching
    如果sample捕获的时候用一个参考时钟,render的时候用另一个参考时钟,那就会出现问题.一般live source不会控制生产的速度,只能让render来进行一个速度匹配.
    现今,出现这种问题的主要是audio, 对于audio 一般有以下规则:
    如果graph没有使用参考时钟,那么audio render就不需要尝试去 match rate. (如果没有参考时钟,那sample来了就立马render了,这时并不关心速度)
    graph有时钟的情况, audio render检查是否有live source, 如果没有,就不需要match rate
    audio检查到有live source的情况, 并且live source支持IAMPushSource接口, audio render调用IAMPushSource::GetPushSourceFlags,返回值如下:
    AM_PUSHSOURCECAPS_INTERNAL_RM: 这个标志表示live source自己有一套rate-match的机制,所以audio render不需要match rate
    AM_PUSHSOURCECAPS_NOT_LIVE: 这个标志表示这个source filter并不是一个live source, 所以render并不需要match rate
    AM_PUSHSOURCECAPS_PRIVATE_CLOCK: 这个表示source filter是基于另一个时钟来打时间戳的,那这个时候是需要match rate.(万事都有例外:如果sample没有时间戳,就忽略这个标志)
    如果IAMPushSource::GetPushSourceFlags返回的不是以上flag,而是0,那么audio render的行为要基于graph时钟以及sample是否有时间戳来决定:
    如果render使用的不是graph时钟,且sampel有时间戳: 进行match rate
    如果sample没有时间戳,render会试图进行match rate
    如果audio使用的是graph时钟,也会进行match rate

    28 graph的动态创建
    graph已经构建好了,需要更改,就是动态构建,流程是先停止graph,修改,重启graph,这是最好的方式
    特殊情况下,需要在graph不停止的情况下修改graph, eg:
    在回放中增加一个视频特效处理filter
    source filter更改了媒体类型,接下来需要一个新的解码filter
    app在graph增加了一个新的视频流
    以上情况都属于动态graph构建,一句话:在graph运行中修改graph就是动态构建.
    那么动态构建分三种情况:
    动态格式改变: 只是格式改变,没有修改graph里的filter
    动态重连: 在graph里增删filter
    filter链: 增删控制一个filter链

    29 graph动态构建之重连
    就是在graph里增删filter,这时pin是要重连的,也可以理解为filter重连
    一般dshow的graph运行时pin不能重连,graph需要在pin重连之前先停止graph.万事都有例外,有些filter就是支持pin重连,这个过程称为动态重连
    动态重连要么由app完成要么由graph完成
    eg: filter a –> output pin 001
    input pin 002 –> filter b –> output pin 003
    input pin 004 –> filter c
    如果filter a连着b和c,这时要删掉b,而且是动态的,首先需要满足以下几点:
    filter c的input pin 004需要支持IPinConnect接口,没有这个接口,就不能在运行过程中重连
    filter a的output pin 001 在重连出现时,需要有阻塞媒体数据的机制,换句话说就是重连时不能有数据从001到004,一般pin 001必须支持IPinFlowControl接口,这个接口用于在重连时阻塞数据
    动态重连的过程:
    001阻塞数据
    001和004重连,001到004中间有可能智能补全
    解除阻塞,让数据流下去
    动态重连的具体代码细节,后续若有需要再补齐

    30 graph动态构建之filter链
    首先要搞明白什么是filter链: 一个filter的集合,需要满足一下条件
    每一个filter最多只有一个output pin,一个input pin
    每个filter都连接一起,没有连在一起的不算
    后续若有需要再补齐

    31 plug-on distributors
    简称pids, 是一种扩展manager功能的方法,利用com对象实现
    后续若有需要再补齐

    32 使用dshow
    前面31个问题都是对dshow的一个介绍,接下来主要是结合理论的代码

    001 使用graphedt模拟一个graph
    graphedt主要是用于调试的工具, 构建graph的可视化工具

    002 外部程序加载graph
    graphedt 可以加载外部程序创建的graph, win2000之后就开始支持了, vista之后需要先注册proppage.dll
    后续若有需要再补齐

    003 保存filter graph
    利用graphedt保存graph,后缀是.grf, 这么做是用于调试app
    也可以在app中保存graph,然后在graphedt中调试
    后续若有需要再补齐

    004 加载graph文件
    上面是保存.grf, 这是用app加载.grf文件, 是使用IPersistStream接口完成的
    后续若有需要再补齐

    005 graph文件格式
    后续若有需要再补齐

    006 dshow里面的video render
    dshow里提供了多种filter来render video:
    video renderer filter: 适用于所有支持dirextX的平台,没有特殊的系统要求.
    如果可以,filter会使用directdraw来进行render,如果不行就使用gdi.
    在xp以前是默认video renderer
    video mixing renderer filter 7: vmr-7, xp可用,xp的默认video renderer,使用directdraw7来render
    相比上一个,提供了很多强大的功能
    video mixing renderer filter 9: vmr-9, 使用direct3D 9来render
    适用于所有支持directX的平台,并不是默认的video renderer,因为她比第一个filter有更多的系统要求
    overlay mixer: 为dvd和视频广播设计的filter,支持vpes,MPEG-2的硬件编码,数字电视视频直接丢到显卡.
    enhanced video renderer: evr, vista之后的产物, 相比上面几个render,这个有更高的视频性能
    一般,vista之后的系统使用evr更合适,而vmr-9适用于全平台.
    好吧说到render,dshow里有两种render模式: windowed mode 和 windowless mode
    一个是render自己创建一个窗口,一个是render直接画在app提供的窗口上面
    video render filter只支持windowed mode, vmr-7, vmr-9支持两种模式,为了向后兼容,她们默认都是windowed mode,不过优先选择还是windowless mode,再到EVR就只支持windowless mode了.

    007 如何选择正确的video renderer
    EVR: 使用direct3D 9, 要求vista及以后
    VMR-9: 使用direct3D 9, 需要xp及以后
    VMR-7: 使用directDraw, xp
    overlay mixer: directDraw,支持硬件覆盖(直接把数据丢到显卡)
    video renderer filter: directdraw或gdi. 这种方式已经不推荐了

    选择哪种renderer主要看要支持的平台, VMR-7现在用的也少,win10上已经很少看到了
    在vista及以后,推荐使用evr(如果硬件支持的话), evr性能卓越,主要是为了dwm设计. 退而求其次,选择vmr9或vmr7
    vista之前优先使用vmr9,退而求其次使用vmr7
    老系统,可以使用overlay mixer或是video renderer filter.
    
    IGraphBuilder::Render和RenderFile方法默认使用VMR-7,如果硬件不支持VMR-7, 会使用video renderer filter.
    EVR和VMR-9从来都不是默认的renderer,这是为了向后兼容,不过条件允许,最好还是使用EVR和VMR-9
    

    008 深入了解windowed mode
    重复一下:video renderer filter只使用windowed mode; vmr7和vmr9默认是windowed mode,但也支持windowless mode; EVR只支持windowless mode
    windowed mode, 由render自己创建一个窗口,窗口属性是top-level,带边框,标题栏, pop
    好吧,再啰嗦一下基本概念: 要创建一个dshow的app,主要的步骤有:构建一个graph, 启动/停止,释放资源.
    构建graph: 像上面说的,可以render,renderfile,还可以完全自己添加filter构建,不管是智能构建还是半智能构建还是全人工构建,这步的目的是弄出一个graph.
    启动/停止: 这步可以通过dshow暴露的多个接口完成, 不过一般使用IMediaControl来简单控制就ok了,不够用的可以翻msdn
    释放资源: 这步主要是释放com对象,也有dshow api指定要释放的.
    接下来对着windowed_mode工程说一下, 要实现windowed mode,总共有5个步骤:
    http://download.csdn.net/download/bai_lu_sz/9759823(windowed_mode工程)
    在OnInitDialog中处理一下dshow的初始化:graph对象的创建,com环境等
    windowed mode的处理全部放在test按钮的处理中OnBnClickedBtnTest,
    接下来直接调用graph对象的RenderFile方法来智能构建一个完成的graph(注意上面一个是创建graph对象,一个是构建graph,这个构建就是用多个filter组成一个graph,前一个创建是创建一个com对象,后一个构建的graph是dshow里的一个概念)
    graph构建好之后如果调用控制接口的Run就会弹出一个窗口,然后显示音视频,而此刻讨论的中心是windowed mode,也就是把弹出的这个窗口作为一个子窗口嵌入到另一个窗口中,而不是直接在指定的窗口绘制数据,所以windowed mode要做的工作主要是graph构建完成之后,Run之前处理.
    i: 获取IVideoWindow对象, IID_IVideoWindow
    ii: 设置一个父窗口(想让这个子窗口嵌入到哪个窗口就把那个窗口设为这个子窗口的父窗口)
    iii: 更改子窗口的风格(默认的子窗口是pop的,要嵌入,需要设置为child)
    iiii: 定位子窗口,并处理一下WM_MOVE消息
    iiiii: 清理(包括暂停graph,隐藏子窗口,重置子窗口的拥有者属性)
    总的来说,大部分设置在graph构建之后,run之前设置就ok了
    工程中添加了一下其他东西,也属于比较重要的(反正对着msdn写出来的有问题,主要是很多细节藏在其他地方):
    第一个:RenderFile之后的清理操作, 函数有一个属性是可重入性,就是可以调多次,所以清理操作很重要.msdn上写的清理,只是释放了资源,但是graph中的那么多filter是没有处理的,如果这个时候再RenderFile一个文件,那么两个文件都会播放,msdn上有写的,如果要干净的,就需要把graph里的所有filter全部删掉
    第二个:当文件播放完或是出现问题之后的处理,为了不出现卡住的情况,msdn上有两种处理方式,一种是利用mfc的消息循环,一种是用dshow的方法,例子中选择了mfc的消息循环

    009 深入了解windowless mode
    就像上面讲的一样,vmr7和vmr9都支持windowless mode,evr只支持windowless mode. 这种模式是IVideoWindow的重大改进.
    如果是说是重大改进,那windowed mode必定是存在重大缺陷才发出了windowless mode:
    最重要的是线程间的消息发送可能会导致死锁
    manager会将某些windows消息(例如WM_PAINT)丢给video renderer filter. app会通过IVideoWindow让manager保持正确的状态.
    如果视频窗口(可以理解windowed mode子窗口嵌入的父窗口)要接收鼠标键盘事件,就必须要设置一下子窗口,让子窗口把消息转到视频窗口.这个设置称为message drain
    为了防止复制问题,视频窗口必须有正确的窗口风格
    为了解决上面几个问题,windowless mode是用directdraw直接把数据绘制在指定的窗口中.这样少了一个中间的子窗口,效果好多了.主要是明显少了很多死锁.vmr在使用windowless mode时并没有暴露IVideoWindow接口,因为没有必要.
    vmr7和vmr9虽然暴露的是不同的接口,但是步骤都是一样的
    vmr-9用的是direct3d,所以要包含两个头文件:d3d9.h和vmr9.h
    和上面的windowed mode一样,还是对着例子来:
    http://download.csdn.net/detail/bai_lu_sz/9760769 以vmr9为例子
    因为指定了video mixer renderer9 filter 这个filter,所以不能想之前那样全自动构建graph,需要先指定vmr9,
    i: 创建一个graph对象
    ii: 创建一个vmr9 filter并加入到graph, 加入的时候为filter指定一个名字
    iii: 通过IVMRFilterConfig9::SetRenderingMode设置VMR9Mode_Winidowless
    iiii: 获取IVMRWindowlessControl9接口
    iiiii:通过上面得到的接口设置哪个窗口来接收媒体数据,位置,是否裁剪等
    接下来还有处理何时绘制,窗口移动时,大小变化时,已经媒体数据分辨率改变时的处理.就是处理WM_PAINT WM_SIZE 等, 必须要修改的是wm_paint.
    wm_paint的处理方式msdn上有一个简单的.当绘制的数据覆盖在控件上导致控件闪烁时,需要设置窗口的属性(控件是否绘制属性,这个属性在mfc上设置)

    展开全文
  • dshow 过滤器, 功能是将yuy2数据转换成yv12,示例是通过捕获摄像头yuy2数据转换成yv12,在转换成rgb24显示在界面上,vs2010工程
  • DSHOW SDK 学习笔记

    2011-04-28 09:40:46
    介绍DShow开发的常用方法,并且对这些方法有代码描述.
  • 使用DShow进行摄像头采集预览,并可以随时拍照,其中有获取采集设备列表、获取设备支持分辨率等功能,希望对大家有用
  • Video capture DSHOW VS VFW

    2010-06-03 17:36:07
    Video capture DSHOW VS VFW Video capture DSHOW VS VFW Video capture DSHOW VS VFW
  • Dshow时间戳

    千次阅读 2013-11-25 00:36:06
    Directshow中的时钟(Time and Clocks in Dshow) 1、参考时钟: 任何一个引出IReferenceClock 接口的对象都可以作为参考时钟。参考时钟可以是Filter提供,例如声卡就可以提供一个硬件的时钟。当然,可靠的时钟...
    Directshow中的时钟(Time and Clocks in Dshow)
    1、参考时钟:
    任何一个引出IReferenceClock 接口的对象都可以作为参考时钟。参考时钟可以是Filter提供,例如声卡就可以提供一个硬件的时钟。当然,可靠的时钟就是采用系统的时间。
    调用IReferenceClock::GetTime可以获取时钟的当前时间。
    尽管时钟的精确性还有所变动,但是GetTime方法返回的保证时间是增加的。也就是说,时钟不会倒退回去,比如,对硬件时钟进行了调整,GetTime方法就返回上次的时间。
    缺省的参考时钟
    当Graph运行的时候,Filter图表管理器会自动选择一个参考时钟的,选择时钟的法则如下
    (1)如果应用程序选择了时钟,就采用应用程序选择的时钟
    (2)如果Graph包含一个活动的源Filter,这个filter有IReferenceClock接口,那么就用这个时钟。
    (3)如果Graph中不含有任何活动的源Filter,就选用graph中任何暴露IReferenceClock接口的Filter,选择的方法是从Renderers逆流向上,连接的filter优先,没有连接的filter次之。
    (4)如果没有任何filter符合条件,就采用系统参考时钟System Reference Clock
    设置参考时钟
    如果你想为graph设置新的时钟,应用程序可以调用图表管理器的接口IMediaFilter::SetSyncSource方法来选择一个参考时钟。

    2、Clock Times
    Directshow定义了两个相关的时间,参考时钟和 数据流时间
    参考时间是参考时钟的绝对时间
    数据流时间和graph开始的时间有关。
    当graph正在运行,流时间就等于从开始时间计数的时间,当graph暂停,流时间就等于它暂停开始的时间,当graph停止时,流时间不确定。
    当一个sample具有时间戳t,就意味着这个sample应该在流时间t播放因此,流时间也叫播放时间。
    当应用程序通过IMediaControl::Run来运行graph时,在graph内部也调用了IMediaFilter::Run
    3、时间戳
    时间戳采用的是流时间,它在sample标上开始和结束时间。时间戳也叫播放时间,通过后面的知识你会了解到,并不是所有格式的数据流都采用同一种样式的时间戳。
    当renderer Filter接收到sample,它会根据sample的时间戳进行排序,等到该sample的播放时间到了,就开始播放该sample,从到达到开始播放的时间,可以通过IReferenceClock::AdviseTime获得。如果sample来晚了,或者sample没有时间戳,filter就立即播放sample。
    展开全文
  • DSHOW网络多媒体.rar

    2010-04-02 13:25:11
    DSHOW网络多媒体.rar DSHOW网络多媒体.rar DSHOW网络多媒体.rar
  • DShow 播放视频

    2019-01-25 15:27:19
    dshow.h> #include <windows.h> #include <vector> #include <comutil.h> using namespace std; #pragma comment(lib,"comsuppw") #pragma comment(lib...
    #include <dshow.h>
    #include <windows.h>
    #include <vector>
    #include <comutil.h>
    using namespace std;
    #pragma comment(lib,"comsuppw")
    #pragma comment(lib, "strmiids")
    #pragma comment(lib, "ole32")
    #pragma comment(lib, "oleaut32")
    int main(void)
    {
        IGraphBuilder *pGraph = NULL;
        IMediaControl *pControl = NULL;
        IMediaEvent   *pEvent = NULL;
    
        // Initialize the COM library.
        HRESULT hr = CoInitialize(NULL);
        if (FAILED(hr))
        {
            printf("ERROR - Could not initialize COM library");
            return 1;
        }
    
        // Create the filter graph manager and query for interfaces.
        hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                            IID_IGraphBuilder, (void **)&pGraph);
        if (FAILED(hr))
        {
            printf("ERROR - Could not create the Filter Graph Manager.");
            return 1;
        }
    
        hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
        hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
    
        // Build the graph. IMPORTANT: Change this string to a file on your system.
        hr = pGraph->RenderFile(L"E:/b.avi", NULL);
        if (SUCCEEDED(hr))
        {
            // Run the graph.
            hr = pControl->Run();
            if (SUCCEEDED(hr))
            {
                // Wait for completion.
                long evCode;
                pEvent->WaitForCompletion(INFINITE, &evCode);
    
                // Note: Do not use INFINITE in a real application, because it
                // can block indefinitely.
            }
        }
        pControl->Release();
        pEvent->Release();
        pGraph->Release();
        CoUninitialize();
        return 1;
    }
    

     

    展开全文
  • Dshow2_简单链路_智能连接.rar
  • Video Capture DSHOW VS VFW

    2010-06-04 12:25:16
    Video Capture DSHOW和VFW两份代码; 需要安装DSHOW,调整DSHOW库目录。
  • Dshow1_简单播放器

    2012-08-03 17:40:27
    Dshow1_简单播放器,需要配置directx
  • 之前博客中用到的DSHOW和X264的头文件和库,请下载使用
  • pc 使用dshow采集视频,直接输出yuv格式的,以便后续处理使用, pc wave采集音频,做了封装 可以直接使用 vs2010工程,可直接编译

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,438
精华内容 2,175
关键字:

dshow