我正在尝试在C#包装器中设置MMF的拓扑对象,以开始从捕获设备作为源进行捕获。我有一个已激活的现有IMFMediaSource
对象,因此我创建了拓扑节点,将该节点添加到拓扑中,然后尝试设置拓扑。在IMFMediaSession::SetTopology
通话期间,它引发以下异常:
System.Runtime.InteropServices.COMException:拓扑中的源流节点没有源。 (来自HRESULT的异常:0xC00D521A)
以前,我使用SourceReader从媒体源中提取样本,因此我知道媒体源可以工作。我在几个不同的地方读过,如果我实际上想在视频设备上在屏幕上显示某些内容,则不能使用SourceReader和SinkWriter,这就是为什么我要创建使用的拓扑。我还可以创建一个演示描述符,并从媒体源创建的演示描述符中提取流描述符。在此过程中,我还验证了该子类型是我实际上可以使用的东西。
我还有一个媒体接收器输出节点作为拓扑的一部分。这似乎没有任何问题或引起异常。我已经删除了源流节点并离开了媒体接收器,并且它没有崩溃。
我尝试搜索有关此异常的更多信息,但是我发现的唯一搜索结果是有关HResult的信息,而我已经有了该信息。
这是我创建拓扑节点的方式(源,表示描述符和流描述符不为空):
if (sourcePresentationDescriptor == null || videoStreamDescriptor == null || !isSelectedStream)
{
return false;
}
status = NativeMethods.MFCreateTopologyNode(MFTopologyType.TopologySourcestreamNode, out videoSourceNode);
if (status < 0) { throw new Exception("Not able to create topology node for source."); }
// Finish instantiating source node
videoSourceNode.SetUnknown(CLSIDsMFMediaTypeAttributes.TopoNodeSource, mediaSource);
videoSourceNode.SetUnknown(CLSIDsMFMediaTypeAttributes.TopoNodePresentationDescriptor, sourcePresentationDescriptor);
videoSourceNode.SetUnknown(CLSIDsMFMediaTypeAttributes.TopoNodeStreamDescriptor, videoStreamDescriptor);
topology.AddNode(videoSourceNode);
MediaSession.SetTopology(0, topology); // <-- Exception thrown here
运行MFTrace,我得到以下信息:
CTopologyHelpers::Trace @05114468 >>>>>>>>>>>>> input topology
CTopologyHelpers::TraceNode @ Node 0 @050EDFD8 ID:7FC400000001, 0 inputs, 0 outputs, type 1, MF_TOPONODE_SOURCE=@050E3E68;MF_TOPONODE_STREAM_DESCRIPTOR=@050FE9B0
CMFTopologyNodeDetours::GetGUID @050EDFD8 attribute not found guidKey = MF_TOPONODE_TRANSFORM_OBJECTID
CTopologyHelpers::TraceObject @ UnknownType @00000000 {00000000-0000-0000-0000-000000000000} ((null)), (null)
CMFTopologyDetours::GetUINT32 @05114468 attribute not found guidKey = MF_TOPOLOGY_RESOLUTION_STATUS
CTopologyHelpers::Trace @05114468 MF_TOPOLOGY_RESOLUTION_STATUS = NOT FOUND!!!
CTopologyHelpers::Trace @05114468 <<<<<<<<<<<<< input topology
我的想法是,这应该创建适当的拓扑节点,但我非常。如果这是我的COM包装程序存在的问题,尽管我不反对将其排除为问题,但我不希望出现这样的特定异常。除了设置拓扑外,它只会引发此异常。
更新
这是我用来创建拓扑的完整代码:
private bool CreateMediaSessionAndTopology(IMFMediaSource mediaSource, IntPtr videoHWnd, string uniqueDeviceName)
{
IMFTopology topology;
IMFTopologyNode videoSourceNode;
IMFTopologyNode outputVideoSinkNode;
//IMFTopologyNode transformNode;
IMFPresentationDescriptor sourcePresentationDescriptor = null;
IMFStreamDescriptor videoStreamDescriptor = null;
IMFMediaTypeHandler mediaTypeHandler;
IMFMediaType captureMediaType;
IMFActivate rendererActivator;
uint sourceStreamCount;
bool isSelectedStream = false;
Guid majorMediaType;
Guid[] subTypes =
{
MFMediaTypeGuids.NV12,
MFMediaTypeGuids.YUY2,
MFMediaTypeGuids.UYVY,
MFMediaTypeGuids.RGB32,
MFMediaTypeGuids.RGB24,
MFMediaTypeGuids.IYUV
};
try
{
// Create the topology
uint status = NativeMethods.MFCreateTopology(out topology);
if (status < 0) { throw new Exception("Couldn't create topology"); }
sourcePresentationDescriptor = mediaSource.CreatePresentationDescriptor();
sourceStreamCount = sourcePresentationDescriptor.GetStreamDescriptorCount();
for (uint i = 0; i < sourceStreamCount; i++)
{
videoStreamDescriptor = sourcePresentationDescriptor.GetStreamDescriptorByIndex(i, out isSelectedStream);
if (videoStreamDescriptor != null)
{
mediaTypeHandler = videoStreamDescriptor.GetMediaTypeHandler();
majorMediaType = mediaTypeHandler.GetMajorType();
if (majorMediaType != MFMediaTypeGuids.Video) { continue; }
if (!isSelectedStream) { continue; }
uint MaxSubTypes = 250; //magic number for now;
for (uint j = 0; j < MaxSubTypes; j++)
{
captureMediaType = mediaTypeHandler.GetMediaTypeByIndex(j);
if (captureMediaType == null) { continue; }
Guid subtype = captureMediaType.GetGuid(CLSIDsMFMediaTypeAttributes.SubType);
for (int k = 0; k < subTypes.Length; k++)
{
if (subtype == subTypes[k])
{
mediaTypeHandler.SetCurrentMediaType(captureMediaType);
break;
}
}
break;
}
break;
}
}
if (sourcePresentationDescriptor == null || videoStreamDescriptor == null || !isSelectedStream)
{
return false;
}
status = NativeMethods.MFCreateTopologyNode(MFTopologyType.TopologySourcestreamNode, out videoSourceNode);
if (status < 0) { throw new Exception("Not able to create topology node for source."); }
// Finish instantiating source node
videoSourceNode.SetUnknown(CLSIDsMFMediaTypeAttributes.TopoNodeSource, mediaSource);
videoSourceNode.SetUnknown(CLSIDsMFMediaTypeAttributes.TopoNodePresentationDescriptor, sourcePresentationDescriptor);
videoSourceNode.SetUnknown(CLSIDsMFMediaTypeAttributes.TopoNodeStreamDescriptor, videoStreamDescriptor);
topology.AddNode(videoSourceNode);
// Create Video Sink node
status = NativeMethods.MFCreateTopologyNode(MFTopologyType.TopologyOutputNode, out outputVideoSinkNode);
if (status < 0) { throw new Exception("Couldn't create output node."); }
status = NativeMethods.MFCreateVideoRendererActivate(videoHWnd, out rendererActivator);
if (status < 0) { throw new Exception("Couldn't create renderer activator"); }
outputVideoSinkNode.SetObject(rendererActivator);
topology.AddNode(outputVideoSinkNode);
videoSourceNode.ConnectOutput(0, outputVideoSinkNode, 0);
// Create the session
status = NativeMethods.MFCreateMediaSession(null, out _mediaSession);
if (status < 0) { throw new Exception("Not able to create media session."); }
_mediaSessionCallbackHandler = new DeviceCaptureCallbackHandler();
_mediaSessionCallbackHandler.MediaSession = _mediaSession;
_mediaSessionCallbackHandler.MediaSessionAsyncCallbackEvent = HandleMediaSessionCallbackEvent;
_mediaSessionCallbackHandler.MediaSessionAsyncCallbackError = HandleMediaSessionCallbackErrors;
_mediaSession.BeginGetEvent(_mediaSessionCallbackHandler, null);
_mediaSession.SetTopology(0, topology);
}
catch (Exception ex)
{
throw new Exception("Failed to create topology", ex);
}
return true;
}
这是激活设备的方式:
public Device(IMFActivate activator)
{
string friendlyName;
string symbolicLinkName;
_activator = activator;
activator.GetAllocatedString(MfAttributeSourceTypeGuids.MfDevsourceAttributeFriendlyName, out friendlyName);
FriendlyName = friendlyName;
activator.GetAllocatedString(MfAttributeSourceTypeGuids.MfDevsourceAttributeSourceTypeVidcapSymbolicLink, out symbolicLinkName);
SymbolicLinkName = symbolicLinkName;
}
实际上使用激活器:
public bool ActivateDevice()
{
object source;
try
{
source = _activator.ActivateObject(typeof(IMFMediaSource).GUID);
MediaSource = source as IMFMediaSource;
}
catch (System.Exception ex)
{
throw new System.Exception("Couldn't activate object", ex);
}
return true;
我想我在这里犯了一个简单的错误,弄糟了这个问题。
答案 0 :(得分:0)
罗马的上述回答似乎已经解决了我的问题。
我想您的真实源代码有些不同,总体上说得通,但也许某个地方有错字。
简而言之,当我为不同的节点导入不同的GUID时,我错误地复制并粘贴了其中一个节点的GUID之一。这意味着,当Windows SDK尝试对其进行处理时,会感到困惑,因为.NET包装器中的GUID不好。具体来说,“呈现描述符节点”已设置为与“源节点”相同的GUID。