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.

410 lines
10 KiB

  1. // Copyright (c) 1997 - 1998 Microsoft Corporation. All Rights Reserved.
  2. // Sample.cpp: implementation of the DirectDraw Sample class.
  3. //
  4. //////////////////////////////////////////////////////////////////////
  5. #include "stdafx.h"
  6. #include "project.h"
  7. #define m_pDDStream ((CDDStream *)m_pStream)
  8. CDDSample::CDDSample() :
  9. m_pSurface(NULL),
  10. m_lLastSurfacePitch(0),
  11. m_bFormatChanged(false),
  12. m_lImageSize(0),
  13. m_pvLockedSurfacePtr(0)
  14. {
  15. }
  16. HRESULT CDDSample::InitSample(CStream *pStream, IDirectDrawSurface *pSurface, const RECT *pRect, bool bIsProgressiveRender, bool bIsInternal,
  17. bool bTemp)
  18. {
  19. m_pMediaSample = new CDDMediaSample(this);
  20. if (!m_pMediaSample) {
  21. return E_OUTOFMEMORY;
  22. }
  23. HRESULT hr = CSample::InitSample(pStream, bIsInternal);
  24. if (FAILED(hr)) {
  25. return hr;
  26. }
  27. m_pSurface = pSurface; // Auto addref since CComPtr
  28. m_Rect = *pRect;
  29. m_bProgressiveRender = bIsProgressiveRender;
  30. m_bTemp = bTemp;
  31. return S_OK;
  32. }
  33. //
  34. // IDirectDrawStreamSample
  35. //
  36. STDMETHODIMP CDDSample::GetSurface(IDirectDrawSurface **ppDirectDrawSurface, RECT * pRect)
  37. {
  38. TRACEINTERFACE(_T("IDirectDrawStreamSample::GetSurface(0x%8.8X, 0x%8.8X)\n"),
  39. ppDirectDrawSurface, pRect);
  40. AUTO_SAMPLE_LOCK;
  41. if (ppDirectDrawSurface) {
  42. *ppDirectDrawSurface = m_pSurface;
  43. (*ppDirectDrawSurface)->AddRef();
  44. }
  45. if (pRect) {
  46. *pRect = m_Rect;
  47. }
  48. return S_OK;
  49. }
  50. STDMETHODIMP CDDSample::SetRect(const RECT * pRect)
  51. {
  52. TRACEINTERFACE(_T("IDirectDrawStreamSample::SetRect(0x%8.8X)\n"),
  53. pRect);
  54. HRESULT hr;
  55. if (!pRect) {
  56. hr = E_POINTER;
  57. } else {
  58. DDSURFACEDESC ddsd;
  59. ddsd.dwSize = sizeof(ddsd);
  60. hr = m_pSurface->GetSurfaceDesc(&ddsd);
  61. if (SUCCEEDED(hr)) {
  62. if (pRect->right > (LONG)ddsd.dwWidth ||
  63. pRect->bottom > (LONG)ddsd.dwHeight ||
  64. pRect->right - pRect->left != m_pDDStream->m_Width ||
  65. pRect->bottom - pRect->top != m_pDDStream->m_Height) {
  66. hr = DDERR_INVALIDRECT;
  67. } else {
  68. AUTO_SAMPLE_LOCK;
  69. m_Rect = *pRect;
  70. m_bFormatChanged = true;
  71. hr = S_OK;
  72. }
  73. }
  74. }
  75. return hr;
  76. }
  77. void CDDSample::ReleaseMediaSampleLock()
  78. {
  79. AUTO_SAMPLE_LOCK;
  80. if (m_pvLockedSurfacePtr != NULL) {
  81. m_pSurface->Unlock(m_pvLockedSurfacePtr);
  82. m_pvLockedSurfacePtr = NULL;
  83. }
  84. }
  85. HRESULT CDDSample::LockMediaSamplePointer()
  86. {
  87. HRESULT hr = S_OK;
  88. AUTO_SAMPLE_LOCK;
  89. if (m_pvLockedSurfacePtr == NULL) {
  90. DDSURFACEDESC ddsd;
  91. ddsd.dwSize = sizeof(ddsd);
  92. hr = m_pSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
  93. if (SUCCEEDED(hr)) {
  94. m_pvLockedSurfacePtr = ddsd.lpSurface;
  95. }
  96. }
  97. return hr;
  98. }
  99. long CDDSample::LockAndPrepareMediaSample(long lLastPinPitch)
  100. {
  101. AUTO_SAMPLE_LOCK;
  102. if (m_pvLockedSurfacePtr == NULL) {
  103. DDSURFACEDESC ddsd;
  104. ddsd.dwSize = sizeof(ddsd);
  105. if (m_pMediaSample->m_pMediaType) {
  106. DeleteMediaType(m_pMediaSample->m_pMediaType);
  107. m_pMediaSample->m_pMediaType = NULL;
  108. }
  109. if (FAILED(m_pSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))) {
  110. return 0;
  111. }
  112. m_pvLockedSurfacePtr = ddsd.lpSurface;
  113. if (lLastPinPitch != ddsd.lPitch ||
  114. m_lLastSurfacePitch != ddsd.lPitch ||
  115. m_bFormatChanged) {
  116. ConvertSurfaceDescToMediaType(&ddsd, m_pDDStream->m_pDirectDrawPalette,
  117. &m_Rect, TRUE, &m_pMediaSample->m_pMediaType,
  118. &m_pStream->m_ConnectedMediaType);
  119. if (m_pMediaSample->m_pMediaType) {
  120. VIDEOINFO *pvi = (VIDEOINFO *)m_pMediaSample->m_pMediaType->pbFormat;
  121. m_lImageSize = pvi->bmiHeader.biSizeImage;
  122. m_lLastSurfacePitch = ddsd.lPitch;
  123. m_bFormatChanged = false;
  124. } else {
  125. ReleaseMediaSampleLock();
  126. return 0;
  127. }
  128. }
  129. return ddsd.lPitch;
  130. } else {
  131. return lLastPinPitch;
  132. }
  133. }
  134. void CDDSample::FinalMediaSampleRelease()
  135. {
  136. ReleaseMediaSampleLock();
  137. CSample::FinalMediaSampleRelease();
  138. }
  139. HRESULT CDDSample::CopyFrom(CDDSample *pSrcSample)
  140. {
  141. AUTO_SAMPLE_LOCK;
  142. CSample::CopyFrom(pSrcSample);
  143. return m_pSurface->BltFast(m_Rect.left, m_Rect.top,
  144. pSrcSample->m_pSurface, &pSrcSample->m_Rect,
  145. DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT);
  146. }
  147. //
  148. // Helper
  149. //
  150. // ASSUMES pClip clipped to surfae
  151. //
  152. void CopySampleToSurface(
  153. IMediaSample *pSample,
  154. VIDEOINFO *pInfo,
  155. DDSURFACEDESC& ddsd,
  156. const RECT *pClip
  157. )
  158. {
  159. DWORD dwBytesPerPixel = pInfo->bmiHeader.biBitCount / 8;
  160. // Need src pointer and stride for source and dest and
  161. // number of lines
  162. //
  163. // The source of the target is the top left-hand corner of pClip
  164. // within the surface
  165. //
  166. PBYTE pbSource;
  167. PBYTE pbTarget;
  168. LONG lSourceStride;
  169. LONG lTargetStride;
  170. DWORD dwWidth;
  171. DWORD dwLines;
  172. //
  173. // Target first
  174. //
  175. pbTarget = (LPBYTE)ddsd.lpSurface;
  176. lTargetStride = ddsd.lPitch;
  177. dwLines = ddsd.dwHeight;
  178. dwWidth = ddsd.dwWidth;
  179. if (pClip) {
  180. pbTarget += (pClip->left + pClip->top * ddsd.lPitch) * dwBytesPerPixel;
  181. lTargetStride -= (ddsd.dwWidth - (pClip->right - pClip->left)) *
  182. dwBytesPerPixel;
  183. dwLines = pClip->bottom - pClip->top;
  184. dwWidth = pClip->right - pClip->left;
  185. }
  186. // Now do the source
  187. HRESULT hr = pSample->GetPointer(&pbSource);
  188. _ASSERTE(SUCCEEDED(hr));
  189. // Adjust to the source rect - if the height is negative
  190. // it means we have a ddraw surface already, otherwise
  191. // we must invert everything
  192. LONG lSourceHeight = (LONG)pInfo->bmiHeader.biHeight;
  193. lSourceStride = pInfo->bmiHeader.biWidth * dwBytesPerPixel;
  194. if (lSourceHeight > 0) {
  195. pbSource += (lSourceStride * (lSourceHeight - 1));
  196. lSourceStride = -lSourceStride;
  197. } else {
  198. lSourceHeight = -lSourceHeight;
  199. }
  200. if (!IsRectEmpty(&pInfo->rcSource)) {
  201. pbSource += (pInfo->rcSource.left +
  202. pInfo->rcSource.top * lSourceStride) * dwBytesPerPixel;
  203. // Now check on the width etc
  204. dwWidth = min(dwWidth, (DWORD)(pInfo->rcSource.right - pInfo->rcSource.left));
  205. dwLines = min(dwLines, (DWORD)(pInfo->rcSource.bottom - pInfo->rcSource.top));
  206. } else {
  207. dwWidth = min(dwWidth, (DWORD)pInfo->bmiHeader.biWidth);
  208. dwLines = min(dwLines, (DWORD)lSourceHeight);
  209. }
  210. //
  211. // Now do the copy
  212. //
  213. DWORD dwWidthInBytes = dwWidth * dwBytesPerPixel;
  214. while (dwLines-- > 0) {
  215. CopyMemory(pbTarget, pbSource, dwWidthInBytes);
  216. pbSource += lSourceStride;
  217. pbTarget += lTargetStride;
  218. }
  219. }
  220. HRESULT CDDSample::CopyFrom(IMediaSample *pSrcMediaSample, const AM_MEDIA_TYPE *pmt)
  221. {
  222. AUTO_SAMPLE_LOCK;
  223. CSample::CopyFrom(pSrcMediaSample);
  224. DDSURFACEDESC ddsd;
  225. ddsd.dwSize = sizeof(ddsd);
  226. HRESULT hr = m_pSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
  227. if (SUCCEEDED(hr)) {
  228. CopySampleToSurface(pSrcMediaSample, (VIDEOINFO *)pmt->pbFormat, ddsd, &m_Rect);
  229. m_pSurface->Unlock(ddsd.lpSurface);
  230. }
  231. return hr;
  232. }
  233. CDDInternalSample::CDDInternalSample() :
  234. m_pBuddySample(NULL),
  235. m_lWaiting(0),
  236. m_hWaitFreeSem(NULL),
  237. m_bDead(false)
  238. {
  239. };
  240. CDDInternalSample::~CDDInternalSample()
  241. {
  242. // ATLTRACE("CDDInternalSample::~CDDInternalSample\n");
  243. if (m_hWaitFreeSem) {
  244. CloseHandle(m_hWaitFreeSem);
  245. }
  246. }
  247. HRESULT CDDInternalSample::InternalInit(void)
  248. {
  249. m_hWaitFreeSem = CreateSemaphore(NULL, 0, 0x7FFFFFF, NULL);
  250. return m_hWaitFreeSem ? S_OK : E_OUTOFMEMORY;
  251. }
  252. HRESULT CDDInternalSample::JoinToBuddy(CDDSample *pBuddy)
  253. {
  254. LOCK_SAMPLE;
  255. while (!m_bDead && m_pBuddySample) {
  256. m_lWaiting++;
  257. UNLOCK_SAMPLE;
  258. WaitForSingleObject(m_hWaitFreeSem, INFINITE);
  259. LOCK_SAMPLE;
  260. }
  261. HRESULT hr;
  262. if (m_bDead) {
  263. hr = VFW_E_NOT_COMMITTED;
  264. } else {
  265. hr = S_OK;
  266. m_pBuddySample = pBuddy;
  267. ResetEvent(m_hCompletionEvent);
  268. m_Status = MS_S_PENDING;
  269. m_bWantAbort = false;
  270. m_bModified = false;
  271. m_bContinuous = false;
  272. m_UserAPC = 0;
  273. m_hUserHandle = NULL;
  274. }
  275. UNLOCK_SAMPLE;
  276. return hr;
  277. }
  278. HRESULT CDDInternalSample::Die(void)
  279. {
  280. AUTO_SAMPLE_LOCK;
  281. m_bDead = true;
  282. if (m_lWaiting) {
  283. ReleaseSemaphore(m_hWaitFreeSem, m_lWaiting, 0);
  284. m_lWaiting = 0;
  285. }
  286. return S_OK;
  287. }
  288. HRESULT CDDInternalSample::SetCompletionStatus(HRESULT hrStatus)
  289. {
  290. if (m_pBuddySample != NULL) {
  291. if (hrStatus == S_OK) {
  292. m_pBuddySample->CopyFrom(this);
  293. }
  294. //
  295. // If we're just being recycled, but our buddy wants to abort, then abort him.
  296. //
  297. m_pBuddySample->SetCompletionStatus((hrStatus == MS_S_PENDING && m_pBuddySample->m_bWantAbort) ? E_ABORT : hrStatus);
  298. }
  299. LOCK_SAMPLE;
  300. m_Status = S_OK;
  301. m_pBuddySample = NULL;
  302. if (m_lWaiting) {
  303. m_lWaiting--;
  304. ReleaseSemaphore(m_hWaitFreeSem, 1, 0);
  305. }
  306. UNLOCK_SAMPLE;
  307. GetControllingUnknown()->Release(); // May die right here
  308. return hrStatus;
  309. }
  310. //
  311. // Forwarded IMediaSample methods.
  312. //
  313. HRESULT CDDSample::MSCallback_GetPointer(BYTE ** ppBuffer)
  314. {
  315. *ppBuffer = (BYTE *)m_pvLockedSurfacePtr;
  316. return NOERROR;
  317. }
  318. LONG CDDSample::MSCallback_GetSize(void)
  319. {
  320. return m_lImageSize;
  321. }
  322. LONG CDDSample::MSCallback_GetActualDataLength(void)
  323. {
  324. return m_lImageSize;
  325. }
  326. HRESULT CDDSample::MSCallback_SetActualDataLength(LONG lActual)
  327. {
  328. if (lActual == m_lImageSize) {
  329. return S_OK;
  330. } else {
  331. return E_FAIL;
  332. }
  333. }
  334. STDMETHODIMP CDDMediaSample::QueryInterface(REFIID riid, void ** ppv)
  335. {
  336. if (riid==IID_IDirectDrawMediaSample) {
  337. *ppv = (IDirectDrawMediaSample *)this;
  338. ((LPUNKNOWN)(*ppv))->AddRef();
  339. return S_OK;
  340. }
  341. return CMediaSample::QueryInterface(riid, ppv);
  342. }
  343. #define m_pDDSample ((CDDSample *)m_pSample)
  344. STDMETHODIMP CDDMediaSample::GetSurfaceAndReleaseLock(IDirectDrawSurface **ppDirectDrawSurface, RECT * pRect)
  345. {
  346. m_pDDSample->ReleaseMediaSampleLock();
  347. return m_pDDSample->GetSurface(ppDirectDrawSurface, pRect);
  348. }
  349. STDMETHODIMP CDDMediaSample::LockMediaSamplePointer()
  350. {
  351. return m_pDDSample->LockMediaSamplePointer();
  352. }