Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

482 lines
19 KiB

  1. //==========================================================================;
  2. //
  3. // Composition.h : Declaration of the custom composition class for gluing encoder to sbe sink
  4. // Copyright (c) Microsoft Corporation 1999.
  5. //
  6. /////////////////////////////////////////////////////////////////////////////
  7. #ifndef ENC2SIN_H
  8. #define ENC2SIN_H
  9. #pragma once
  10. #include <uuids.h>
  11. #include "bdamedia.h"
  12. #include "MSVidTVTuner.h"
  13. #include "resource.h" // main symbols
  14. #include <winerror.h>
  15. #include <algorithm>
  16. #include <compimpl.h>
  17. #include <seg.h>
  18. #include <objectwithsiteimplsec.h>
  19. #include "msvidsbesource.h"
  20. #include "segment.h"
  21. /////////////////////////////////////////////////////////////////////////////
  22. // Helper functions
  23. HRESULT CheckIfSecureClient(IUnknown *pUnk){
  24. if(!pUnk){
  25. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient NULL pointer");
  26. return E_POINTER;
  27. }
  28. #ifndef BUILD_WITH_DRM
  29. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient BUILD_WITH_DRM = false");
  30. return S_OK;
  31. #else
  32. #ifdef USE_TEST_DRM_CERT
  33. {
  34. DWORD dwDisableDRMCheck = 0;
  35. CRegKey c;
  36. CString keyname(_T("SOFTWARE\\Debug\\MSVidCtl"));
  37. DWORD rc = c.Open(HKEY_LOCAL_MACHINE, keyname, KEY_READ);
  38. if (rc == ERROR_SUCCESS) {
  39. rc = c.QueryValue(dwDisableDRMCheck, _T("DisableDRMCheck"));
  40. if (rc != ERROR_SUCCESS) {
  41. dwDisableDRMCheck = 0;
  42. }
  43. }
  44. if(dwDisableDRMCheck == 1){
  45. return S_OK;
  46. }
  47. }
  48. #endif
  49. // QI for the SecureChannel interface on the Punk
  50. // (hopefully the ETFilter)
  51. HRESULT hr = S_OK;
  52. CComQIPtr<IDRMSecureChannel> spSecureClient(pUnk);
  53. if (!spSecureClient) {
  54. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient Passed in pUnk doesnt support IDRMSecureChannel");
  55. // Error: Passed in pUnk doesnt support IDRMSecureChannel
  56. return E_NOINTERFACE;
  57. }
  58. // Create the Server side and Init the keys/certs
  59. CComPtr<IDRMSecureChannel> spSecureServer;
  60. hr = DRMCreateSecureChannel( &spSecureServer);
  61. if(spSecureServer == NULL ){
  62. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient Cannot create secure server");
  63. return E_OUTOFMEMORY;
  64. }
  65. hr = spSecureServer->DRMSC_AtomicConnectAndDisconnect(
  66. (BYTE *)pabCert2, cBytesCert2, // Cert
  67. (BYTE *)pabPVK2, cBytesPVK2, // PrivKey
  68. (BYTE *)abEncDecCertRoot, sizeof(abEncDecCertRoot), // PubKey
  69. spSecureClient);
  70. if(FAILED(hr)){
  71. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient DRMSC_AtomicConnectAndDisconnect failed " << hr);
  72. }
  73. else{
  74. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckIfSecureClient DRMSC_AtomicConnectAndDisconnect Succeeded");
  75. }
  76. return hr;
  77. #endif // BUILD_WITH_DRM
  78. }
  79. /////////////////////////////////////////////////////////////////////////////
  80. // CEnc2SinComp
  81. class ATL_NO_VTABLE __declspec(uuid("A0B9B497-AFBC-45ad-A8A6-9B077C40D4F2")) CEnc2SinComp :
  82. public CComObjectRootEx<CComSingleThreadModel>,
  83. public CComCoClass<CEnc2SinComp, &__uuidof(CEnc2SinComp)>,
  84. public IObjectWithSiteImplSec<CEnc2SinComp>,
  85. public IMSVidCompositionSegmentImpl<CEnc2SinComp>
  86. {
  87. private:
  88. DSFilterList m_pEncFilters;
  89. public:
  90. CEnc2SinComp() {}
  91. virtual ~CEnc2SinComp() {}
  92. REGISTER_NONAUTOMATION_OBJECT(IDS_PROJNAME,
  93. IDS_REG_ENC2SINCOMP_DESC,
  94. LIBID_MSVidCtlLib,
  95. __uuidof(CEnc2SinComp));
  96. DECLARE_PROTECT_FINAL_CONSTRUCT()
  97. BEGIN_COM_MAP(CEnc2SinComp)
  98. COM_INTERFACE_ENTRY(IMSVidCompositionSegment)
  99. COM_INTERFACE_ENTRY(IMSVidGraphSegment)
  100. COM_INTERFACE_ENTRY(IObjectWithSite)
  101. COM_INTERFACE_ENTRY(IPersist)
  102. END_COM_MAP()
  103. // IMSVidComposition
  104. public:
  105. // IMSVidGraphSegment
  106. // IMSVidCompositionSegment
  107. STDMETHOD(CheckEncFilters)(){
  108. int j = 0;
  109. for(DSFilterList::iterator i = m_pEncFilters.begin(); i != m_pEncFilters.end(); ++i){
  110. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckEncFilters checking filter " << j);
  111. CComQIPtr<IETFilterConfig> spETConfig;
  112. CComPtr<IUnknown> spUnkSecChan;
  113. spETConfig = (*i);
  114. if(!spETConfig){
  115. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckEncFilters filter " << j << " could not get et filter config interface");
  116. return E_NOINTERFACE;
  117. }
  118. HRESULT hr = spETConfig->GetSecureChannelObject(&spUnkSecChan);
  119. hr = CheckIfSecureClient(spUnkSecChan);
  120. if(FAILED(hr)){
  121. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckEncFilters filter " << j << " Failed");
  122. return E_FAIL;
  123. }
  124. ++j;
  125. }
  126. TRACELM(TRACE_ERROR, "CAnaSinComp::CheckEncFilters no failures");
  127. return NOERROR;
  128. }
  129. STDMETHOD(PreRun)(){
  130. return CheckEncFilters();
  131. }
  132. STDMETHOD(OnEventNotify)(long lEvent, LONG_PTR lParam1, LONG_PTR lParam2){
  133. if (lEvent == EC_STATE_CHANGE && lParam1 == State_Running) {
  134. TRACELM(TRACE_ERROR, "CAnaSinComp::OnEventNotify State_Running Event");
  135. HRESULT hr = CheckEncFilters();
  136. if(FAILED(hr)){
  137. TRACELM(TRACE_ERROR, "CAnaSinComp::OnEventNotify CheckEncFilters Failed");
  138. // need to throw a cert failure
  139. CComQIPtr<IMSVidCtl> pq_vidCtl;
  140. if(!m_pContainer){
  141. return S_OK;
  142. }
  143. else{
  144. hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast<void**>(&pq_vidCtl));
  145. if(SUCCEEDED(hr) && pq_vidCtl){
  146. pq_vidCtl->Stop();
  147. }
  148. CComQIPtr<IMSVidStreamBufferSinkEvent>pq_SBESink;
  149. VWOutputDevices pq_dev;
  150. hr = pq_vidCtl->get_OutputsActive(&pq_dev);
  151. if(FAILED(hr)){
  152. return hr;
  153. }
  154. VWOutputDevices::iterator i;
  155. for(i = pq_dev.begin(); i != pq_dev.end(); ++i){
  156. pq_SBESink = (*i).punkVal;
  157. if(pq_SBESink){
  158. break;
  159. }
  160. }
  161. if(i != pq_dev.end() && pq_SBESink){
  162. pq_SBESink->CertificateFailure();
  163. }
  164. }
  165. }
  166. }
  167. return E_NOTIMPL;
  168. }
  169. STDMETHOD(put_Container)(IMSVidGraphSegmentContainer *pCtl) {
  170. try {
  171. if (!pCtl) {
  172. m_pEncFilters.clear();
  173. return Unload();
  174. }
  175. if (m_pContainer) {
  176. if (!m_pContainer.IsEqualObject(VWSegmentContainer(pCtl))) {
  177. //undone: support moving to different graph
  178. return Error(IDS_OBJ_ALREADY_INIT, __uuidof(IMSVidGraphSegment), CO_E_ALREADYINITIALIZED);
  179. } else {
  180. return NO_ERROR;
  181. }
  182. }
  183. // DON'T addref the container. we're guaranteed nested lifetimes
  184. // and an addref creates circular refcounts so we never unload.
  185. m_pContainer.p = pCtl;
  186. m_pGraph = m_pContainer.GetGraph();
  187. } catch(...) {
  188. return E_UNEXPECTED;
  189. }
  190. return NOERROR;
  191. }
  192. STDMETHOD(Compose)(IMSVidGraphSegment * upstream, IMSVidGraphSegment * downstream)
  193. {
  194. if (m_fComposed) {
  195. return NOERROR;
  196. }
  197. ASSERT(m_pGraph);
  198. try {
  199. VIDPERF_FUNC;
  200. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose()");
  201. VWGraphSegment up(upstream);
  202. ASSERT(up.Graph() == m_pGraph);
  203. VWGraphSegment down(downstream);
  204. ASSERT(down.Graph() == m_pGraph);
  205. if (up.begin() == up.end()) {
  206. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't compose empty up segment");
  207. return E_INVALIDARG;
  208. }
  209. if (down.begin() == down.end()) {
  210. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't compose empty down segment");
  211. return E_INVALIDARG;
  212. }
  213. CMSVidStreamBufferSink* ds = (CMSVidStreamBufferSink*)downstream;
  214. DSFilter pSink(ds->m_Filters[0]);
  215. CComQIPtr<IMSVidEncoder> qiEnc(upstream);
  216. CEncoder* iEnc;
  217. iEnc = static_cast<CEncoder*>(qiEnc.p);
  218. DSPin pVidPin;
  219. DSPin pAudPin;
  220. DSPin genVidPin;
  221. DSPin genAudPin;
  222. CString csName;
  223. // render demux out to vr
  224. DSFilter pDeMux = iEnc->m_Filters[iEnc->m_iDemux];
  225. DSFilter::iterator iVidPin;
  226. DSFilter vr;
  227. DSMediaType mtVideo(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO, FORMAT_MPEG2Video);
  228. DSMediaType mtAudio(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Payload, FORMAT_WaveFormatEx);
  229. DSMediaType genericVideo(MEDIATYPE_Video);
  230. DSMediaType genericAudio(MEDIATYPE_Audio);
  231. for (iVidPin = pDeMux.begin(); iVidPin != pDeMux.end(); ++iVidPin) {
  232. DSPin::iterator j;
  233. for(j = (*iVidPin).begin(); j != (*iVidPin).end(); ++j){
  234. DSMediaType pinType(*j);
  235. if (pinType == mtVideo){
  236. CComPtr<IUnknown> spMpeg2Analyze(CLSID_Mpeg2VideoStreamAnalyzer, NULL, CLSCTX_INPROC_SERVER);
  237. if (!spMpeg2Analyze) {
  238. //TRACELSM(TRACE_ERROR, (dbgDump << "CMSVidStreamBufferSink::Build() can't load Time Shift Sink");
  239. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), E_UNEXPECTED);
  240. }
  241. spMpeg2Analyze->QueryInterface(IID_IBaseFilter, reinterpret_cast<void**>(&vr));
  242. if (!vr) {
  243. ASSERT(false);
  244. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_UNEXPECTED);
  245. }
  246. m_Filters.push_back(vr);
  247. csName = _T("Mpeg2 Analysis");
  248. m_pGraph.AddFilter(vr, csName);
  249. DSFilter::iterator a;
  250. for(a = vr.begin(); a != vr.end(); ++a){
  251. HRESULT hr = (*a).Connect(*iVidPin);
  252. if(FAILED(hr)){
  253. continue;
  254. }
  255. else{
  256. break;
  257. }
  258. }
  259. if(a == vr.end()){
  260. return E_FAIL;
  261. }
  262. for(a = vr.begin(); a != vr.end(); ++a){
  263. if((*a).GetDirection() == PINDIR_OUTPUT){
  264. pVidPin = (*a);
  265. }
  266. }
  267. if(!pVidPin){
  268. return E_FAIL;
  269. }
  270. }
  271. else if(pinType == mtAudio){
  272. pAudPin = (*iVidPin);
  273. }
  274. else if(pinType == genericVideo){
  275. genVidPin = (*iVidPin);
  276. }
  277. else if(pinType == genericAudio){
  278. genAudPin = (*iVidPin);
  279. }
  280. }
  281. if(!!pVidPin && !!pAudPin){
  282. break;
  283. }
  284. }
  285. if(!pVidPin){
  286. pVidPin = genVidPin;
  287. }
  288. if(!pAudPin){
  289. pAudPin = genAudPin;
  290. }
  291. if(!pVidPin){
  292. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't find video pin on demux");
  293. return E_UNEXPECTED;
  294. }
  295. if(!pAudPin){
  296. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't find audio pin on demux");
  297. return E_UNEXPECTED;
  298. }
  299. DSFilterList intermediates;
  300. HRESULT hr = S_OK;
  301. DSFilter::iterator fil;
  302. #if ENCRYPT_NEEDED
  303. CComBSTR encString(L"{C4C4C4F1-0049-4E2B-98FB-9537F6CE516D}");
  304. GUID2 encdecGuid (encString);
  305. // Create and add to graph the Video Tagger Filter
  306. CComPtr<IUnknown> spEncTagV(encdecGuid, NULL, CLSCTX_INPROC_SERVER);
  307. if (!spEncTagV) {
  308. TRACELM(TRACE_ERROR, "CMSVidStreamBufferSink::Build() can't load Tagger filter");
  309. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), VFW_E_CERTIFICATION_FAILURE);
  310. }
  311. DSFilter vrV(spEncTagV);
  312. if (!vrV) {
  313. ASSERT(false);
  314. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() on tagger interface");
  315. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_NOINTERFACE);
  316. }
  317. m_pEncFilters.push_back(vrV);
  318. m_Filters.push_back(vrV);
  319. csName = _T("Video Encoder Tagger Filter");
  320. m_pGraph.AddFilter(vrV, csName);
  321. // Connect video pin to Tagger
  322. hr = pVidPin.IntelligentConnect(vrV, intermediates);
  323. if(FAILED(hr)){
  324. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect audio pin to Audio Tagger");
  325. return E_UNEXPECTED;
  326. }
  327. // Connect Video to Sink
  328. DSFilter::iterator vP;
  329. hr = E_FAIL;
  330. for(vP = vrV.begin(); vP != vrV.end(); ++ vP){
  331. if((*vP).GetDirection() == PINDIR_OUTPUT){
  332. break;
  333. }
  334. }
  335. if(vP == vrV.end()){
  336. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() not video output pin");
  337. return E_UNEXPECTED;
  338. }
  339. for(fil = pSink.begin(); fil != pSink.end() && FAILED(hr); ++fil){
  340. hr = (*vP).Connect((*fil));
  341. }
  342. if(FAILED(hr)){
  343. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Video Tagger to Sink");
  344. return E_UNEXPECTED;
  345. }
  346. // Create and add to graph the Audio Tagger Filter
  347. CComPtr<IUnknown> spEncTagA(encdecGuid, NULL, CLSCTX_INPROC_SERVER);
  348. if (!spEncTagA) {
  349. TRACELM(TRACE_ERROR, "CMSVidStreamBufferSink::Build() can't load Tagger filter");
  350. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), VFW_E_CERTIFICATION_FAILURE);
  351. }
  352. DSFilter vrA(spEncTagA);
  353. if (!vrA) {
  354. ASSERT(false);
  355. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() can't create audio tagger filter");
  356. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_NOINTERFACE);
  357. }
  358. m_pEncFilters.push_back(vrV);
  359. m_Filters.push_back(vrA);
  360. csName = _T("Audio Encoder Tagger Filter");
  361. m_pGraph.AddFilter(vrA, csName);
  362. // Connect audio pin to the Tagger
  363. hr = pAudPin.IntelligentConnect(vrA, intermediates);
  364. if(FAILED(hr)){
  365. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect audio pin to Audio Tagger");
  366. return E_UNEXPECTED;
  367. }
  368. // Connect Tagger to Sink
  369. hr = E_FAIL;
  370. for(vP = vrA.begin(); vP != vrA.end(); ++ vP){
  371. if((*vP).GetDirection() == PINDIR_OUTPUT){
  372. break;
  373. }
  374. }
  375. if(vP == vrA.end()){
  376. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() no audio tagger pin");
  377. return E_UNEXPECTED;
  378. }
  379. for(fil = pSink.begin(); fil != pSink.end() && FAILED(hr); ++fil){
  380. hr = (*vP).Connect((*fil));
  381. }
  382. if(FAILED(hr)){
  383. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Audio Tagger to Sink");
  384. return E_UNEXPECTED;
  385. }
  386. #else
  387. // Connect the Video Pin to the sink
  388. DSFilter::iterator vidAnaPin;
  389. hr = E_FAIL;
  390. hr = E_FAIL;
  391. for(fil = pSink.begin(); fil != pSink.end() && FAILED(hr); ++fil){
  392. if((*fil).GetDirection() == PINDIR_INPUT && !(*fil).IsConnected()){
  393. hr = pVidPin.Connect((*fil));
  394. }
  395. }
  396. if(FAILED(hr)){
  397. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Video Tagger to Sink");
  398. ASSERT((L"Can't Connect vid to sink", FALSE));
  399. return E_UNEXPECTED;
  400. }
  401. // Connect the Audio Pin to the Sink
  402. hr = E_FAIL;
  403. for(fil = pSink.begin(); fil != pSink.end() && FAILED(hr); ++fil){
  404. if((*fil).GetDirection() == PINDIR_INPUT && !(*fil).IsConnected()){
  405. hr = pAudPin.Connect((*fil));
  406. }
  407. }
  408. if(FAILED(hr)){
  409. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Audio Tagger to Sink");
  410. ASSERT((L"Can't Connect aud to sink", FALSE));
  411. return E_UNEXPECTED;
  412. }
  413. #endif
  414. /*
  415. hr = m_pGraph.Connect(vrA, pSink, intermediates);
  416. if(FAILED(hr)){
  417. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() can't connect Audio Tagger to Sink");
  418. return E_UNEXPECTED;
  419. }
  420. */
  421. ASSERT(intermediates.begin() == intermediates.end());
  422. m_Filters.insert(m_Filters.end(), intermediates.begin(), intermediates.end());
  423. TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() SUCCEEDED");
  424. m_fComposed = true;
  425. return NOERROR;
  426. } catch (ComException &e) {
  427. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() com exception");
  428. return e;
  429. } catch (...) {
  430. TRACELM(TRACE_ERROR, "CAnaSinComp::Compose() ... exception");
  431. return E_UNEXPECTED;
  432. }
  433. }
  434. };
  435. #endif // Enc2Sin_H
  436. // end of file - Enc2Sin.h