1

我使用以下代码连接到设备并流式传输视频,它的效果很好,除了我不知道如何检测实际帧何时发生变化

变量

fGraph: iGraphBuilder;
fBuilder: iCaptureGraphBuilder2;
fDevEnum: iCreateDevEnum;
fClassEnum: iEnumMoniker;
fMoniker: iMoniker;
fSrc: iBaseFilter;
fFetched: pLongInt;
fvideoWindow: iVideoWindow;
fmediaControl: iMediaControl;
fEvent: IMediaEvent;
fMediaEvent: IMediaEventEx;

代码:

fGraph := createComObject(CLSID_FilterGraph) as iGraphBuilder;
fBuilder := createComObject(CLSID_CaptureGraphBuilder2) as iCaptureGraphBuilder2;
fBuilder.SetFiltergraph(fGraph);
fDevEnum := createComObject(CLSID_SystemDeviceEnum) as iCreateDevEnum;
fDevEnum.createClassEnumerator(CLSID_VideoInputDeviceCategory , fClassEnum , 0);
fClassEnum.next(1 , fMoniker , fFetched);
fMoniker.bindToObject(nil , nil , IID_IBaseFilter , fSrc);
fGraph.addFilter(fSrc , 'Video Capture');
fGraph.queryInterface(IID_IMediaControl , fmediaControl);
fGraph.queryInterface(IID_IVideoWindow , fvideoWindow);
fGraph.queryInterface(IID_IMediaEvent , fEvent);
fEvent.queryInterface(IID_IMediaEventEx , fMediaEvent); // TForm(fOwner)
fMediaEvent.SetNotifyWindow(self.Handle , WM_MMNOTIFY , Integer(self));
fBuilder.renderStream(@PIN_CATEGORY_PREVIEW , @MEDIATYPE_VIDEO , fSrc , nil , nil);
fvideoWindow.put_windowStyle(WS_CHILD or WS_CLIPSIBLINGS);
fvideoWindow.setWindowPosition(0 , 0 , self.width , self.height);
fvideoWindow.put_owner(self.Handle);
fmediaControl.run;

如您所见,我尝试使用 IMediaEvent 和 IMediaEventEx,但仅在视频流开始或停止时触发,每次添加新帧时我都需要知道。

4

1 回答 1

0

视频渲染器不会报告帧呈现,例如使用回调。当帧到达视频渲染器时,它会根据可能附加的时间戳排队等待呈现。然后视频渲染器决定是否丢弃、呈现或排队数据。

如果您绝对需要知道演示时间,您可能想做的是

  • 在渲染器之前连接一个 Sample Grabber 过滤器
  • 确保数据已解压缩
  • 通过删除SampleCB抓取回调中的相应标志来剥离帧的时间

一旦视频渲染器收到该帧,该帧将很快呈现。不过,在它发生之前你仍然可以控制。如果您之后需要它,您需要一个自定义过滤器,该过滤器实际上将媒体样本传递给渲染器,并且在将控制权返回给您的过滤器时,您知道该帧刚刚呈现给用户。

于 2012-11-09T00:51:47.800 回答