HRESULT DirectShowVideoWrapper::ConnectSampleGrabber(void)
{
    HRESULT hr = S_OK;
    TCHAR szErr[MAX_ERROR_TEXT_LEN];
    
    // Register the graph in the Running Object Table (for debug purposes)
    AddGraphToROT(_pGraphBuilder, &dwROT);

    // Create the Sample Grabber which we will use
    // To take each frame for texture generation
    if(_pSampleGrabberFilter == NULL)
    {
        hr = _pSampleGrabberFilter.CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER);
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "Could not create SampleGrabberFilter, error: " << szErr << std::endl;
            return hr;
        }
    }

    _pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, reinterpret_cast<void**>(&_pSampleGrabber));

    // We have to set the 24-bit RGB desire here
    // So that the proper conversion filters
    // Are added automatically.
    AM_MEDIA_TYPE desiredType;
    memset(&desiredType, 0, sizeof(desiredType));
    desiredType.majortype = MEDIATYPE_Video;
    //desiredType.subtype = MEDIASUBTYPE_RGB565;
    desiredType.subtype = MEDIASUBTYPE_RGB24;
    //desiredType.subtype = GUID_NULL;
    desiredType.formattype = GUID();
    //desiredType.formattype = FORMAT_VideoInfo;

    _pSampleGrabber->SetMediaType(&desiredType);
    _pSampleGrabber->SetBufferSamples(TRUE);


    // A Null Renderer does not display the video
    // But it allows the Sample Grabber to run
    // And it will keep proper playback timing
    // Unless specified otherwise.
    if(_pVideoRenderer == NULL)
    {
        hr = _pVideoRenderer.CoCreateInstance(CLSID_NullRenderer,   NULL, CLSCTX_INPROC_SERVER);
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "Unable to create Null Renderer, error: " << szErr << std::endl;
            return hr;
        }
    }
    
    //Get Input pins to VideoRenderer
    IPin* _VideoRendererIntputPin;
    if (FAILED(hr = _pVideoRenderer->FindPin(L"In", &_VideoRendererIntputPin)))
    {
        AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
        SWARNING << "Could not find VideoRenderer Intput Pin, error: " << szErr << std::endl;
        return hr;
    }

    IBaseFilter* pVidRenderer = NULL;
	hr = FindVideoRenderer(_pGraphBuilder,&pVidRenderer);
    if (FAILED(hr))
    {
        AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
        SWARNING << "error: " << szErr << std::endl;
        return hr;
    }

	if(pVidRenderer)
	{
        SLOG << "Removing default video renderer" << std::endl;
		//get input pin of video renderer
		IPin* ipin;
        hr = GetPin(pVidRenderer, PINDIR_INPUT, 0, &ipin);
		if (FAILED(hr))
		{
			AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
			SWARNING << "Get Vidio Renderer in pin, error: " << szErr << std::endl;
			return hr;
		}
		IPin* opin = NULL;
		//find out who the renderer is connected to and disconnect from them
		hr = ipin->ConnectedTo(&opin);
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "error: " << szErr << std::endl;
            return hr;
        }

		//Get the filter of the opin
		PIN_INFO OpinInfo;
		opin->QueryPinInfo(&OpinInfo);
		IBaseFilter* LastFilter(OpinInfo.pFilter);

		FILTER_INFO LastFilterInfo;
		LastFilter->QueryFilterInfo(&LastFilterInfo);
		CLSID LastFilterClassID;
		LastFilter->GetClassID(&LastFilterClassID);
		SLOG << "Last filter name: " << LastFilterInfo.achName 
			<< ", ClassID " << LastFilterClassID.Data1 << "-" << LastFilterClassID.Data2 << "-" << LastFilterClassID.Data3 << "-" << LastFilterClassID.Data4
			 << std::endl;
		LPWSTR *VendorInfo;
		LastFilter->QueryVendorInfo(VendorInfo);
		if(VendorInfo)
		{
			SLOG << "Last filter vendor: " << *VendorInfo << std::endl;
		}
		
		hr = ipin->Disconnect();
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "error: " << szErr << std::endl;
            return hr;
        }
		hr = opin->Disconnect();
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "error: " << szErr << std::endl;
            return hr;
        }

		//SAFE_RELEASE(ipin);

		//remove the default renderer from the graph		
		hr = _pGraphBuilder->RemoveFilter(pVidRenderer);
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "error: " << szErr << std::endl;
            return hr;
        }
		//SAFE_RELEASE(pVidRenderer);

		//see if the video renderer was originally connected to 
		//a color space converter
		_pGraphBuilder->FindFilterByName(L"Color Space Converter", &_pCSCFilter);
		if(_pCSCFilter == NULL)
		{
			// Create the Color Space filter
			hr = _pCSCFilter.CoCreateInstance(CLSID_Colour, NULL, CLSCTX_INPROC_SERVER);
			if (FAILED(hr))
			{
				AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
				SWARNING << "Could not create Color Space Converter Filter, error: " << szErr << std::endl;
				return hr;
			}

			hr = _pGraphBuilder->AddFilter(_pCSCFilter, L"Color Space Converter");
			if (FAILED(hr))
			{
				AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
				SWARNING << "Could not add Color Space Converter Filter, error: " << szErr << std::endl;
				return hr;
			}

			//get the output pin of the last filter
			hr = GetPin(LastFilter, PINDIR_OUTPUT, 0, &opin);
			if (FAILED(hr))
			{
				AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
				SWARNING << "Get Last filter out pin, error: " << szErr << std::endl;
				return hr;
			}

			//get the input pin of the Color Space Converter
			hr = GetPin(_pCSCFilter, PINDIR_INPUT, 0, &ipin);
			if (FAILED(hr))
			{
				AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
				SWARNING << "Get Color Space Converter In Pin, error: " << szErr << std::endl;
				return hr;
			}

			//connect the filter that was originally connected to the default renderer
			//to the Color Space Converter
			SLOG << "Attaching Color Space Converter Filter. "
				 << opin
				 << " -> " << ipin << std::endl;
			hr = _pGraphBuilder->Connect(opin, ipin);
			if (FAILED(hr))
			{
				AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
				SWARNING << "Could not attach Color Space Converter Filter so it won't be used, error: " << szErr << std::endl;
				//return hr;
			}
			else
			{
				LastFilter = _pCSCFilter;
			}
		}

        hr = _pGraphBuilder->AddFilter(_pSampleGrabberFilter, L"Video Sample Grabber");
        
		//get the input pin of the Sample Grabber
		hr = GetPin(_pSampleGrabberFilter, PINDIR_INPUT, 0, &ipin);
		if (FAILED(hr))
		{
			AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
			SWARNING << "Get Sample Grabber In Pin, error: " << szErr << std::endl;
			return hr;
		}

		//get the output pin of the last filter in the graph
		hr = GetPin(LastFilter, PINDIR_OUTPUT, 0, &opin);
		if (FAILED(hr))
		{
			AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
			SWARNING << "Get Color Space Converter out pin, error: " << szErr << std::endl;
			return hr;
		}

        SLOG << "Attaching video sample grabber filter." << std::endl;
		hr = _pGraphBuilder->Connect(opin, ipin);
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "error: " << szErr << std::endl;
            return hr;
        }



		//SAFE_RELEASE(ipin);
		//SAFE_RELEASE(opin);

		//get output pin of sample grabber
		hr = GetPin(_pSampleGrabberFilter, PINDIR_OUTPUT, 0, &opin);
		if (FAILED(hr))
		{
			AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
			SWARNING << "Get Sample Grabber out pin, error: " << szErr << std::endl;
			return hr;
		}
        
		
        SLOG << "Attaching Video Null Renderer." << std::endl;
        hr = _pGraphBuilder->AddFilter(_pVideoRenderer, L"Video Null Renderer");
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "Unable to add Renderer to filter graph, error: " << szErr << std::endl;
            return hr;
        }

		//get input pin of null renderer
		hr = GetPin(_pVideoRenderer, PINDIR_INPUT, 0, &ipin);
		if (FAILED(hr))
		{
			AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
			SWARNING << "Get Null Renderer in pin, error: " << szErr << std::endl;
			return hr;
		}

		//connect them
        SLOG << "Attaching null video renderer." << std::endl;
		hr = _pGraphBuilder->Connect(opin, ipin);
        if (FAILED(hr))
        {
            AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
            SWARNING << "Unable to connect Renderer to sample grabber, error: " << szErr << std::endl;
            return hr;
        }
		//SAFE_RELEASE(ipin);
		//SAFE_RELEASE(opin);
	}

    

    // Just a little trick so that we don't have to know
    // The video resolution when calling this method.
    bool mediaConnected = false;
    AM_MEDIA_TYPE connectedType;
    if (SUCCEEDED(hr = _pSampleGrabber->GetConnectedMediaType(&connectedType)))
    {
        if (connectedType.formattype == FORMAT_VideoInfo)
        {
            VIDEOINFOHEADER* infoHeader = (VIDEOINFOHEADER*)connectedType.pbFormat;
            _VideoWidth = infoHeader->bmiHeader.biWidth;
            _VideoHeight = infoHeader->bmiHeader.biHeight;

            mediaConnected = true;
        }
        else if (connectedType.formattype == FORMAT_VideoInfo2)
        {
            VIDEOINFOHEADER* infoHeader = (VIDEOINFOHEADER*)connectedType.pbFormat;
            _VideoWidth = infoHeader->bmiHeader.biWidth;
            _VideoHeight = infoHeader->bmiHeader.biHeight;

            mediaConnected = true;
        }
        else
        {
            SWARNING << "Unable to get the media type connected to the sample grabber." << std::endl;
        }
        SLOG << "Video Dimensions: " << _VideoWidth << " x " << _VideoHeight << std::endl;
        CoTaskMemFree(connectedType.pbFormat);
    }
    else
    {
        AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
        SWARNING << "Unable to get connected media type, error: " << szErr << std::endl;
        return hr;
    }

    /*if (!mediaConnected)
    {
        uninitVideo();
        return false;
    }*/
    return hr;
}
Пример #2
0
//----------------------------------------------------------------------------
//! @brief	  	フィルタグラフの構築
//! @param 		callbackwin : メッセージを送信するウィンドウ
//! @param 		stream : 読み込み元ストリーム
//! @param 		streamname : ストリームの名前
//! @param 		type : メディアタイプ(拡張子)
//! @param 		size : メディアサイズ
//----------------------------------------------------------------------------
void __stdcall tTVPDSMixerVideoOverlay::BuildGraph( HWND callbackwin, IStream *stream, const wchar_t * streamname, const wchar_t *type, unsigned __int64 size )
{
	HRESULT			hr;

	//CoInitialize(NULL);

	// detect CMediaType from stream's extension ('type')
	try {
		if( FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)) )
			ThrowDShowException(L"Failed to call CoInitializeEx.", hr);

		// create IFilterGraph instance
		if( FAILED(hr = m_GraphBuilder.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC)) )
			ThrowDShowException(L"Failed to create FilterGraph.", hr);

		// Register to ROT
		if(GetShouldRegisterToROT())
		{
			AddToROT(m_dwROTReg);
		}

		{
			CAutoLock Lock(&m_VMRLock);
			OwnerWindow = callbackwin;	// copy window handle for D3D
			m_OwnerInst = GetModuleHandle(NULL);
		}
		m_AllocatorPresenter = new CVMRCustomAllocatorPresenter9(this,m_VMRLock);
		m_AllocatorPresenter->AddRef();
		m_AllocatorPresenter->Initialize();
		if( IsWindowsMediaFile(type) )
		{
			CComPtr<IBaseFilter>	pVMR9;
			AddVMR9Filer( pVMR9 );
			BuildWMVGraph( pVMR9, stream );

			if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerCtrl ) ) )
				ThrowDShowException(L"Failed to query IVMRMixerControl9.", hr);
			if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerBmp ) ) )
				ThrowDShowException(L"Failed to query IVMRMixerBitmap9.", hr);
		}
		else
		{
			CMediaType mt;
			mt.majortype = MEDIATYPE_Stream;
			ParseVideoType( mt, type ); // may throw an exception

			// create proxy filter
			m_Proxy = new CIStreamProxy( stream, size );
			hr = S_OK;
			m_Reader = new CIStreamReader( m_Proxy, &mt, &hr );
			if( FAILED(hr) || m_Reader == NULL )
				ThrowDShowException(L"Failed to create proxy filter object.", hr);
			m_Reader->AddRef();

			// add fliter
			if( FAILED(hr = GraphBuilder()->AddFilter( m_Reader, L"Stream Reader")) )
				ThrowDShowException(L"Failed to call IFilterGraph::AddFilter.", hr);
	
			// AddFilterしたのでRelease
			m_Reader->Release();

			if( mt.subtype == MEDIASUBTYPE_Avi || mt.subtype == MEDIASUBTYPE_QTMovie )
			{
				// render output pin
				if( FAILED(hr = GraphBuilder()->Render(m_Reader->GetPin(0))) )
					ThrowDShowException(L"Failed to call IGraphBuilder::Render.", hr);
	
				CComPtr<IBaseFilter>	pRender;
				if( FAILED(hr = FindVideoRenderer( &pRender ) ) )
					ThrowDShowException(L"Failed to call FindVideoRenderer( &pRender ).", hr);
	
				CComPtr<IPin>	pRenderPin;
				pRenderPin = GetInPin(pRender, 0);
	
				// get decoder output pin
				CComPtr<IPin>			pDecoderPinOut;
				if( FAILED(hr = pRenderPin->ConnectedTo( &pDecoderPinOut )) )
					ThrowDShowException(L"Failed to call pRenderPin->ConnectedTo( &pDecoderPinOut ).", hr);
	
				// dissconnect pins
				if( FAILED(hr = pDecoderPinOut->Disconnect()) )
					ThrowDShowException(L"Failed to call pDecoderPinOut->Disconnect().", hr);
				if( FAILED(hr = pRenderPin->Disconnect()) )
					ThrowDShowException(L"Failed to call pRenderPin->Disconnect().", hr);
	
				// remove default render
				if( FAILED(hr = GraphBuilder()->RemoveFilter( pRender ) ) )
					ThrowDShowException(L"Failed to call GraphBuilder->RemoveFilter(pRenderPin).", hr);

				CComPtr<IBaseFilter>	pVMR9;
				AddVMR9Filer( pVMR9 );
	
				CComPtr<IPin>	pRdrPinIn;
				pRdrPinIn = GetInPin(pVMR9, 0);
	
				if( FAILED(hr = GraphBuilder()->ConnectDirect( pDecoderPinOut, pRdrPinIn, NULL )) )
					ThrowDShowException(L"Failed to call GraphBuilder()->ConnectDirect( pDecoderPinOut, pRdrPinIn, NULL ).", hr);
	
				if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerCtrl ) ) )
					ThrowDShowException(L"Failed to query IVMRMixerControl9.", hr);
				if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerBmp ) ) )
					ThrowDShowException(L"Failed to query IVMRMixerBitmap9.", hr);
			}
			else
			{
				CComPtr<IBaseFilter>	pVMR9;
				AddVMR9Filer( pVMR9 );
				BuildMPEGGraph( pVMR9, m_Reader); // may throw an exception
	
				if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerCtrl ) ) )
					ThrowDShowException(L"Failed to query IVMRMixerControl9.", hr);
				if( FAILED(hr = pVMR9.QueryInterface( &m_VMR9MixerBmp ) ) )
					ThrowDShowException(L"Failed to query IVMRMixerBitmap9.", hr);
			}
		}
#if 1
		{	// 平均フレーム表示時間を取得する
			CComPtr<IBaseFilter>	pRender;
			if( FAILED(hr = FindVideoRenderer( &pRender ) ) )
				ThrowDShowException(L"Failed to call FindVideoRenderer( &pRender ).", hr);

			CComPtr<IPin>	pRenderPin;
			pRenderPin = GetInPin(pRender, 0);

			AM_MEDIA_TYPE mt;
			if( FAILED(hr = pRenderPin->ConnectionMediaType(&mt)) )
				ThrowDShowException(L"Failed to call IPin::ConnectionMediaType(pmt).", hr);
			if( mt.formattype == FORMAT_VideoInfo && mt.cbFormat != 0 )
			{
				VIDEOINFOHEADER	*vih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat);
				m_AvgTimePerFrame = vih->AvgTimePerFrame;
				m_Width = vih->bmiHeader.biWidth;
				m_Height = vih->bmiHeader.biHeight;
			}
			else if( mt.formattype == FORMAT_VideoInfo2 && mt.cbFormat != 0 )
			{
				VIDEOINFOHEADER2 *vih = reinterpret_cast<VIDEOINFOHEADER2*>(mt.pbFormat);
				m_AvgTimePerFrame = vih->AvgTimePerFrame;
				m_Width = vih->bmiHeader.biWidth;
				m_Height = vih->bmiHeader.biHeight;
			}
			FreeMediaType(mt);
		}
#endif
		// query each interfaces
		if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_MediaControl )) )
			ThrowDShowException(L"Failed to query IMediaControl", hr);
		if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_MediaPosition )) )
			ThrowDShowException(L"Failed to query IMediaPosition", hr);
		if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_MediaSeeking )) )
			ThrowDShowException(L"Failed to query IMediaSeeking", hr);
		if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_MediaEventEx )) )
			ThrowDShowException(L"Failed to query IMediaEventEx", hr);

		if( FAILED(hr = m_GraphBuilder.QueryInterface( &m_BasicAudio )) )
			ThrowDShowException(L"Failed to query IBasicAudio", hr);

		// set notify event
		if(callbackwin)
		{
			if(FAILED(hr = Event()->SetNotifyWindow((OAHWND)callbackwin, WM_GRAPHNOTIFY, (long)(this))))
				ThrowDShowException(L"Failed to set IMediaEventEx::SetNotifyWindow.", hr);
		}
	}
	catch(const wchar_t *msg)
	{
		MakeAPause(true);
		ReleaseAll();
		CoUninitialize();
		TVPThrowExceptionMessage(msg);
	}
	catch(...)
	{
		MakeAPause(true);
		ReleaseAll();
		CoUninitialize();
		throw;
	}

	MakeAPause(false);
	CoUninitialize();
}