Как исправить ошибку «У исходного потокового узла в топологии нет источника» в Microsoft Media Foundation? - PullRequest
1 голос
/ 18 апреля 2019

Я пытаюсь настроить объект топологии в моей оболочке C # для MMF, чтобы начать захват с устройства захвата в качестве источника.У меня есть существующий и активированный объект IMFMediaSource, поэтому я создаю узел топологии, добавляю узел в топологию и пытаюсь установить топологию.Во время вызова IMFMediaSession::SetTopology выдается следующее исключение:

System.Runtime.InteropServices.COMException: узел потока источника в топологии не имеет источника.(Исключение из HRESULT: 0xC00D521A)

Ранее я использовал SourceReader для извлечения сэмплов из источника мультимедиа, поэтому я знаю, что источник мультимедиа работает.Я читал в нескольких разных местах, что если я на самом деле хочу отобразить что-то на экране с видеоустройства, я не могу использовать SourceReader и SinkWriter, поэтому я пытаюсь создатьТопология для использования.Я также могу создать дескриптор презентации и получить дескрипторы потока из дескриптора презентации, созданного из медиаисточника.В ходе этого процесса я также проверяю, что подтип - это то, что я действительно могу использовать.

У меня также есть выходной узел приемника мультимедиа как часть топологии.Это, кажется, не имеет никаких проблем или вызывает исключения.Я удалил узел исходного потока и оставил приемник мультимедиа, и он не аварийно завершился.

Я попытался найти дополнительную информацию об этом исключении, но единственные результаты поиска, которые я нашел, - это то, чтоHResult, о котором у меня уже есть эта информация.

Вот как я создаю узел топологии (источник, дескриптор представления и потоковый дескриптор не равны NULL):

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, я бы не ожидал такого конкретного исключения, хотя я не против исключить это как проблему.Вместо установки топологии он просто выдает это исключение.

UPDATE

Вот полный код, который я использую для создания топологии:

        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;

Я думаю, что здесь я совершаю простую ошибку,испортить это.

1 Ответ

0 голосов
/ 06 июня 2019

Ответ Романа, по-видимому, решил мою проблему.

Полагаю, ваш реальный исходный код немного отличается, в целом имеет смысл, но, возможно, где-то есть опечатка.

Короче говоря, когда я импортировал разные GUID для разных узлов, я неправильно скопировал и вставил один из GUID для одного из узлов. Это означало, что, когда Windows SDK пытался что-то с ним сделать, он мог запутаться, потому что в моей оболочке .NET был неправильный GUID. В частности, для узла дескриптора представления был задан тот же GUID, что и для исходного узла.

...