Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

668 lines
22 KiB

  1. //==========================================================================;
  2. //
  3. // Copyright (c) Microsoft Corporation 1999-2000.
  4. //
  5. //--------------------------------------------------------------------------;
  6. //
  7. // MSVidTVTuner.cpp : Implementation of CMSVidTVTuner
  8. //
  9. #include "stdafx.h"
  10. #ifndef TUNING_MODEL_ONLY
  11. #include "perfcntr.h"
  12. #include "MSVidCtl.h"
  13. #include "MSVidTVTuner.h"
  14. #include <bdamedia.h>
  15. #include "segimpl.h"
  16. #include "segimpl.h"
  17. #include "devices.h"
  18. const ULONG t_SVIDEO = 0;
  19. const ULONG t_COMPOSITE = 1;
  20. const ULONG t_TUNER = 2;
  21. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_MSVidAnalogTunerDevice, CMSVidTVTuner)
  22. const int DEFAULT_ANALOG_CHANNEL = 4;
  23. typedef CComQIPtr<IMSVidCtl> PQMSVidCtl;
  24. typedef CComQIPtr<IMSVidVideoRenderer> PQMSVidVideoRenderer;
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CMSVidTVTuner
  27. STDMETHODIMP CMSVidTVTuner::Decompose(){
  28. m_bRouted = false;
  29. return S_OK;
  30. }
  31. STDMETHODIMP CMSVidTVTuner::ChannelAvailable(LONG nChannel, LONG * SignalStrength, VARIANT_BOOL * fSignalPresent){
  32. VIDPERF_FUNC;
  33. if(!SignalStrength || !fSignalPresent){
  34. return E_POINTER;
  35. }
  36. CComQIPtr<IAMAnalogVideoDecoder> qi_VidDec(m_Filters[m_iCapture]);
  37. if(qi_VidDec){
  38. long signal = FALSE;
  39. HRESULT hr = qi_VidDec->get_HorizontalLocked(&signal);
  40. if(FAILED(hr)){
  41. return hr;
  42. }
  43. *fSignalPresent = signal ? VARIANT_TRUE:VARIANT_FALSE;
  44. return NOERROR;
  45. }
  46. return E_NOINTERFACE;
  47. }
  48. STDMETHODIMP CMSVidTVTuner::InterfaceSupportsErrorInfo(REFIID riid)
  49. {
  50. static const IID* arr[] =
  51. {
  52. &IID_IMSVidAnalogTuner
  53. };
  54. for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
  55. {
  56. if (InlineIsEqualGUID(*arr[i],riid))
  57. return S_OK;
  58. }
  59. return S_FALSE;
  60. }
  61. STDMETHODIMP CMSVidTVTuner::put_Tune(ITuneRequest *pTR) {
  62. VIDPERF_FUNC;
  63. TRACELM(TRACE_DETAIL, "CMSVidTVTuner<>::put_Tune()");
  64. if (!m_fInit) {
  65. return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidTuner), CO_E_NOTINITIALIZED);
  66. }
  67. if (!pTR) {
  68. return E_POINTER;
  69. }
  70. try {
  71. TNTuneRequest req(pTR);
  72. ASSERT(req);
  73. // This whole next section would be nice to check, but due to aux in
  74. // the Tuning Space may change
  75. /*if (m_TS) {
  76. // if this tuner has been initialized propertly it will have a tuning space
  77. // that it handles already specified. in that case, we should only
  78. // handle tune requests for our ts
  79. TNTuningSpace ts(req.TuningSpace());
  80. if (ts != m_TS) {
  81. return ImplReportError(__uuidof(T), IDS_INVALID_TS, __uuidof(IMSVidTuner), E_INVALIDARG);
  82. }
  83. } else {
  84. // undone: if dev init is correct this case should never occur
  85. // return E_UNEXPECTED;
  86. }
  87. */
  88. HRESULT hr = S_OK;
  89. PQVidCtl pqCtl;
  90. if(!!m_pContainer){
  91. hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast<void**>(&pqCtl));
  92. if(FAILED(hr)){
  93. return hr;
  94. }
  95. MSVidCtlStateList curState = STATE_UNBUILT;
  96. hr = pqCtl->get_State(&curState);
  97. if(SUCCEEDED(hr) && curState > STATE_STOP){
  98. hr = DoTune(req);
  99. }
  100. else{
  101. m_bRouted = false;
  102. hr = NOERROR;
  103. }
  104. }
  105. if (SUCCEEDED(hr)) {
  106. m_pCurrentTR = req;
  107. m_pCurrentTR.Clone();
  108. if (!m_TS) {
  109. // undone: this is bad. temporary hack until dev init is correct.
  110. m_TS = req.TuningSpace();
  111. m_TS.Clone();
  112. }
  113. }
  114. return hr;
  115. } catch(...) {
  116. return E_INVALIDARG;
  117. }
  118. }
  119. HRESULT CMSVidTVTuner::UpdateTR(TNTuneRequest &tr) {
  120. TNChannelTuneRequest ctr(tr);
  121. // If we have not been routed yet, check the current tr first to make sure it is not set
  122. // if we don't get_Tune wacks the tr currently set
  123. if(!m_bRouted){
  124. if(m_pCurrentTR){
  125. TNChannelTuneRequest curTR(m_pCurrentTR);
  126. HRESULT hr = ctr->put_Channel(curTR.Channel());
  127. if (FAILED(hr)) {
  128. return E_UNEXPECTED;
  129. }
  130. return NOERROR;
  131. }
  132. }
  133. long channel;
  134. PQTVTuner ptv(m_Filters[m_iTuner]);
  135. long vs, as;
  136. HRESULT hr = ptv->get_Channel(&channel, &vs, &as);
  137. if (FAILED(hr)) {
  138. return E_UNEXPECTED;
  139. }
  140. hr = ctr->put_Channel(channel);
  141. if (FAILED(hr)) {
  142. return E_UNEXPECTED;
  143. }
  144. // undone: update the components
  145. return NOERROR;
  146. }
  147. HRESULT CMSVidTVTuner::TwiddleXBar(ULONG dwInput){ // For Support for Aux Inputs
  148. VIDPERF_FUNC;
  149. if(dwInput < 0 || dwInput > 2){
  150. return E_INVALIDARG;
  151. }
  152. // Set up lists of audio and video types for use in routing data
  153. int m_iDeMux = -1;
  154. MediaMajorTypeList VideoTypes;
  155. MediaMajorTypeList AudioTypes;
  156. if (!VideoTypes.size()) {
  157. VideoTypes.push_back(MEDIATYPE_Video);
  158. VideoTypes.push_back(MEDIATYPE_AnalogVideo);
  159. }
  160. if (!AudioTypes.size()) {
  161. AudioTypes.push_back(MEDIATYPE_Audio);
  162. AudioTypes.push_back(MEDIATYPE_AnalogAudio);
  163. }
  164. // See how far we have to route the audio/video
  165. PQVidCtl pqCtl;
  166. if(!!m_pContainer){
  167. HRESULT hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast<void**>(&pqCtl));
  168. if(FAILED(hr)){
  169. return hr;
  170. }
  171. PQFeatures fa;
  172. hr = pqCtl->get_FeaturesActive(&fa);
  173. if(FAILED(hr)){
  174. return hr;
  175. }
  176. CFeatures* pC = static_cast<CFeatures *>(fa.p);
  177. DeviceCollection::iterator i;
  178. for(i = pC->m_Devices.begin(); i != pC->m_Devices.end(); ++i){
  179. if(VWGraphSegment(*i).ClassID() == CLSID_MSVidEncoder){
  180. break;
  181. }
  182. }
  183. if(i != pC->m_Devices.end()){
  184. m_iDeMux = 1;
  185. }
  186. }
  187. // Find the Capture Filter
  188. DSFilter capFilter (m_Filters[m_iCapture]);
  189. if(!capFilter){
  190. return E_FAIL;
  191. }
  192. // Get the Crossbar
  193. DSFilterList::iterator i;
  194. for(i = m_Filters.begin(); i != m_Filters.end(); ++i){
  195. if((*i).IsXBar()){
  196. break;
  197. }
  198. }
  199. if(i == m_Filters.end()){
  200. return E_FAIL;
  201. }
  202. // DSextend helper class
  203. PQCrossbarSwitch qiXBar((*i));
  204. if(!qiXBar){
  205. return E_FAIL;
  206. }
  207. // DSExtend does not have all the functions so get the filter as well
  208. DSFilter bar(qiXBar);
  209. if(!bar){
  210. return E_FAIL;
  211. }
  212. // Variables for routing audio and video
  213. DSFilter startFilter;
  214. DSPin audioStartPin, videoStartPin;
  215. VWStream vpath;
  216. VWStream apath;
  217. // Setup startFilter and startPins if needed
  218. if(dwInput == t_TUNER){
  219. PQVidCtl pqCtl;
  220. HRESULT hr = m_pContainer->QueryInterface(IID_IMSVidCtl, reinterpret_cast<void**>(&pqCtl));
  221. if(FAILED(hr)){
  222. return hr;
  223. }
  224. if(!pqCtl){
  225. return E_FAIL;
  226. }
  227. DSFilter tunerFilter(m_Filters[m_iTuner]);
  228. if(!tunerFilter){
  229. return E_FAIL;
  230. }
  231. startFilter = tunerFilter;
  232. if(!tunerFilter){
  233. _ASSERT(false);
  234. return E_UNEXPECTED;
  235. }
  236. }
  237. if(dwInput == t_SVIDEO || dwInput == t_COMPOSITE){
  238. // Route Audio from Audio Line In
  239. DSPin inAudio;
  240. DSPin inVideo;
  241. long inputs, outputs;
  242. HRESULT hr = qiXBar->get_PinCounts(&outputs, &inputs);
  243. if(FAILED(hr)){
  244. return E_FAIL;
  245. }
  246. long physConn, audioConn;
  247. // set up the physical connnecter we are looking for
  248. if(dwInput == t_SVIDEO){
  249. physConn = PhysConn_Video_SVideo;
  250. }
  251. else if(dwInput == t_COMPOSITE){
  252. physConn = PhysConn_Video_Composite;
  253. }
  254. // always want line in
  255. audioConn = PhysConn_Audio_Line;
  256. long audioIdx = -1;
  257. long videoIdx = -1;
  258. // Look through all of the input pins looking for the audio and video input we need
  259. for(long n = 0; n <= inputs; ++n){
  260. long inRelate, inType;
  261. hr = qiXBar->get_CrossbarPinInfo(TRUE, n, &inRelate, &inType);
  262. if(FAILED(hr)){
  263. continue;
  264. }
  265. if(inType == physConn){
  266. videoIdx = n;
  267. }
  268. if(inType == audioConn){
  269. audioIdx = n;
  270. }
  271. }
  272. if(videoIdx == audioIdx || videoIdx == -1 || audioIdx == -1){
  273. return E_FAIL;
  274. }
  275. long idx = -1;
  276. // Crossbars are wank and dont return pins instead they return indexes so we need to find the pin
  277. for(DSFilter::iterator foo = bar.begin(); foo != bar.end(); ++foo){
  278. if((*foo).GetDirection() == PINDIR_INPUT){
  279. ++idx;
  280. if(idx == videoIdx){
  281. inVideo = (*foo);
  282. }
  283. if(idx == audioIdx){
  284. inAudio = (*foo);
  285. }
  286. }
  287. }
  288. if(!inAudio || !inVideo){
  289. return E_FAIL;
  290. }
  291. startFilter = bar;
  292. audioStartPin = inAudio;
  293. videoStartPin = inVideo;
  294. if(!startFilter || !audioStartPin || !videoStartPin){
  295. _ASSERT(false);
  296. return E_UNEXPECTED;
  297. }
  298. }
  299. m_pGraph.BuildGraphPath(startFilter, capFilter, vpath, VideoTypes, DOWNSTREAM, videoStartPin);
  300. // undone: in win64 size() is really __int64. fix output operator for
  301. // that type and remove cast
  302. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::RouteStreams routing video path of size " << (long)vpath.size()), "");
  303. vpath.Route();
  304. TRACELM(TRACE_DETAIL, "CVidCtl::RouteStreams finding audio path");
  305. if(m_iDeMux > 0){
  306. m_pGraph.BuildGraphPath(startFilter, capFilter, apath, AudioTypes, DOWNSTREAM, audioStartPin);
  307. apath.Route();
  308. }
  309. else {
  310. VWGraphSegment::iterator i;
  311. // there's an analog filter and a digital filter in every audio renderer segment, try both until
  312. // we find one that's connected.
  313. CComQIPtr<IMSVidAudioRenderer> audioR;
  314. pqCtl->get_AudioRendererActive(&audioR);
  315. VWGraphSegment ar(audioR);
  316. if(!!ar){
  317. for (i = ar.begin(); i != ar.end(); ++i) {
  318. m_pGraph.BuildGraphPath(startFilter, (*i), apath, AudioTypes, DOWNSTREAM, audioStartPin);
  319. if (apath.size()) {
  320. TRACELSM(TRACE_DETAIL, (dbgDump << "Analog tuner Twiddling for audio path of size " << (long)apath.size()), "");
  321. apath.Route();
  322. break;
  323. }
  324. }
  325. }
  326. }
  327. m_bRouted = true;
  328. return NOERROR;
  329. }
  330. HRESULT CMSVidTVTuner::DoTune(TNTuneRequest &tr) {
  331. VIDPERF_FUNC;
  332. TRACELM(TRACE_DETAIL, "CMSVidTVTuner()::DoTune()");
  333. // validate that this tuning request is one we can handle
  334. TNChannelTuneRequest newTR(tr);
  335. if (!newTR) {
  336. return Error(IDS_INVALID_TR, __uuidof(IMSVidAnalogTuner), DISP_E_TYPEMISMATCH);
  337. }
  338. TNChannelTuneRequest curTR(m_pCurrentTR);
  339. TNAnalogTVTuningSpace ats;
  340. ats = newTR.TuningSpace();
  341. if (!ats) {
  342. //return Error(IDS_INVALID_TR, __uuidof(IMSVidAnalogTuner), E_INVALIDARG);
  343. //********************************************************************//
  344. // MOGUL "FIX": //
  345. // Support for Analog Tuners that output mpeg //
  346. //********************************************************************//
  347. TNAuxInTuningSpace auxts;
  348. auxts = newTR.TuningSpace();
  349. if(!auxts){
  350. return Error(IDS_INVALID_TR, __uuidof(IMSVidAnalogTuner), E_INVALIDARG);
  351. }
  352. // if the graph isn't built don't do any more.
  353. if (m_iTuner == -1) {
  354. return S_FALSE;
  355. //Error(IDS_NP_NOT_INIT, __uuidof(IMSVidAnalogTuner), S_FALSE);
  356. }
  357. long channel = newTR.Channel();
  358. // Default is SVideo
  359. if (channel == -1) {
  360. channel = t_SVIDEO;
  361. }
  362. // Check to see if the m_pCurrentTR is the same type as the one we are tuning to
  363. TNAuxInTuningSpace curTS(m_pCurrentTR.TuningSpace());
  364. if(!m_bRouted || !curTS || !curTR || curTR.Channel() != channel){
  365. if(channel == t_SVIDEO){
  366. HRESULT hr = TwiddleXBar(t_SVIDEO);
  367. }
  368. else if(channel == t_COMPOSITE){
  369. HRESULT hr = TwiddleXBar(t_COMPOSITE);
  370. }
  371. else{
  372. return Error(IDS_INVALID_TR, __uuidof(IMSVidAnalogTuner), E_INVALIDARG);
  373. }
  374. }
  375. //********************************************************************//
  376. // END "FIX" //
  377. //********************************************************************//
  378. }
  379. else{
  380. // if the graph isn't built don't do any more.
  381. if (m_iTuner == -1) {
  382. return S_FALSE;
  383. //Error(IDS_NP_NOT_INIT, __uuidof(IMSVidAnalogTuner), S_FALSE);
  384. }
  385. PQTVTuner ptv(m_Filters[m_iTuner]);
  386. if(!ptv){
  387. return E_NOINTERFACE;
  388. }
  389. long channel = newTR.Channel();
  390. if (channel == -1) {
  391. channel = DEFAULT_ANALOG_CHANNEL;
  392. }
  393. long curChannel = -1;
  394. if(curTR){
  395. curChannel = curTR.Channel();
  396. }
  397. long curInputType = ats.InputType();
  398. long curCountryCode = ats.CountryCode();
  399. TNAnalogTVTuningSpace curTS;
  400. if(curTR){
  401. curTS = curTR.TuningSpace();
  402. if(curTS){
  403. curInputType = curTS.InputType();
  404. curCountryCode = curTS.CountryCode();
  405. }
  406. }
  407. bool bXbarTwiddled = false;
  408. if(!m_bRouted || !curTR || curInputType != ats.InputType() || curCountryCode != ats.CountryCode() || !curTS || curTS != ats){
  409. HRESULT hr = TwiddleXBar(t_TUNER);
  410. if(FAILED(hr)){
  411. return hr;
  412. }
  413. TunerInputType ti = ats.InputType();
  414. hr = ptv->put_InputType(0, ti);
  415. if (FAILED(hr)) {
  416. return Error(IDS_CANT_SET_INPUTTYPE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
  417. }
  418. long countrycode = ats.CountryCode();
  419. hr = ptv->put_CountryCode(countrycode);
  420. if (FAILED(hr)) {
  421. return Error(IDS_CANT_SET_COUNTRYCODE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
  422. }
  423. bXbarTwiddled = true;
  424. }
  425. if(channel != curChannel || bXbarTwiddled){
  426. // undone: use components to determine subchannel stuff
  427. HRESULT hr = ptv->put_Channel(channel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT);
  428. if (FAILED(hr)) {
  429. return Error(IDS_CANT_SET_CHANNEL, __uuidof(IMSVidAnalogTuner), hr);
  430. }
  431. }
  432. }
  433. if (!m_pBcast) {
  434. PQServiceProvider sp(m_pGraph);
  435. if (!sp) {
  436. TRACELM(TRACE_ERROR, "CMSVidTVTuner::DoTune() can't get service provider i/f");
  437. return Error(IDS_CANT_NOTIFY_CHANNEL_CHANGE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
  438. }
  439. HRESULT hr = sp->QueryService(SID_SBroadcastEventService, IID_IBroadcastEvent, reinterpret_cast<LPVOID*>(&m_pBcast));
  440. if (FAILED(hr) || !m_pBcast) {
  441. hr = m_pBcast.CoCreateInstance(CLSID_BroadcastEventService, 0, CLSCTX_INPROC_SERVER);
  442. if (FAILED(hr)) {
  443. TRACELM(TRACE_ERROR, "CMSVidTVTuner::DoTune() can't create bcast service");
  444. return Error(IDS_CANT_NOTIFY_CHANNEL_CHANGE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
  445. }
  446. PQRegisterServiceProvider rsp(m_pGraph);
  447. if (!rsp) {
  448. TRACELM(TRACE_ERROR, "CMSVidTVTuner::DoTune() can't get get register service provider i/f");
  449. return Error(IDS_CANT_NOTIFY_CHANNEL_CHANGE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
  450. }
  451. hr = rsp->RegisterService(SID_SBroadcastEventService, m_pBcast);
  452. if (FAILED(hr)) {
  453. TRACELSM(TRACE_ERROR, (dbgDump << "CMSVidTVTuner::DoTune() can't get register service provider. hr = " << hexdump(hr)), "");
  454. return Error(IDS_CANT_NOTIFY_CHANNEL_CHANGE, __uuidof(IMSVidAnalogTuner), E_UNEXPECTED);
  455. }
  456. }
  457. }
  458. ASSERT(m_pBcast);
  459. m_pBcast->Fire(EVENTID_TuningChanged);
  460. return NOERROR;
  461. }
  462. HRESULT CMSVidTVTuner::put_Container(IMSVidGraphSegmentContainer *pCtl)
  463. {
  464. if (!m_fInit) {
  465. return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidAnalogTuner), CO_E_NOTINITIALIZED);
  466. }
  467. try {
  468. CPerfCounter pCounterTuner;
  469. pCounterTuner.Reset();
  470. if (!pCtl) {
  471. return Unload();
  472. }
  473. if (m_pContainer) {
  474. if (!m_pContainer.IsEqualObject(VWSegmentContainer(pCtl))) {
  475. return Error(IDS_OBJ_ALREADY_INIT, __uuidof(IMSVidAnalogTuner), CO_E_ALREADYINITIALIZED);
  476. } else {
  477. return NO_ERROR;
  478. }
  479. }
  480. // DON'T addref the container. we're guaranteed nested lifetimes
  481. // and an addref creates circular refcounts so we never unload.
  482. m_pContainer.p = pCtl;
  483. m_pGraph = m_pContainer.GetGraph();
  484. DSFilter pTuner(m_pGraph.AddMoniker(m_pDev));
  485. if (!pTuner) {
  486. return E_UNEXPECTED;
  487. }
  488. m_Filters.push_back(pTuner);
  489. m_iTuner = 0;
  490. TRACELM(TRACE_DETAIL, "CMSVidTVTuner::put_Container() tuner added");
  491. pCounterTuner.Stop();
  492. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer TVTuner Filter: " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  493. pCounterTuner.Reset();
  494. if (!m_pSystemEnum) {
  495. m_pSystemEnum = PQCreateDevEnum(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER);
  496. if (!m_pSystemEnum) {
  497. return E_UNEXPECTED;
  498. }
  499. }
  500. pCounterTuner.Stop();
  501. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer TVTuner SysEnum: " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  502. pCounterTuner.Reset();
  503. DSDevices CaptureList(m_pSystemEnum, KSCATEGORY_CAPTURE);
  504. DSDevices::iterator i;
  505. DSFilter Capture;
  506. DSFilterList intermediates;
  507. try {
  508. ASSERT(m_iTuner > -1);
  509. for (i = CaptureList.begin(); i != CaptureList.end(); ++i) {
  510. CString csName;
  511. Capture = m_pGraph.LoadFilter(*i, csName);
  512. if (!Capture) {
  513. continue;
  514. }
  515. TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidTVTuner::put_Container() found not video capture filter = " << csName), "");
  516. if (!IsVideoFilter(Capture)) {
  517. continue;
  518. }
  519. TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidTVTuner::put_Container() found video capture filter = " << csName), "");
  520. HRESULT hr = m_pGraph.AddFilter(Capture, csName);
  521. if (FAILED(hr)) {
  522. continue;
  523. }
  524. hr = m_pGraph.Connect(m_Filters[m_iTuner], Capture, intermediates);
  525. pCounterTuner.Stop();
  526. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer Capture Filter: " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  527. pCounterTuner.Reset();
  528. if (SUCCEEDED(hr)) {
  529. break;
  530. }
  531. TRACELM(TRACE_DETAIL, "CMSVidTVTuner::put_Container() removing unconnectable capture filter");
  532. m_pGraph.RemoveFilter(Capture);
  533. }
  534. if (i == CaptureList.end()) {
  535. TRACELM(TRACE_ERROR, "CMSVidTVTuner::put_Container() can't find valid capture");
  536. return Error(IDS_NO_CAPTURE, __uuidof(IMSVidAnalogTuner), E_NOINTERFACE);
  537. }
  538. m_Filters.insert(m_Filters.end(), intermediates.begin(), intermediates.end());
  539. m_iTuner = 0;
  540. ASSERT(m_iTuner > -1);
  541. } catch(ComException &e) {
  542. return e;
  543. }
  544. m_Filters.push_back(Capture);
  545. m_iCapture = m_Filters.size() - 1;
  546. m_iTuner = 0;
  547. ASSERT(m_iTuner > -1 && m_iCapture > 0 && m_iCapture != m_iTuner);
  548. TRACELM(TRACE_DETAIL, "CMSVidTVTuner::put_Container() tuner connected");
  549. pCounterTuner.Stop();
  550. 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"), "");
  551. pCounterTuner.Reset();
  552. HRESULT hr = BroadcastAdvise();
  553. if (FAILED(hr)) {
  554. TRACELM(TRACE_ERROR, "CMSVidTVTuner::put_Container() can't advise for broadcast events");
  555. return E_UNEXPECTED;
  556. }
  557. TRACELM(TRACE_DETAIL, "CMSVidTVTuner::put_Container() registered for tuning changed events");
  558. pCounterTuner.Stop();
  559. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl:: PutContainer Rest : " << (unsigned long)(pCounterTuner.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterTuner.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  560. } catch (ComException &e) {
  561. return e;
  562. } catch(...) {
  563. return E_UNEXPECTED;
  564. }
  565. return NOERROR;
  566. }
  567. HRESULT CMSVidTVTuner::Build() {
  568. HRESULT hr = put_SAP(VARIANT_FALSE);
  569. if(FAILED(hr)){
  570. TRACELM(TRACE_ERROR, "CVidCtl put_sap failed");
  571. //ASSERT(false);
  572. }
  573. PQMSVidCtl pv(m_pContainer);
  574. if (!pv) {
  575. return E_UNEXPECTED;
  576. }
  577. PQMSVidVideoRenderer pvr;
  578. hr = pv->get_VideoRendererActive(&pvr);
  579. if (FAILED(hr) || !pvr) {
  580. return NOERROR; // video disabled, no vr present
  581. }
  582. hr = pvr->put_SourceSize(sslClipByOverScan);
  583. if (FAILED(hr)) {
  584. return hr;
  585. }
  586. return pvr->put_OverScan(DEFAULT_OVERSCAN_PCT);
  587. }
  588. #endif //TUNING_MODEL_ONLY
  589. // end of file - msvidtvtuner.cpp