生成 Recompression Graph

[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayerIMFMediaEngine音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]

AVI 文件重新压缩的典型筛选器图如下所示:

avi recompression 图

AVI 拆分器筛选器文件源 (异步) 筛选器中提取数据,并将其分析为视频和音频流。 视频解压缩器对压缩的视频进行解码,视频压缩器在其中对其进行重新压缩。 解压缩器的选择取决于源文件; 它将由智能连接自动处理。 应用程序必须选择压缩器,通常通过向用户显示列表。 (请参阅 选择压缩筛选器。)

然后,压缩的视频将转到 AVI 复用器筛选器。 此示例中的音频流未压缩,因此它直接从 AVI 拆分器传输到 AVI 复用器。 AVI Mux 将两个流交错在一起, 文件编写器筛选器 将输出写入磁盘。 请注意,即使原始文件没有音频流,也需要 AVI 复用函数。

生成此筛选器图的最简单方法是使用 捕获图形生成器,这是用于生成捕获图和其他自定义筛选图的 DirectShow 组件。

首先,调用 CoCreateInstance 创建捕获图形生成器:

ICaptureGraphBuilder2 *pBuild = NULL;
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, 
                        NULL, CLSCTX_INPROC_SERVER,
    IID_ICaptureGraphBuilder2, (void **)&pBuild);

然后使用捕获图形生成器生成筛选器图:

  1. 生成图形的呈现部分,其中包括 AVI 复用器筛选器和 文件编写器
  2. 将源筛选器和压缩筛选器添加到图形。
  3. 将源筛选器连接到 MUX 筛选器。 捕获图生成器插入分析源文件所需的任何拆分器和解码器筛选器。 它还可以通过压缩筛选器路由视频和音频流。

以下各节介绍了其中每个步骤。

生成呈现部分

若要生成图形的呈现部分,请调用 ICaptureGraphBuilder2::SetOutputFileName 方法。 此方法采用指定输出的媒体子类型和输出文件名称的输入参数。 它返回指向 MUX 筛选器和文件编写器的指针。 下一阶段的图形生成需要 MUX 筛选器。 此示例不需要指向文件编写器的指针,因此该参数可以为 NULL

IBaseFilter *pMux = NULL;
hr = pBuild->SetOutputFileName(
        &MEDIASUBTYPE_Avi, // File type. 
        wszOutputFile,     // File name, as a wide-character string.
        &pMux,             // Receives a pointer to the multiplexer.
        NULL);             // Receives a pointer to the file writer. 

该方法返回时,MUX 筛选器具有未完成的引用计数,因此请务必稍后释放指针。

下图显示了此时的筛选器图。

筛选器图的呈现部分

MUX 筛选器公开两个用于控制 AVI 格式的接口:

添加源筛选器和压缩筛选器

下一步是将源筛选器和压缩筛选器添加到筛选器图。 调用 SetOutputFileName 时,捕获图形生成器会自动创建 Filter Graph 管理器的实例。 通过调用 ICaptureGraphBuilder2::GetFiltergraph 方法获取指向它的指针:

IGraphBuilder *pGraph = NULL;
hr = pBuild->GetFiltergraph(&pGraph);

现在调用 IGraphBuilder::AddSourceFilter 方法来添加异步文件源筛选器,并调用 IFilterGraph::AddFilter 方法添加视频压缩器:

IBaseFilter *pSrc = NULL;
hr = pGraph->AddSourceFilter(wszInputFile, L"Source Filter", &pSrc);
hr = pGraph->AddFilter(pVComp, L"Compressor");

此时,源筛选器和压缩筛选器未连接到图中的其他任何内容,如下图所示:

具有源筛选器和压缩筛选器的筛选器图

将源连接到复用函数

最后一步是通过视频压缩器将源筛选器连接到 AVI 复用器。 使用 ICaptureGraphBuilder2::RenderStream 方法,该方法(可选)通过压缩筛选器将源筛选器上的输出引脚连接到指定的接收器筛选器。

前两个参数通过指定引脚类别和媒体类型来指定要连接的源筛选器的引脚。 异步文件源筛选器只有一个输出引脚,因此这些参数应为 NULL。 接下来的三个参数指定源筛选器、压缩筛选器 ((如果有任何) )和 Mux 筛选器。

下面的代码示例通过视频压缩器呈现视频流:

hr = pBuild->RenderStream(
        NULL,       // Output pin category
        NULL,       // Media type
        pSrc,       // Source filter
        pVComp,     // Compression filter
        pMux);      // Sink filter (the AVI Mux)

下图显示了到目前为止的筛选器图。

呈现的视频流

假设源文件具有音频流, AVI 拆分器 筛选器已为音频创建输出引脚。 若要连接此引脚,请再次调用 RenderStream:

hr = pBuild->RenderStream(NULL, NULL, pSrc, NULL, pMux);

此处未指定压缩筛选器。 源筛选器的输出引脚已连接,因此 RenderStream 方法在拆分器筛选器上搜索未连接的输出引脚。 它会查找音频引脚并将其直接连接到 MUX 筛选器。 如果源文件没有音频流,则对 RenderStream 的第二次调用将失败。 这是预期的行为。 该图在第一次调用 RenderStream 后完成,因此第二次调用中的失败是无害的。

在此示例中,两个 RenderStream 调用的顺序非常重要。 由于第二次调用未指定压缩器,因此它将从 AVI 拆分器连接任何未连接的引脚。 如果在另一个调用之前进行此调用,它可能会将视频流连接到 AVI 复用器,而无需视频压缩器。 因此,必须首先对压缩筛选器) 进行更具体的调用 (。

前面的讨论假定源文件是 AVI 文件。 但是,此方法也适用于其他文件类型,例如 MPEG 文件。 生成的筛选器图将稍有不同。

重新压缩 AVI 文件