483 lines
19 KiB
C++
483 lines
19 KiB
C++
//==========================================================================;
|
|
//
|
|
// 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 <uuids.h>
|
|
#include "bdamedia.h"
|
|
#include "MSVidTVTuner.h"
|
|
#include "resource.h" // main symbols
|
|
#include <winerror.h>
|
|
#include <algorithm>
|
|
#include <compimpl.h>
|
|
#include <seg.h>
|
|
#include <objectwithsiteimplsec.h>
|
|
#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<IDRMSecureChannel> 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<IDRMSecureChannel> 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<CComSingleThreadModel>,
|
|
public CComCoClass<CEnc2SinComp, &__uuidof(CEnc2SinComp)>,
|
|
public IObjectWithSiteImplSec<CEnc2SinComp>,
|
|
public IMSVidCompositionSegmentImpl<CEnc2SinComp>
|
|
{
|
|
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<IETFilterConfig> spETConfig;
|
|
CComPtr<IUnknown> 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<IMSVidCtl> pq_vidCtl;
|
|
if(!m_pContainer){
|
|
return S_OK;
|
|
}
|
|
else{
|
|
hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast<void**>(&pq_vidCtl));
|
|
if(SUCCEEDED(hr) && pq_vidCtl){
|
|
pq_vidCtl->Stop();
|
|
}
|
|
CComQIPtr<IMSVidStreamBufferSinkEvent>pq_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<IMSVidEncoder> qiEnc(upstream);
|
|
CEncoder* iEnc;
|
|
iEnc = static_cast<CEncoder*>(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<IUnknown> 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<void**>(&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<IUnknown> 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<IUnknown> 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
|