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.

448 lines
14 KiB

  1. // Copyright (c) 1997 Microsoft Corporation. All Rights Reserved.
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include "strmif.h"
  5. #include "uuids.h"
  6. #include "ddraw.h"
  7. #include "mmstream.h"
  8. #include "amstream.h"
  9. #include "ddstream.h"
  10. typedef HRESULT (STDAPICALLTYPE * PFNSAMPLECALLBACK) (IStreamSample *pSource,
  11. IStreamSample *pDest,
  12. void * pvContext);
  13. #define RELEASE(x) if (x) { (x)->Release(); (x) = NULL; };
  14. #define CHECK_ERROR(x) \
  15. if (FAILED(hr = (x))) { \
  16. printf(#x " failed with HRESULT(0x%8.8X)\n", hr); \
  17. goto Exit; \
  18. }
  19. #define MAX_COPY_STREAMS 5
  20. class CopyPair {
  21. public:
  22. IStreamSample *pSource;
  23. IStreamSample *pDest;
  24. PFNSAMPLECALLBACK pCallback;
  25. void * pCallbackContext;
  26. HRESULT hrLastStatus;
  27. bool bReading;
  28. };
  29. class CCopyEngine
  30. {
  31. public:
  32. CCopyEngine() : m_cNumPairs(0) {};
  33. ~CCopyEngine();
  34. HRESULT CopyMediaStream(IMultiMediaStream *pSourceStream,
  35. IMultiMediaStream *pDestStream,
  36. REFMSPID PurposeId,
  37. PFNSAMPLECALLBACK pCallback = NULL,
  38. void * pContext = NULL);
  39. HRESULT AddCopyPair(IStreamSample *pSource, IStreamSample *pDest,
  40. PFNSAMPLECALLBACK pCallback = NULL, void * pvContext = NULL);
  41. HRESULT CopyStreamData();
  42. private:
  43. CopyPair m_aPair[MAX_COPY_STREAMS];
  44. HANDLE m_aEvent[MAX_COPY_STREAMS];
  45. int m_cNumPairs;
  46. };
  47. HRESULT CCopyEngine::AddCopyPair(IStreamSample *pSource, IStreamSample *pDest,
  48. PFNSAMPLECALLBACK pCallback, void * pContext)
  49. {
  50. if (m_cNumPairs >= MAX_COPY_STREAMS) {
  51. return E_FAIL;
  52. }
  53. HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  54. if (!hEvent) {
  55. return E_OUTOFMEMORY;
  56. }
  57. pSource->AddRef();
  58. pDest->AddRef();
  59. m_aEvent[m_cNumPairs] = hEvent;
  60. m_aPair[m_cNumPairs].pSource = pSource;
  61. m_aPair[m_cNumPairs].pDest = pDest;
  62. m_aPair[m_cNumPairs].pCallback = pCallback;
  63. m_aPair[m_cNumPairs].pCallbackContext = pContext;
  64. m_cNumPairs++;
  65. return NOERROR;
  66. }
  67. HRESULT CCopyEngine::CopyMediaStream(IMultiMediaStream *pSourceMMStream,
  68. IMultiMediaStream *pDestMMStream,
  69. REFMSPID PurposeId,
  70. PFNSAMPLECALLBACK pCallback, void * pContext)
  71. {
  72. HRESULT hr = E_FAIL; // Assume it won't work.
  73. IMediaStream *pSource;
  74. if (pSourceMMStream->GetMediaStream(PurposeId, &pSource) == NOERROR) {
  75. IMediaStream *pDest;
  76. if (pDestMMStream->GetMediaStream(PurposeId, &pDest) == NOERROR) {
  77. IStreamSample *pSourceSample;
  78. hr = pSource->AllocateSample(0, &pSourceSample);
  79. if (SUCCEEDED(hr)) {
  80. IStreamSample *pDestSample;
  81. hr = pDest->CreateSharedSample(pSourceSample, 0, &pDestSample);
  82. if (SUCCEEDED(hr)) {
  83. hr = AddCopyPair(pSourceSample, pDestSample, pCallback, pContext);
  84. pDestSample->Release();
  85. }
  86. pSourceSample->Release();
  87. }
  88. pDest->Release();
  89. }
  90. pSource->Release();
  91. }
  92. return hr;
  93. }
  94. HRESULT CCopyEngine::CopyStreamData()
  95. {
  96. if (m_cNumPairs == 0) {
  97. return S_FALSE;
  98. }
  99. int i;
  100. for (i = 0; i < m_cNumPairs; i++) {
  101. m_aPair[i].hrLastStatus = NOERROR;
  102. m_aPair[i].bReading = true;
  103. m_aPair[i].pSource->Update(0, m_aEvent[i], NULL, 0);
  104. }
  105. int NumRunning = i;
  106. while (NumRunning > 0) {
  107. DWORD dwWaitRet = WaitForMultipleObjects(m_cNumPairs, m_aEvent, FALSE, INFINITE);
  108. if (dwWaitRet >= WAIT_OBJECT_0 && dwWaitRet < WAIT_OBJECT_0 + m_cNumPairs) {
  109. int iCompleted = dwWaitRet - WAIT_OBJECT_0;
  110. CopyPair *pPair = &m_aPair[iCompleted];
  111. IStreamSample *pDone = pPair->bReading ? pPair->pSource : pPair->pDest;
  112. pPair->hrLastStatus = pDone->CompletionStatus(0, 0);
  113. if (pPair->hrLastStatus == NOERROR) {
  114. if (pPair->bReading) {
  115. STREAM_TIME stStart, stStop;
  116. if (pPair->pCallback) {
  117. pPair->pCallback(pPair->pSource, pPair->pDest, pPair->pCallbackContext);
  118. }
  119. pPair->pSource->GetSampleTimes(&stStart, &stStop, NULL);
  120. pPair->pDest->SetSampleTimes(&stStart, &stStop);
  121. pPair->pDest->Update(0, m_aEvent[iCompleted], NULL, 0);
  122. pPair->bReading = false;
  123. } else {
  124. pPair->pSource->Update(0, m_aEvent[iCompleted], NULL, 0);
  125. pPair->bReading = true;
  126. }
  127. } else {
  128. if (pPair->bReading && pPair->hrLastStatus == MS_S_ENDOFSTREAM) {
  129. IMediaStream *pStream;
  130. pPair->pDest->GetMediaStream(&pStream);
  131. pStream->SendEndOfStream(0);
  132. pStream->Release();
  133. ResetEvent(m_aEvent[iCompleted]);
  134. }
  135. NumRunning--;
  136. }
  137. }
  138. }
  139. return NOERROR;
  140. }
  141. CCopyEngine::~CCopyEngine()
  142. {
  143. int i;
  144. for (i = 0; i < m_cNumPairs; i++) {
  145. CloseHandle(m_aEvent[i]);
  146. m_aPair[i].pSource->Release();
  147. m_aPair[i].pDest->Release();
  148. }
  149. }
  150. HRESULT STDAPICALLTYPE ArcEffect(IStreamSample *pSource, IStreamSample *pDest, void * pvPrimarySurface)
  151. {
  152. static int iFrame = 0;
  153. IDirectDrawStreamSample *pSample;
  154. if (pSource->QueryInterface(IID_IDirectDrawStreamSample, (void **)&pSample) == NOERROR) {
  155. IDirectDrawSurface *pSurface;
  156. IDirectDrawSurface *pPrimarySurface = (IDirectDrawSurface *)pvPrimarySurface;
  157. RECT rect;
  158. if (SUCCEEDED(pSample->GetSurface(&pSurface, &rect))) {
  159. HDC hdc;
  160. if (SUCCEEDED(pSurface->GetDC(&hdc))) {
  161. Ellipse(hdc, 0, 0, (iFrame * 2) % rect.right, iFrame % rect.bottom);
  162. pSurface->ReleaseDC(hdc);
  163. }
  164. pPrimarySurface->Blt(&rect, pSurface, &rect, DDBLT_WAIT, NULL);
  165. pSurface->Release();
  166. }
  167. pSample->Release();
  168. }
  169. iFrame ++;
  170. return NOERROR;
  171. }
  172. /*
  173. HRESULT PolylineEffectToSample(IDirectDrawStreamSample *pSample)
  174. {
  175. IDirectDrawSurface *pSurface = NULL;
  176. RECT rect;
  177. HRESULT hr;
  178. POINT pt[2] = {0};
  179. HDC hdc;
  180. CHECK_ERROR(pSample->GetSurface(&pSurface, &rect));
  181. pt[1].x = iFrame % rect.right;
  182. pt[1].y = rect.bottom;
  183. CHECK_ERROR(pSurface->GetDC(&hdc));
  184. Polyline(hdc, pt, 2);
  185. pSurface->ReleaseDC(hdc);
  186. iFrame ++;
  187. Exit:
  188. RELEASE(pSurface);
  189. return hr;
  190. }
  191. */
  192. HRESULT FindCompressor(REFCLSID rcidCategory,
  193. int Index,
  194. IBaseFilter **ppFilter)
  195. {
  196. *ppFilter = NULL;
  197. ICreateDevEnum *pCreateDevEnum = NULL;
  198. IEnumMoniker *pEm = NULL;
  199. IMoniker *pMoniker = NULL;
  200. ULONG cFetched;
  201. HRESULT hr;
  202. CHECK_ERROR(CoCreateInstance(
  203. CLSID_SystemDeviceEnum,
  204. NULL,
  205. CLSCTX_INPROC_SERVER,
  206. IID_ICreateDevEnum,
  207. (void**)&pCreateDevEnum));
  208. CHECK_ERROR(pCreateDevEnum->CreateClassEnumerator(rcidCategory, &pEm, 0));
  209. if (Index) {
  210. pEm->Skip(Index);
  211. }
  212. CHECK_ERROR(pEm->Next(1, &pMoniker, &cFetched));
  213. if (cFetched == 1) {
  214. hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void **)ppFilter);
  215. }
  216. Exit:
  217. RELEASE(pMoniker);
  218. RELEASE(pCreateDevEnum);
  219. RELEASE(pEm);
  220. return hr;
  221. }
  222. HRESULT CreateStreamWithSameFormat(IAMMultiMediaStream *pAMStream,
  223. IMultiMediaStream *pSourceMMStream,
  224. REFMSPID PurposeId,
  225. IMediaStream **ppNewMediaStream)
  226. {
  227. IMediaStream *pSource;
  228. HRESULT hr = pSourceMMStream->GetMediaStream(PurposeId, &pSource);
  229. if (SUCCEEDED(hr)) {
  230. hr = pAMStream->AddMediaStream(pSource, &PurposeId, AMMSF_CREATEPEER, ppNewMediaStream);
  231. pSource->Release();
  232. }
  233. return hr;
  234. }
  235. HRESULT CreateWriterStream(const char * pszOutputFileName,
  236. IMultiMediaStream *pSourceMMStream,
  237. IDirectDraw *pDD,
  238. IMultiMediaStream **ppMMStream)
  239. {
  240. static LPWSTR szVideoRender = L"@device:sw:CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\{70E102B0-5556-11CE-97C0-00AA0055595A}";
  241. *ppMMStream = NULL;
  242. IAMMultiMediaStream *pAMStream = NULL;
  243. IMediaStream *pVideoStream = NULL;
  244. IMediaStream *pAudioStream = NULL;
  245. ICaptureGraphBuilder *pBuilder = NULL;
  246. IGraphBuilder *pFilterGraph = NULL;
  247. IFileSinkFilter *pFileSinkWriter = NULL;
  248. IBaseFilter *pVideoCompressFilter = NULL;
  249. IBaseFilter *pMuxFilter = NULL;
  250. HRESULT hr;
  251. WCHAR wPath[MAX_PATH];
  252. MultiByteToWideChar(CP_ACP, 0, pszOutputFileName, -1, wPath, sizeof(wPath)/sizeof(wPath[0]));
  253. CHECK_ERROR(CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
  254. IID_IAMMultiMediaStream, (void **)&pAMStream));
  255. CHECK_ERROR(pAMStream->Initialize(STREAMTYPE_WRITE, 0, NULL));
  256. CHECK_ERROR(CreateStreamWithSameFormat(pAMStream, pSourceMMStream, MSPID_PrimaryVideo, &pVideoStream));
  257. CHECK_ERROR(CreateStreamWithSameFormat(pAMStream, pSourceMMStream, MSPID_PrimaryAudio, &pAudioStream));
  258. CHECK_ERROR(pAMStream->GetFilterGraph(&pFilterGraph));
  259. // Create a new Bind Context (connects a file to an object type)
  260. LPBC lpBC;
  261. CreateBindCtx(0, &lpBC);
  262. ULONG cchEaten;
  263. IMoniker *pMoniker;
  264. hr = MkParseDisplayName(lpBC, szVideoRender, &cchEaten, &pMoniker);
  265. if( SUCCEEDED(hr) ) {
  266. IBaseFilter *pVideoRenderFilter = 0;
  267. hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pVideoRenderFilter);
  268. if( SUCCEEDED(hr) ) {
  269. pFilterGraph->AddFilter(pVideoRenderFilter, L"Video Renderer");
  270. pVideoRenderFilter->Release();
  271. }
  272. pMoniker->Release();
  273. }
  274. pAMStream->Render(0);
  275. /*
  276. CHECK_ERROR(CoCreateInstance(CLSID_CaptureGraphBuilder, NULL, CLSCTX_INPROC_SERVER,
  277. IID_ICaptureGraphBuilder, (void **)&pBuilder));
  278. CHECK_ERROR(pBuilder->SetFiltergraph(pFilterGraph));
  279. CHECK_ERROR(pBuilder->SetOutputFileName(&MEDIASUBTYPE_Avi, wPath, &pMuxFilter, &pFileSinkWriter));
  280. CHECK_ERROR(FindCompressor(CLSID_VideoCompressorCategory, 1, &pVideoCompressFilter));
  281. CHECK_ERROR(pFilterGraph->AddFilter(pVideoCompressFilter, L"Video Compression filter"))
  282. CHECK_ERROR(pBuilder->RenderCompressionStream(pVideoStream, pVideoCompressFilter, pMuxFilter));
  283. CHECK_ERROR(pBuilder->RenderCompressionStream(pAudioStream, NULL, pMuxFilter));
  284. */
  285. *ppMMStream = pAMStream;
  286. pAMStream->AddRef();
  287. Exit:
  288. if (pAMStream == NULL) {
  289. printf("Could not create a CLSID_MultiMediaStream object\n"
  290. "Check you have run regsvr32 amstream.dll\n");
  291. }
  292. RELEASE(pAMStream);
  293. RELEASE(pBuilder);
  294. RELEASE(pFilterGraph);
  295. RELEASE(pFileSinkWriter);
  296. RELEASE(pVideoCompressFilter);
  297. RELEASE(pMuxFilter);
  298. RELEASE(pVideoStream);
  299. RELEASE(pAudioStream);
  300. return hr;
  301. }
  302. HRESULT OpenReadMMStream(const char * pszFileName, IDirectDraw *pDD, IMultiMediaStream **ppMMStream)
  303. {
  304. *ppMMStream = NULL;
  305. IAMMultiMediaStream *pAMStream;
  306. HRESULT hr;
  307. CHECK_ERROR(CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
  308. IID_IAMMultiMediaStream, (void **)&pAMStream));
  309. CHECK_ERROR(pAMStream->Initialize(STREAMTYPE_READ, 0, NULL));
  310. CHECK_ERROR(pAMStream->AddMediaStream(pDD, &MSPID_PrimaryVideo, 0, NULL));
  311. CHECK_ERROR(pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL));
  312. WCHAR wPath[MAX_PATH];
  313. MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, wPath, sizeof(wPath)/sizeof(wPath[0]));
  314. CHECK_ERROR(pAMStream->OpenFile(wPath, 0));
  315. *ppMMStream = pAMStream;
  316. pAMStream->AddRef();
  317. Exit:
  318. if (pAMStream == NULL) {
  319. printf("Could not create a CLSID_MultiMediaStream object\n"
  320. "Check you have run regsvr32 amstream.dll\n");
  321. }
  322. RELEASE(pAMStream);
  323. return hr;
  324. }
  325. HRESULT RenderStreamToSurface(IDirectDraw *pDD, IDirectDrawSurface *pPrimary,
  326. IMultiMediaStream *pReadStream,
  327. IMultiMediaStream *pWriteStream)
  328. {
  329. HRESULT hr;
  330. CCopyEngine Engine;
  331. CHECK_ERROR(Engine.CopyMediaStream(pReadStream, pWriteStream, MSPID_PrimaryVideo, ArcEffect, pPrimary));
  332. CHECK_ERROR(Engine.CopyMediaStream(pReadStream, pWriteStream, MSPID_PrimaryAudio));
  333. CHECK_ERROR(pReadStream->SetState(STREAMSTATE_RUN));
  334. CHECK_ERROR(pWriteStream->SetState(STREAMSTATE_RUN));
  335. Engine.CopyStreamData();
  336. pReadStream->SetState(STREAMSTATE_STOP);
  337. pWriteStream->SetState(STREAMSTATE_STOP);
  338. Exit:
  339. return hr;
  340. }
  341. int _CRTAPI1
  342. main(
  343. int argc,
  344. char *argv[]
  345. )
  346. {
  347. if (argc < 2) {
  348. printf("Usage : writer movie.ext\n");
  349. exit(0);
  350. }
  351. CoInitialize(NULL);
  352. IDirectDraw *pDD;
  353. HRESULT hr = DirectDrawCreate(NULL, &pDD, NULL);
  354. if (SUCCEEDED(hr)) {
  355. DDSURFACEDESC ddsd;
  356. IDirectDrawSurface *pPrimarySurface;
  357. pDD->SetCooperativeLevel(GetDesktopWindow(), DDSCL_NORMAL);
  358. ddsd.dwSize = sizeof(ddsd);
  359. ddsd.dwFlags = DDSD_CAPS;
  360. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  361. // ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  362. hr = pDD->CreateSurface(&ddsd, &pPrimarySurface, NULL);
  363. if (SUCCEEDED(hr)) {
  364. IMultiMediaStream *pReadStream;
  365. hr = OpenReadMMStream(argv[1], pDD, &pReadStream);
  366. if (SUCCEEDED(hr)) {
  367. IMultiMediaStream *pWriteStream;
  368. hr = CreateWriterStream("C:\\TEST.AVI", pReadStream, pDD, &pWriteStream);
  369. if (SUCCEEDED(hr)) {
  370. RenderStreamToSurface(pDD, pPrimarySurface, pReadStream, pWriteStream);
  371. pWriteStream->Release();
  372. }
  373. pReadStream->Release();
  374. }
  375. pPrimarySurface->Release();
  376. }
  377. pDD->Release();
  378. } else {
  379. printf("Could not open DirectDraw - check it is installed\n");
  380. }
  381. CoUninitialize();
  382. return 0;
  383. }