/* Adds the video and audio stream to the H.264 writer sink. */ HRESULT ConfigureEncoder(IMFMediaType *pVideoType, DWORD *videoStreamIndex, DWORD *audioStreamIndex, IMFSinkWriter *pWriter) { IMFMediaType *pVideoOutType = NULL; IMFMediaType *pAudioOutType = NULL; // Configure the video stream. CHECK_HR(MFCreateMediaType(&pVideoOutType), L"Configure encoder failed to create media type for video output sink."); CHECK_HR(pVideoOutType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), L"Failed to set video writer attribute, media type."); CHECK_HR(pVideoOutType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264), L"Failed to set video writer attribute, video format (H.264)."); CHECK_HR(pVideoOutType->SetUINT32(MF_MT_AVG_BITRATE, 240 * 1000), L"Failed to set video writer attribute, bit rate."); CHECK_HR(CopyAttribute(pVideoType, pVideoOutType, MF_MT_FRAME_SIZE), L"Failed to set video writer attribute, frame size."); CHECK_HR(CopyAttribute(pVideoType, pVideoOutType, MF_MT_FRAME_RATE), L"Failed to set video writer attribute, frame rate."); CHECK_HR(CopyAttribute(pVideoType, pVideoOutType, MF_MT_PIXEL_ASPECT_RATIO), L"Failed to set video writer attribute, aspect ratio."); CHECK_HR(CopyAttribute(pVideoType, pVideoOutType, MF_MT_INTERLACE_MODE), L"Failed to set video writer attribute, interlace mode.");; CHECK_HR(pWriter->AddStream(pVideoOutType, videoStreamIndex), L"Failed to add the video stream to the sink writer."); pVideoOutType->Release(); // Configure the audio stream. // See http://msdn.microsoft.com/en-us/library/windows/desktop/dd742785(v=vs.85).aspx for AAC encoder settings. // http://msdn.microsoft.com/en-us/library/ff819476%28VS.85%29.aspx CHECK_HR(MFCreateMediaType(&pAudioOutType), L"Configure encoder failed to create media type for audio output sink."); CHECK_HR(pAudioOutType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), L"Failed to set audio writer attribute, media type."); CHECK_HR(pAudioOutType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC), L"Failed to set audio writer attribute, audio format (AAC)."); CHECK_HR(pAudioOutType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), L"Failed to set audio writer attribute, number of channels."); CHECK_HR(pAudioOutType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), L"Failed to set audio writer attribute, bits per sample."); CHECK_HR(pAudioOutType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), L"Failed to set audio writer attribute, samples per second."); CHECK_HR(pAudioOutType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 16000), L"Failed to set audio writer attribute, average bytes per second."); //CHECK_HR( pAudioOutType->SetUINT32( MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0x29 ), L"Failed to set audio writer attribute, level indication."); CHECK_HR(pWriter->AddStream(pAudioOutType, audioStreamIndex), L"Failed to add the audio stream to the sink writer."); pAudioOutType->Release(); return S_OK; }
/* List all the media modes available on the device. */ void ListModes(IMFSourceReader *pReader) { HRESULT hr = NULL; DWORD dwMediaTypeIndex = 0; while (SUCCEEDED(hr)) { IMFMediaType *pType = NULL; hr = pReader->GetNativeMediaType(0, dwMediaTypeIndex, &pType); if (hr == MF_E_NO_MORE_TYPES) { hr = S_OK; break; } else if (SUCCEEDED(hr)) { // Examine the media type. (Not shown.) CMediaTypeTrace *nativeTypeMediaTrace = new CMediaTypeTrace(pType); printf("Native media type: %s.\n", nativeTypeMediaTrace->GetString()); pType->Release(); } ++dwMediaTypeIndex; } }
// This is called from the DoProcessOutput method if the stream format // has changed. // // Thread context: decoder thread bool DecoderMF::HandleStreamChange() { bool ret = false; HRESULT hr; DWORD numOutputStreams; IMFMediaType* mediaType = NULL; AM_MEDIA_TYPE* mformt = NULL; hr = m_h264Decoder->GetStreamCount(NULL, &numOutputStreams); if (FAILED(hr)) goto bail; if (numOutputStreams != 1) goto bail; hr = S_OK; int idx = 0; while (hr == S_OK) { hr = m_h264Decoder->GetOutputAvailableType(0, idx, &mediaType); if (FAILED(hr)) goto bail; mediaType->GetRepresentation(FORMAT_MFVideoFormat , (LPVOID*)&mformt); MFVIDEOFORMAT* z = (MFVIDEOFORMAT*)mformt->pbFormat; unsigned int format = z->surfaceInfo.Format; mediaType->FreeRepresentation(FORMAT_MFVideoFormat ,(LPVOID)mformt); if (format == '2YUY') break; ++idx; } hr = m_h264Decoder->SetOutputType(0, mediaType, 0); if (FAILED(hr)) goto bail; if (! CreateOutputSample()) goto bail; if (m_previewWindow != NULL) { if (! m_previewWindow->SetMediaType(mediaType)) goto bail; m_previewConfigured = true; } ret = true; bail: if (mediaType != NULL) mediaType->Release(); return ret; }
IMFMediaType* MFDecoderSourceReader::setSource(IMFMediaSource *source, const QAudioFormat &audioFormat) { IMFMediaType *mediaType = NULL; if (m_source == source) return mediaType; if (m_source) { m_source->Release(); m_source = NULL; } if (m_sourceReader) { m_sourceReader->Release(); m_sourceReader = NULL; } if (!source) return mediaType; IMFAttributes *attr = NULL; MFCreateAttributes(&attr, 1); if (SUCCEEDED(attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this))) { if (SUCCEEDED(MFCreateSourceReaderFromMediaSource(source, attr, &m_sourceReader))) { m_source = source; m_source->AddRef(); m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_ALL_STREAMS), FALSE); m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE); IMFMediaType *pPartialType = NULL; MFCreateMediaType(&pPartialType); pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio); if (audioFormat.sampleType() == QAudioFormat::Float) { pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float); } else { pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM); } m_sourceReader->SetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), NULL, pPartialType); pPartialType->Release(); m_sourceReader->GetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), &mediaType); // Ensure the stream is selected. m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE); } attr->Release(); } return mediaType; }
/* List all the media modes available on the device. */ void FindVideoMode(IMFSourceReader *pReader, const GUID mediaSubType, int width, int height, /* out */ IMFMediaType *&foundpType) { HRESULT hr = NULL; DWORD dwMediaTypeIndex = 0; while (SUCCEEDED(hr)) { IMFMediaType *pType = NULL; hr = pReader->GetNativeMediaType(0, dwMediaTypeIndex, &pType); if (hr == MF_E_NO_MORE_TYPES) { hr = S_OK; break; } else if (SUCCEEDED(hr)) { // Examine the media type. (Not shown.) /*CMediaTypeTrace *nativeTypeMediaTrace = new CMediaTypeTrace(pType); printf("Native media type: %s.\n", nativeTypeMediaTrace->GetString());*/ GUID videoSubType; UINT32 pWidth = 0, pHeight = 0; hr = pType->GetGUID(MF_MT_SUBTYPE, &videoSubType); MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &pWidth, &pHeight); if (SUCCEEDED(hr)) { //printf("Video subtype %s, width=%i, height=%i.\n", STRING_FROM_GUID(videoSubType), pWidth, pHeight); if (videoSubType == mediaSubType && pWidth == width && pHeight == height) { foundpType = pType; printf("Media type successfully located.\n"); break; } } pType->Release(); } ++dwMediaTypeIndex; } }
// Called by the constructor only (for setting up the IMFTransform) // // Thread context: Dialog window thread bool DecoderMF::CreateInputMediaType(IMFMediaType** mediaType) { bool ret = false; HRESULT hr; IMFMediaType* newMediaType = NULL; if (mediaType == NULL) return false; hr = MFCreateMediaType(&newMediaType); if (FAILED(hr)) goto bail; hr = newMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); if (FAILED(hr)) goto bail; hr = newMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); if (FAILED(hr)) goto bail; ret = true; bail: if (ret == false) { if (newMediaType != NULL) { newMediaType->Release(); newMediaType = NULL; } } else { *mediaType = newMediaType; } return ret; }
// Thread context: Dialog window thread DecoderMF::DecoderMF() : m_outputSample(NULL), m_previewWindow(NULL), m_decoderThread(NULL), m_decoderThreadRunning(false), m_decoderThreadEvent(NULL) { HRESULT hr; IMFMediaType* mediaType; m_previewConfigured = true; hr = CoCreateInstance(CLSID_CMSH264DecoderMFT, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, (void**)&m_h264Decoder); if (FAILED(hr)) throw 1; // Create and set input Media Type if (! CreateInputMediaType(&mediaType)) { m_h264Decoder->Release(); throw 1; } hr = m_h264Decoder->SetInputType(0, mediaType, 0); mediaType->Release(); if (FAILED(hr)) { m_h264Decoder->Release(); throw 1; } // Set output type hr = m_h264Decoder->GetOutputAvailableType(0, 0, &mediaType); if (FAILED(hr)) { m_h264Decoder->Release(); throw 1; } hr = m_h264Decoder->SetOutputType(0, mediaType, 0); mediaType->Release(); if (FAILED(hr)) { m_h264Decoder->Release(); throw 1; } // Some sanity checks DWORD numInputStreams, numOutputStreams; hr = m_h264Decoder->GetStreamCount(&numInputStreams, &numOutputStreams); if (FAILED(hr)) { m_h264Decoder->Release(); throw 1; } if (numInputStreams != 1 || numOutputStreams != 1) { // This would be unexpected... m_h264Decoder->Release(); throw 1; } MFT_OUTPUT_STREAM_INFO outputStreamInfo; hr = m_h264Decoder->GetOutputStreamInfo(0, &outputStreamInfo); if (FAILED(hr)) { m_h264Decoder->Release(); throw 1; } if ((outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) || !(outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE) || !(outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_WHOLE_SAMPLES)) { // This would be unexpected... m_h264Decoder->Release(); throw 1; } // Great - if we got here, it means Media Foundation is all OK. Lets // start the decoder thread. InitializeCriticalSection(&m_criticalSection); m_decoderThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_decoderThreadRunning = true; m_decoderThread = CreateThread(NULL, 0, DecoderThreadFunction, this, 0, NULL); }
unsigned char *BBWin8Game::LoadAudioData( String path,int *length,int *channels,int *format,int *hertz ){ String url=PathToFilePath( path ); DXASS( MFStartup( MF_VERSION ) ); IMFAttributes *attrs; DXASS( MFCreateAttributes( &attrs,1 ) ); DXASS( attrs->SetUINT32( MF_LOW_LATENCY,TRUE ) ); IMFSourceReader *reader; DXASS( MFCreateSourceReaderFromURL( url.ToCString<wchar_t>(),attrs,&reader ) ); attrs->Release(); IMFMediaType *mediaType; DXASS( MFCreateMediaType( &mediaType ) ); DXASS( mediaType->SetGUID( MF_MT_MAJOR_TYPE,MFMediaType_Audio ) ); DXASS( mediaType->SetGUID( MF_MT_SUBTYPE,MFAudioFormat_PCM ) ); DXASS( reader->SetCurrentMediaType( MF_SOURCE_READER_FIRST_AUDIO_STREAM,0,mediaType ) ); mediaType->Release(); IMFMediaType *outputMediaType; DXASS( reader->GetCurrentMediaType( MF_SOURCE_READER_FIRST_AUDIO_STREAM,&outputMediaType ) ); WAVEFORMATEX *wformat; uint32 formatByteCount=0; DXASS( MFCreateWaveFormatExFromMFMediaType( outputMediaType,&wformat,&formatByteCount ) ); *channels=wformat->nChannels; *format=wformat->wBitsPerSample/8; *hertz=wformat->nSamplesPerSec; CoTaskMemFree( wformat ); outputMediaType->Release(); /* PROPVARIANT var; DXASS( reader->GetPresentationAttribute( MF_SOURCE_READER_MEDIASOURCE,MF_PD_DURATION,&var ) ); LONGLONG duration=var.uhVal.QuadPart; float64 durationInSeconds=(duration / (float64)(10000 * 1000)); m_maxStreamLengthInBytes=(uint32)( durationInSeconds * m_waveFormat.nAvgBytesPerSec ); */ std::vector<unsigned char*> bufs; std::vector<uint32> lens; uint32 len=0; for( ;; ){ uint32 flags=0; IMFSample *sample; DXASS( reader->ReadSample( MF_SOURCE_READER_FIRST_AUDIO_STREAM,0,0,reinterpret_cast<DWORD*>(&flags),0,&sample ) ); if( flags & MF_SOURCE_READERF_ENDOFSTREAM ){ break; } if( sample==0 ){ abort(); } IMFMediaBuffer *mediaBuffer; DXASS( sample->ConvertToContiguousBuffer( &mediaBuffer ) ); uint8 *audioData=0; uint32 sampleBufferLength=0; DXASS( mediaBuffer->Lock( &audioData,0,reinterpret_cast<DWORD*>( &sampleBufferLength ) ) ); unsigned char *buf=(unsigned char*)malloc( sampleBufferLength ); memcpy( buf,audioData,sampleBufferLength ); bufs.push_back( buf ); lens.push_back( sampleBufferLength ); len+=sampleBufferLength; DXASS( mediaBuffer->Unlock() ); mediaBuffer->Release(); sample->Release(); } reader->Release(); *length=len/(*channels * *format); unsigned char *data=(unsigned char*)malloc( len ); unsigned char *p=data; for( int i=0;i<bufs.size();++i ){ memcpy( p,bufs[i],lens[i] ); free( bufs[i] ); p+=lens[i]; } gc_force_sweep=true; return data; }
VideoCompressorResult VideoCompressor::OpenFile(const String &Filename, UINT Width, UINT Height, UINT BitRate, UINT FrameRate, UINT AudioDeviceIndex, Clock *Timer) { VideoCompressorResult Result = VideoCompressorResultSuccess; _Width = Width; _Height = Height; _CapturingAudio = (AudioDeviceIndex != 0xFFFFFFFF); _Clock = Timer; HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); //PersistentAssert(SUCCEEDED(hr), "CoInitializeEx failed"); hr = MFStartup(MF_VERSION); PersistentAssert(SUCCEEDED(hr), "MFStartup failed"); hr = MFCreateSinkWriterFromURL( UnicodeString(Filename).CString(), NULL, NULL, &_Writer ); PersistentAssert(SUCCEEDED(hr), "MFCreateSinkWriterFromURL failed"); const UINT RawBufferSize = Width * Height * 4; IMFMediaType *OutputMediaType; MFCreateMediaType(&OutputMediaType); InitMediaType(OutputMediaType, MFVideoFormat_H264, BitRate, Width, Height, FrameRate); IMFMediaType *InputMediaType; MFCreateMediaType(&InputMediaType); InitMediaType(InputMediaType, MFVideoFormat_RGB32, RawBufferSize, Width, Height, FrameRate); DWORD VideoStreamIndex; hr = _Writer->AddStream(OutputMediaType, &VideoStreamIndex); PersistentAssert(SUCCEEDED(hr), "AddStream failed"); OutputMediaType->Release(); /*hr = MFTRegisterLocalByCLSID( __uuidof(CColorConvertDMO), MFT_CATEGORY_VIDEO_PROCESSOR, L"", MFT_ENUM_FLAG_SYNCMFT, 0, NULL, 0, NULL ); PersistentAssert(SUCCEEDED(hr), "MFTRegisterLocalByCLSID failed");*/ hr = _Writer->SetInputMediaType(VideoStreamIndex, InputMediaType, NULL); InputMediaType->Release(); if(FAILED(hr)) { if(Width > 1920 || Height > 1080) { MessageBox(NULL, "The maximum resolution for H.264 video is 1920x1080.", "Invalid Window Dimensions", MB_OK | MB_ICONERROR); } else { MessageBox(NULL, "There was an error when attempting to initialize video capture. The maximum resolution for H.264 video is 1920x1080.", "Invalid Window Dimensions", MB_OK | MB_ICONERROR); } _Writer->Release(); _Writer = NULL; _Clock = NULL; return VideoCompressorResultFailure; } if(_CapturingAudio) { // // Setup the output media type // IMFMediaType *OutputAudioType; hr = MFCreateMediaType( &OutputAudioType ); PersistentAssert(SUCCEEDED(hr), "MFCreateMediaType failed"); const UINT SamplesPerSecond = 44100; const UINT AverageBytesPerSecond = 24000; const UINT ChannelCount = 2; const UINT BitsPerSample = 16; OutputAudioType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Audio ) ; OutputAudioType->SetGUID( MF_MT_SUBTYPE, MFAudioFormat_AAC ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, SamplesPerSecond ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_BITS_PER_SAMPLE, BitsPerSample ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_NUM_CHANNELS, ChannelCount ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_AVG_BYTES_PER_SECOND, AverageBytesPerSecond ) ; OutputAudioType->SetUINT32( MF_MT_AUDIO_BLOCK_ALIGNMENT, 1 ) ; //OutputAudioType->SetUINT32( MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0x29 ) ; DWORD AudioStreamIndex; hr = _Writer->AddStream( OutputAudioType, &AudioStreamIndex ); PersistentAssert(SUCCEEDED(hr), "AddStream failed"); // // Setup the input media type // IMFMediaType *InputAudioType; MFCreateMediaType( &InputAudioType ); InputAudioType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Audio ); InputAudioType->SetGUID( MF_MT_SUBTYPE, MFAudioFormat_PCM ); InputAudioType->SetUINT32( MF_MT_AUDIO_BITS_PER_SAMPLE, BitsPerSample ); InputAudioType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, SamplesPerSecond ); InputAudioType->SetUINT32( MF_MT_AUDIO_NUM_CHANNELS, ChannelCount ); hr = _Writer->SetInputMediaType( AudioStreamIndex, InputAudioType, NULL ); PersistentAssert(SUCCEEDED(hr), "SetInputMediaType failed"); _AudioCapture.StartCapture(this, AudioDeviceIndex); } hr = _Writer->BeginWriting(); PersistentAssert(SUCCEEDED(hr), "BeginWriting failed"); hr = MFCreateSample(&_Sample); PersistentAssert(SUCCEEDED(hr), "MFCreateSample failed"); hr = MFCreateMemoryBuffer(RawBufferSize, &_Buffer); _Buffer->SetCurrentLength(RawBufferSize); _Sample->AddBuffer(_Buffer); return Result; }
/** Add stream to topology */ FIntPoint FImfVideoPlayer::AddStreamToTopology( IMFTopology* Topology, IMFPresentationDescriptor* PresentationDesc, IMFStreamDescriptor* StreamDesc, FImfSampleGrabberCallback* SampleGrabberCallback ) { FIntPoint OutDimensions = FIntPoint( ForceInit ); HRESULT HResult = S_OK; IMFActivate* SinkActivate = NULL; { IMFMediaTypeHandler* Handler = NULL; HResult = StreamDesc->GetMediaTypeHandler( &Handler ); check( SUCCEEDED( HResult ) ); GUID MajorType; HResult = Handler->GetMajorType( &MajorType ); check( SUCCEEDED( HResult ) ); /* Audio stream */ if( MajorType == MFMediaType_Audio ) { /* No audio required */ Handler->Release( ); return FIntPoint( ForceInit ); } /* Video stream */ else if( MajorType == MFMediaType_Video ) { IMFMediaType* OutputType = NULL; HResult = Handler->GetCurrentMediaType( &OutputType ); check( SUCCEEDED( HResult ) ); IMFMediaType* InputType = NULL; HResult = MFCreateMediaType( &InputType ); UINT32 Width = 0, Height = 0; HResult = MFGetAttributeSize( OutputType, MF_MT_FRAME_SIZE, &Width, &Height ); check( SUCCEEDED( HResult ) ); HResult = InputType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Video ); check( SUCCEEDED( HResult ) ); HResult = InputType->SetGUID( MF_MT_SUBTYPE, MFVideoFormat_RGB32 ); check( SUCCEEDED( HResult ) ); HResult = InputType->SetUINT32( MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE ); check( SUCCEEDED( HResult ) ); HResult = MFCreateSampleGrabberSinkActivate( InputType, SampleGrabberCallback, &SinkActivate ); check( SUCCEEDED( HResult ) ); InputType->Release( ); OutputType->Release( ); OutDimensions = FIntPoint( Width, Height ); } Handler->Release( ); } IMFTopologyNode* SourceNode = NULL; { HResult = MFCreateTopologyNode( MF_TOPOLOGY_SOURCESTREAM_NODE, &SourceNode ); check( SUCCEEDED( HResult ) ); HResult = SourceNode->SetUnknown( MF_TOPONODE_SOURCE, MediaSource ); check( SUCCEEDED( HResult ) ); HResult = SourceNode->SetUnknown( MF_TOPONODE_PRESENTATION_DESCRIPTOR, PresentationDesc ); check( SUCCEEDED( HResult ) ); HResult = SourceNode->SetUnknown( MF_TOPONODE_STREAM_DESCRIPTOR, StreamDesc ); check( SUCCEEDED( HResult ) ); HResult = Topology->AddNode( SourceNode ); check( SUCCEEDED( HResult ) ); } IMFTopologyNode* OutputNode = NULL; { HResult = MFCreateTopologyNode( MF_TOPOLOGY_OUTPUT_NODE, &OutputNode ); check( SUCCEEDED( HResult ) ); HResult = OutputNode->SetObject( SinkActivate ); check( SUCCEEDED( HResult ) ); HResult = OutputNode->SetUINT32( MF_TOPONODE_STREAMID, 0 ); check( SUCCEEDED( HResult ) ); HResult = OutputNode->SetUINT32( MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, 0 ); check( SUCCEEDED( HResult ) ); HResult = Topology->AddNode( OutputNode ); check( SUCCEEDED( HResult ) ); } HResult = SourceNode->ConnectOutput( 0, OutputNode, 0 ); check( SUCCEEDED( HResult ) ); SourceNode->Release( ); OutputNode->Release( ); SinkActivate->Release( ); return OutDimensions; }