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.

1539 lines
37 KiB

  1. /****************************************************************************
  2. *
  3. * EDITSTRM.C
  4. *
  5. * routines for reading Standard AVI files
  6. *
  7. * Copyright (c) 1992 Microsoft Corporation. All Rights Reserved.
  8. *
  9. * You have a royalty-free right to use, modify, reproduce and
  10. * distribute the Sample Files (and/or any modified version) in
  11. * any way you find useful, provided that you agree that
  12. * Microsoft has no warranty obligations or liability for any
  13. * Sample Application Files which are modified.
  14. *
  15. ***************************************************************************/
  16. #include <win32.h>
  17. #include <compman.h>
  18. #include "avifile.h"
  19. #include <storage.h>
  20. #include "editstrm.h"
  21. #ifdef DEBUG
  22. static void CDECL dprintf(LPSTR, ...);
  23. #define DPF dprintf
  24. #else
  25. #define DPF ; / ## /
  26. #endif
  27. /*
  28. * memcopy.asm
  29. */
  30. #ifdef WIN32
  31. #define MemCopy(dst, src, cnt) memmove(dst,src,cnt)
  32. #else
  33. EXTERN_C LONG FAR PASCAL MemCopy(HPSTR, HPSTR, DWORD);
  34. #endif
  35. STDAPI EditStreamCut(PAVISTREAM pavi, LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult)
  36. {
  37. PAVIEDITSTREAM pedit = NULL;
  38. HRESULT hr;
  39. pavi->QueryInterface(IID_IAVIEditStream, (LPVOID FAR *) &pedit);
  40. if (!pedit)
  41. return ResultFromScode(E_NOINTERFACE);
  42. hr = pedit->Cut(plStart, plLength, ppResult);
  43. pedit->Release();
  44. return hr;
  45. }
  46. STDAPI EditStreamCopy(PAVISTREAM pavi, LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult)
  47. {
  48. PAVIEDITSTREAM pedit = NULL;
  49. HRESULT hr;
  50. pavi->QueryInterface(IID_IAVIEditStream, (LPVOID FAR *) &pedit);
  51. if (!pedit)
  52. return ResultFromScode(E_NOINTERFACE);
  53. hr = pedit->Copy(plStart, plLength, ppResult);
  54. pedit->Release();
  55. return hr;
  56. }
  57. STDAPI EditStreamPaste(PAVISTREAM pavi, LONG FAR *plPos, LONG FAR *plLength, PAVISTREAM pstream, LONG lStart, LONG lLength)
  58. {
  59. PAVIEDITSTREAM pedit = NULL;
  60. HRESULT hr;
  61. pavi->QueryInterface(IID_IAVIEditStream, (LPVOID FAR *) &pedit);
  62. if (!pedit)
  63. return ResultFromScode(E_NOINTERFACE);
  64. hr = pedit->Paste(plPos, plLength, pstream, lStart, lLength);
  65. pedit->Release();
  66. return hr;
  67. }
  68. STDAPI EditStreamClone(PAVISTREAM pavi, PAVISTREAM FAR *ppResult)
  69. {
  70. PAVIEDITSTREAM pedit = NULL;
  71. HRESULT hr;
  72. pavi->QueryInterface(IID_IAVIEditStream, (LPVOID FAR *) &pedit);
  73. if (!pedit)
  74. return ResultFromScode(E_NOINTERFACE);
  75. hr = pedit->Clone(ppResult);
  76. pedit->Release();
  77. return hr;
  78. }
  79. STDAPI EditStreamSetInfo(PAVISTREAM pavi, AVISTREAMINFO FAR *lpInfo, LONG cbInfo)
  80. {
  81. PAVIEDITSTREAM pedit = NULL;
  82. HRESULT hr;
  83. pavi->QueryInterface(IID_IAVIEditStream, (LPVOID FAR *) &pedit);
  84. if (!pedit)
  85. return ResultFromScode(E_NOINTERFACE);
  86. hr = pedit->SetInfo(lpInfo, cbInfo);
  87. pedit->Release();
  88. return hr;
  89. }
  90. STDAPI EditStreamSetName(PAVISTREAM pavi, LPCSTR lpszName)
  91. {
  92. PAVIEDITSTREAM pedit = NULL;
  93. HRESULT hr;
  94. AVISTREAMINFO info;
  95. pavi->QueryInterface(IID_IAVIEditStream, (LPVOID FAR *) &pedit);
  96. if (!pedit)
  97. return ResultFromScode(E_NOINTERFACE);
  98. pavi->Info(&info, sizeof(info));
  99. _fstrncpy(info.szName, lpszName, sizeof(info.szName));
  100. hr = pedit->SetInfo(&info, sizeof(info));
  101. pedit->Release();
  102. return hr;
  103. }
  104. // #define EDITCHECK
  105. ///////////////////////////////////////////////////////////////////////////
  106. ///////////////////////////////////////////////////////////////////////////
  107. #define USUAL_ALLOC 16
  108. #define EXTRA_ALLOC 8
  109. HRESULT CEditStream::AllocEditSpace(LONG l, LONG cNew)
  110. {
  111. LPEDIT p;
  112. LONG size;
  113. if (cedits + cNew > maxedits) {
  114. size = maxedits + max(cNew + EXTRA_ALLOC, USUAL_ALLOC);
  115. p = (LPEDIT) GlobalReAllocPtr(edits, size * sizeof(EDIT), GHND | GMEM_SHARE);
  116. if (!p)
  117. return ResultFromScode(AVIERR_MEMORY);
  118. edits = p;
  119. maxedits = size;
  120. }
  121. if (l < cedits)
  122. MemCopy((HPSTR) &edits[l + cNew],
  123. (HPSTR) &edits[l],
  124. (cedits - l) * sizeof(EDIT));
  125. cedits += cNew;
  126. return AVIERR_OK;
  127. }
  128. HRESULT CEditStream::PossiblyRemoveEdit(LONG l)
  129. {
  130. if (edits[l].lLength > 0)
  131. return AVIERR_OK;
  132. if (edits[l].pavi)
  133. AVIStreamRelease(edits[l].pavi);
  134. --cedits;
  135. if (l < cedits)
  136. MemCopy((HPSTR) &edits[l],
  137. (HPSTR) &edits[l + 1],
  138. (cedits - l) * sizeof(EDIT));
  139. return AVIERR_OK;
  140. }
  141. CEditStream FAR * CEditStream::NewEditStream(PAVISTREAM psSource)
  142. {
  143. CEditStream FAR * pedit;
  144. pedit = new CEditStream;
  145. if (pedit)
  146. (pedit->Create)((LONG) psSource, 0);
  147. // !!! error check
  148. return pedit;
  149. }
  150. STDAPI CreateEditableStream(
  151. PAVISTREAM FAR * ppsEditable,
  152. PAVISTREAM psSource)
  153. {
  154. // First, check if the stream is already editable....
  155. if (psSource) {
  156. PAVIEDITSTREAM paviedit = NULL;
  157. psSource->QueryInterface(IID_IAVIEditStream, (LPVOID FAR *) &paviedit);
  158. if (paviedit) {
  159. paviedit->Clone(ppsEditable);
  160. paviedit->Release();
  161. return AVIERR_OK;
  162. }
  163. }
  164. *ppsEditable = (PAVISTREAM) CEditStream::NewEditStream(psSource);
  165. if (!*ppsEditable)
  166. return ResultFromScode(AVIERR_MEMORY);
  167. return AVIERR_OK;
  168. }
  169. ///////////////////////////////////////////////////////////////////////////
  170. //
  171. // EditStreamOpen()
  172. //
  173. // open a single stream of a particular type from a AVI file.
  174. //
  175. // params:
  176. // szFile - AVI file name
  177. // fccType - stream type 0 for any type
  178. // iStream - zero based stream number
  179. //
  180. // returns:
  181. // a PAVISTREAM for the specifed stream or NULL.
  182. //
  183. // example:
  184. //
  185. // EditStreamOpen(pavi, "Foo.avi", 0, 0)
  186. //
  187. // will open stream 0 (the first stream)
  188. //
  189. // EditStreamOpen(pavi, "Foo.avi", 1)
  190. //
  191. // will open stream 1
  192. //
  193. // EditStreamOpenStream(pavi, "Foo.avi", 'vids', 0)
  194. //
  195. // will open the first video stream
  196. //
  197. // AVIOpenStream(pavi, "Foo.avi", 'auds', 0)
  198. //
  199. // will open the first audio stream
  200. //
  201. ///////////////////////////////////////////////////////////////////////////
  202. HRESULT STDMETHODCALLTYPE CEditStream::Create(LONG lParam1, LONG lParam2)
  203. {
  204. this->edits = (LPEDIT) GlobalAllocPtr(GHND | GMEM_SHARE, USUAL_ALLOC * sizeof(EDIT));
  205. if (this->edits == NULL)
  206. return ResultFromScode(AVIERR_MEMORY);
  207. this->maxedits = USUAL_ALLOC;
  208. this->ulRefCount = 1;
  209. this->pgf = NULL;
  210. this->psgf = NULL;
  211. this->lpbiLast = NULL;
  212. this->fFullFrames = FALSE;
  213. this->edits[0].pavi = (PAVISTREAM)lParam1;
  214. _fmemset(&this->sinfo, 0, sizeof(this->sinfo));
  215. this->cedits = 1;
  216. if (this->edits[0].pavi) {
  217. AVIStreamAddRef(this->edits[0].pavi);
  218. this->edits[0].lStart = AVIStreamStart(this->edits[0].pavi);
  219. this->edits[0].lLength = AVIStreamLength(this->edits[0].pavi);
  220. AVIStreamInfo(this->edits[0].pavi, &this->sinfo, sizeof(this->sinfo));
  221. CheckEditList();
  222. } else {
  223. this->edits[0].lStart = 0;
  224. this->edits[0].lLength = 0;
  225. }
  226. DPF("Edit %08lx: Usage++=%lx\n", (DWORD) (LPVOID) this, 1L);
  227. //
  228. // all done return success.
  229. //
  230. return 0; // success
  231. }
  232. ///////////////////////////////////////////////////////////////////////////
  233. //
  234. // EditStreamAddRef()
  235. //
  236. // increase the reference count of the stream
  237. //
  238. ///////////////////////////////////////////////////////////////////////////
  239. ULONG STDMETHODCALLTYPE CEditStream::AddRef()
  240. {
  241. DPF("Edit %08lx: Usage++=%lx\n", (DWORD) (LPVOID) this, this->ulRefCount + 1);
  242. return ++this->ulRefCount;
  243. }
  244. ///////////////////////////////////////////////////////////////////////////
  245. //
  246. // EditStreamRelease()
  247. //
  248. // close a EditStream stream
  249. //
  250. ///////////////////////////////////////////////////////////////////////////
  251. ULONG STDMETHODCALLTYPE CEditStream::Release()
  252. {
  253. LONG l;
  254. DPF("Edit %08lx: Usage--=%lx\n", (DWORD) (LPVOID) this, this->ulRefCount - 1);
  255. if (--this->ulRefCount)
  256. return this->ulRefCount;
  257. // free edits....
  258. for (l = 0; l < this->cedits; l++) {
  259. if (this->edits[l].pavi)
  260. AVIStreamRelease(this->edits[l].pavi);
  261. }
  262. GlobalFreePtr(this->edits);
  263. this->edits = 0;
  264. if (this->pgf)
  265. AVIStreamGetFrameClose(this->pgf);
  266. delete this;
  267. return 0;
  268. }
  269. LPBITMAPINFOHEADER NEAR PASCAL CEditStream::CallGetFrame(
  270. PAVISTREAM p,
  271. LONG l)
  272. {
  273. if (psgf != p) {
  274. PGETFRAME pgfNew;
  275. pgfNew = AVIStreamGetFrameOpen(p, NULL);
  276. if (!pgfNew)
  277. return NULL;
  278. if (pgf) {
  279. #ifdef DEBUG
  280. DPF("Trying to SetFormat %dx%dx%d '%4.4s'\n",
  281. (int)lpbiLast->biWidth,
  282. (int)lpbiLast->biHeight,
  283. (int)lpbiLast->biBitCount,
  284. (lpbiLast->biCompression == BI_RGB ? (LPSTR)"None" :
  285. lpbiLast->biCompression == BI_RLE8 ? (LPSTR)"Rle8" :
  286. lpbiLast->biCompression == BI_RLE4 ? (LPSTR)"Rle4" :
  287. (LPSTR)&lpbiLast->biCompression));
  288. #endif
  289. if (pgfNew->SetFormat(lpbiLast, NULL, 0, 0, -1, -1) != AVIERR_OK) {
  290. DPF("Couldn't AVIStreamGetFrameSetFormat!\n");
  291. AVIStreamGetFrameClose(pgfNew);
  292. return NULL;
  293. }
  294. AVIStreamGetFrameClose(pgf);
  295. }
  296. pgf = pgfNew;
  297. psgf = p;
  298. }
  299. lpbiLast = (LPBITMAPINFOHEADER) AVIStreamGetFrame(pgf, l);
  300. if (lpbiLast)
  301. sinfo.dwSuggestedBufferSize = lpbiLast->biSizeImage;
  302. return lpbiLast;
  303. }
  304. ///////////////////////////////////////////////////////////////////////////
  305. ///////////////////////////////////////////////////////////////////////////
  306. HRESULT STDMETHODCALLTYPE CEditStream::ReadFormat(LONG lPos, LPVOID lpFormat, LONG FAR *lpcbFormat)
  307. {
  308. PAVISTREAM p;
  309. LONG l;
  310. HRESULT hr;
  311. if ((lPos < (LONG) sinfo.dwStart) ||
  312. (lPos >= (LONG) (sinfo.dwStart + sinfo.dwLength))) {
  313. return ResultFromScode(AVIERR_BADPARAM);
  314. }
  315. hr = ResolveEdits(lPos, &p, &l, NULL, FALSE);
  316. if (hr != 0) {
  317. DPF("ReadFormat: ResolveEdits failed!\n");
  318. return hr;
  319. }
  320. if (fFullFrames) {
  321. LPBITMAPINFOHEADER lpbi;
  322. LONG lSize;
  323. // This isn't really right: we really need to make the formats
  324. // agree. Should we just get the format from the first frame?
  325. lpbi = CallGetFrame(p, l);
  326. if (!lpbi) {
  327. DPF("ReadFormat: GetFrame failed!\n");
  328. return ResultFromScode(E_FAIL);
  329. }
  330. lSize = lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
  331. if (lpFormat)
  332. hmemcpy(lpFormat, lpbi, min(*lpcbFormat, lSize));
  333. *lpcbFormat = lSize;
  334. return 0;
  335. } else {
  336. return AVIStreamReadFormat(p, l, lpFormat, lpcbFormat);
  337. }
  338. }
  339. ///////////////////////////////////////////////////////////////////////////
  340. ///////////////////////////////////////////////////////////////////////////
  341. HRESULT STDMETHODCALLTYPE CEditStream::Info(AVISTREAMINFO FAR * psi, LONG lSize)
  342. {
  343. if (psi)
  344. hmemcpy(psi, &sinfo, min(lSize, sizeof(sinfo)));
  345. return 0; // !!! sizeof(pavi->sinfo);
  346. }
  347. ///////////////////////////////////////////////////////////////////////////
  348. ///////////////////////////////////////////////////////////////////////////
  349. LONG STDMETHODCALLTYPE CEditStream::FindSample(LONG lPos, LONG lFlags)
  350. {
  351. PAVISTREAM p;
  352. LONG l;
  353. LONG edit;
  354. LONG lRet;
  355. HRESULT hr;
  356. if ((lPos < (LONG) sinfo.dwStart) ||
  357. (lPos >= (LONG) (sinfo.dwStart + sinfo.dwLength))) {
  358. return -1;
  359. }
  360. hr = ResolveEdits(lPos, &p, &l, &edit, TRUE);
  361. if (hr != 0) {
  362. DPF("FindSample: error from ResolveEdits!\n");
  363. return -1;
  364. }
  365. if (lFlags & FIND_FORMAT) {
  366. // !!!! This isn't right, obviously.
  367. if (lFlags & FIND_PREV)
  368. return 0;
  369. else
  370. return -1;
  371. }
  372. if (this->fFullFrames) {
  373. return lPos;
  374. }
  375. // !!! This won't really work, especially for searching forward.
  376. lRet = AVIStreamFindSample(p, l, lFlags);
  377. #ifdef DEBUG
  378. if (lRet < edits[edit].lStart) {
  379. DPF("We were about to return a key frame before a segment: returning %ld instead of %ld.\n", edits[edit].lStart, lRet);
  380. }
  381. #endif
  382. // DPF("FindSample: lPos = %ld, Key = %ld\n", lPos, lPos - (l - lRet));
  383. return lPos - (l - lRet);
  384. }
  385. ///////////////////////////////////////////////////////////////////////////
  386. ///////////////////////////////////////////////////////////////////////////
  387. HRESULT STDMETHODCALLTYPE CEditStream::Read(
  388. LONG lStart,
  389. LONG lSamples,
  390. LPVOID lpBuffer,
  391. LONG cbBuffer,
  392. LONG FAR * plBytes,
  393. LONG FAR * plSamples)
  394. {
  395. PAVISTREAM p;
  396. LONG l;
  397. LONG edit;
  398. LONG lSamplesRead;
  399. LONG lBytesRead;
  400. LONG lSamplesThisTime;
  401. HRESULT hr;
  402. if (plBytes)
  403. *plBytes = 0;
  404. if (plSamples)
  405. *plSamples = 0;
  406. #ifdef TOOMUCHDEBUG
  407. if (lpBuffer) {
  408. DPF("Read %08lx: Start = %ld Length = %ld\n", (DWORD) (LPVOID) this, lStart, lSamples);
  409. }
  410. #endif
  411. if ((lStart < (LONG) sinfo.dwStart) ||
  412. (lStart >= (LONG) (sinfo.dwStart + sinfo.dwLength))) {
  413. DPF("Read at position %ld, start = %lu, len = %lu\n", lStart, sinfo.dwStart, sinfo.dwStart + sinfo.dwLength);
  414. return ResultFromScode(AVIERR_BADPARAM);
  415. }
  416. while (lSamples) {
  417. hr = ResolveEdits(lStart, &p, &l, &edit, FALSE);
  418. if (hr != 0) {
  419. DPF("Read: ResolveEdits failed!\n");
  420. return ResultFromScode(E_FAIL);
  421. }
  422. // Don't read past the end of this edit.
  423. if ((l - this->edits[edit].lStart) + lSamples > this->edits[edit].lLength)
  424. lSamplesThisTime = this->edits[edit].lLength - (l - this->edits[edit].lStart);
  425. else
  426. lSamplesThisTime = lSamples;
  427. if (this->fFullFrames) {
  428. LPBITMAPINFOHEADER lpbi;
  429. LPVOID lp;
  430. lpbi = CallGetFrame(p, l);
  431. if (!lpbi) {
  432. DPF("Read: GetFrame failed!\n");
  433. return ResultFromScode(E_FAIL);
  434. }
  435. //
  436. // a NULL buffer means return the size buffer needed to read
  437. // the given sample.
  438. //
  439. if (lpBuffer == NULL)
  440. goto exit;
  441. lp = (LPBYTE) lpbi + lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
  442. if (cbBuffer >= (LONG) lpbi->biSizeImage) {
  443. hmemcpy(lpBuffer, lp, lpbi->biSizeImage);
  444. exit:
  445. if (plBytes)
  446. *plBytes = lpbi->biSizeImage;
  447. if (plSamples)
  448. *plSamples = 1;
  449. return 0;
  450. }
  451. if (plBytes)
  452. *plBytes = 0;
  453. if (plSamples)
  454. *plSamples = 0;
  455. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  456. } else {
  457. hr = AVIStreamRead(p, l, lSamplesThisTime, lpBuffer, cbBuffer,
  458. &lBytesRead, &lSamplesRead);
  459. if (hr != NOERROR)
  460. return hr;
  461. if (plBytes)
  462. *plBytes += lBytesRead;
  463. if (plSamples)
  464. *plSamples += lSamplesRead;
  465. lpBuffer = (BYTE _huge *) lpBuffer + lBytesRead;
  466. lStart += lSamplesThisTime;
  467. lSamples -= lSamplesThisTime;
  468. cbBuffer -= lBytesRead;
  469. // If we've read up to the end of the file,
  470. // stop now, rather than return an error....
  471. if (lStart >= (LONG) (this->sinfo.dwLength + this->sinfo.dwStart))
  472. break;
  473. }
  474. }
  475. #ifdef TOOMUCHDEBUG
  476. if (lpBuffer && plBytes) {
  477. DPF("Read %08lx: Bytes Read = %ld\n", (DWORD) (LPVOID) this, *plBytes);
  478. }
  479. #endif
  480. return 0;
  481. }
  482. void CEditStream::CheckEditList()
  483. {
  484. #ifdef EDITCHECK
  485. LONG lTotal = 0;
  486. LONG l;
  487. DPF("Edit list %08lx: %s\n", (DWORD) this, fFullFrames ? (LPSTR) " (Using full frames)" : (LPSTR) "");
  488. for (l = 0; l < cedits; l++) {
  489. DPF("\t\t%ld:\t%08lx\t%ld\t%ld\n", l, (DWORD) (LPVOID) edits[l].pavi, edits[l].lStart, edits[l].lLength);
  490. lTotal += edits[l].lLength;
  491. }
  492. if (lTotal != (LONG) sinfo.dwLength) {
  493. * (LPSTR) 0 = 0;
  494. }
  495. #endif
  496. }
  497. HRESULT CEditStream::ResolveEdits(LONG lPos, PAVISTREAM FAR *ppavi,
  498. LONG FAR *plPos, LONG FAR *pl, BOOL fAllowEnd)
  499. {
  500. LONG edit;
  501. //
  502. // Search edit list, get position...
  503. //
  504. if (lPos < (LONG) this->sinfo.dwStart) {
  505. DPF("ResolveEdits: Read at %ld, before start at %ld\n", lPos, this->sinfo.dwStart);
  506. return ResultFromScode(AVIERR_BADPARAM);
  507. }
  508. lPos -= (LONG) this->sinfo.dwStart;
  509. for (edit = 0; edit < this->cedits; edit++) {
  510. if (lPos < this->edits[edit].lLength) {
  511. *ppavi = this->edits[edit].pavi;
  512. *plPos = lPos + this->edits[edit].lStart;
  513. if (pl)
  514. *pl = edit;
  515. return 0;
  516. }
  517. lPos -= this->edits[edit].lLength;
  518. }
  519. // Normally, we don't return a position at the end of an edit--we instead
  520. // go to the next thing.
  521. if (lPos == 0 && fAllowEnd) {
  522. edit--;
  523. *ppavi = this->edits[edit].pavi;
  524. *plPos = this->edits[edit].lStart + this->edits[edit].lLength;
  525. if (pl)
  526. *pl = edit;
  527. return 0;
  528. }
  529. *ppavi = 0;
  530. *plPos = 0;
  531. if (pl)
  532. *pl = 0;
  533. return ResultFromScode(AVIERR_BADPARAM);
  534. }
  535. //
  536. // Cut:
  537. //
  538. // Takes start, length to cut out
  539. //
  540. // returns actual start, length cut, along with new stream
  541. //
  542. STDMETHODIMP CEditStream::Cut(LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult)
  543. {
  544. HRESULT hr = AVIERR_OK;
  545. PAVISTREAM p;
  546. LONG l;
  547. LONG edit;
  548. LONG lStart, lLength;
  549. l = AVIStreamLength(this);
  550. if (ppResult)
  551. *ppResult = 0;
  552. if (!plStart || !plLength) {
  553. return ResultFromScode(AVIERR_BADPARAM);
  554. }
  555. if (*plStart < 0) {
  556. return ResultFromScode(AVIERR_BADPARAM);
  557. }
  558. if (*plLength < 0 || *plStart + *plLength > l) {
  559. if (*plStart >= l)
  560. return ResultFromScode(AVIERR_BADPARAM);
  561. *plLength = l - *plStart;
  562. }
  563. #ifdef KEYALWAYS
  564. // Make cut end at key frame
  565. for (l = *plStart + *plLength; l < AVIStreamLength(this); l++) {
  566. if (AVIStreamFindSample(this, l, 0) == l)
  567. break;
  568. }
  569. *plLength = l - *plStart;
  570. #else
  571. // we cut whatever they ask us to....
  572. #endif
  573. // Make a copy of the section being cut out
  574. if (ppResult) {
  575. // This will make cut start at key frame if it needs to
  576. hr = this->Copy(plStart, plLength, ppResult);
  577. if (hr != AVIERR_OK)
  578. return hr;
  579. }
  580. lLength = *plLength;
  581. lStart = *plStart;
  582. #ifndef KEYALWAYS
  583. if (!this->fFullFrames &&
  584. lStart + lLength < AVIStreamLength(this) &&
  585. AVIStreamFindSample(this, lStart + lLength, 0) != lStart + lLength) {
  586. DPF("Cut: Converting stream to full frames\n");
  587. this->fFullFrames = TRUE;
  588. this->sinfo.dwFormatChangeCount++;
  589. this->sinfo.fccHandler = 0;
  590. }
  591. #endif
  592. // Now do the actual cut
  593. hr = ResolveEdits(lStart, &p, &l, &edit, FALSE);
  594. if (hr != NOERROR)
  595. return hr;
  596. if (this->edits[edit].lStart + this->edits[edit].lLength > l + lLength) {
  597. // The part cut out is entirely within this edit.
  598. if (this->edits[edit].lStart == l) {
  599. // The part cut out is the start of this edit
  600. this->edits[edit].lStart = l + lLength;
  601. this->edits[edit].lLength -= lLength;
  602. } else {
  603. hr = AllocEditSpace(edit, 1);
  604. if (hr == AVIERR_OK) {
  605. this->edits[edit] = this->edits[edit+1];
  606. if (this->edits[edit].pavi)
  607. AVIStreamAddRef(this->edits[edit].pavi);
  608. this->edits[edit].lStart = this->edits[edit+1].lStart;
  609. this->edits[edit].lLength = l - this->edits[edit].lStart;
  610. this->edits[edit+1].lStart = l + lLength;
  611. this->edits[edit+1].lLength -= lLength +
  612. this->edits[edit].lLength;
  613. }
  614. }
  615. } else if (this->edits[edit].lStart + this->edits[edit].lLength == l + lLength) {
  616. // The part cut out is the end of this edit
  617. this->edits[edit].lLength = l - this->edits[edit].lStart;
  618. } else {
  619. LONG lTemp = lLength;
  620. // We're cutting out more than this one edit.
  621. // First, cut out the rest of this edit.
  622. lTemp -= this->edits[edit].lStart + this->edits[edit].lLength - l;
  623. this->edits[edit].lLength = l - this->edits[edit].lStart;
  624. edit++;
  625. // As long as subsequent edits are still shorter than the cut,
  626. // kill them..
  627. while (edit < this->cedits &&
  628. this->edits[edit].lLength < lTemp) {
  629. lTemp -= this->edits[edit].lLength;
  630. this->edits[edit].lLength = 0;
  631. edit++;
  632. }
  633. if (edit < this->cedits) {
  634. this->edits[edit].lStart += lTemp;
  635. this->edits[edit].lLength -= lTemp;
  636. }
  637. }
  638. if (hr == AVIERR_OK) {
  639. this->sinfo.dwLength -= lLength;
  640. this->sinfo.dwEditCount++;
  641. CheckEditList();
  642. } else {
  643. if (ppResult)
  644. AVIStreamRelease(*ppResult);
  645. }
  646. return hr;
  647. }
  648. //
  649. // Copy:
  650. //
  651. // Takes start, length to cut out
  652. //
  653. // returns actual start, length cut, along with new stream
  654. //
  655. //
  656. STDMETHODIMP CEditStream::Copy(LONG FAR *plStart, LONG FAR *plLength, PAVISTREAM FAR * ppResult)
  657. {
  658. PAVISTREAM p1;
  659. LONG l1;
  660. LONG edit1;
  661. PAVISTREAM p2;
  662. LONG l2;
  663. LONG edit2;
  664. LONG l;
  665. CEditStream FAR *p;
  666. HRESULT hr;
  667. LONG lStart, lLength;
  668. l1 = AVIStreamLength(this);
  669. // If start, length < 0, pick some defaults
  670. if (*plStart < 0)
  671. *plStart = 0;
  672. if (*plLength < 0)
  673. *plLength = l1 - *plStart;
  674. // Make sure the start position is within range
  675. if (*plStart > l1) {
  676. if (ppResult)
  677. *ppResult = 0;
  678. return ResultFromScode(AVIERR_BADPARAM);
  679. }
  680. // Make sure the length is within range
  681. if (*plStart + *plLength > l1)
  682. *plLength = l1 - *plStart;
  683. #ifdef KEYALWAYS
  684. // Make copy start at key frame
  685. lStart = AVIStreamFindSample(this, *plStart, 0);
  686. *plLength += *plStart - lStart;
  687. *plStart = lStart;
  688. #endif
  689. lLength = *plLength;
  690. lStart = *plStart;
  691. p = NewEditStream(NULL);
  692. *ppResult = (PAVISTREAM) p;
  693. if (!p)
  694. return ResultFromScode(AVIERR_MEMORY);
  695. hmemcpy(&p->sinfo, &this->sinfo, sizeof(p->sinfo));
  696. if (lLength <= 0)
  697. lLength = (LONG) (p->sinfo.dwLength + p->sinfo.dwStart) - lStart;
  698. hr = ResolveEdits(lStart, &p1, &l1, &edit1, FALSE);
  699. hr = ResolveEdits(lStart + lLength, &p2, &l2, &edit2, TRUE);
  700. if (edit1 == edit2) {
  701. p->edits[0].pavi = p1;
  702. if (p1)
  703. AVIStreamAddRef(p1);
  704. p->edits[0].lStart = l1;
  705. p->edits[0].lLength = lLength;
  706. } else {
  707. hr = p->AllocEditSpace(1, edit2 - edit1);
  708. for (l = 0; l <= edit2 - edit1; l++) {
  709. if (l == 0) {
  710. p->edits[l].pavi = p1;
  711. if (p1)
  712. AVIStreamAddRef(p1);
  713. p->edits[l].lStart = l1;
  714. p->edits[l].lLength = this->edits[edit1].lStart +
  715. this->edits[edit1].lLength - l1;
  716. } else if (l < edit2 - edit1) {
  717. p->edits[l] = this->edits[l+edit1];
  718. if (p->edits[l].pavi)
  719. AVIStreamAddRef(p->edits[l].pavi);
  720. } else {
  721. p->edits[l] = this->edits[edit2];
  722. if (p->edits[l].pavi)
  723. AVIStreamAddRef(p->edits[l].pavi);
  724. p->edits[l].lLength = l2 - p->edits[l].lStart;
  725. }
  726. }
  727. p->PossiblyRemoveEdit(edit2 - edit1);
  728. p->PossiblyRemoveEdit(0);
  729. }
  730. #ifndef KEYALWAYS
  731. l1 = AVIStreamFindSample(p->edits[0].pavi, p->edits[0].lStart, 0);
  732. DPF("edit starts at %ld, key at %ld\n", p->edits[0].lStart, l1);
  733. if (l1 != p->edits[0].lStart) {
  734. p->fFullFrames = TRUE;
  735. DPF("Copy: Converting new stream to full frames\n");
  736. }
  737. #endif
  738. AVIStreamInfo(this->edits[0].pavi, &p->sinfo, sizeof(p->sinfo));
  739. p->sinfo.dwStart = 0;
  740. p->sinfo.dwLength = (DWORD) lLength;
  741. p->sinfo.dwEditCount = 0;
  742. p->sinfo.dwFormatChangeCount = 0;
  743. if (p->fFullFrames)
  744. p->sinfo.fccHandler = 0;
  745. p->CheckEditList();
  746. CheckEditList();
  747. return AVIERR_OK;
  748. }
  749. /**************************************************************************
  750. * @doc INTERNAL DRAWDIB
  751. *
  752. * @api BOOL | DibEq | This function compares two dibs.
  753. *
  754. * @parm LPBITMAPINFOHEADER lpbi1 | Pointer to one bitmap.
  755. * this DIB is assumed to have the colors after the BITMAPINFOHEADER
  756. *
  757. * @parm LPBITMAPINFOHEADER | lpbi2 | Pointer to second bitmap.
  758. * this DIB is assumed to have the colors after biSize bytes.
  759. *
  760. * @rdesc Returns TRUE if bitmaps are identical, FALSE otherwise.
  761. *
  762. **************************************************************************/
  763. inline BOOL DibEq(LPBITMAPINFOHEADER lpbi1, LPBITMAPINFOHEADER lpbi2)
  764. {
  765. return
  766. lpbi1->biCompression == lpbi2->biCompression &&
  767. lpbi1->biSize == lpbi2->biSize &&
  768. lpbi1->biWidth == lpbi2->biWidth &&
  769. lpbi1->biHeight == lpbi2->biHeight &&
  770. lpbi1->biBitCount == lpbi2->biBitCount;
  771. }
  772. BOOL AreVideoStreamsCompatible(PAVISTREAM ps1, PAVISTREAM ps2)
  773. {
  774. LONG cb1, cb2;
  775. BITMAPINFOHEADER bih1, bih2;
  776. AVIStreamReadFormat(ps1, AVIStreamStart(ps1), NULL, &cb1);
  777. AVIStreamReadFormat(ps2, AVIStreamStart(ps2), NULL, &cb2);
  778. if (cb1 != cb2)
  779. return FALSE;
  780. cb1 = sizeof(bih1);
  781. cb2 = sizeof(bih2);
  782. AVIStreamReadFormat(ps1, AVIStreamStart(ps1), &bih1, &cb1);
  783. AVIStreamReadFormat(ps2, AVIStreamStart(ps2), &bih2, &cb2);
  784. if (DibEq(&bih1, &bih2))
  785. return TRUE;
  786. return FALSE;
  787. }
  788. BOOL AreAudioStreamsCompatible(PAVISTREAM ps1, PAVISTREAM ps2)
  789. {
  790. LONG cb1, cb2;
  791. LPVOID lpf;
  792. BOOL f;
  793. AVIStreamReadFormat(ps1, AVIStreamStart(ps1), NULL, &cb1);
  794. AVIStreamReadFormat(ps2, AVIStreamStart(ps2), NULL, &cb2);
  795. if (cb1 != cb2)
  796. return FALSE;
  797. lpf = GlobalAllocPtr(GHND, cb1 + cb2);
  798. if (!lpf)
  799. return FALSE; // !!!
  800. AVIStreamReadFormat(ps1, AVIStreamStart(ps1), lpf, &cb1);
  801. AVIStreamReadFormat(ps2, AVIStreamStart(ps2), (BYTE FAR *)lpf + cb1, &cb2);
  802. f = !_fmemcmp(lpf, (BYTE FAR *)lpf + cb1, (UINT) cb1);
  803. GlobalFreePtr(lpf);
  804. return f;
  805. }
  806. //
  807. // Paste:
  808. //
  809. // Takes stream to paste, along with start and length within that stream,
  810. // and also target stream and position within the stream to do the paste.
  811. //
  812. // Returns position and length pasted.
  813. //
  814. STDMETHODIMP CEditStream::Paste(LONG FAR *plPos, LONG FAR *plLength, PAVISTREAM pstream, LONG lStart, LONG lLength)
  815. {
  816. PAVISTREAM p;
  817. LONG l;
  818. LONG edit;
  819. HRESULT hr;
  820. LONG lPos;
  821. CEditStream FAR *pnew;
  822. AVISTREAMINFO strinfo;
  823. AVIStreamInfo(pstream, &strinfo, sizeof(strinfo));
  824. if (this->sinfo.fccType == 0) {
  825. AVIStreamInfo(pstream, &this->sinfo, sizeof(this->sinfo));
  826. this->sinfo.dwLength = 0;
  827. this->sinfo.dwStart = *plPos;
  828. }
  829. if (*plPos > (LONG) (sinfo.dwLength + sinfo.dwStart)) {
  830. // !!! We should handle this case....
  831. return ResultFromScode(AVIERR_BADPARAM);
  832. }
  833. #ifdef KEYALWAYS
  834. // Make paste go before a key frame...
  835. *plPos = AVIStreamFindSample(this, *plPos, 0);
  836. #endif
  837. lPos = *plPos;
  838. if (strinfo.fccType != this->sinfo.fccType) {
  839. DPF("Paste: Incompatible stream types!\n");
  840. return ResultFromScode(AVIERR_UNSUPPORTED);
  841. }
  842. if (lLength <= 0 || ((lStart + lLength) >
  843. (LONG) (strinfo.dwStart + strinfo.dwLength))) {
  844. if (lStart >= (LONG) (strinfo.dwLength + strinfo.dwStart))
  845. return ResultFromScode(AVIERR_BADPARAM);
  846. lLength = (LONG) (strinfo.dwLength + strinfo.dwStart) - lStart;
  847. }
  848. if ((DWORD) lPos + (DWORD) lLength > 0x80000000) {
  849. DPF("Paste result would be more than 2 billion frames!\n");
  850. return ResultFromScode(AVIERR_MEMORY);
  851. }
  852. // !!! What if the frame rates don't match?
  853. #define SIZEMISMATCH(rc1, rc2) \
  854. (((rc1.right - rc1.left) != (rc2.right - rc2.left)) || \
  855. ((rc1.bottom - rc1.top) != (rc2.bottom - rc2.top)))
  856. if (strinfo.fccType == streamtypeVIDEO &&
  857. SIZEMISMATCH(strinfo.rcFrame, this->sinfo.rcFrame)) {
  858. // !!! It would be nice if this worked.
  859. DPF("Paste: Video streams are different sizes!\n");
  860. return ResultFromScode(AVIERR_UNSUPPORTED);
  861. }
  862. if (this->sinfo.fccType == streamtypeAUDIO) {
  863. if (!AreAudioStreamsCompatible((PAVISTREAM) this, pstream)) {
  864. DPF("Paste: Audio streams are different formats!\n");
  865. return ResultFromScode(AVIERR_UNSUPPORTED);
  866. }
  867. }
  868. pnew = NULL;
  869. pstream->QueryInterface(CLSID_EditStream, (LPVOID FAR *) &pnew);
  870. #ifndef KEYALWAYS
  871. if (this->sinfo.fccType == streamtypeVIDEO) {
  872. if (!this->fFullFrames) {
  873. if ((!AVIStreamIsKeyFrame(pstream, lStart) ||
  874. (pnew && pnew->fFullFrames)) ||
  875. ((lPos < (LONG) (sinfo.dwLength + sinfo.dwStart)) &&
  876. !AVIStreamIsKeyFrame((PAVISTREAM) this, lPos)) ||
  877. !AreVideoStreamsCompatible((PAVISTREAM) this, pstream)) {
  878. // !!! What if we're pasting, say, an 8-bit and a 32-bit
  879. // movie together? Do we have to pick a common format
  880. // to convert to?
  881. CallGetFrame(this->edits[0].pavi, this->edits[0].lStart);
  882. if (CallGetFrame(pstream, lStart) == NULL) {
  883. DPF("Paste: Can't make a common format!\n");
  884. if (pnew)
  885. pnew->Release();
  886. return ResultFromScode(AVIERR_BADFORMAT);
  887. }
  888. this->fFullFrames = TRUE;
  889. DPF("Paste: Converting stream to full frames\n");
  890. this->sinfo.dwFormatChangeCount++;
  891. // ??? !!! Call get frame once, just so it's been done....
  892. }
  893. } else {
  894. if (CallGetFrame(pstream, lStart) == NULL) {
  895. DPF("Paste: Can't make a common format!\n");
  896. if (pnew)
  897. pnew->Release();
  898. return ResultFromScode(AVIERR_BADFORMAT);
  899. }
  900. }
  901. }
  902. #endif
  903. // Find where to do the paste...
  904. hr = ResolveEdits(lPos, &p, &l, &edit, TRUE);
  905. // Report back the size of what we pasted...
  906. if (plLength)
  907. *plLength = lLength;
  908. if (pnew) {
  909. LONG lNew;
  910. // The inserted stream is itself an edit list; take advantage
  911. // of this fact.
  912. hr = AllocEditSpace(edit, 1 + pnew->cedits);
  913. this->edits[edit].pavi = this->edits[edit + 1 + pnew->cedits].pavi;
  914. if (this->edits[edit].pavi)
  915. AVIStreamAddRef(this->edits[edit].pavi);
  916. this->edits[edit].lStart = this->edits[edit + 1 + pnew->cedits].lStart;
  917. this->edits[edit].lLength = l - this->edits[edit].lStart;
  918. // !!! We're ignoring lStart and lLength!
  919. for (lNew = 0; lNew < pnew->cedits; lNew++) {
  920. this->edits[edit + 1 + lNew] = pnew->edits[lNew];
  921. AVIStreamAddRef(pnew->edits[lNew].pavi);
  922. }
  923. this->edits[edit + pnew->cedits + 1].lStart = l;
  924. this->edits[edit + pnew->cedits + 1].lLength -= this->edits[edit].lLength;
  925. // Get rid of zero-length edits....
  926. PossiblyRemoveEdit(edit + pnew->cedits + 1);
  927. PossiblyRemoveEdit(edit);
  928. this->sinfo.dwLength += lLength;
  929. pnew->CheckEditList();
  930. pnew->Release();
  931. } else {
  932. // Just insert the stream as a blob.
  933. hr = AllocEditSpace(edit, 2);
  934. this->edits[edit].pavi = this->edits[edit+2].pavi;
  935. if (this->edits[edit].pavi)
  936. AVIStreamAddRef(this->edits[edit].pavi);
  937. this->edits[edit].lStart = this->edits[edit+2].lStart;
  938. this->edits[edit].lLength = l - this->edits[edit+2].lStart;
  939. this->edits[edit+ 1].pavi = pstream;
  940. if (pstream)
  941. AVIStreamAddRef(pstream);
  942. this->edits[edit + 1].lStart = lStart;
  943. this->edits[edit + 1].lLength = lLength;
  944. this->edits[edit + 2].lStart = l;
  945. this->edits[edit + 2].lLength -= this->edits[edit].lLength;
  946. // No addref here, since the edit we're splitting had a ref already
  947. this->sinfo.dwLength += lLength;
  948. // Get rid of zero-length edits....
  949. PossiblyRemoveEdit(edit + 2);
  950. PossiblyRemoveEdit(edit);
  951. }
  952. CheckEditList();
  953. this->sinfo.dwEditCount++;
  954. return AVIERR_OK;
  955. }
  956. STDMETHODIMP CEditStream::Clone(PAVISTREAM FAR *ppResult)
  957. {
  958. CEditStream FAR * pnew;
  959. HRESULT hr;
  960. LONG l;
  961. pnew = NewEditStream(NULL);
  962. *ppResult = (PAVISTREAM) pnew;
  963. if (!pnew)
  964. return ResultFromScode(AVIERR_MEMORY);
  965. if (this->cedits > 1) {
  966. hr = pnew->AllocEditSpace(1, this->cedits - 1);
  967. if (hr != NOERROR) {
  968. // !!! Clean things up
  969. return hr;
  970. }
  971. }
  972. for (l = 0; l < this->cedits; l++) {
  973. pnew->edits[l] = this->edits[l];
  974. if (pnew->edits[l].pavi)
  975. AVIStreamAddRef(pnew->edits[l].pavi);
  976. }
  977. pnew->sinfo = this->sinfo;
  978. pnew->fFullFrames = this->fFullFrames;
  979. pnew->CheckEditList();
  980. return AVIERR_OK;
  981. }
  982. STDMETHODIMP CEditStream::SetInfo(AVISTREAMINFO FAR * lpInfo, LONG cbInfo)
  983. {
  984. if ((cbInfo < sizeof(AVISTREAMINFO)) ||
  985. (IsBadReadPtr(lpInfo, sizeof(AVISTREAMINFO))))
  986. return ResultFromScode(AVIERR_BADPARAM);
  987. // Things we don't copy:
  988. // fccType
  989. // fccHandler
  990. // dwFlags
  991. // dwCaps
  992. // dwLength
  993. // dwInitialFrames
  994. // dwSuggestedBufferSize
  995. // dwSampleSize
  996. // dwEditCount
  997. // dwFormatChangeCount
  998. this->sinfo.wPriority = lpInfo->wPriority;
  999. this->sinfo.wLanguage = lpInfo->wLanguage;
  1000. this->sinfo.dwScale = lpInfo->dwScale;
  1001. this->sinfo.dwRate = lpInfo->dwRate;
  1002. this->sinfo.dwStart = lpInfo->dwStart; // !!! ???
  1003. this->sinfo.dwQuality = lpInfo->dwQuality;
  1004. this->sinfo.rcFrame = lpInfo->rcFrame;
  1005. if (lpInfo->szName[0])
  1006. _fmemcpy(this->sinfo.szName, lpInfo->szName, sizeof(this->sinfo.szName));
  1007. // The stream has been changed....
  1008. ++this->sinfo.dwEditCount;
  1009. return NOERROR;
  1010. }
  1011. //
  1012. //
  1013. // Extra unimplemented functions.....
  1014. //
  1015. //
  1016. //
  1017. HRESULT STDMETHODCALLTYPE CEditStream::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  1018. {
  1019. if (riid == IID_IUnknown)
  1020. *ppvObj = ((IUnknown FAR *) (IAVIStream FAR *) this);
  1021. else if (riid == IID_IAVIStream)
  1022. *ppvObj = ((IAVIStream FAR *) this);
  1023. else if (riid == IID_IAVIEditStream)
  1024. *ppvObj = ((IAVIEditStream FAR *) this);
  1025. #if 0
  1026. else if ((riid == IID_IMarshal) && CanMarshalSimply()) // !!!! Remove once fixed!
  1027. *ppvObj = ((IMarshal FAR *) this);
  1028. #endif
  1029. else if (riid == CLSID_EditStream)
  1030. *ppvObj = this;
  1031. else { // unsupported interface
  1032. *ppvObj = NULL;
  1033. return ResultFromScode(E_NOINTERFACE);
  1034. }
  1035. AddRef();
  1036. return NOERROR;
  1037. }
  1038. HRESULT STDMETHODCALLTYPE CEditStream::ReadData (DWORD fcc, LPVOID lp, LONG FAR *lpcb)
  1039. {
  1040. return ResultFromScode(AVIERR_UNSUPPORTED);
  1041. }
  1042. HRESULT STDMETHODCALLTYPE CEditStream::SetFormat (LONG lPos, LPVOID lpFormat, LONG cbFormat)
  1043. {
  1044. // !!! We could set the whole format of the stream here, and do mapping....
  1045. return ResultFromScode(AVIERR_UNSUPPORTED);
  1046. }
  1047. HRESULT STDMETHODCALLTYPE CEditStream::WriteData (DWORD fcc, LPVOID lp, LONG cb)
  1048. {
  1049. return ResultFromScode(AVIERR_UNSUPPORTED);
  1050. }
  1051. HRESULT STDMETHODCALLTYPE CEditStream::Write (LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG FAR *plSampWritten, LONG FAR *plBytesWritten)
  1052. {
  1053. return ResultFromScode(AVIERR_UNSUPPORTED);
  1054. }
  1055. HRESULT STDMETHODCALLTYPE CEditStream::Delete (LONG lStart, LONG lSamples)
  1056. {
  1057. return ResultFromScode(AVIERR_UNSUPPORTED);
  1058. }
  1059. HRESULT CEditStream::NewInstance(IUnknown FAR* pUnknownOuter,
  1060. REFIID riid,
  1061. LPVOID FAR* ppv)
  1062. {
  1063. CEditStream FAR * pedit;
  1064. HRESULT hr;
  1065. pedit = new CEditStream;
  1066. if (pedit)
  1067. (pedit->Create)(NULL, 0);
  1068. // !!! error check
  1069. hr = pedit->QueryInterface(riid, ppv);
  1070. if (FAILED(GetScode(hr)))
  1071. delete pedit;
  1072. return hr;
  1073. }
  1074. BOOL CEditStream::CanMarshalSimply()
  1075. {
  1076. LONG l;
  1077. LPUNKNOWN punk;
  1078. for (l = 0; l < this->cedits; l++) {
  1079. punk = NULL;
  1080. this->edits[l].pavi->QueryInterface(CLSID_AVISimpleUnMarshal,
  1081. (LPVOID FAR *) &punk);
  1082. if (!punk)
  1083. return FALSE;
  1084. punk->Release();
  1085. }
  1086. return TRUE;
  1087. }
  1088. STDMETHODIMP CEditStream::GetUnmarshalClass (REFIID riid, LPVOID pv,
  1089. DWORD dwDestContext, LPVOID pvDestContext,
  1090. DWORD mshlflags, LPCLSID pCid)
  1091. {
  1092. if (CanMarshalSimply()) {
  1093. DPF("UnMarshalClass called (simple)\n");
  1094. *pCid = CLSID_AVISimpleUnMarshal;
  1095. } else {
  1096. DPF("UnMarshalClass called (not simple)\n");
  1097. *pCid = CLSID_EditStream;
  1098. }
  1099. return NOERROR;
  1100. }
  1101. STDMETHODIMP CEditStream::GetMarshalSizeMax (REFIID riid, LPVOID pv,
  1102. DWORD dwDestContext, LPVOID pvDestContext,
  1103. DWORD mshlflags, LPDWORD pSize)
  1104. {
  1105. if (CanMarshalSimply())
  1106. *pSize = 4;
  1107. else
  1108. *pSize = 0;
  1109. return NOERROR;
  1110. }
  1111. STDMETHODIMP CEditStream::MarshalInterface (LPSTREAM pStm, REFIID riid,
  1112. LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
  1113. DWORD mshlflags)
  1114. {
  1115. HRESULT hr;
  1116. if ((riid != IID_IAVIStream && riid != IID_IAVIFile && riid != IID_IUnknown))
  1117. return ResultFromScode(E_INVALIDARG);
  1118. if (CanMarshalSimply()) {
  1119. LPUNKNOWN pUnk = (LPUNKNOWN) (PAVISTREAM) this;
  1120. DPF("MarshalInterface called (simple): Marshalling %lx\n", (DWORD) pUnk);
  1121. if ((hr = pStm->Write(&pUnk, sizeof(pUnk), NULL)) == NOERROR)
  1122. AddRef();
  1123. } else {
  1124. DPF("MarshalInterface called (not simple)\n");
  1125. hr = ResultFromScode(AVIERR_UNSUPPORTED);
  1126. }
  1127. DPF("Returns %lx\n", (DWORD) (LPVOID) hr);
  1128. return hr;
  1129. }
  1130. STDMETHODIMP CEditStream::UnmarshalInterface (LPSTREAM pStm, REFIID riid,
  1131. LPVOID FAR* ppv)
  1132. {
  1133. return ResultFromScode(AVIERR_UNSUPPORTED);
  1134. }
  1135. STDMETHODIMP CEditStream::ReleaseMarshalData (LPSTREAM pStm)
  1136. {
  1137. return ResultFromScode(AVIERR_UNSUPPORTED);
  1138. }
  1139. STDMETHODIMP CEditStream::DisconnectObject (DWORD dwReserved)
  1140. {
  1141. return ResultFromScode(AVIERR_UNSUPPORTED);
  1142. }
  1143. HRESULT STDMETHODCALLTYPE CEditStream::Reserved1()
  1144. {
  1145. return ResultFromScode(AVIERR_UNSUPPORTED);
  1146. }
  1147. HRESULT STDMETHODCALLTYPE CEditStream::Reserved2()
  1148. {
  1149. return ResultFromScode(AVIERR_UNSUPPORTED);
  1150. }
  1151. HRESULT STDMETHODCALLTYPE CEditStream::Reserved3()
  1152. {
  1153. return ResultFromScode(AVIERR_UNSUPPORTED);
  1154. }
  1155. HRESULT STDMETHODCALLTYPE CEditStream::Reserved4()
  1156. {
  1157. return ResultFromScode(AVIERR_UNSUPPORTED);
  1158. }
  1159. HRESULT STDMETHODCALLTYPE CEditStream::Reserved5()
  1160. {
  1161. return ResultFromScode(AVIERR_UNSUPPORTED);
  1162. }
  1163. /*****************************************************************************
  1164. *
  1165. * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  1166. *
  1167. * The messages will be send to COM1: like any debug message. To
  1168. * enable debug output, add the following to WIN.INI :
  1169. *
  1170. * [debug]
  1171. * ICSAMPLE=1
  1172. *
  1173. ****************************************************************************/
  1174. #ifdef DEBUG
  1175. #define MODNAME "EditStrm"
  1176. static BOOL fDebug = -1;
  1177. static void cdecl dprintf(LPSTR szFormat, ...)
  1178. {
  1179. char ach[128];
  1180. #ifdef WIN32
  1181. va_list va;
  1182. if (fDebug == -1)
  1183. fDebug = GetProfileIntA("Debug",MODNAME, FALSE);
  1184. if (!fDebug)
  1185. return;
  1186. va_start(va, szFormat);
  1187. if (szFormat[0] == '!')
  1188. ach[0]=0, szFormat++;
  1189. else
  1190. lstrcpyA(ach, MODNAME ": ");
  1191. wvsprintfA(ach+lstrlenA(ach),szFormat,(LPSTR)va);
  1192. va_end(va);
  1193. // lstrcatA(ach, "\r\r\n");
  1194. OutputDebugStringA(ach);
  1195. #else
  1196. if (fDebug == -1)
  1197. fDebug = GetProfileInt("Debug",MODNAME, FALSE);
  1198. if (!fDebug)
  1199. return;
  1200. if (szFormat[0] == '!')
  1201. ach[0]=0, szFormat++;
  1202. else
  1203. lstrcpy(ach, MODNAME ": ");
  1204. wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
  1205. // lstrcat(ach, "\r\r\n");
  1206. OutputDebugString(ach);
  1207. #endif
  1208. }
  1209. #endif
  1210.