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.

1931 lines
60 KiB

  1. //==========================================================================
  2. //
  3. // Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  4. //
  5. //--------------------------------------------------------------------------
  6. #include <streams.h>
  7. #include <ddraw.h>
  8. #include <VBIObj.h>
  9. #include <VPMUtil.h>
  10. #include <vpconfig.h>
  11. #include <ddkernel.h>
  12. #include <KHandleArray.h>
  13. #include <FormatList.h>
  14. //==========================================================================
  15. // constructor
  16. CVBIVideoPort::CVBIVideoPort(LPUNKNOWN pUnk, HRESULT* phr)
  17. : CUnknown(NAME("VBI Object"), pUnk)
  18. , m_pDDVPContainer(NULL)
  19. , m_pOffscreenSurf(NULL)
  20. , m_pOffscreenSurf1( NULL )
  21. , m_bConnected(FALSE)
  22. , m_pIVPConfig(NULL)
  23. , m_VPState(VP_STATE_NO_VP)
  24. , m_bFilterRunning(FALSE)
  25. , m_Communication(KSPIN_COMMUNICATION_SOURCE)
  26. , m_CategoryGUID(GUID_NULL)
  27. , m_pDirectDraw(NULL)
  28. , m_dwPixelsPerSecond(0)
  29. , m_dwVideoPortId(0)
  30. , m_pVideoPort(NULL)
  31. , m_dwDefaultOutputFormat( 0 )
  32. {
  33. AMTRACE((TEXT("CVBIVideoPort::Constructor")));
  34. m_Medium.Set = GUID_NULL;
  35. m_Medium.Id = 0;
  36. m_Medium.Flags = 0;
  37. ZeroStruct( m_capVPDataInfo );
  38. ZeroStruct( m_svpInfo );
  39. ZeroStruct( m_vpCaps );
  40. ZeroStruct( m_vpConnectInfo );
  41. ZeroStruct( m_ddVPInputVideoFormat );
  42. ZeroStruct( m_ddVPOutputVideoFormat );
  43. }
  44. //==========================================================================
  45. // destructor
  46. CVBIVideoPort::~CVBIVideoPort()
  47. {
  48. AMTRACE((TEXT("CVBIVideoPort::Destructor")));
  49. if (m_bConnected)
  50. {
  51. DbgLog((LOG_ERROR, 0, TEXT("Destructor called without calling breakconnect")));
  52. BreakConnect();
  53. }
  54. return;
  55. }
  56. //==========================================================================
  57. // overridden to expose IVPVBINotify and IVideoPortVBIObject
  58. STDMETHODIMP CVBIVideoPort::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  59. {
  60. HRESULT hr = NOERROR;
  61. if (riid == IID_IVPVBINotify)
  62. {
  63. DbgLog((LOG_TRACE, 4, TEXT("CVBIVideoPort::NonDelegatingQueryInterface(IID_IVPVBINotify)")));
  64. hr = GetInterface( static_cast<IVPVBINotify*>( this ), ppv);
  65. if (FAILED(hr)) {
  66. DbgLog((LOG_ERROR, 0, TEXT("GetInterface(IVPVBINotify*) failed, hr = 0x%x"), hr));
  67. }
  68. }
  69. else if (riid == IID_IKsPin)
  70. {
  71. DbgLog((LOG_TRACE, 4, TEXT("CVBIVideoPort::NonDelegatingQueryInterface(IID_IKsPin)")));
  72. hr = GetInterface( static_cast<IKsPin*>( this ), ppv);
  73. if (FAILED(hr)) {
  74. DbgLog((LOG_ERROR, 0, TEXT("GetInterface(IKsPin*) failed, hr = 0x%x"), hr));
  75. }
  76. }
  77. else if (riid == IID_IKsPropertySet)
  78. {
  79. DbgLog((LOG_TRACE, 4, TEXT("CVBIVideoPort::NonDelegatingQueryInterface(IID_IKsPropertySet)")));
  80. hr = GetInterface( static_cast<IKsPropertySet*>( this ), ppv);
  81. if (FAILED(hr)) {
  82. DbgLog((LOG_ERROR, 0, TEXT("GetInterface(IKsPropertySet*) failed, hr = 0x%x"), hr));
  83. }
  84. }
  85. else
  86. {
  87. DbgLog((LOG_TRACE, 4, TEXT("CVBIVideoPort::NonDelegatingQueryInterface(Other)")));
  88. hr = CUnknown::NonDelegatingQueryInterface(riid, ppv);
  89. if (FAILED(hr)) {
  90. DbgLog((LOG_ERROR, 0, TEXT("CUnknown::NonDelegatingQueryInterface failed, hr = 0x%x"), hr));
  91. }
  92. }
  93. return hr;
  94. }
  95. //==========================================================================
  96. // sets the pointer to directdraw
  97. STDMETHODIMP CVBIVideoPort::SetDirectDraw(LPDIRECTDRAW7 pDirectDraw)
  98. {
  99. CAutoLock cObjectLock(m_pMainObjLock);
  100. AMTRACE((TEXT("CVBIVideoPort::SetDirectDraw")));
  101. HRESULT hr = NOERROR;
  102. m_pDirectDraw = pDirectDraw;
  103. return hr;
  104. }
  105. //==========================================================================
  106. // sets the pointer to the lock, which would be used to synchronize calls to the object
  107. STDMETHODIMP CVBIVideoPort::SetObjectLock(CCritSec* pMainObjLock)
  108. {
  109. AMTRACE((TEXT("CVBIVideoPort::SetObjectLock")));
  110. HRESULT hr = NOERROR;
  111. if (!pMainObjLock)
  112. {
  113. DbgLog((LOG_ERROR, 0, TEXT("pMainObjLock is NULL")));
  114. hr = E_INVALIDARG;
  115. goto CleanUp;
  116. }
  117. m_pMainObjLock = pMainObjLock;
  118. CleanUp:
  119. return hr;
  120. }
  121. //==========================================================================
  122. // check that the mediatype is acceptable
  123. STDMETHODIMP CVBIVideoPort::CheckMediaType(const CMediaType* pmt)
  124. {
  125. CAutoLock cObjectLock(m_pMainObjLock);
  126. AMTRACE((TEXT("CVBIVideoPort::CheckMediaType")));
  127. HRESULT hr = NOERROR;
  128. if ((pmt->majortype != MEDIATYPE_Video) || (pmt->subtype != MEDIASUBTYPE_VPVBI))
  129. {
  130. hr = VFW_E_TYPE_NOT_ACCEPTED;
  131. goto CleanUp;
  132. }
  133. CleanUp:
  134. return hr;
  135. }
  136. //==========================================================================
  137. HRESULT CVBIVideoPort::GetMediaType(int iPosition, CMediaType* pmt)
  138. {
  139. CAutoLock cObjectLock(m_pMainObjLock);
  140. AMTRACE((TEXT("CVBIVideoPort::GetMediaType")));
  141. HRESULT hr = S_OK;
  142. if (iPosition == 0)
  143. {
  144. pmt->SetType(&MEDIATYPE_Video);
  145. pmt->SetSubtype(&MEDIASUBTYPE_VPVBI);
  146. pmt->SetFormatType(&FORMAT_None);
  147. pmt->SetSampleSize(1);
  148. pmt->SetTemporalCompression(FALSE);
  149. }
  150. else if (iPosition > 0) {
  151. hr = VFW_S_NO_MORE_ITEMS;
  152. } else { // iPosition < 0
  153. hr = E_INVALIDARG;
  154. }
  155. return hr;
  156. }
  157. //==========================================================================
  158. //
  159. STDMETHODIMP CVBIVideoPort::CheckConnect(IPin* pReceivePin)
  160. {
  161. CAutoLock cObjectLock(m_pMainObjLock);
  162. AMTRACE((TEXT("CVBIVideoPort::CheckConnect")));
  163. HRESULT hr = NOERROR;
  164. PKSMULTIPLE_ITEM pMediumList = NULL;
  165. IKsPin* pIKsPin = NULL;
  166. PKSPIN_MEDIUM pMedium = NULL;
  167. hr = pReceivePin->QueryInterface(IID_IKsPin, (void** )&pIKsPin);
  168. if (FAILED(hr))
  169. goto CleanUp;
  170. ASSERT(pIKsPin);
  171. hr = pIKsPin->KsQueryMediums(&pMediumList);
  172. if (FAILED(hr))
  173. goto CleanUp;
  174. ASSERT(pMediumList);
  175. pMedium = (KSPIN_MEDIUM* )(pMediumList+1);
  176. SetKsMedium((const KSPIN_MEDIUM* )pMedium);
  177. CleanUp:
  178. RELEASE (pIKsPin);
  179. if (pMediumList)
  180. {
  181. CoTaskMemFree((void*)pMediumList);
  182. pMediumList = NULL;
  183. }
  184. return hr;
  185. }
  186. //==========================================================================
  187. // supposed to be called when the host connects with the decoder
  188. STDMETHODIMP CVBIVideoPort::CompleteConnect(IPin* pReceivePin)
  189. {
  190. CAutoLock cObjectLock(m_pMainObjLock);
  191. AMTRACE((TEXT("CVBIVideoPort::CompleteConnect")));
  192. ASSERT(!m_bConnected);
  193. HRESULT hr = NOERROR;
  194. // re-initialize variables
  195. m_dwPixelsPerSecond = 0;
  196. ZeroStruct( m_vpConnectInfo );
  197. ZeroStruct( m_capVPDataInfo );
  198. if (!m_pDirectDraw)
  199. {
  200. DbgLog((LOG_ERROR, 0, TEXT("m_pDirectDraw is NULL")));
  201. hr = VFW_E_VP_NEGOTIATION_FAILED;
  202. goto CleanUp;
  203. }
  204. ASSERT(m_pIVPConfig == NULL);
  205. RELEASE( m_pIVPConfig );
  206. hr = pReceivePin->QueryInterface(IID_IVPVBIConfig, (void** )&m_pIVPConfig);
  207. if (FAILED(hr))
  208. {
  209. DbgLog((LOG_ERROR,0, TEXT("QueryInterface(IID_IVPVBIConfig) failed, hr = 0x%x"), hr));
  210. hr = VFW_E_NO_TRANSPORT;
  211. goto CleanUp;
  212. }
  213. ASSERT(m_pIVPConfig);
  214. // create the VP container
  215. ASSERT(m_pDDVPContainer == NULL);
  216. hr = m_pDirectDraw->QueryInterface( IID_IDDVideoPortContainer, (LPVOID* )&m_pDDVPContainer);
  217. if (FAILED(hr))
  218. {
  219. DbgLog((LOG_ERROR,0, TEXT("m_pDirectDraw->QueryInterface(IID_IDDVideoPortContainer) failed, hr = 0x%x"), hr));
  220. hr = VFW_E_VP_NEGOTIATION_FAILED;
  221. goto CleanUp;
  222. }
  223. // negotiate the connection parameters
  224. // get/set connection info happens here
  225. hr = NegotiateConnectionParameters();
  226. if (FAILED(hr))
  227. {
  228. DbgLog((LOG_ERROR, 0, TEXT("NegotiateConnectionParameters failed, hr = 0x%x"), hr));
  229. hr = VFW_E_VP_NEGOTIATION_FAILED;
  230. goto CleanUp;
  231. }
  232. // get the decoder data parameters
  233. hr = GetDecoderVPDataInfo();
  234. if (FAILED(hr))
  235. {
  236. DbgLog((LOG_ERROR, 0, TEXT("GetDecoderVPDataInfo failed, hr = 0x%x"), hr));
  237. hr = VFW_E_VP_NEGOTIATION_FAILED;
  238. goto CleanUp;
  239. }
  240. hr = SetupVideoPort();
  241. if (FAILED(hr))
  242. {
  243. DbgLog((LOG_ERROR, 0, TEXT("SetupVideoPort failed, hr = 0x%x"), hr));
  244. hr = VFW_E_VP_NEGOTIATION_FAILED;
  245. goto CleanUp;
  246. }
  247. // Success!
  248. m_bConnected = TRUE;
  249. CleanUp:
  250. if (FAILED(hr))
  251. BreakConnect();
  252. return hr;
  253. }
  254. //==========================================================================
  255. STDMETHODIMP CVBIVideoPort::BreakConnect()
  256. {
  257. CAutoLock cObjectLock(m_pMainObjLock);
  258. AMTRACE((TEXT("CVBIVideoPort::BreakConnect")));
  259. ASSERT(!m_bFilterRunning);
  260. HRESULT hr = NOERROR;
  261. if( m_bConnected ) {
  262. if (m_VPState == VP_STATE_RUNNING)
  263. {
  264. DbgLog((LOG_ERROR, 0, TEXT("BreakConnect called while videoport running")));
  265. StopVideo();
  266. }
  267. if (m_VPState == VP_STATE_STOPPED)
  268. {
  269. hr = TearDownVideoPort();
  270. if (FAILED(hr))
  271. {
  272. DbgLog((LOG_ERROR, 0, TEXT("TearDownVideoPort failed, hr = 0x%x"), hr));
  273. return hr;
  274. }
  275. }
  276. // release the videoport container
  277. RELEASE (m_pDDVPContainer);
  278. // release the IVPConfig interface
  279. RELEASE (m_pIVPConfig);
  280. // delete the output Video pixelformat
  281. ZeroStruct( m_ddVPOutputVideoFormat);
  282. // delete the input Video pixelformat
  283. ZeroStruct( m_ddVPInputVideoFormat);
  284. m_bConnected = FALSE;
  285. }
  286. return hr;
  287. }
  288. //==========================================================================
  289. // transition from Stop to Pause.
  290. // We do not need to to anything
  291. STDMETHODIMP CVBIVideoPort::Active()
  292. {
  293. CAutoLock cObjectLock(m_pMainObjLock);
  294. AMTRACE((TEXT("CVBIVideoPort::Active")));
  295. ASSERT(m_bConnected);
  296. ASSERT(!m_bFilterRunning);
  297. ASSERT(m_VPState != VP_STATE_RUNNING);
  298. HRESULT hr = NOERROR;
  299. if (!m_bConnected)
  300. {
  301. hr = VFW_E_NOT_CONNECTED;
  302. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::Active - not connected")));
  303. goto CleanUp;
  304. }
  305. CleanUp:
  306. return hr;
  307. }
  308. //==========================================================================
  309. // transition (from Pause or Run) to Stop
  310. STDMETHODIMP CVBIVideoPort::Inactive()
  311. {
  312. CAutoLock cObjectLock(m_pMainObjLock);
  313. AMTRACE((TEXT("CVBIVideoPort::Inactive")));
  314. ASSERT(m_bConnected);
  315. HRESULT hr = NOERROR;
  316. if (!m_bConnected)
  317. {
  318. hr = VFW_E_NOT_CONNECTED;
  319. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::Inactive - not connected")));
  320. goto CleanUp;
  321. }
  322. // Inactive is also called when going from pause to stop, in which case the
  323. // VideoPort would have already been stopped in the function RunToPause.
  324. // Also, we may have been temporarily disconnected from the videoport by
  325. // a full screen DOS box or a DirectX game, in which case m_VPState would be
  326. // VP_STATE_RETRYING
  327. if (m_VPState == VP_STATE_RUNNING)
  328. {
  329. ASSERT(m_bFilterRunning);
  330. // stop the VideoPort
  331. hr = StopVideo();
  332. if (FAILED(hr))
  333. {
  334. DbgLog((LOG_ERROR, 0, TEXT("StopVideo failed, hr = 0x%x"), hr));
  335. goto CleanUp;
  336. }
  337. }
  338. m_bFilterRunning = FALSE;
  339. CleanUp:
  340. return hr;
  341. }
  342. //==========================================================================
  343. // transition from Pause to Run. We just start the VideoPort.
  344. STDMETHODIMP CVBIVideoPort::Run(REFERENCE_TIME tStart)
  345. {
  346. CAutoLock cObjectLock(m_pMainObjLock);
  347. AMTRACE((TEXT("CVBIVideoPort::Run")));
  348. UNREFERENCED_PARAMETER(tStart);
  349. ASSERT(m_bConnected);
  350. ASSERT(!m_bFilterRunning);
  351. ASSERT(m_VPState != VP_STATE_RUNNING);
  352. HRESULT hr = NOERROR;
  353. if (!m_bConnected)
  354. {
  355. hr = VFW_E_NOT_CONNECTED;
  356. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::Run - not connected")));
  357. goto CleanUp;
  358. }
  359. if (m_VPState == VP_STATE_NO_VP)
  360. {
  361. hr = SetupVideoPort();
  362. if (FAILED(hr))
  363. {
  364. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::Run - SetupVideoPort failed, hr = 0x%x"), hr));
  365. goto CleanUp;
  366. }
  367. }
  368. hr = StartVideo();
  369. if (FAILED(hr))
  370. {
  371. DbgLog((LOG_ERROR, 0, TEXT("StartVideo failed, hr = 0x%x"), hr));
  372. ASSERT( SUCCEEDED(hr));
  373. goto CleanUp;
  374. }
  375. m_bFilterRunning = TRUE;
  376. CleanUp:
  377. return hr;
  378. }
  379. //==========================================================================
  380. // transition from Run to Pause. We just stop the VideoPort
  381. // Note that transition from Run to Stop is caught by Inactive
  382. STDMETHODIMP CVBIVideoPort::RunToPause()
  383. {
  384. CAutoLock cObjectLock(m_pMainObjLock);
  385. AMTRACE((TEXT("CVBIVideoPort::RunToPause")));
  386. ASSERT(m_bConnected);
  387. ASSERT(m_bFilterRunning);
  388. HRESULT hr = NOERROR;
  389. if (!m_bConnected)
  390. {
  391. hr = VFW_E_NOT_CONNECTED;
  392. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::RunToPause - not connected")));
  393. goto CleanUp;
  394. }
  395. // We may have been temporarily disconnected from the videoport by
  396. // a full screen DOS box or a DirectX game, in which case m_VPState would be
  397. // VP_STATE_RETRYING
  398. if (m_VPState == VP_STATE_RUNNING)
  399. {
  400. // stop the VideoPort
  401. hr = StopVideo();
  402. if (FAILED(hr))
  403. {
  404. DbgLog((LOG_ERROR, 0, TEXT("StopVideo failed, hr = 0x%x"), hr));
  405. goto CleanUp;
  406. }
  407. }
  408. m_bFilterRunning = FALSE;
  409. CleanUp:
  410. return hr;
  411. }
  412. //==========================================================================
  413. STDMETHODIMP CVBIVideoPort::GetVPDataInfo(AMVPDATAINFO* pAMVPDataInfo)
  414. {
  415. CAutoLock cObjectLock(m_pMainObjLock);
  416. AMTRACE((TEXT("CVBIVideoPort::GetVPDataInfo")));
  417. HRESULT hr = NOERROR;
  418. if (!m_bConnected)
  419. {
  420. hr = VFW_E_NOT_CONNECTED;
  421. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::GetVPDataInfo - not connected")));
  422. goto CleanUp;
  423. }
  424. if (!pAMVPDataInfo)
  425. {
  426. hr = E_INVALIDARG;
  427. DbgLog((LOG_ERROR, 2, TEXT("pAMVPDataInfo is NULL")));
  428. goto CleanUp;
  429. }
  430. *pAMVPDataInfo = m_capVPDataInfo;
  431. CleanUp:
  432. return hr;
  433. }
  434. //==========================================================================
  435. // this function is used to redo the whole videoport connect process, while the graph
  436. // maybe be running.
  437. STDMETHODIMP CVBIVideoPort::RenegotiateVPParameters()
  438. {
  439. CAutoLock cObjectLock(m_pMainObjLock);
  440. DbgLog((LOG_TRACE, 1, TEXT("Entering CVBIVideoPort::RenegotiateVPParameters")));
  441. ASSERT(m_bConnected);
  442. HRESULT hr = NOERROR;
  443. if (!m_bConnected)
  444. {
  445. hr = VFW_E_NOT_CONNECTED;
  446. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::RenegotiateVPParameters - not connected")));
  447. goto CleanUp;
  448. }
  449. if (m_VPState == VP_STATE_RUNNING)
  450. StopVideo();
  451. if (m_VPState == VP_STATE_STOPPED)
  452. TearDownVideoPort();
  453. hr = SetupVideoPort(); // always want_vp_setup (if connected)
  454. if (FAILED(hr))
  455. {
  456. DbgLog((LOG_ERROR,0, TEXT("SetupVideoPort failed in RenegotiateVPParameters, hr = 0x%x"), hr));
  457. goto CleanUp;
  458. }
  459. if (m_bFilterRunning)
  460. {
  461. hr = StartVideo();
  462. if (FAILED(hr))
  463. {
  464. DbgLog((LOG_ERROR,0, TEXT("StartVideo failed in RenegotiateVPParameters, hr = 0x%x"), hr));
  465. goto CleanUp;
  466. }
  467. }
  468. CleanUp:
  469. DbgLog((LOG_TRACE, 1, TEXT("Leaving CVBIVideoPort::RenegotiateVPParameters, hr = 0x%x"), hr));
  470. return hr;
  471. }
  472. //==========================================================================
  473. // IKsPin::Get implementation
  474. STDMETHODIMP CVBIVideoPort::Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData,
  475. DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD* pcbReturned)
  476. {
  477. HRESULT hr = S_OK;
  478. AMTRACE((TEXT("CVBIVideoPort::Get")));
  479. if (guidPropSet != AMPROPSETID_Pin)
  480. {
  481. hr = E_PROP_SET_UNSUPPORTED;
  482. goto CleanUp;
  483. }
  484. if ((pPropData == NULL) && (pcbReturned == NULL))
  485. {
  486. hr = E_POINTER;
  487. goto CleanUp;
  488. }
  489. if (dwPropID == KSPROPERTY_PIN_CATEGORY)
  490. {
  491. if (pcbReturned)
  492. * pcbReturned = sizeof(GUID);
  493. if (pPropData != NULL)
  494. {
  495. if (cbPropData < sizeof(GUID))
  496. {
  497. hr = E_UNEXPECTED;
  498. goto CleanUp;
  499. }
  500. * (GUID* )pPropData = m_CategoryGUID;
  501. }
  502. }
  503. else if (dwPropID == KSPROPERTY_PIN_MEDIUMS)
  504. {
  505. if (pcbReturned)
  506. * pcbReturned = sizeof (KSPIN_MEDIUM);
  507. if (pPropData != NULL)
  508. {
  509. if (cbPropData < sizeof(KSPIN_MEDIUM))
  510. {
  511. hr = E_UNEXPECTED;
  512. goto CleanUp;
  513. }
  514. * (KSPIN_MEDIUM* )pPropData = m_Medium;
  515. }
  516. }
  517. else
  518. hr = E_PROP_ID_UNSUPPORTED;
  519. CleanUp:
  520. return hr;
  521. }
  522. //==========================================================================
  523. //
  524. STDMETHODIMP CVBIVideoPort::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport)
  525. {
  526. HRESULT hr = S_OK;
  527. AMTRACE((TEXT("CVBIVideoPort::QuerySupported")));
  528. if (guidPropSet != AMPROPSETID_Pin)
  529. {
  530. hr = E_PROP_SET_UNSUPPORTED;
  531. goto CleanUp;
  532. }
  533. if ((dwPropID != KSPROPERTY_PIN_CATEGORY) && (dwPropID != KSPROPERTY_PIN_MEDIUMS))
  534. {
  535. hr = E_PROP_ID_UNSUPPORTED;
  536. goto CleanUp;
  537. }
  538. if (pTypeSupport)
  539. * pTypeSupport = KSPROPERTY_SUPPORT_GET;
  540. CleanUp:
  541. return hr;
  542. }
  543. //==========================================================================
  544. //
  545. STDMETHODIMP CVBIVideoPort::KsQueryMediums(PKSMULTIPLE_ITEM* pMediumList)
  546. {
  547. // The following special return code notifies the proxy that this pin is
  548. // not available as a kernel mode connection
  549. HRESULT hr = S_FALSE;
  550. AMTRACE((TEXT("CVBIVideoPort::KsQueryMediums")));
  551. * pMediumList = reinterpret_cast<PKSMULTIPLE_ITEM>(CoTaskMemAlloc(sizeof(**pMediumList)));
  552. if (!*pMediumList)
  553. {
  554. hr = E_OUTOFMEMORY;
  555. goto CleanUp;
  556. }
  557. (*pMediumList)->Count = 0;
  558. (*pMediumList)->Size = sizeof(**pMediumList);
  559. CleanUp:
  560. return hr;
  561. }
  562. //==========================================================================
  563. //
  564. STDMETHODIMP CVBIVideoPort::KsQueryInterfaces(PKSMULTIPLE_ITEM* pInterfaceList)
  565. {
  566. PKSPIN_INTERFACE pInterface;
  567. HRESULT hr = NOERROR;
  568. AMTRACE((TEXT("CVBIVideoPort::KsQueryInterfaces")));
  569. * pInterfaceList = reinterpret_cast<PKSMULTIPLE_ITEM>(CoTaskMemAlloc(sizeof(**pInterfaceList) + sizeof(*pInterface)));
  570. if (!*pInterfaceList)
  571. {
  572. hr = E_OUTOFMEMORY;
  573. goto CleanUp;
  574. }
  575. (*pInterfaceList)->Count = 1;
  576. (*pInterfaceList)->Size = sizeof(**pInterfaceList) + sizeof(*pInterface);
  577. pInterface = reinterpret_cast<PKSPIN_INTERFACE>(*pInterfaceList + 1);
  578. pInterface->Set = KSINTERFACESETID_Standard;
  579. pInterface->Id = KSINTERFACE_STANDARD_STREAMING;
  580. pInterface->Flags = 0;
  581. CleanUp:
  582. return hr;
  583. }
  584. //==========================================================================
  585. //
  586. STDMETHODIMP CVBIVideoPort::KsGetCurrentCommunication(KSPIN_COMMUNICATION* pCommunication,
  587. KSPIN_INTERFACE* pInterface, KSPIN_MEDIUM* pMedium)
  588. {
  589. AMTRACE((TEXT("CVBIVideoPort::KsGetCurrentCommunication")));
  590. if (pCommunication != NULL)
  591. * pCommunication = m_Communication;
  592. if (pInterface != NULL)
  593. {
  594. pInterface->Set = KSINTERFACESETID_Standard;
  595. pInterface->Id = KSINTERFACE_STANDARD_STREAMING;
  596. pInterface->Flags = 0;
  597. }
  598. if (pMedium != NULL)
  599. * pMedium = m_Medium;
  600. return NOERROR;
  601. }
  602. //==========================================================================
  603. // Called every second or two by the thread in CSurfaceWatcher m_SurfaceWatcher,
  604. // this function checks if we have lost our DDraw surface to a full-screen DOS box
  605. // or a DirectX game. If we have (on this call or a previous one or on a call
  606. // to RenegotiateVPParameters), attempt to get it back.
  607. HRESULT CVBIVideoPort::CheckSurfaces()
  608. {
  609. CAutoLock cObjectLock(m_pMainObjLock);
  610. //AMTRACE((TEXT("CVBIVideoPort::CheckSurfaces")));
  611. HRESULT hr = NOERROR;
  612. if (!m_bConnected)
  613. {
  614. //DbgLog((LOG_TRACE, 2, TEXT("CVBIVideoPort::CheckSurfaces - not connected")));
  615. goto CleanUp;
  616. }
  617. // First, see if we think we have surfaces but have really lost them.
  618. if (m_VPState != VP_STATE_NO_VP)
  619. {
  620. //DbgLog((LOG_TRACE, 1, TEXT("CVBIVideoPort::CheckSurfaces - checking surfaces")));
  621. if (m_pOffscreenSurf)
  622. {
  623. hr = m_pOffscreenSurf->IsLost();
  624. if (hr == DDERR_SURFACELOST)
  625. {
  626. DbgLog((LOG_TRACE, 1, TEXT("CVBIVideoPort::CheckSurfaces - Surface Lost!")));
  627. if (m_VPState == VP_STATE_RUNNING)
  628. {
  629. hr = StopVideo();
  630. if (FAILED(hr))
  631. {
  632. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::CheckSurfaces - StopVideo failed (1), hr = 0x%x"), hr));
  633. goto CleanUp;
  634. }
  635. }
  636. TearDownVideoPort();
  637. }
  638. }
  639. else
  640. {
  641. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::CheckSurfaces - no surface!")));
  642. if (m_VPState == VP_STATE_RUNNING)
  643. {
  644. hr = StopVideo();
  645. if (FAILED(hr))
  646. {
  647. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::CheckSurfaces - StopVideo failed (2), hr = 0x%x"), hr));
  648. goto CleanUp;
  649. }
  650. }
  651. TearDownVideoPort();
  652. }
  653. }
  654. // Next, check if our state is what we need. May have been changed above, or on a previous
  655. // call, or on a call to RenegotiateVPParameters.
  656. if (m_VPState == VP_STATE_NO_VP)
  657. {
  658. DbgLog((LOG_TRACE, 1, TEXT("CVBIVideoPort::CheckSurfaces - trying to re-setup videoport")));
  659. hr = SetupVideoPort();
  660. if (FAILED(hr))
  661. {
  662. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::CheckSurfaces - SetupVideoPort failed, hr = 0x%x"), hr));
  663. goto CleanUp;
  664. }
  665. }
  666. if ((m_VPState == VP_STATE_STOPPED) && m_bFilterRunning)
  667. {
  668. hr = StartVideo();
  669. if (FAILED(hr))
  670. {
  671. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::CheckSurfaces - StartVideo failed, hr = 0x%x"), hr));
  672. goto CleanUp;
  673. }
  674. }
  675. CleanUp:
  676. return NOERROR;
  677. }
  678. //==========================================================================
  679. // this functions negotiates the connection parameters with
  680. // the decoder.
  681. // Since this function might be called during renegotiation, the
  682. // existing connection parameters are passed in as input and if
  683. // possible, we try to use the same parameters.
  684. HRESULT CVBIVideoPort::GetVideoPortCaps()
  685. {
  686. AMTRACE((TEXT("CVBIVideoPort::GetVideoPortCaps")));
  687. HRESULT hr = NOERROR;
  688. // vpCaps is scratch memory, results stored in this->m_vpCaps
  689. ZeroStruct( m_vpCaps );
  690. // DDVIDEOPORTCAPS vpCaps;
  691. // INITDDSTRUCT( vpCaps );
  692. hr = VPMUtil::FindVideoPortCaps( m_pDDVPContainer, &m_vpCaps, m_dwVideoPortId );
  693. if (FAILED(hr) || S_FALSE == hr )
  694. {
  695. DbgLog((LOG_ERROR,0, TEXT("m_pDDVPContainer->EnumVideoPorts failed, hr = 0x%x"), hr));
  696. hr = VFW_E_VP_NEGOTIATION_FAILED;
  697. goto CleanUp;
  698. }
  699. CleanUp:
  700. return hr;
  701. }
  702. //==========================================================================
  703. // This functions negotiates the connection parameters with the decoder.
  704. HRESULT CVBIVideoPort::NegotiateConnectionParameters()
  705. {
  706. HRESULT hr = NOERROR;
  707. LPDDVIDEOPORTCONNECT lpddCaptureConnect = NULL;
  708. DWORD dwNumCaptureEntries = 0;
  709. LPDDVIDEOPORTCONNECT lpddVideoPortConnect = NULL;
  710. DWORD dwNumVideoPortEntries = 0;
  711. BOOL bIntersectionFound = FALSE;
  712. DWORD i, j;
  713. AMTRACE((TEXT("CVBIVideoPort::NegotiateConnectionParameters")));
  714. ASSERT(m_pIVPConfig);
  715. ASSERT(m_pDDVPContainer);
  716. // find the number of entries to be proposed by the decoder
  717. hr = m_pIVPConfig->GetConnectInfo(&dwNumCaptureEntries, NULL);
  718. if (FAILED(hr))
  719. {
  720. DbgLog((LOG_ERROR,0,TEXT("m_pIVPConfig->GetConnectInfo failed, hr = 0x%x"), hr));
  721. goto CleanUp;
  722. }
  723. ASSERT(dwNumCaptureEntries);
  724. // allocate the necessary memory
  725. lpddCaptureConnect = (LPDDVIDEOPORTCONNECT) new BYTE [dwNumCaptureEntries*sizeof(DDVIDEOPORTCONNECT)];
  726. if (lpddCaptureConnect == NULL)
  727. {
  728. DbgLog((LOG_ERROR,0,TEXT("NegotiateConnectionParameters : Out of Memory")));
  729. hr = E_OUTOFMEMORY;
  730. goto CleanUp;
  731. }
  732. // memset the allocated memory to zero
  733. memset(lpddCaptureConnect, 0, dwNumCaptureEntries*sizeof(DDVIDEOPORTCONNECT));
  734. // set the right size in each of the structs.
  735. for (i = 0; i < dwNumCaptureEntries; i++)
  736. {
  737. lpddCaptureConnect[i].dwSize = sizeof(DDVIDEOPORTCONNECT);
  738. }
  739. // get the entries proposed by the decoder
  740. hr = m_pIVPConfig->GetConnectInfo(&dwNumCaptureEntries, lpddCaptureConnect);
  741. if (FAILED(hr))
  742. {
  743. DbgLog((LOG_ERROR,0,TEXT("m_pIVPConfig->GetConnectInfo failed, hr = 0x%x"), hr));
  744. goto CleanUp;
  745. }
  746. // find the number of entries supported by the videoport
  747. hr = m_pDDVPContainer->GetVideoPortConnectInfo(m_dwVideoPortId, &dwNumVideoPortEntries, NULL);
  748. if (FAILED(hr))
  749. {
  750. DbgLog((LOG_ERROR,0,TEXT("m_pDDVPContainer->GetVideoPortConnectInfo failed, hr = 0x%x"), hr));
  751. goto CleanUp;
  752. }
  753. ASSERT(dwNumVideoPortEntries);
  754. // allocate the necessary memory
  755. lpddVideoPortConnect = (LPDDVIDEOPORTCONNECT) new BYTE[dwNumVideoPortEntries*sizeof(DDVIDEOPORTCONNECT)];
  756. if (lpddVideoPortConnect == NULL)
  757. {
  758. DbgLog((LOG_ERROR,0,TEXT("NegotiateConnectionParameters : Out of Memory")));
  759. hr = E_OUTOFMEMORY;
  760. goto CleanUp;
  761. }
  762. // memset the allocated memory to zero
  763. memset(lpddVideoPortConnect, 0, dwNumVideoPortEntries*sizeof(DDVIDEOPORTCONNECT));
  764. // set the right size in each of the structs.
  765. for (i = 0; i < dwNumVideoPortEntries; i++)
  766. {
  767. lpddVideoPortConnect[i].dwSize = sizeof(DDVIDEOPORTCONNECT);
  768. }
  769. // get the entries supported by the videoport
  770. hr = m_pDDVPContainer->GetVideoPortConnectInfo(0, &dwNumVideoPortEntries, lpddVideoPortConnect);
  771. if (FAILED(hr))
  772. {
  773. DbgLog((LOG_ERROR,0,TEXT("m_pDDVPContainer->GetVideoPortConnectInfo failed, hr = 0x%x"), hr));
  774. hr = E_FAIL;
  775. goto CleanUp;
  776. }
  777. #ifdef DEBUG
  778. for (i = 0; i < dwNumCaptureEntries; i++)
  779. DbgLog((LOG_TRACE, 3, TEXT("lpddCaptureConnect[%d].dwFlags = 0x%x"), i, lpddCaptureConnect[i].dwFlags));
  780. for (j = 0; j < dwNumVideoPortEntries; j++)
  781. DbgLog((LOG_TRACE,3,TEXT("lpddVideoPortConnect[%d].dwFlags = 0x%x"), j, lpddVideoPortConnect[j].dwFlags));
  782. #endif
  783. // take the first element of the intersection of the two lists and
  784. // set that value on the decoder
  785. for (i = 0; i < dwNumCaptureEntries && !bIntersectionFound; i++)
  786. {
  787. for (j = 0; j < dwNumVideoPortEntries && !bIntersectionFound; j++)
  788. {
  789. if (lpddCaptureConnect[i].dwPortWidth == lpddVideoPortConnect[j].dwPortWidth &&
  790. IsEqualIID(lpddCaptureConnect[i].guidTypeID, lpddVideoPortConnect[j].guidTypeID))
  791. {
  792. // make sure we save the right one (the one from the video port, not the one
  793. // from the capture driver)
  794. memcpy(&m_vpConnectInfo, (lpddVideoPortConnect+j), sizeof(DDVIDEOPORTCONNECT));
  795. hr = m_pIVPConfig->SetConnectInfo(i);
  796. if (FAILED(hr))
  797. {
  798. DbgLog((LOG_ERROR,0,TEXT("m_pIVPConfig->SetConnectInfo failed, hr = 0x%x"), hr));
  799. goto CleanUp;
  800. }
  801. bIntersectionFound = TRUE;
  802. }
  803. }
  804. }
  805. if (!bIntersectionFound)
  806. {
  807. hr = E_FAIL;
  808. goto CleanUp;
  809. }
  810. // cleanup
  811. CleanUp:
  812. delete [] lpddCaptureConnect;
  813. delete [] lpddVideoPortConnect;
  814. return hr;
  815. }
  816. //==========================================================================
  817. // This functions gets various data parameters from the decoder
  818. // parameters include dimensions, double-clock, vact etc.
  819. // Also maximum pixel rate the decoder will output.
  820. // This happens after the connnection parameters have been set-up
  821. HRESULT CVBIVideoPort::GetDecoderVPDataInfo()
  822. {
  823. HRESULT hr = NOERROR;
  824. DWORD dwMaxPixelsPerSecond = 0;
  825. AMVPSIZE amvpSize;
  826. AMTRACE((TEXT("CVBIVideoPort::GetDecoderVPDataInfo")));
  827. // set the size of the struct
  828. m_capVPDataInfo.dwSize = sizeof(AMVPDATAINFO);
  829. // get the VideoPort data information
  830. hr = m_pIVPConfig->GetVPDataInfo(&m_capVPDataInfo);
  831. if (FAILED(hr))
  832. {
  833. DbgLog((LOG_ERROR,0,TEXT("m_pIVPConfig->GetVPDataInfo failed, hr = 0x%x"), hr));
  834. goto CleanUp;
  835. }
  836. amvpSize.dwWidth = m_capVPDataInfo.amvpDimInfo.dwVBIWidth;
  837. amvpSize.dwHeight = m_capVPDataInfo.amvpDimInfo.dwVBIHeight;
  838. // get the maximum pixel rate the decoder will output
  839. hr = m_pIVPConfig->GetMaxPixelRate(&amvpSize, &dwMaxPixelsPerSecond);
  840. if (FAILED(hr))
  841. {
  842. DbgLog((LOG_ERROR,0,TEXT("m_pIVPConfig->GetMaxPixelRate failed, hr = 0x%x"), hr));
  843. goto CleanUp;
  844. }
  845. m_dwPixelsPerSecond = dwMaxPixelsPerSecond;
  846. CleanUp:
  847. return hr;
  848. }
  849. //==========================================================================
  850. // Calls DDRAW to actually create the video port.
  851. HRESULT CVBIVideoPort::CreateVideoPort()
  852. {
  853. HRESULT hr = NOERROR;
  854. DDVIDEOPORTDESC svpDesc;
  855. AMTRACE((TEXT("CVBIVideoPort::CreateVideoPort")));
  856. INITDDSTRUCT( svpDesc );
  857. // fill up the fields of the description struct
  858. svpDesc.dwVBIWidth = m_capVPDataInfo.amvpDimInfo.dwVBIWidth;
  859. svpDesc.dwFieldHeight = m_capVPDataInfo.amvpDimInfo.dwFieldHeight;
  860. svpDesc.dwFieldWidth = m_capVPDataInfo.amvpDimInfo.dwFieldWidth;
  861. svpDesc.dwMicrosecondsPerField = m_capVPDataInfo.dwMicrosecondsPerField;
  862. svpDesc.dwMaxPixelsPerSecond = m_dwPixelsPerSecond;
  863. svpDesc.dwVideoPortID = m_dwVideoPortId;
  864. //DAG_TODO: need to use QueryVideoPortStatus
  865. svpDesc.VideoPortType.dwSize = sizeof(DDVIDEOPORTCONNECT);
  866. svpDesc.VideoPortType.dwPortWidth = m_vpConnectInfo.dwPortWidth;
  867. memcpy(&(svpDesc.VideoPortType.guidTypeID), &(m_vpConnectInfo.guidTypeID), sizeof(GUID));
  868. svpDesc.VideoPortType.dwFlags = 0;
  869. // if the decoder can send double clocked data and the videoport
  870. // supports it, then set that property. This field is only valid
  871. // with an external signal.
  872. if (m_capVPDataInfo.bEnableDoubleClock &&
  873. m_vpConnectInfo.dwFlags & DDVPCONNECT_DOUBLECLOCK)
  874. {
  875. svpDesc.VideoPortType.dwFlags |= DDVPCONNECT_DOUBLECLOCK;
  876. }
  877. // if the decoder can give an external activation signal and the
  878. // videoport supports it, then set that property. This field is
  879. // only valid with an external signal.
  880. if (m_capVPDataInfo.bEnableVACT &&
  881. m_vpConnectInfo.dwFlags & DDVPCONNECT_VACT)
  882. {
  883. svpDesc.VideoPortType.dwFlags |= DDVPCONNECT_VACT;
  884. }
  885. // if the decoder can send interlaced data and the videoport
  886. // supports it, then set that property.
  887. // !!!SJF_TODO - should we fail if the decoder can't send interlaced data?
  888. if (m_capVPDataInfo.bDataIsInterlaced)
  889. {
  890. svpDesc.VideoPortType.dwFlags |= DDVPCONNECT_INTERLACED;
  891. }
  892. if (m_bHalfLineFix)
  893. {
  894. //!!!SJF_TODO - flip polarity back to normal on decoder?
  895. ASSERT(!m_capVPDataInfo.bFieldPolarityInverted);
  896. //!!!SJF_TODO - fail if videoport doesn't handle inverted polarity?
  897. ASSERT(m_vpConnectInfo.dwFlags & DDVPCONNECT_INVERTPOLARITY);
  898. DbgLog((LOG_TRACE, 3, TEXT("INVERTPOLARITY & HALFLINE")));
  899. svpDesc.VideoPortType.dwFlags |=
  900. (DDVPCONNECT_INVERTPOLARITY | DDVPCONNECT_HALFLINE);
  901. }
  902. #if 0 // def DEBUG
  903. DbgLog((LOG_TRACE, 3, TEXT("CreateVideoPort - DDVIDEOPORTDESC")));
  904. DbgLog((LOG_TRACE, 3, TEXT("dwSize: %d"),svpDesc.dwSize));
  905. DbgLog((LOG_TRACE, 3, TEXT("dwFieldWidth: %d"),svpDesc.dwFieldWidth));
  906. DbgLog((LOG_TRACE, 3, TEXT("dwVBIWidth: %d"),svpDesc.dwVBIWidth));
  907. DbgLog((LOG_TRACE, 3, TEXT("dwFieldHeight: %d"),svpDesc.dwFieldHeight));
  908. DbgLog((LOG_TRACE, 3, TEXT("dwMicroseconds: %d"),svpDesc.dwMicrosecondsPerField));
  909. DbgLog((LOG_TRACE, 3, TEXT("dwMaxPixels: %d"),svpDesc.dwMaxPixelsPerSecond));
  910. DbgLog((LOG_TRACE, 3, TEXT("dwVideoPortID: %d"),svpDesc.dwVideoPortID));
  911. DbgLog((LOG_TRACE, 3, TEXT("dwReserved1: %d"),svpDesc.dwReserved1));
  912. DbgLog((LOG_TRACE, 3, TEXT("dwReserved2: %d"),svpDesc.dwReserved2));
  913. DbgLog((LOG_TRACE, 3, TEXT("dwReserved3: %d"),svpDesc.dwReserved3));
  914. DbgLog((LOG_TRACE, 3, TEXT("DDVIDEOPORTCONNECT")));
  915. DbgLog((LOG_TRACE, 3, TEXT("dwSize: %d"),svpDesc.VideoPortType.dwSize));
  916. DbgLog((LOG_TRACE, 3, TEXT("dwPortWidth: %d"),svpDesc.VideoPortType.dwPortWidth));
  917. DbgLog((LOG_TRACE, 3, TEXT("dwFlags: 0x%x"),svpDesc.VideoPortType.dwFlags));
  918. DbgLog((LOG_TRACE, 3, TEXT("GUID: 0x%x"),*((DWORD* )&svpDesc.VideoPortType.guidTypeID)));
  919. DbgLog((LOG_TRACE, 3, TEXT("dwReserved1: %d"),svpDesc.VideoPortType.dwReserved1));
  920. #endif // DEBUG
  921. // create the videoport. The first parameter is dwFlags, reserved for
  922. // future use by ddraw. The last parameter is pUnkOuter, again must be
  923. // NULL.
  924. hr = m_pDDVPContainer->CreateVideoPort(DDVPCREATE_VBIONLY, &svpDesc, &m_pVideoPort, NULL );
  925. if (FAILED(hr))
  926. {
  927. DbgLog((LOG_ERROR, 0, TEXT("Unable to create the video port, hr = 0x%x"), hr));
  928. goto CleanUp;
  929. }
  930. CleanUp:
  931. return hr;
  932. }
  933. //==========================================================================
  934. // this function is used to allocate an offscreen surface to attach to the
  935. // videoport.
  936. // The allocation order it tries is just in decreasing amount of memory
  937. // required.
  938. // (3 buffers, single height)
  939. // (2 buffers, single height)
  940. // (1 buffer , single height).
  941. HRESULT CVBIVideoPort::CreateVPSurface(void)
  942. {
  943. DWORD dwMaxBuffers;
  944. HRESULT hr = NOERROR;
  945. DWORD dwCurHeight = 0, dwCurBuffers = 0;
  946. AMTRACE((TEXT("CVBIVideoPort::CreateVPSurface")));
  947. ASSERT(m_pDirectDraw);
  948. // we will try to allocate up to 3 buffers (unless the
  949. // hardware can handle less than 3)
  950. dwMaxBuffers = 3;
  951. if (m_vpCaps.dwNumVBIAutoFlipSurfaces < dwMaxBuffers)
  952. dwMaxBuffers = m_vpCaps.dwNumVBIAutoFlipSurfaces;
  953. // initialize the fields of ddsdDesc
  954. DDSURFACEDESC2 ddsdDesc;
  955. INITDDSTRUCT( ddsdDesc );
  956. ddsdDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  957. ddsdDesc.ddpfPixelFormat = m_ddVPOutputVideoFormat;
  958. ddsdDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_VIDEOPORT;
  959. // if we're bob interleaving, the VBI surface seems to need to be doubled too, so always
  960. // double it (the VBI surface memory is relatively small anyways)
  961. ddsdDesc.dwHeight = m_dwSurfaceHeight * 2;
  962. ddsdDesc.dwWidth = m_dwSurfacePitch;
  963. DbgLog((LOG_TRACE, 3, TEXT("Surface height %d, width %d, max buffers %d"),
  964. ddsdDesc.dwHeight, ddsdDesc.dwWidth, dwMaxBuffers));
  965. // we will only try to allocate more than one buffer if the videoport
  966. // is cabable of autoflipping
  967. if ((m_vpCaps.dwFlags & DDVPD_CAPS) && (m_vpCaps.dwCaps & DDVPCAPS_AUTOFLIP) && dwMaxBuffers > 1)
  968. {
  969. ddsdDesc.dwFlags |= DDSD_BACKBUFFERCOUNT;
  970. ddsdDesc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
  971. for (dwCurBuffers = dwMaxBuffers; !m_pOffscreenSurf && dwCurBuffers >= 2; dwCurBuffers--)
  972. {
  973. ddsdDesc.dwBackBufferCount = dwCurBuffers-1;
  974. hr = m_pDirectDraw->CreateSurface(&ddsdDesc, &m_pOffscreenSurf, NULL);
  975. if (SUCCEEDED(hr))
  976. {
  977. hr = m_pOffscreenSurf->QueryInterface( IID_IDirectDrawSurface, (VOID **)&m_pOffscreenSurf1 );
  978. if( SUCCEEDED( hr )) {
  979. DbgLog((LOG_TRACE, 3, TEXT("allocated %d backbuffers"), ddsdDesc.dwBackBufferCount));
  980. goto CleanUp;
  981. } else {
  982. // should never fail, but just in case try again
  983. ASSERT( !"VBI Surface doesn't support DDraw1" );
  984. RELEASE( m_pOffscreenSurf );
  985. }
  986. }
  987. else
  988. {
  989. DbgLog((LOG_ERROR, 0, TEXT("failed to allocate %d backbuffers, hr = 0x%x"),
  990. ddsdDesc.dwBackBufferCount, hr));
  991. }
  992. }
  993. }
  994. // we should only reach this point when attempt to allocate multiple
  995. // buffers failed or no autoflip available
  996. DbgLog((LOG_ERROR, 0, TEXT("Warning: unable to allocate backbuffers")));
  997. ddsdDesc.dwFlags &= ~DDSD_BACKBUFFERCOUNT;
  998. ddsdDesc.ddsCaps.dwCaps &= ~(DDSCAPS_COMPLEX | DDSCAPS_FLIP);
  999. m_svpInfo.dwVPFlags &= ~DDVP_AUTOFLIP;
  1000. hr = m_pDirectDraw->CreateSurface(&ddsdDesc, &m_pOffscreenSurf, NULL);
  1001. if (SUCCEEDED(hr))
  1002. {
  1003. hr = m_pOffscreenSurf->QueryInterface( IID_IDirectDrawSurface, (VOID **)&m_pOffscreenSurf1 );
  1004. if( SUCCEEDED( hr )) {
  1005. goto CleanUp;
  1006. } else {
  1007. // should never fail, but just in case try again
  1008. ASSERT( !"VBI Surface doesn't support DDraw1" );
  1009. RELEASE( m_pOffscreenSurf );
  1010. }
  1011. }
  1012. ASSERT(!m_pOffscreenSurf);
  1013. DbgLog((LOG_ERROR,0, TEXT("Unable to create offscreen surface")));
  1014. CleanUp:
  1015. return hr;
  1016. }
  1017. //==========================================================================
  1018. // this function is used to inform the decoder of the various ddraw kernel handle
  1019. // using IVPConfig interface
  1020. HRESULT CVBIVideoPort::SetDDrawKernelHandles()
  1021. {
  1022. HRESULT hr = NOERROR;
  1023. IDirectDrawKernel* pDDK = NULL;
  1024. IDirectDrawSurfaceKernel* pDDSK = NULL;
  1025. ULONG_PTR* rgKernelHandles = NULL;
  1026. DWORD dwCount = 0;
  1027. ULONG_PTR ddKernelHandle = 0;
  1028. AMTRACE((TEXT("CVBIVideoPort::SetDDrawKernelHandles")));
  1029. // get the IDirectDrawKernel interface
  1030. ASSERT(m_pDirectDraw);
  1031. hr = m_pDirectDraw->QueryInterface(IID_IDirectDrawKernel, (LPVOID* )&pDDK);
  1032. if (FAILED(hr))
  1033. {
  1034. DbgLog((LOG_ERROR,0,TEXT("QueryInterface for IDirectDrawKernel failed, hr = 0x%x"), hr));
  1035. goto CleanUp;
  1036. }
  1037. // get the kernel handle
  1038. ASSERT(pDDK);
  1039. hr = pDDK->GetKernelHandle(&ddKernelHandle);
  1040. if (FAILED(hr))
  1041. {
  1042. DbgLog((LOG_ERROR,0,TEXT("GetKernelHandle from IDirectDrawKernel failed, hr = 0x%x"), hr));
  1043. goto CleanUp;
  1044. }
  1045. // set the kernel handle to directdraw using IVPConfig
  1046. ASSERT(m_pIVPConfig);
  1047. ASSERT(ddKernelHandle);
  1048. hr = m_pIVPConfig->SetDirectDrawKernelHandle(ddKernelHandle);
  1049. if (FAILED(hr))
  1050. {
  1051. DbgLog((LOG_ERROR,0,TEXT("IVPConfig::SetDirectDrawKernelHandle failed, hr = 0x%x"), hr));
  1052. goto CleanUp;
  1053. }
  1054. // set the VidceoPort Id using IVPConfig
  1055. ASSERT(m_pIVPConfig);
  1056. hr = m_pIVPConfig->SetVideoPortID(m_dwVideoPortId);
  1057. if (FAILED(hr))
  1058. {
  1059. DbgLog((LOG_ERROR,0,TEXT("IVPConfig::SetVideoPortID failed, hr = 0x%x"), hr));
  1060. goto CleanUp;
  1061. }
  1062. {
  1063. // should not be NULL
  1064. ASSERT( m_pOffscreenSurf1 );
  1065. KernelHandleArray pArray( m_pOffscreenSurf, hr );
  1066. if (FAILED(hr))
  1067. {
  1068. DbgLog((LOG_ERROR,0,TEXT("GetKernelHandles failed, hr = 0x%x"), hr));
  1069. goto CleanUp;
  1070. }
  1071. // set the kernel handle to the offscreen surface using IVPConfig
  1072. ASSERT(m_pIVPConfig);
  1073. hr = m_pIVPConfig->SetDDSurfaceKernelHandles( pArray.GetCount(), pArray.GetHandles() );
  1074. if (FAILED(hr))
  1075. {
  1076. DbgLog((LOG_ERROR,0,TEXT("IVPConfig::SetDDSurfaceKernelHandles failed, hr = 0x%x"), hr));
  1077. goto CleanUp;
  1078. }
  1079. // call SetSurfaceParameters interface on IVPConfig
  1080. ASSERT(m_pIVPConfig);
  1081. DbgLog((LOG_TRACE, 3, TEXT("SetSurfaceParams(%d,%d,%d)"),
  1082. m_dwSurfacePitch, m_dwSurfaceOriginX, m_dwSurfaceOriginY));
  1083. hr = m_pIVPConfig->SetSurfaceParameters(m_dwSurfacePitch,
  1084. m_dwSurfaceOriginX,m_dwSurfaceOriginY);
  1085. if (FAILED(hr))
  1086. {
  1087. DbgLog((LOG_ERROR,0,TEXT("IVPConfig::SetSurfaceParameters failed, hr = 0x%x"), hr));
  1088. goto CleanUp;
  1089. }
  1090. }
  1091. CleanUp:
  1092. // release the kernel ddraw handle
  1093. RELEASE (pDDK);
  1094. return hr;
  1095. }
  1096. /*****************************Private*Routine******************************\
  1097. * CVideoPortObj::NegotiatePixelFormat
  1098. *
  1099. * this function is used to negotiate the pixelformat with the decoder.
  1100. * It asks the decoder fot a list of input formats, intersects that list
  1101. * with the one the deocoder supports (while maintaining the order) and
  1102. * then calls "GetBestFormat" on that list to get the "best" input and
  1103. * output format. After that it calls "SetPixelFormat" on the decoder in
  1104. * order to inform the decoder of the decision.
  1105. *
  1106. *
  1107. * History:
  1108. * Thu 09/09/1999 - StEstrop - Added this comment and cleaned up the code
  1109. *
  1110. \**************************************************************************/
  1111. HRESULT CVBIVideoPort::GetInputPixelFormats( PixelFormatList* pList )
  1112. {
  1113. AMTRACE((TEXT("CVideoPortObj::NegotiatePixelFormat")));
  1114. CAutoLock cObjectLock(m_pMainObjLock);
  1115. HRESULT hr = NOERROR;
  1116. // find the number of entries to be proposed
  1117. DWORD dwNumProposedEntries = 0;
  1118. hr = m_pIVPConfig->GetVideoFormats(&dwNumProposedEntries, NULL);
  1119. if (FAILED(hr))
  1120. {
  1121. DbgLog((LOG_ERROR,0,
  1122. TEXT("m_pIVPConfig->GetVideoFormats failed, hr = 0x%x"), hr));
  1123. return hr;
  1124. }
  1125. ASSERT(dwNumProposedEntries);
  1126. // find the number of entries supported by the videoport
  1127. DWORD dwNumVPInputEntries = 0;
  1128. hr = m_pVideoPort->GetInputFormats(&dwNumVPInputEntries, NULL, DDVPFORMAT_VBI);
  1129. if (FAILED(hr))
  1130. {
  1131. DbgLog((LOG_ERROR,0,
  1132. TEXT("m_pVideoPort->GetInputFormats failed, hr = 0x%x"), hr));
  1133. return hr;
  1134. }
  1135. ASSERT(dwNumVPInputEntries);
  1136. // allocate the necessary memory
  1137. PixelFormatList lpddProposedFormats(dwNumProposedEntries);
  1138. if (lpddProposedFormats.GetEntries() == NULL)
  1139. {
  1140. DbgLog((LOG_ERROR,0,TEXT("NegotiatePixelFormat : Out of Memory")));
  1141. hr = E_OUTOFMEMORY;
  1142. return hr;
  1143. }
  1144. // get the entries proposed
  1145. hr = m_pIVPConfig->GetVideoFormats(&dwNumProposedEntries, lpddProposedFormats.GetEntries() );
  1146. if (FAILED(hr))
  1147. {
  1148. DbgLog((LOG_ERROR,0,
  1149. TEXT("m_pIVPConfig->GetVideoFormats failed, hr = 0x%x"), hr));
  1150. return hr;
  1151. }
  1152. // allocate the necessary memory
  1153. PixelFormatList lpddVPInputFormats(dwNumVPInputEntries);
  1154. if (lpddVPInputFormats.GetEntries() == NULL)
  1155. {
  1156. DbgLog((LOG_ERROR,0,TEXT("NegotiatePixelFormat : Out of Memory")));
  1157. hr = E_OUTOFMEMORY;
  1158. return hr;
  1159. }
  1160. // get the entries supported by the videoport
  1161. hr = m_pVideoPort->GetInputFormats(&dwNumVPInputEntries,
  1162. lpddVPInputFormats.GetEntries(), DDVPFORMAT_VBI);
  1163. if (FAILED(hr))
  1164. {
  1165. DbgLog((LOG_ERROR,0,
  1166. TEXT("m_pVideoPort->GetInputFormats failed, hr = 0x%x"), hr));
  1167. hr = E_FAIL;
  1168. return hr;
  1169. }
  1170. *pList = lpddVPInputFormats.IntersectWith( lpddProposedFormats );
  1171. // the number of entries in the intersection is zero!!
  1172. // Return failure.
  1173. if (pList->GetCount() == 0)
  1174. {
  1175. hr = E_FAIL;
  1176. return hr;
  1177. }
  1178. // call GetBestFormat with whatever search criterion you want
  1179. // DWORD dwBestEntry;
  1180. // hr = GetBestFormat(lpddIntersectionFormats.GetCount(),
  1181. // lpddIntersectionFormats.GetEntries(), TRUE, &dwBestEntry,
  1182. // &m_ddVPOutputVideoFormat);
  1183. // if (FAILED(hr))
  1184. // {
  1185. // DbgLog((LOG_ERROR,0,TEXT("GetBestFormat failed, hr = 0x%x"), hr));
  1186. // } else {
  1187. // hr = SetVPInputPixelFormat( lpddIntersectionFormats[dwBestEntry] )
  1188. // }
  1189. return hr;
  1190. }
  1191. HRESULT
  1192. CVBIVideoPort::GetOutputPixelFormats(
  1193. const PixelFormatList& ddInputFormats,
  1194. PixelFormatList* pddOutputFormats )
  1195. {
  1196. HRESULT hr = S_OK;
  1197. AMTRACE((TEXT("CVideoPortObj::GetOutputFormats")));
  1198. CAutoLock cObjectLock(m_pMainObjLock);
  1199. for (DWORD i = 0; i < ddInputFormats.GetCount(); i++)
  1200. {
  1201. // For each input format, figure out the output formats
  1202. DDPIXELFORMAT* pInputFormat = const_cast<DDPIXELFORMAT*>(&ddInputFormats[i]);
  1203. DWORD dwNumOutputFormats;
  1204. hr = m_pVideoPort->GetOutputFormats(pInputFormat,
  1205. &dwNumOutputFormats,
  1206. NULL, DDVPFORMAT_VBI);
  1207. if (FAILED(hr))
  1208. {
  1209. DbgLog((LOG_ERROR,0,
  1210. TEXT("m_pVideoPort->GetOutputFormats failed, hr = 0x%x"),
  1211. hr));
  1212. break;
  1213. }
  1214. ASSERT(dwNumOutputFormats);
  1215. // allocate the necessary memory
  1216. pddOutputFormats[i].Reset( dwNumOutputFormats );
  1217. if (pddOutputFormats[i].GetEntries() == NULL)
  1218. {
  1219. DbgLog((LOG_ERROR, 0,
  1220. TEXT("new failed, failed to allocate memnory for ")
  1221. TEXT("lpddOutputFormats in NegotiatePixelFormat")));
  1222. hr = E_OUTOFMEMORY;
  1223. break;
  1224. }
  1225. // get the entries supported by the videoport
  1226. hr = m_pVideoPort->GetOutputFormats(pInputFormat,
  1227. &dwNumOutputFormats,
  1228. pddOutputFormats[i].GetEntries(),
  1229. DDVPFORMAT_VBI);
  1230. if (FAILED(hr))
  1231. {
  1232. DbgLog((LOG_ERROR,0,
  1233. TEXT("m_pVideoPort->GetOutputFormats failed, hr = 0x%x"),
  1234. hr));
  1235. break;
  1236. }
  1237. } // end of outer for loop
  1238. return hr;
  1239. }
  1240. HRESULT CVBIVideoPort::SetInputPixelFormat( DDPIXELFORMAT& ddFormat )
  1241. {
  1242. HRESULT hr = NOERROR;
  1243. // find the number of entries to be proposed
  1244. DWORD dwNumProposedEntries = 0;
  1245. hr = m_pIVPConfig->GetVideoFormats(&dwNumProposedEntries, NULL);
  1246. if (FAILED(hr))
  1247. {
  1248. DbgLog((LOG_ERROR,0,
  1249. TEXT("m_pIVPConfig->GetVideoFormats failed, hr = 0x%x"), hr));
  1250. return hr;
  1251. }
  1252. ASSERT(dwNumProposedEntries);
  1253. PixelFormatList lpddProposedFormats(dwNumProposedEntries);
  1254. if (lpddProposedFormats.GetEntries() == NULL)
  1255. {
  1256. DbgLog((LOG_ERROR,0,TEXT("NegotiatePixelFormat : Out of Memory")));
  1257. hr = E_OUTOFMEMORY;
  1258. return hr;
  1259. }
  1260. // get the entries proposed
  1261. hr = m_pIVPConfig->GetVideoFormats(&dwNumProposedEntries, lpddProposedFormats.GetEntries() );
  1262. if (FAILED(hr))
  1263. {
  1264. DbgLog((LOG_ERROR,0,
  1265. TEXT("m_pIVPConfig->GetVideoFormats failed, hr = 0x%x"), hr));
  1266. return hr;
  1267. }
  1268. // set the format the decoder is supposed to be using
  1269. for (DWORD i = 0; i < dwNumProposedEntries; i++)
  1270. {
  1271. if (VPMUtil::EqualPixelFormats(lpddProposedFormats[i], ddFormat ))
  1272. {
  1273. hr = m_pIVPConfig->SetVideoFormat(i);
  1274. if (FAILED(hr))
  1275. {
  1276. DbgLog((LOG_ERROR,0,
  1277. TEXT("m_pIVPConfig->SetVideoFormat failed, hr = 0x%x"),
  1278. hr));
  1279. return hr;
  1280. }
  1281. // cache the input format
  1282. m_ddVPInputVideoFormat = ddFormat;
  1283. break;
  1284. }
  1285. }
  1286. return hr;
  1287. }
  1288. //==========================================================================
  1289. HRESULT CVBIVideoPort::InitializeVideoPortInfo()
  1290. {
  1291. HRESULT hr = NOERROR;
  1292. RECT rcVPCrop;
  1293. AMTRACE((TEXT("CVBIVideoPort::InitializeVideoPortInfo")));
  1294. m_dwSurfacePitch = m_capVPDataInfo.amvpDimInfo.dwVBIWidth;
  1295. m_dwSurfaceHeight = m_capVPDataInfo.amvpDimInfo.dwVBIHeight;
  1296. m_dwSurfaceOriginX = m_capVPDataInfo.amvpDimInfo.rcValidRegion.left;
  1297. m_dwSurfaceOriginY = m_capVPDataInfo.amvpDimInfo.rcValidRegion.top;
  1298. m_bHalfLineFix = FALSE;
  1299. // If we ask the videoport to do cropping, the bottom of the cropping
  1300. // region MUST touch but not overlap the top of the cropping region
  1301. // for video set by OVMIXER due to h/w limitations.
  1302. // So, the bottom of our crop region is always dwVBIHeight (or
  1303. // possibly dwVBIHeight+1 if certain halfline fixes are in effect,
  1304. // see below) even if the capture driver hasn't set ValidRegion to
  1305. // include that many lines.
  1306. rcVPCrop.top = 0;
  1307. rcVPCrop.left = 0;
  1308. rcVPCrop.bottom = m_capVPDataInfo.amvpDimInfo.dwVBIHeight;
  1309. rcVPCrop.right = m_capVPDataInfo.amvpDimInfo.dwVBIWidth;
  1310. // Adjust for half-lines
  1311. // Some video decoders send halflines in even or odd field.
  1312. // Some video ports capture halflines, some don't.
  1313. // See Video Line Numbering using VPE by smac
  1314. if (m_vpConnectInfo.dwFlags & DDVPCONNECT_HALFLINE) // e.g. ATI videoport
  1315. {
  1316. if ((m_capVPDataInfo.lHalfLinesOdd == 0) &&
  1317. (m_capVPDataInfo.lHalfLinesEven == 1)) // e.g. Brooktree decoder
  1318. {
  1319. // ATI All In Wonder (AIW) board
  1320. // halfline problem
  1321. DbgLog((LOG_TRACE, 3, TEXT("Setting up for AIW h/w")));
  1322. m_dwSurfaceHeight++;
  1323. rcVPCrop.bottom += 1;
  1324. m_bHalfLineFix = TRUE;
  1325. }
  1326. else if (((m_capVPDataInfo.lHalfLinesOdd == -1) && (m_capVPDataInfo.lHalfLinesEven == 0)) || // e.g. Philips decoder
  1327. ((m_capVPDataInfo.lHalfLinesOdd == 0) && (m_capVPDataInfo.lHalfLinesEven == -1)) || // e.g. ? decoder
  1328. ((m_capVPDataInfo.lHalfLinesOdd == 0) && (m_capVPDataInfo.lHalfLinesEven == 0))) // e.g. ? decoder
  1329. {
  1330. // no halfline problem, do nothing
  1331. }
  1332. else
  1333. {
  1334. // YIKES! We have no solution for these cases (if they even exist)!
  1335. DbgLog((LOG_ERROR, 0,TEXT("CVBIVideoPort::InitializeVideoPortInfo: unfixable halfline problem!")));
  1336. hr = VFW_E_VP_NEGOTIATION_FAILED;
  1337. goto CleanUp;
  1338. }
  1339. }
  1340. else // videoport that doesn't capture halflines
  1341. {
  1342. if ((m_capVPDataInfo.lHalfLinesOdd == -1) &&
  1343. (m_capVPDataInfo.lHalfLinesEven == 0)) // e.g. Philips decoder
  1344. {
  1345. // halfline problem
  1346. m_dwSurfaceHeight++;
  1347. rcVPCrop.top -= 1;
  1348. m_bHalfLineFix = TRUE;
  1349. }
  1350. else if (((m_capVPDataInfo.lHalfLinesOdd == 0) && (m_capVPDataInfo.lHalfLinesEven == 1)) || // e.g. BT829 decoder
  1351. ((m_capVPDataInfo.lHalfLinesOdd == 1) && (m_capVPDataInfo.lHalfLinesEven == 0)) || // e.g. ? decoder
  1352. ((m_capVPDataInfo.lHalfLinesOdd == 0) && (m_capVPDataInfo.lHalfLinesEven == 0))) // e.g. ? decoder
  1353. {
  1354. // no halfline problem, do nothing
  1355. }
  1356. else
  1357. {
  1358. // YIKES! We have no solution for these cases (if they even exist)!
  1359. DbgLog((LOG_ERROR, 0,TEXT("CVBIVideoPort::InitializeVideoPortInfo: unfixable halfline problem!")));
  1360. hr = VFW_E_VP_NEGOTIATION_FAILED;
  1361. goto CleanUp;
  1362. }
  1363. }
  1364. // Adjust if video discards lines during the VREF period
  1365. if (m_vpConnectInfo.dwFlags & DDVPCONNECT_DISCARDSVREFDATA)
  1366. {
  1367. DbgLog((LOG_TRACE, 3, TEXT("VideoPort discards %d VREF lines"),
  1368. m_capVPDataInfo.dwNumLinesInVREF));
  1369. ASSERT(m_dwSurfaceOriginY >= m_capVPDataInfo.dwNumLinesInVREF);
  1370. m_dwSurfaceOriginY -= m_capVPDataInfo.dwNumLinesInVREF;
  1371. m_dwSurfaceHeight -= m_capVPDataInfo.dwNumLinesInVREF;
  1372. rcVPCrop.bottom -= m_capVPDataInfo.dwNumLinesInVREF;
  1373. }
  1374. // initialize the DDVIDEOPORTINFO struct to be passed to pVideoport->StartVideo
  1375. INITDDSTRUCT( m_svpInfo );
  1376. m_svpInfo.dwVBIHeight = m_dwSurfaceHeight;
  1377. // Assume we're going to be able to autoflip
  1378. m_svpInfo.dwVPFlags = DDVP_AUTOFLIP;
  1379. // pixelformats get filled in in NegotiatePixelFormats
  1380. #if 0 // !!!SJF_TODO - ATI says that cropping for VBI is not supported.
  1381. // We always set h/w cropping in the Y direction if we can.
  1382. // For VBI, we don't need to do cropping in the X direction.
  1383. // Can the videoport crop in the Y direction?
  1384. if ((m_vpCaps.dwFlags & DDVPD_FX) && (m_vpCaps.dwFX & DDVPFX_CROPY))
  1385. {
  1386. rcVPCrop.top = m_dwSurfaceOriginY;
  1387. m_dwSurfaceHeight -= m_dwSurfaceOriginY;
  1388. m_dwSurfaceOriginY = 0;
  1389. m_svpInfo.rCrop = rcVPCrop;
  1390. m_svpInfo.dwVPFlags |= DDVP_CROP;
  1391. DbgLog((LOG_TRACE, 3, TEXT("Cropping left top: (%d,%d)"),
  1392. m_svpInfo.rCrop.left, m_svpInfo.rCrop.top));
  1393. DbgLog((LOG_TRACE, 3, TEXT("Cropping bottom right: (%d,%d)"),
  1394. m_svpInfo.rCrop.right, m_svpInfo.rCrop.bottom));
  1395. }
  1396. else
  1397. {
  1398. if (m_bHalfLineFix)
  1399. {
  1400. DbgLog((LOG_ERROR, 0,TEXT("CVBIVideoPort::InitializeVideoPortInfo: can't crop to fix halfline problem!")));
  1401. hr = VFW_E_VP_NEGOTIATION_FAILED;
  1402. goto CleanUp;
  1403. }
  1404. }
  1405. #endif // 0
  1406. if (m_bHalfLineFix)
  1407. {
  1408. if (!(m_vpConnectInfo.dwFlags & DDVPCONNECT_INVERTPOLARITY))
  1409. {
  1410. DbgLog((LOG_ERROR, 0, TEXT("CVBIVideoPort::InitializeVideoPortInfo: can't invert polarity to fix halfline problem!")));
  1411. hr = VFW_E_VP_NEGOTIATION_FAILED;
  1412. goto CleanUp;
  1413. }
  1414. }
  1415. #if 0 // def DEBUG
  1416. DbgLog((LOG_TRACE, 3, TEXT("m_dwSurfaceHeight: %d"),m_dwSurfaceHeight));
  1417. DbgLog((LOG_TRACE, 3, TEXT("m_dwSurfacePitch: %d"),m_dwSurfacePitch));
  1418. DbgLog((LOG_TRACE, 3, TEXT("m_dwSurfaceOriginX: %d"),m_dwSurfaceOriginX));
  1419. DbgLog((LOG_TRACE, 3, TEXT("m_dwSurfaceOriginY: %d"),m_dwSurfaceOriginY));
  1420. #endif // DEBUG
  1421. CleanUp:
  1422. return hr;
  1423. }
  1424. //==========================================================================
  1425. //
  1426. HRESULT CVBIVideoPort::SetupVideoPort()
  1427. {
  1428. AMTRACE((TEXT("CVBIVideoPort::SetupVideoPort")));
  1429. ASSERT(m_VPState == VP_STATE_NO_VP);
  1430. HRESULT hr = NOERROR;
  1431. // initialize variables
  1432. ZeroStruct( m_svpInfo );
  1433. ZeroStruct( m_vpCaps );
  1434. // Get the Video Port caps
  1435. hr = GetVideoPortCaps();
  1436. if (FAILED(hr))
  1437. {
  1438. DbgLog((LOG_ERROR, 0, TEXT("GetVideoPortCaps failed, hr = 0x%x"), hr));
  1439. goto CleanUp;
  1440. }
  1441. // initalize the DDVideoPortInfo structure
  1442. hr = InitializeVideoPortInfo();
  1443. if (FAILED(hr))
  1444. {
  1445. DbgLog((LOG_ERROR, 0, TEXT("InitializeVideoPortInfo FAILED, hr = 0x%x"), hr));
  1446. goto CleanUp;
  1447. }
  1448. // create the video port
  1449. hr = CreateVideoPort();
  1450. if (FAILED(hr))
  1451. {
  1452. DbgLog((LOG_ERROR, 0, TEXT("CreateVideoPort failed, hr = 0x%x"), hr));
  1453. goto CleanUp;
  1454. }
  1455. // negotiate the pixel format
  1456. hr = NegotiatePixelFormat();
  1457. if ( FAILED( hr ))
  1458. {
  1459. DbgLog((LOG_ERROR, 0, TEXT("NegotiatePixelFormat Failed, hr = 0x%x"), hr));
  1460. goto CleanUp;
  1461. }
  1462. // Update the m_svpInfo structure which was mostly filled in in
  1463. // InitializeVideoPortInfo
  1464. ASSERT(VPMUtil::EqualPixelFormats(m_ddVPInputVideoFormat, m_ddVPOutputVideoFormat));
  1465. m_svpInfo.lpddpfVBIInputFormat = &m_ddVPInputVideoFormat;
  1466. m_svpInfo.lpddpfVBIOutputFormat = &m_ddVPOutputVideoFormat;
  1467. // create the offscreen surface
  1468. hr = CreateVPSurface();
  1469. if (FAILED(hr))
  1470. {
  1471. DbgLog((LOG_ERROR, 0, TEXT("CreateVPSurface FAILED, hr = 0x%x"), hr));
  1472. hr = VFW_E_OUT_OF_VIDEO_MEMORY;
  1473. goto CleanUp;
  1474. }
  1475. // attach the offscreen surface to the videoport
  1476. hr = m_pVideoPort->SetTargetSurface(m_pOffscreenSurf1, DDVPTARGET_VBI);
  1477. if (FAILED(hr))
  1478. {
  1479. DbgLog((LOG_ERROR, 0, TEXT("m_pVideoPort->SetTargetSurface failed, hr = 0x%x"), hr));
  1480. goto CleanUp;
  1481. }
  1482. // inform the decoder of the ddraw kernel handle, videoport id and surface kernel
  1483. // handle
  1484. hr = SetDDrawKernelHandles();
  1485. if (FAILED(hr))
  1486. {
  1487. DbgLog((LOG_ERROR, 0, TEXT("SetDDrawKernelHandles failed, hr = 0x%x"), hr));
  1488. goto CleanUp;
  1489. }
  1490. m_VPState = VP_STATE_STOPPED;
  1491. CleanUp:
  1492. if (FAILED(hr))
  1493. TearDownVideoPort();
  1494. return hr;
  1495. }
  1496. HRESULT CVBIVideoPort::NegotiatePixelFormat()
  1497. {
  1498. PixelFormatList ddInputVideoFormats;
  1499. HRESULT hr = GetInputPixelFormats( &ddInputVideoFormats );
  1500. if (FAILED(hr))
  1501. {
  1502. DbgLog((LOG_ERROR, 0,
  1503. TEXT("NegotiatePixelFormat Failed, hr = 0x%x"), hr));
  1504. } else {
  1505. PixelFormatList* pddOutputVideoFormats = NULL;
  1506. if( ddInputVideoFormats.GetCount() ) {
  1507. pddOutputVideoFormats = new PixelFormatList[ ddInputVideoFormats.GetCount() ];
  1508. if( !pddOutputVideoFormats ) {
  1509. hr = E_OUTOFMEMORY;
  1510. goto CleanUp;
  1511. }
  1512. hr = GetOutputPixelFormats( ddInputVideoFormats, pddOutputVideoFormats );
  1513. if (FAILED(hr))
  1514. {
  1515. DbgLog((LOG_ERROR, 0,
  1516. TEXT("NegotiatePixelFormat Failed, hr = 0x%x"), hr));
  1517. goto CleanUp;
  1518. }
  1519. // for every input format, figure out a table of every possible output format
  1520. // Then we can offer a list of possible output formats. When we need one of them, search
  1521. // the input lists to locate it (and possibly select the conversion with the lowest bandwidth)
  1522. PixelFormatList ddAllOutputVideoFormats = PixelFormatList::Union( pddOutputVideoFormats, ddInputVideoFormats.GetCount() );
  1523. if( ddAllOutputVideoFormats.GetCount() > 0 ) {
  1524. m_ddVPOutputVideoFormat = ddAllOutputVideoFormats[ m_dwDefaultOutputFormat ];
  1525. DWORD dwInput = PixelFormatList::FindListContaining(
  1526. m_ddVPOutputVideoFormat, pddOutputVideoFormats, ddInputVideoFormats.GetCount() );
  1527. if( dwInput < ddInputVideoFormats.GetCount() ) {
  1528. hr = SetInputPixelFormat( ddInputVideoFormats[dwInput] );
  1529. } else {
  1530. // can't happen
  1531. hr = E_FAIL;
  1532. goto CleanUp;
  1533. }
  1534. }
  1535. }
  1536. }
  1537. CleanUp:
  1538. return hr;
  1539. }
  1540. //==========================================================================
  1541. //
  1542. HRESULT CVBIVideoPort::TearDownVideoPort()
  1543. {
  1544. AMTRACE((TEXT("CVBIVideoPort::TearDownVideoPort")));
  1545. // Release the DirectDraw surface
  1546. RELEASE (m_pOffscreenSurf);
  1547. RELEASE (m_pOffscreenSurf1);
  1548. // release the videoport
  1549. RELEASE (m_pVideoPort);
  1550. m_VPState = VP_STATE_NO_VP;
  1551. return NOERROR;
  1552. }
  1553. //==========================================================================
  1554. //
  1555. HRESULT CVBIVideoPort::StartVideo()
  1556. {
  1557. AMTRACE((TEXT("CVBIVideoPort::StartVideo")));
  1558. ASSERT(m_VPState == VP_STATE_STOPPED);
  1559. HRESULT hr = NOERROR;
  1560. DWORD dwSignalStatus;
  1561. hr = m_pVideoPort->StartVideo(&m_svpInfo);
  1562. if (FAILED(hr))
  1563. {
  1564. DbgLog((LOG_ERROR, 0, TEXT("StartVideo failed, hr = 0x%x"), hr));
  1565. goto CleanUp;
  1566. }
  1567. m_VPState = VP_STATE_RUNNING;
  1568. DbgLog((LOG_TRACE, 2, TEXT("STARTVIDEO DONE!")));
  1569. // check if the videoport is receiving a signal.
  1570. hr = m_pVideoPort->GetVideoSignalStatus(&dwSignalStatus);
  1571. if (hr != E_NOTIMPL)
  1572. {
  1573. if (FAILED(hr))
  1574. {
  1575. DbgLog((LOG_ERROR, 0, TEXT("GetVideoSignalStatus() failed, hr = 0x%x"), hr));
  1576. goto CleanUp;
  1577. }
  1578. else if (dwSignalStatus == DDVPSQ_NOSIGNAL)
  1579. {
  1580. DbgLog((LOG_ERROR, 0, TEXT("GetVideoSignalStatus() returned DDVPSQ_NOSIGNAL, hr = 0x%x"), hr));
  1581. //goto CleanUp; // SJF_TODO - ignore error for now
  1582. }
  1583. }
  1584. //m_pVideoPort->WaitForSync(DDVPWAIT_END, 0, 0);
  1585. CleanUp:
  1586. return hr;
  1587. }
  1588. HRESULT CVBIVideoPort::StopVideo()
  1589. {
  1590. AMTRACE((TEXT("CVBIVideoPort::StopVideo")));
  1591. ASSERT(m_VPState == VP_STATE_RUNNING);
  1592. HRESULT hr = NOERROR;
  1593. hr = m_pVideoPort->StopVideo();
  1594. if (FAILED(hr))
  1595. {
  1596. DbgLog((LOG_ERROR,0, TEXT("m_pVideoPort->StopVideo failed, hr = 0x%x"), hr));
  1597. //goto CleanUp;
  1598. hr = NOERROR;
  1599. }
  1600. m_VPState = VP_STATE_STOPPED;
  1601. //CleanUp:
  1602. return hr;
  1603. }
  1604. /******************************Public*Routine******************************\
  1605. * CVideoPortObj::SetVideoPortID
  1606. *
  1607. *
  1608. *
  1609. * History:
  1610. * Thu 09/09/1999 - GlennE - Added this comment and cleaned up the code
  1611. *
  1612. \**************************************************************************/
  1613. STDMETHODIMP CVBIVideoPort::SetVideoPortID( DWORD dwVideoPortId )
  1614. {
  1615. AMTRACE((TEXT("CVideoPortObj::SetVideoPortID")));
  1616. CAutoLock cObjectLock(m_pMainObjLock);
  1617. HRESULT hr = S_OK;
  1618. if ( m_dwVideoPortId != dwVideoPortId ) {
  1619. // we can't switch ports when running
  1620. if( m_VPState != VPInfoState_STOPPED ) {
  1621. hr = VFW_E_WRONG_STATE;
  1622. } else {
  1623. if( m_pDDVPContainer ) {
  1624. hr = VPMUtil::FindVideoPortCaps( m_pDDVPContainer, NULL, m_dwVideoPortId );
  1625. } else {
  1626. hr = VPMUtil::FindVideoPortCaps( m_pDirectDraw, NULL, m_dwVideoPortId );
  1627. }
  1628. if( hr == S_OK) {
  1629. m_dwVideoPortId = dwVideoPortId;
  1630. } else if( hr == S_FALSE ) {
  1631. return E_INVALIDARG;
  1632. }// else fail
  1633. }
  1634. }
  1635. return hr;
  1636. }