Leaked source code of windows server 2003
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.

1176 lines
39 KiB

  1. // Copyright (c) 1997 - 1998 Microsoft Corporation. All Rights Reserved.
  2. // DDStrm.cpp : Implementation of CDDStream
  3. #include "stdafx.h"
  4. #include "project.h"
  5. //#define SHOWSURFACES
  6. #ifdef SHOWSURFACES
  7. // See if we can blt this to the screen
  8. void ShowSurface(IDirectDrawSurface *pSurface)
  9. {
  10. CComPtr<IDirectDraw> pDDraw;
  11. CComPtr<IDirectDrawSurface2> pSurface2;
  12. DDSURFACEDESC ddsdSurf;
  13. ddsdSurf.dwSize = sizeof(ddsdSurf);
  14. HRESULT hr = pSurface->QueryInterface(IID_IDirectDrawSurface2, (void **)&pSurface2);
  15. if (SUCCEEDED(hr)) {
  16. hr = pSurface2->GetDDInterface((void **)&pDDraw);
  17. }
  18. if (SUCCEEDED(hr)) {
  19. hr = pSurface->GetSurfaceDesc(&ddsdSurf);
  20. }
  21. if (SUCCEEDED(hr)) {
  22. CComPtr<IDirectDrawSurface> pPrimary;
  23. DDSURFACEDESC ddsd;
  24. ddsd.dwSize = sizeof(ddsd);
  25. ddsd.dwFlags = DDSD_CAPS;
  26. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  27. HRESULT hr = pDDraw->CreateSurface(&ddsd, &pPrimary, NULL);
  28. RECT rc;
  29. rc.left = 0;
  30. rc.top = 0;
  31. rc.right = ddsdSurf.dwWidth;
  32. rc.bottom = ddsdSurf.dwHeight;
  33. if (SUCCEEDED(hr)) {
  34. pPrimary->Blt(&rc, pSurface, &rc, DDBLT_WAIT, NULL);
  35. } else {
  36. }
  37. }
  38. }
  39. #endif
  40. /////////////////////////////////////////////////////////////////////////////
  41. // CDDStream
  42. CDDStream::CDDStream() :
  43. m_dwForcedFormatFlags(0),
  44. m_Height(0),
  45. m_Width(0),
  46. m_lLastPitch(0),
  47. m_pMyReadOnlySample(NULL),
  48. m_pDefPixelFormat(GetDefaultPixelFormatPtr(NULL))
  49. {
  50. }
  51. HRESULT CDDStream::InitDirectDraw()
  52. {
  53. HRESULT hr = NOERROR;
  54. if (!m_pDirectDraw) {
  55. CComPtr<IDirectDraw> pDDraw;
  56. hr = DirectDrawCreate(NULL, &pDDraw, NULL);
  57. if (SUCCEEDED(hr)) {
  58. hr = pDDraw->SetCooperativeLevel(NULL, DDSCL_NORMAL);
  59. }
  60. if (SUCCEEDED(hr)) {
  61. m_pDirectDraw = pDDraw;
  62. }
  63. }
  64. return hr;
  65. }
  66. HRESULT CDDStream::InternalAllocateSample(
  67. DWORD dwFlags,
  68. bool bIsInternalSample,
  69. IDirectDrawStreamSample **ppDDSample,
  70. bool bTemp
  71. )
  72. {
  73. AUTO_CRIT_LOCK;
  74. HRESULT hr = S_OK;
  75. CComPtr <IDirectDrawSurface> pSurface;
  76. CComPtr<IDirectDrawPalette> pPalette;
  77. //
  78. // Create the direct draw object here if necessary. It is important to call the
  79. // SetDirectDraw method so it can set other member variables appropriately
  80. //
  81. if (!m_pDirectDraw) {
  82. hr = InitDirectDraw();
  83. if (FAILED(hr)) {
  84. goto Exit;
  85. }
  86. }
  87. DDSURFACEDESC ddsd;
  88. ddsd.dwSize = sizeof(ddsd);
  89. GetFormatInternal(&ddsd, &pPalette, NULL, NULL);
  90. hr = m_pDirectDraw->CreateSurface(&ddsd, &pSurface, NULL);
  91. if (SUCCEEDED(hr)) {
  92. if (pPalette) {
  93. pSurface->SetPalette(pPalette);
  94. }
  95. RECT rect = {0, 0, ddsd.dwWidth, ddsd.dwHeight};
  96. hr = InternalCreateSample(pSurface,
  97. &rect,
  98. dwFlags,
  99. bIsInternalSample,
  100. ppDDSample,
  101. bTemp);
  102. // No need to release surface if create fails since pSurface is a CComPtr
  103. if (SUCCEEDED(hr) && !bIsInternalSample) {
  104. // Make sure the surface has a palette if the stream has one
  105. if (pPalette == NULL && m_pDirectDrawPalette) {
  106. pSurface->SetPalette(m_pDirectDrawPalette);
  107. }
  108. }
  109. }
  110. Exit:
  111. return hr;
  112. }
  113. STDMETHODIMP CDDStream::SetSameFormat(IMediaStream *pStream, DWORD dwFlags)
  114. {
  115. TRACEINTERFACE(_T("IDirectDrawStream::SetSameFormat(0x%8.8X, 0x%8.8X)\n"),
  116. pStream, dwFlags);
  117. CComQIPtr<IDirectDrawMediaStream, &IID_IDirectDrawMediaStream> pSource(pStream);
  118. if (!pSource) {
  119. return MS_E_INCOMPATIBLE;
  120. }
  121. DDSURFACEDESC ddsdCurrent;
  122. CComPtr <IDirectDrawPalette> pPalette;
  123. ddsdCurrent.dwSize = sizeof(ddsdCurrent);
  124. HRESULT hr = pSource->GetFormat(&ddsdCurrent, &pPalette, NULL, 0);
  125. /* Lock the source format */
  126. ddsdCurrent.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
  127. if (SUCCEEDED(hr)) {
  128. hr = pSource->SetFormat(&ddsdCurrent, pPalette);
  129. }
  130. if (SUCCEEDED(hr)) {
  131. hr = SetFormat(&ddsdCurrent, pPalette);
  132. if (SUCCEEDED(hr)) {
  133. CComPtr<IDirectDraw> pDD;
  134. hr = pSource->GetDirectDraw(&pDD);
  135. if (SUCCEEDED(hr)) {
  136. hr = SetDirectDraw(pDD);
  137. }
  138. }
  139. }
  140. return hr;
  141. }
  142. STDMETHODIMP CDDStream::AllocateSample(DWORD dwFlags, IStreamSample **ppSample)
  143. {
  144. TRACEINTERFACE(_T("IDirectDrawStream::AllocateSample(0x%8.8X, 0x%8.8X)\n"),
  145. dwFlags, ppSample);
  146. HRESULT hr;
  147. if (ppSample) {
  148. *ppSample = NULL;
  149. }
  150. if (!ppSample || dwFlags) {
  151. hr = E_INVALIDARG;
  152. } else {
  153. IDirectDrawStreamSample *pDDSample = NULL;
  154. hr = InternalAllocateSample(0, false, &pDDSample);
  155. *ppSample = pDDSample;
  156. }
  157. return hr;
  158. }
  159. STDMETHODIMP CDDStream::CreateSharedSample(IStreamSample *pExistingSample,
  160. DWORD dwFlags,
  161. IStreamSample **ppNewSample)
  162. {
  163. TRACEINTERFACE(_T("IDirectDrawStream::CreateSharedSample(0x%8.8X, 0x%8.8X, 0x%8.8X)\n"),
  164. pExistingSample, dwFlags, ppNewSample);
  165. *ppNewSample = NULL;
  166. CComQIPtr<IDirectDrawStreamSample, &IID_IDirectDrawStreamSample> pSource(pExistingSample);
  167. if (!pSource) {
  168. return MS_E_INCOMPATIBLE;
  169. }
  170. CComPtr<IDirectDrawSurface> pSurface;
  171. RECT rect;
  172. pSource->GetSurface(&pSurface, &rect);
  173. IDirectDrawStreamSample * pDDSample;
  174. HRESULT hr = CreateSample(pSurface, &rect, 0, &pDDSample);
  175. if (SUCCEEDED(hr)) {
  176. *ppNewSample = pDDSample;
  177. }
  178. return hr;
  179. }
  180. //
  181. // IDirectDrawMediaStream
  182. //
  183. void CDDStream::InitSurfaceDesc(LPDDSURFACEDESC lpddsd)
  184. {
  185. lpddsd->dwFlags = 0;
  186. if (m_Height) {
  187. lpddsd->dwHeight = m_Height;
  188. lpddsd->dwWidth = m_Width;
  189. } else {
  190. lpddsd->dwHeight = lpddsd->dwWidth = 100;
  191. }
  192. if ((m_dwForcedFormatFlags & DDSD_PIXELFORMAT) || m_pConnectedPin) {
  193. memcpy(&lpddsd->ddpfPixelFormat, &m_PixelFormat, sizeof(m_PixelFormat));
  194. } else {
  195. memcpy(&lpddsd->ddpfPixelFormat, m_pDefPixelFormat, sizeof(m_PixelFormat));
  196. }
  197. lpddsd->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
  198. }
  199. STDMETHODIMP CDDStream::GetFormat(DDSURFACEDESC *pDDSDCurrent,
  200. IDirectDrawPalette **ppDirectDrawPalette,
  201. DDSURFACEDESC *pDDSDDesired,
  202. DWORD *pdwFlags)
  203. {
  204. if(!m_pConnectedPin) {
  205. return MS_E_NOSTREAM;
  206. }
  207. return GetFormatInternal(pDDSDCurrent, ppDirectDrawPalette, pDDSDDesired, pdwFlags);
  208. }
  209. STDMETHODIMP CDDStream::GetFormatInternal(DDSURFACEDESC *pDDSDCurrent,
  210. IDirectDrawPalette **ppDirectDrawPalette,
  211. DDSURFACEDESC *pDDSDDesired,
  212. DWORD *pdwFlags)
  213. {
  214. TRACEINTERFACE(_T("IDirectDrawStream::GetFormat(0x%8.8X, 0x%8.8X, 0x%8.8X, 0x%8.8X)\n"),
  215. pDDSDCurrent, ppDirectDrawPalette, pDDSDDesired, pdwFlags);
  216. //
  217. // If we have never connected, and the format is not set, then default
  218. // to returning a height and width (100 x 100) and a caps of
  219. // data interchange type,
  220. //
  221. // If we are connected but haven't allocated a sureface, simply return the
  222. // correct height and width, and a caps of data interchange type.
  223. //
  224. // If we have a set format, then return the height, width, pixel format,
  225. // and caps of the current surfacedesc we have.
  226. //
  227. if (pDDSDCurrent) {
  228. InitSurfaceDesc(pDDSDCurrent);
  229. pDDSDCurrent->dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS | m_dwForcedFormatFlags;
  230. if (m_cAllocated) {
  231. pDDSDCurrent->dwFlags |= DDSD_PIXELFORMAT;
  232. }
  233. }
  234. if (pDDSDDesired) {
  235. InitSurfaceDesc(pDDSDDesired);
  236. if (m_pConnectedPin) {
  237. pDDSDDesired->dwFlags |= DDSD_HEIGHT | DDSD_WIDTH;
  238. }
  239. }
  240. if (ppDirectDrawPalette) {
  241. *ppDirectDrawPalette = m_pDirectDrawPalette;
  242. if (*ppDirectDrawPalette) {
  243. (*ppDirectDrawPalette)->AddRef();
  244. }
  245. }
  246. if (pdwFlags) {
  247. *pdwFlags = m_bSamplesAreReadOnly ? DDSFF_PROGRESSIVERENDER : 0;
  248. }
  249. return S_OK;
  250. }
  251. STDMETHODIMP CDDStream::SetFormat(const DDSURFACEDESC *lpDDSurfaceDesc,
  252. IDirectDrawPalette *pDirectDrawPalette)
  253. {
  254. TRACEINTERFACE(_T("IDirectDrawStream::SetFormat(0x%8.8X, 0x%8.8X)\n"),
  255. lpDDSurfaceDesc, pDirectDrawPalette);
  256. HRESULT hr = InternalSetFormat(lpDDSurfaceDesc, pDirectDrawPalette, false);
  257. if (hr == VFW_E_TYPE_NOT_ACCEPTED) {
  258. hr = DDERR_INVALIDSURFACETYPE;
  259. }
  260. return hr;
  261. }
  262. HRESULT CDDStream::RenegotiateMediaType(const DDSURFACEDESC *lpDDSurfaceDesc,
  263. IDirectDrawPalette *pPalette,
  264. const AM_MEDIA_TYPE *pmt)
  265. {
  266. HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
  267. // If the type is acceptable and we're using
  268. // our own allocator then QueryAccept is OK - we can
  269. // just return the new type from GetBuffer
  270. if (m_bUsingMyAllocator) {
  271. if (S_OK == m_pConnectedPin->QueryAccept(pmt)) {
  272. hr = S_OK;
  273. }
  274. }
  275. // Check if we'll be able to make a read-only sample
  276. if (m_bSamplesAreReadOnly) {
  277. // If the pixel format is not OK
  278. if (!IsSupportedType(&lpDDSurfaceDesc->ddpfPixelFormat)) {
  279. hr = VFW_E_TYPE_NOT_ACCEPTED;
  280. }
  281. }
  282. //
  283. // If we're stopped then we can attempt to reconnect
  284. //
  285. if (S_OK != hr && m_FilterState == State_Stopped) {
  286. AM_MEDIA_TYPE SavedType;
  287. DDSURFACEDESC ddsdSaved;
  288. CComPtr<IDirectDrawPalette> pPaletteSaved;
  289. ddsdSaved.dwSize = sizeof(ddsdSaved);
  290. ConnectionMediaType(&SavedType);
  291. GetFormatInternal(&ddsdSaved, &pPaletteSaved, NULL, NULL);
  292. CComPtr<IPin> pConnected = m_pConnectedPin;
  293. Disconnect();
  294. pConnected->Disconnect();
  295. IPin *ppinIn;
  296. IPin *ppinOut;
  297. if (m_Direction == PINDIR_INPUT) {
  298. ppinIn = this;
  299. ppinOut = pConnected;
  300. } else {
  301. ppinOut = this;
  302. ppinIn = pConnected;
  303. }
  304. HRESULT hrTmp = InternalSetFormat(lpDDSurfaceDesc, pPalette, false); // Recurse!
  305. if (SUCCEEDED(hrTmp)) {
  306. CComQIPtr<IGraphBuilder, &IID_IGraphBuilder>
  307. pBuilder(m_pFilterGraph);
  308. hrTmp = pBuilder->Connect(ppinOut, ppinIn);
  309. }
  310. if (FAILED(hrTmp)) {
  311. SetFormat(&ddsdSaved, pPaletteSaved);
  312. m_pFilterGraph->ConnectDirect(ppinOut, ppinIn, &SavedType);
  313. } else {
  314. hr = S_OK;
  315. }
  316. CoTaskMemFree(SavedType.pbFormat);
  317. }
  318. return hr;
  319. }
  320. HRESULT CDDStream::InternalSetFormat(const DDSURFACEDESC *lpDDSurfaceDesc,
  321. IDirectDrawPalette *pPalette,
  322. bool bFromPin,
  323. bool bQuery)
  324. {
  325. if (!lpDDSurfaceDesc) {
  326. return E_POINTER;
  327. }
  328. if (lpDDSurfaceDesc->dwSize != sizeof(*lpDDSurfaceDesc)) {
  329. return DDERR_INVALIDPARAMS;
  330. }
  331. DDSURFACEDESC ddsd;
  332. bool bPaletteAllocated = false;
  333. Lock();
  334. DDSURFACEDESC ddsdCopy;
  335. if (m_pConnectedPin && !bQuery &&
  336. (bFromPin && !(m_dwForcedFormatFlags & (DDSD_WIDTH | DDSD_HEIGHT)) ||
  337. !bFromPin && pPalette == NULL &&
  338. lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount == 8
  339. )
  340. ) {
  341. /* See what size the connected pin would like :
  342. -- If the width and height haven't been specified set them
  343. to the output pin's preferred values
  344. -- If no palette is specified try to get one from the output
  345. pin
  346. */
  347. AM_MEDIA_TYPE *pmt;
  348. IEnumMediaTypes *pEnum;
  349. HRESULT hr = m_pConnectedPin->EnumMediaTypes(&pEnum);
  350. if (SUCCEEDED(hr)) {
  351. ULONG ulGot;
  352. bool bBreak = false;
  353. while (!bBreak && S_OK == pEnum->Next(1, &pmt, &ulGot)) {
  354. if (pmt->formattype == FORMAT_VideoInfo) {
  355. VIDEOINFO *pvi = (VIDEOINFO *)pmt->pbFormat;
  356. if (bFromPin) {
  357. ddsdCopy = *lpDDSurfaceDesc;
  358. ddsdCopy.dwWidth = pvi->bmiHeader.biWidth;
  359. ddsdCopy.dwHeight = pvi->bmiHeader.biHeight < 0 ?
  360. -pvi->bmiHeader.biHeight :
  361. pvi->bmiHeader.biHeight;
  362. lpDDSurfaceDesc = &ddsdCopy;
  363. bBreak = true;
  364. } else {
  365. if (pmt->subtype == MEDIASUBTYPE_RGB8) {
  366. DDSURFACEDESC ddsd;
  367. _ASSERTE(pPalette == NULL);
  368. if (SUCCEEDED(ConvertMediaTypeToSurfaceDesc(
  369. pmt,
  370. m_pDirectDraw,
  371. &pPalette,
  372. &ddsd)) &&
  373. pPalette != NULL) {
  374. bPaletteAllocated = true;
  375. }
  376. bBreak = true;
  377. }
  378. }
  379. }
  380. DeleteMediaType(pmt);
  381. }
  382. pEnum->Release();
  383. }
  384. }
  385. InitSurfaceDesc(&ddsd);
  386. ddsd.dwFlags = lpDDSurfaceDesc->dwFlags;
  387. bool bMatches = true;
  388. bool bPixelFmtMatches = true;
  389. BOOL bContradictsForced = FALSE;
  390. if (ddsd.dwFlags & (DDSD_HEIGHT | DDSD_WIDTH)) {
  391. if (ddsd.dwHeight != lpDDSurfaceDesc->dwHeight ||
  392. ddsd.dwWidth != lpDDSurfaceDesc->dwWidth) {
  393. bMatches = false;
  394. ddsd.dwHeight = lpDDSurfaceDesc->dwHeight;
  395. ddsd.dwWidth = lpDDSurfaceDesc->dwWidth;
  396. bContradictsForced |= (m_dwForcedFormatFlags & DDSD_HEIGHT);
  397. }
  398. }
  399. if (ddsd.dwFlags & DDSD_PIXELFORMAT) {
  400. if (!ComparePixelFormats(&ddsd.ddpfPixelFormat,
  401. &lpDDSurfaceDesc->ddpfPixelFormat)) {
  402. bMatches = false;
  403. bPixelFmtMatches = false;
  404. bContradictsForced |= (m_dwForcedFormatFlags & DDSD_PIXELFORMAT);
  405. }
  406. // Always copy because ComparePixelFormats doesn't check all
  407. // the bits but we need to save the correct format for making
  408. // more surfaces
  409. memcpy(&ddsd.ddpfPixelFormat, &lpDDSurfaceDesc->ddpfPixelFormat, sizeof(ddsd.ddpfPixelFormat));
  410. }
  411. HRESULT hr;
  412. if (bMatches) {
  413. hr = S_OK;
  414. } else {
  415. if (bContradictsForced && bFromPin) {
  416. hr = VFW_E_TYPE_NOT_ACCEPTED;
  417. } else {
  418. if (m_cAllocated) {
  419. hr = MS_E_SAMPLEALLOC;
  420. } else {
  421. //
  422. // If the pin is trying to change its own type via query accept then skip the
  423. // renegotiation phase.
  424. //
  425. if (bFromPin || bQuery) {
  426. // If we're connected then this is from QueryAccept so we'll say OK. Otherwise, only
  427. // accept a ReceiveConnection if the pixel format matches the display pixel format.
  428. //
  429. // NOTE - aren't we going to return S_OK always here?
  430. // During connection m_pConnectedPin is not set anyway
  431. // and bQuery already checks for QueryAccept (Robin)
  432. hr = (m_pConnectedPin || bPixelFmtMatches) ? S_OK : VFW_E_TYPE_NOT_ACCEPTED;
  433. } else {
  434. _ASSERTE(!bQuery);
  435. // Note: The below call to ConvertSurfaceDescToMediaType should always be done to make
  436. // sure that the surface descriptor is valid, EVEN IF WE'RE NOT CONNECTED TO A PIN!
  437. AM_MEDIA_TYPE *pmt;
  438. hr = ConvertSurfaceDescToMediaType(lpDDSurfaceDesc, pPalette,
  439. NULL, true, &pmt);
  440. if (SUCCEEDED(hr)) {
  441. hr = m_pConnectedPin ? RenegotiateMediaType(lpDDSurfaceDesc, pPalette, pmt) : S_OK;
  442. DeleteMediaType(pmt);
  443. }
  444. }
  445. }
  446. }
  447. }
  448. //
  449. // Even if we match we may be forcing more format flags and
  450. // setting caps flags
  451. if (S_OK == hr && !bQuery) {
  452. // Don't update the pixel format if it was already forced
  453. if (ddsd.dwFlags & DDSD_PIXELFORMAT) {
  454. if (!bFromPin || !(m_dwForcedFormatFlags & DDSD_PIXELFORMAT)) {
  455. memcpy(&m_PixelFormat, &ddsd.ddpfPixelFormat, sizeof(m_PixelFormat));
  456. m_PixelFormat.dwSize = sizeof(m_PixelFormat);
  457. }
  458. }
  459. if (!bFromPin) {
  460. m_dwForcedFormatFlags = ddsd.dwFlags &
  461. (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS);
  462. }
  463. m_pDirectDrawPalette = pPalette;
  464. if (ddsd.dwFlags & (DDSD_HEIGHT | DDSD_WIDTH)) {
  465. m_Height = ddsd.dwHeight;
  466. m_Width = ddsd.dwWidth;
  467. }
  468. }
  469. if (bPaletteAllocated) {
  470. pPalette->Release();
  471. pPalette = NULL;
  472. }
  473. Unlock();
  474. return hr;
  475. }
  476. STDMETHODIMP CDDStream::GetDirectDraw(IDirectDraw **ppDirectDraw)
  477. {
  478. TRACEINTERFACE(_T("IDirectDrawStream::GetDirectDraw(0x%8.8X)\n"),
  479. ppDirectDraw);
  480. if (!ppDirectDraw) {
  481. return E_POINTER;
  482. }
  483. Lock();
  484. *ppDirectDraw = m_pDirectDraw;
  485. Unlock();
  486. if (*ppDirectDraw) {
  487. (*ppDirectDraw)->AddRef();
  488. }
  489. return S_OK;
  490. }
  491. STDMETHODIMP CDDStream::SetDirectDraw(IDirectDraw *pDirectDraw)
  492. {
  493. TRACEINTERFACE(_T("IDirectDrawStream::SetDirectDraw(0x%8.8X)\n"),
  494. pDirectDraw);
  495. HRESULT hr;
  496. AUTO_CRIT_LOCK;
  497. if (m_cAllocated) {
  498. hr = IsSameObject(m_pDirectDraw, pDirectDraw) ? S_OK : MS_E_SAMPLEALLOC;
  499. } else {
  500. //
  501. // NOTE: This is important! We need to release ALL objects that were allocated
  502. // by the previous DirectDraw object since they will magically disappear
  503. // beneath us. So far, the only object we hold is the palette so we'll copy
  504. // the entries and then create a new object.
  505. //
  506. hr = S_OK;
  507. if (m_pDirectDrawPalette) {
  508. if (pDirectDraw) {
  509. PALETTEENTRY aPaletteEntry[256];
  510. hr = m_pDirectDrawPalette->GetEntries(0, 0, 256, aPaletteEntry);
  511. if (SUCCEEDED(hr)) {
  512. CComPtr <IDirectDrawPalette> pNewPal;
  513. hr = pDirectDraw->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, aPaletteEntry, &pNewPal, NULL);
  514. if (SUCCEEDED(hr)) {
  515. m_pDirectDrawPalette = pNewPal;
  516. }
  517. }
  518. } else {
  519. m_pDirectDrawPalette = NULL; // If no direct draw object then toss the palette.
  520. }
  521. }
  522. if (SUCCEEDED(hr)) {
  523. m_pDirectDraw = pDirectDraw;
  524. if (pDirectDraw) {
  525. m_pDefPixelFormat = GetDefaultPixelFormatPtr(pDirectDraw);
  526. }
  527. }
  528. }
  529. return hr;
  530. }
  531. //
  532. // NOTE: For this function, the caller MUST provide a rect. The format of the surface
  533. // and the DirectDraw object are not checked for validity. They are assumed to be correct.
  534. //
  535. HRESULT CDDStream::InternalCreateSample(IDirectDrawSurface *pSurface, const RECT *pRect,
  536. DWORD dwFlags, bool bIsInternalSample,
  537. IDirectDrawStreamSample **ppSample,
  538. bool bTemp)
  539. {
  540. HRESULT hr = S_OK;
  541. *ppSample = NULL;
  542. AUTO_CRIT_LOCK;
  543. CDDSample *pSample;
  544. // First check the surface format
  545. {
  546. DDSURFACEDESC ddsd;
  547. CComPtr<IDirectDrawPalette> pPalette;
  548. pSurface->GetPalette(&pPalette);
  549. ddsd.dwSize = sizeof(ddsd);
  550. _ASSERTE(pRect != NULL);
  551. hr = pSurface->GetSurfaceDesc(&ddsd);
  552. ddsd.dwWidth = pRect->right - pRect->left;
  553. ddsd.dwHeight = pRect->bottom - pRect->top;
  554. if (SUCCEEDED(hr)) {
  555. hr = SetFormat(&ddsd, pPalette ? pPalette : m_pDirectDrawPalette);
  556. }
  557. }
  558. if (SUCCEEDED(hr)) {
  559. if (bIsInternalSample) {
  560. CDDInternalSample *pInternal = new CComObject<CDDInternalSample>;
  561. if (pInternal != NULL) {
  562. hr = pInternal->InternalInit();
  563. }
  564. pSample = pInternal;
  565. } else {
  566. pSample = new CComObject<CDDSample>;
  567. }
  568. if (pSample) {
  569. //
  570. // InitSample will increment our m_cAllocated variable if this is not an internal sample....
  571. //
  572. if (SUCCEEDED(hr)) {
  573. hr = pSample->InitSample(this, pSurface, pRect, dwFlags & DDSFF_PROGRESSIVERENDER, bIsInternalSample,
  574. bTemp);
  575. }
  576. if (SUCCEEDED(hr)) {
  577. pSample->GetControllingUnknown()->QueryInterface(IID_IDirectDrawStreamSample, (void **)ppSample);
  578. } else {
  579. delete pSample;
  580. }
  581. } else {
  582. hr = E_OUTOFMEMORY;
  583. }
  584. }
  585. #if 0
  586. // Use the real pixel format for subsequent surfaces
  587. if (SUCCEEDED(hr)) {
  588. m_PixelFormat.dwFlags = ddsd.ddpfPixelFormat.dwFlags;
  589. }
  590. #endif
  591. return hr;
  592. }
  593. STDMETHODIMP CDDStream::CreateSample(IDirectDrawSurface *pSurface, const RECT *pRect, DWORD dwFlags,
  594. IDirectDrawStreamSample **ppSample)
  595. {
  596. TRACEINTERFACE(_T("IDirectDrawStream::CreateSample(0x%8.8X, 0x%8.8X, 0x%8.8X, 0x%8.8X)\n"),
  597. pSurface, pRect, dwFlags, ppSample);
  598. HRESULT hr;
  599. *ppSample = NULL;
  600. if (dwFlags & (~DDSFF_PROGRESSIVERENDER)) {
  601. return E_INVALIDARG;
  602. }
  603. AUTO_CRIT_LOCK;
  604. if (pSurface == NULL) {
  605. if (pRect) {
  606. hr = E_INVALIDARG;
  607. } else {
  608. hr = InternalAllocateSample(dwFlags, false, ppSample);
  609. }
  610. } else {
  611. CComQIPtr <IDirectDrawSurface2, &IID_IDirectDrawSurface2> pSurf2(pSurface);
  612. // Work around DDrawEx bug
  613. IUnknown *pUnk;
  614. hr = pSurf2->GetDDInterface((void **)&pUnk);
  615. if (SUCCEEDED(hr)) {
  616. IDirectDraw *pDD;
  617. hr = pUnk->QueryInterface(IID_IDirectDraw, (void **)&pDD);
  618. pUnk->Release();
  619. if (SUCCEEDED(hr)) {
  620. hr = SetDirectDraw(pDD);
  621. pDD->Release();
  622. }
  623. }
  624. if (SUCCEEDED(hr)) {
  625. DDSURFACEDESC ddsd;
  626. ddsd.dwSize = sizeof(ddsd);
  627. hr = pSurface->GetSurfaceDesc(&ddsd);
  628. if (SUCCEEDED(hr)) {
  629. RECT SubRect;
  630. if (pRect) {
  631. SubRect = *pRect;
  632. if (SubRect.left > SubRect.right || SubRect.right > (LONG)ddsd.dwWidth ||
  633. SubRect.top > SubRect.bottom || SubRect.bottom > (LONG)ddsd.dwHeight) {
  634. hr = DDERR_INVALIDRECT;
  635. goto Exit;
  636. }
  637. ddsd.dwWidth = SubRect.right - SubRect.left;
  638. ddsd.dwHeight = SubRect.bottom - SubRect.top;
  639. } else {
  640. SubRect.top = SubRect.left = 0;
  641. SubRect.bottom = ddsd.dwHeight;
  642. SubRect.right = ddsd.dwWidth;
  643. }
  644. //
  645. // We don't set the CAPS flag here so we won't force a particular caps
  646. // mode. I'm not sure if this is the right choice, but it seems more
  647. // flexible.
  648. //
  649. ddsd.dwFlags &= (DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT);
  650. CComPtr<IDirectDrawPalette> pPalette;
  651. pSurface->GetPalette(&pPalette);
  652. hr = SetFormat(&ddsd, pPalette);
  653. if (SUCCEEDED(hr)) {
  654. hr = InternalCreateSample(pSurface, &SubRect, dwFlags, false, ppSample);
  655. }
  656. }
  657. }
  658. }
  659. Exit:
  660. return hr;
  661. }
  662. // Get the time per frame
  663. // If we're connected this comes out of the media type, otherwise we
  664. // don't know
  665. STDMETHODIMP CDDStream::GetTimePerFrame(
  666. /* [out] */ STREAM_TIME *pFrameTime
  667. )
  668. {
  669. if (pFrameTime == NULL) {
  670. return E_POINTER;
  671. }
  672. AUTO_CRIT_LOCK;
  673. if (m_pConnectedPin) {
  674. *pFrameTime = ((VIDEOINFO *)m_ConnectedMediaType.pbFormat)->AvgTimePerFrame;
  675. } else {
  676. return MS_E_NOSTREAM;
  677. }
  678. return S_OK;
  679. }
  680. //
  681. // IPin implementation
  682. //
  683. STDMETHODIMP CDDStream::ReceiveConnection(IPin * pConnector, const AM_MEDIA_TYPE *pmt)
  684. {
  685. AUTO_CRIT_LOCK;
  686. //
  687. // This helper function in CStream checks basic parameters for the Pin such as
  688. // the connecting pin's direction (we need to check this -- Sometimes the filter
  689. // graph will try to connect us to ourselves!) and other errors like already being
  690. // connected, etc.
  691. //
  692. HRESULT hr = CheckReceiveConnectionPin(pConnector);
  693. if (hr == NOERROR && pmt->formattype == FORMAT_VideoInfo) {
  694. //
  695. // Check the source accepts negative heights
  696. //
  697. VIDEOINFO * const pvi = (VIDEOINFO *)pmt->pbFormat;
  698. if (pvi->bmiHeader.biHeight > 0) {
  699. VIDEOINFO vi;
  700. CopyMemory((PVOID)&vi, (PVOID)pmt->pbFormat,
  701. min(pmt->cbFormat, sizeof(vi)));
  702. AM_MEDIA_TYPE mt = *pmt;
  703. mt.pbFormat = (PBYTE)&vi;
  704. vi.bmiHeader.biHeight = - vi.bmiHeader.biHeight;
  705. if (S_OK != pConnector->QueryAccept(&mt)) {
  706. hr = VFW_E_TYPE_NOT_ACCEPTED;
  707. }
  708. }
  709. }
  710. if (hr == NOERROR) {
  711. DDSURFACEDESC SurfaceDesc;
  712. SurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
  713. CComPtr <IDirectDrawPalette> pPalette;
  714. m_pConnectedPin = pConnector;
  715. if (NOERROR == ConvertMediaTypeToSurfaceDesc(pmt, m_pDirectDraw, &pPalette, &SurfaceDesc) &&
  716. SUCCEEDED(InternalSetFormat(&SurfaceDesc, pPalette, true))) {
  717. CopyMediaType(&m_ConnectedMediaType, pmt);
  718. CopyMediaType(&m_ActualMediaType, pmt);
  719. hr = NOERROR;
  720. } else {
  721. m_pConnectedPin = NULL;
  722. hr = VFW_E_TYPE_NOT_ACCEPTED;
  723. }
  724. }
  725. if (SUCCEEDED(hr)) {
  726. pConnector->QueryInterface(IID_IQualityControl, (void **)&m_pQC);
  727. }
  728. return hr;
  729. }
  730. STDMETHODIMP CDDStream::QueryAccept(const AM_MEDIA_TYPE *pmt)
  731. {
  732. AUTO_CRIT_LOCK;
  733. HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
  734. DDSURFACEDESC SurfaceDesc;
  735. SurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
  736. CComPtr <IDirectDrawPalette> pPalette;
  737. if (S_OK == ConvertMediaTypeToSurfaceDesc(pmt, m_pDirectDraw, &pPalette, &SurfaceDesc) &&
  738. SUCCEEDED(InternalSetFormat(&SurfaceDesc, pPalette, true, true)) &&
  739. ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight >= 0) {
  740. hr = S_OK;
  741. }
  742. return hr;
  743. }
  744. STDMETHODIMP CDDStream::Receive(IMediaSample *pMediaSample)
  745. {
  746. bool bDummySample = false;
  747. if (m_bFlushing || m_bStopIfNoSamples && m_cAllocated == 0) {
  748. EndOfStream();
  749. return S_FALSE;
  750. }
  751. HRESULT hr = S_OK;
  752. #ifdef DEBUG
  753. if (bDbgTraceTimes) {
  754. REFERENCE_TIME rtStart, rtStop;
  755. if (SUCCEEDED(pMediaSample->GetTime(&rtStart, &rtStop))) {
  756. ATLTRACE(_T("AMSTREAM.DLL : Video sample received - start %dms, end %dms, duration %dms\n"),
  757. (LONG)(rtStart / 10000), (LONG)(rtStop / 10000),
  758. (LONG)((rtStop - rtStart) / 10000));
  759. }
  760. }
  761. #endif
  762. if (m_bUsingMyAllocator) {
  763. CDDSample *pSrcSample = (CDDSample *)((CMediaSample *)pMediaSample)->m_pSample;
  764. pSrcSample->ReleaseMediaSampleLock();
  765. pSrcSample->m_bReceived = true;
  766. if (!pSrcSample->m_bWaited) {
  767. // Wait for render time
  768. REFERENCE_TIME rtStart, rtStop;
  769. if (SUCCEEDED(pMediaSample->GetTime(&rtStart, &rtStop))) {
  770. m_pFilter->WaitUntil(rtStart);
  771. }
  772. }
  773. if (pSrcSample->IsTemp()) {
  774. bDummySample = true;
  775. } else {
  776. #ifdef SHOWSURFACES
  777. ShowSurface(pSrcSample->m_pSurface);
  778. #endif
  779. // In this case if the read-only sample has no buddy then
  780. // it's a temp sample for the nostall stuff
  781. if (pSrcSample == m_pMyReadOnlySample &&
  782. !m_pMyReadOnlySample->HasBuddy()) {
  783. _ASSERTE(m_bNoStall);
  784. bDummySample = true;
  785. }
  786. }
  787. } else {
  788. CDDSample *pDestSample;
  789. REFERENCE_TIME rtStart, rtEnd;
  790. pMediaSample->GetTime(&rtStart, &rtEnd);
  791. hr = AllocDDSampleFromPool(&rtStart, &pDestSample);
  792. if (SUCCEEDED(hr)) {
  793. _ASSERTE(!pDestSample->IsTemp());
  794. Lock();
  795. // This is a media sample coming from a different allocator.
  796. AM_MEDIA_TYPE *pNewMediaType;
  797. if (pMediaSample->GetMediaType(&pNewMediaType) == S_OK) {
  798. FreeMediaType(m_ActualMediaType);
  799. // Note just copying has the effect
  800. // of transferring pNewMediaType's format block
  801. // and pUnk reference count
  802. // Also this way we avoid allocation failures
  803. m_ActualMediaType = *pNewMediaType;
  804. CoTaskMemFree((PVOID)pNewMediaType);
  805. }
  806. if (SUCCEEDED(hr)) {
  807. hr = pDestSample->CopyFrom(pMediaSample, &m_ActualMediaType);
  808. #ifdef SHOWSURFACES
  809. ShowSurface(pDestSample->m_pSurface);
  810. #endif
  811. hr = pDestSample->SetCompletionStatus(hr);
  812. // Warning! The SetCompletionStatus may delete pDestSample. Don't touch it after this point!
  813. }
  814. Unlock();
  815. } else {
  816. // Might be timeout which means we become a zombie
  817. hr = S_OK;
  818. bDummySample = true;
  819. }
  820. }
  821. // Send quality message if clocked
  822. // NOTE - we must do this AFTER releasing the media sample lock
  823. // or we can deadlock on the win16 lock when querying the clock
  824. // because dsound can be running on another thread waiting for
  825. // the win16 lock but holding its global mutex
  826. REFERENCE_TIME CurTime;
  827. if (S_OK == m_pFilter->GetCurrentStreamTime(&CurTime)) {
  828. REFERENCE_TIME rtStart, rtStop;
  829. if (m_pQC && SUCCEEDED(pMediaSample->GetTime(&rtStart, &rtStop))) {
  830. Quality msg;
  831. msg.Proportion = 1000;
  832. msg.Type = Famine;
  833. msg.Late = CurTime - rtStart;
  834. msg.TimeStamp = rtStart;
  835. if (bDummySample) {
  836. // Tell them they're later than they actually are
  837. msg.Late += 150 * 10000;
  838. }
  839. // Call Notify on our connected pin
  840. m_pQC->Notify(m_pBaseFilter, msg);
  841. //ATLTRACE("Late by %dms\n", (LONG)((CurTime - rtStart) / 10000));
  842. } else {
  843. //ATLTRACE("No timestamp\n");
  844. }
  845. }
  846. #ifdef DEBUG
  847. if (bDbgTraceTimes) {
  848. REFERENCE_TIME CurTime;
  849. m_pFilter->GetCurrentStreamTime(&CurTime);
  850. ATLTRACE(_T("AMSTREAM.DLL : Got sample at %dms\n"),
  851. (LONG)(CurTime / 10000));
  852. }
  853. #endif
  854. return hr;
  855. }
  856. STDMETHODIMP CDDStream::NotifyAllocator(IMemAllocator * pAllocator, BOOL bReadOnly)
  857. {
  858. if (bReadOnly) {
  859. // If the pixel format is not OK
  860. if (!IsSupportedType(&m_PixelFormat)) {
  861. return VFW_E_TYPE_NOT_ACCEPTED;
  862. }
  863. }
  864. return CStream::NotifyAllocator(pAllocator, bReadOnly);
  865. }
  866. //
  867. // IMemAllocator implementation
  868. //
  869. //
  870. // IMemAllocator
  871. //
  872. STDMETHODIMP CDDStream::SetProperties(ALLOCATOR_PROPERTIES* pRequest, ALLOCATOR_PROPERTIES* pActual)
  873. {
  874. HRESULT hr;
  875. AUTO_CRIT_LOCK;
  876. ZeroMemory(pActual, sizeof(*pActual));
  877. if (pRequest->cbAlign == 0) {
  878. hr = VFW_E_BADALIGN;
  879. } else {
  880. if (m_bCommitted == TRUE) {
  881. hr = VFW_E_ALREADY_COMMITTED;
  882. } else {
  883. m_lRequestedBufferCount = pRequest->cBuffers;
  884. hr = GetProperties(pActual);
  885. }
  886. }
  887. return hr;
  888. }
  889. STDMETHODIMP CDDStream::GetProperties(ALLOCATOR_PROPERTIES* pProps)
  890. {
  891. AUTO_CRIT_LOCK;
  892. AM_MEDIA_TYPE *pMediaType;
  893. HRESULT hr = GetMediaType(-1, &pMediaType);
  894. if (SUCCEEDED(hr)) {
  895. VIDEOINFO *pVideoInfo = (VIDEOINFO *)pMediaType->pbFormat;
  896. BITMAPINFOHEADER *pbmiHeader = &pVideoInfo->bmiHeader;
  897. pProps->cbBuffer = pbmiHeader->biSizeImage;
  898. pProps->cBuffers = m_lRequestedBufferCount ?
  899. m_lRequestedBufferCount : 1;
  900. pProps->cbAlign = 1;
  901. pProps->cbPrefix = 0;
  902. DeleteMediaType(pMediaType);
  903. }
  904. return hr;
  905. }
  906. STDMETHODIMP CDDStream::Decommit()
  907. {
  908. AUTO_CRIT_LOCK;
  909. if (m_pMyReadOnlySample) {
  910. m_pMyReadOnlySample->Die();
  911. m_pMyReadOnlySample->GetControllingUnknown()->Release();
  912. m_pMyReadOnlySample = NULL;
  913. }
  914. return CStream::Decommit();
  915. }
  916. //
  917. // This method assumes the critical section is *NOT* owned!
  918. //
  919. HRESULT CDDStream::GetMyReadOnlySample(CDDSample *pBuddy, CDDSample **ppSample)
  920. {
  921. *ppSample = NULL;
  922. CDDInternalSample *pROSample;
  923. Lock();
  924. if (!m_pMyReadOnlySample) {
  925. IDirectDrawStreamSample *pDDSample;
  926. HRESULT hr = InternalAllocateSample(DDSFF_PROGRESSIVERENDER, true, &pDDSample);
  927. if (FAILED(hr)) {
  928. Unlock();
  929. return hr;
  930. }
  931. m_pMyReadOnlySample = (CDDInternalSample *)pDDSample;
  932. }
  933. pROSample = m_pMyReadOnlySample;
  934. pROSample->GetControllingUnknown()->AddRef();
  935. Unlock();
  936. //
  937. // Must leave our critical section here! This is very important since JoinToBuddy can fail.
  938. //
  939. HRESULT hr;
  940. if (pBuddy) {
  941. hr = pROSample->JoinToBuddy(pBuddy);
  942. } else {
  943. hr = S_OK;
  944. }
  945. if (hr == S_OK) {
  946. *ppSample = pROSample;
  947. } else {
  948. pROSample->GetControllingUnknown()->Release();
  949. }
  950. return hr;
  951. }
  952. STDMETHODIMP CDDStream::GetBuffer(IMediaSample **ppBuffer, REFERENCE_TIME * pStartTime,
  953. REFERENCE_TIME * pEndTime, DWORD dwFlags)
  954. {
  955. *ppBuffer = NULL;
  956. if (m_bStopIfNoSamples && m_cAllocated == 0) {
  957. return E_FAIL;
  958. }
  959. CDDSample *pSample;
  960. #ifdef DEBUG
  961. if (bDbgTraceTimes) {
  962. ATLTRACE(_T("AMSTREAM.DLL : GetBuffer for %dms\n"),
  963. pStartTime ? (LONG)(*pStartTime / 10000) : 0);
  964. }
  965. #endif
  966. HRESULT hr = AllocDDSampleFromPool(pStartTime, &pSample);
  967. if (SUCCEEDED(hr)) {
  968. if (CreateInternalSample() && !pSample->m_bProgressiveRender) {
  969. CDDSample *pMyReadOnlySample;
  970. hr = GetMyReadOnlySample(pSample, &pMyReadOnlySample);
  971. if (FAILED(hr)) {
  972. return pSample->SetCompletionStatus(hr);
  973. }
  974. pSample = pMyReadOnlySample;
  975. }
  976. Lock();
  977. pSample->m_pMediaSample->m_dwFlags = dwFlags;
  978. m_lLastPitch = pSample->LockAndPrepareMediaSample(m_lLastPitch);
  979. if (m_lLastPitch == 0) {
  980. hr = pSample->SetCompletionStatus(E_UNEXPECTED); // Really strange to fail this way!
  981. } else {
  982. pSample->m_bReceived = false;
  983. pSample->m_bModified = true;
  984. *ppBuffer = (IMediaSample *)(pSample->m_pMediaSample);
  985. (*ppBuffer)->AddRef();
  986. }
  987. Unlock();
  988. }
  989. return hr;
  990. }
  991. //
  992. // Special CStream methods
  993. //
  994. HRESULT CDDStream::GetMediaType(ULONG Index, AM_MEDIA_TYPE **ppMediaType)
  995. {
  996. if (Index != 0 && Index != -1) {
  997. return S_FALSE;
  998. }
  999. DDSURFACEDESC ddsd;
  1000. ddsd.dwSize = sizeof(ddsd);
  1001. CComPtr<IDirectDrawPalette> pPalette;
  1002. GetFormatInternal(&ddsd, &pPalette, NULL, NULL);
  1003. HRESULT hr = ConvertSurfaceDescToMediaType(&ddsd, pPalette, NULL, TRUE, ppMediaType);
  1004. // Don't offer a type for input - someone might use it!
  1005. if (SUCCEEDED(hr) && m_Direction == PINDIR_INPUT && Index == 0) {
  1006. // Something impossible - or at least something we'll reject
  1007. // but something they won't fall over on
  1008. (*ppMediaType)->formattype = GUID_NULL;
  1009. }
  1010. return hr;
  1011. }
  1012. // Create a temporary sample in order to throw away the data
  1013. HRESULT CDDStream::CreateTempSample(CSample **ppSample)
  1014. {
  1015. if (CreateInternalSample()) {
  1016. CDDSample *pDDSample;
  1017. HRESULT hr = GetMyReadOnlySample(NULL, &pDDSample);
  1018. *ppSample = pDDSample;
  1019. return hr;
  1020. }
  1021. //ATLTRACE("Creating temp sample\n");
  1022. IDirectDrawStreamSample *pSample;
  1023. *ppSample = NULL;
  1024. // This must be allocated as an internal sample otherwise
  1025. // we wind up AddRef'ing the filter graph and leaking
  1026. // everything (because the final release is on a filter
  1027. // thread and the filter graph hangs waiting for the thread
  1028. // that is actually doing the final release to go away).
  1029. HRESULT hr = InternalAllocateSample(0, true, &pSample, true);
  1030. if (SUCCEEDED(hr)) {
  1031. *ppSample = static_cast<CDDSample *>(pSample);
  1032. } else {
  1033. //ATLTRACE("Failed to create temp sample\n");
  1034. }
  1035. return hr;
  1036. }
  1037. STDMETHODIMP CDDStream::Initialize(IUnknown *pSourceObject, DWORD dwFlags, REFMSPID PurposeId, const STREAM_TYPE StreamType)
  1038. {
  1039. //
  1040. TRACEINTERFACE(_T("IDirectDrawStream::Initialize(0x%8.8X, 0x%8.8X, %s, %d)\n"),
  1041. pSourceObject, dwFlags, TextFromPurposeId(PurposeId), StreamType);
  1042. // It is important to call the base class first since if we are creating a peer
  1043. // stream then the Initalize call from the base class will end up calling SetSameFormat
  1044. // which will initialize this stream with the same directdraw object as it's peer.
  1045. // Otherwise, if the pSourceObject is actually a DirectDraw then we'll use that one.
  1046. //
  1047. HRESULT hr = CStream::Initialize(pSourceObject,
  1048. dwFlags & ~AMMSF_NOSTALL,
  1049. PurposeId,
  1050. StreamType);
  1051. if (SUCCEEDED(hr)) {
  1052. if (dwFlags & AMMSF_NOSTALL) {
  1053. m_bNoStall = true;
  1054. }
  1055. IDirectDraw *pDD;
  1056. if (pSourceObject &&
  1057. pSourceObject->QueryInterface(IID_IDirectDraw, (void **)&pDD) == S_OK) {
  1058. SetDirectDraw(pDD);
  1059. pDD->Release();
  1060. } else {
  1061. hr = InitDirectDraw();
  1062. }
  1063. }
  1064. return hr;
  1065. }