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

3063 lines
114 KiB
C++

//===========================================================================
//
// 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