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.

434 lines
15 KiB

  1. //==========================================================================;
  2. // MSVidStreamBufferSink.h : Declaration of the CMSVidStreamBufferSink
  3. // copyright (c) Microsoft Corp. 1998-1999.
  4. //==========================================================================;
  5. //==========================================================================;
  6. /* MSVidStreamBufferSink is the sink (destination, output) segement for the MSVidCtl
  7. implementation of the SBE/StreamBuffer (StreamBuffer/digital video recording).
  8. Other than the normal methods of a output segment (see msvidclt.idl and
  9. segment.idl) the sink also has:
  10. get/put_SinkName to name this instance of the SBE/StreamBuffer filter, so it can
  11. be easily refered to in another
  12. In the MSVidCtl solution for SBE/StreamBuffer there are three segments that had to be added
  13. to MSVidCtl. The sink, source and StreamBufferSource segements.
  14. The sink is the segement that gets connected to the input that is being StreamBuffered.
  15. The source is the segment that acts as the input for playback of the StreamBuffered content.
  16. The StreamBufferSource segment exists to play back the recorded files that are stored seperatly
  17. from the SBE/StreamBuffer buffers. This is a seperate segment since there is no support, currently,
  18. for wm* (v or a) or asf content in MSVidCtl and even if there was the SBE/StreamBuffer content is in a
  19. form of asf that is not supported by the windows media codec anyway.
  20. */
  21. //==========================================================================;
  22. #ifndef __MSVidSTREAMBUFFERSINK_H_
  23. #define __MSVidSTREAMBUFFERSINK_H_
  24. #pragma once
  25. #include <algorithm>
  26. #include <map>
  27. #include <functional>
  28. #include <iostream>
  29. #include <string>
  30. #include <evcode.h>
  31. #include <uuids.h>
  32. #include <amvideo.h>
  33. #include <strmif.h>
  34. #include <dvdmedia.h>
  35. #include <objectwithsiteimplsec.h>
  36. #include <bcasteventimpl.h>
  37. #include "sbesinkcp.h"
  38. #include "msvidctl.h"
  39. #include "vidrect.h"
  40. #include "vrsegimpl.h"
  41. #include "devimpl.h"
  42. #include "devsegimpl.h"
  43. #include "seg.h"
  44. #include "msvidsberecorder.h"
  45. #include "resource.h" // main symbols
  46. #ifdef BUILD_WITH_DRM
  47. #include "DRMSecure.h"
  48. #include "DRMRootCert.h"
  49. #ifdef USE_TEST_DRM_CERT // don�t use true (7002) CERT
  50. #include "Keys_7001.h" // until final release
  51. static const BYTE* pabCert2 = abCert7001;
  52. static const int cBytesCert2 = sizeof(abCert7001);
  53. static const BYTE* pabPVK2 = abPVK7001;
  54. static const int cBytesPVK2 = sizeof(abPVK7001);
  55. #else
  56. #include "Keys_7002.h" // used in release code�
  57. static const BYTE* pabCert2 = abCert7002;
  58. static const int cBytesCert2 = sizeof(abCert7002);
  59. static const BYTE* pabPVK2 = abPVK7002;
  60. static const int cBytesPVK2 = sizeof(abPVK7002);
  61. #endif
  62. #endif
  63. typedef CComQIPtr<IStreamBufferSink> PQTSSink;
  64. typedef CComQIPtr<IMSVidStreamBufferRecordingControl> pqRecorder;
  65. /////////////////////////////////////////////////////////////////////////////
  66. // CMSVidStreamBufferSink
  67. class ATL_NO_VTABLE __declspec(uuid("9E77AAC4-35E5-42a1-BDC2-8F3FF399847C")) CMSVidStreamBufferSink :
  68. public CComObjectRootEx<CComSingleThreadModel>,
  69. public CComCoClass<CMSVidStreamBufferSink, &CLSID_MSVidStreamBufferSink>,
  70. public IObjectWithSiteImplSec<CMSVidStreamBufferSink>,
  71. public ISupportErrorInfo,
  72. public IBroadcastEventImpl<CMSVidStreamBufferSink>,
  73. public CProxy_StreamBufferSinkEvent<CMSVidStreamBufferSink>,
  74. public IMSVidGraphSegmentImpl<CMSVidStreamBufferSink, MSVidSEG_DEST, &GUID_NULL>,
  75. public IConnectionPointContainerImpl<CMSVidStreamBufferSink>,
  76. public IMSVidDeviceImpl<CMSVidStreamBufferSink, &LIBID_MSVidCtlLib, &GUID_NULL, IMSVidStreamBufferSink>
  77. {
  78. public:
  79. CMSVidStreamBufferSink() :
  80. m_StreamBuffersink(-1),
  81. m_bNameSet(FALSE)
  82. {
  83. }
  84. virtual ~CMSVidStreamBufferSink() {
  85. Expunge();
  86. }
  87. REGISTER_AUTOMATION_OBJECT(IDS_PROJNAME,
  88. IDS_REG_MSVIDSTREAMBUFFERSINK_PROGID,
  89. IDS_REG_MSVIDSTREAMBUFFERSINK_DESC,
  90. LIBID_MSVidCtlLib,
  91. __uuidof(CMSVidStreamBufferSink));
  92. DECLARE_PROTECT_FINAL_CONSTRUCT()
  93. BEGIN_COM_MAP(CMSVidStreamBufferSink)
  94. COM_INTERFACE_ENTRY(IMSVidGraphSegment)
  95. COM_INTERFACE_ENTRY(IMSVidStreamBufferSink)
  96. COM_INTERFACE_ENTRY(IMSVidOutputDevice)
  97. COM_INTERFACE_ENTRY(IMSVidDevice)
  98. COM_INTERFACE_ENTRY(IDispatch)
  99. COM_INTERFACE_ENTRY(IBroadcastEvent)
  100. COM_INTERFACE_ENTRY(IObjectWithSite)
  101. COM_INTERFACE_ENTRY(IConnectionPointContainer)
  102. COM_INTERFACE_ENTRY(ISupportErrorInfo)
  103. COM_INTERFACE_ENTRY(IPersist)
  104. END_COM_MAP()
  105. BEGIN_CATEGORY_MAP(CMSVidStreamBufferSink)
  106. IMPLEMENTED_CATEGORY(CATID_SafeForScripting)
  107. IMPLEMENTED_CATEGORY(CATID_SafeForInitializing)
  108. IMPLEMENTED_CATEGORY(CATID_PersistsToPropertyBag)
  109. END_CATEGORY_MAP()
  110. BEGIN_CONNECTION_POINT_MAP(CMSVidStreamBufferSink)
  111. CONNECTION_POINT_ENTRY(IID_IMSVidStreamBufferSinkEvent)
  112. END_CONNECTION_POINT_MAP()
  113. // ISupportsErrorInfo
  114. STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
  115. protected:
  116. PQTSSink m_ptsSink;
  117. int m_StreamBuffersink;
  118. CComBSTR m_SinkName;
  119. public:
  120. CComBSTR __declspec(property(get=GetName)) m_Name;
  121. CComBSTR GetName(void) {
  122. CString csName;
  123. if(m_StreamBuffersink != -1){
  124. csName = (m_Filters[m_StreamBuffersink]).GetName();
  125. }
  126. if (csName.IsEmpty()) {
  127. csName = _T("Time Shift Sink");
  128. }
  129. csName += _T(" Segment");
  130. return CComBSTR(csName);
  131. }
  132. STDMETHOD(get_SinkName)(BSTR *pName);
  133. STDMETHOD(put_SinkName)(BSTR Name);
  134. STDMETHOD(get_ContentRecorder)(BSTR pszFilename, IMSVidStreamBufferRecordingControl ** ppRecording);
  135. STDMETHOD(get_ReferenceRecorder)(BSTR pszFilename, IMSVidStreamBufferRecordingControl ** ppRecording);
  136. STDMETHOD(get_SBESink)(IUnknown ** sbeConfig);
  137. STDMETHOD(Unload)(void) {
  138. // TODO fix this
  139. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::Unload()");
  140. BroadcastUnadvise();
  141. IMSVidGraphSegmentImpl<CMSVidStreamBufferSink, MSVidSEG_DEST, &GUID_NULL>::Unload();
  142. m_StreamBuffersink = -1;
  143. m_ptsSink = reinterpret_cast<IUnknown*>(NULL);
  144. m_RecordObj.Release();
  145. _ASSERT(!m_RecordObj);
  146. m_bNameSet = FALSE;
  147. return NO_ERROR;
  148. }
  149. STDMETHOD(Decompose)(void) {
  150. // TODO fix this
  151. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::Decompose()");
  152. IMSVidGraphSegmentImpl<CMSVidStreamBufferSink, MSVidSEG_DEST, &GUID_NULL>::Decompose();
  153. Unload();
  154. return NO_ERROR;
  155. }
  156. STDMETHOD(Build)() {
  157. try{
  158. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::Build()");
  159. if (!m_fInit || !m_pGraph) {
  160. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSink), CO_E_NOTINITIALIZED);
  161. }
  162. CString csName;
  163. PQTSSink pTSSink(CLSID_StreamBufferSink, NULL, CLSCTX_INPROC_SERVER);
  164. if (!pTSSink) {
  165. //TRACELSM(TRACE_ERROR, (dbgDump << "CMSVidStreamBufferSink::Build() can't load Time Shift Sink");
  166. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), E_UNEXPECTED);
  167. }
  168. DSFilter vr(pTSSink);
  169. if (!vr) {
  170. ASSERT(false);
  171. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_UNEXPECTED);
  172. }
  173. if (m_StreamBuffersink == -1) {
  174. m_Filters.push_back(vr);
  175. csName = _T("Time Shift Sink");
  176. m_pGraph.AddFilter(vr, csName);
  177. }
  178. m_ptsSink = pTSSink;
  179. if(!m_ptsSink){
  180. return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_UNEXPECTED);
  181. }
  182. m_StreamBuffersink = 0;
  183. ASSERT(m_StreamBuffersink == 0);
  184. m_bNameSet = FALSE;
  185. return NOERROR;
  186. } catch (ComException &e) {
  187. return e;
  188. } catch (...) {
  189. return E_UNEXPECTED;
  190. }
  191. }
  192. STDMETHOD(get_Segment)(IMSVidGraphSegment * * pIMSVidGraphSegment){
  193. if (!m_fInit) {
  194. return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSink), CO_E_NOTINITIALIZED);
  195. }
  196. try {
  197. if (pIMSVidGraphSegment == NULL) {
  198. return E_POINTER;
  199. }
  200. *pIMSVidGraphSegment = this;
  201. AddRef();
  202. return NOERROR;
  203. } catch(...) {
  204. return E_POINTER;
  205. }
  206. }
  207. // IGraphSegment
  208. STDMETHOD(put_Container)(IMSVidGraphSegmentContainer *pCtl) {
  209. try {
  210. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::put_Container()");
  211. HRESULT hr = IMSVidGraphSegmentImpl<CMSVidStreamBufferSink, MSVidSEG_DEST, &GUID_NULL>::put_Container(pCtl);
  212. if (FAILED(hr)) {
  213. return hr;
  214. }
  215. if (!pCtl) {
  216. #ifdef BUILD_WITH_DRM
  217. CComQIPtr<IServiceProvider> spServiceProvider(m_pGraph);
  218. if (spServiceProvider != NULL) {
  219. CComPtr<IDRMSecureChannel> spSecureService;
  220. hr = spServiceProvider->QueryService(SID_DRMSecureServiceChannel,
  221. IID_IDRMSecureChannel,
  222. reinterpret_cast<LPVOID*>(&spSecureService));
  223. if(S_OK == hr){
  224. // Found existing Secure Server
  225. CComQIPtr<IRegisterServiceProvider> spRegServiceProvider(m_pGraph);
  226. if(spRegServiceProvider == NULL){
  227. // no service provider interface on the graph - fatal!
  228. hr = E_NOINTERFACE;
  229. }
  230. if(SUCCEEDED(hr)){
  231. hr = spRegServiceProvider->RegisterService(SID_DRMSecureServiceChannel, NULL);
  232. }
  233. }
  234. _ASSERT(SUCCEEDED(hr));
  235. }
  236. #endif
  237. }
  238. hr = BroadcastAdvise();
  239. if (FAILED(hr)) {
  240. TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::put_Container() can't advise for broadcast events");
  241. return E_UNEXPECTED;
  242. }
  243. #ifdef BUILD_WITH_DRM
  244. #ifdef USE_TEST_DRM_CERT
  245. {
  246. DWORD dwDisableDRMCheck = 0;
  247. CRegKey c;
  248. CString keyname(_T("SOFTWARE\\Debug\\MSVidCtl"));
  249. DWORD rc = c.Open(HKEY_LOCAL_MACHINE, keyname, KEY_READ);
  250. if (rc == ERROR_SUCCESS) {
  251. rc = c.QueryValue(dwDisableDRMCheck, _T("DisableDRMCheck"));
  252. if (rc != ERROR_SUCCESS) {
  253. dwDisableDRMCheck = 0;
  254. }
  255. }
  256. if(dwDisableDRMCheck == 1){
  257. return S_OK;
  258. }
  259. }
  260. #endif
  261. CComQIPtr<IServiceProvider> spServiceProvider(m_pGraph);
  262. if (spServiceProvider == NULL) {
  263. return E_NOINTERFACE;
  264. }
  265. CComPtr<IDRMSecureChannel> spSecureService;
  266. hr = spServiceProvider->QueryService(SID_DRMSecureServiceChannel,
  267. IID_IDRMSecureChannel,
  268. reinterpret_cast<LPVOID*>(&spSecureService));
  269. if(S_OK == hr){
  270. // Found existing Secure Server
  271. return S_OK;
  272. }
  273. else{
  274. // if it's not there or failed for ANY reason
  275. // lets create it and register it
  276. CComQIPtr<IRegisterServiceProvider> spRegServiceProvider(m_pGraph);
  277. if(spRegServiceProvider == NULL){
  278. // no service provider interface on the graph - fatal!
  279. hr = E_NOINTERFACE;
  280. }
  281. else{
  282. // Create the Client
  283. CComPtr<IDRMSecureChannel> spSecureServiceServer;
  284. hr = DRMCreateSecureChannel( &spSecureServiceServer);
  285. if(spSecureServiceServer == NULL){
  286. hr = E_OUTOFMEMORY;
  287. }
  288. if(FAILED(hr)){
  289. return hr;
  290. }
  291. // Init keys
  292. hr = spSecureServiceServer->DRMSC_SetCertificate((BYTE *)pabCert2, cBytesCert2);
  293. if(FAILED(hr)){
  294. return hr;
  295. }
  296. hr = spSecureServiceServer->DRMSC_SetPrivateKeyBlob((BYTE *)pabPVK2, cBytesPVK2);
  297. if(FAILED(hr)){
  298. return hr;
  299. }
  300. hr = spSecureServiceServer->DRMSC_AddVerificationPubKey((BYTE *)abEncDecCertRoot, sizeof(abEncDecCertRoot) );
  301. if(FAILED(hr)){
  302. return hr;
  303. }
  304. // Register It
  305. // note RegisterService does not addref pUnkSeekProvider
  306. hr = spRegServiceProvider->RegisterService(SID_DRMSecureServiceChannel, spSecureServiceServer);
  307. }
  308. }
  309. #endif // BUILD_WITH_DRM
  310. return NOERROR;
  311. } catch(...) {
  312. return E_UNEXPECTED;
  313. }
  314. }
  315. STDMETHODIMP CMSVidStreamBufferSink::PreRun(){
  316. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::PreRun()");
  317. return NameSetLock();
  318. }
  319. STDMETHODIMP CMSVidStreamBufferSink::NameSetLock(){
  320. try {
  321. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock()");
  322. HRESULT hr;
  323. if(!m_bNameSet){
  324. if(!m_SinkName){
  325. return S_FALSE;
  326. }
  327. else{
  328. hr = m_ptsSink->IsProfileLocked();
  329. if(FAILED(hr)){
  330. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() IsProfileLocked failed");
  331. return hr;
  332. }
  333. else if(hr == S_OK){
  334. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() Profile is locked");
  335. return E_FAIL;
  336. }
  337. hr = m_ptsSink->LockProfile(m_SinkName);
  338. if(FAILED(hr)){
  339. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() LockedProfile failed");
  340. return hr;
  341. }
  342. }
  343. m_bNameSet = TRUE;
  344. }
  345. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() Succeeded");
  346. return S_OK;
  347. } catch (ComException &e) {
  348. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() Exception");
  349. return e;
  350. } catch (...) {
  351. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() Possible AV");
  352. return E_UNEXPECTED;
  353. }
  354. }
  355. STDMETHODIMP CMSVidStreamBufferSink::PostStop() {
  356. try {
  357. m_bNameSet = FALSE;
  358. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::PostStop()");
  359. return S_OK;
  360. } catch (...) {
  361. ASSERT(FALSE);
  362. return E_UNEXPECTED;
  363. }
  364. }
  365. // IMSVidDevice
  366. STDMETHOD(get_Name)(BSTR * Name) {
  367. if (!m_fInit) {
  368. return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSink), CO_E_NOTINITIALIZED);
  369. }
  370. if (Name == NULL)
  371. return E_POINTER;
  372. try {
  373. *Name = m_Name.Copy();
  374. } catch(...) {
  375. return E_POINTER;
  376. }
  377. return NOERROR;
  378. }
  379. STDMETHOD(get_Status)(LONG * Status) {
  380. if (!m_fInit) {
  381. return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSink), CO_E_NOTINITIALIZED);
  382. }
  383. if (Status == NULL)
  384. return E_POINTER;
  385. return E_NOTIMPL;
  386. }
  387. STDMETHOD(OnEventNotify)(LONG lEventCode, LONG_PTR lEventParm1, LONG_PTR lEventParm2){
  388. if(lEventCode == STREAMBUFFER_EC_WRITE_FAILURE){
  389. TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::OnEventNotify STREAMBUFFER_EC_WRITE_FAILURE");
  390. Fire_WriteFailure();
  391. return NO_ERROR;
  392. }
  393. return E_NOTIMPL;
  394. }
  395. // IBroadcastEvent
  396. STDMETHOD(Fire)(GUID gEventID);
  397. private:
  398. void Expunge();
  399. pqRecorder m_RecordObj;
  400. BOOL m_bNameSet;
  401. };
  402. #endif //__MSVIDSTREAMBUFFERSINK_H_