【发布时间】:2015-12-20 18:29:14
【问题描述】:
我一直试图想出一个使用 Microsoft 的 Media Foundation Enhanced Video Renderer (EVR) 显示视频的简单示例,但徒劳无功。我正在使用 Visual Studio 2013 在 Windows 7 上进行测试。
我很确定我已经正确配置了媒体类型,因为我可以从读取循环中的 IMFSample 导出缓冲区并将其保存到位图中。如果我让 MF 自动生成拓扑,我也可以让视频渲染,但在这种情况下,我需要手动连接源读取器和接收器写入器,以便我可以访问管道的不同部分。
我使用 mftrace 来查看是否可以发现自动生成的拓扑和手动连接的示例之间有什么不同,但没有明显的跳出。
代码如下(完整示例项目https://github.com/sipsorcery/mediafoundationsamples/tree/master/MFVideoEVR)。
我是否错过了从 SinkWriter 获取 IMFSample 以显示在视频窗口上的步骤?我一直在研究一些深入到 DirectX 管道的示例,但是这是否是必要的,或者 EVR 是否意味着将这些机制抽象出来?
#include <stdio.h>
#include <tchar.h>
#include <evr.h>
#include <mfapi.h>
#include <mfplay.h>
#include <mfreadwrite.h>
#include <mferror.h>
#include "..\Common\MFUtility.h"
#include <windows.h>
#include <windowsx.h>
#pragma comment(lib, "mf.lib")
#pragma comment(lib, "evr.lib")
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfplay.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")
#pragma comment(lib, "Strmiids")
#pragma comment(lib, "wmcodecdspuuid.lib")
#define CHECK_HR(hr, msg) if (hr != S_OK) { printf(msg); printf("Error: %.2X.\n", hr); goto done; }
void InitializeWindow();
// Constants
const WCHAR CLASS_NAME[] = L"MFVideoEVR Window Class";
const WCHAR WINDOW_NAME[] = L"MFVideoEVR";
// Globals.
HWND _hwnd;
using namespace System::Threading::Tasks;
int main()
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
MFStartup(MF_VERSION);
IMFMediaSource *videoSource = NULL;
UINT32 videoDeviceCount = 0;
IMFAttributes *videoConfig = NULL;
IMFActivate **videoDevices = NULL;
IMFSourceReader *videoReader = NULL;
WCHAR *webcamFriendlyName;
IMFMediaType *videoSourceOutputType = NULL, *pvideoSourceModType = NULL, *pSrcOutMediaType = NULL;
IMFSourceResolver *pSourceResolver = NULL;
IUnknown* uSource = NULL;
IMFMediaSource *mediaFileSource = NULL;
IMFAttributes *pVideoReaderAttributes = NULL;
IMFMediaType *pVideoOutType = NULL;
MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
IMFMediaSink *pVideoSink = NULL;
IMFStreamSink *pStreamSink = NULL;
IMFMediaTypeHandler *pMediaTypeHandler = NULL;
IMFMediaType *pMediaType = NULL;
IMFMediaType *pSinkMediaType = NULL;
IMFSinkWriter *pSinkWriter = NULL;
IMFVideoRenderer *pVideoRenderer = NULL;
IMFVideoPresenter *pVideoPresenter = nullptr;
IMFVideoDisplayControl *pVideoDisplayControl = nullptr;
IMFGetService *pService = nullptr;
IMFActivate* pActive = NULL;
MFVideoNormalizedRect nrcDest = { 0.5f, 0.5f, 1.0f, 1.0f };
IMFPresentationTimeSource *pSystemTimeSource = nullptr;
IMFMediaType *sinkPreferredType = nullptr;
IMFPresentationClock *pClock = NULL;
IMFPresentationTimeSource *pTimeSource = NULL;
CHECK_HR(MFTRegisterLocalByCLSID(
__uuidof(CColorConvertDMO),
MFT_CATEGORY_VIDEO_PROCESSOR,
L"",
MFT_ENUM_FLAG_SYNCMFT,
0,
NULL,
0,
NULL
), "Error registering colour converter DSP.\n");
Task::Factory->StartNew(gcnew Action(InitializeWindow));
Sleep(1000);
if (_hwnd == nullptr)
{
printf("Failed to initialise video window.\n");
goto done;
}
// Set up the reader for the file.
CHECK_HR(MFCreateSourceResolver(&pSourceResolver), "MFCreateSourceResolver failed.\n");
CHECK_HR(pSourceResolver->CreateObjectFromURL(
L"..\\..\\MediaFiles\\big_buck_bunny.mp4", // URL of the source.
MF_RESOLUTION_MEDIASOURCE, // Create a source object.
NULL, // Optional property store.
&ObjectType, // Receives the created object type.
&uSource // Receives a pointer to the media source.
), "Failed to create media source resolver for file.\n");
CHECK_HR(uSource->QueryInterface(IID_PPV_ARGS(&mediaFileSource)), "Failed to create media file source.\n");
CHECK_HR(MFCreateAttributes(&pVideoReaderAttributes, 2), "Failed to create attributes object for video reader.\n");
CHECK_HR(pVideoReaderAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID), "Failed to set dev source attribute type for reader config.\n");
CHECK_HR(pVideoReaderAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, 1), "Failed to set enable video processing attribute type for reader config.\n");
CHECK_HR(MFCreateSourceReaderFromMediaSource(mediaFileSource, pVideoReaderAttributes, &videoReader),
"Error creating media source reader.\n");
CHECK_HR(videoReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &videoSourceOutputType),
"Error retrieving current media type from first video stream.\n");
Console::WriteLine("Default output media type for source reader:");
Console::WriteLine(GetMediaTypeDescription(videoSourceOutputType));
Console::WriteLine();
// Set the video output type on the source reader.
CHECK_HR(MFCreateMediaType(&pvideoSourceModType), "Failed to create video output media type.\n");
CHECK_HR(pvideoSourceModType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), "Failed to set video output media major type.\n");
CHECK_HR(pvideoSourceModType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), "Failed to set video sub-type attribute on EVR input media type.\n");
CHECK_HR(pvideoSourceModType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive), "Failed to set interlace mode attribute on EVR input media type.\n");
CHECK_HR(pvideoSourceModType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE), "Failed to set independent samples attribute on EVR input media type.\n");
CHECK_HR(MFSetAttributeRatio(pvideoSourceModType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1), "Failed to set pixel aspect ratio attribute on EVR input media type.\n");
CHECK_HR(CopyAttribute(videoSourceOutputType, pvideoSourceModType, MF_MT_FRAME_SIZE), "Failed to copy video frame size attribute from input file to output sink.\n");
CHECK_HR(CopyAttribute(videoSourceOutputType, pvideoSourceModType, MF_MT_FRAME_RATE), "Failed to copy video frame rate attribute from input file to output sink.\n");
CHECK_HR(videoReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pvideoSourceModType), "Failed to set media type on source reader.\n");
Console::WriteLine("Output media type set on source reader:");
Console::WriteLine(GetMediaTypeDescription(pvideoSourceModType));
Console::WriteLine();
// Create EVR sink .
//CHECK_HR(MFCreateVideoRenderer(__uuidof(IMFMediaSink), (void**)&pVideoSink), "Failed to create video sink.\n");
CHECK_HR(MFCreateVideoRendererActivate(_hwnd, &pActive), "Failed to created video rendered activation context.\n");
CHECK_HR(pActive->ActivateObject(IID_IMFMediaSink, (void**)&pVideoSink), "Failed to activate IMFMediaSink interface on video sink.\n");
// Initialize the renderer before doing anything else including querying for other interfaces (https://msdn.microsoft.com/en-us/library/windows/desktop/ms704667(v=vs.85).aspx).
CHECK_HR(pVideoSink->QueryInterface(__uuidof(IMFVideoRenderer), (void**)&pVideoRenderer), "Failed to get video Renderer interface from EVR media sink.\n");
CHECK_HR(pVideoRenderer->InitializeRenderer(NULL, NULL), "Failed to initialise the video renderer.\n");
CHECK_HR(pVideoSink->QueryInterface(__uuidof(IMFGetService), (void**)&pService), "Failed to get service interface from EVR media sink.\n");
CHECK_HR(pService->GetService(MR_VIDEO_RENDER_SERVICE, __uuidof(IMFVideoDisplayControl), (void**)&pVideoDisplayControl), "Failed to get video display control interface from service interface.\n");
CHECK_HR(pVideoSink->GetStreamSinkByIndex(0, &pStreamSink), "Failed to get video renderer stream by index.\n");
CHECK_HR(pStreamSink->GetMediaTypeHandler(&pMediaTypeHandler), "Failed to get media type handler.\n");
// Set the video output type on the source reader.
CHECK_HR(MFCreateMediaType(&pVideoOutType), "Failed to create video output media type.\n");
CHECK_HR(pVideoOutType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), "Failed to set video output media major type.\n");
CHECK_HR(pVideoOutType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), "Failed to set video sub-type attribute on EVR input media type.\n");
CHECK_HR(pVideoOutType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive), "Failed to set interlace mode attribute on EVR input media type.\n");
CHECK_HR(pVideoOutType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE), "Failed to set independent samples attribute on EVR input media type.\n");
CHECK_HR(MFSetAttributeRatio(pVideoOutType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1), "Failed to set pixel aspect ratio attribute on EVR input media type.\n");
CHECK_HR(CopyAttribute(videoSourceOutputType, pVideoOutType, MF_MT_FRAME_SIZE), "Failed to copy video frame size attribute from input file to output sink.\n");
CHECK_HR(CopyAttribute(videoSourceOutputType, pVideoOutType, MF_MT_FRAME_RATE), "Failed to copy video frame rate attribute from input file to output sink.\n");
//CHECK_HR(pMediaTypeHandler->GetMediaTypeByIndex(0, &pSinkMediaType), "Failed to get sink media type.\n");
CHECK_HR(pMediaTypeHandler->SetCurrentMediaType(pVideoOutType), "Failed to set current media type.\n");
Console::WriteLine("Input media type set on EVR:");
Console::WriteLine(GetMediaTypeDescription(pVideoOutType));
Console::WriteLine();
CHECK_HR(MFCreatePresentationClock(&pClock), "Failed to create presentation clock.\n");
CHECK_HR(MFCreateSystemTimeSource(&pTimeSource), "Failed to create system time source.\n");
CHECK_HR(pClock->SetTimeSource(pTimeSource), "Failed to set time source.\n");
//CHECK_HR(pClock->Start(0), "Error starting presentation clock.\n");
CHECK_HR(pVideoSink->SetPresentationClock(pClock), "Failed to set presentation clock on video sink.\n");
Console::WriteLine("Press any key to start video sampling...");
Console::ReadLine();
IMFSample *videoSample = NULL;
DWORD streamIndex, flags;
LONGLONG llTimeStamp;
while (true)
{
CHECK_HR(videoReader->ReadSample(
MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0, // Flags.
&streamIndex, // Receives the actual stream index.
&flags, // Receives status flags.
&llTimeStamp, // Receives the time stamp.
&videoSample // Receives the sample or NULL.
), "Error reading video sample.");
if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
{
printf("End of stream.\n");
break;
}
if (flags & MF_SOURCE_READERF_STREAMTICK)
{
printf("Stream tick.\n");
}
if (!videoSample)
{
printf("Null video sample.\n");
}
else
{
printf("Attempting to write sample to stream sink.\n");
CHECK_HR(videoSample->SetSampleTime(llTimeStamp), "Error setting the video sample time.\n");
//CHECK_HR(videoSample->SetSampleDuration(41000000), "Error setting the video sample duration.\n");
CHECK_HR(pStreamSink->ProcessSample(videoSample), "Streamsink process sample failed.\n");
}
SafeRelease(&videoSample);
}
done:
printf("finished.\n");
getchar();
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void InitializeWindow()
{
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = CLASS_NAME;
if (RegisterClass(&wc))
{
_hwnd = CreateWindow(
CLASS_NAME,
WINDOW_NAME,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
640,
480,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
if (_hwnd)
{
ShowWindow(_hwnd, SW_SHOWDEFAULT);
MSG msg = { 0 };
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Sleep(1);
}
}
}
}
}
【问题讨论】:
-
据我了解,媒体接收器使用pull model。您应该发送样本以响应 MEStreamSinkRequestSample 事件。
标签: visual-c++ ms-media-foundation