435 lines
15 KiB
C++
435 lines
15 KiB
C++
//==========================================================================;
|
||
// MSVidStreamBufferSink.h : Declaration of the CMSVidStreamBufferSink
|
||
// copyright (c) Microsoft Corp. 1998-1999.
|
||
//==========================================================================;
|
||
|
||
//==========================================================================;
|
||
/* MSVidStreamBufferSink is the sink (destination, output) segement for the MSVidCtl
|
||
implementation of the SBE/StreamBuffer (StreamBuffer/digital video recording).
|
||
Other than the normal methods of a output segment (see msvidclt.idl and
|
||
segment.idl) the sink also has:
|
||
get/put_SinkName to name this instance of the SBE/StreamBuffer filter, so it can
|
||
be easily refered to in another
|
||
In the MSVidCtl solution for SBE/StreamBuffer there are three segments that had to be added
|
||
to MSVidCtl. The sink, source and StreamBufferSource segements.
|
||
The sink is the segement that gets connected to the input that is being StreamBuffered.
|
||
The source is the segment that acts as the input for playback of the StreamBuffered content.
|
||
The StreamBufferSource segment exists to play back the recorded files that are stored seperatly
|
||
from the SBE/StreamBuffer buffers. This is a seperate segment since there is no support, currently,
|
||
for wm* (v or a) or asf content in MSVidCtl and even if there was the SBE/StreamBuffer content is in a
|
||
form of asf that is not supported by the windows media codec anyway.
|
||
|
||
*/
|
||
//==========================================================================;
|
||
|
||
#ifndef __MSVidSTREAMBUFFERSINK_H_
|
||
#define __MSVidSTREAMBUFFERSINK_H_
|
||
|
||
#pragma once
|
||
|
||
#include <algorithm>
|
||
#include <map>
|
||
#include <functional>
|
||
#include <iostream>
|
||
#include <string>
|
||
#include <evcode.h>
|
||
#include <uuids.h>
|
||
#include <amvideo.h>
|
||
#include <strmif.h>
|
||
#include <dvdmedia.h>
|
||
#include <objectwithsiteimplsec.h>
|
||
#include <bcasteventimpl.h>
|
||
#include "sbesinkcp.h"
|
||
#include "msvidctl.h"
|
||
#include "vidrect.h"
|
||
#include "vrsegimpl.h"
|
||
#include "devimpl.h"
|
||
#include "devsegimpl.h"
|
||
#include "seg.h"
|
||
#include "msvidsberecorder.h"
|
||
#include "resource.h" // main symbols
|
||
#ifdef BUILD_WITH_DRM
|
||
#include "DRMSecure.h"
|
||
#include "DRMRootCert.h"
|
||
|
||
#ifdef USE_TEST_DRM_CERT // don<6F>t use true (7002) CERT
|
||
#include "Keys_7001.h" // until final release
|
||
static const BYTE* pabCert2 = abCert7001;
|
||
static const int cBytesCert2 = sizeof(abCert7001);
|
||
static const BYTE* pabPVK2 = abPVK7001;
|
||
static const int cBytesPVK2 = sizeof(abPVK7001);
|
||
#else
|
||
#include "Keys_7002.h" // used in release code<64>
|
||
static const BYTE* pabCert2 = abCert7002;
|
||
static const int cBytesCert2 = sizeof(abCert7002);
|
||
static const BYTE* pabPVK2 = abPVK7002;
|
||
static const int cBytesPVK2 = sizeof(abPVK7002);
|
||
#endif
|
||
#endif
|
||
typedef CComQIPtr<IStreamBufferSink> PQTSSink;
|
||
typedef CComQIPtr<IMSVidStreamBufferRecordingControl> pqRecorder;
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// CMSVidStreamBufferSink
|
||
class ATL_NO_VTABLE __declspec(uuid("9E77AAC4-35E5-42a1-BDC2-8F3FF399847C")) CMSVidStreamBufferSink :
|
||
public CComObjectRootEx<CComSingleThreadModel>,
|
||
public CComCoClass<CMSVidStreamBufferSink, &CLSID_MSVidStreamBufferSink>,
|
||
public IObjectWithSiteImplSec<CMSVidStreamBufferSink>,
|
||
public ISupportErrorInfo,
|
||
public IBroadcastEventImpl<CMSVidStreamBufferSink>,
|
||
public CProxy_StreamBufferSinkEvent<CMSVidStreamBufferSink>,
|
||
public IMSVidGraphSegmentImpl<CMSVidStreamBufferSink, MSVidSEG_DEST, &GUID_NULL>,
|
||
public IConnectionPointContainerImpl<CMSVidStreamBufferSink>,
|
||
public IMSVidDeviceImpl<CMSVidStreamBufferSink, &LIBID_MSVidCtlLib, &GUID_NULL, IMSVidStreamBufferSink>
|
||
{
|
||
public:
|
||
CMSVidStreamBufferSink() :
|
||
m_StreamBuffersink(-1),
|
||
m_bNameSet(FALSE)
|
||
{
|
||
|
||
}
|
||
virtual ~CMSVidStreamBufferSink() {
|
||
Expunge();
|
||
}
|
||
|
||
REGISTER_AUTOMATION_OBJECT(IDS_PROJNAME,
|
||
IDS_REG_MSVIDSTREAMBUFFERSINK_PROGID,
|
||
IDS_REG_MSVIDSTREAMBUFFERSINK_DESC,
|
||
LIBID_MSVidCtlLib,
|
||
__uuidof(CMSVidStreamBufferSink));
|
||
|
||
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
||
|
||
BEGIN_COM_MAP(CMSVidStreamBufferSink)
|
||
COM_INTERFACE_ENTRY(IMSVidGraphSegment)
|
||
COM_INTERFACE_ENTRY(IMSVidStreamBufferSink)
|
||
COM_INTERFACE_ENTRY(IMSVidOutputDevice)
|
||
COM_INTERFACE_ENTRY(IMSVidDevice)
|
||
COM_INTERFACE_ENTRY(IDispatch)
|
||
COM_INTERFACE_ENTRY(IBroadcastEvent)
|
||
COM_INTERFACE_ENTRY(IObjectWithSite)
|
||
COM_INTERFACE_ENTRY(IConnectionPointContainer)
|
||
COM_INTERFACE_ENTRY(ISupportErrorInfo)
|
||
COM_INTERFACE_ENTRY(IPersist)
|
||
END_COM_MAP()
|
||
|
||
BEGIN_CATEGORY_MAP(CMSVidStreamBufferSink)
|
||
IMPLEMENTED_CATEGORY(CATID_SafeForScripting)
|
||
IMPLEMENTED_CATEGORY(CATID_SafeForInitializing)
|
||
IMPLEMENTED_CATEGORY(CATID_PersistsToPropertyBag)
|
||
END_CATEGORY_MAP()
|
||
|
||
BEGIN_CONNECTION_POINT_MAP(CMSVidStreamBufferSink)
|
||
CONNECTION_POINT_ENTRY(IID_IMSVidStreamBufferSinkEvent)
|
||
END_CONNECTION_POINT_MAP()
|
||
// ISupportsErrorInfo
|
||
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
|
||
protected:
|
||
PQTSSink m_ptsSink;
|
||
int m_StreamBuffersink;
|
||
CComBSTR m_SinkName;
|
||
public:
|
||
CComBSTR __declspec(property(get=GetName)) m_Name;
|
||
CComBSTR GetName(void) {
|
||
CString csName;
|
||
if(m_StreamBuffersink != -1){
|
||
csName = (m_Filters[m_StreamBuffersink]).GetName();
|
||
}
|
||
if (csName.IsEmpty()) {
|
||
csName = _T("Time Shift Sink");
|
||
}
|
||
csName += _T(" Segment");
|
||
return CComBSTR(csName);
|
||
}
|
||
STDMETHOD(get_SinkName)(BSTR *pName);
|
||
STDMETHOD(put_SinkName)(BSTR Name);
|
||
STDMETHOD(get_ContentRecorder)(BSTR pszFilename, IMSVidStreamBufferRecordingControl ** ppRecording);
|
||
STDMETHOD(get_ReferenceRecorder)(BSTR pszFilename, IMSVidStreamBufferRecordingControl ** ppRecording);
|
||
STDMETHOD(get_SBESink)(IUnknown ** sbeConfig);
|
||
STDMETHOD(Unload)(void) {
|
||
// TODO fix this
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::Unload()");
|
||
BroadcastUnadvise();
|
||
|
||
IMSVidGraphSegmentImpl<CMSVidStreamBufferSink, MSVidSEG_DEST, &GUID_NULL>::Unload();
|
||
m_StreamBuffersink = -1;
|
||
m_ptsSink = reinterpret_cast<IUnknown*>(NULL);
|
||
m_RecordObj.Release();
|
||
_ASSERT(!m_RecordObj);
|
||
m_bNameSet = FALSE;
|
||
return NO_ERROR;
|
||
}
|
||
STDMETHOD(Decompose)(void) {
|
||
// TODO fix this
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::Decompose()");
|
||
IMSVidGraphSegmentImpl<CMSVidStreamBufferSink, MSVidSEG_DEST, &GUID_NULL>::Decompose();
|
||
Unload();
|
||
return NO_ERROR;
|
||
}
|
||
|
||
STDMETHOD(Build)() {
|
||
try{
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::Build()");
|
||
if (!m_fInit || !m_pGraph) {
|
||
return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSink), CO_E_NOTINITIALIZED);
|
||
}
|
||
CString csName;
|
||
PQTSSink pTSSink(CLSID_StreamBufferSink, NULL, CLSCTX_INPROC_SERVER);
|
||
if (!pTSSink) {
|
||
//TRACELSM(TRACE_ERROR, (dbgDump << "CMSVidStreamBufferSink::Build() can't load Time Shift Sink");
|
||
return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), E_UNEXPECTED);
|
||
}
|
||
DSFilter vr(pTSSink);
|
||
if (!vr) {
|
||
ASSERT(false);
|
||
return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_UNEXPECTED);
|
||
}
|
||
if (m_StreamBuffersink == -1) {
|
||
m_Filters.push_back(vr);
|
||
csName = _T("Time Shift Sink");
|
||
m_pGraph.AddFilter(vr, csName);
|
||
}
|
||
m_ptsSink = pTSSink;
|
||
if(!m_ptsSink){
|
||
return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IBaseFilter), E_UNEXPECTED);
|
||
}
|
||
m_StreamBuffersink = 0;
|
||
ASSERT(m_StreamBuffersink == 0);
|
||
m_bNameSet = FALSE;
|
||
return NOERROR;
|
||
} catch (ComException &e) {
|
||
return e;
|
||
} catch (...) {
|
||
return E_UNEXPECTED;
|
||
}
|
||
}
|
||
STDMETHOD(get_Segment)(IMSVidGraphSegment * * pIMSVidGraphSegment){
|
||
if (!m_fInit) {
|
||
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSink), CO_E_NOTINITIALIZED);
|
||
}
|
||
try {
|
||
if (pIMSVidGraphSegment == NULL) {
|
||
return E_POINTER;
|
||
}
|
||
*pIMSVidGraphSegment = this;
|
||
AddRef();
|
||
return NOERROR;
|
||
} catch(...) {
|
||
return E_POINTER;
|
||
}
|
||
}
|
||
// IGraphSegment
|
||
STDMETHOD(put_Container)(IMSVidGraphSegmentContainer *pCtl) {
|
||
try {
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::put_Container()");
|
||
HRESULT hr = IMSVidGraphSegmentImpl<CMSVidStreamBufferSink, MSVidSEG_DEST, &GUID_NULL>::put_Container(pCtl);
|
||
if (FAILED(hr)) {
|
||
return hr;
|
||
}
|
||
|
||
if (!pCtl) {
|
||
#ifdef BUILD_WITH_DRM
|
||
CComQIPtr<IServiceProvider> spServiceProvider(m_pGraph);
|
||
if (spServiceProvider != NULL) {
|
||
CComPtr<IDRMSecureChannel> spSecureService;
|
||
hr = spServiceProvider->QueryService(SID_DRMSecureServiceChannel,
|
||
IID_IDRMSecureChannel,
|
||
reinterpret_cast<LPVOID*>(&spSecureService));
|
||
if(S_OK == hr){
|
||
// Found existing Secure Server
|
||
CComQIPtr<IRegisterServiceProvider> spRegServiceProvider(m_pGraph);
|
||
if(spRegServiceProvider == NULL){
|
||
// no service provider interface on the graph - fatal!
|
||
hr = E_NOINTERFACE;
|
||
}
|
||
|
||
if(SUCCEEDED(hr)){
|
||
hr = spRegServiceProvider->RegisterService(SID_DRMSecureServiceChannel, NULL);
|
||
}
|
||
}
|
||
_ASSERT(SUCCEEDED(hr));
|
||
}
|
||
#endif
|
||
}
|
||
|
||
hr = BroadcastAdvise();
|
||
if (FAILED(hr)) {
|
||
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::put_Container() can't advise for broadcast events");
|
||
return E_UNEXPECTED;
|
||
}
|
||
#ifdef BUILD_WITH_DRM
|
||
#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
|
||
CComQIPtr<IServiceProvider> spServiceProvider(m_pGraph);
|
||
if (spServiceProvider == NULL) {
|
||
return E_NOINTERFACE;
|
||
}
|
||
CComPtr<IDRMSecureChannel> spSecureService;
|
||
hr = spServiceProvider->QueryService(SID_DRMSecureServiceChannel,
|
||
IID_IDRMSecureChannel,
|
||
reinterpret_cast<LPVOID*>(&spSecureService));
|
||
if(S_OK == hr){
|
||
// Found existing Secure Server
|
||
return S_OK;
|
||
}
|
||
else{
|
||
// if it's not there or failed for ANY reason
|
||
// lets create it and register it
|
||
CComQIPtr<IRegisterServiceProvider> spRegServiceProvider(m_pGraph);
|
||
if(spRegServiceProvider == NULL){
|
||
// no service provider interface on the graph - fatal!
|
||
hr = E_NOINTERFACE;
|
||
}
|
||
else{
|
||
// Create the Client
|
||
CComPtr<IDRMSecureChannel> spSecureServiceServer;
|
||
hr = DRMCreateSecureChannel( &spSecureServiceServer);
|
||
if(spSecureServiceServer == NULL){
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
if(FAILED(hr)){
|
||
return hr;
|
||
}
|
||
|
||
// Init keys
|
||
hr = spSecureServiceServer->DRMSC_SetCertificate((BYTE *)pabCert2, cBytesCert2);
|
||
if(FAILED(hr)){
|
||
return hr;
|
||
}
|
||
|
||
hr = spSecureServiceServer->DRMSC_SetPrivateKeyBlob((BYTE *)pabPVK2, cBytesPVK2);
|
||
if(FAILED(hr)){
|
||
return hr;
|
||
}
|
||
|
||
hr = spSecureServiceServer->DRMSC_AddVerificationPubKey((BYTE *)abEncDecCertRoot, sizeof(abEncDecCertRoot) );
|
||
if(FAILED(hr)){
|
||
return hr;
|
||
}
|
||
|
||
// Register It
|
||
// note RegisterService does not addref pUnkSeekProvider
|
||
hr = spRegServiceProvider->RegisterService(SID_DRMSecureServiceChannel, spSecureServiceServer);
|
||
}
|
||
}
|
||
#endif // BUILD_WITH_DRM
|
||
return NOERROR;
|
||
} catch(...) {
|
||
return E_UNEXPECTED;
|
||
}
|
||
}
|
||
|
||
|
||
STDMETHODIMP CMSVidStreamBufferSink::PreRun(){
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::PreRun()");
|
||
return NameSetLock();
|
||
}
|
||
|
||
STDMETHODIMP CMSVidStreamBufferSink::NameSetLock(){
|
||
try {
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock()");
|
||
HRESULT hr;
|
||
if(!m_bNameSet){
|
||
if(!m_SinkName){
|
||
return S_FALSE;
|
||
}
|
||
else{
|
||
hr = m_ptsSink->IsProfileLocked();
|
||
if(FAILED(hr)){
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() IsProfileLocked failed");
|
||
return hr;
|
||
}
|
||
else if(hr == S_OK){
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() Profile is locked");
|
||
return E_FAIL;
|
||
}
|
||
hr = m_ptsSink->LockProfile(m_SinkName);
|
||
if(FAILED(hr)){
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() LockedProfile failed");
|
||
return hr;
|
||
}
|
||
|
||
}
|
||
m_bNameSet = TRUE;
|
||
}
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() Succeeded");
|
||
return S_OK;
|
||
|
||
} catch (ComException &e) {
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() Exception");
|
||
return e;
|
||
} catch (...) {
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::NameSetLock() Possible AV");
|
||
return E_UNEXPECTED;
|
||
}
|
||
}
|
||
|
||
STDMETHODIMP CMSVidStreamBufferSink::PostStop() {
|
||
try {
|
||
m_bNameSet = FALSE;
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::PostStop()");
|
||
return S_OK;
|
||
} catch (...) {
|
||
ASSERT(FALSE);
|
||
return E_UNEXPECTED;
|
||
}
|
||
}
|
||
|
||
// IMSVidDevice
|
||
STDMETHOD(get_Name)(BSTR * Name) {
|
||
if (!m_fInit) {
|
||
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSink), CO_E_NOTINITIALIZED);
|
||
}
|
||
if (Name == NULL)
|
||
return E_POINTER;
|
||
try {
|
||
*Name = m_Name.Copy();
|
||
} catch(...) {
|
||
return E_POINTER;
|
||
}
|
||
return NOERROR;
|
||
}
|
||
STDMETHOD(get_Status)(LONG * Status) {
|
||
if (!m_fInit) {
|
||
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSink), CO_E_NOTINITIALIZED);
|
||
}
|
||
if (Status == NULL)
|
||
return E_POINTER;
|
||
|
||
return E_NOTIMPL;
|
||
}
|
||
|
||
STDMETHOD(OnEventNotify)(LONG lEventCode, LONG_PTR lEventParm1, LONG_PTR lEventParm2){
|
||
if(lEventCode == STREAMBUFFER_EC_WRITE_FAILURE){
|
||
TRACELM(TRACE_DETAIL, "CMSVidStreamBufferSink::OnEventNotify STREAMBUFFER_EC_WRITE_FAILURE");
|
||
Fire_WriteFailure();
|
||
return NO_ERROR;
|
||
}
|
||
return E_NOTIMPL;
|
||
}
|
||
// IBroadcastEvent
|
||
STDMETHOD(Fire)(GUID gEventID);
|
||
private:
|
||
void Expunge();
|
||
pqRecorder m_RecordObj;
|
||
BOOL m_bNameSet;
|
||
};
|
||
#endif //__MSVIDSTREAMBUFFERSINK_H_
|