DirectShow通用媒体解码器

时间:2017-08-07 20:19:26

标签: c++ winapi directshow decoding

我是DirectShow API的新手。

我想使用DirectShow解码媒体文件并获取未压缩的RGB 视频帧。

我注意到所有这些操作都应该通过 GraphBuilder 来完成。此外,每个处理块都称为过滤器,并且针对不同的媒体文件有许多不同的过滤器。例如,对于解码H264,我们应该使用" Microsoft MPEG-2 Video Decoder",用于AVI文件" AVI Splitter Filter"等

我想知道是否有一种可以处理所有这些文件类型的通用方法(解码器)?

如果有人可以指出从导入本地文件到将其解码为未压缩RGB帧的示例,我将非常感激。我发现的所有示例都处理窗口句柄,它们只是配置它并调用pGraph-> run()。我还浏览过Windows SDK示例,但无法找到有用的示例。

非常感谢。

2 个答案:

答案 0 :(得分:1)

通用DirectShow解码器通常违反DirectShow API的概念。整个想法是个别过滤器负责个别任务(尤其是解码某些编码或解复用某些容器格式)。过滤器和Intelligent Connect的注册表允许一个过滤器内置过滤器来执行某些请求的处理,特别是从压缩格式解码为24位RGB视频。

从这个角度来看,您不需要通用解码器,并且不期望存在这样的解码器。然而,这样的解码器(或关闭)确实存在,它是ffdshow或其衍生物之一。目前,您可能希望查看LAVFilters。它们包装FFmpeg,它本身可以处理多种格式,并将它连接到DirectShow API,这样就像过滤器一样,ffdshow可以处理许多格式/编码。

使用或不使用此类编解码器包没有一般规则,在大多数情况下,您会考虑各种因素并决定该怎么做。如果您的应用程序处理各种场景,那么构建图形的良好起点将是Overview of Graph Building

  

我的目标是使用DirectShow完成任务,以便没有外部依赖项。您是否知道某个文件类型的解压缩帧的特定示例?

您的要求过于宽泛,同时也是典型的,并且在某种程度上,简单易懂。如果你花一些时间玩GraphEdit SDK工具,或者更确切地说是GraphStudioNext,这是前者更强大的版本,你将能够以交互方式构建过滤器图形,同时渲染不同类型的媒体文件并查看哪些过滤器参与渲染。您也可以通过编程方式完成相同的操作,因为交互式操作基本上都是单独匹配的API调用。

您将能够看到特定格式由不同的过滤器处理,上面提到的Intelligent Connect正在组合构建过滤器链,以满足请求并将管道组合在一起。

默认用例是回放,如果你想将视频呈现为24/32位RGB,你的行为过程非常相似:你要建立一个图形,只需要用其他东西终止。对于高级开发方法而言,更灵活,更复杂和典型的是提供自定义视频渲染器过滤器并在其上接受解压缩的RGB帧。

一个简单且如此受欢迎的解决方案版本是使用Sample Grabber过滤器,将其初始化为接受RGB,在其上设置回调,以便每次解压缩RGB帧时调用SampleCB回调方法,并在图表中使用Sample Grabber。 (如果您在搜索开源代码和/或网络上搜索关键字ISampleGrabberISampleGrabberCBSampleCBBufferCB,{{},您会发现很多尝试要做到这一点1}})。

另一种或多或少受欢迎的方法是设置播放管道,播放文件以及从视频演示者回读帧。这是在问题的另一个答案中建议的,相对容易做,并且如果您没有提取每个帧的性能要求和要求,则可以完成工作。也就是说,这是从feed中获取随机RGB帧的好方法,但不是每个/所有帧。请参阅相关内容:

答案 1 :(得分:1)

您正在寻找DirectShow库中的 vmr9 示例。

在Windows SDK的安装中,查找以下示例:

Microsoft SDK \ Windows \ v7.0 \ Samples \ multimedia \ directshow \ vmr9 \ windowless \ windowless.sln

并搜索此功能: CaptureImage ,在此方法中,请参阅IVMRWindowlessControl9::GetCurrentImage,这正是您想要的。

此方法以位图格式(RGB)捕获视频帧。 接下来,这是CaptureImage代码的副本:

BOOL CaptureImage(LPCTSTR szFile)
{
HRESULT hr;

if(pWC && !g_bAudioOnly)
{
    BYTE* lpCurrImage = NULL;

    // Read the current video frame into a byte buffer.  The information
    // will be returned in a packed Windows DIB and will be allocated
    // by the VMR.
    if(SUCCEEDED(hr = pWC->GetCurrentImage(&lpCurrImage)))
    {
        BITMAPFILEHEADER    hdr;
        DWORD               dwSize, dwWritten;
        LPBITMAPINFOHEADER  pdib = (LPBITMAPINFOHEADER) lpCurrImage;

        // Create a new file to store the bitmap data
        HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
                                  CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

        if (hFile == INVALID_HANDLE_VALUE)
            return FALSE;

        // Initialize the bitmap header
        dwSize = DibSize(pdib);
        hdr.bfType          = BFT_BITMAP;
        hdr.bfSize          = dwSize + sizeof(BITMAPFILEHEADER);
        hdr.bfReserved1     = 0;
        hdr.bfReserved2     = 0;
        hdr.bfOffBits       = (DWORD)sizeof(BITMAPFILEHEADER) + pdib->biSize +
            DibPaletteSize(pdib);

        // Write the bitmap header and bitmap bits to the file
        WriteFile(hFile, (LPCVOID) &hdr, sizeof(BITMAPFILEHEADER), &dwWritten, 0);
        WriteFile(hFile, (LPCVOID) pdib, dwSize, &dwWritten, 0);

        // Close the file
        CloseHandle(hFile);

        // The app must free the image data returned from GetCurrentImage()
        CoTaskMemFree(lpCurrImage);

        // Give user feedback that the write has completed
        TCHAR szDir[MAX_PATH];

        GetCurrentDirectory(MAX_PATH, szDir);

        // Strip off the trailing slash, if it exists
        int nLength = (int) _tcslen(szDir);
        if (szDir[nLength-1] == TEXT('\\'))
            szDir[nLength-1] = TEXT('\0');

        Msg(TEXT("Captured current image to %s\\%s."), szDir, szFile);
        return TRUE;
    }
    else
    {
        Msg(TEXT("Failed to capture image!  hr=0x%x"), hr);
        return FALSE;
    }
}

return FALSE;
}