|
|
//===========================================================================
//
// VidCtl.cpp : Implementation of CVidCtl the core viewer control class
// Copyright (c) Microsoft Corporation 1999.
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#ifndef TUNING_MODEL_ONLY
#define ENCODERCAT_HACK 1
#include <atlgdi.h>
#include <bdatypes.h>
#include <bdamedia.h>
#include <evcode.h>
#include <wmsdk.h>
#include <wininet.h>
#include "seg.h"
#include "MSVidtvtuner.h"
#include "msvidvideorenderer.h"
#include "msvidwebdvd.h"
#include "VidCtl.h"
#include "msvidsbesink.h"
#include "msvidsbesource.h"
#include "msvidfileplayback.h"
//#include "perfevents.h"
const WCHAR g_kwszDVDURLPrefix[] = L"DVD:"; const WCHAR g_kwszDVDSimpleURL[] = L"DVD";
DEFINE_EXTERN_OBJECT_ENTRY(CLSID_MSVidCtl, CVidCtl)
MediaMajorTypeList CVidCtl::VideoTypes; MediaMajorTypeList CVidCtl::AudioTypes;
#ifndef KSCATEGORY_ENCODER
#define STATIC_KSCATEGORY_ENCODER \
0x19689bf6, 0xc384, 0x48fd, 0xad, 0x51, 0x90, 0xe5, 0x8c, 0x79, 0xf7, 0xb DEFINE_GUIDSTRUCT("19689BF6-C384-48fd-AD51-90E58C79F70B", KSCATEGORY_ENCODER); #define KSCATEGORY_ENCODER DEFINE_GUIDNAMED(KSCATEGORY_ENCODER)
#endif
/////////////////////////////////////////////////////////////////////////////
// CVidCtl
STDMETHODIMP CVidCtl::get_State(MSVidCtlStateList *lState){ try{ if(lState){ *lState = m_State; return S_OK; } return E_POINTER; } catch(HRESULT hres){ return hres; } catch(...){ return E_UNEXPECTED; } }
CVidCtl::~CVidCtl() { try { try { if (m_pGraph && !m_pGraph.IsStopped()) { Stop(); } } catch(...) { } m_pSystemEnum.Release(); m_pFilterMapper.Release(); DecomposeAll(); // put_Container(NULL) on all the composition segments
m_pComposites.clear(); if (m_pInput) { PQGraphSegment(m_pInput)->put_Container(NULL); m_pInput.Release(); } if (m_pVideoRenderer) { PQGraphSegment(m_pVideoRenderer)->put_Container(NULL); m_pVideoRenderer.Release(); } if (m_pAudioRenderer) { PQGraphSegment(m_pAudioRenderer)->put_Container(NULL); m_pAudioRenderer.Release(); }
{ // chosen devices&Outputs
if (!!m_pOutputsInUse && m_pOutputsInUse.begin() != m_pOutputsInUse.end()) {
VWOutputDevices::iterator i; for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { if ((*i).punkVal) { PQGraphSegment((*i).punkVal)->put_Container(NULL); } } m_pOutputsInUse.Release(); }
}
{ // chosen devices&features
if(m_pFeaturesInUse && m_pFeaturesInUse.begin() != m_pFeaturesInUse.end()){ VWFeatures::iterator i; for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { if ((*i).punkVal) { PQGraphSegment((*i).punkVal)->put_Container(NULL); } } m_pFeaturesInUse.Release(); } }
// available collections
m_pInputs.Release(); m_pOutputs.Release(); m_pFeatures.Release(); m_pVRs.Release(); m_pARs.Release();
if (m_fNotificationSet) { m_pGraph.SetMediaEventNotificationWindow(0, 0, 0); } if (m_pGraph) { if (m_dwROTCookie) { m_pGraph.RemoveFromROT(m_dwROTCookie); } m_pGraph.Release(); } if (m_pTopWin && m_pTopWin->m_hWnd && ::IsWindow(m_pTopWin->m_hWnd)) { m_pTopWin->SendMessage(WM_CLOSE); delete m_pTopWin; m_pTopWin = NULL; } } catch (...) { TRACELM(TRACE_ERROR, "CVidCtl::~CVidCtl() catch(...)"); } }
void CVidCtl::Init() { VIDPERF_FUNC; if (m_fInit) return;
TRACELM(TRACE_DETAIL, "CVidCtl::Init()"); ASSERT(!m_pGraph);
m_pGraph = PQGraphBuilder(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER); if (!m_pGraph) { TRACELM(TRACE_ERROR, "CVidCtl::Init() can't create graph object"); THROWCOM(E_UNEXPECTED); } PQObjectWithSite pos(m_pGraph); if (pos) { pos->SetSite(static_cast<IMSVidCtl*>(this)); }
HRESULT hr = m_pGraph.AddToROT(&m_dwROTCookie); if (FAILED(hr)) { m_dwROTCookie = 0; TRACELM(TRACE_ERROR, "CVidCtl::Init() can't add graph to ROT"); }
TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::Init() graph = " << m_pGraph), ""); SetTimer(); SetMediaEventNotification(); if (!m_pSystemEnum) { m_pSystemEnum = PQCreateDevEnum(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER); ASSERT(m_pSystemEnum); } if (!m_pFilterMapper) { m_pFilterMapper = m_pGraph; ASSERT(m_pFilterMapper); }
m_pFeaturesInUse = static_cast<IMSVidFeatures *>(new CFeatures(false, true)); m_pOutputsInUse = static_cast<IMSVidOutputDevices *>(new COutputDevices(false, true)); m_fInit = true;
}
HRESULT CVidCtl::GetInputs(const GUID2& catguid, VWInputDevices& pInputs) { VIDPERF_FUNC; //undone: look up category guid to segment object mapping in registry
// for now we're just hard coding the few we're testing with
// inputs
if (catguid == KSCATEGORY_TVTUNER) { CInputDevices *pDev = new CInputDevices(true); DSDevices TunerList(m_pSystemEnum, catguid); DSDevices::iterator i; for (i = TunerList.begin(); i != TunerList.end(); ++i) { PQGraphSegment p(CLSID_MSVidAnalogTunerDevice); if (!p) continue; p->put_Init(*i); pDev->m_Devices.push_back(PQDevice(p)); } pDev->Valid = true; pInputs = static_cast<IMSVidInputDevices *>(pDev); return NOERROR; } else if (catguid == KSCATEGORY_BDA_NETWORK_PROVIDER || catguid == KSCATEGORY_BDA_NETWORK_TUNER) { GUID2 catguid2 = KSCATEGORY_BDA_NETWORK_PROVIDER; CInputDevices *pDev = new CInputDevices(true); DSDevices TunerList(m_pSystemEnum, catguid2); DSDevices::iterator i; for (i = TunerList.begin(); i != TunerList.end(); ++i) { PQGraphSegment p(CLSID_MSVidBDATunerDevice); if (!p) continue; p->put_Init(*i); pDev->m_Devices.push_back(PQDevice(p)); } pDev->Valid = true; pInputs = static_cast<IMSVidInputDevices *>(pDev); return NOERROR; } else if (catguid == GUID_NULL) { CInputDevices *pDev = new CInputDevices(true); // non cat enumerated devices
{ PQGraphSegment p(CLSID_MSVidFilePlaybackDevice); if (!p) { _ASSERT(false); pDev->Release(); return E_NOTIMPL; } p->put_Init(NULL); pDev->m_Devices.push_back(PQDevice(p)); pDev->Valid = true; pInputs = static_cast<IMSVidInputDevices *>(pDev); } { PQGraphSegment p(CLSID_MSVidWebDVD); if (!p) { _ASSERT(false); pDev->Release(); return E_NOTIMPL; } p->put_Init(NULL); pDev->m_Devices.push_back(PQDevice(p)); pDev->Valid = true; pInputs = static_cast<IMSVidInputDevices *>(pDev); } {
PQGraphSegment p(CLSID_MSVidStreamBufferSource); if (!p) { _ASSERT(false); pDev->Release(); return E_NOTIMPL; } p->put_Init(NULL); pDev->m_Devices.push_back(PQDevice(p)); pDev->Valid = true; pInputs = static_cast<IMSVidInputDevices *>(pDev);
}
return NOERROR; }
return E_INVALIDARG; }
HRESULT CVidCtl::GetOutputs(const GUID2& CategoryGuid) { VIDPERF_FUNC; // We only have one output
if (CategoryGuid == GUID_NULL) { COutputDevices *pDev = new COutputDevices(true); PQGraphSegment p(CLSID_MSVidStreamBufferSink); if (!p) { pDev->Release(); return E_NOTIMPL; } p->put_Init(NULL); pDev->m_Devices.push_back(PQDevice(p)); pDev->Valid = true; m_pOutputs = static_cast<IMSVidOutputDevices *>(pDev); } return S_OK;
}
HRESULT CVidCtl::GetVideoRenderers() { VIDPERF_FUNC; //Video Renderers
CVideoRendererDevices *pDevs = new CVideoRendererDevices(true);
PQGraphSegment p(CLSID_MSVidVideoRenderer); if (!p) { pDevs->Release(); return Error(IDS_CANT_CREATE_FILTER, __uuidof(IMSVidCtl), IDS_CANT_CREATE_FILTER); }
p->put_Init(NULL); PQDevice pd(p); if (!pd) { pDevs->Release(); return E_UNEXPECTED; } pDevs->m_Devices.push_back(pd); pDevs->Valid = true; m_pVRs = static_cast<IMSVidVideoRendererDevices *>(pDevs);
return NOERROR; }
HRESULT CVidCtl::GetAudioRenderers() { VIDPERF_FUNC; //Audio Renderers
CAudioRendererDevices *pDevs = new CAudioRendererDevices(true);
PQGraphSegment p(CLSID_MSVidAudioRenderer); if (!p) { pDevs->Release(); return Error(IDS_CANT_CREATE_FILTER, __uuidof(IMSVidCtl), IDS_CANT_CREATE_FILTER); } p->put_Init(NULL); PQDevice pd(p); if (!pd) { pDevs->Release(); return E_UNEXPECTED; } pDevs->m_Devices.push_back(pd); pDevs->Valid = true; m_pARs = static_cast<IMSVidAudioRendererDevices *>(pDevs); return NOERROR; }
HRESULT CVidCtl::GetFeatures() { VIDPERF_FUNC; // available features
// undone: change hard coded list of features into registry lookup
if (!m_pFeatures) { CFeatures *pDev = new CFeatures; if (!pDev) { return E_OUTOFMEMORY; } pDev->Valid = true; m_pFeatures = static_cast<IMSVidFeatures *>(pDev); { PQGraphSegment p(CLSID_MSVidDataServices); if (p) { p->put_Init(NULL); pDev->m_Devices.push_back(PQDevice(p)); } else { _ASSERT(false); } }
{ PQGraphSegment p(CLSID_MSVidClosedCaptioning); if (p) { p->put_Init(NULL); pDev->m_Devices.push_back(PQDevice(p)); } else { _ASSERT(false); } } { PQGraphSegment p(CLSID_MSVidXDS); if (p) { p->put_Init(NULL); pDev->m_Devices.push_back(PQDevice(p)); } else { _ASSERT(false); } } #if ENCODERCAT_HACK
bool AddedMux = false; #endif
{ // Hardware mux category
DSDevices EncoderList(m_pSystemEnum, KSCATEGORY_MULTIPLEXER); DSDevices::iterator i; for (i = EncoderList.begin(); i != EncoderList.end(); ++i) { PQGraphSegment p(CLSID_MSVidEncoder); if (!p) continue; p->put_Init(*i); pDev->m_Devices.push_back(PQDevice(p)); #if ENCODERCAT_HACK
AddedMux = true; #endif
} } { // Software mux category
DSDevices EncoderList(m_pSystemEnum, CLSID_MediaMultiplexerCategory); DSDevices::iterator i; for (i = EncoderList.begin(); i != EncoderList.end(); ++i) { PQGraphSegment p(CLSID_MSVidEncoder); if (!p) continue; p->put_Init(*i); pDev->m_Devices.push_back(PQDevice(p)); #if ENCODERCAT_HACK
AddedMux = true; #endif
} } #if ENCODERCAT_HACK
if(!AddedMux){ DSDevices EncoderList(m_pSystemEnum, KSCATEGORY_ENCODER); DSDevices::iterator i; for (i = EncoderList.begin(); i != EncoderList.end(); ++i) { PQGraphSegment p(CLSID_MSVidEncoder); if (!p) continue; p->put_Init(*i); pDev->m_Devices.push_back(PQDevice(p)); } } #endif
}
return NOERROR; }
// Takes a variant input and a list of input devices to attempt to view the input with
HRESULT CVidCtl::SelectViewFromSegmentList(CComVariant &pVar, VWInputDevices& grList, PQInputDevice& pCurInput) { VIDPERF_FUNC; VWInputDevices::iterator i = grList.begin(); // skip devices until we're past the current one(if there is a current one)
for (; pCurInput && i != grList.end(); ++i) { PQInputDevice pInDev((*i).punkVal); VARIANT_BOOL f = VARIANT_FALSE; HRESULT hr = pCurInput->IsEqualDevice(pInDev, &f); if (SUCCEEDED(hr) && f == VARIANT_TRUE){ ++i; break; } } // run thru to the end of the list
for (; i != grList.end(); ++i) { PQInputDevice pInDev((*i).punkVal); HRESULT hr = pInDev->View(&pVar); if(SUCCEEDED(hr)){ if(m_pInput){ PQGraphSegment(m_pInput)->put_Container(NULL); } m_pInput = pInDev; m_pInputNotify = m_pInput; m_CurView = pVar; m_fGraphDirty = true; return NOERROR; } } if (pCurInput) { // retry the ones we skipped
i = grList.begin(); for (; i != grList.end(); ++i) { PQInputDevice pInDev((*i).punkVal); HRESULT hr = pInDev->View(&pVar); if(SUCCEEDED(hr)){ if(m_pInput){ PQGraphSegment(m_pInput)->put_Container(NULL); } m_pInput = pInDev; m_pInputNotify = m_pInput; m_CurView = pVar; m_fGraphDirty = true; return NOERROR; } } }
return E_FAIL; }
// non-interface functions
HRESULT CVidCtl::SelectView(VARIANT *pv, bool fNext) { VIDPERF_FUNC; HRESULT hr; TRACELM(TRACE_DETAIL, "CVidCtl::SelectView()"); if (!m_fInit) { Init(); } if (!pv) { m_CurView = CComVariant(); return NOERROR; } CComVariant pVar(*pv); if(pv->vt & VT_BYREF){ if(pv->vt == (VT_UNKNOWN|VT_BYREF)){ pVar=(*reinterpret_cast<IUnknown**>(pv->punkVal)); } else if(pv->vt == (VT_DISPATCH|VT_BYREF)){ pVar = (*reinterpret_cast<IDispatch**>(pv->pdispVal)); } } if (!pVar) { m_CurView = CComVariant(); return NOERROR; } if (m_pInput && !fNext) { // && pVar != m_CurView) {
// note: only try different content on current device,
// if app tries to re-view the current view content then we
// attempt to iterate to next available device
hr = m_pInput->View(&pVar); if (SUCCEEDED(hr)) { // currently selected device can view this new content
return hr; } } if (m_pGraph.GetState() != State_Stopped) { return Error(IDS_INVALID_STATE, __uuidof(IMSVidCtl), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); }
if (m_pInput) { hr = DecomposeSegment(VWGraphSegment(m_pInput)); if (FAILED(hr)) { return Error(IDS_CANT_REMOVE_SEG, __uuidof(IMSVidCtl), IDS_CANT_REMOVE_SEG); } } // Try the ATSC tune request
if (pVar.vt == VT_UNKNOWN || pVar.vt == VT_DISPATCH) { PQTuneRequest ptr(pVar.vt == VT_UNKNOWN ? pVar.punkVal : pVar.pdispVal); if (ptr) { VWInputDevices pInputs; PQChannelTuneRequest ptr2(ptr); if (ptr2) { PQATSCChannelTuneRequest ptr3(ptr); if (!ptr3) { hr = GetInputs(KSCATEGORY_TVTUNER, pInputs); if(SUCCEEDED(hr)){ hr = SelectViewFromSegmentList(pVar, pInputs, m_pInput); if(SUCCEEDED(hr)){ m_CurViewCatGuid = KSCATEGORY_TVTUNER; return hr; } } } }
hr = GetInputs(KSCATEGORY_BDA_NETWORK_PROVIDER, pInputs); if(SUCCEEDED(hr)){ hr = SelectViewFromSegmentList(pVar, pInputs, m_pInput); if(SUCCEEDED(hr)){ m_CurViewCatGuid = KSCATEGORY_BDA_NETWORK_PROVIDER; return hr; } } if(FAILED(hr)){ return hr; } } }
// Try to view the File input and DVD Segments
VWInputDevices pInputs; hr = GetInputs(GUID_NULL, pInputs); hr = SelectViewFromSegmentList(pVar, pInputs, m_pInput); if(SUCCEEDED(hr)){ m_CurViewCatGuid = GUID_NULL; return hr; } return Error(IDS_CANT_VIEW, __uuidof(IMSVidCtl), IDS_CANT_VIEW); }
HRESULT CVidCtl::LoadDefaultVR(void) { VIDPERF_FUNC; PQVRGraphSegment pGS; HRESULT hr = pGS.CoCreateInstance(CLSID_MSVidVideoRenderer); if (FAILED(hr) || !pGS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultVR() can't instantiate default video renderer. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_FILTER, __uuidof(IMSVidCtl), IDS_CANT_CREATE_FILTER); } hr = pGS->put_Init(NULL); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultVR() can't init default video renderer. hr = " << std::hex << hr), ""); return hr; } hr = pGS->put_Container(this); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultVR() can't load default video renderer. hr = " << std::hex << hr), ""); return hr; } if (!m_bNegotiatedWnd) { if (!m_bInPlaceActive) { hr = InPlaceActivate(OLEIVERB_INPLACEACTIVATE, NULL); if (FAILED(hr)) { return hr; } } } #if 0
VARIANT_BOOL ov = (m_bWndLess && WindowHasHWOverlay(m_CurrentSurface.Owner())) ? VARIANT_TRUE : VARIANT_FALSE; #else
// always try to use overlay if we're wndless. vmr will tell us if it isn't available
VARIANT_BOOL ov = m_bWndLess ? VARIANT_TRUE : VARIANT_FALSE; #endif
hr = pGS->put_UseOverlay(ov); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultVR() can't set useoverlay. hr = " << std::hex << hr), ""); return hr; } m_pVideoRenderer = pGS;
return NOERROR; }
HRESULT CVidCtl::LoadDefaultAR(void) { VIDPERF_FUNC; PQGraphSegment pGS; HRESULT hr = pGS.CoCreateInstance(CLSID_MSVidAudioRenderer); if (FAILED(hr) || !pGS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultAR() can't instantiate default Audio renderer. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_FILTER, __uuidof(IMSVidCtl), IDS_CANT_CREATE_FILTER); } hr = pGS->put_Init(NULL); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultAR() can't init default Audio renderer. hr = " << std::hex << hr), ""); return hr; } hr = pGS->put_Container(this); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultAR() can't load default Audio renderer. hr = " << std::hex << hr), ""); return hr; } m_pAudioRenderer = pGS;
return NOERROR; }
HRESULT CVidCtl::Compose(VWGraphSegment &Up, VWGraphSegment &Down, int &NewIdx) { VIDPERF_FUNC; PQCompositionSegment pCS; #if 0
// This code is for returning error codes in failure cases for the default composition segment
HRESULT hrExpected = S_OK; HRESULT hrFailed = E_FAIL; bool bCheckHR = false; #endif
_ASSERT(!!Up && !!Down);
// Analog TV to Video Renderer Composition Segment
if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidVideoRenderer) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogCaptureToOverlayMixer); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to ov mixer composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // Analog TV to Stream Buffer Sink Compsition Segment
else if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogCaptureToStreamBufferSink); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to time shift sink composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // Digital TV (bda) to Video Renderer Compsition Segment
else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidBDATunerDevice && VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidDigitalCaptureToStreamBufferSink); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to time shift sink composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // Analog TV to Data Services Compsition Segment
else if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidDataServices) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogCaptureToDataServices); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog tuner/capture to data services composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // Digial TV (bda) or DVD to Closed Caption Compsition Segment
else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidBDATunerDevice || VWGraphSegment(Up).ClassID() == CLSID_MSVidWebDVD) && VWGraphSegment(Down).ClassID() == CLSID_MSVidClosedCaptioning) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidMPEG2DecoderToClosedCaptioning); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate mp2 to CC composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // File Playback to Video Renderer Compsition Segment
else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidFilePlaybackDevice ) && VWGraphSegment(Down).ClassID() == CLSID_MSVidVideoRenderer) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidFilePlaybackToVideoRenderer); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate file playback to video renderer composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // File Playback to Audio Renderer Compsition Segment
else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidFilePlaybackDevice ) && VWGraphSegment(Down).ClassID() == CLSID_MSVidAudioRenderer) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidFilePlaybackToAudioRenderer); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate file playback to audio renderer composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), E_UNEXPECTED); } } // DVD to Video Renderer Compsition Segment
else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidWebDVD && VWGraphSegment(Down).ClassID() == CLSID_MSVidVideoRenderer) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidWebDVDToVideoRenderer); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate webdvd to video renderer, hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } #if 0
else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidWebDVD && VWGraphSegment(Down).ClassID() == CLSID_MSVidAudioRenderer) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidWebDVDToAudioRenderer); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate time shift source to data services composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } #endif
///////////////////////////////////////////////////
// New Compostion Segments for FreeStyle Endgame //
///////////////////////////////////////////////////
// XDS to Stream Buffer Sink Compsition Segment
else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidXDS && (VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink)) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidDataServicesToStreamBufferSink); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate time shift source to data services composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // Encoder to Stream Buffer Sink Compsition Segment
else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidEncoder && (VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink)) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidEncoderToStreamBufferSink); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate encoder to time shift sink composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // StreamBufferSource to Video Renderer Compsition Segment
else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidStreamBufferSource ) && VWGraphSegment(Down).ClassID() == CLSID_MSVidVideoRenderer) { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidStreamBufferSourceToVideoRenderer); // name change needed
if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate time shift source to CC composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // Analog Capture to XDS
else if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidXDS){ HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogCaptureToXDS); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to XDS composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // Analog Capture to Encoder
else if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidEncoder){ HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogTVToEncoder); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to XDS composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } // StreamBufferSource to CC
else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidStreamBufferSource ) && VWGraphSegment(Down).ClassID() == CLSID_MSVidClosedCaptioning){ HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidSBESourceToCC); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to XDS composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidStreamBufferSource) && (VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink)){ return E_FAIL; } else { HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidGenericComposite); if (FAILED(hr) || !pCS) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate generic composite. hr = " << std::hex << hr), ""); return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG); } } HRESULT hr = pCS->put_Init(NULL); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't init new comp seg. hr = " << std::hex << hr), ""); return hr; } VWGraphSegment pSeg(pCS); ASSERT(pSeg); m_pComposites.push_back(pSeg); NewIdx = m_pComposites.size() - 1; hr = pCS->put_Container(this); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't put_continaer for new comp segment. hr = " << std::hex << hr), ""); return hr; }
hr = pCS->Compose(PQGraphSegment(Up), PQGraphSegment(Down)); #if 0
if(bCheckHR){ if(hr != hrExpected){ return hrFailed; } else{ return hr; } } #endif
if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't compose up = " << Up << " with down = " << Down << " hr = " << hexdump(hr) ), ""); return hr; }
return NOERROR; }
HRESULT CVidCtl::BuildGraph(void) { CPerfCounter pCounterBuild, pCounterPutC, pCounterCompose, pCounterBuilds, pCounterComp, pCounterB; pCounterBuild.Reset(); TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph()"); BOOL lRes = 0; OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); HRESULT hr; ASSERT(m_pGraph); if(m_State != STATE_UNBUILT && m_fGraphDirty != true){ return S_OK; // need a graph already built warning message
}
// make sure any needed default renderer's are selected prior to calling
// build on the other segments so all segments are loaded before any
// build() functions are called.
// make sure required defaultable segments are set or assign a default
// also make sure every segment knows the container
bool fDefVideoRenderer = false; pCounterPutC.Reset(); if (m_pVideoRenderer) { hr = PQGraphSegment(m_pVideoRenderer)->put_Container(this); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() put_Container failed for Video Renderer"); return hr; } } else if (!m_videoSetNull) { hr = LoadDefaultVR(); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() LoadDefaultVR failed"); return hr; } if (!m_pVideoRenderer) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() LoadDefaultVR returned NULL Video Renderer"); return E_UNEXPECTED; } fDefVideoRenderer = true; } TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() default vr checked");
bool fDefAudioRenderer = false; if (m_pAudioRenderer) { hr = PQGraphSegment(m_pAudioRenderer)->put_Container(this); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() put_Container failed for Audio Renderer"); return hr; } } else if (!m_audioSetNull) { hr = LoadDefaultAR(); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() LoadDefaultAR failed"); return hr; } if (!m_pAudioRenderer) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() LoadDefaultAR returned NULL Audio Renderer"); return E_UNEXPECTED; } fDefAudioRenderer = true; } TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() default ar checked");
if (!m_pInput) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() input segment required" << std::hex << hr), ""); return Error(IDS_INPUT_SEG_REQUIRED, __uuidof(IMSVidCtl), IDS_INPUT_SEG_REQUIRED); }
hr = PQGraphSegment(m_pInput)->put_Container(this); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't load input segment. hr = " << std::hex << hr), ""); return hr; }
TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() input container set"); { for (VWFeatures::iterator i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { // notify them that we're building
hr = VWGraphSegment(*i)->put_Container(this); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't load feature segment: " << (*i) << " hr = " << std::hex << hr), ""); return hr; }
} }
{ for (VWOutputDevices::iterator i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { // notify them that we're building
hr = VWGraphSegment(*i)->put_Container(this); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't load output segment: " << (*i) << " hr = " << std::hex << hr), ""); return hr; } } }
pCounterPutC.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() PutContainer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterPutC.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterPutC.GetLastTime() % _100NS_IN_MS) << " ms"), "");
TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() feature container set");
pCounterBuilds.Reset(); // Notify all of the output segments that we are about to build
pCounterB.Reset(); // Notify everyone that composition is about to start
hr = VWGraphSegment(m_pInput)->Build(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() Build call for input failed"); return hr; }
pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to Input: " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset();
{ VWFeatures::iterator i; for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { // notify them that we're building
hr = VWGraphSegment(*i)->Build(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't build feature segment: " << (*i) << " hr = " << std::hex << hr), ""); return hr; } pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to Feature " << (*i) << " : " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset(); } }
{ VWOutputDevices::iterator i; for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { // notify them that we're building
hr = VWGraphSegment(*i)->Build(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't build output segment: " << (*i) << " hr = " << std::hex << hr), ""); return hr; } pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to Output " << (*i) << " : " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset(); } }
if (m_pVideoRenderer) { hr = VWGraphSegment(m_pVideoRenderer)->Build(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() Build call to Video Renderer Failed"); return hr; } pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to VideoRenderer: " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset(); } if (m_pAudioRenderer) { hr = VWGraphSegment(m_pAudioRenderer)->Build(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() Build call to Audio Renderer Failed"); return hr; } pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to Audio Renderer: " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset(); } pCounterBuilds.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build Calls to segments " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterBuilds.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterBuilds.GetLastTime() % _100NS_IN_MS) << " ms"), "");
TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() build notifications issued"); pCounterCompose.Reset(); pCounterComp.Reset(); { VWFeatures::iterator i; // composing input w/ features
TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Input w/ Features"); for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { int NewCompositionSegmentIdx = -1; hr = Compose(VWGraphSegment(m_pInput), VWGraphSegment(*i), NewCompositionSegmentIdx); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose input segment with feature segment: " << (*i) << " hr = " << std::hex << hr), ""); return hr; } } } pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Composing Input w/ Features " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset(); // compose input w/ renderers
TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Input w/ Video Renderer"); if (m_pVideoRenderer) { if (m_iCompose_Input_Video == -1) { hr = Compose(VWGraphSegment(m_pInput), VWGraphSegment(m_pVideoRenderer), m_iCompose_Input_Video); if (FAILED(hr) /*&& !fDefVideoRenderer*/ ) { // this should fail even if it is the default video renderer
TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose input and video. hr = " << std::hex << hr), ""); return hr; } } ASSERT(m_iCompose_Input_Video != -1); PQCompositionSegment pCS(m_pComposites[m_iCompose_Input_Video]); } pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Input w/ Video Renderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Input w/ Audio Renderer"); if (m_pAudioRenderer) { if (m_iCompose_Input_Audio == -1) { hr = Compose(VWGraphSegment(m_pInput), VWGraphSegment(m_pAudioRenderer), m_iCompose_Input_Audio); if (FAILED(hr) && !fDefAudioRenderer) { // didn't work and the client explicitly specificed they want an audio renderer
TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose input and audio. hr = " << std::hex << hr), ""); return hr; } } } pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Input w/ Audio Renderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
// compose input w/ outputs
{ TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Input w/ Outputs"); for (VWOutputDevices::iterator i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { int NewCompositionSegmentIdx = -1; hr = Compose(VWGraphSegment(m_pInput),VWGraphSegment(*i), NewCompositionSegmentIdx); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose output segment with input: " << (*i) << " hr = " << std::hex << hr), ""); return hr; }
} } pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() inputs w/ Outputs " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
// composing Features w/ Renderers
TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Features w/ Renderers"); for (VWFeatures::iterator i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { int NewCompositionSegmentIdx = -1; if (m_pVideoRenderer) { hr = Compose(VWGraphSegment(*i), VWGraphSegment(m_pVideoRenderer), NewCompositionSegmentIdx); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose feature segment: " << (*i) << " w/ video renderer. hr = " << std::hex << hr), ""); // note: this is not a fatal error for building. many features won't
// connect to vr(such as data services)
} } pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Features w/ Video Renderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
if (m_pAudioRenderer) { hr = Compose(VWGraphSegment(*i), VWGraphSegment(m_pAudioRenderer), NewCompositionSegmentIdx); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose feature segment: " << (*i) << " w/ Audio renderer. hr = " << std::hex << hr), ""); // note: this is not a fatal error for building. many features won't
// connect to ar(such as data services)
} } pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Features w/ Audio Renderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
{ for (VWOutputDevices::iterator oi = m_pOutputsInUse.begin(); oi != m_pOutputsInUse.end(); ++oi) { hr = Compose(VWGraphSegment(*i),VWGraphSegment(*oi), NewCompositionSegmentIdx); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose output segment with feature: " << (*i) << " hr = " << std::hex << hr), ""); return hr; }
} } pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Features w/ Outputs " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset(); } pCounterCompose.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() compose segments " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterCompose.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterCompose.GetLastTime() % _100NS_IN_MS) << " ms"), "");
RouteStreams(); SetExtents();
m_fGraphDirty = false; // m_State = STATE_STOP;
//SetMediaEventNotification();
// fire state change at client
PQMediaEventSink mes(m_pGraph); hr = mes->Notify(EC_BUILT, 0, 0); OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); _ASSERT(m_State == STATE_STOP); TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterBuild.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterBuild.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterBuild.Stop(); return NOERROR; }
HRESULT CVidCtl::RunGraph(void) { VIDPERF_FUNC; TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph()"); CPerfCounter pCounterMCRun, pCounterPostRun, pCounterPreRun, pCounterRunGraph, pCounterEachPreRun; pCounterRunGraph.Reset(); if (!m_pInput || !m_pGraph) { return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidCtl), CO_E_NOTINITIALIZED); } BOOL lRes = 0; OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); HRESULT hr; if (m_pGraph.IsPlaying()) { TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() already playing"); return NOERROR; } else if (m_pGraph.IsPaused() && m_State == STATE_PAUSE) { TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() is paused"); PQMediaControl pmc(m_pGraph); if (!pmc) { return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidCtl), IDS_NO_MEDIA_CONTROL); } hr = pmc->Run(); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Run() hr = " << hexdump(hr)), ""); return Error(IDS_CANT_START_GRAPH, __uuidof(IMSVidCtl), hr); } OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); return NOERROR; } else { TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() build/prerun"); // Rebuild the graph if necessary
if (m_fGraphDirty) { TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() building"); hr = BuildGraph(); if (FAILED(hr)) { return hr; } } OAFilterState graphState = m_pGraph.GetState();
TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() prerun notifications"); // Notify all segments graph is about to run
pCounterPreRun.Reset(); pCounterEachPreRun.Reset(); ASSERT(m_pInput); hr = VWGraphSegment(m_pInput)->PreRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Input " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset(); if (m_pVideoRenderer) { hr = VWGraphSegment(m_pVideoRenderer)->PreRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun VideoRenderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset(); if (m_pAudioRenderer) { hr = VWGraphSegment(m_pAudioRenderer)->PreRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun AudioRenderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset(); { VWOutputDevices::iterator i; for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { hr = VWGraphSegment(*i)->PreRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Output " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset(); { VWFeatures::iterator i; for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { hr = VWGraphSegment(*i)->PreRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Features " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset(); { VWSegmentList::iterator i; for(i = m_pComposites.begin(); i != m_pComposites.end(); ++i){ hr = VWGraphSegment(*i)->PreRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Composites " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset(); // Make sure graph state hasn't changed
ASSERT(graphState == m_pGraph.GetState()); Refresh(); // make sure we're in place active etc.
pCounterPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), "");
// Start the graph running
PQMediaControl pmc(m_pGraph); if (!pmc) { return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidCtl), IDS_NO_MEDIA_CONTROL); } pCounterMCRun.Reset(); hr = pmc->Run(); pCounterMCRun.Stop(); #if 0
if(FAILED(hr)){ hr = pmc->Run(); } #endif
TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() MediaControl Run Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterMCRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterMCRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Run() hr = " << hexdump(hr)), ""); return Error(IDS_CANT_START_GRAPH, __uuidof(IMSVidCtl), hr); } } TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() postrun"); // Notify all segments graph is running
pCounterPostRun.Reset(); ASSERT(m_pInput); hr = VWGraphSegment(m_pInput)->PostRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; }
if (m_pVideoRenderer) { hr = VWGraphSegment(m_pVideoRenderer)->PostRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } if (m_pAudioRenderer) { hr = VWGraphSegment(m_pAudioRenderer)->PostRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } }
{ VWOutputDevices::iterator i; for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { hr = VWGraphSegment(*i)->PostRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } { VWFeatures::iterator i; for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { hr = VWGraphSegment(*i)->PostRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } { VWSegmentList::iterator i; for (i = m_pComposites.begin(); i != m_pComposites.end(); ++i){ hr = VWGraphSegment(*i)->PostRun(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } Refresh(); OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); pCounterPostRun.Stop(); pCounterRunGraph.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() Post Run Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterPostRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterPostRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::RunGraph() RunGraph Total Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterRunGraph.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterRunGraph.GetLastTime() % _100NS_IN_MS) << " ms"), "");
return NOERROR; }
HRESULT CVidCtl::DecomposeAll() { CPerfCounter pCounterDecompose; pCounterDecompose.Reset(); HRESULT hr;
if (!m_pGraph) { return NOERROR; } BOOL lRes = 0; OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); if (m_pGraph.GetState() != State_Stopped) { hr = Stop(); if (FAILED(hr)) { return Error(IDS_CANT_DECOMPOSE_GRAPH, __uuidof(IMSVidCtl), hr); } }
{ // decompose all the composites
VWSegmentList::iterator i; for (i = m_pComposites.begin(); i != m_pComposites.end(); ++i) { hr = (*i)->put_Container(NULL); ASSERT(SUCCEEDED(hr)); } m_pComposites.clear(); }
// Notify everyone to decompose
if(!!m_pInput){ hr = VWGraphSegment(m_pInput)->Decompose(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } }
{ // decompose all the features
VWFeatures::iterator i; for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { // notify them that we're decomposing
hr = VWGraphSegment(*i)->Decompose(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() can't decompose feature segment: " << (*i) << " hr = " << std::hex << hr), ""); return hr; } } }
{ // decompose all the outputs
VWOutputDevices::iterator i; for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { // notify them that we're decomposing
hr = VWGraphSegment(*i)->Decompose(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() can't decompose output segment: " << (*i) << " hr = " << std::hex << hr), ""); return hr; } } }
if (!!m_pVideoRenderer) { hr = VWGraphSegment(m_pVideoRenderer)->Decompose(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() can't decompose videorenderer segment: " << " hr = " << std::hex << hr), ""); return hr; } } if (!!m_pAudioRenderer) { hr = VWGraphSegment(m_pAudioRenderer)->Decompose(); if (FAILED(hr) && hr != E_NOTIMPL) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() can't decompose audiorenderer segment: " << " hr = " << std::hex << hr), ""); return hr; } }
TRACELM(TRACE_DETAIL, "CVidCtl::Decomose() decompose notifications issued");
m_iCompose_Input_Video = -1; m_iCompose_Input_Audio = -1;
m_fGraphDirty = true; PQMediaEventSink mes(m_pGraph); hr = mes->Notify(EC_UNBUILT, 0, 0); OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); _ASSERT(m_State == STATE_UNBUILT); pCounterDecompose.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() Death Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterDecompose.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterDecompose.GetLastTime() % _100NS_IN_MS) << " ms"), ""); return NOERROR; }
HRESULT CVidCtl::DecomposeSegment(VWGraphSegment& pSegment) { if (m_pGraph.GetState() != State_Stopped) { return HRESULT_FROM_WIN32(ERROR_INVALID_STATE); } return DecomposeAll(); }
// interface functions
STDMETHODIMP CVidCtl::get_InputsAvailable(BSTR CategoryGuid, IMSVidInputDevices * * pVal) { try { GUID2 catguid(CategoryGuid); return get__InputsAvailable(&catguid, pVal); } catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } }
STDMETHODIMP CVidCtl::get__InputsAvailable(LPCGUID CategoryGuid, IMSVidInputDevices * * pVal) { if (pVal == NULL) return E_POINTER; try { if (!m_fInit) { Init(); } } catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } try { *pVal = NULL; } catch(...) { return E_POINTER; } try { CInputDevices *p = NULL; if(m_InputsCatGuid == CategoryGuid){ p = static_cast<CInputDevices *>(m_pInputs.p); } if (!p || !p->Valid) { HRESULT hr = GetInputs(GUID2(CategoryGuid), m_pInputs); if (FAILED(hr)) { return hr; } m_InputsCatGuid = CategoryGuid; } CInputDevices *d = new CInputDevices(m_pInputs); *pVal = PQInputDevices(d).Detach(); } catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } return NOERROR; }
STDMETHODIMP CVidCtl::get_OutputsAvailable(BSTR CategoryGuid, IMSVidOutputDevices * * pVal) { try { GUID2 catguid(CategoryGuid); return get__OutputsAvailable(&catguid, pVal); } catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } }
STDMETHODIMP CVidCtl::get__OutputsAvailable(LPCGUID CategoryGuid, IMSVidOutputDevices * * pVal) { if (pVal == NULL) return E_POINTER; try { if (!m_fInit) { Init(); } } catch(ComException &e) { return e; } catch(...) { return Error(IDS_CANT_INIT, __uuidof(IMSVidCtl), IDS_CANT_INIT); } try { *pVal = NULL; } catch(...) { return E_POINTER; } try { COutputDevices *p = static_cast<COutputDevices *>(m_pOutputs.p); if (!p || !p->Valid) { HRESULT hr = GetOutputs(GUID2(CategoryGuid)); if (FAILED(hr)) { return hr; } } COutputDevices *d = new COutputDevices(m_pOutputs); *pVal = PQOutputDevices(d).Detach(); } catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } return NOERROR; }
STDMETHODIMP CVidCtl::get_VideoRenderersAvailable(IMSVidVideoRendererDevices * * pVal) { if (pVal == NULL) return E_POINTER; try { if (!m_fInit) { Init(); } } catch(ComException &e) { return e; } catch(...) { return Error(IDS_CANT_INIT, __uuidof(IMSVidCtl), IDS_CANT_INIT); } try { *pVal = NULL; } catch(...) { return E_POINTER; } try { CVideoRendererDevices *p = static_cast<CVideoRendererDevices *>(m_pVRs.p); if (!p || !p->Valid) { HRESULT hr = GetVideoRenderers(); if (FAILED(hr)) { return hr; } } CVideoRendererDevices *d = new CVideoRendererDevices(m_pVRs); if (!d) { return E_OUTOFMEMORY; } *pVal = PQVideoRendererDevices(d).Detach(); if (!*pVal) { return E_UNEXPECTED; } } catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } return NOERROR; }
STDMETHODIMP CVidCtl::get_AudioRenderersAvailable(IMSVidAudioRendererDevices * * pVal) { if (pVal == NULL) return E_POINTER; try { if (!m_fInit) { Init(); } } catch(ComException &e) { return e; } catch(...) { return Error(IDS_CANT_INIT, __uuidof(IMSVidCtl), IDS_CANT_INIT); } try { *pVal = NULL; } catch(...) { return E_POINTER; } try { CAudioRendererDevices *p = static_cast<CAudioRendererDevices *>(m_pARs.p); if (!p || !p->Valid) { HRESULT hr = GetAudioRenderers(); if (FAILED(hr)) { return hr; } } CAudioRendererDevices *d = new CAudioRendererDevices(m_pARs); if (!d) { return E_OUTOFMEMORY; } *pVal = PQAudioRendererDevices(d).Detach(); if (!*pVal) { return E_UNEXPECTED; } return NOERROR; } catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } }
STDMETHODIMP CVidCtl::get_FeaturesAvailable(IMSVidFeatures * * pVal) { if (pVal == NULL) return E_POINTER; try { if (!m_fInit) { Init(); } } catch(ComException &e) { return e; } catch(...) { return Error(IDS_CANT_INIT, __uuidof(IMSVidCtl), IDS_CANT_INIT); } try { *pVal = NULL; } catch(...) { return E_POINTER; } try { CFeatures *p = static_cast<CFeatures *>(m_pFeatures.p); if (!p || !p->Valid) { HRESULT hr = GetFeatures(); if (FAILED(hr)) { return hr; } } CFeatures *d = new CFeatures(m_pFeatures); *pVal = PQFeatures(d).Detach(); return NOERROR; } catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } }
HRESULT CVidCtl::Pause(void) { VIDPERF_FUNC; try { if (!m_pInput || !m_pGraph) { return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidCtl), IDS_OBJ_NO_INIT); } BOOL lRes = 0; OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); if (m_pGraph.IsPaused()) { return NOERROR; }
HRESULT hr = S_OK; if (m_fGraphDirty) { hr = BuildGraph(); } if (FAILED(hr)) { return hr; }
PQMediaControl pmc(m_pGraph); if (!pmc) { return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidCtl), IDS_NO_MEDIA_CONTROL); } hr = pmc->Pause(); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Pause() hr = " << std::hex << hr), ""); return Error(IDS_CANT_PAUSE_GRAPH, __uuidof(IMSVidCtl), hr); }
// This is to force the pause event to get thrown up to apps.
OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); return NOERROR;
} catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } }
HRESULT CVidCtl::Stop(void) { VIDPERF_FUNC; CPerfCounter pCounterStop; pCounterStop.Reset(); try { TRACELM(TRACE_DETAIL, "CVidCtl::Stop()"); if (!m_pInput || !m_pGraph) { return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidCtl), CO_E_NOTINITIALIZED); } BOOL lRes = 0; OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); HRESULT hr; if (!m_pGraph.IsStopped()) {
OAFilterState graphState = m_pGraph.GetState();
// Notify all segments graph is about to stop
ASSERT(m_pInput); hr = VWGraphSegment(m_pInput)->PreStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; }
if (!!m_pVideoRenderer) { hr = VWGraphSegment(m_pVideoRenderer)->PreStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } if (!!m_pAudioRenderer) { hr = VWGraphSegment(m_pAudioRenderer)->PreStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } }
{ VWOutputDevices::iterator i; for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { hr = VWGraphSegment(*i)->PreStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } { VWFeatures::iterator i; for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { hr = VWGraphSegment(*i)->PreStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } { VWSegmentList::iterator i; for(i = m_pComposites.begin(); i != m_pComposites.end(); ++i){ hr = VWGraphSegment(*i)->PreStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } if (!!m_pVideoRenderer) { m_pVideoRenderer->put_Visible(false); m_pVideoRenderer->put_Owner(0); }
// Stop the graph
PQMediaControl pmc(m_pGraph); if (!pmc) { return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidCtl), IDS_NO_MEDIA_CONTROL); } hr = pmc->Stop(); if (FAILED(hr)) { TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Stop() hr = " << std::hex << hr), ""); return Error(IDS_CANT_PAUSE_GRAPH, __uuidof(IMSVidCtl), hr); } }
// Notify all segments graph is stopped
ASSERT(m_pInput); hr = VWGraphSegment(m_pInput)->PostStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; }
if (!!m_pVideoRenderer) { hr = VWGraphSegment(m_pVideoRenderer)->PostStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } if (!!m_pAudioRenderer) { hr = VWGraphSegment(m_pAudioRenderer)->PostStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } }
{ VWOutputDevices::iterator i; for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { hr = VWGraphSegment(*i)->PostStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } { VWFeatures::iterator i; for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) { hr = VWGraphSegment(*i)->PostStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } { VWSegmentList::iterator i; for(i = m_pComposites.begin(); i != m_pComposites.end(); ++i){ hr = VWGraphSegment(*i)->PostStop(); if (FAILED(hr) && hr != E_NOTIMPL) { return hr; } } } FireViewChange(); // force refresh to repaint background immediately(black)
OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); pCounterStop.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Stop() Stop Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterStop.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterStop.GetLastTime() % _100NS_IN_MS) << " ms"), ""); return NOERROR;
} catch(ComException &e) { return e; } catch(...) { return E_UNEXPECTED; } }
// Setup events handling
// If we have a window, then send notification messages to it
// If we are windowless, then set up a timer to process the messages
void CVidCtl::SetMediaEventNotification() {
SetTimer(); if (!m_fNotificationSet) {
// If graph is built and notification hasn't been set
// then set it here
if (m_pGraph) { // Setup notification window for WM_MEDIAEVENT
HRESULT hr = m_pGraph.SetMediaEventNotificationWindow(m_pTopWin->m_hWnd, WM_MEDIAEVENT, 0); if (FAILED(hr)) { THROWCOM(E_UNEXPECTED); } m_fNotificationSet = true; } }
return; }
// actually submit changes to VR
bool CVidCtl::RefreshVRSurfaceState() { TRACELM(TRACE_PAINT, "CVidCtl::RefreshVRSurfaceState()"); if (m_pVideoRenderer) { HWND hOwner(m_CurrentSurface.Owner()); HRESULT hr = m_pVideoRenderer->put_Owner(hOwner); if (FAILED(hr) || hOwner == INVALID_HWND || !::IsWindow(hOwner)) { TRACELM(TRACE_PAINT, "CVidCtl::RefreshVRSurfaceState() unowned, vis false"); hr = m_pVideoRenderer->put_Visible(false); if (FAILED(hr)) { return false; } } else { hr = m_pVideoRenderer->put_Destination(m_CurrentSurface); if (FAILED(hr)) { return false; } hr = m_pVideoRenderer->put_Visible(m_CurrentSurface.IsVisible() ? VARIANT_TRUE : VARIANT_FALSE); if (FAILED(hr) && hr == E_FAIL) { return false; } } m_CurrentSurface.Dirty(false); } return true; }
HRESULT CVidCtl::Refresh() { try { TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::Refresh() owner = " << m_CurrentSurface.Owner()), ""); BOOL temp; if (!m_bInPlaceActive) { HRESULT hr = InPlaceActivate(OLEIVERB_INPLACEACTIVATE, NULL); if (FAILED(hr)) { return hr; } } CheckMouseCursor(temp);
ComputeDisplaySize(); SetExtents(); if (m_pVideoRenderer) { RefreshVRSurfaceState(); m_pVideoRenderer->Refresh(); } FireViewChange();
return NOERROR; } catch (...) { return E_UNEXPECTED; } }
#if 0
// old flawed OnDraw saved for reference
HRESULT CVidCtl::OnDraw(ATL_DRAWINFO& di) { try { SetTimer(); //SetMediaEventNotification();
TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" ); bool fOverlay = false; if (m_pVideoRenderer) { VARIANT_BOOL fo = VARIANT_FALSE; HRESULT hr = m_pVideoRenderer->get_UseOverlay(&fo); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't get useoverlay flag"); } fOverlay = !!fo; hr = m_pVideoRenderer->put_ColorKey(m_clrColorKey); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set color key on vr"); } #ifdef 0
hr = m_pVideoRenderer->put_BorderColor(0x0000ff); #else
hr = m_pVideoRenderer->put_BorderColor(m_clrBackColor); #endif
if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set border color on vr"); } hr = m_pVideoRenderer->put_MaintainAspectRatio(m_fMaintainAspectRatio); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set fMaintainAspectRatio on vr"); } } // undone: if we're straddling a monitor edge in the multimon case, then we treat the smaller
// portion as part of the border/background
// undone: if we're on a monitor that our input device cannot reach(video port case) then we need
// to paint the background color
// we only force overlay and tell vmr not to paint color key if we're windowless
// this allows us to put the color key in the correct z-order amongst a stack of
// multiple windowless controls. when we do this we also need to paint the letter box
// border otherwise it won't z-order right since it isn't colorkeyed.
// if we're windowed then gdi, ddraw, and the vmr deal
// with the z-order correctly so we let the vmr do the color key and border for us and we
// fill rect the bg color
// so, we have three cases
// 1: paint the whole rect the color key color
// 2: paint the whole rect the bg color
// 3: paint the video portion colorkey and the borders bg
if (di.dwDrawAspect != DVASPECT_CONTENT) { return DV_E_DVASPECT; } if (!di.hdcDraw) { return NOERROR; } CDC pdc(di.hdcDraw); TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() di.prcBounds " << *(reinterpret_cast<LPCRECT>(di.prcBounds))), ""); CRect rcBounds(reinterpret_cast<LPCRECT>(di.prcBounds)); TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), ""); long lBGColor = m_clrBackColor; TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() wndless = " << m_bWndLess << " active = " << m_bInPlaceActive << " !stopped = " << (m_pGraph ? !m_pGraph.IsStopped() : 0)), ""); if (m_bNegotiatedWnd) { if (m_bWndLess) { HWND hwndParent; if (m_spInPlaceSite && m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) { m_CurrentSurface.Owner(hwndParent); } CheckSurfaceStateChanged(CScalingRect(m_rcPos)); } else { m_CurrentSurface.Owner(m_hWndCD); CScalingRect r(::GetDesktopWindow()); if (!::GetWindowRect(m_hWndCD, &r)) { return HRESULT_FROM_WIN32(GetLastError()); } CheckSurfaceStateChanged(r); } } else { m_CurrentSurface.Site(PQSiteWindowless(m_spInPlaceSite)); CheckSurfaceStateChanged(CScalingRect(m_rcPos)); } if (m_bInPlaceActive && fOverlay) { if (m_pGraph && !m_pGraph.IsStopped()) { TRACELSM(TRACE_PAINT, (dbgDump << "CVidCtl::OnDraw() m_rcPos = " << m_rcPos << " m_cursurf = " << m_CurrentSurface), ""); TRACELSM(TRACE_PAINT, (dbgDump << "CVidCtl::OnDraw() m_cursurf rounded = " << m_CurrentSurface), ""); // get the color from the current video renderer because we always notify it
// if we've received a colorkey change but it may not notify us if one went directly to
// the vr object.
if (m_fMaintainAspectRatio) { AspectRatio src(SourceAspect()); AspectRatio surf(m_rcPos); TRACELSM(TRACE_PAINT, (dbgDump << "CVidCtl::OnDraw() Checking AR() src = " << src << " surf = " << surf), ""); if (src != surf) { CBrush hb; HBRUSH hbrc = hb.CreateSolidBrush(m_clrBackColor); if (!hbrc) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't create brush for letterbox"); THROWCOM(E_UNEXPECTED); }
TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds at border paint = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), ""); if (!pdc.FillRect(&rcBounds, hb)) { DWORD er = GetLastError(); TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill top/left letterbox rect er = " << er), ""); return HRESULT_FROM_WIN32(er); } } } lBGColor = m_clrColorKey; CRect SurfDP(m_CurrentSurface); TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() SurfDP before LPtoDP = " << SurfDP << " w = " << SurfDP.Width() << " h = " << SurfDP.Height()), ""); if (di.hicTargetDev == di.hdcDraw) { // ATL has a weird bug in the windowless case where they reset the transform
// origins of hicTargetDev inadvertently. this happens because in the windowless
// non metafile case ATLCreateTargetDC returns the existing hdcDraw instead
// of creatin a new dc so after that in CComControlBase::OnDrawAdvanced
// when the save hdcDraw and reset the origins, they change hicTargetDev
// too(since they're the same ptr).
// we undo this so that we can map in the same space and then put it back
// the way it was just to be safe
// currently, this works because in the non-metafile case atl always
// does a prior SaveDC everywhere they call the derived control's OnDraw
// since we already reject non-metafile above(it doesn't make sense for video)
// we can just check for pointer equality and temporarily undo their
// origin change and then put it back the way it was. if atl ever calls
// our ondraw for non-metafiles anywhere without doing a savedc then this
// will break bigtime.
::RestoreDC(di.hdcDraw, -1); } if (!::LPtoDP(di.hicTargetDev, reinterpret_cast<LPPOINT>(&SurfDP), 2)) { DWORD er = GetLastError(); TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't LPToDP current surf er = " << er), ""); return HRESULT_FROM_WIN32(er); } if (di.hicTargetDev == di.hdcDraw) { // restore the window state as per the above comment block
SaveDC(di.hdcDraw); SetMapMode(di.hdcDraw, MM_TEXT); SetWindowOrgEx(di.hdcDraw, 0, 0, NULL); SetViewportOrgEx(di.hdcDraw, 0, 0, NULL); } TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() SurfDP after LPtoDP = " << SurfDP << " w = " << SurfDP.Width() << " h = " << SurfDP.Height()), ""); #if 1
TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds prior to boundary intersect = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), ""); rcBounds.IntersectRect(&SurfDP); TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds after to boundary intersect = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), ""); #endif
} } else { if (m_pGraph && !m_pGraph.IsStopped()) { lBGColor = m_clrColorKey; if (m_pVideoRenderer) { m_pVideoRenderer->RePaint(di.hdcDraw); pdc = NULL; // don't delete the DC, it isn't ours
return S_OK; } } } CBrush hb; HBRUSH hbrc = hb.CreateSolidBrush(lBGColor); if (!hbrc) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't create brush for mainrect"); THROWCOM(E_UNEXPECTED); }
TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds at main paint = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), ""); TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() bkcolor = " << hexdump(lBGColor)), "");
if (!pdc.FillRect(&rcBounds, hb)) { DWORD er = GetLastError(); TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill main video rect er = " << er), ""); return HRESULT_FROM_WIN32(er); } pdc = NULL; // don't delete the DC, it isn't ours
return S_OK; } catch(...) { return E_UNEXPECTED; }
}
#else
HRESULT CVidCtl::OnDrawAdvanced(ATL_DRAWINFO& di) { try { SetTimer(); TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" ); bool fOverlay = false; if (m_pVideoRenderer) { VARIANT_BOOL fo = VARIANT_FALSE; HRESULT hr = m_pVideoRenderer->get_UseOverlay(&fo); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't get useoverlay flag"); } fOverlay = !!fo; hr = m_pVideoRenderer->put_ColorKey(m_clrColorKey); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set color key on vr"); } #if 0
hr = m_pVideoRenderer->put_BorderColor(0x0000ff); #else
hr = m_pVideoRenderer->put_BorderColor(m_clrBackColor); #endif
if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set border color on vr"); } hr = m_pVideoRenderer->put_MaintainAspectRatio(m_fMaintainAspectRatio); if (FAILED(hr)) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set fMaintainAspectRatio on vr"); } }
if (di.dwDrawAspect != DVASPECT_CONTENT) { return DV_E_DVASPECT; } if (!di.hdcDraw) { return NOERROR; }
// we only default to force overlay if we're windowless, but overlay is an independently controllable
// boolean property that can be overriden. based on this, if we're in useoverlay == true mode
// then we tell vmr not to paint color key. if we don't have an rgb overlay available that vmr
// event causes useoverlay to go false.
// when we have the overlay, this allows us to put the color key in the correct z-order
// amongst a stack of multiple windowless controls such as html page elements in IE.
// when we do this we also need to paint the letter box
// border otherwise it won't z-order right since it isn't colorkeyed.
// if we're windowed then gdi, ddraw, and the vmr deal
// with the z-order correctly so we let the vmr do the color key and border for us and we
// fill rect the bg color
// so, we have three cases
// 1: paint the whole rect the color key color
// 2: paint the whole rect the bg color
// 3: paint the video portion colorkey and the borders bg
TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() wndless = " << m_bWndLess << " active = " << m_bInPlaceActive << " !stopped = " << (m_pGraph ? !m_pGraph.IsStopped() : 0) << " mar = " << m_fMaintainAspectRatio), ""); CSize szSrc; GetSourceSize(szSrc); CRect rctSrc(0, 0, szSrc.cx, szSrc.cy); // rectangle representing the actual source size(and aspect ratio)
// in zero top-left coords
TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rctSrc = " << rctSrc), "");
CScalingRect rctOuterDst(reinterpret_cast<LPCRECT>(di.prcBounds)); // rectangle representing our paint area in client device coords
TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rctOuterDst = " << rctOuterDst), ""); CScalingRect rctInnerDst(rctOuterDst); // rectangle representing where the video goes that we pass through
// to the VMR in client logical coords. assume its the whole
// paint area for now
CScalingRect rctTLBorder(0, 0, 0, 0); // rectangle representing our top/left letter box(if necessary) in client logical coords
CScalingRect rctBRBorder(0, 0, 0, 0); // rectangle representing our bottom/left letter box(if necessary) in client logical coords
CDC pdc(di.hdcDraw); long lInnerColor = m_clrBackColor; #if 0
if (!m_bNegotiatedWnd) { if (!rctOuterDst) { // pull rctOuterDst from site
// m_CurrentSurface.Site(PQSiteWindowless(m_spInPlaceSite));
// CheckSurfaceStateChanged(CScalingRect(m_rcPos));
} } #endif
if (m_bInPlaceActive) { if (fOverlay) { if (m_pGraph && !m_pGraph.IsStopped()) { TRACELM(TRACE_PAINT, "CVidCtl::OnDraw() letterboxing"); // get the color from the current video renderer because we always notify it
// if we've received a colorkey change but it may not notify us if one went directly to
// the vr object.
lInnerColor = m_clrColorKey; if (m_fMaintainAspectRatio) { ComputeAspectRatioAdjustedRects(rctSrc, rctOuterDst, rctInnerDst, rctTLBorder, rctBRBorder); ASSERT((!rctTLBorder && !rctBRBorder) || (rctTLBorder && rctBRBorder)); // both zero or both valid
if (rctTLBorder && rctBRBorder) { CBrush lb; HBRUSH hbrc = lb.CreateSolidBrush(m_clrBackColor); if (!hbrc) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't create brush for letterbox borders"); THROWCOM(E_UNEXPECTED); } if (!pdc.FillRect(rctTLBorder, lb)) { DWORD er = GetLastError(); TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill rctTLBorder er = " << er), ""); return HRESULT_FROM_WIN32(er); } if (!pdc.FillRect(rctBRBorder, lb)) { DWORD er = GetLastError(); TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill rctBRBorder er = " << er), ""); return HRESULT_FROM_WIN32(er); } } } } } else { if (m_pGraph && !m_pGraph.IsStopped()) { TRACELM(TRACE_PAINT, "CVidctrl::OnDraw() vmr repaint"); lInnerColor = m_clrColorKey; if (m_pVideoRenderer) { CheckSurfaceStateChanged(rctInnerDst); m_pVideoRenderer->RePaint(di.hdcDraw); pdc = NULL; // don't delete the DC, it isn't ours
return S_OK; } } } } CheckSurfaceStateChanged(rctInnerDst); CBrush hb; HBRUSH hbrc = hb.CreateSolidBrush(lInnerColor); if (!hbrc) { TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't create brush for mainrect"); THROWCOM(E_UNEXPECTED); }
TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rctInnerDst at main paint = " << rctInnerDst), ""); TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() innercolor = " << hexdump(lInnerColor)), "");
if (!pdc.FillRect(rctInnerDst, hb)) { DWORD er = GetLastError(); TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill main video rect er = " << er), ""); return HRESULT_FROM_WIN32(er); } pdc = NULL; // don't delete the DC, it isn't ours
return S_OK; } catch(...) { return E_UNEXPECTED; }
}
#endif
// this code is taken from the vmr utility library alloclib function LetterBoxDstRect().
// its been modified to match my variable names, do inline __int64 arithmetic, use ATL CRect references,
// and always compute borders.
void CVidCtl::ComputeAspectRatioAdjustedRects(const CRect& rctSrc, const CRect& rctOuterDst, CRect& rctInnerDst, CRect& rctTLBorder, CRect& rctBRBorder) { // figure out src/dest scale ratios
int iSrcWidth = rctSrc.Width(); int iSrcHeight = rctSrc.Height();
int iOuterDstWidth = rctOuterDst.Width(); int iOuterDstHeight = rctOuterDst.Height();
int iInnerDstWidth; int iInnerDstHeight;
//
// work out if we are Column or Row letter boxing
//
__int64 iWHTerm = iSrcWidth * (__int64)iOuterDstHeight; iWHTerm /= iSrcHeight; if (iWHTerm <= iOuterDstWidth) {
//
// column letter boxing - we add border color bars to the
// left and right of the video image to fill the destination
// rectangle.
//
iWHTerm = iOuterDstHeight * (__int64)iSrcWidth; iInnerDstWidth = iWHTerm / iSrcHeight; iInnerDstHeight = iOuterDstHeight; TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::ComputeAspectRatioAdjustedRects() col lb iw = " << iInnerDstWidth << " ih = " << iInnerDstHeight), ""); } else {
//
// row letter boxing - we add border color bars to the top
// and bottom of the video image to fill the destination
// rectangle
//
iWHTerm = iOuterDstWidth * (__int64)iSrcHeight; iInnerDstHeight = iWHTerm / iSrcWidth; iInnerDstWidth = iOuterDstWidth; TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::ComputeAspectRatioAdjustedRects() row lb iw = " << iInnerDstWidth << " ih = " << iInnerDstHeight), ""); }
//
// now create a centered inner letter-boxed rectangle within the current outer destination rect
//
rctInnerDst.left = rctOuterDst.left + ((iOuterDstWidth - iInnerDstWidth) / 2); rctInnerDst.right = rctInnerDst.left + iInnerDstWidth;
rctInnerDst.top = rctOuterDst.top + ((iOuterDstHeight - iInnerDstHeight) / 2); rctInnerDst.bottom = rctInnerDst.top + iInnerDstHeight;
//
// Fill out the border rects
//
if (rctOuterDst.top != rctInnerDst.top) { // border is on the top
rctTLBorder = CRect(rctOuterDst.left, rctOuterDst.top, rctInnerDst.right, rctInnerDst.top); } else { // border is on the left
rctTLBorder = CRect(rctOuterDst.left, rctOuterDst.top, rctInnerDst.left, rctInnerDst.bottom); }
if (rctOuterDst.top != rctInnerDst.top) { // border is on the bottom
rctBRBorder = CRect(rctInnerDst.left, rctInnerDst.bottom, rctOuterDst.right, rctOuterDst.bottom); } else { // border is on the right
rctBRBorder = CRect(rctInnerDst.right, rctInnerDst.top, rctOuterDst.right, rctOuterDst.bottom); }
return; }
LRESULT CVidCtl::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = false; m_CurrentSurface.Visible(wParam != 0); TRACELSM(TRACE_DETAIL, (dbgDump << "CVidctrl::OnShowWindow() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" ); RefreshVRSurfaceState(); return 0; }
LRESULT CVidCtl::OnMoveWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = false; CSize cursize(m_CurrentSurface.Width(), m_CurrentSurface.Height()); HWND parent = ::GetParent(m_CurrentSurface.Owner()); POINTS p(MAKEPOINTS(lParam)); CPoint pt(p.x, p.y); CScalingRect newpos(pt, cursize, parent); ::InvalidateRect(m_CurrentSurface.Owner(), newpos, false); // force repaint to recalc letterboxing, etc.
TRACELSM(TRACE_DETAIL, (dbgDump << "CVidctrl::OnMoveWindow() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" ); return 0; }
LRESULT CVidCtl::OnSizeWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = false; CScalingRect newsize(m_CurrentSurface.TopLeft(), CSize(lParam), m_CurrentSurface.Owner()); ::InvalidateRect(m_CurrentSurface.Owner(), newsize, false); // force repaint to recalc letterboxing, etc.
TRACELSM(TRACE_DETAIL, (dbgDump << "CVidctrl::OnSizeWindow() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" ); return 0; }
LRESULT CVidCtl::OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = false; m_CurrentSurface.WindowPos(reinterpret_cast<LPWINDOWPOS>(lParam)); TRACELSM(TRACE_DETAIL, (dbgDump << "CVidctrl::OnWindowPosChanged() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" ); ::InvalidateRect(m_CurrentSurface.Owner(), m_CurrentSurface, false); // force repaint to recalc letterboxing, etc.
return 0; }
LRESULT CVidCtl::OnTerminate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { Stop(); KillTimer(); bHandled = false; return 0; }
#if 0
[id(DISPID_CLICK)] void Click(); [id(DISPID_DBLCLICK)] void DblClick(); [id(DISPID_KEYDOWN)] void KeyDown(short* KeyCode, short Shift); [id(DISPID_KEYPRESS)] void KeyPress(short* KeyAscii); [id(DISPID_KEYUP)] void KeyUp(short* KeyCode, short Shift); [id(DISPID_MOUSEDOWN)] void MouseDown(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y); [id(DISPID_MOUSEMOVE)] void MouseMove(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y); [id(DISPID_MOUSEUP)] void MouseUp(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y); [id(DISPID_ERROREVENT)] void Error(short Number, BSTR* Description, long Scode, BSTR Source, BSTR HelpFile, long HelpContext, boolean* CancelDisplay); #endif
LRESULT CVidCtl::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_TimerID == wParam) { if (m_bNegotiatedWnd) { if (!m_bWndLess) { if (m_CurrentSurface.Width() && m_CurrentSurface.Height()) { CScalingRect prevpos(m_CurrentSurface); prevpos.Owner(::GetDesktopWindow()); CScalingRect curpos(::GetDesktopWindow()); if (!::GetWindowRect(m_CurrentSurface.Owner(), &curpos)) { return HRESULT_FROM_WIN32(GetLastError()); } if (curpos != prevpos) { FireViewChange(); // force a repaint
} } } }
BOOL lRes = 0; if (m_pGraph) { // as long as we're here, check for events too.
OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes); }
bHandled = true; } else { bHandled = false; } return 0; }
LRESULT CVidCtl::OnPNP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // undone: implement pnp support
return 0; }
LRESULT CVidCtl::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return CheckMouseCursor(bHandled); }
LRESULT CVidCtl::OnPower(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // undone: implement rational power management support
return 0; }
LRESULT CVidCtl::OnDisplayChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_pVideoRenderer) { m_pVideoRenderer->DisplayChange(); FireViewChange(); } return 0; }
HRESULT CVidCtl::OnPreEventNotify(LONG lEvent, LONG_PTR LParam1, LONG_PTR LParam2){ try{ TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify ev = " << hexdump(lEvent)), ""); TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify lp1 = " << hexdump(LParam1)), ""); TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify lp2 = " << hexdump(LParam2)), ""); MSVidCtlStateList prevstate = m_State; MSVidCtlStateList newstate = m_State; // Events where stop is the new state
if (lEvent == EC_BUILT) { prevstate = STATE_UNBUILT; newstate = STATE_STOP; } if (lEvent == EC_STATE_CHANGE && LParam1 == State_Stopped) { newstate = STATE_STOP; } // Events where play is the new state
if (lEvent == EC_STATE_CHANGE && LParam1 == State_Running) { newstate = STATE_PLAY; } // Events where unbuilt is the new state
if( lEvent == EC_UNBUILT ) { newstate = STATE_UNBUILT; } // Events where paused is the new state
if( lEvent == EC_STATE_CHANGE && LParam1 == State_Paused ) { newstate = STATE_PAUSE; } if( lEvent == EC_PAUSED ){ TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify EC_PAUSED"), ""); } if (newstate != prevstate) { m_State = newstate; Fire_StateChange(prevstate, m_State); } if (lEvent == EC_DISPLAY_CHANGED) { ComputeDisplaySize(); } if (lEvent == EC_VMR_RECONNECTION_FAILED){ TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify EC_VMR_RECONNECTION_FAILED"), ""); HRESULT hr = Stop(); if(FAILED(hr)){ return hr; } return Error(IDS_NOT_ENOUGH_VIDEO_MEMORY, __uuidof(IMSVidCtl), IDS_NOT_ENOUGH_VIDEO_MEMORY); } if(lEvent == EC_COMPLETE){ TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify EC_COMPLETE"), ""); } // undone: recompute displaysize if video source changes
} catch (HRESULT hr){ return hr; } catch (...){ return E_UNEXPECTED; } return E_NOTIMPL; }
HRESULT CVidCtl::OnPostEventNotify(LONG lEvent, LONG_PTR LParam1, LONG_PTR LParam2){ try{ if (lEvent == EC_VMR_RENDERDEVICE_SET) { #if 0
CSize s; GetSourceSize(s); TRACELSM(TRACE_DEBUG, (dbgDump << "CVidCtl::OnPostEventNotify() VMR_RENDERDEVICE_SET srcrect = " << s), ""); #endif
Refresh(); } } catch (HRESULT hr){ return hr; } catch (...){ return E_UNEXPECTED; } return E_NOTIMPL; }
LRESULT CVidCtl::OnMediaEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
PQMediaEventEx pme(m_pGraph); LONG lEvent; LONG_PTR lParam1, lParam2; HRESULT hr2; try{ if (!pme) { return E_UNEXPECTED; } hr2 = pme->GetEvent(&lEvent, &lParam1, &lParam2, 0); while (SUCCEEDED(hr2)){ TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::OnMediaevent ev = " << hexdump(lEvent) << " lp1 = " << hexdump(lParam1) << " lp2 = " << hexdump(lParam2)), ""); HRESULT hr; /*** Check who wants the Event ***/ /*** If they want it should return something other than E_NOTIMPL ***/
// Does CVidCtl want it?
hr = OnPreEventNotify(lEvent, lParam1, lParam2);
//Does the input want it?
if(hr == E_NOTIMPL){ PQGraphSegment pSeg(m_pInput); if (pSeg) { hr = pSeg->OnEventNotify(lEvent, lParam1, lParam2); } }
// Do any of the features want it?
if (hr == E_NOTIMPL) {
for ( VWFeatures::iterator i = m_pFeaturesInUse.begin(); hr == E_NOTIMPL && i != m_pFeaturesInUse.end(); ++i) { hr = PQGraphSegment((*i).punkVal)->OnEventNotify(lEvent, lParam1, lParam2); } }
//Does the video renderer want it?
if(hr == E_NOTIMPL){ PQGraphSegment pSeg(m_pVideoRenderer); if(pSeg){ hr = pSeg->OnEventNotify(lEvent, lParam1, lParam2); } }
// Does the audio renderer want it?
if(hr == E_NOTIMPL){ PQGraphSegment pSeg(m_pAudioRenderer); if(pSeg){ hr = pSeg->OnEventNotify(lEvent, lParam1, lParam2); } }
// Do any of the outputs want it?
if(hr == E_NOTIMPL){ if (!!m_pOutputsInUse && m_pOutputsInUse.begin() != m_pOutputsInUse.end()) { for (VWOutputDevices::iterator i = m_pOutputs.begin(); hr == E_NOTIMPL && i != m_pOutputs.end(); ++i) { hr = PQGraphSegment((*i).punkVal)->OnEventNotify(lEvent, lParam1, lParam2); } } }
// Finally do any of the composites want it?
if(hr == E_NOTIMPL){ for(VWSegmentList::iterator i = m_pComposites.begin(); hr == E_NOTIMPL && i != m_pComposites.end(); i++){ hr = PQGraphSegment(*i)->OnEventNotify(lEvent, lParam1, lParam2); } }
// Check again to see if CVidCtl want to do anything else regardless of whether or not
// it got handled by a segment
hr = OnPostEventNotify(lEvent, lParam1, lParam2);
//
// Remember to free the event params
//
pme->FreeEventParams(lEvent, lParam1, lParam2) ; hr2 = pme->GetEvent(&lEvent, &lParam1, &lParam2, 0); } } catch (HRESULT hr){ return hr; } catch (...){ return E_UNEXPECTED; } return 0; }
// rev2: if we ever redist to 9x then we need to examine the mfc dbcs processing
// and adapt it.
LRESULT CVidCtl::OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { //(UINT nChar, UINT nRepCnt, UINT nFlags)
SHORT nCharShort = LOWORD(wParam); HRESULT hr = NOERROR; if (m_pInputNotify) { hr = m_pInputNotify->KeyPress(&nCharShort); } if (hr != S_FALSE) { Fire_KeyPress(&nCharShort); } if (!nCharShort) { return 0; }
return 1; }
LRESULT CVidCtl::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (!(KF_REPEAT & HIWORD(lParam))) { short keycode = LOWORD(wParam); short shiftstate = GetShiftState(); HRESULT hr = NOERROR; if (m_pInputNotify) { hr = m_pInputNotify->KeyDown(&keycode, shiftstate); } if (hr != S_FALSE) { Fire_KeyDown(&keycode, shiftstate); } if (!keycode) { return 0; } }
return 1; }
LRESULT CVidCtl::OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { short keycode = LOWORD(wParam); short shiftstate = GetShiftState(); HRESULT hr = NOERROR; if (m_pInputNotify) { hr = m_pInputNotify->KeyUp(&keycode, shiftstate); } if (hr != S_FALSE) { Fire_KeyUp(&keycode, shiftstate); } if (!keycode) { return 0; }
return 1; }
// undone: syskey stuff
LRESULT CVidCtl::OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (!m_bUIActive) { m_bPendingUIActivation = true; }
return 1; }
LRESULT CVidCtl::OnCancelMode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { SetControlFocus(false); SetControlCapture(false); m_bPendingUIActivation = false;
return 1; }
LRESULT CVidCtl::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT /*nFlags*/, CPoint point)
{ CheckMouseCursor(bHandled); CPoint point(lParam); HRESULT hr = NOERROR; if (m_pInputNotify) { hr = m_pInputNotify->MouseMove(m_usButtonState, m_usShiftState, point.x, point.y); } if (hr != S_FALSE) { Fire_MouseMove(m_usButtonState, m_usShiftState, point.x, point.y); }
return 1; }
LRESULT CVidCtl::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonDown(MSVIDCTL_LEFT_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonUp(MSVIDCTL_LEFT_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonDblClk(MSVIDCTL_LEFT_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnMButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonDown(MSVIDCTL_MIDDLE_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnMButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonUp(MSVIDCTL_MIDDLE_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnMButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonDblClk(MSVIDCTL_MIDDLE_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonDown(MSVIDCTL_RIGHT_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonUp(MSVIDCTL_RIGHT_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnRButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ OnButtonDblClk(MSVIDCTL_RIGHT_BUTTON, wParam, lParam);
return 1; }
LRESULT CVidCtl::OnXButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ UINT button = HIWORD(wParam); if (button & XBUTTON1) { OnButtonDown(MSVIDCTL_X_BUTTON1, wParam, lParam); } else { OnButtonDown(MSVIDCTL_X_BUTTON2, wParam, lParam); }
return 1; }
LRESULT CVidCtl::OnXButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ UINT button = HIWORD(wParam); if (button & XBUTTON1) { OnButtonUp(MSVIDCTL_X_BUTTON1, wParam, lParam); } else { OnButtonUp(MSVIDCTL_X_BUTTON2, wParam, lParam); }
return 1; }
LRESULT CVidCtl::OnXButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //(UINT nFlags, CPoint point)
{ UINT button = HIWORD(wParam); if (button & XBUTTON1) { OnButtonDblClk(MSVIDCTL_X_BUTTON1, wParam, lParam); } else { OnButtonDblClk(MSVIDCTL_X_BUTTON2, wParam, lParam); }
return 1; }
void CVidCtl::OnButtonDown(USHORT nButton, UINT nFlags, CPoint point) { if (nButton == MSVIDCTL_LEFT_BUTTON) { if (m_bWndLess || m_bUIActive || m_bPendingUIActivation) { SetControlFocus(true); } } if (!m_usButtonState && (m_bUIActive || m_bPendingUIActivation)) { SetControlCapture(true); }
m_usButtonState |= nButton;
HRESULT hr = NOERROR; if (m_pInputNotify) { hr = m_pInputNotify->MouseDown(m_usButtonState, m_usShiftState, point.x, point.y); } if (hr != S_FALSE) { Fire_MouseDown(m_usButtonState, m_usShiftState, point.x, point.y); }
m_iDblClkState &= ~nButton;
return; }
void CVidCtl::OnButtonUp(USHORT nButton, UINT nFlags, CPoint point) { m_usButtonState &= nButton;
if (!m_usButtonState) { SetControlCapture(false); }
HRESULT hr = NOERROR; if (m_pInputNotify) { hr = m_pInputNotify->MouseUp(m_usButtonState, m_usShiftState, point.x, point.y); } if (hr != S_FALSE) { Fire_MouseUp(m_usButtonState, m_usShiftState, point.x, point.y); }
if (!(m_iDblClkState & nButton)) { bool bHitUs = false; if (m_bWndLess) { bHitUs = !!::PtInRect(&m_rcPos, point); } else if (m_hWnd && ::IsWindow(m_hWnd)) { CRect rect; GetClientRect(&rect); bHitUs = !!rect.PtInRect(point); } if (!bHitUs) { return; } hr = NOERROR; if (m_pInputNotify) { hr = m_pInputNotify->Click(); } if (hr != S_FALSE) { Fire_Click(); } if (!m_bInPlaceActive) { InPlaceActivate(OLEIVERB_INPLACEACTIVATE, NULL); } else if (!m_bUIActive && m_bPendingUIActivation) { InPlaceActivate(OLEIVERB_UIACTIVATE, NULL); } m_bPendingUIActivation = FALSE; } else { m_iDblClkState &= ~nButton; }
return; }
void CVidCtl::OnButtonDblClk(USHORT nButton, UINT nFlags, CPoint point) { HRESULT hr = NOERROR; if (m_pInputNotify) { hr = m_pInputNotify->DblClick(); }
if (hr != S_FALSE) { Fire_DblClick(); }
m_iDblClkState |= nButton; if (!m_bInPlaceActive) { InPlaceActivate(OLEIVERB_INPLACEACTIVATE, NULL); } else if (!m_bUIActive && m_bPendingUIActivation){ InPlaceActivate(OLEIVERB_UIACTIVATE, NULL); }
m_bPendingUIActivation = FALSE;
return; }
// this routine sets up all the crossbar routing so the streams coming out of the
// input get where they're supposed to go
HRESULT CVidCtl::RouteStreams() { VIDPERF_FUNC; int isEncoder = -1; VWStream vpath; VWStream apath; // See how far we have to route the audio/video
CComQIPtr<IMSVidAnalogTuner> qiITV(m_pInput); if(!!qiITV){ CComQIPtr<ITuneRequest> qiTR; HRESULT hr = qiITV->get_Tune(&qiTR); if(SUCCEEDED(hr)){ qiITV->put_Tune(qiTR); } } // undone: in win64 size() is really __int64. fix output operator for
// that type and remove cast
{ if (!!m_pOutputsInUse && m_pOutputsInUse.begin() != m_pOutputsInUse.end()) {
for (VWOutputDevices::iterator i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) { CComQIPtr<IMSVidOutputDevice> pqODev = VWGraphSegment(*i); if(!pqODev){ return E_UNEXPECTED; }
GUID2 outputID; HRESULT hr = pqODev->get__ClassID(&outputID); if(FAILED(hr)){ return hr; }
if(outputID == CLSID_MSVidStreamBufferSink){ CComQIPtr<IMSVidStreamBufferSink> pqTSSink(pqODev); hr = pqTSSink->NameSetLock(); if(FAILED(hr)){ return hr; } }
} } } // undone: other dest segments
return NOERROR; }
#if 0
CString CVidCtl::GetMonitorName(HMONITOR hm) { MONITORINFOEX mi; mi.cbSize = sizeof(mi); if (!GetMonitorInfo(hm, &mi)) { THROWCOM(HRESULT_FROM_WIN32(GetLastError())); } return CString(mi.szDevice); }
HRESULT CVidCtl::GetDDrawNameForMonitor(HMONITOR hm, VMRGUID& guid) { PQVMRMonitorConfig pmc(m_pVideoRenderer); if (!pmc) { return E_UNEXPECTED; // should always exist by now
} DWORD dwCount; HRESULT hr = pmc->GetAvailableMonitors(NULL, 0, &dwCount); if (FAILED(hr)) { return hr; } VMRMONITORINFO* pInfo = reinterpret_cast<VMRMONITORINFO*>(_alloca(sizeof(VMRMONITORINFO) * dwCount)); if (!pInfo) { return E_OUTOFMEMORY; } hr = pmc->GetAvailableMonitors(pInfo, dwCount, &dwCount); if (FAILED(hr)) { return hr; } CString csMonitorName(GetMonitorName(hm));
for (int i = 0; i < dwCount; ++i) { CString csDevName(pInfo[i].szDevice); if (csDevName == csMonitorName) break; } if (i >= dwCount) { // no ddraw device exist with a name which matches the monitor name
return HRESULT_FROM_WIN32(ERROR_DEV_NOT_EXIST); } guid = pInfo[i].guid; return NOERROR; }
HRESULT CVidCtl::GetCapsForMonitor(HMONITOR hm, LPDDCAPS pDDCaps) { VMRGUID ddname; HRESULT hr = GetDDrawNameForMonitor(hm, ddname); if (FAILED(hr)) { return hr; } PQDirectDraw7 pDD; hr = DirectDrawCreateEx(ddname.pGUID, reinterpret_cast<LPVOID*>(&pDD), IID_IDirectDraw7, NULL); if (FAILED(hr)) { return hr; } return pDD->GetCaps(pDDCaps, NULL); }
bool CVidCtl::MonitorHasHWOverlay(HMONITOR hm) { DDCAPS caps; HRESULT hr = GetCapsForMonitor(hm, &caps); if (SUCCEEDED(hr)) { // undone: if caps include hw overlay {
// return true;
// }
} return false; }
bool CVidCtl::WindowHasHWOverlay(HWND hWnd) { #if 0 // undone: turn on when finished
DWORD dwFlags = MONITOR_DEFAULT_TO_NEAREST if (hWnd == INVALID_HWND_VALUE) { // if we don't have an hwnd yet, assume the primary
hWnd = HWND_DESKTOP; dwFlags = MONITOR_DEFAULT_TO_PRIMARY; } HMONITOR hm = ::MonitorFromWindow(hWnd, dwFlags); return MonitorHasHWOverlay(hm); #else
return true; // mimic current behavior
#endif
} #endif
// ISupportsErrorInfo
STDMETHODIMP CVidCtl::InterfaceSupportsErrorInfo(REFIID riid) { static const IID* arr[] = { &__uuidof(IMSVidCtl), }; for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++) { if (InlineIsEqualGUID(*arr[i], riid)) return S_OK; } return S_FALSE; } STDMETHODIMP CVidCtl::put_ServiceProvider(/*[in]*/ IUnknown * pServiceP){ if(!pServiceP){ punkCert.Release(); return S_FALSE; } punkCert = pServiceP; if(!punkCert){ return E_NOINTERFACE; } return S_OK; } STDMETHODIMP CVidCtl::QueryService(REFIID service, REFIID iface, LPVOID* ppv) { if (service == __uuidof(IWMReader) && iface == IID_IUnknown && (VWGraphSegment(m_pInput).ClassID() == CLSID_MSVidFilePlaybackDevice || VWGraphSegment(m_pInput).ClassID() == CLSID_MSVidStreamBufferSource)) { if (!!punkCert) { return punkCert.CopyTo(ppv); } } PQServiceProvider psp(m_spInPlaceSite); if (!psp) { if (m_spClientSite) { HRESULT hr = m_spClientSite->QueryInterface(IID_IServiceProvider, reinterpret_cast<LPVOID*>(&psp)); if (FAILED(hr)) { return E_FAIL; } } else { return E_FAIL; } } return psp->QueryService(service, iface, ppv); } HRESULT CVidCtl::SetClientSite(IOleClientSite *pClientSite){ if(!!pClientSite){ HRESULT hr = IsSafeSite(pClientSite); if(FAILED(hr)){ return hr; } } return IOleObjectImpl<CVidCtl>::SetClientSite(pClientSite); }
#if 0
HRESULT CVidCtl::DoVerb(LONG iVerb, LPMSG pMsg, IOleClientSite* pActiveSite, LONG linddex, HWND hwndParent, LPCRECT lprcPosRect){ if(!m_spClientSite){ return E_FAIL; } else{ return IOleObjectImpl<CVidCtl>::DoVerb(iVerb, pMsg, pActiveSite, linddex, hwndParent, lprcPosRect); } } #endif
#endif //TUNING_MODEL_ONLY
// end of file - VidCtl.cpp
|