我目前正在开发一个同时录制两个视频的软件。第一个的帧率为 25fps,第二个的帧率为 10fps(或者将来可能为 15fps)。之后,将这两个视频组合成一个画中画视频。问题是,画中画的 DirectShow 过滤器不支持不同帧率的视频。现在我正在寻找一个 DirectShow 过滤器,它可以产生“虚拟帧”以将第二个视频的帧速率提高到 25fps。有谁知道这样的 DirectShow 过滤器?
在此先感谢,大卫
我目前正在开发一个同时录制两个视频的软件。第一个的帧率为 25fps,第二个的帧率为 10fps(或者将来可能为 15fps)。之后,将这两个视频组合成一个画中画视频。问题是,画中画的 DirectShow 过滤器不支持不同帧率的视频。现在我正在寻找一个 DirectShow 过滤器,它可以产生“虚拟帧”以将第二个视频的帧速率提高到 25fps。有谁知道这样的 DirectShow 过滤器?
在此先感谢,大卫
Appleton 给出的答案是正确的。我正在扩展该答案,提供一些示例代码(在 C++/CLI 中)显示如何为手动构建的 DirectShow 图形实例化过滤器(从可用的稀疏文档中获取片段可能很耗时)。相关代码在REDUCE_FRAME_RATE
条件编译代码中。COM_CALL()
是我的自定义 HRESULT 检查宏。
// Additional include files required for DMO support
#include <ParserUIDs.h>
#include <dmodshow.h>
#include <propsys.h>
…
static void AddDecodedVideoSampleGrabber(
AVStreamSourceBox^ sourceBox,
IGraphBuilder* pGraph,
CComPtr<IBaseFilter>& pDecodedVideoSampleGrabber,
IPin* pSourcePin,
CComPtr<IPin>& pDecodedVideoSampleGrabberOutPin
) {
HRESULT hRes;
COM_CALL(pDecodedVideoSampleGrabber.CoCreateInstance(CLSID_SampleGrabber));
COM_CALL(pGraph->AddFilter(pDecodedVideoSampleGrabber, L"DecodedVideoSampleGrabber"));
CComPtr<IPin> pDecodedVideoSampleGrabberInPin(FilterTools::GetPin(pDecodedVideoSampleGrabber, "Input"));
COM_CALL(pGraph->ConnectDirect(pSourcePin, pDecodedVideoSampleGrabberInPin, NULL));
pDecodedVideoSampleGrabberOutPin = FilterTools::GetPin(pDecodedVideoSampleGrabber, "Output");
auto pFrameCallbackSink = (SampleGrabberCBSink*)sourceBox->SetupSampleGrabberCallback(
FRAME_SAMPLE_GRABBER,
IntPtr(pDecodedVideoSampleGrabber)
).ToPointer();
sourceBox->SetDecodedVideoSampleGrabber(IntPtr(pFrameCallbackSink));
#ifdef REDUCE_FRAME_RATE
// insert frame-reduction filter before x264 encoding
CComPtr<IBaseFilter> pFrameReducer;
COM_CALL(pFrameReducer.CoCreateInstance(CLSID_DMOWrapperFilter));
COM_CALL(pGraph->AddFilter(pFrameReducer, L"FrameReducer"));
CComPtr<IDMOWrapperFilter> pDmoWrapper;
COM_CALL(pFrameReducer->QueryInterface(__uuidof(IDMOWrapperFilter), (void**)&pDmoWrapper));
COM_CALL(pDmoWrapper->Init(__uuidof(CFrameRateConvertDmo), DMOCATEGORY_VIDEO_EFFECT));
CComPtr<IPropertyStore> pPropStore;
COM_CALL(pFrameReducer->QueryInterface(IID_PPV_ARGS(&pPropStore)));
PROPVARIANT var;
PropVariantInit(&var);
var.vt = VT_UI8;
var.uhVal.HighPart = OUTPUT_FPS; // Desired frame rate
var.uhVal.LowPart = 1;
pPropStore->SetValue(MFPKEY_CONV_OUTPUTFRAMERATE, var);
PropVariantClear(&var);
CComPtr<IPin>&pDmoInPin(FilterTools::GetPin(pFrameReducer, "in0"));
COM_CALL(pGraph->ConnectDirect(pDecodedVideoSampleGrabberOutPin, pDmoInPin, NULL));
CComPtr<IPin>&pDmoOutPin(FilterTools::GetPin(pFrameReducer, "out0"));
pDecodedVideoSampleGrabberOutPin = pDmoOutPin;
#endif
}
您需要实现自己的叠加过滤器并将其放在解码器和渲染器之间。这个过滤器应该能够接受流 -> 所以两个输入引脚。在第一个流的情况下,它将只获取帧并将图像覆盖应用到它,由第二个流生成。因此,每次您都会在叠加流中存储一张图像。另一种解决方案是使用第三方覆盖过滤器。
实现此目的的第二种方法是在 VMR9 过滤器上使用自定义的 direct3d 分配器演示器。这样,您将在 3d 环境中渲染期间混合图像。在这种情况下,第二个流实际上将实现为一个单独的图形,并且作为输出必须使用 samplegrabber 过滤器或您的自定义渲染器生成 bmp 图像。这种方式将产生更灵活的解决方案 - 您将能够在需要时交换叠加视频。