视频渲染

    技术2022-05-11  22

    要为CE做硬件解码的filter,除了驱动部分,更多的工作在于支持媒体类型的查询、适配上。视频渲染组件,是整个filter模型的最后一个环境,负责显示和输出。视频渲染只是显示驱动的控制者,不需要进行媒体sample的处理。

     

    视频渲染有2个输出途径:

    1、  GDI

    2、  Ddraw

     

    当graph首次连接时候,视频渲染尝试使用GDI。它需要连接上主显示器支持的某种RGB媒体格式。当进入暂停模式时候,视频渲染会给Ddraw尝试分 配表面(前提是显示驱动支持Ddraw模式)。当某些应用场景不支持Ddraw时候,也会切换回GDI模式(如播放时候,在Ddraw视频表面之上,显示 某个菜单。这个时候整个画面,包括Ddraw视频,都要切换回GDI模式)。

     

    选择加速媒体类型:

    当视频渲染进入暂停阶段(filter的几个状态,请参考相关资料),可以进行Ddraw表面的分配工作。视频渲染枚举上层filter的所有媒体类型,然后分配出一个支持以上某个媒体类型的表面。如果上层filter是WMV DMO,那么这个filter支持以下输出媒体类型:

    YV12NV12YUY2I420IYUVUYVYYVYURGB565RGB555RGB32RGB24RGB8

    视频渲染首先会尝试分配出flip overlay表面,然后才是无filp功能的表面:

    1、对于上层filter支持的每种媒体类型,按顺序进行:

    A、尝试为这个类型,分配flip表面

    B、如果成功,调用上层filter的输出pin上QueryAccept函数

    C、如果成功,就使用这个表面

     

    2、如果flip表面分配失败,尝试分配flip的主表面

    A、分配成功,调用上层filter的输出pin上QueryAccept函数

    B、如果成功,就使用这个表面

     

    3、  如果flip主表面分配失败,对于上层filter支持的每种媒体类型,按顺序进行:

    A、尝试为这个类型,分配无flip功能的表面

    B、如果成功,调用上层filter的输出pin上QueryAccept函数

    C、如果成功,就使用这个表面

     

    这个过程中,如果上层filter想使用YUV格式,那它需要控制媒体类型的选择。如果显示驱动也可以提供这个类型的表面的话,那这个媒体加速类型就能定下来。整个选择是由上层filter控制,显示驱动被动的过程。

     

    视频渲染的动态格式变更:

    对于一个优先选择的媒体类型,通常希望有overlay flip的表面。不尽人意的是,根据显示驱动的上报功能,当视频按原始大小播放时候,flip overlay的表面不一定能有效的使用起来。当用户进行放大、缩小操作,这个表面也可能无效。这取决于Ddraw硬件上报的功能中 dwMinOverlayStretch和dwMaxOverlayStretch的内容。当显示驱动不支持拉伸,而视频渲染正在使用overlay表 面,那么就要切换到GDI模式。GDI模式能做拉伸处理。

     

    每次上层filter从视频渲染中,申请一个新的buffer。视频渲染会尝试返回一个Ddraw的buffer。如果使用环境的要求都符合(如clip、拉伸、视频内存,这部分功能参考《wince DirectDraw设计分析》),这个表面才能被使用。否则,也是要切换到GDI模式。

     

    视频渲染连接问题的调试:

    当编写了新的解码filter或者capture驱动时,经常遇到一些问题:

    1、  插入到graph的颜色转换

    2、  视频渲染连接不上

    3、  YUV表面不能使用,只能用GDI

     

    认识Dshow的log

    首先,打开Dshwo DLL、quartz.dll和连接相关的视频渲染中的debug zone。方法有2个:

    1、  quartz.dll加载后,打开debug zone的前4个开关。

    2、  HKEY_CURRENT_USER/Pegasus/Zones的注册表中,添加名字为quartz 的DWORD键值,内容是0xf。

     

    开始测试,保存运行的debug输出。找到Filter Graph Dump字段,然后观察log内容。如下:

    Filter graph dump Filter 1a199a30 'Video Renderer' Iunknown 1a199a20     Pin 1a199f10 Input (Input) connected to 1a0e1880 Filter 1a0e1200 'WMVideo & MPEG4 Decoder DMO' Iunknown 1a0e11f0     Pin 1a0e16e0 in0 (Input) connected to 1a0e0600     Pin 1a0e1880 out0 (PINDIR_OUTPUT) connected to 1a199f10     Pin 1a0e1a00 ~out1 (PINDIR_OUTPUT) connected to 0 Filter 1a0ecc60 'ASF ICM Handler' Iunknown 1a0ecc50     Pin 1a0ecd70 In (Input) connected to 1a0aa3a0     Pin 1a0e0600 Out (PINDIR_OUTPUT) connected to 1a0e16e0 Filter 1a0ec240 'Audio Renderer' Iunknown 1a0ec230 wo: GetPin, 0     Pin 1a0ec4e0 Audio Input pin (rendered) (Input) connected to 1a0eb880 Filter 1a0eb220 'WMAudio Decoder DMO' Iunknown 1a0eb210     Pin 1a0eb660 in0 (Input) connected to 1a0ea800     Pin 1a0eb880 out0 (PINDIR_OUTPUT) connected to 1a0ec4e0 Filter 1a0e9380 'ASF ACM Handler' Iunknown 1a0e9370     Pin 1a0e9490 In (Input) connected to 1a0aa000     Pin 1a0ea800 Out (PINDIR_OUTPUT) connected to 1a0eb660 Filter 1a0a2ae0 '/Hard Disk2/clips/wmv/0-1.asf' Iunknown 1a0a2ad0     Pin 1a0aa000 Stream 1 (PINDIR_OUTPUT) connected to 1a0e9490     Pin 1a0aa3a0 Stream 2 (PINDIR_OUTPUT) connected to 1a0ecd70 End of filter graph dump

     

    然后观察视频渲染使用那个媒体类型,查找Allocating video resources,如下:

    Allocating video resources Initialising DCI/DirectDraw Searching for direct format Entering ReleaseSurfaces Entering HideOverlaySurface Enumerated 32315659 Entering FindSurface Entering GetMediaType Not a RGB format Entering CreateYUVFlipping Entering CheckCreateOverlay GWES Hook fails surface creation. IDirectDraw::CreateSurface fails. No surface Entering ReleaseSurfaces Entering HideOverlaySurface Enumerated 3231564e Entering FindSurface Entering GetMediaType Not a RGB format Entering CreateYUVFlipping Entering CheckCreateOverlay GWES Hook fails surface creation. IDirectDraw::CreateSurface fails. No surface Entering ReleaseSurfaces Entering HideOverlaySurface Enumerated 32595559 Entering FindSurface Entering GetMediaType Not a RGB format Entering CreateYUVFlipping Entering CheckCreateOverlay Entering InitOverlaySurface Entering InitDrawFormat Entering InitDrawFormat Entering GetDefaultColorKey Returning default colour key Entering InitDefaultColourKey Entering SetSurfaceSize Preparing source and destination rectangles Entering ClipPrepare Entering InitialiseClipper Entering InitialiseColourKey overlay color key on Colour key No palette Found AMDDS_YUVFLP surface Proposing output type  M type MEDIATYPE_Video  S type MEDIASUBTYPE_YUY2

    以上是WMV DMO建立表面的过程。显示驱动会建立YUV2的表面,WMV解码器的第三个媒体选项。

     

    Graph 的颜色转换问题:

    上层filter往往不报出支持的RGB格式,而只有YUV格式。视频渲染就不能直接用RGB格式进行连接,这时graph一般会加入颜色转换。但我们不希望这个情况发生,因为这会导致一个内存复制的动作,所以需要知道上层filter可以提供那些RGB的格式支持。

     

    有时候,即使上层filter支持RGB格式,graph也会加入一个颜色转换。这可能是上层filter需要进行内存地址的对全。目前视频渲染只支持1字节的内存对齐,所以这个情况也有可能发生。

     

    另一个可能是,颜色转换器加入时候使用BITMAPINFOHEADER。上层filter得到输出媒体时,不知道应该在BITMAPINFOHEADER结束部分,使用哪种bitmask。确认正确的使用bitmask,例如RGB565:

    *pdwBitfield++  = 0xF800;       // Red – 5

     *pdwBitfield++  = 0x07E0;       // Green - 6

     *pdwBitfield    = 0x001F;       // Blue - 5

    Bitmask应该是0xF800、0x07E0和0x001F。

     

    Graph 连接不上:

    如果上层filter只支持YUV格式的一个子集,而且没有合适的颜色转换器。那就不能连接到任何视频渲染器上。这就要上层filter提供RGB的支持。

     

    YUV 表面没有使用,只使用了GDI :

    上层filter提供了内存分配器,视频渲染就尝试不使用Ddraw模式(内存buffer不能传递给Ddraw)。要使用flip overlay的话,就需要内存分配的工作由视频渲染完成(关于filter内存分配的知识,参考filter相关资料)。

     

    表面类型,控制视频渲染创建的表面:

    有几个方法可以让视频渲染控制加速表面的创建,在调试连接问题时候比较有用。特别是减少显示驱动支持格式选项的这个方式,可以在注册表中控制:

    HKEY_LOCAL_MACHINE/Software/Microsoft/DirectX/DirectShow/Video Renderer/SurfaceTypes

    下面是 SurfaceTypes 键值中 AMDDS 的值表:

    Flag

    Hexadecimal value

    Description

    AMDDS_NONE

    0x00

    No support for Device Control Interface (DCI) or DirectDraw.

    AMDDS_DCIPS

    0x01

    Use DCI primary surface.

    AMDDS_PS

    0x02

    Use DirectDraw primary surface.

    AMDDS_RGBOVR

    0x04

    RGB overlay surfaces.

    AMDDS_YUVOVR

    0x08

    YUV overlay surfaces.

    AMDDS_RGBOFF

    0x10

    RGB off-screen surfaces.

    AMDDS_YUVOFF

    0x20

    YUV off-screen surfaces.

    AMDDS_RGBFLP

    0x40

    RGB flipping surfaces.

    AMDDS_YUVFLP

    0x80

    YUV flipping surfaces.

    AMDDS_ALL

    0xFF

    Use all available surfaces.

    AMDDS_DEFAULT

    0xFF

    Use all available surfaces.

    AMDDS_YUV

    0xA8

    (AMDDS_YUVOFF | AMDDS_YUVOVR | AMDDS_YUVFLP)

    AMDDS_RGB

    0x58

    (AMDDS_RGBOFF | AMDDS_RGBOVR | AMDDS_RGBFLP)

    AMDDS_PRIMARY

    0x03

    (AMDDS_DCIPS | AMDDS_PS)

     

    如果调试时候,只想使用YUV的overlay flip表面。就把键值只设置为AMDDS_YUVFLP。

     

    关于FourCC:

    FourCC是描述媒体格式的GUID方式。每种媒体格式,在全球使用中,都有一个特定的编号。如下:

    Enumerated 32315659

    0x32 = '2', 0x31 = '1', 0x56 = 'V', 0x59 = 'Y' ===> 0x32315659 = YV12

     Enumerated 3231564e

    0x32 = '2', 0x31 = '1', 0x56 = 'V', 0x4e = 'N' ===> 0x3231564e = NV12

     Enumerated 32595559

    0x32 = '2', 0x59 = 'Y', 0x55 = 'U', 0x59 = 'Y' ===> 0x32595559 = YUY2

     Enumerated 56555949

    0x56 = 'V', 0x55 = 'U', 0x59 = 'Y', 0x49 = 'I' ===> 0x56555949 = IYUV

     Enumerated 59565955

    0x59 = 'Y', 0x56 = 'V', 0x59 = 'Y', 0x55 = 'U' ===> 0x59565955 = UYVY

     Enumerated 55595659

    0x55 = 'U', 0x59 = 'Y', 0x56 = 'V', 0x59 = 'Y' ===> 0x55595659 = YVYU

    也可以在public/directx/sdk/inc/uuids.h中,查找对应的定义

    // 32595559-0000-0010-8000-00AA00389B71 'YUY2' == MEDIASUBTYPE_YUY2OUR_GUID_ENTRY(MEDIASUBTYPE_YUY2,0x32595559, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 55595659-0000-0010-8000-00AA00389B71 'YVYU' == MEDIASUBTYPE_YVYUOUR_GUID_ENTRY(MEDIASUBTYPE_YVYU,0x55595659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 59565955-0000-0010-8000-00AA00389B71 'UYVY' == MEDIASUBTYPE_UYVYOUR_GUID_ENTRY(MEDIASUBTYPE_UYVY,0x59565955, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 31313259-0000-0010-8000-00AA00389B71 'Y211' == MEDIASUBTYPE_Y211OUR_GUID_ENTRY(MEDIASUBTYPE_Y211,0x31313259, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 32315659-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_YV12OUR_GUID_ENTRY(MEDIASUBTYPE_YV12,0x32315659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 36313259-0000-0010-8000-00AA00389B71 'YV16' == MEDIASUBTYPE_YV16OUR_GUID_ENTRY(MEDIASUBTYPE_YV16,0x36315659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 56595549-0000-0010-8000-00AA00389B71 'IUYV' == MEDIASUBTYPE_IUYVOUR_GUID_ENTRY(MEDIASUBTYPE_IUYV,0x56595549, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 3231564E-0000-0010-8000-00AA00389B71 'NV12' == MEDIASUBTYPE_NV12OUR_GUID_ENTRY(MEDIASUBTYPE_NV12,0x3231564E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 30323449-0000-0010-8000-00AA00389B71 'I420' == MEDIASUBTYPE_I420OUR_GUID_ENTRY(MEDIASUBTYPE_I420,0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)// 56555949-0000-0010-8000-00AA00389B71 'IYUV' == MEDIASUBTYPE_IYUVOUR_GUID_ENTRY(MEDIASUBTYPE_IYUV,0x56555949, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)

     

    http://blogs.msdn.com/medmedia/archive/2007/06/11/the-video-renderer-connection-process.aspx

    最新回复(0)