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.

1712 lines
42 KiB

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