windows-nt/Source/XPSP1/NT/multimedia/dshow/vidctl/msvidctl/enc2sin.h
2020-09-26 16:20:57 +08:00

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