//==========================================================================; // // Composition.h : Declaration of the custom composition class for gluing encoder to sbe sink // Copyright (c) Microsoft Corporation 1999. // ///////////////////////////////////////////////////////////////////////////// #ifndef ENC2SIN_H #define ENC2SIN_H #pragma once #include #include "bdamedia.h" #include "MSVidTVTuner.h" #include "resource.h" // main symbols #include #include #include #include #include #include "msvidsbesource.h" #include "segment.h" ///////////////////////////////////////////////////////////////////////////// // Helper functions HRESULT CheckIfSecureClient(IUnknown *pUnk){ if(!pUnk){ TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient NULL pointer"); return E_POINTER; } #ifndef BUILD_WITH_DRM TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient BUILD_WITH_DRM = false"); return S_OK; #else #ifdef USE_TEST_DRM_CERT { DWORD dwDisableDRMCheck = 0; CRegKey c; CString keyname(_T("SOFTWARE\\Debug\\MSVidCtl")); DWORD rc = c.Open(HKEY_LOCAL_MACHINE, keyname, KEY_READ); if (rc == ERROR_SUCCESS) { rc = c.QueryValue(dwDisableDRMCheck, _T("DisableDRMCheck")); if (rc != ERROR_SUCCESS) { dwDisableDRMCheck = 0; } } if(dwDisableDRMCheck == 1){ return S_OK; } } #endif // QI for the SecureChannel interface on the Punk // (hopefully the ETFilter) HRESULT hr = S_OK; CComQIPtr spSecureClient(pUnk); if (!spSecureClient) { TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient Passed in pUnk doesnt support IDRMSecureChannel"); // Error: Passed in pUnk doesnt support IDRMSecureChannel return E_NOINTERFACE; } // Create the Server side and Init the keys/certs CComPtr spSecureServer; hr = DRMCreateSecureChannel( &spSecureServer); if(spSecureServer == NULL ){ TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient Cannot create secure server"); return E_OUTOFMEMORY; } hr = spSecureServer->DRMSC_AtomicConnectAndDisconnect( (BYTE *)pabCert2, cBytesCert2, // Cert (BYTE *)pabPVK2, cBytesPVK2, // PrivKey (BYTE *)abEncDecCertRoot, sizeof(abEncDecCertRoot), // PubKey spSecureClient); if(FAILED(hr)){ TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient DRMSC_AtomicConnectAndDisconnect failed " << hr); } else{ TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient DRMSC_AtomicConnectAndDisconnect Succeeded"); } return hr; #endif // BUILD_WITH_DRM } ///////////////////////////////////////////////////////////////////////////// // CEnc2SinComp class ATL_NO_VTABLE __declspec(uuid("A0B9B497-AFBC-45ad-A8A6-9B077C40D4F2")) CEnc2SinComp : public CComObjectRootEx, public CComCoClass, public IObjectWithSiteImplSec, public IMSVidCompositionSegmentImpl { private: DSFilterList m_pEncFilters; public: CEnc2SinComp() {} virtual ~CEnc2SinComp() {} REGISTER_NONAUTOMATION_OBJECT(IDS_PROJNAME, IDS_REG_ENC2SINCOMP_DESC, LIBID_MSVidCtlLib, __uuidof(CEnc2SinComp)); DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CEnc2SinComp) COM_INTERFACE_ENTRY(IMSVidCompositionSegment) COM_INTERFACE_ENTRY(IMSVidGraphSegment) COM_INTERFACE_ENTRY(IObjectWithSite) COM_INTERFACE_ENTRY(IPersist) END_COM_MAP() // IMSVidComposition public: // IMSVidGraphSegment // IMSVidCompositionSegment STDMETHOD(CheckEncFilters)(){ int j = 0; for(DSFilterList::iterator i = m_pEncFilters.begin(); i != m_pEncFilters.end(); ++i){ TRACELM(TRACE_ERROR, "CAnaSinComp::CheckEncFilters checking filter " << j); CComQIPtr spETConfig; CComPtr spUnkSecChan; spETConfig = (*i); if(!spETConfig){ TRACELM(TRACE_ERROR, "CAnaSinComp::CheckEncFilters filter " << j << " could not get et filter config interface"); return E_NOINTERFACE; } HRESULT hr = spETConfig->GetSecureChannelObject(&spUnkSecChan); hr = CheckIfSecureClient(spUnkSecChan); if(FAILED(hr)){ TRACELM(TRACE_ERROR, "CAnaSinComp::CheckEncFilters filter " << j << " Failed"); return E_FAIL; } ++j; } TRACELM(TRACE_ERROR, "CAnaSinComp::CheckEncFilters no failures"); return NOERROR; } STDMETHOD(PreRun)(){ return CheckEncFilters(); } STDMETHOD(OnEventNotify)(long lEvent, LONG_PTR lParam1, LONG_PTR lParam2){ if (lEvent == EC_STATE_CHANGE && lParam1 == State_Running) { TRACELM(TRACE_ERROR, "CAnaSinComp::OnEventNotify State_Running Event"); HRESULT hr = CheckEncFilters(); if(FAILED(hr)){ TRACELM(TRACE_ERROR, "CAnaSinComp::OnEventNotify CheckEncFilters Failed"); // need to throw a cert failure CComQIPtr pq_vidCtl; if(!m_pContainer){ return S_OK; } else{ hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast(&pq_vidCtl)); if(SUCCEEDED(hr) && pq_vidCtl){ pq_vidCtl->Stop(); } CComQIPtrpq_SBESink; VWOutputDevices pq_dev; hr = pq_vidCtl->get_OutputsActive(&pq_dev); if(FAILED(hr)){ return hr; } VWOutputDevices::iterator i; for(i = pq_dev.begin(); i != pq_dev.end(); ++i){ pq_SBESink = (*i).punkVal; if(pq_SBESink){ break; } } if(i != pq_dev.end() && pq_SBESink){ pq_SBESink->CertificateFailure(); } } } } return E_NOTIMPL; } STDMETHOD(put_Container)(IMSVidGraphSegmentContainer *pCtl) { try { if (!pCtl) { m_pEncFilters.clear(); return Unload(); } if (m_pContainer) { if (!m_pContainer.IsEqualObject(VWSegmentContainer(pCtl))) { //undone: support moving to different graph return Error(IDS_OBJ_ALREADY_INIT, __uuidof(IMSVidGraphSegment), CO_E_ALREADYINITIALIZED); } else { return NO_ERROR; } } // DON'T addref the container. we're guaranteed nested lifetimes // and an addref creates circular refcounts so we never unload. m_pContainer.p = pCtl; m_pGraph = m_pContainer.GetGraph(); } catch(...) { return E_UNEXPECTED; } return NOERROR; } STDMETHOD(Compose)(IMSVidGraphSegment * upstream, IMSVidGraphSegment * downstream) { if (m_fComposed) { return NOERROR; } ASSERT(m_pGraph); try { VIDPERF_FUNC; TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose()"); VWGraphSegment up(upstream); ASSERT(up.Graph() == m_pGraph); VWGraphSegment down(downstream); ASSERT(down.Graph() == m_pGraph); if (up.begin() == up.end()) { TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't compose empty up segment"); return E_INVALIDARG; } if (down.begin() == down.end()) { TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't compose empty down segment"); return E_INVALIDARG; } CMSVidStreamBufferSink* ds = (CMSVidStreamBufferSink*)downstream; DSFilter pSink(ds->m_Filters[0]); CComQIPtr qiEnc(upstream); CEncoder* iEnc; iEnc = static_cast(qiEnc.p); DSPin pVidPin; DSPin pAudPin; DSPin genVidPin; DSPin genAudPin; CString csName; // render demux out to vr DSFilter pDeMux = iEnc->m_Filters[iEnc->m_iDemux]; DSFilter::iterator iVidPin; DSFilter vr; DSMediaType mtVideo(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO, FORMAT_MPEG2Video); DSMediaType mtAudio(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Payload, FORMAT_WaveFormatEx); DSMediaType genericVideo(MEDIATYPE_Video); DSMediaType genericAudio(MEDIATYPE_Audio); for (iVidPin = pDeMux.begin(); iVidPin != pDeMux.end(); ++iVidPin) { DSPin::iterator j; for(j = (*iVidPin).begin(); j != (*iVidPin).end(); ++j){ DSMediaType pinType(*j); if (pinType == mtVideo){ CComPtr spMpeg2Analyze(CLSID_Mpeg2VideoStreamAnalyzer, NULL, CLSCTX_INPROC_SERVER); if (!spMpeg2Analyze) { //TRACELSM(TRACE_ERROR, (dbgDump << "CMSVidStreamBufferSink::Build() can't load Time Shift Sink"); return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), E_UNEXPECTED); } spMpeg2Analyze->QueryInterface(IID_IBaseFilter, reinterpret_cast(&vr)); if (!vr) { ASSERT(false); return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_UNEXPECTED); } m_Filters.push_back(vr); csName = _T("Mpeg2 Analysis"); m_pGraph.AddFilter(vr, csName); DSFilter::iterator a; for(a = vr.begin(); a != vr.end(); ++a){ HRESULT hr = (*a).Connect(*iVidPin); if(FAILED(hr)){ continue; } else{ break; } } if(a == vr.end()){ return E_FAIL; } for(a = vr.begin(); a != vr.end(); ++a){ if((*a).GetDirection() == PINDIR_OUTPUT){ pVidPin = (*a); } } if(!pVidPin){ return E_FAIL; } } else if(pinType == mtAudio){ pAudPin = (*iVidPin); } else if(pinType == genericVideo){ genVidPin = (*iVidPin); } else if(pinType == genericAudio){ genAudPin = (*iVidPin); } } if(!!pVidPin && !!pAudPin){ break; } } if(!pVidPin){ pVidPin = genVidPin; } if(!pAudPin){ pAudPin = genAudPin; } if(!pVidPin){ TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't find video pin on demux"); return E_UNEXPECTED; } if(!pAudPin){ TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't find audio pin on demux"); return E_UNEXPECTED; } DSFilterList intermediates; HRESULT hr = S_OK; DSFilter::iterator fil; #if ENCRYPT_NEEDED CComBSTR encString(L"{C4C4C4F1-0049-4E2B-98FB-9537F6CE516D}"); GUID2 encdecGuid (encString); // Create and add to graph the Video Tagger Filter CComPtr spEncTagV(encdecGuid, NULL, CLSCTX_INPROC_SERVER); if (!spEncTagV) { TRACELM(TRACE_ERROR, "CMSVidStreamBufferSink::Build() can't load Tagger filter"); return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), VFW_E_CERTIFICATION_FAILURE); } DSFilter vrV(spEncTagV); if (!vrV) { ASSERT(false); TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() on tagger interface"); return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_NOINTERFACE); } m_pEncFilters.push_back(vrV); m_Filters.push_back(vrV); csName = _T("Video Encoder Tagger Filter"); m_pGraph.AddFilter(vrV, csName); // Connect video pin to Tagger hr = pVidPin.IntelligentConnect(vrV, intermediates); if(FAILED(hr)){ TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect audio pin to Audio Tagger"); return E_UNEXPECTED; } // Connect Video to Sink DSFilter::iterator vP; hr = E_FAIL; for(vP = vrV.begin(); vP != vrV.end(); ++ vP){ if((*vP).GetDirection() == PINDIR_OUTPUT){ break; } } if(vP == vrV.end()){ TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() not video output pin"); return E_UNEXPECTED; } for(fil = pSink.begin(); fil != pSink.end() && FAILED(hr); ++fil){ hr = (*vP).Connect((*fil)); } if(FAILED(hr)){ TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Video Tagger to Sink"); return E_UNEXPECTED; } // Create and add to graph the Audio Tagger Filter CComPtr spEncTagA(encdecGuid, NULL, CLSCTX_INPROC_SERVER); if (!spEncTagA) { TRACELM(TRACE_ERROR, "CMSVidStreamBufferSink::Build() can't load Tagger filter"); return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), VFW_E_CERTIFICATION_FAILURE); } DSFilter vrA(spEncTagA); if (!vrA) { ASSERT(false); TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't create audio tagger filter"); return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_NOINTERFACE); } m_pEncFilters.push_back(vrV); m_Filters.push_back(vrA); csName = _T("Audio Encoder Tagger Filter"); m_pGraph.AddFilter(vrA, csName); // Connect audio pin to the Tagger hr = pAudPin.IntelligentConnect(vrA, intermediates); if(FAILED(hr)){ TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect audio pin to Audio Tagger"); return E_UNEXPECTED; } // Connect Tagger to Sink hr = E_FAIL; for(vP = vrA.begin(); vP != vrA.end(); ++ vP){ if((*vP).GetDirection() == PINDIR_OUTPUT){ break; } } if(vP == vrA.end()){ TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() no audio tagger pin"); return E_UNEXPECTED; } for(fil = pSink.begin(); fil != pSink.end() && FAILED(hr); ++fil){ hr = (*vP).Connect((*fil)); } if(FAILED(hr)){ TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Audio Tagger to Sink"); return E_UNEXPECTED; } #else // Connect the Video Pin to the sink DSFilter::iterator vidAnaPin; hr = E_FAIL; hr = E_FAIL; for(fil = pSink.begin(); fil != pSink.end() && FAILED(hr); ++fil){ if((*fil).GetDirection() == PINDIR_INPUT && !(*fil).IsConnected()){ hr = pVidPin.Connect((*fil)); } } if(FAILED(hr)){ TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Video Tagger to Sink"); ASSERT((L"Can't Connect vid to sink", FALSE)); return E_UNEXPECTED; } // Connect the Audio Pin to the Sink hr = E_FAIL; for(fil = pSink.begin(); fil != pSink.end() && FAILED(hr); ++fil){ if((*fil).GetDirection() == PINDIR_INPUT && !(*fil).IsConnected()){ hr = pAudPin.Connect((*fil)); } } if(FAILED(hr)){ TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Audio Tagger to Sink"); ASSERT((L"Can't Connect aud to sink", FALSE)); return E_UNEXPECTED; } #endif /* hr = m_pGraph.Connect(vrA, pSink, intermediates); if(FAILED(hr)){ TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Audio Tagger to Sink"); return E_UNEXPECTED; } */ ASSERT(intermediates.begin() == intermediates.end()); m_Filters.insert(m_Filters.end(), intermediates.begin(), intermediates.end()); TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() SUCCEEDED"); m_fComposed = true; return NOERROR; } catch (ComException &e) { TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() com exception"); return e; } catch (...) { TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() ... exception"); return E_UNEXPECTED; } } }; #endif // Enc2Sin_H // end of file - Enc2Sin.h