669 lines
22 KiB
C++
669 lines
22 KiB
C++
|
//==========================================================================;
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation 1999-2000.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------;
|
||
|
//
|
||
|
// MSVidTVTuner.cpp : Implementation of CMSVidTVTuner
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#ifndef TUNING_MODEL_ONLY
|
||
|
|
||
|
|
||
|
|
||
|
#include "perfcntr.h"
|
||
|
#include "MSVidCtl.h"
|
||
|
#include "MSVidTVTuner.h"
|
||
|
#include <bdamedia.h>
|
||
|
#include "segimpl.h"
|
||
|
#include "segimpl.h"
|
||
|
#include "devices.h"
|
||
|
|
||
|
|
||
|
const ULONG t_SVIDEO = 0;
|
||
|
const ULONG t_COMPOSITE = 1;
|
||
|
const ULONG t_TUNER = 2;
|
||
|
DEFINE_EXTERN_OBJECT_ENTRY(CLSID_MSVidAnalogTunerDevice, CMSVidTVTuner)
|
||
|
|
||
|
const int DEFAULT_ANALOG_CHANNEL = 4;
|
||
|
|
||
|
typedef CComQIPtr<IMSVidCtl> PQMSVidCtl;
|
||
|
typedef CComQIPtr<IMSVidVideoRenderer> PQMSVidVideoRenderer;
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CMSVidTVTuner
|
||
|
|
||
|
STDMETHODIMP CMSVidTVTuner::Decompose(){
|
||
|
m_bRouted = false;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CMSVidTVTuner::ChannelAvailable(LONG nChannel, LONG * SignalStrength, VARIANT_BOOL * fSignalPresent){
|
||
|
VIDPERF_FUNC;
|
||
|
if(!SignalStrength || !fSignalPresent){
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
CComQIPtr<IAMAnalogVideoDecoder> qi_VidDec(m_Filters[m_iCapture]);
|
||
|
if(qi_VidDec){
|
||
|
long signal = FALSE;
|
||
|
HRESULT hr = qi_VidDec->get_HorizontalLocked(&signal);
|
||
|
if(FAILED(hr)){
|
||
|
return hr;
|
||
|
}
|
||
|
*fSignalPresent = signal ? VARIANT_TRUE:VARIANT_FALSE;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CMSVidTVTuner::InterfaceSupportsErrorInfo(REFIID riid)
|
||
|
{
|
||
|
static const IID* arr[] =
|
||
|
{
|
||
|
&IID_IMSVidAnalogTuner
|
||
|
};
|
||
|
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
|
||
|
{
|
||
|
if (InlineIsEqualGUID(*arr[i],riid))
|
||
|
return S_OK;
|
||
|
}
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
STDMETHODIMP CMSVidTVTuner::put_Tune(ITuneRequest *pTR) {
|
||
|
VIDPERF_FUNC;
|
||
|
TRACELM(TRACE_DETAIL, "CMSVidTVTuner<>::put_Tune()");
|
||
|
if (!m_fInit) {
|
||
|
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidTuner), CO_E_NOTINITIALIZED);
|
||
|
}
|
||
|
if (!pTR) {
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
try {
|
||
|
TNTuneRequest req(pTR);
|
||
|
ASSERT(req);
|
||
|
// This whole next section would be nice to check, but due to aux in
|
||
|
// the Tuning Space may change
|
||
|
/*if (m_TS) {
|
||
|
// if this tuner has been initialized propertly it will have a tuning space
|
||
|
// that it handles already specified. in that case, we should only
|
||
|
// handle tune requests for our ts
|
||
|
TNTuningSpace ts(req.TuningSpace());
|
||
|
if (ts != m_TS) {
|
||
|
return ImplReportError(__uuidof(T), IDS_INVALID_TS, __uuidof(IMSVidTuner), E_INVALIDARG);
|
||
|
}
|
||
|
} else {
|
||
|
// undone: if dev init is correct this case should never occur
|
||
|
// return E_UNEXPECTED;
|
||
|
}
|
||
|
*/
|
||
|
HRESULT hr = S_OK;
|
||
|
PQVidCtl pqCtl;
|
||
|
if(!!m_pContainer){
|
||
|
hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast<void**>(&pqCtl));
|
||
|
if(FAILED(hr)){
|
||
|
return hr;
|
||
|
}
|
||
|
MSVidCtlStateList curState = STATE_UNBUILT;
|
||
|
hr = pqCtl->get_State(&curState);
|
||
|
if(SUCCEEDED(hr) && curState > STATE_STOP){
|
||
|
hr = DoTune(req);
|
||
|
}
|
||
|
else{
|
||
|
m_bRouted = false;
|
||
|
hr = NOERROR;
|
||
|
}
|
||
|
}
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
m_pCurrentTR = req;
|
||
|
m_pCurrentTR.Clone();
|
||
|
if (!m_TS) {
|
||
|
// undone: this is bad. temporary hack until dev init is correct.
|
||
|
m_TS = req.TuningSpace();
|
||
|
m_TS.Clone();
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
} catch(...) {
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
HRESULT CMSVidTVTuner::UpdateTR(TNTuneRequest &tr) {
|
||
|
TNChannelTuneRequest ctr(tr);
|
||
|
|
||
|
// If we have not been routed yet, check the current tr first to make sure it is not set
|
||
|
// if we don't get_Tune wacks the tr currently set
|
||
|
if(!m_bRouted){
|
||
|
if(m_pCurrentTR){
|
||
|
TNChannelTuneRequest curTR(m_pCurrentTR);
|
||
|
HRESULT hr = ctr->put_Channel(curTR.Channel());
|
||
|
if (FAILED(hr)) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
return NOERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long channel;
|
||
|
PQTVTuner ptv(m_Filters[m_iTuner]);
|
||
|
long vs, as;
|
||
|
HRESULT hr = ptv->get_Channel(&channel, &vs, &as);
|
||
|
if (FAILED(hr)) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
hr = ctr->put_Channel(channel);
|
||
|
if (FAILED(hr)) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
// undone: update the components
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
HRESULT CMSVidTVTuner::TwiddleXBar(ULONG dwInput){ // For Support for Aux Inputs
|
||
|
VIDPERF_FUNC;
|
||
|
if(dwInput < 0 || dwInput > 2){
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
// Set up lists of audio and video types for use in routing data
|
||
|
int m_iDeMux = -1;
|
||
|
MediaMajorTypeList VideoTypes;
|
||
|
MediaMajorTypeList AudioTypes;
|
||
|
if (!VideoTypes.size()) {
|
||
|
VideoTypes.push_back(MEDIATYPE_Video);
|
||
|
VideoTypes.push_back(MEDIATYPE_AnalogVideo);
|
||
|
|
||
|
}
|
||
|
|
||
|
if (!AudioTypes.size()) {
|
||
|
AudioTypes.push_back(MEDIATYPE_Audio);
|
||
|
AudioTypes.push_back(MEDIATYPE_AnalogAudio);
|
||
|
}
|
||
|
|
||
|
// See how far we have to route the audio/video
|
||
|
PQVidCtl pqCtl;
|
||
|
if(!!m_pContainer){
|
||
|
HRESULT hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast<void**>(&pqCtl));
|
||
|
if(FAILED(hr)){
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
PQFeatures fa;
|
||
|
hr = pqCtl->get_FeaturesActive(&fa);
|
||
|
if(FAILED(hr)){
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CFeatures* pC = static_cast<CFeatures *>(fa.p);
|
||
|
DeviceCollection::iterator i;
|
||
|
for(i = pC->m_Devices.begin(); i != pC->m_Devices.end(); ++i){
|
||
|
if(VWGraphSegment(*i).ClassID() == CLSID_MSVidEncoder){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(i != pC->m_Devices.end()){
|
||
|
m_iDeMux = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Find the Capture Filter
|
||
|
DSFilter capFilter (m_Filters[m_iCapture]);
|
||
|
if(!capFilter){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// Get the Crossbar
|
||
|
DSFilterList::iterator i;
|
||
|
for(i = m_Filters.begin(); i != m_Filters.end(); ++i){
|
||
|
if((*i).IsXBar()){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(i == m_Filters.end()){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// DSextend helper class
|
||
|
PQCrossbarSwitch qiXBar((*i));
|
||
|
if(!qiXBar){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// DSExtend does not have all the functions so get the filter as well
|
||
|
DSFilter bar(qiXBar);
|
||
|
if(!bar){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// Variables for routing audio and video
|
||
|
DSFilter startFilter;
|
||
|
DSPin audioStartPin, videoStartPin;
|
||
|
VWStream vpath;
|
||
|
VWStream apath;
|
||
|
|
||
|
// Setup startFilter and startPins if needed
|
||
|
if(dwInput == t_TUNER){
|
||
|
PQVidCtl pqCtl;
|
||
|
HRESULT hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast<void**>(&pqCtl));
|
||
|
if(FAILED(hr)){
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if(!pqCtl){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
DSFilter tunerFilter(m_Filters[m_iTuner]);
|
||
|
if(!tunerFilter){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
startFilter = tunerFilter;
|
||
|
if(!tunerFilter){
|
||
|
_ASSERT(false);
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if(dwInput == t_SVIDEO || dwInput == t_COMPOSITE){
|
||
|
// Route Audio from Audio Line In
|
||
|
DSPin inAudio;
|
||
|
DSPin inVideo;
|
||
|
long inputs, outputs;
|
||
|
|
||
|
HRESULT hr = qiXBar->get_PinCounts(&outputs, &inputs);
|
||
|
if(FAILED(hr)){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
long physConn, audioConn;
|
||
|
// set up the physical connnecter we are looking for
|
||
|
if(dwInput == t_SVIDEO){
|
||
|
physConn = PhysConn_Video_SVideo;
|
||
|
}
|
||
|
else if(dwInput == t_COMPOSITE){
|
||
|
physConn = PhysConn_Video_Composite;
|
||
|
}
|
||
|
|
||
|
// always want line in
|
||
|
audioConn = PhysConn_Audio_Line;
|
||
|
long audioIdx = -1;
|
||
|
long videoIdx = -1;
|
||
|
|
||
|
// Look through all of the input pins looking for the audio and video input we need
|
||
|
for(long n = 0; n <= inputs; ++n){
|
||
|
long inRelate, inType;
|
||
|
hr = qiXBar->get_CrossbarPinInfo(TRUE, n, &inRelate, &inType);
|
||
|
if(FAILED(hr)){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(inType == physConn){
|
||
|
videoIdx = n;
|
||
|
}
|
||
|
|
||
|
if(inType == audioConn){
|
||
|
audioIdx = n;
|
||
|
}
|
||
|
}
|
||
|
if(videoIdx == audioIdx || videoIdx == -1 || audioIdx == -1){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
long idx = -1;
|
||
|
|
||
|
// Crossbars are wank and dont return pins instead they return indexes so we need to find the pin
|
||
|
for(DSFilter::iterator foo = bar.begin(); foo != bar.end(); ++foo){
|
||
|
if((*foo).GetDirection() == PINDIR_INPUT){
|
||
|
++idx;
|
||
|
if(idx == videoIdx){
|
||
|
inVideo = (*foo);
|
||
|
}
|
||
|
|
||
|
if(idx == audioIdx){
|
||
|
inAudio = (*foo);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(!inAudio || !inVideo){
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
startFilter = bar;
|
||
|
audioStartPin = inAudio;
|
||
|
videoStartPin = inVideo;
|
||
|
if(!startFilter || !audioStartPin || !videoStartPin){
|
||
|
_ASSERT(false);
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_pGraph.BuildGraphPath(startFilter, capFilter, vpath, VideoTypes, DOWNSTREAM, videoStartPin);
|
||
|
// undone: in win64 size() is really __int64. fix output operator for
|
||
|
// that type and remove cast
|
||
|
TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::RouteStreams routing video path of size " << (long)vpath.size()), "");
|
||
|
vpath.Route();
|
||
|
|
||
|
TRACELM(TRACE_DETAIL, "CVidCtl::RouteStreams finding audio path");
|
||
|
|
||
|
if(m_iDeMux > 0){
|
||
|
m_pGraph.BuildGraphPath(startFilter, capFilter, apath, AudioTypes, DOWNSTREAM, audioStartPin);
|
||
|
apath.Route();
|
||
|
}
|
||
|
else {
|
||
|
VWGraphSegment::iterator i;
|
||
|
// there's an analog filter and a digital filter in every audio renderer segment, try both until
|
||
|
// we find one that's connected.
|
||
|
|
||
|
CComQIPtr<IMSVidAudioRenderer> audioR;
|
||
|
pqCtl->get_AudioRendererActive(&audioR);
|
||
|
VWGraphSegment ar(audioR);
|
||
|
if(!!ar){
|
||
|
for (i = ar.begin(); i != ar.end(); ++i) {
|
||
|
m_pGraph.BuildGraphPath(startFilter, (*i), apath, AudioTypes, DOWNSTREAM, audioStartPin);
|
||
|
if (apath.size()) {
|
||
|
TRACELSM(TRACE_DETAIL, (dbgDump << "Analog tuner Twiddling for audio path of size " << (long)apath.size()), "");
|
||
|
apath.Route();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
m_bRouted = true;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
HRESULT CMSVidTVTuner::DoTune(TNTuneRequest &tr) {
|
||
|
VIDPERF_FUNC;
|
||
|
TRACELM(TRACE_DETAIL, "CMSVidTVTuner()::DoTune()");
|
||
|
// validate that this tuning request is one we can handle
|
||
|
TNChannelTuneRequest newTR(tr);
|
||
|
if (!newTR) {
|
||
|
return Error(IDS_INVALID_TR, __uuidof(IMSVidAnalogTuner), DISP_E_TYPEMISMATCH);
|
||
|
}
|
||
|
|
||
|
TNChannelTuneRequest curTR(m_pCurrentTR);
|
||
|
TNAnalogTVTuningSpace ats;
|
||
|
ats = newTR.TuningSpace();
|
||
|
if (!ats) {
|
||
|
//return Error(IDS_INVALID_TR, __uuidof(IMSVidAnalogTuner), E_INVALIDARG);
|
||
|
|
||
|
//********************************************************************//
|
||
|
// MOGUL "FIX": //
|
||
|
// Support for Analog Tuners that output mpeg //
|
||
|
//********************************************************************//
|
||
|
TNAuxInTuningSpace auxts;
|
||
|
auxts = newTR.TuningSpace();
|
||
|
if(!auxts){
|
||
|
return Error(IDS_INVALID_TR, __uuidof(IMSVidAnalogTuner), E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
// if the graph isn't built don't do any more.
|
||
|
if (m_iTuner == -1) {
|
||
|
return S_FALSE;
|
||
|
//Error(IDS_NP_NOT_INIT, __uuidof(IMSVidAnalogTuner), S_FALSE);
|
||
|
}
|
||
|
|
||
|
long channel = newTR.Channel();
|
||
|
// Default is SVideo
|
||
|
if (channel == -1) {
|
||
|
channel = t_SVIDEO;
|
||
|
}
|
||
|
|
||
|
// Check to see if the m_pCurrentTR is the same type as the one we are tuning to
|
||
|
TNAuxInTuningSpace curTS(m_pCurrentTR.TuningSpace());
|
||
|
|
||
|
if(!m_bRouted || !curTS || !curTR || curTR.Channel() != channel){
|
||
|
if(channel == t_SVIDEO){
|
||
|
HRESULT hr = TwiddleXBar(t_SVIDEO);
|
||
|
}
|
||
|
else if(channel == t_COMPOSITE){
|
||
|
HRESULT hr = TwiddleXBar(t_COMPOSITE);
|
||
|
}
|
||
|
else{
|
||
|
return Error(IDS_INVALID_TR, __uuidof(IMSVidAnalogTuner), E_INVALIDARG);
|
||
|
}
|
||
|
}
|
||
|
//********************************************************************//
|
||
|
// END "FIX" //
|
||
|
//********************************************************************//
|
||
|
|
||
|
}
|
||
|
else{
|
||
|
// if the graph isn't built don't do any more.
|
||
|
if (m_iTuner == -1) {
|
||
|
return S_FALSE;
|
||
|
//Error(IDS_NP_NOT_INIT, __uuidof(IMSVidAnalogTuner), S_FALSE);
|
||
|
}
|
||
|
|
||
|
PQTVTuner ptv(m_Filters[m_iTuner]);
|
||
|
if(!ptv){
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
long channel = newTR.Channel();
|
||
|
if (channel == -1) {
|
||
|
channel = DEFAULT_ANALOG_CHANNEL;
|
||
|
}
|
||
|
|
||
|
long curChannel = -1;
|
||
|
if(curTR){
|
||
|
curChannel = curTR.Channel();
|
||
|
}
|
||
|
|
||
|
long curInputType = ats.InputType();
|
||
|
long curCountryCode = ats.CountryCode();
|
||
|
TNAnalogTVTuningSpace curTS;
|
||
|
if(curTR){
|
||
|
curTS = curTR.TuningSpace();
|
||
|
if(curTS){
|
||
|
curInputType = curTS.InputType();
|
||
|
curCountryCode = curTS.CountryCode();
|
||
|
}
|
||
|
}
|
||
|
bool bXbarTwiddled = false;
|
||
|
if(!m_bRouted || !curTR || curInputType != ats.InputType() || curCountryCode != ats.CountryCode() || !curTS || curTS != ats){
|
||
|
HRESULT hr = TwiddleXBar(t_TUNER);
|
||
|
if(FAILED(hr)){
|
||
|
return hr;
|
||
|
}
|
||
|
TunerInputType ti = ats.InputType();
|
||
|
hr = ptv->put_InputType(0, ti);
|
||
|
if (FAILED(hr)) {
|
||
|
return Error(IDS_CANT_SET_INPUTTYPE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
|
||
|
}
|
||
|
|
||
|
long countrycode = ats.CountryCode();
|
||
|
hr = ptv->put_CountryCode(countrycode);
|
||
|
if (FAILED(hr)) {
|
||
|
return Error(IDS_CANT_SET_COUNTRYCODE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
|
||
|
}
|
||
|
bXbarTwiddled = true;
|
||
|
}
|
||
|
|
||
|
if(channel != curChannel || bXbarTwiddled){
|
||
|
// undone: use components to determine subchannel stuff
|
||
|
HRESULT hr = ptv->put_Channel(channel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT);
|
||
|
if (FAILED(hr)) {
|
||
|
return Error(IDS_CANT_SET_CHANNEL, __uuidof(IMSVidAnalogTuner), hr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if (!m_pBcast) {
|
||
|
PQServiceProvider sp(m_pGraph);
|
||
|
if (!sp) {
|
||
|
TRACELM(TRACE_ERROR, "CMSVidTVTuner::DoTune() can't get service provider i/f");
|
||
|
return Error(IDS_CANT_NOTIFY_CHANNEL_CHANGE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
|
||
|
}
|
||
|
|
||
|
HRESULT hr = sp->QueryService(SID_SBroadcastEventService, IID_IBroadcastEvent, reinterpret_cast<LPVOID*>(&m_pBcast));
|
||
|
if (FAILED(hr) || !m_pBcast) {
|
||
|
hr = m_pBcast.CoCreateInstance(CLSID_BroadcastEventService, 0, CLSCTX_INPROC_SERVER);
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELM(TRACE_ERROR, "CMSVidTVTuner::DoTune() can't create bcast service");
|
||
|
return Error(IDS_CANT_NOTIFY_CHANNEL_CHANGE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
|
||
|
}
|
||
|
|
||
|
PQRegisterServiceProvider rsp(m_pGraph);
|
||
|
if (!rsp) {
|
||
|
TRACELM(TRACE_ERROR, "CMSVidTVTuner::DoTune() can't get get register service provider i/f");
|
||
|
return Error(IDS_CANT_NOTIFY_CHANNEL_CHANGE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
|
||
|
}
|
||
|
|
||
|
hr = rsp->RegisterService(SID_SBroadcastEventService, m_pBcast);
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELSM(TRACE_ERROR, (dbgDump << "CMSVidTVTuner::DoTune() can't get register service provider. hr = " << hexdump(hr)), "");
|
||
|
return Error(IDS_CANT_NOTIFY_CHANNEL_CHANGE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASSERT(m_pBcast);
|
||
|
m_pBcast->Fire(EVENTID_TuningChanged);
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
HRESULT CMSVidTVTuner::put_Container(IMSVidGraphSegmentContainer *pCtl)
|
||
|
{
|
||
|
if (!m_fInit) {
|
||
|
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidAnalogTuner), CO_E_NOTINITIALIZED);
|
||
|
}
|
||
|
try {
|
||
|
CPerfCounter pCounterTuner;
|
||
|
pCounterTuner.Reset();
|
||
|
if (!pCtl) {
|
||
|
return Unload();
|
||
|
}
|
||
|
if (m_pContainer) {
|
||
|
if (!m_pContainer.IsEqualObject(VWSegmentContainer(pCtl))) {
|
||
|
return Error(IDS_OBJ_ALREADY_INIT, __uuidof(IMSVidAnalogTuner), CO_E_ALREADYINITIALIZED);
|
||
|
} else {
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
// DON'T addref the container. we're guaranteed nested lifetimes
|
||
|
// and an addref creates circular refcounts so we never unload.
|
||
|
m_pContainer.p = pCtl;
|
||
|
m_pGraph = m_pContainer.GetGraph();
|
||
|
DSFilter pTuner(m_pGraph.AddMoniker(m_pDev));
|
||
|
if (!pTuner) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
m_Filters.push_back(pTuner);
|
||
|
m_iTuner = 0;
|
||
|
TRACELM(TRACE_DETAIL, "CMSVidTVTuner::put_Container() tuner added");
|
||
|
pCounterTuner.Stop();
|
||
|
TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer TVTuner Filter: " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
|
||
|
pCounterTuner.Reset();
|
||
|
if (!m_pSystemEnum) {
|
||
|
m_pSystemEnum = PQCreateDevEnum(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER);
|
||
|
if (!m_pSystemEnum) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
}
|
||
|
pCounterTuner.Stop();
|
||
|
TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer TVTuner SysEnum: " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
|
||
|
pCounterTuner.Reset();
|
||
|
DSDevices CaptureList(m_pSystemEnum, KSCATEGORY_CAPTURE);
|
||
|
DSDevices::iterator i;
|
||
|
DSFilter Capture;
|
||
|
DSFilterList intermediates;
|
||
|
try {
|
||
|
ASSERT(m_iTuner > -1);
|
||
|
for (i = CaptureList.begin(); i != CaptureList.end(); ++i) {
|
||
|
CString csName;
|
||
|
Capture = m_pGraph.LoadFilter(*i, csName);
|
||
|
if (!Capture) {
|
||
|
continue;
|
||
|
}
|
||
|
TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidTVTuner::put_Container() found not video capture filter = " << csName), "");
|
||
|
if (!IsVideoFilter(Capture)) {
|
||
|
continue;
|
||
|
}
|
||
|
TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidTVTuner::put_Container() found video capture filter = " << csName), "");
|
||
|
HRESULT hr = m_pGraph.AddFilter(Capture, csName);
|
||
|
if (FAILED(hr)) {
|
||
|
continue;
|
||
|
}
|
||
|
hr = m_pGraph.Connect(m_Filters[m_iTuner], Capture, intermediates);
|
||
|
pCounterTuner.Stop();
|
||
|
TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer Capture Filter: " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
|
||
|
pCounterTuner.Reset();
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
break;
|
||
|
}
|
||
|
TRACELM(TRACE_DETAIL, "CMSVidTVTuner::put_Container() removing unconnectable capture filter");
|
||
|
m_pGraph.RemoveFilter(Capture);
|
||
|
}
|
||
|
if (i == CaptureList.end()) {
|
||
|
TRACELM(TRACE_ERROR, "CMSVidTVTuner::put_Container() can't find valid capture");
|
||
|
return Error(IDS_NO_CAPTURE, __uuidof(IMSVidAnalogTuner), E_NOINTERFACE);
|
||
|
}
|
||
|
m_Filters.insert(m_Filters.end(), intermediates.begin(), intermediates.end());
|
||
|
m_iTuner = 0;
|
||
|
ASSERT(m_iTuner > -1);
|
||
|
} catch(ComException &e) {
|
||
|
return e;
|
||
|
}
|
||
|
m_Filters.push_back(Capture);
|
||
|
m_iCapture = m_Filters.size() - 1;
|
||
|
m_iTuner = 0;
|
||
|
ASSERT(m_iTuner > -1 && m_iCapture > 0 && m_iCapture != m_iTuner);
|
||
|
TRACELM(TRACE_DETAIL, "CMSVidTVTuner::put_Container() tuner connected");
|
||
|
pCounterTuner.Stop();
|
||
|
TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer TVTuner added to list: " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
|
||
|
|
||
|
|
||
|
pCounterTuner.Reset();
|
||
|
HRESULT hr = BroadcastAdvise();
|
||
|
if (FAILED(hr)) {
|
||
|
TRACELM(TRACE_ERROR, "CMSVidTVTuner::put_Container() can't advise for broadcast events");
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
TRACELM(TRACE_DETAIL, "CMSVidTVTuner::put_Container() registered for tuning changed events");
|
||
|
pCounterTuner.Stop();
|
||
|
TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer Rest : " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
|
||
|
|
||
|
} catch (ComException &e) {
|
||
|
return e;
|
||
|
} catch(...) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CMSVidTVTuner::Build() {
|
||
|
HRESULT hr = put_SAP(VARIANT_FALSE);
|
||
|
if(FAILED(hr)){
|
||
|
TRACELM(TRACE_ERROR, "CVidCtl put_sap failed");
|
||
|
//ASSERT(false);
|
||
|
}
|
||
|
|
||
|
PQMSVidCtl pv(m_pContainer);
|
||
|
if (!pv) {
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
PQMSVidVideoRenderer pvr;
|
||
|
hr = pv->get_VideoRendererActive(&pvr);
|
||
|
if (FAILED(hr) || !pvr) {
|
||
|
return NOERROR; // video disabled, no vr present
|
||
|
}
|
||
|
|
||
|
hr = pvr->put_SourceSize(sslClipByOverScan);
|
||
|
if (FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
return pvr->put_OverScan(DEFAULT_OVERSCAN_PCT);
|
||
|
}
|
||
|
|
||
|
#endif //TUNING_MODEL_ONLY
|
||
|
|
||
|
// end of file - msvidtvtuner.cpp
|