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.

3521 lines
106 KiB

  1. /****************************************************************************
  2. *
  3. * AVIFILE.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 <ole2.h>
  18. #include <vfw.h>
  19. #include "avifilei.h"
  20. #include "avifile.rc"
  21. #include <checkbmi.h>
  22. #include "debug.h"
  23. #if !defined NUMELMS
  24. #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
  25. #endif
  26. #ifdef _WIN32
  27. // We need a structure to read in the AVIStreamHeader from persistent
  28. // storage. This structure contains a RECT element, which in 16 bit land
  29. // contains 4 16-bit values. Hence when 16 bit AVIFILE.DLL writes the
  30. // file out, it uses a RECT composed of 4 16-bit values. On WIN32 we have
  31. // to map this "short rect" to a WIN32 RECT of 4 32-bit elements. In order
  32. // that 16 bit code can continue to read/write files interchangeably with
  33. // 32 bit code we map the two structures on read/write.
  34. // The AVIStreamHeader structure exists on disk. Hence the RECT struct
  35. // is the same size for all systems, i.e. SHORT, 16 bit values. The code
  36. // that reads/writes files, and returns INFO will map these 16 bit values
  37. // to the 32 bit RECT structure as appropriate.
  38. typedef struct tagSRECT {
  39. SHORT left;
  40. SHORT top;
  41. SHORT right;
  42. SHORT bottom;
  43. } SRECT;
  44. typedef struct {
  45. FOURCC fccType;
  46. FOURCC fccHandler;
  47. DWORD dwFlags; /* Contains AVITF_* flags */
  48. WORD wPriority;
  49. WORD wLanguage;
  50. DWORD dwInitialFrames;
  51. DWORD dwScale;
  52. DWORD dwRate; /* dwRate / dwScale == samples/second */
  53. DWORD dwStart;
  54. DWORD dwLength; /* In units above... */
  55. // new....
  56. DWORD dwSuggestedBufferSize;
  57. DWORD dwQuality;
  58. DWORD dwSampleSize;
  59. SRECT rcFrame; /* does each frame need this? */
  60. /* additional type-specific data goes in StreamInfo chunk */
  61. /* For video: position within rectangle... */
  62. /* For audio: volume? stereo channel? */
  63. } AVIStreamHeaderShort;
  64. #else
  65. // Map one name to the other for 16 bit code...
  66. #define AVIStreamHeaderShort AVIStreamHeader
  67. #endif
  68. #if defined _WIN32 && !defined UNICODE
  69. //
  70. // This is Win 95 code. Explicit unicode stuff is needed.
  71. //
  72. int LoadUnicodeString(HINSTANCE hinst, UINT wID, LPWSTR lpBuffer, int cchBuffer)
  73. {
  74. char ach[256];
  75. int i;
  76. i = LoadString(hinst, wID, ach, NUMELMS(ach));
  77. if (i > 0)
  78. MultiByteToWideChar(CP_ACP, 0, ach, -1, lpBuffer, cchBuffer);
  79. return i;
  80. }
  81. #define lstrlenW lstrlenUnicode
  82. int
  83. WINAPI
  84. lstrlenUnicode(
  85. LPCWSTR lpString
  86. )
  87. {
  88. int count = 0;
  89. while (*lpString++)
  90. count++;
  91. return count;
  92. }
  93. #else
  94. #define LoadUnicodeString LoadString
  95. #endif
  96. extern "C" {
  97. LPSTR FAR lstrzcpyA (LPSTR pszTarget, LPCSTR pszSource, size_t cchMax)
  98. {
  99. lstrcpynA (pszTarget, pszSource, cchMax -1);
  100. pszTarget[ cchMax -1 ] = TEXT('\0');
  101. return pszTarget;
  102. }
  103. LPWSTR FAR lstrzcpyW (LPWSTR pszTarget, LPCWSTR pszSource, size_t cchMax)
  104. {
  105. lstrcpynW (pszTarget, pszSource, cchMax -1);
  106. pszTarget[ cchMax -1 ] = TEXT('\0');
  107. return pszTarget;
  108. }
  109. LPTSTR FAR lstrzcpy (LPTSTR pszTarget, LPCTSTR pszSource, size_t cchMax)
  110. {
  111. lstrcpyn (pszTarget, pszSource, cchMax -1);
  112. pszTarget[ cchMax -1 ] = TEXT('\0');
  113. return pszTarget;
  114. }
  115. LPWSTR FAR lstrzcpyAtoW (LPWSTR pszTarget, LPCSTR pszSourceA, size_t cchMax)
  116. {
  117. LPWSTR pszSourceW;
  118. pszSourceW = (LPWSTR)GlobalAllocPtr(GMEM_MOVEABLE,sizeof(WCHAR)*cchMax);
  119. if (pszSourceW != NULL) {
  120. mbstowcs(pszSourceW, pszSourceA, cchMax);
  121. lstrcpynW (pszTarget, pszSourceW, cchMax -1);
  122. pszTarget[ cchMax -1 ] = TEXT('\0');
  123. GlobalFreePtr(pszSourceW);
  124. }
  125. return pszTarget;
  126. }
  127. LPSTR FAR lstrzcpyWtoA (LPSTR pszTarget, LPCWSTR pszSourceW, size_t cchMax)
  128. {
  129. LPSTR pszSourceA;
  130. pszSourceA = (LPSTR)GlobalAllocPtr (GMEM_MOVEABLE, cchMax);
  131. if (pszSourceA != NULL) {
  132. wcstombs(pszSourceA, pszSourceW, cchMax);
  133. lstrcpynA (pszTarget, pszSourceA, cchMax -1);
  134. pszTarget[ cchMax -1 ] = TEXT('\0');
  135. GlobalFreePtr(pszSourceA);
  136. }
  137. return pszTarget;
  138. }
  139. } // extern "C"
  140. extern "C" STDAPI CalculateFileDataRate(PAVIFILE pf, LONG FAR *plMaxBytesPerSec);
  141. //#undef StreamFromFOURCC
  142. //#define StreamFromFOURCC(fcc) (UINT)(HIBYTE(LOWORD(fcc)) - (BYTE)'0')
  143. BOOL AddToIndex(CAVIFile FAR * pfile, DWORD ckid, DWORD cksize, LONG off, DWORD dwFlags);
  144. ///////////////////////////////////////////////////////////////////////////
  145. ///////////////////////////////////////////////////////////////////////////
  146. ///////////////////////////////////////////////////////////////////////////
  147. EXTERN_C void DecodeRle(LPBITMAPINFOHEADER lpbi, BYTE _huge *pb, BYTE _huge *prle, DWORD dwInSize);
  148. EXTERN_C HINSTANCE ghMod;
  149. ///////////////////////////////////////////////////////////////////////////
  150. ///////////////////////////////////////////////////////////////////////////
  151. #define comptypeNONE mmioFOURCC('N','O','N','E')
  152. #define comptypeRLE0 mmioFOURCC('R','L','E','0')
  153. #define comptypeRLE mmioFOURCC('R','L','E',' ')
  154. #define WIDTHBYTES(i) ((UINT)((i+31)&(~31))/8)
  155. #define DIBWIDTHBYTES(lpbi) (UINT)WIDTHBYTES((UINT)(lpbi)->biWidth * (UINT)(lpbi)->biBitCount)
  156. LONG lBufferSize = 0;
  157. int nBuffers = 0;
  158. #define ckidSTREAMNAME mmioFOURCC('s', 't', 'r', 'n')
  159. /***************************************************************************
  160. ***************************************************************************/
  161. /***************************************************************************
  162. ***************************************************************************/
  163. EXTERN_C LONG FAR PASCAL shfileReadProc(HANDLE hsf, LONG lSeek, LONG lRead, LPVOID lpBuffer)
  164. {
  165. if (shfileSeek((HSHFILE)hsf, lSeek, SEEK_SET) == -1)
  166. return -1;
  167. if (shfileRead((HSHFILE)hsf, (HPSTR)lpBuffer, lRead) != lRead)
  168. return -1;
  169. return lRead;
  170. }
  171. ///////////////////////////////////////////////////////////////////////////
  172. ///////////////////////////////////////////////////////////////////////////
  173. #define INDEX_WRITE_SIZE 32l*1024
  174. #define INDEX_READ_SIZE 32l*1024
  175. static BOOL WriteOutIndex(CAVIFile FAR *pfile, DWORD dwOffsetMovie)
  176. {
  177. MMCKINFO ck;
  178. PAVIINDEXENTRY pIndex;
  179. LONG cnt = INDEX_WRITE_SIZE / sizeof(*pIndex);
  180. LONG l;
  181. BOOL f=FALSE;
  182. #ifdef DEBUG
  183. DWORD time;
  184. #endif
  185. /*
  186. ** Now write index out!
  187. */
  188. ck.ckid = ckidAVINEWINDEX;
  189. ck.cksize = sizeof(AVIINDEXENTRY) * pfile->px->nIndex;
  190. if (shfileCreateChunk(pfile->hshfile, &ck, 0))
  191. return FALSE;
  192. DPF("Writing Index", time=timeGetTime());
  193. pIndex = (PAVIINDEXENTRY)GlobalAllocPtr(GHND,INDEX_WRITE_SIZE);
  194. if (pIndex) {
  195. for (l=0; l < pfile->px->nIndex; ) {
  196. cnt = IndexGetFileIndex(pfile->px, l, cnt, pIndex, -(LONG)dwOffsetMovie);
  197. if (cnt == 0)
  198. break;
  199. //l = cnt * sizeof(AVIINDEXENTRY);
  200. if (shfileWrite(pfile->hshfile, (HPSTR)pIndex,
  201. cnt * sizeof(AVIINDEXENTRY))
  202. != cnt * (LONG)sizeof(AVIINDEXENTRY))
  203. goto exit;
  204. l += cnt;
  205. DPF("!.");
  206. }
  207. DPF("!Done (%ldms)\n", timeGetTime()-time);
  208. if (!shfileAscend(pfile->hshfile, &ck, 0))
  209. f = TRUE;
  210. exit:
  211. GlobalFreePtr(pIndex);
  212. }
  213. return f;
  214. }
  215. ///////////////////////////////////////////////////////////////////////////
  216. ///////////////////////////////////////////////////////////////////////////
  217. static BOOL ReadInIndex(CAVIFile FAR *pfile, DWORD size, DWORD dwOffsetMovie, BOOL fRle)
  218. {
  219. PAVIINDEXENTRY pIndex;
  220. LONG cnt;
  221. LONG lIndexAdjust;
  222. BOOL f = FALSE;
  223. #ifdef DEBUG
  224. DWORD time;
  225. #endif
  226. pIndex = (PAVIINDEXENTRY)GlobalAllocPtr(GHND,INDEX_READ_SIZE);
  227. if (pIndex == NULL)
  228. goto exit;
  229. pfile->px = IndexCreate();
  230. if (pfile->px == 0)
  231. goto exit;
  232. DPF("Reading index.", time = timeGetTime());
  233. if (pfile->avihdr.dwFlags & AVIF_MUSTUSEINDEX)
  234. lIndexAdjust = dwOffsetMovie;
  235. else
  236. lIndexAdjust = -1; // set when we read first index entry.
  237. while (size > 0) {
  238. cnt = min(INDEX_READ_SIZE, size);
  239. if (shfileRead(pfile->hshfile,(HPSTR)pIndex,cnt) != cnt)
  240. goto exit;
  241. size -= cnt;
  242. cnt /= sizeof(AVIINDEXENTRY);
  243. //
  244. // fix up the index
  245. //
  246. if (lIndexAdjust == -1) {
  247. lIndexAdjust = (LONG)(dwOffsetMovie + sizeof(DWORD)) -
  248. (LONG)pIndex->dwChunkOffset;
  249. }
  250. pfile->px = IndexAddFileIndex(pfile->px, pIndex, cnt, lIndexAdjust, fRle);
  251. if (pfile->px == NULL)
  252. goto exit;
  253. DPF("!.");
  254. }
  255. DPF("!Done (%ldms)\n", timeGetTime() - time);
  256. f = TRUE;
  257. exit:
  258. if (pIndex)
  259. GlobalFreePtr(pIndex);
  260. return f;
  261. }
  262. ///////////////////////////////////////////////////////////////////////////
  263. ///////////////////////////////////////////////////////////////////////////
  264. HRESULT SaveChanges(CAVIFile FAR * pfile, BOOL fRelease)
  265. {
  266. CAVIStream FAR * pavi;
  267. int stream;
  268. MMCKINFO ck;
  269. MMCKINFO ckRIFF;
  270. MMCKINFO ckLIST;
  271. MMCKINFO ckStream;
  272. LONG lCur;
  273. HRESULT hr = AVIERR_OK;
  274. AVIStreamHeaderShort strhdr;
  275. // Clean up interleaving
  276. if (pfile->fInRecord) {
  277. if (pfile->px->nIndex > pfile->lRecordIndex + 1) {
  278. AVIFileEndRecord((PAVIFILE) pfile);
  279. }
  280. // back out of last record....
  281. --pfile->px->nIndex;
  282. pfile->lWriteLoc -= 3 * sizeof(DWORD);
  283. shfileSeek(pfile->hshfile, pfile->lWriteLoc, SEEK_SET);
  284. pfile->fInRecord = FALSE;
  285. }
  286. // Go back and write out the header
  287. lCur = shfileSeek(pfile->hshfile, 0, SEEK_CUR);
  288. shfileSeek(pfile->hshfile, 0, SEEK_SET);
  289. /* Create RIFF chunk */
  290. ckRIFF.cksize = 0;
  291. ckRIFF.fccType = formtypeAVI;
  292. if (shfileCreateChunk(pfile->hshfile, &ckRIFF, MMIO_CREATERIFF)) {
  293. goto FileError;
  294. }
  295. /* Create header list */
  296. ckLIST.cksize = 0;
  297. ckLIST.fccType = listtypeAVIHEADER;
  298. if (shfileCreateChunk(pfile->hshfile, &ckLIST, MMIO_CREATELIST)) {
  299. goto FileError;
  300. }
  301. /* Create AVI header chunk */
  302. ck.cksize = sizeof(pfile->avihdr);
  303. ck.ckid = ckidAVIMAINHDR;
  304. if (shfileCreateChunk(pfile->hshfile, &ck, 0)) {
  305. goto FileError;
  306. }
  307. CalculateFileDataRate(&pfile->m_AVIFile, (LONG FAR *) &pfile->avihdr.dwMaxBytesPerSec);
  308. // !!! CalculateFileDataRate may have seeked us to the wrong place....
  309. shfileSeek(pfile->hshfile, ck.dwDataOffset, SEEK_SET);
  310. /* Write AVI header info */
  311. if (shfileWrite(pfile->hshfile,
  312. (HPSTR)&pfile->avihdr,
  313. sizeof(pfile->avihdr)) != sizeof(pfile->avihdr)) {
  314. goto FileError;
  315. }
  316. if (shfileAscend(pfile->hshfile, &ck, 0)) {
  317. goto FileError;
  318. }
  319. #if 0
  320. for (l = 0;
  321. l < muldiv32(pfile->avihdr.dwTotalFrames,
  322. pfile->avihdr.dwMicroSecPerFrame,
  323. 1000000L);
  324. l++) {
  325. for (stream = 0; stream < (int) pfile->avihdr.dwStreams; stream++) {
  326. }
  327. }
  328. #endif
  329. for (stream = 0; stream < (int) pfile->avihdr.dwStreams; stream++) {
  330. pavi = pfile->ps[stream];
  331. /* Create stream header list */
  332. ckStream.cksize = 0;
  333. ckStream.fccType = listtypeSTREAMHEADER;
  334. if (shfileCreateChunk(pfile->hshfile,&ckStream,MMIO_CREATELIST)) {
  335. goto FileError;
  336. }
  337. ck.ckid = ckidSTREAMHEADER;
  338. if (shfileCreateChunk(pfile->hshfile, &ck, 0)) {
  339. goto FileError;
  340. }
  341. // Make an AVIStreamHeader from the AVISTREAMINFO
  342. strhdr.fccType = pavi->avistream.fccType;
  343. strhdr.fccHandler = pavi->avistream.fccHandler;
  344. strhdr.dwFlags = pavi->avistream.dwFlags;
  345. strhdr.wPriority = pavi->avistream.wPriority;
  346. strhdr.wLanguage = pavi->avistream.wLanguage;
  347. strhdr.dwRate = pavi->avistream.dwRate;
  348. strhdr.dwScale = pavi->avistream.dwScale;
  349. strhdr.dwStart = pavi->avistream.dwStart;
  350. strhdr.dwLength = pavi->avistream.dwLength;
  351. strhdr.dwSuggestedBufferSize = pavi->avistream.dwSuggestedBufferSize;
  352. strhdr.dwQuality = pavi->avistream.dwQuality;
  353. strhdr.dwSampleSize = pavi->avistream.dwSampleSize;
  354. #ifdef _WIN32
  355. // Write out the Short rectangle format
  356. strhdr.rcFrame.left = (SHORT)pavi->avistream.rcFrame.left ;
  357. strhdr.rcFrame.right = (SHORT)pavi->avistream.rcFrame.right ;
  358. strhdr.rcFrame.top = (SHORT)pavi->avistream.rcFrame.top ;
  359. strhdr.rcFrame.bottom = (SHORT)pavi->avistream.rcFrame.bottom ;
  360. #else
  361. strhdr.rcFrame = pavi->avistream.rcFrame;
  362. #endif
  363. strhdr.dwInitialFrames = pavi->avistream.dwInitialFrames;
  364. if (shfileWrite(pfile->hshfile, (HPSTR) &strhdr, sizeof(strhdr)) !=
  365. sizeof(strhdr)) {
  366. goto FileError;
  367. }
  368. if (shfileAscend(pfile->hshfile, &ck, 0)) {
  369. goto FileError;
  370. }
  371. ck.cksize = pavi->cbFormat;
  372. ck.ckid = ckidSTREAMFORMAT;
  373. if (shfileCreateChunk(pfile->hshfile, &ck, 0))
  374. goto FileError;
  375. if (shfileWrite(pfile->hshfile, (HPSTR) pavi->lpFormat, ck.cksize) !=
  376. (LONG) ck.cksize)
  377. goto FileError;
  378. if (shfileAscend(pfile->hshfile, &ck, 0))
  379. goto FileError;
  380. if (pavi->avistream.szName[0]) {
  381. long sz = lstrlenW(pavi->avistream.szName)+1;
  382. ck.cksize = sz;
  383. ck.ckid = ckidSTREAMNAME;
  384. if (shfileCreateChunk(pfile->hshfile, &ck, 0))
  385. goto FileError;
  386. #ifdef _WIN32
  387. // the file format expects ANSI names!
  388. LPSTR pA = (LPSTR) GlobalAllocPtr(GPTR, sz);
  389. if (pA == 0) {
  390. DPF(("memory allocation failed for Unicode conversion"));
  391. goto FileError;
  392. }
  393. WideCharToMultiByte(CP_ACP, 0, pavi->avistream.szName, -1,
  394. pA, sz, NULL, NULL);
  395. sz = shfileWrite(pfile->hshfile, (HPSTR) pA, ck.cksize);
  396. GlobalFreePtr(pA);
  397. if (sz != (LONG) ck.cksize)
  398. goto FileError;
  399. #else
  400. if (shfileWrite(pfile->hshfile, (HPSTR) pavi->avistream.szName, ck.cksize) !=
  401. (LONG) ck.cksize)
  402. goto FileError;
  403. #endif
  404. if (shfileAscend(pfile->hshfile, &ck, 0))
  405. goto FileError;
  406. }
  407. if (pavi->extra.cb) {
  408. DPF2("Writing %ld bytes of extra stream data.\n", pavi->extra.cb);
  409. if (shfileWrite(pfile->hshfile, (HPSTR) pavi->extra.lp, pavi->extra.cb) !=
  410. (LONG) pavi->extra.cb)
  411. goto FileError;
  412. }
  413. /* Ascend out of stream's header */
  414. if (shfileAscend(pfile->hshfile, &ckStream, 0)) {
  415. goto FileError;
  416. }
  417. }
  418. /* ascend from the Header list */
  419. if (shfileAscend(pfile->hshfile, &ckLIST, 0)) {
  420. goto FileError;
  421. }
  422. lCur = shfileSeek(pfile->hshfile, 0, SEEK_CUR);
  423. DPF("Data list start = %ld, current pos = %ld\n", pfile->lDataListStart, lCur);
  424. if (lCur + 8 > pfile->lDataListStart) {
  425. // !!! Ack: we didn't leave enough space for the header.
  426. // !!! How can we avoid this?
  427. DPF("Header was too big! Failing!\n");
  428. goto FileError;
  429. }
  430. /* Pad this header out so that the real data will start on a 2K
  431. ** boundary by writing a JUNK chunk.
  432. */
  433. ck.ckid = ckidAVIPADDING;
  434. ck.cksize = pfile->lDataListStart - lCur - 8;
  435. if (shfileCreateChunk(pfile->hshfile,&ck,0)) {
  436. goto FileError;
  437. }
  438. shfileZero(pfile->hshfile, pfile->lDataListStart - lCur - 8);
  439. if (shfileAscend(pfile->hshfile, &ck, 0)) {
  440. goto FileError;
  441. }
  442. /* Start the 'movi' list, where all of the actual data will be. */
  443. ckLIST.cksize = pfile->lWriteLoc - pfile->lDataListStart - 8;
  444. ckLIST.fccType = listtypeAVIMOVIE;
  445. if (shfileCreateChunk(pfile->hshfile, &ckLIST, MMIO_CREATELIST)) {
  446. goto FileError;
  447. }
  448. shfileSeek(pfile->hshfile, pfile->lWriteLoc, SEEK_SET);
  449. if (shfileAscend(pfile->hshfile, &ckLIST, 0))
  450. goto FileError;
  451. if (!WriteOutIndex(pfile, ckLIST.dwDataOffset))
  452. goto FileError;
  453. //
  454. // Write out any extra data around
  455. //
  456. if (pfile->extra.cb) {
  457. DPF2("Writing %ld bytes of extra file data.\n", pfile->extra.cb);
  458. if (shfileWrite(pfile->hshfile,
  459. (HPSTR) pfile->extra.lp,
  460. pfile->extra.cb) !=
  461. (LONG) pfile->extra.cb)
  462. goto FileError;
  463. }
  464. FinishUp:
  465. if (shfileAscend(pfile->hshfile, &ckRIFF, 0)) {
  466. hr = ResultFromScode(AVIERR_FILEWRITE);
  467. }
  468. //
  469. // Always flush to be sure that the data really made it to the disk....
  470. //
  471. if (shfileFlush(pfile->hshfile, 0)) {
  472. hr = ResultFromScode(AVIERR_FILEWRITE);
  473. }
  474. return hr;
  475. FileError:
  476. DPF("SaveChanges returning Error! This error will be ignored!\n");
  477. hr = ResultFromScode(AVIERR_FILEWRITE);
  478. goto FinishUp;
  479. }
  480. ///////////////////////////////////////////////////////////////////////////
  481. ///////////////////////////////////////////////////////////////////////////
  482. STDMETHODIMP_(ULONG) CAVIFile::CUnknownImpl::Release()
  483. {
  484. CAVIFile FAR * pfile = m_pAVIFile;
  485. CAVIStream FAR * pavi;
  486. int iStream;
  487. CLock tlock(pfile);
  488. DPF2("File %p: Usage--=%lx\n", (DWORD_PTR) (LPVOID) this, m_refs - 1);
  489. uUseCount--;
  490. if (!--m_refs) {
  491. if (pfile->fDirty) {
  492. ++m_refs;
  493. SaveChanges(pfile, TRUE);
  494. --m_refs;
  495. // Unfortunately, it's too late to tell about any errors....
  496. }
  497. for (iStream = 0; iStream < (int)pfile->avihdr.dwStreams; iStream++) {
  498. pavi = pfile->ps[iStream];
  499. if (!pavi)
  500. continue;
  501. delete pavi;
  502. }
  503. if (pfile->hshfile) {
  504. shfileRelease(pfile->hshfile);
  505. shfileClose(pfile->hshfile, 0);
  506. }
  507. if (pfile->px)
  508. FreeIndex(pfile->px);
  509. if (pfile->extra.lp) {
  510. DPF2("Freeing %ld bytes of extra file data.\n", pfile->extra.cb);
  511. GlobalFreePtr(pfile->extra.lp);
  512. }
  513. if (pfile->pb)
  514. EndBuffered(pfile->pb);
  515. pfile->hshfile = NULL;
  516. pfile->px = NULL;
  517. // done with critsec now - no-one else has any refs to it
  518. tlock.Exit();
  519. #ifdef _WIN32
  520. DeleteCriticalSection(&pfile->m_critsec);
  521. #endif
  522. delete pfile;
  523. return 0;
  524. } else {
  525. if (pfile->hshfile)
  526. shfileRelease(pfile->hshfile);
  527. }
  528. return m_refs;
  529. }
  530. ///////////////////////////////////////////////////////////////////////////
  531. ///////////////////////////////////////////////////////////////////////////
  532. #ifndef _WIN32
  533. STDMETHODIMP CAVIFile::CAVIFileImpl::Save(
  534. LPCTSTR szFile,
  535. AVICOMPRESSOPTIONS FAR *lpOptions,
  536. AVISAVECALLBACK lpfnCallback)
  537. {
  538. CAVIFile FAR * pfile = m_pAVIFile;
  539. HRESULT hr = ResultFromScode(AVIERR_OK);
  540. CLock tlock(pfile);
  541. if (pfile->fDirty) {
  542. hr = SaveChanges(pfile, FALSE);
  543. }
  544. return hr;
  545. }
  546. #endif
  547. #define SLASH(c) ((c) == TEXT('/') || (c) == TEXT('\\'))
  548. /*--------------------------------------------------------------+
  549. | FileName - return a pointer to the filename part of szPath |
  550. | with no preceding path. |
  551. +--------------------------------------------------------------*/
  552. LPTSTR FAR FileName(LPCTSTR lszPath)
  553. {
  554. LPCTSTR lszCur;
  555. #ifdef _WIN32
  556. // We really should be using GetFileTitle API as this will provide
  557. // better validation on the input name.
  558. #endif
  559. for (lszCur = lszPath + lstrlen(lszPath); lszCur > lszPath && !SLASH(*lszCur) && *lszCur != ':';) {
  560. #ifdef _WIN32
  561. lszCur = CharPrev(lszPath, lszCur);
  562. #else
  563. lszCur = AnsiPrev(lszPath, lszCur);
  564. #endif
  565. }
  566. if (lszCur == lszPath)
  567. return (LPTSTR)lszCur;
  568. else
  569. return (LPTSTR)(lszCur + 1);
  570. }
  571. // We do not currently use the last defined parameter for IsRectBogus
  572. // Use a macro to remove it. (It can be quickly restored.)
  573. #define ISRECTBOGUS(lprc, dwW, dwH, lpbi) IsRectBogus(lprc, dwW, dwH)
  574. INLINE BOOL IsRectBogus(LPRECT lprc, DWORD dwFrameWidth, DWORD dwFrameHeight)
  575. // unused LPBITMAPINFOHEADER lpbi)
  576. {
  577. if (IsRectEmpty(lprc))
  578. return TRUE;
  579. if (lprc->right - lprc->left > (int) dwFrameWidth)
  580. return TRUE;
  581. if (lprc->bottom - lprc->top > (int) dwFrameHeight)
  582. return TRUE;
  583. // !!!! Check that rectangle matches lpbi?
  584. // We've run out of things to check, so it's OK....
  585. return FALSE;
  586. }
  587. ///////////////////////////////////////////////////////////////////////////
  588. ///////////////////////////////////////////////////////////////////////////
  589. STDMETHODIMP CAVIFile::OpenInternal(DWORD mode)
  590. {
  591. CAVIFile FAR * pfile = this;
  592. CAVIStream FAR * pavi;
  593. MMCKINFO ck;
  594. MMCKINFO ckRIFF;
  595. MMCKINFO ckLIST;
  596. MMCKINFO ckStream;
  597. DWORD dwSize;
  598. BOOL fRle=FALSE;
  599. LONG l;
  600. int iStream;
  601. int i;
  602. HRESULT hr = ResultFromScode(AVIERR_OK);
  603. IUnknown FAR * pUnk;
  604. AVIStreamHeaderShort strhdr;
  605. TCHAR ach[20];
  606. TCHAR ach2[20];
  607. int iStreamNumber;
  608. #ifdef DEBUG
  609. DWORD time;
  610. #endif
  611. CLock tlock(pfile);
  612. if (!pfile->hshfile) {
  613. hr = ResultFromScode(AVIERR_FILEOPEN);
  614. goto error;
  615. }
  616. if (mode & OF_CREATE) {
  617. // make a empty index.
  618. pfile->px = IndexCreate();
  619. if (pfile->px == 0)
  620. goto memerror;
  621. pfile->lWriteLoc = 0;
  622. pfile->lHeaderSize = sizeof(MainAVIHeader) + 11 * sizeof(DWORD);
  623. #ifndef AVIF_TRUSTCKTYPE
  624. #define AVIF_TRUSTCKTYPE 0x00000800 // Use CKType to find key frames?
  625. #endif
  626. pfile->avihdr.dwFlags = AVIF_HASINDEX | AVIF_TRUSTCKTYPE;
  627. } else {
  628. /* Read RIFF chunk */
  629. if (shfileDescend(pfile->hshfile, &ckRIFF, NULL, 0) != 0)
  630. goto readerror;
  631. /*
  632. * check for a 'QuickTime AVI' file, a QuickTime AVI file is a
  633. * QuickTime public movie with a AVI file in the 'mdat' atom.
  634. */
  635. if (ckRIFF.cksize == mmioFOURCC('m','d','a','t'))
  636. {
  637. /*
  638. * now the 'mdat' atom better be a RIFF/AVI or we cant handle it.
  639. */
  640. if (shfileDescend(pfile->hshfile, &ckRIFF, NULL, 0) != 0)
  641. goto formaterror;
  642. }
  643. if (ckRIFF.ckid != FOURCC_RIFF)
  644. goto formaterror;
  645. if (ckRIFF.fccType != formtypeAVI)
  646. goto formaterror;
  647. /* Read header list */
  648. ckLIST.fccType = listtypeAVIHEADER;
  649. if (FindChunkAndKeepExtras(&pfile->extra, pfile->hshfile, &ckLIST, &ckRIFF, MMIO_FINDLIST))
  650. goto error;
  651. pfile->lHeaderSize = ckLIST.cksize + 8 * sizeof(DWORD);
  652. /* Read AVI header chunk */
  653. ck.ckid = ckidAVIMAINHDR;
  654. if (FindChunkAndKeepExtras(&pfile->extra, pfile->hshfile, &ck, &ckLIST, MMIO_FINDCHUNK))
  655. goto error;
  656. dwSize = min(ck.cksize, sizeof(MainAVIHeader));
  657. /* Read AVI header info */
  658. if (shfileRead(pfile->hshfile, (HPSTR)&pfile->avihdr, dwSize) != (LONG)dwSize)
  659. goto readerror;
  660. if (shfileAscend(pfile->hshfile, &ck, 0))
  661. goto readerror;
  662. /* Check there aren't more streams than we can handle */
  663. if (pfile->avihdr.dwStreams > MAXSTREAMS) {
  664. /* Make sure we don't crash deleteing non-existent streams */
  665. pfile->avihdr.dwStreams = 0;
  666. goto error;
  667. }
  668. for (iStream = 0; iStream < (int)pfile->avihdr.dwStreams; iStream++) {
  669. pfile->ps[iStream] = NULL;
  670. }
  671. /* Allocate stream data stuff, read streams */
  672. for (iStream = 0; iStream < (int)pfile->avihdr.dwStreams; ) {
  673. if (shfileDescend(pfile->hshfile, &ckStream, &ckLIST, 0) != 0)
  674. goto readerror;
  675. //
  676. // found a non-stream header skip
  677. //
  678. if (ckStream.fccType != listtypeSTREAMHEADER ||
  679. ckStream.ckid != FOURCC_LIST) {
  680. if ((hr = ReadIntoExtra(&pfile->extra,
  681. pfile->hshfile,
  682. &ckStream)) != ResultFromScode(AVIERR_OK))
  683. goto error;
  684. if (shfileAscend(pfile->hshfile, &ckStream, 0) != 0)
  685. goto readerror;
  686. continue;
  687. }
  688. pfile->ps[iStream] = new FAR CAVIStream(NULL, &pUnk);
  689. if (!pfile->ps[iStream])
  690. goto memerror;
  691. pavi = pfile->ps[iStream];
  692. pavi->pfile = pfile;
  693. pavi->iStream = iStream;
  694. //
  695. // walk every chunk in this stream header, until we are done.
  696. //
  697. while (shfileDescend(pfile->hshfile, &ck, &ckStream, 0) == 0) {
  698. switch (ck.ckid) {
  699. case ckidSTREAMHEADER:
  700. //
  701. // set these to sane default's incase the file
  702. // header is not big enough
  703. //
  704. // NOTE the stream rectangle is set to NULL, if
  705. // this is a video stream it will be corrected
  706. // when we process the format.
  707. //
  708. strhdr.dwQuality = (DWORD) ICQUALITY_DEFAULT;
  709. #ifdef _WIN32
  710. // Set the 16 bit rectangle values to 0
  711. strhdr.rcFrame.left =
  712. strhdr.rcFrame.right=
  713. strhdr.rcFrame.top =
  714. strhdr.rcFrame.bottom = 0;
  715. #else
  716. SetRectEmpty(&strhdr.rcFrame);
  717. #endif
  718. l = min(ck.cksize, sizeof(strhdr));
  719. if (shfileRead(pfile->hshfile, (HPSTR)&strhdr, l) != l)
  720. goto readerror;
  721. // Copy fields from strhdr into StreamInfo
  722. pavi->avistream.fccType = strhdr.fccType;
  723. pavi->avistream.fccHandler = strhdr.fccHandler;
  724. pavi->avistream.dwFlags = strhdr.dwFlags; //!!!
  725. pavi->avistream.dwCaps = 0; // !!!
  726. pavi->avistream.wPriority = strhdr.wPriority;
  727. pavi->avistream.wLanguage = strhdr.wLanguage;
  728. pavi->avistream.dwRate = strhdr.dwRate;
  729. pavi->avistream.dwScale = strhdr.dwScale;
  730. pavi->avistream.dwStart = strhdr.dwStart;
  731. pavi->avistream.dwLength = strhdr.dwLength;
  732. pavi->avistream.dwSuggestedBufferSize = strhdr.dwSuggestedBufferSize;
  733. pavi->avistream.dwInitialFrames = strhdr.dwInitialFrames;
  734. pavi->avistream.dwQuality = strhdr.dwQuality;
  735. pavi->avistream.dwSampleSize = strhdr.dwSampleSize;
  736. #ifdef _WIN32
  737. // Copy the 16 bit rectangle we have read from
  738. // persistent storage into a WIN32 RECT (32 bit)
  739. // structure. There is no operator= defined for
  740. // this "short rect" to RECT assignment.
  741. pavi->avistream.rcFrame.left = strhdr.rcFrame.left;
  742. pavi->avistream.rcFrame.top = strhdr.rcFrame.top;
  743. pavi->avistream.rcFrame.right = strhdr.rcFrame.right;
  744. pavi->avistream.rcFrame.bottom= strhdr.rcFrame.bottom;
  745. #else
  746. pavi->avistream.rcFrame = strhdr.rcFrame;
  747. #endif
  748. pavi->avistream.dwEditCount = 0;
  749. pavi->avistream.dwFormatChangeCount = 0;
  750. // Make up a stream name out of the filename, stream
  751. // type, and stream number.
  752. if (pavi->avistream.fccType == streamtypeVIDEO)
  753. LoadString(ghMod, IDS_VIDEO, ach, NUMELMS(ach));
  754. else if (pavi->avistream.fccType == streamtypeAUDIO)
  755. LoadString(ghMod, IDS_AUDIO, ach, NUMELMS(ach));
  756. else
  757. wsprintf(ach, TEXT("'%4.4hs'"),
  758. (LPSTR)&(pavi->avistream.fccType));
  759. // figure out what # stream of this type this is....
  760. iStreamNumber = 1;
  761. for (i = 0; i < iStream; i++) {
  762. if (pfile->ps[i]->avistream.fccType ==
  763. pavi->avistream.fccType)
  764. ++iStreamNumber;
  765. }
  766. LoadString(ghMod, IDS_SSSTREAMD, ach2, NUMELMS(ach2));
  767. {
  768. TCHAR achTemp[MAX_PATH];
  769. wsprintf(achTemp,
  770. (LPTSTR)ach2,
  771. (LPTSTR)FileName(pfile->achFile),
  772. (LPTSTR)ach,
  773. iStreamNumber);
  774. #if defined _WIN32 && !defined UNICODE
  775. lstrzcpyAtoW (pavi->avistream.szName,
  776. achTemp,
  777. NUMELMS (pavi->avistream.szName));
  778. #else
  779. lstrzcpy (pavi->avistream.szName,
  780. achTemp,
  781. NUMELMS (pavi->avistream.szName));
  782. #endif
  783. }
  784. break;
  785. case ckidSTREAMFORMAT:
  786. if (pavi->lpFormat == NULL) {
  787. pavi->cbFormat = ck.cksize;
  788. pavi->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
  789. ck.cksize);
  790. if (pavi->lpFormat == NULL)
  791. goto memerror;
  792. if (shfileRead(pfile->hshfile, (HPSTR) pavi->lpFormat, (LONG)ck.cksize) != (LONG)ck.cksize)
  793. goto readerror;
  794. #define lpbi ((LPBITMAPINFOHEADER)pavi->lpFormat)
  795. if (pavi->avistream.fccType != streamtypeVIDEO)
  796. break;
  797. if (!ValidateBitmapInfoHeader(lpbi, ck.cksize)) {
  798. break;
  799. }
  800. //
  801. // make sure this is set
  802. //
  803. if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
  804. lpbi->biClrUsed = (1 << (int)lpbi->biBitCount);
  805. //
  806. // fix up bogus stream rectangles.
  807. //
  808. if (ISRECTBOGUS(&pavi->avistream.rcFrame,
  809. pfile->avihdr.dwWidth,
  810. pfile->avihdr.dwHeight,
  811. lpbi)) {
  812. SetRect(&pavi->avistream.rcFrame, 0, 0,
  813. (int)lpbi->biWidth, (int)lpbi->biHeight);
  814. }
  815. //
  816. // make sure the biCompression is right for
  817. // RLE files.
  818. //
  819. if (lpbi->biCompression == 0 && lpbi->biBitCount == 8) {
  820. if (pavi->avistream.fccHandler == comptypeRLE0 ||
  821. pavi->avistream.fccHandler == comptypeRLE)
  822. lpbi->biCompression = BI_RLE8;
  823. }
  824. if (pavi->avistream.fccHandler == comptypeNONE &&
  825. lpbi->biCompression == 0)
  826. pavi->avistream.fccHandler = comptypeDIB;
  827. if (pavi->avistream.fccHandler == 0 &&
  828. lpbi->biCompression == 0)
  829. pavi->avistream.fccHandler = comptypeDIB;
  830. // Assuming a DIB handler has RGB data will blow up
  831. // if it has RLE data, and VidEdit et. al write out
  832. // confusing files like this.
  833. //if (pavi->avistream.fccHandler == comptypeDIB)
  834. // lpbi->biCompression = BI_RGB;
  835. if (lpbi->biCompression <= BI_RLE8)
  836. fRle = TRUE;
  837. #undef lpbi
  838. }
  839. break;
  840. case ckidSTREAMHANDLERDATA:
  841. if (pavi->lpData == NULL) {
  842. pavi->cbData = ck.cksize;
  843. pavi->lpData = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
  844. ck.cksize);
  845. if (pavi->lpData == NULL)
  846. goto memerror;
  847. if (shfileRead(pfile->hshfile, (HPSTR)pavi->lpData,
  848. (LONG)ck.cksize) != (LONG)ck.cksize)
  849. goto readerror;
  850. }
  851. break;
  852. case ckidSTREAMNAME:
  853. {
  854. #ifdef _WIN32
  855. char achTemp[MAX_PATH];
  856. l = (LONG)min((LONG) ck.cksize, NUMELMS(achTemp));
  857. if (shfileRead(pfile->hshfile, (LPSTR)achTemp, l) != l) {
  858. goto readerror;
  859. }
  860. MultiByteToWideChar(CP_ACP, 0, achTemp, -1,
  861. pavi->avistream.szName,
  862. NUMELMS(pavi->avistream.szName));
  863. #else
  864. l = min((LONG) ck.cksize, NUMELMS(pavi->avistream.szName));
  865. if (shfileRead(pfile->hshfile,
  866. (HPSTR)pavi->avistream.szName, l) != l)
  867. goto readerror;
  868. #endif
  869. }
  870. break;
  871. case ckidAVIPADDING:
  872. case mmioFOURCC('p','a','d','d'):
  873. break;
  874. default:
  875. if ((hr = ReadIntoExtra(&pavi->extra,
  876. pfile->hshfile,
  877. &ck)) != ResultFromScode(AVIERR_OK))
  878. goto error;
  879. break;
  880. }
  881. if (shfileAscend(pfile->hshfile, &ck, 0) != 0)
  882. goto readerror;
  883. }
  884. /* Ascend out of stream header */
  885. if (shfileAscend(pfile->hshfile, &ckStream, 0) != 0)
  886. goto readerror;
  887. if (pavi->avistream.fccType == 0)
  888. goto formaterror;
  889. if (pavi->lpFormat == NULL)
  890. goto formaterror;
  891. //
  892. // make sure the sample size is set right
  893. //
  894. switch(pavi->avistream.fccType) {
  895. case streamtypeAUDIO:
  896. /* Hack for backward compatibility with audio */
  897. pavi->avistream.dwSampleSize =
  898. ((LPWAVEFORMAT)pavi->lpFormat)->nBlockAlign;
  899. // For audio, this number isn't useful when reading.
  900. // !!!pavi->avistream.dwInitialFrames = 0;
  901. // !!! We should let people read what the header says....
  902. break;
  903. case streamtypeVIDEO:
  904. // !!! But what if the samples are all the right size?
  905. pavi->avistream.dwSampleSize = 0;
  906. break;
  907. default:
  908. // !!! ??? pavi->avistream.dwInitialFrames = 0;
  909. // !!! ??? pavi->avistream.dwSampleSize = 0;
  910. break;
  911. }
  912. l = NUMELMS(pavi->avistream.szName) - 1;
  913. pavi->avistream.szName[l] = TEXT('\0');
  914. // next stream
  915. iStream++;
  916. }
  917. // Read extra data at end of header list....
  918. FindChunkAndKeepExtras(&pfile->extra, pfile->hshfile, &ck, &ckLIST, 0);
  919. if (shfileAscend(pfile->hshfile, &ckLIST, 0))
  920. goto readerror;
  921. /* Find big data chunk */
  922. ckLIST.fccType = listtypeAVIMOVIE;
  923. if (FindChunkAndKeepExtras(&pfile->extra, pfile->hshfile, &ckLIST, &ckRIFF, MMIO_FINDLIST))
  924. goto error;
  925. pfile->lDataListStart = ckLIST.dwDataOffset - 2 * sizeof(DWORD);
  926. if (shfileAscend(pfile->hshfile, &ckLIST, 0))
  927. goto readerror;
  928. // Keep track of where data can be written
  929. pfile->lWriteLoc = ckLIST.dwDataOffset + ckLIST.cksize;
  930. //
  931. // read in or create a index, we only want the index entries for the
  932. // stream we are interested in!
  933. //
  934. ck.ckid = ckidAVINEWINDEX;
  935. if (FindChunkAndKeepExtras(&pfile->extra, pfile->hshfile, &ck, &ckRIFF, MMIO_FINDCHUNK) == 0 && ck.cksize != 0) {
  936. if (!ReadInIndex(pfile, ck.cksize, ckLIST.dwDataOffset, fRle))
  937. goto formaterror;
  938. } else {
  939. /* Seek back to beginning of list, so we can scan */
  940. shfileSeek(pfile->hshfile, ckLIST.dwDataOffset + sizeof(DWORD), SEEK_SET);
  941. //!!! should we really scan big files, or give a error?
  942. pfile->px = IndexCreate();
  943. if (pfile->px == 0)
  944. goto formaterror;
  945. DPF("Scanning index", time = timeGetTime());
  946. /* Scan through chunks... */
  947. while (shfileDescend(pfile->hshfile, &ck, &ckLIST, 0) == 0) {
  948. AddToIndex(pfile,ck.ckid,ck.cksize,ck.dwDataOffset-8,0);
  949. /* Hack: don't ascend from LISTs */
  950. if (ck.ckid != FOURCC_LIST) {
  951. if (shfileAscend(pfile->hshfile, &ck, 0) != 0)
  952. goto readerror;
  953. }
  954. if (pfile->px->nIndex % 512 == 0) {
  955. DPF("!.");
  956. }
  957. }
  958. DPF("!Done (%ldms)\n", timeGetTime() - time);
  959. }
  960. if (pfile->px->nIndex == 0)
  961. goto formaterror;
  962. // Read extra data at end of file....
  963. FindChunkAndKeepExtras(&pfile->extra, pfile->hshfile, &ck, &ckRIFF, 0);
  964. // shfileSetBuffer(pfile->hshfile, NULL, 0L, 0);
  965. //
  966. // compute dwSuggestedBufferSize
  967. //
  968. if (pfile->avihdr.dwFlags & AVIF_ISINTERLEAVED) {
  969. LONG l;
  970. LONG lLen;
  971. pfile->avihdr.dwSuggestedBufferSize = 0;
  972. for (l=IndexFirst(pfile->px, STREAM_REC);
  973. l != -1;
  974. l = IndexNext(pfile->px, l, 0)) {
  975. lLen = IndexLength(pfile->px, l);
  976. if (pfile->avihdr.dwSuggestedBufferSize < (DWORD)lLen)
  977. pfile->avihdr.dwSuggestedBufferSize = (DWORD)lLen;
  978. }
  979. }
  980. #ifdef USE_DIRECTIO
  981. // don't use additional buffering if we're using direct io
  982. if (shfileIsDirect(pfile->hshfile)) {
  983. pfile->pb = NULL;
  984. } else
  985. #endif
  986. {
  987. if ((pfile->avihdr.dwFlags & AVIF_ISINTERLEAVED) &&
  988. pfile->avihdr.dwInitialFrames) {
  989. pfile->pb = InitBuffered((int) pfile->avihdr.dwInitialFrames * 2,
  990. pfile->avihdr.dwSuggestedBufferSize,
  991. pfile->hshfile,
  992. pfile->px);
  993. }
  994. else /* if (pfile->avihdr.dwSuggestedBufferSize > 0 &&
  995. pfile->avihdr.dwSuggestedBufferSize < 32l*1024) */ {
  996. int nBuffers = GetProfileIntA("avifile", "buffers", 5);
  997. pfile->pb = InitBuffered(nBuffers,
  998. min(pfile->avihdr.dwSuggestedBufferSize * 2, 32768L),
  999. pfile->hshfile,
  1000. pfile->px);
  1001. }
  1002. }
  1003. }
  1004. return ResultFromScode(AVIERR_OK);
  1005. readerror:
  1006. return ResultFromScode(AVIERR_FILEREAD);
  1007. memerror:
  1008. return ResultFromScode(AVIERR_MEMORY);
  1009. formaterror:
  1010. return ResultFromScode(AVIERR_BADFORMAT);
  1011. error:
  1012. if (hr == ResultFromScode(AVIERR_OK))
  1013. return ResultFromScode(AVIERR_ERROR);
  1014. return hr;
  1015. }
  1016. ///////////////////////////////////////////////////////////////////////////
  1017. ///////////////////////////////////////////////////////////////////////////
  1018. #ifndef _WIN32
  1019. STDMETHODIMP CAVIFile::CAVIFileImpl::Open(LPCTSTR szFile, UINT mode)
  1020. {
  1021. CAVIFile FAR * pfile = m_pAVIFile;
  1022. UINT ui;
  1023. CLock tlock(pfile);
  1024. if (pfile->achFile[0])
  1025. return ResultFromScode(-1);
  1026. pfile->mode = mode;
  1027. lstrcpy(pfile->achFile, szFile);
  1028. // Assumptions about avilib.cpp:
  1029. // We're assuming that if CREATE is set, WRITE is set too.
  1030. // We're assuming that we'll always see READWRITE instead of just WRITE.
  1031. // If it ain't broke, don't fix it - who do I look like, the share flag
  1032. // standards enforcing committee?
  1033. #if 0
  1034. // force the share flags to the 'correct' values
  1035. if (mode & OF_READWRITE) {
  1036. pfile->mode = (mode & ~(MMIO_SHAREMODE)) | OF_SHARE_EXCLUSIVE;
  1037. } else {
  1038. pfile->mode = (mode & ~(MMIO_SHAREMODE)) | OF_SHARE_DENY_WRITE;
  1039. }
  1040. #endif
  1041. // try to open the actual file
  1042. // If the first attempt fails, no system error box, please.
  1043. ui = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  1044. pfile->hshfile = shfileOpen(pfile->achFile, NULL, pfile->mode);
  1045. if (!pfile->hshfile && ((mode & MMIO_RWMODE) == OF_READ)) {
  1046. // if the open fails, try again without the share flags.
  1047. pfile->mode &= ~(MMIO_SHAREMODE);
  1048. pfile->hshfile = shfileOpen(pfile->achFile, NULL, pfile->mode);
  1049. }
  1050. if (pfile->hshfile)
  1051. shfileAddRef(pfile->hshfile); // compensate for later rel of IUnknown
  1052. SetErrorMode(ui);
  1053. return pfile->OpenInternal(mode);
  1054. }
  1055. #endif
  1056. ///////////////////////////////////////////////////////////////////////////
  1057. ///////////////////////////////////////////////////////////////////////////
  1058. STDMETHODIMP CAVIFile::CAVIFileImpl::GetStream(PAVISTREAM FAR *ppavi, DWORD fccType, LONG lParam)
  1059. {
  1060. CAVIFile FAR * pfile = m_pAVIFile;
  1061. CAVIStream FAR *pavi;
  1062. int iStreamCur;
  1063. int iStreamWant;
  1064. int iStream;
  1065. LONG lLength;
  1066. // thread locking
  1067. CLock tlock(pfile);
  1068. *ppavi = NULL;
  1069. iStreamWant = (int)lParam;
  1070. if (iStreamWant < 0 || iStreamWant >= (int)pfile->avihdr.dwStreams)
  1071. return ResultFromScode(AVIERR_NODATA);
  1072. /* Allocate stream data stuff, read streams */
  1073. for (iStreamCur = -1, iStream = 0;
  1074. iStream < (int)pfile->avihdr.dwStreams;
  1075. iStream++) {
  1076. if (fccType == 0 || pfile->ps[iStream]->avistream.fccType == fccType)
  1077. iStreamCur++;
  1078. if (iStreamCur == iStreamWant)
  1079. break;
  1080. }
  1081. if (iStreamCur != iStreamWant)
  1082. return ResultFromScode(AVIERR_NODATA);
  1083. pavi = pfile->ps[iStream];
  1084. if (pavi->fInit)
  1085. goto returnnow;
  1086. pavi->fInit = TRUE;
  1087. #if 0
  1088. if ((pf->mode & (OF_WRITE | OF_READWRITE)) == 0) {
  1089. pavi->hshfile = shfileOpen(pfile->achFile, NULL, MMIO_ALLOCBUF | pfile->mode);
  1090. if (!pavi->hshfile)
  1091. goto error;
  1092. } else
  1093. #endif
  1094. pavi->hshfile = pfile->hshfile;
  1095. pavi->lPal = -4242;
  1096. pavi->psx = MakeStreamIndex(pfile->px, iStream,
  1097. (LONG)pavi->avistream.dwStart - pavi->avistream.dwInitialFrames,
  1098. (LONG)pavi->avistream.dwSampleSize,
  1099. pfile->hshfile, shfileReadProc, NULL);
  1100. if (pavi->psx == NULL) {
  1101. pavi->fInit = FALSE; // sigh; failed.
  1102. return ResultFromScode(AVIERR_MEMORY);
  1103. }
  1104. AddRef(); // Now safe. We only ever return AVIERR_OK after this.
  1105. pavi->avistream.dwSuggestedBufferSize = pavi->psx->lMaxSampleSize;
  1106. if (pavi->psx->lPalFrames == 0)
  1107. pavi->avistream.dwFlags &= ~AVISF_VIDEO_PALCHANGES;
  1108. else
  1109. pavi->avistream.dwFlags |= AVISF_VIDEO_PALCHANGES;
  1110. pavi->pb = pavi->pfile->pb;
  1111. if (!pavi->pb) {
  1112. #ifdef USE_DIRECTIO
  1113. if (!shfileIsDirect(pavi->hshfile))
  1114. #endif
  1115. {
  1116. lBufferSize = GetProfileIntA("avifile", "buffersize", 0) * 1024L;
  1117. nBuffers = GetProfileIntA("avifile", "buffers", 0);
  1118. if (lBufferSize && nBuffers && !(pavi->pfile->mode & OF_CREATE)) {
  1119. pavi->pb = InitBuffered(nBuffers, lBufferSize,
  1120. pavi->hshfile, NULL);
  1121. }
  1122. }
  1123. }
  1124. //
  1125. // use ReadBuffered() to read data!
  1126. //
  1127. if (pavi->pb) {
  1128. pavi->psx->hFile = (HANDLE)pavi->pb;
  1129. pavi->psx->Read = (STREAMIOPROC)BufferedRead;
  1130. }
  1131. lLength = pavi->psx->lEnd - pavi->psx->lStart;
  1132. if (lLength != (LONG)pavi->avistream.dwLength +
  1133. (LONG)pavi->avistream.dwInitialFrames) {
  1134. #ifdef DEBUG
  1135. DPF("Stream %d: Length is %ld, header says %ld.\n",
  1136. iStream, lLength,
  1137. pavi->avistream.dwLength + pavi->avistream.dwInitialFrames);
  1138. #endif
  1139. //!!! should we correct the header!!!
  1140. }
  1141. returnnow:
  1142. pavi->m_AVIStream.QueryInterface(IID_IAVIStream, (LPVOID FAR *) ppavi);
  1143. Assert(*ppavi); // We had better return an interface pointer
  1144. //
  1145. // all done return success.
  1146. //
  1147. return ResultFromScode(AVIERR_OK); // success
  1148. }
  1149. ///////////////////////////////////////////////////////////////////////////
  1150. ///////////////////////////////////////////////////////////////////////////
  1151. STDMETHODIMP CAVIFile::CAVIFileImpl::CreateStream(
  1152. PAVISTREAM FAR *ppavi,
  1153. AVISTREAMINFOW FAR *psi)
  1154. {
  1155. CAVIFile FAR * pf = m_pAVIFile;
  1156. CAVIStream FAR * pavi;
  1157. int iStream = (int) pf->avihdr.dwStreams;
  1158. IUnknown FAR * pUnk;
  1159. CLock tlock(m_pAVIFile);
  1160. // !!! If we are writing to an existing file, and not to a new file, we have
  1161. // a limitation where we cannot grow the size of the header.
  1162. // Check to see if the header will take up too much room!
  1163. if (pf->lWriteLoc > 0) {
  1164. LONG lHeader = sizeof(AVIStreamHeader) +
  1165. pf->lHeaderSize +
  1166. 8 * sizeof(DWORD) +
  1167. lstrlenW(psi->szName);
  1168. if (lHeader > pf->lDataListStart) {
  1169. DPF("Header will be too big with this new stream!\n");
  1170. return ResultFromScode(AVIERR_UNSUPPORTED);
  1171. }
  1172. }
  1173. pf->lHeaderSize += sizeof(AVIStreamHeader) + 8 * sizeof(DWORD) +
  1174. lstrlenW(psi->szName);
  1175. if (iStream >= MAXSTREAMS) {
  1176. DPF("Ack: Too many streams: we only support %ld.\n", (LONG) MAXSTREAMS);
  1177. return ResultFromScode(AVIERR_UNSUPPORTED);
  1178. }
  1179. if ((pf->mode & (OF_WRITE | OF_READWRITE)) == 0)
  1180. return ResultFromScode(AVIERR_READONLY);
  1181. pf->ps[iStream] = new FAR CAVIStream(NULL, &pUnk);
  1182. if (!pf->ps[iStream])
  1183. return ResultFromScode(AVIERR_MEMORY);
  1184. pavi = pf->ps[iStream];
  1185. pavi->iStream = iStream;
  1186. pavi->pfile = pf;
  1187. pavi->avistream = *psi;
  1188. pavi->avistream.dwLength = 0; // no data initially
  1189. pavi->avistream.dwSuggestedBufferSize = 0;
  1190. pavi->hshfile = pf->hshfile;
  1191. pavi->m_AVIStream.AddRef();
  1192. AddRef();
  1193. pavi->lpFormat = NULL; // This will be set leater with a SetFormat
  1194. pavi->cbFormat = 0;
  1195. if (pavi->avistream.fccType == streamtypeAUDIO) {
  1196. SetRectEmpty(&pavi->avistream.rcFrame);
  1197. }
  1198. pf->avihdr.dwStreams++;
  1199. if (pavi->iStream == 0) {
  1200. pavi->pfile->avihdr.dwMicroSecPerFrame =
  1201. max(1000L, muldiv32(1000000L,
  1202. pavi->avistream.dwScale,
  1203. pavi->avistream.dwRate));
  1204. }
  1205. /* Make sure the width and height of the created file are right.... */
  1206. pf->avihdr.dwWidth = max(pf->avihdr.dwWidth,
  1207. (DWORD) pavi->avistream.rcFrame.right);
  1208. pf->avihdr.dwHeight = max(pf->avihdr.dwHeight,
  1209. (DWORD) pavi->avistream.rcFrame.bottom);
  1210. // Only if interleaved?
  1211. pf->avihdr.dwInitialFrames = max(pf->avihdr.dwInitialFrames,
  1212. pavi->avistream.dwInitialFrames);
  1213. *ppavi = &pavi->m_AVIStream;
  1214. return ResultFromScode(AVIERR_OK);
  1215. }
  1216. ///////////////////////////////////////////////////////////////////////////
  1217. ///////////////////////////////////////////////////////////////////////////
  1218. #if 0
  1219. STDMETHODIMP CAVIFile::CAVIFileImpl::AddStream(
  1220. PAVISTREAM pavi,
  1221. PAVISTREAM FAR *ppaviNew)
  1222. {
  1223. CAVIFile FAR * pf = m_pAVIFile;
  1224. CAVIStream FAR * paviNew;
  1225. int iStream = (int) pf->avihdr.dwStreams;
  1226. HRESULT hr;
  1227. IUnknown FAR * pUnk;
  1228. if ((pf->mode & (OF_WRITE | OF_READWRITE)) == 0)
  1229. return ResultFromScode(AVIERR_READONLY);
  1230. pfile->ps[iStream] = new FAR CAVIStream(NULL, &pUnk);
  1231. if (!pfile->ps[iStream])
  1232. return ResultFromScode(AVIERR_MEMORY);
  1233. paviNew = pf->ps[iStream];
  1234. paviNew->iStream = iStream;
  1235. paviNew->pfile = pf;
  1236. AVIStreamInfo(pavi, &paviNew->avistream, sizeof(paviNew->avistream));
  1237. paviNew->hshfile = pf->hshfile;
  1238. paviNew->m_AVIStream.AddRef();
  1239. paviNew->paviBase = pavi;
  1240. AVIStreamAddRef(pavi);
  1241. paviNew->cbFormat = AVIStreamFormatSize(pavi, 0);
  1242. paviNew->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, paviNew->cbFormat);
  1243. if (!paviNew->lpFormat) {
  1244. AVIStreamClose((PAVISTREAM) pf->ps[iStream]);
  1245. return ResultFromScode(AVIERR_MEMORY);
  1246. }
  1247. AVIStreamReadFormat(pavi, 0, paviNew->lpFormat, &paviNew->cbFormat);
  1248. pf->avihdr.dwStreams++;
  1249. AddRef();
  1250. if (paviNew->iStream == 0) {
  1251. pf->avihdr.dwMicroSecPerFrame =
  1252. muldiv32(1000000L,
  1253. paviNew->avistream.dwScale,
  1254. paviNew->avistream.dwRate);
  1255. }
  1256. *ppaviNew = (PAVISTREAM) paviNew;
  1257. return ResultFromScode(AVIERR_OK);
  1258. }
  1259. #endif
  1260. ///////////////////////////////////////////////////////////////////////////
  1261. ///////////////////////////////////////////////////////////////////////////
  1262. STDMETHODIMP CAVIFile::CAVIFileImpl::WriteData(
  1263. DWORD ckid,
  1264. LPVOID lpData,
  1265. LONG cbData)
  1266. {
  1267. CAVIFile FAR * pf = m_pAVIFile;
  1268. CLock tlock(m_pAVIFile);
  1269. // !!! Anything else we can check?
  1270. if (lpData == NULL || cbData == 0)
  1271. return ResultFromScode(AVIERR_BADPARAM);
  1272. if ((pf->mode & (OF_WRITE | OF_READWRITE)) == 0)
  1273. return ResultFromScode(AVIERR_READONLY);
  1274. pf->fDirty = TRUE;
  1275. return WriteExtra(&pf->extra, ckid, lpData, cbData);
  1276. }
  1277. ///////////////////////////////////////////////////////////////////////////
  1278. ///////////////////////////////////////////////////////////////////////////
  1279. STDMETHODIMP CAVIFile::CAVIFileImpl::ReadData(
  1280. DWORD ckid,
  1281. LPVOID lpData,
  1282. LONG FAR *lpcbData)
  1283. {
  1284. CAVIFile FAR * pf = m_pAVIFile;
  1285. CLock tlock(m_pAVIFile);
  1286. return ReadExtra(&pf->extra, ckid, lpData, lpcbData);
  1287. }
  1288. ///////////////////////////////////////////////////////////////////////////
  1289. ///////////////////////////////////////////////////////////////////////////
  1290. STDMETHODIMP CAVIFile::CAVIFileImpl::EndRecord()
  1291. {
  1292. CAVIFile FAR * pf = m_pAVIFile;
  1293. CLock tlock(m_pAVIFile);
  1294. if ((pf->mode & (OF_WRITE | OF_READWRITE)) == 0)
  1295. return ResultFromScode(AVIERR_READONLY);
  1296. pf->fDirty = TRUE;
  1297. pf->avihdr.dwFlags |= AVIF_ISINTERLEAVED;
  1298. if (pf->lWriteLoc == 0) {
  1299. pf->lWriteLoc = (pf->lHeaderSize + 1024 + 2047) & ~(2047);
  1300. // Leave room for start of first 'rec' chunk....
  1301. pf->lWriteLoc -= 3 * sizeof(DWORD);
  1302. pf->lDataListStart = pf->lWriteLoc - 3 * sizeof(DWORD);
  1303. DPF("Writing first chunk at position %lu\n", pf->lWriteLoc);
  1304. }
  1305. shfileSeek(pf->hshfile, pf->lWriteLoc, SEEK_SET);
  1306. if (pf->fInRecord) {
  1307. #ifndef NOPADDING
  1308. {
  1309. DWORD dwCurOffset;
  1310. DWORD dwPadNeeded;
  1311. MMCKINFO ck;
  1312. dwCurOffset = shfileSeek(pf->hshfile, 0, SEEK_CUR);
  1313. // want to start next record at 2K-12 byte boundary
  1314. dwCurOffset = (dwCurOffset + 12) % 2048;
  1315. if (dwCurOffset != 0) {
  1316. // we need to pad....
  1317. dwPadNeeded = 4096 - dwCurOffset - 8;
  1318. if (dwPadNeeded >= 2048)
  1319. dwPadNeeded -= 2048;
  1320. ck.ckid = mmioFOURCC('J','U','N','K');
  1321. ck.cksize = dwPadNeeded;
  1322. if (shfileCreateChunk(pf->hshfile, &ck, 0)) {
  1323. return ResultFromScode(AVIERR_FILEWRITE);
  1324. }
  1325. shfileZero(pf->hshfile, dwPadNeeded);
  1326. if (shfileAscend(pf->hshfile, &ck, 0))
  1327. return ResultFromScode(AVIERR_FILEWRITE);
  1328. }
  1329. }
  1330. #endif
  1331. if (shfileAscend(pf->hshfile, (MMCKINFO FAR *) &pf->ckRecord, 0))
  1332. return ResultFromScode(AVIERR_FILEWRITE);
  1333. IndexSetLength(pf->px, pf->lRecordIndex, pf->ckRecord.cksize);
  1334. //
  1335. // Keep the main suggested buffer size as big as the biggest
  1336. // record....
  1337. //
  1338. if (pf->ckRecord.cksize + 3 * sizeof(DWORD) >
  1339. pf->avihdr.dwSuggestedBufferSize)
  1340. pf->avihdr.dwSuggestedBufferSize = pf->ckRecord.cksize +
  1341. 3 * sizeof(DWORD);
  1342. }
  1343. /* Start the next 'rec' list */
  1344. pf->ckRecord.cksize = 0;
  1345. pf->ckRecord.fccType = listtypeAVIRECORD;
  1346. pf->fInRecord = TRUE;
  1347. if (shfileCreateChunk(pf->hshfile, (MMCKINFO FAR *) &pf->ckRecord, MMIO_CREATELIST)) {
  1348. return ResultFromScode(AVIERR_FILEWRITE);
  1349. }
  1350. pf->lWriteLoc = shfileSeek(pf->hshfile, 0, SEEK_CUR);
  1351. pf->lRecordIndex = pf->px->nIndex;
  1352. if (!AddToIndex(pf, pf->ckRecord.fccType, 0,
  1353. pf->ckRecord.dwDataOffset - 2 * sizeof(DWORD), AVIIF_LIST)) {
  1354. return ResultFromScode(AVIERR_MEMORY);
  1355. }
  1356. return ResultFromScode(AVIERR_OK);
  1357. }
  1358. ///////////////////////////////////////////////////////////////////////////
  1359. ///////////////////////////////////////////////////////////////////////////
  1360. STDMETHODIMP CAVIFile::CAVIFileImpl::Info(
  1361. AVIFILEINFOW FAR * pfi,
  1362. LONG lSize)
  1363. {
  1364. CAVIFile FAR * pf = m_pAVIFile;
  1365. if (pfi == NULL)
  1366. return ResultFromScode(AVIERR_BADPARAM);
  1367. if (lSize < sizeof(AVIFILEINFOW))
  1368. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  1369. CLock tlock(m_pAVIFile);
  1370. pfi->dwMaxBytesPerSec = pf->avihdr.dwMaxBytesPerSec;
  1371. pfi->dwFlags = (pf->avihdr.dwFlags & AVIF_ISINTERLEAVED);
  1372. pfi->dwCaps = AVIFILECAPS_CANREAD | AVIFILECAPS_CANWRITE;
  1373. pfi->dwStreams = pf->avihdr.dwStreams;
  1374. pfi->dwSuggestedBufferSize = pf->avihdr.dwSuggestedBufferSize;
  1375. pfi->dwWidth = pf->avihdr.dwWidth;
  1376. pfi->dwHeight = pf->avihdr.dwHeight;
  1377. pfi->dwScale = pf->avihdr.dwMicroSecPerFrame;
  1378. pfi->dwRate = 1000000L;
  1379. pfi->dwLength = pf->avihdr.dwTotalFrames;
  1380. pfi->dwEditCount = 0;
  1381. LoadUnicodeString(ghMod, IDS_AVIFILE, pfi->szFileType, NUMELMS(pfi->szFileType));
  1382. return AVIERR_OK;
  1383. }
  1384. ///////////////////////////////////////////////////////////////////////////
  1385. //
  1386. // AVIFileClose()
  1387. //
  1388. // close a AVIFile stream
  1389. //
  1390. ///////////////////////////////////////////////////////////////////////////
  1391. STDMETHODIMP_(ULONG) CAVIStream::CUnknownImpl::Release()
  1392. {
  1393. CAVIStream FAR * pavi = m_pAVIStream;
  1394. CLock tlock(pavi->pfile);
  1395. uUseCount--;
  1396. if (m_refs < 20) {
  1397. DPF2("Stream %p: Usage--=%lx\n", (DWORD_PTR) (LPVOID) this, m_refs - 1);
  1398. }
  1399. shfileRelease(pavi->hshfile);
  1400. if (!--m_refs) {
  1401. if (pavi->hshfile != pavi->pfile->hshfile) {
  1402. shfileClose(pavi->hshfile, 0);
  1403. pavi->hshfile = 0;
  1404. }
  1405. if (pavi->pb && pavi->pb != pavi->pfile->pb) {
  1406. EndBuffered(pavi->pb);
  1407. pavi->pb = 0;
  1408. }
  1409. if (pavi->psx) {
  1410. FreeStreamIndex(pavi->psx);
  1411. pavi->psx = NULL;
  1412. }
  1413. pavi->fInit = FALSE;
  1414. // this call can cause the AVIFile object to be deleted, and
  1415. // thus we must release the critical section first. There is no
  1416. // danger in this, as nothing unsafe can happen to us between
  1417. // releasing it here and getting it again when we enter
  1418. // the file Release() call.
  1419. tlock.Exit();
  1420. pavi->pfile->m_AVIFile.Release();
  1421. return 0;
  1422. }
  1423. return m_refs;
  1424. }
  1425. /* - - - - - - - - */
  1426. ///////////////////////////////////////////////////////////////////////////
  1427. ///////////////////////////////////////////////////////////////////////////
  1428. void CAVIStream::CAVIStreamImpl::ReadPalette(LONG lPos, LONG lPal, LPRGBQUAD prgb)
  1429. {
  1430. CAVIStream FAR * pavi = m_pAVIStream;
  1431. CLock tlock(pavi->pfile);
  1432. LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER) pavi->lpFormat;
  1433. LONG l;
  1434. int i,n;
  1435. static struct {
  1436. BYTE bFirstEntry; /* first entry to change */
  1437. BYTE bNumEntries; /* # entries to change (0 if 256) */
  1438. WORD wFlags; /* Mostly to preserve alignment... */
  1439. PALETTEENTRY peNew[256]; /* New color specifications */
  1440. } pc;
  1441. DPF("Reading palette: lPos = %ld, lPal = %ld\n", lPos, lPal);
  1442. if (lPal > lPos)
  1443. lPal = 0;
  1444. //
  1445. // get the palette colors in the initial format header
  1446. //
  1447. if (lPal <= 0) {
  1448. hmemcpy(prgb,(LPBYTE)lpbi+(int)lpbi->biSize, lpbi->biClrUsed * sizeof(RGBQUAD));
  1449. lPal = -1;
  1450. }
  1451. for (;;) {
  1452. //
  1453. // search index forward for next palette change
  1454. //
  1455. l = StreamFindSample(pavi->psx, lPal+1, FIND_FORMAT|FIND_NEXT);
  1456. if (l < 0 || l > lPos || l == lPal)
  1457. break;
  1458. lPal = l;
  1459. if (l <= (LONG) pavi->avistream.dwStart)
  1460. continue;
  1461. LONG off = StreamFindSample(pavi->psx, lPal, FIND_FORMAT|FIND_OFFSET);
  1462. LONG len = StreamFindSample(pavi->psx, lPal, FIND_FORMAT|FIND_LENGTH);
  1463. #ifdef DEBUG
  1464. DWORD adw[2];
  1465. shfileSeek(pavi->hshfile, off-8, SEEK_SET);
  1466. shfileRead(pavi->hshfile, (HPSTR)adw, sizeof(adw));
  1467. Assert(TWOCCFromFOURCC(adw[0]) == cktypePALchange);
  1468. Assert(adw[1] == (DWORD) len);
  1469. #endif
  1470. if (len > (LONG)(sizeof(AVIPALCHANGE) + (LONG)lpbi->biClrUsed * sizeof(PALETTEENTRY) * 2)) {
  1471. DPF("Palette chunk obviously too large!\n");
  1472. break;
  1473. }
  1474. //
  1475. // read palchange from file and apply it
  1476. //
  1477. shfileSeek(pavi->hshfile, off, SEEK_SET);
  1478. while (len >= (LONG)sizeof(AVIPALCHANGE)) {
  1479. if (shfileRead(pavi->hshfile, (HPSTR)&pc, sizeof(AVIPALCHANGE)) !=
  1480. sizeof(AVIPALCHANGE)) {
  1481. DPF("Error reading palette change\n");
  1482. break;
  1483. }
  1484. n = pc.bNumEntries == 0 ? 256 : (int)pc.bNumEntries;
  1485. if ((DWORD) n > lpbi->biClrUsed) {
  1486. DPF("%d colors in palette change, only %lu in movie!\n", n, lpbi->biClrUsed);
  1487. break;
  1488. }
  1489. if (pc.bFirstEntry + n > (int)lpbi->biClrUsed) {
  1490. DPF("%d colors in palette change, only %lu in movie!\n", n, lpbi->biClrUsed);
  1491. break;
  1492. }
  1493. if (shfileRead(pavi->hshfile,
  1494. (HPSTR)&pc.peNew,
  1495. n * sizeof(PALETTEENTRY)) !=
  1496. (LONG) (n * sizeof(PALETTEENTRY))) {
  1497. DPF("Error reading palette change entries\n");
  1498. break;
  1499. }
  1500. for (i=0; i<n; i++) {
  1501. pavi->argbq[pc.bFirstEntry+i].rgbRed = pc.peNew[i].peRed;
  1502. pavi->argbq[pc.bFirstEntry+i].rgbGreen = pc.peNew[i].peGreen;
  1503. pavi->argbq[pc.bFirstEntry+i].rgbBlue = pc.peNew[i].peBlue;
  1504. pavi->argbq[pc.bFirstEntry+i].rgbReserved = 0;
  1505. }
  1506. len -= n * sizeof(PALETTEENTRY) + sizeof(AVIPALCHANGE);
  1507. }
  1508. }
  1509. }
  1510. ///////////////////////////////////////////////////////////////////////////
  1511. ///////////////////////////////////////////////////////////////////////////
  1512. STDMETHODIMP CAVIStream::CAVIStreamImpl::ReadFormat(LONG lPos, LPVOID lpFormat, LONG FAR *lpcbFormat)
  1513. {
  1514. CAVIStream FAR * pavi = m_pAVIStream;
  1515. CLock tlock(pavi->pfile);
  1516. LONG lPal;
  1517. LPBITMAPINFOHEADER lpbi;
  1518. if (lpcbFormat == NULL)
  1519. return ResultFromScode(AVIERR_BADPARAM);
  1520. if (lpFormat == NULL || *lpcbFormat == 0) {
  1521. *lpcbFormat = pavi->cbFormat;
  1522. return AVIERR_OK;
  1523. }
  1524. if (pavi->avistream.dwFlags & AVISF_VIDEO_PALCHANGES) {
  1525. Assert(pavi->psx);
  1526. //
  1527. // now go find the nearest palette change
  1528. //
  1529. lPal = StreamFindSample(pavi->psx, lPos, FIND_FORMAT|FIND_PREV);
  1530. if (lPal < 0)
  1531. lPal = 0;
  1532. if (lPal != pavi->lPal) {
  1533. ReadPalette(lPal, pavi->lPal, pavi->argbq);
  1534. pavi->lPal = lPal;
  1535. }
  1536. lpbi = (LPBITMAPINFOHEADER) pavi->lpFormat;
  1537. hmemcpy(lpFormat, lpbi, min((LONG) lpbi->biSize, *lpcbFormat));
  1538. if (*lpcbFormat > (LONG) lpbi->biSize) {
  1539. hmemcpy((LPBYTE)lpFormat + (int)lpbi->biSize, pavi->argbq,
  1540. min(lpbi->biClrUsed * sizeof(RGBQUAD),
  1541. *lpcbFormat - lpbi->biSize));
  1542. }
  1543. }
  1544. else {
  1545. hmemcpy(lpFormat, pavi->lpFormat, min(*lpcbFormat, pavi->cbFormat));
  1546. }
  1547. if (*lpcbFormat < pavi->cbFormat) {
  1548. *lpcbFormat = pavi->cbFormat;
  1549. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  1550. }
  1551. *lpcbFormat = pavi->cbFormat;
  1552. return AVIERR_OK;
  1553. }
  1554. ///////////////////////////////////////////////////////////////////////////
  1555. ///////////////////////////////////////////////////////////////////////////
  1556. STDMETHODIMP CAVIStream::CAVIStreamImpl::Create(LPARAM lParam1, LPARAM lParam2)
  1557. {
  1558. return ResultFromScode(AVIERR_UNSUPPORTED);
  1559. }
  1560. ///////////////////////////////////////////////////////////////////////////
  1561. ///////////////////////////////////////////////////////////////////////////
  1562. STDMETHODIMP CAVIStream::CAVIStreamImpl::Info(AVISTREAMINFOW FAR * psi, LONG lSize)
  1563. {
  1564. CAVIStream FAR * pavi = m_pAVIStream;
  1565. CLock tlock(pavi->pfile);
  1566. if (psi == NULL)
  1567. return ResultFromScode(AVIERR_BADPARAM);
  1568. if (lSize < sizeof(pavi->avistream))
  1569. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  1570. hmemcpy(psi, &pavi->avistream, sizeof(pavi->avistream));
  1571. return AVIERR_OK;
  1572. }
  1573. ///////////////////////////////////////////////////////////////////////////
  1574. ///////////////////////////////////////////////////////////////////////////
  1575. STDMETHODIMP_(LONG) CAVIStream::CAVIStreamImpl::FindSample(LONG lPos, LONG lFlags)
  1576. {
  1577. CAVIStream FAR * pavi = m_pAVIStream;
  1578. CLock tlock(pavi->pfile);
  1579. if (pavi->paviBase) {
  1580. // If we haven't copied over the data yet, delegate.
  1581. return AVIStreamFindSample(pavi->paviBase, lPos, lFlags);
  1582. }
  1583. #ifdef _WIN32
  1584. if (!lPos && (lFlags & FIND_FROM_START)) {
  1585. lPos = pavi->avistream.dwStart;
  1586. } else
  1587. #endif
  1588. if (lPos < (LONG)pavi->avistream.dwStart)
  1589. return -1;
  1590. if (lPos >= (LONG)(pavi->avistream.dwStart + pavi->avistream.dwLength))
  1591. return -1;
  1592. lPos = StreamFindSample(pavi->psx, lPos, (UINT)lFlags);
  1593. return lPos < 0 ? -1 : lPos;
  1594. }
  1595. ///////////////////////////////////////////////////////////////////////////
  1596. ///////////////////////////////////////////////////////////////////////////
  1597. STDMETHODIMP CAVIStream::CAVIStreamImpl::Read(
  1598. LONG lStart,
  1599. LONG lSamples,
  1600. LPVOID lpBuffer,
  1601. LONG cbBuffer,
  1602. LONG FAR * plBytes,
  1603. LONG FAR * plSamples)
  1604. {
  1605. CAVIStream FAR * pavi = m_pAVIStream;
  1606. LONG lBytes;
  1607. CLock tlock(pavi->pfile);
  1608. if (pavi->paviBase) {
  1609. // If we haven't copied over the data yet, delegate.
  1610. return AVIStreamRead(pavi->paviBase, lStart, lSamples,
  1611. lpBuffer, cbBuffer, plBytes, plSamples);
  1612. }
  1613. Assert(pavi->psx);
  1614. // !!! What if start too big? Length too long?
  1615. if (lStart < (LONG) pavi->avistream.dwStart) {
  1616. DPF("Read before start!\n");
  1617. return ResultFromScode(AVIERR_BADPARAM);
  1618. }
  1619. // Handle one of the sillier aspects of AVI files:
  1620. // Certain RLE-encoded files have their first frames split
  1621. // up into lots of small pieces. This code puts all of those
  1622. // pieces back together again if necessary.
  1623. if ((lStart == (LONG) pavi->avistream.dwStart) &&
  1624. (pavi->avistream.fccType == streamtypeVIDEO) &&
  1625. (pavi->avistream.dwInitialFrames > 0)) {
  1626. LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER) pavi->lpFormat;
  1627. LPVOID lp;
  1628. lStart -= (LONG) pavi->avistream.dwInitialFrames;
  1629. lBytes = (DWORD)(WORD)DIBWIDTHBYTES(lpbi) * (DWORD)(WORD)lpbi->biHeight;
  1630. //
  1631. // a NULL buffer means return the size buffer needed to read
  1632. // the given sample.
  1633. //
  1634. if (lpBuffer == NULL || cbBuffer == 0) {
  1635. if (plBytes)
  1636. *plBytes = lBytes;
  1637. return AVIERR_OK;
  1638. }
  1639. if (cbBuffer < lBytes) {
  1640. if (plBytes)
  1641. *plBytes = lBytes;
  1642. DPF("ReadFirst: Buffer is %ld bytes, needed %ld\n", cbBuffer, lBytes);
  1643. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  1644. }
  1645. lp = GlobalAllocPtr(GMEM_MOVEABLE, lBytes);
  1646. if (!lp)
  1647. return ResultFromScode(AVIERR_MEMORY);
  1648. while (lStart <= (LONG)pavi->avistream.dwStart) {
  1649. if (StreamRead(pavi->psx, lStart, 1, lp, lBytes) < 0) {
  1650. GlobalFreePtr(lp);
  1651. return ResultFromScode(AVIERR_FILEREAD);
  1652. }
  1653. // We probably shouldn't assume RLE here....
  1654. DecodeRle(lpbi, (BYTE _huge *) lpBuffer, (BYTE _huge *) lp, lBytes);
  1655. lStart++;
  1656. }
  1657. GlobalFreePtr(lp);
  1658. goto done;
  1659. }
  1660. //
  1661. // do the read
  1662. //
  1663. lBytes = StreamRead(pavi->psx,lStart,lSamples,lpBuffer,cbBuffer);
  1664. //
  1665. // check for error
  1666. //
  1667. if (lBytes < 0) {
  1668. if (plBytes)
  1669. *plBytes = 0;
  1670. if (plSamples)
  1671. *plSamples = 0;
  1672. if (cbBuffer == 0)
  1673. return ResultFromScode(AVIERR_ERROR);
  1674. //
  1675. // the error may have been buffer too small, check this.
  1676. //
  1677. if (cbBuffer < pavi->psx->lSampleSize)
  1678. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  1679. lBytes = StreamFindSample(pavi->psx,lStart,FIND_PREV|FIND_LENGTH);
  1680. if (cbBuffer < lBytes) {
  1681. if (plBytes)
  1682. *plBytes = lBytes;
  1683. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  1684. }
  1685. else
  1686. return ResultFromScode(AVIERR_FILEREAD);
  1687. }
  1688. done:
  1689. if (plBytes)
  1690. *plBytes = lBytes;
  1691. if (plSamples) {
  1692. LONG lSampleSize = pavi->psx->lSampleSize;
  1693. if (lSampleSize)
  1694. *plSamples = lBytes / lSampleSize;
  1695. else
  1696. *plSamples = 1;
  1697. }
  1698. return AVIERR_OK;
  1699. }
  1700. /**************************************************************************
  1701. * @doc INTERNAL DRAWDIB
  1702. *
  1703. * @api BOOL | DibEq | This function compares two dibs.
  1704. *
  1705. * @parm LPBITMAPINFOHEADER lpbi1 | Pointer to one bitmap.
  1706. * this DIB is assumed to have the colors after the BITMAPINFOHEADER
  1707. *
  1708. * @parm LPBITMAPINFOHEADER | lpbi2 | Pointer to second bitmap.
  1709. * this DIB is assumed to have the colors after biSize bytes.
  1710. *
  1711. * @rdesc Returns TRUE if bitmaps are identical, FALSE otherwise.
  1712. *
  1713. **************************************************************************/
  1714. inline BOOL DibEq(LPBITMAPINFOHEADER lpbi1, LPBITMAPINFOHEADER lpbi2)
  1715. {
  1716. return
  1717. lpbi1->biCompression == lpbi2->biCompression &&
  1718. lpbi1->biSize == lpbi2->biSize &&
  1719. lpbi1->biWidth == lpbi2->biWidth &&
  1720. lpbi1->biHeight == lpbi2->biHeight &&
  1721. lpbi1->biBitCount == lpbi2->biBitCount;
  1722. }
  1723. ///////////////////////////////////////////////////////////////////////////
  1724. ///////////////////////////////////////////////////////////////////////////
  1725. STDMETHODIMP CAVIStream::CAVIStreamImpl::SetFormat(LONG lPos,LPVOID lpFormat,LONG cbFormat)
  1726. {
  1727. CAVIStream FAR * pavi = m_pAVIStream;
  1728. CLock tlock(pavi->pfile);
  1729. LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER) lpFormat;
  1730. int i;
  1731. RGBQUAD FAR * lprgb;
  1732. struct {
  1733. BYTE bFirstEntry; /* first entry to change */
  1734. BYTE bNumEntries; /* # entries to change (0 if 256) */
  1735. WORD wFlags; /* Mostly to preserve alignment... */
  1736. PALETTEENTRY pe[256];
  1737. } s;
  1738. //
  1739. // Make sure the stream isn't read-only
  1740. //
  1741. if ((pavi->pfile->mode & (OF_WRITE | OF_READWRITE)) == 0)
  1742. return ResultFromScode(AVIERR_READONLY);
  1743. if (pavi->lpFormat == NULL) {
  1744. // !!! If we are writing to an existing file, and not to a new file, we
  1745. // have a limitation where we cannot grow the size of the header.
  1746. // Check to see if the header will take up too much room!
  1747. if (pavi->pfile->lWriteLoc > 0) {
  1748. LONG lHeader = pavi->cbFormat +
  1749. pavi->pfile->lHeaderSize +
  1750. 2 * sizeof(DWORD);
  1751. if (lHeader > pavi->pfile->lDataListStart) {
  1752. DPF("Header will be too big with this format!\n");
  1753. return ResultFromScode(AVIERR_UNSUPPORTED);
  1754. }
  1755. }
  1756. pavi->pfile->lHeaderSize += cbFormat + 2 * sizeof(DWORD);
  1757. // This is a new stream, whose format hasn't been set.
  1758. pavi->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, cbFormat);
  1759. if (!pavi->lpFormat) {
  1760. return ResultFromScode(AVIERR_MEMORY);
  1761. }
  1762. hmemcpy(pavi->lpFormat, lpFormat, cbFormat);
  1763. pavi->cbFormat = cbFormat;
  1764. if (pavi->avistream.fccType == streamtypeVIDEO) {
  1765. if (ISRECTBOGUS(&pavi->avistream.rcFrame,
  1766. pavi->pfile->avihdr.dwWidth,
  1767. pavi->pfile->avihdr.dwHeight,
  1768. lpbi)) {
  1769. DPF("Resetting stream rectangle....\n");
  1770. SetRect(&pavi->avistream.rcFrame, 0, 0,
  1771. (int)lpbi->biWidth, (int)lpbi->biHeight);
  1772. }
  1773. if (lpbi->biClrUsed > 0) {
  1774. // Get the right colors, so that we can detect palette changes
  1775. hmemcpy(pavi->argbq,
  1776. (LPBYTE) lpbi + lpbi->biSize,
  1777. lpbi->biClrUsed * sizeof(RGBQUAD));
  1778. }
  1779. /* Make sure the width and height of the created file are right.... */
  1780. pavi->pfile->avihdr.dwWidth = max(pavi->pfile->avihdr.dwWidth,
  1781. (DWORD) pavi->avistream.rcFrame.right);
  1782. pavi->pfile->avihdr.dwHeight = max(pavi->pfile->avihdr.dwHeight,
  1783. (DWORD) pavi->avistream.rcFrame.bottom);
  1784. }
  1785. return ResultFromScode(AVIERR_OK);
  1786. }
  1787. //
  1788. // First, check if the format is actually different....
  1789. //
  1790. if (cbFormat == pavi->cbFormat &&
  1791. (_fmemcmp(pavi->lpFormat, lpFormat, (int) cbFormat) == 0))
  1792. return ResultFromScode(AVIERR_OK);
  1793. //
  1794. // We really only support format changes if they're palette changes...
  1795. //
  1796. if (pavi->avistream.fccType != streamtypeVIDEO) {
  1797. return ResultFromScode(AVIERR_UNSUPPORTED);
  1798. }
  1799. //
  1800. // Can only currently set the palette at the end of the file
  1801. //
  1802. if (lPos < (LONG) (pavi->avistream.dwStart + pavi->avistream.dwLength))
  1803. return ResultFromScode(AVIERR_UNSUPPORTED);
  1804. //
  1805. // We can only change the palette for things with palettes....
  1806. //
  1807. if (lpbi->biBitCount > 8 || lpbi->biClrUsed == 0)
  1808. return ResultFromScode(AVIERR_UNSUPPORTED);
  1809. //
  1810. // Be sure only the palette is changing, nothing else....
  1811. //
  1812. if (cbFormat != pavi->cbFormat)
  1813. return ResultFromScode(AVIERR_UNSUPPORTED);
  1814. if (!DibEq((LPBITMAPINFOHEADER) lpFormat,
  1815. (LPBITMAPINFOHEADER) pavi->lpFormat))
  1816. return ResultFromScode(AVIERR_UNSUPPORTED);
  1817. // !!! Need to do here:
  1818. // Get the correct palette for this point in the file, and check
  1819. // that the new palette is in fact different.
  1820. lprgb = (RGBQUAD FAR *) ((LPBYTE) lpbi + lpbi->biSize);
  1821. if (_fmemcmp(pavi->argbq, lprgb, (UINT) lpbi->biClrUsed * sizeof(RGBQUAD)) == 0)
  1822. return ResultFromScode(AVIERR_OK);
  1823. //
  1824. // Make the new format the current one....
  1825. //
  1826. hmemcpy(pavi->argbq, lprgb, lpbi->biClrUsed * sizeof(RGBQUAD));
  1827. pavi->lPal = lPos;
  1828. //
  1829. // And be sure the stream is marked as having changes...
  1830. //
  1831. pavi->avistream.dwFlags |= AVISF_VIDEO_PALCHANGES;
  1832. s.bFirstEntry = 0;
  1833. s.bNumEntries = (BYTE) lpbi->biClrUsed;
  1834. s.wFlags = 0;
  1835. for (i = 0; i < (int) lpbi->biClrUsed; i++, lprgb++) {
  1836. s.pe[i].peRed = lprgb->rgbRed;
  1837. s.pe[i].peGreen = lprgb->rgbGreen;
  1838. s.pe[i].peBlue = lprgb->rgbBlue;
  1839. }
  1840. // !!! Hack: use Write to write the palette change....
  1841. return Write(lPos,
  1842. 0,
  1843. &s,
  1844. sizeof(AVIPALCHANGE) + lpbi->biClrUsed * sizeof(PALETTEENTRY),
  1845. AVIIF_NOTIME, NULL, NULL);
  1846. }
  1847. ///////////////////////////////////////////////////////////////////////////
  1848. ///////////////////////////////////////////////////////////////////////////
  1849. STDMETHODIMP CAVIStream::CAVIStreamImpl::Write(LONG lStart,
  1850. LONG lSamples,
  1851. LPVOID lpData,
  1852. LONG cbData,
  1853. DWORD dwFlags,
  1854. LONG FAR *plSampWritten,
  1855. LONG FAR *plBytesWritten)
  1856. {
  1857. CAVIStream FAR * pavi = m_pAVIStream;
  1858. CLock tlock(pavi->pfile);
  1859. MMCKINFO ck;
  1860. WORD cktype;
  1861. HRESULT hr;
  1862. DWORD dwmsec;
  1863. // !!! Idea: if it's audio-like data, and everything else matches the
  1864. // last chunk written out, then merge the new data in with the old
  1865. // data, rather than making a new chunk....
  1866. if ((pavi->pfile->mode & (OF_WRITE | OF_READWRITE)) == 0)
  1867. return ResultFromScode(AVIERR_READONLY);
  1868. if (!pavi->lpFormat) {
  1869. // The format must be set before any write calls
  1870. // are made....
  1871. return ResultFromScode(E_UNEXPECTED);
  1872. }
  1873. if (pavi->avistream.fccType == streamtypeAUDIO)
  1874. cktype = aviTWOCC('w', 'b');
  1875. else if (pavi->avistream.fccType == streamtypeVIDEO) {
  1876. if (dwFlags & AVIIF_NOTIME)
  1877. cktype = aviTWOCC('p', 'c');
  1878. else {
  1879. LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER) pavi->lpFormat;
  1880. if ((dwFlags & AVIIF_KEYFRAME) ||
  1881. (lpbi->biCompression <= BI_RLE8 && cbData == (LONG) lpbi->biSizeImage))
  1882. cktype = aviTWOCC('d', 'b');
  1883. else
  1884. cktype = aviTWOCC('d', 'c');
  1885. // !!! 00dx ack!
  1886. }
  1887. } else {
  1888. cktype = aviTWOCC('d', 'c');
  1889. }
  1890. ck.ckid = MAKEAVICKID(cktype, pavi->iStream);
  1891. ck.cksize = cbData;
  1892. if (lStart < 0)
  1893. lStart = pavi->avistream.dwStart + pavi->avistream.dwLength;
  1894. if (lStart > (LONG) (pavi->avistream.dwStart + pavi->avistream.dwLength)) {
  1895. if (pavi->avistream.dwSampleSize == 0) {
  1896. // !!! hack--insert lots of blank index entries....
  1897. while (lStart > (LONG) (pavi->avistream.dwStart + pavi->avistream.dwLength)) {
  1898. #if 1
  1899. hr = Write(pavi->avistream.dwStart + pavi->avistream.dwLength,
  1900. 1,
  1901. NULL,
  1902. 0,
  1903. 0,
  1904. NULL,
  1905. NULL);
  1906. if (FAILED(hr))
  1907. return hr;
  1908. #else
  1909. if (!AddToIndex(pavi->pfile, ck.ckid, 0, 0, 0))
  1910. return ResultFromScode(AVIERR_MEMORY);
  1911. ++pavi->avistream.dwLength;
  1912. pavi->pfile->avihdr.dwFlags |= AVIF_MUSTUSEINDEX;
  1913. #endif
  1914. }
  1915. } else
  1916. return ResultFromScode(AVIERR_BADPARAM);
  1917. }
  1918. if (lStart < (LONG) (pavi->avistream.dwStart + pavi->avistream.dwLength))
  1919. return ResultFromScode(AVIERR_UNSUPPORTED);
  1920. pavi->pfile->fDirty = TRUE;
  1921. if (pavi->pfile->lWriteLoc == 0) {
  1922. pavi->pfile->lWriteLoc = (pavi->pfile->lHeaderSize + 1024 + 2047) & ~(2047);
  1923. pavi->pfile->lDataListStart = pavi->pfile->lWriteLoc - 3 * sizeof(DWORD);
  1924. DPF("Writing first chunk at position %lu\n", pavi->pfile->lWriteLoc);
  1925. }
  1926. #if 0
  1927. if ((lStart == (LONG) (pavi->avistream.dwStart + pavi->avistream.dwLength)) &&
  1928. (pavi->avistream.fccType == streamtypeAUDIO) &&
  1929. (pavi->pfile->lIndex > 0)) {
  1930. AVIINDEXENTRY idx = pavi->pfile->pIndex[pavi->pfile->lIndex - 1];
  1931. if ((idx.ckid == ckid) &&
  1932. (idx.dwChunkOffset +
  1933. 2 * sizeof(DWORD) +
  1934. idx.dwChunkLength == lWriteLoc)) {
  1935. // We could append to the previous chunk here....
  1936. }
  1937. }
  1938. #endif
  1939. #ifdef DONTWRITEZEROLENGTH
  1940. if (cbData == 0) {
  1941. ck.dwDataOffset = 0;
  1942. pavi->pfile->avihdr.dwFlags |= AVIF_MUSTUSEINDEX;
  1943. } else
  1944. #endif
  1945. {
  1946. shfileSeek(pavi->hshfile, pavi->pfile->lWriteLoc, SEEK_SET);
  1947. shfileCreateChunk(pavi->hshfile, &ck, 0);
  1948. if (cbData) {
  1949. if (shfileWrite(pavi->hshfile, (HPSTR) lpData, cbData) != cbData)
  1950. return ResultFromScode(AVIERR_FILEWRITE);
  1951. }
  1952. if (shfileAscend(pavi->hshfile, &ck, 0) != 0)
  1953. return ResultFromScode(AVIERR_FILEWRITE);
  1954. pavi->pfile->lWriteLoc = shfileSeek(pavi->hshfile, 0, SEEK_CUR);
  1955. }
  1956. if (!AddToIndex(pavi->pfile, ck.ckid, cbData,
  1957. ck.dwDataOffset - 2 * sizeof(DWORD), dwFlags))
  1958. return ResultFromScode(AVIERR_MEMORY);
  1959. //
  1960. // if we dont have a stream index now is a good time to make one.
  1961. //
  1962. if (pavi->psx == NULL) {
  1963. pavi->psx = MakeStreamIndex(pavi->pfile->px, pavi->iStream,
  1964. (LONG)pavi->avistream.dwStart - pavi->avistream.dwInitialFrames,
  1965. (LONG)pavi->avistream.dwSampleSize,
  1966. pavi->pfile->hshfile, shfileReadProc, NULL);
  1967. //!!! what about pavi->pb
  1968. if (!(dwFlags & AVIIF_NOTIME))
  1969. pavi->psx->lEnd -= lSamples; // correct for the decrement below
  1970. }
  1971. if (pavi->psx == NULL) {
  1972. DPF("CAVIStream::Write no stream index!\n");
  1973. return ResultFromScode(AVIERR_MEMORY);
  1974. }
  1975. if (!(dwFlags & AVIIF_NOTIME)) {
  1976. pavi->avistream.dwLength += lSamples;
  1977. if (pavi->psx)
  1978. pavi->psx->lEnd += lSamples;
  1979. }
  1980. if (cbData > (LONG) pavi->avistream.dwSuggestedBufferSize)
  1981. pavi->avistream.dwSuggestedBufferSize = cbData;
  1982. if (cbData > (LONG) pavi->pfile->avihdr.dwSuggestedBufferSize)
  1983. pavi->pfile->avihdr.dwSuggestedBufferSize = cbData;
  1984. // Recalculate the overall file length....
  1985. dwmsec = muldiv32(pavi->avistream.dwLength,
  1986. pavi->avistream.dwScale * 1000L,
  1987. pavi->avistream.dwRate);
  1988. pavi->pfile->avihdr.dwTotalFrames =
  1989. max(pavi->pfile->avihdr.dwTotalFrames,
  1990. (DWORD) muldiv32(dwmsec, 1000L,
  1991. pavi->pfile->avihdr.dwMicroSecPerFrame));
  1992. // !!! The above calculation could easily overflow.
  1993. // !!! NEEDS TO BE REORGANIZED!
  1994. if (plBytesWritten)
  1995. *plBytesWritten = cbData;
  1996. if (plSampWritten)
  1997. *plSampWritten = lSamples;
  1998. return ResultFromScode(AVIERR_OK);
  1999. }
  2000. ///////////////////////////////////////////////////////////////////////////
  2001. ///////////////////////////////////////////////////////////////////////////
  2002. STDMETHODIMP CAVIStream::CAVIStreamImpl::Delete(LONG lStart,LONG lSamples)
  2003. {
  2004. CAVIStream FAR * pavi = m_pAVIStream;
  2005. CLock tlock(pavi->pfile);
  2006. if ((pavi->pfile->mode & (OF_WRITE | OF_READWRITE)) == 0)
  2007. return ResultFromScode(AVIERR_READONLY);
  2008. // go through and kill things from the index?
  2009. // !!! what about keyframe boundaries?
  2010. return ResultFromScode(AVIERR_UNSUPPORTED);
  2011. }
  2012. ///////////////////////////////////////////////////////////////////////////
  2013. ///////////////////////////////////////////////////////////////////////////
  2014. STDMETHODIMP CAVIStream::CAVIStreamImpl::ReadData(DWORD ckid, LPVOID lp, LONG FAR *lpcb)
  2015. {
  2016. CAVIStream FAR * pavi = m_pAVIStream;
  2017. CLock tlock(pavi->pfile);
  2018. return ReadExtra(&pavi->extra, ckid, lp, lpcb);
  2019. }
  2020. ///////////////////////////////////////////////////////////////////////////
  2021. ///////////////////////////////////////////////////////////////////////////
  2022. STDMETHODIMP CAVIStream::CAVIStreamImpl::WriteData(DWORD ckid, LPVOID lp, LONG cb)
  2023. {
  2024. CAVIStream FAR * pavi = m_pAVIStream;
  2025. CLock tlock(pavi->pfile);
  2026. DPF("WriteData asked to write %ld bytes\n", cb);
  2027. if ((pavi->pfile->mode & (OF_WRITE | OF_READWRITE)) == 0)
  2028. return ResultFromScode(AVIERR_READONLY);
  2029. // !!! If we are writing to an existing file, and not to a new file, we have
  2030. // a limitation where we cannot grow the size of the header.
  2031. // Check to see if the header will take up too much room.
  2032. if (pavi->pfile->lWriteLoc > 0) {
  2033. LONG lHeader = cb + pavi->pfile->lHeaderSize + 2 * sizeof(DWORD);
  2034. if (lHeader > pavi->pfile->lDataListStart) {
  2035. DPF("Header will be too big with this extra data!\n");
  2036. return ResultFromScode(AVIERR_UNSUPPORTED);
  2037. }
  2038. }
  2039. pavi->pfile->lHeaderSize += cb + 3 * sizeof(DWORD);
  2040. pavi->pfile->fDirty = TRUE;
  2041. return WriteExtra(&pavi->extra, ckid, lp, cb);
  2042. }
  2043. ///////////////////////////////////////////////////////////////////////////
  2044. ///////////////////////////////////////////////////////////////////////////
  2045. #if 0
  2046. STDMETHODIMP CAVIStream::CAVIStreamImpl::Clone(PAVISTREAM FAR * ppaviNew)
  2047. {
  2048. CAVIStream FAR * pavi = m_pAVIStream;
  2049. return ResultFromScode(AVIERR_UNSUPPORTED);
  2050. }
  2051. #endif
  2052. STDMETHODIMP CAVIStream::CStreamingImpl::Begin(LONG lStart,
  2053. LONG lEnd,
  2054. LONG lRate)
  2055. {
  2056. CAVIStream FAR * pavi = m_pAVIStream;
  2057. CLock tlock(pavi->pfile);
  2058. #ifdef USE_DIRECTIO
  2059. if (shfileIsDirect(pavi->hshfile)) {
  2060. shfileStreamStart(pavi->hshfile);
  2061. } else
  2062. #endif
  2063. if (pavi->pb)
  2064. BeginBufferedStreaming(pavi->pb, lRate > 0);
  2065. return ResultFromScode(AVIERR_OK);
  2066. }
  2067. STDMETHODIMP CAVIStream::CStreamingImpl::End()
  2068. {
  2069. CAVIStream FAR * pavi = m_pAVIStream;
  2070. CLock tlock(pavi->pfile);
  2071. #ifdef USE_DIRECTIO
  2072. if (shfileIsDirect(pavi->hshfile)) {
  2073. shfileStreamStop(pavi->hshfile);
  2074. } else
  2075. #endif
  2076. if (pavi->pb)
  2077. EndBufferedStreaming(pavi->pb);
  2078. return ResultFromScode(AVIERR_OK);
  2079. }
  2080. ///////////////////////////////////////////////////////////////////////////
  2081. ///////////////////////////////////////////////////////////////////////////
  2082. static
  2083. BOOL AddToIndex(CAVIFile FAR * pfile, DWORD ckid, DWORD cksize, LONG off, DWORD dwFlags)
  2084. {
  2085. PAVIINDEX px;
  2086. AVIINDEXENTRY idx;
  2087. idx.ckid = ckid;
  2088. idx.dwChunkOffset = off;
  2089. idx.dwChunkLength = cksize;
  2090. idx.dwFlags = dwFlags;
  2091. px = IndexAddFileIndex(pfile->px, &idx, 1, 0, FALSE);
  2092. if (px == NULL)
  2093. return FALSE;
  2094. //
  2095. // GlobalReAlloc may have moved our pointer, we need to patch all
  2096. // places we use it!
  2097. //
  2098. if (px != pfile->px) {
  2099. DPF("Index pointer has changed!\n");
  2100. pfile->px = px;
  2101. for (int i=0; i<(int)pfile->avihdr.dwStreams; i++) {
  2102. CAVIStream FAR *ps = pfile->ps[i];
  2103. if (ps->psx)
  2104. ps->psx->px = px;
  2105. }
  2106. if (pfile->pb)
  2107. pfile->pb->px = px;
  2108. }
  2109. return TRUE;
  2110. }
  2111. #ifdef _WIN32
  2112. STDMETHODIMP CAVIStream::CAVIStreamImpl::SetInfo(AVISTREAMINFOW FAR *lpInfo, LONG cbInfo)
  2113. {
  2114. CAVIStream FAR * pavi = m_pAVIStream;
  2115. CLock tlock(pavi->pfile);
  2116. if ((pavi->pfile->mode & (OF_WRITE | OF_READWRITE)) == 0)
  2117. return ResultFromScode(AVIERR_READONLY);
  2118. if ((cbInfo < sizeof(AVISTREAMINFOW)) ||
  2119. (IsBadReadPtr(lpInfo, sizeof(AVISTREAMINFOW))))
  2120. return ResultFromScode(AVIERR_BADPARAM);
  2121. // Things we don't copy:
  2122. // fccType
  2123. // fccHandler
  2124. // dwFlags
  2125. // dwCaps
  2126. // dwLength
  2127. // dwInitialFrames
  2128. // dwSuggestedBufferSize
  2129. // dwSampleSize
  2130. // dwEditCount
  2131. // dwFormatChangeCount
  2132. pavi->avistream.wPriority = lpInfo->wPriority;
  2133. pavi->avistream.wLanguage = lpInfo->wLanguage;
  2134. pavi->avistream.dwScale = lpInfo->dwScale;
  2135. pavi->avistream.dwRate = lpInfo->dwRate;
  2136. pavi->avistream.dwStart = lpInfo->dwStart; // !!! ???
  2137. pavi->avistream.dwQuality = lpInfo->dwQuality;
  2138. pavi->avistream.rcFrame = lpInfo->rcFrame;
  2139. if (lpInfo->szName[0])
  2140. _fmemcpy(pavi->avistream.szName, lpInfo->szName, sizeof(pavi->avistream.szName));
  2141. pavi->pfile->fDirty = TRUE;
  2142. return NOERROR;
  2143. }
  2144. STDMETHODIMP CAVIFile::CAVIFileImpl::DeleteStream(DWORD fccType, LONG lParam)
  2145. {
  2146. CAVIFile FAR * pfile = m_pAVIFile;
  2147. CAVIStream FAR *pavi;
  2148. int iStreamCur;
  2149. int iStreamWant;
  2150. int iStream;
  2151. // thread locking
  2152. CLock tlock(pfile);
  2153. iStreamWant = (int)lParam;
  2154. if (iStreamWant < 0 || iStreamWant >= (int)pfile->avihdr.dwStreams)
  2155. return ResultFromScode(AVIERR_NODATA);
  2156. /* Allocate stream data stuff, read streams */
  2157. for (iStreamCur = -1, iStream = 0;
  2158. iStream < (int)pfile->avihdr.dwStreams;
  2159. iStream++) {
  2160. if (fccType == 0 || pfile->ps[iStream]->avistream.fccType == fccType)
  2161. iStreamCur++;
  2162. if (iStreamCur == iStreamWant)
  2163. break;
  2164. }
  2165. if (iStreamCur != iStreamWant)
  2166. return ResultFromScode(AVIERR_NODATA);
  2167. pavi = pfile->ps[iStream];
  2168. // Is somebody using this stream?
  2169. if (pavi->fInit)
  2170. return ResultFromScode(AVIERR_UNSUPPORTED);
  2171. pfile->avihdr.dwStreams++;
  2172. pfile->lHeaderSize -= sizeof(AVIStreamHeader) + 8 * sizeof(DWORD) +
  2173. lstrlenW(pavi->avistream.szName);
  2174. while (iStream < (int) pfile->avihdr.dwStreams) {
  2175. pfile->ps[iStream] = pfile->ps[iStream + 1];
  2176. iStream++;
  2177. }
  2178. delete pavi;
  2179. return ResultFromScode(AVIERR_UNSUPPORTED);
  2180. }
  2181. #else
  2182. ///////////////////////////////////////////////////////////////////////////
  2183. ///////////////////////////////////////////////////////////////////////////
  2184. STDMETHODIMP CAVIFile::CAVIFileImpl::Reserved1(void)
  2185. {
  2186. return ResultFromScode(AVIERR_UNSUPPORTED);
  2187. }
  2188. ///////////////////////////////////////////////////////////////////////////
  2189. ///////////////////////////////////////////////////////////////////////////
  2190. STDMETHODIMP CAVIFile::CAVIFileImpl::Reserved2(void)
  2191. {
  2192. return ResultFromScode(AVIERR_UNSUPPORTED);
  2193. }
  2194. ///////////////////////////////////////////////////////////////////////////
  2195. ///////////////////////////////////////////////////////////////////////////
  2196. STDMETHODIMP CAVIFile::CAVIFileImpl::Reserved3(void)
  2197. {
  2198. return ResultFromScode(AVIERR_UNSUPPORTED);
  2199. }
  2200. ///////////////////////////////////////////////////////////////////////////
  2201. ///////////////////////////////////////////////////////////////////////////
  2202. STDMETHODIMP CAVIFile::CAVIFileImpl::Reserved4(void)
  2203. {
  2204. return ResultFromScode(AVIERR_UNSUPPORTED);
  2205. }
  2206. ///////////////////////////////////////////////////////////////////////////
  2207. ///////////////////////////////////////////////////////////////////////////
  2208. STDMETHODIMP CAVIFile::CAVIFileImpl::Reserved5(void)
  2209. {
  2210. return ResultFromScode(AVIERR_UNSUPPORTED);
  2211. }
  2212. ///////////////////////////////////////////////////////////////////////////
  2213. ///////////////////////////////////////////////////////////////////////////
  2214. STDMETHODIMP CAVIStream::CAVIStreamImpl::Reserved1(void)
  2215. {
  2216. return ResultFromScode(AVIERR_UNSUPPORTED);
  2217. }
  2218. ///////////////////////////////////////////////////////////////////////////
  2219. ///////////////////////////////////////////////////////////////////////////
  2220. STDMETHODIMP CAVIStream::CAVIStreamImpl::Reserved2(void)
  2221. {
  2222. return ResultFromScode(AVIERR_UNSUPPORTED);
  2223. }
  2224. ///////////////////////////////////////////////////////////////////////////
  2225. ///////////////////////////////////////////////////////////////////////////
  2226. STDMETHODIMP CAVIStream::CAVIStreamImpl::Reserved3(void)
  2227. {
  2228. return ResultFromScode(AVIERR_UNSUPPORTED);
  2229. }
  2230. ///////////////////////////////////////////////////////////////////////////
  2231. ///////////////////////////////////////////////////////////////////////////
  2232. STDMETHODIMP CAVIStream::CAVIStreamImpl::Reserved4(void)
  2233. {
  2234. return ResultFromScode(AVIERR_UNSUPPORTED);
  2235. }
  2236. ///////////////////////////////////////////////////////////////////////////
  2237. ///////////////////////////////////////////////////////////////////////////
  2238. STDMETHODIMP CAVIStream::CAVIStreamImpl::Reserved5(void)
  2239. {
  2240. return ResultFromScode(AVIERR_UNSUPPORTED);
  2241. }
  2242. #endif
  2243. #ifdef CUSTOMMARSHAL
  2244. CAVIFile::CMarshalImpl::CMarshalImpl(
  2245. CAVIFile FAR* pAVIFile)
  2246. {
  2247. m_pAVIFile = pAVIFile;
  2248. }
  2249. STDMETHODIMP CAVIFile::CMarshalImpl::QueryInterface(
  2250. const IID FAR& iid,
  2251. void FAR* FAR* ppv)
  2252. {
  2253. return m_pAVIFile->m_pUnknownOuter->QueryInterface(iid, ppv);
  2254. }
  2255. /* - - - - - - - - */
  2256. STDMETHODIMP_(ULONG) CAVIFile::CMarshalImpl::AddRef()
  2257. {
  2258. return m_pAVIFile->m_pUnknownOuter->AddRef();
  2259. }
  2260. /* - - - - - - - - */
  2261. STDMETHODIMP_(ULONG) CAVIFile::CMarshalImpl::Release()
  2262. {
  2263. return m_pAVIFile->m_pUnknownOuter->Release();
  2264. }
  2265. /* - - - - - - - - */
  2266. // *** IMarshal methods ***
  2267. STDMETHODIMP CAVIFile::CMarshalImpl::GetUnmarshalClass (THIS_ REFIID riid, LPVOID pv,
  2268. DWORD dwDestContext, LPVOID pvDestContext,
  2269. DWORD mshlflags, LPCLSID pCid)
  2270. {
  2271. HRESULT hr = NOERROR;
  2272. IUnknown FAR * pUnk = &m_pAVIFile->m_Unknown;
  2273. DPF("(F) UnMarshalClass called (context = %lx)\n", dwDestContext);
  2274. if (dwDestContext != MSHCTX_LOCAL) {
  2275. LPMARSHAL pMarshal;
  2276. DPF("Marshal context is %lu: delegating...\n", dwDestContext);
  2277. hr = CoGetStandardMarshal(riid, NULL,
  2278. dwDestContext, pvDestContext,
  2279. mshlflags, &pMarshal);
  2280. if (hr != NOERROR)
  2281. return hr;
  2282. hr = pMarshal->GetUnmarshalClass(riid, pv,
  2283. dwDestContext, pvDestContext,
  2284. mshlflags, pCid);
  2285. pMarshal->Release();
  2286. return hr;
  2287. }
  2288. *pCid = CLSID_AVISimpleUnMarshal;
  2289. return hr;
  2290. }
  2291. STDMETHODIMP CAVIFile::CMarshalImpl::GetMarshalSizeMax (THIS_ REFIID riid, LPVOID pv,
  2292. DWORD dwDestContext, LPVOID pvDestContext,
  2293. DWORD mshlflags, LPDWORD pSize)
  2294. {
  2295. HRESULT hr = NOERROR;
  2296. IUnknown FAR * pUnk = &m_pAVIFile->m_Unknown;
  2297. if (dwDestContext != MSHCTX_LOCAL) {
  2298. LPMARSHAL pMarshal;
  2299. hr = CoGetStandardMarshal(riid, NULL, dwDestContext, pvDestContext,
  2300. mshlflags, &pMarshal);
  2301. if (hr != NOERROR)
  2302. return hr;
  2303. hr = pMarshal->GetMarshalSizeMax(riid, pv,
  2304. dwDestContext, pvDestContext,
  2305. mshlflags, pSize);
  2306. pMarshal->Release();
  2307. return hr;
  2308. }
  2309. *pSize = sizeof(pUnk);
  2310. return hr;
  2311. }
  2312. STDMETHODIMP CAVIFile::CMarshalImpl::MarshalInterface (THIS_ LPSTREAM pStm, REFIID riid,
  2313. LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
  2314. DWORD mshlflags)
  2315. {
  2316. HRESULT hr = NOERROR;
  2317. IUnknown FAR * pUnk = &m_pAVIFile->m_Unknown;
  2318. DPF("MarshalInterface (F) called\n");
  2319. if (dwDestContext != MSHCTX_LOCAL) {
  2320. LPMARSHAL pMarshal;
  2321. DPF("Marshal context is %lu: delegating...\n", dwDestContext);
  2322. hr = CoGetStandardMarshal(riid, NULL,
  2323. dwDestContext, pvDestContext,
  2324. mshlflags, &pMarshal);
  2325. if (hr != NOERROR)
  2326. return hr;
  2327. hr = pMarshal->MarshalInterface(pStm, riid, pv,
  2328. dwDestContext, pvDestContext,
  2329. mshlflags);
  2330. pMarshal->Release();
  2331. return hr;
  2332. }
  2333. if ((riid != IID_IAVIStream && riid != IID_IAVIFile && riid != IID_IUnknown))
  2334. return ResultFromScode(E_INVALIDARG);
  2335. if ((hr = pStm->Write(&pUnk, sizeof(pUnk), NULL)) == NOERROR)
  2336. AddRef();
  2337. DPF("Returns %lx\n", (DWORD) (LPVOID) hr);
  2338. return hr;
  2339. }
  2340. STDMETHODIMP CAVIFile::CMarshalImpl::UnmarshalInterface (THIS_ LPSTREAM pStm, REFIID riid,
  2341. LPVOID FAR* ppv)
  2342. {
  2343. HRESULT hr = ResultFromScode(E_FAIL);
  2344. DPF("(F) UnMarshalInterface called!!!\n");
  2345. return hr;
  2346. }
  2347. STDMETHODIMP CAVIFile::CMarshalImpl::ReleaseMarshalData (THIS_ LPSTREAM pStm)
  2348. {
  2349. HRESULT hr = NOERROR;
  2350. IUnknown FAR * pUnk;
  2351. hr = pStm->Read(&pUnk,sizeof(pUnk),NULL);
  2352. DPF("(F) ReleaseMarshalData\n");
  2353. if (hr == NOERROR)
  2354. pUnk->Release();
  2355. return hr;
  2356. }
  2357. STDMETHODIMP CAVIFile::CMarshalImpl::DisconnectObject (THIS_ DWORD dwReserved)
  2358. {
  2359. HRESULT hr = NOERROR;
  2360. return hr;
  2361. }
  2362. CAVIStream::CMarshalImpl::CMarshalImpl(
  2363. CAVIStream FAR* pAVIStream)
  2364. {
  2365. m_pAVIStream = pAVIStream;
  2366. }
  2367. STDMETHODIMP CAVIStream::CMarshalImpl::QueryInterface(
  2368. const IID FAR& iid,
  2369. void FAR* FAR* ppv)
  2370. {
  2371. return m_pAVIStream->m_pUnknownOuter->QueryInterface(iid, ppv);
  2372. }
  2373. /* - - - - - - - - */
  2374. STDMETHODIMP_(ULONG) CAVIStream::CMarshalImpl::AddRef()
  2375. {
  2376. return m_pAVIStream->m_pUnknownOuter->AddRef();
  2377. }
  2378. /* - - - - - - - - */
  2379. STDMETHODIMP_(ULONG) CAVIStream::CMarshalImpl::Release()
  2380. {
  2381. return m_pAVIStream->m_pUnknownOuter->Release();
  2382. }
  2383. /* - - - - - - - - */
  2384. // *** IMarshal methods ***
  2385. STDMETHODIMP CAVIStream::CMarshalImpl::GetUnmarshalClass (THIS_ REFIID riid, LPVOID pv,
  2386. DWORD dwDestContext, LPVOID pvDestContext,
  2387. DWORD mshlflags, LPCLSID pCid)
  2388. {
  2389. HRESULT hr = NOERROR;
  2390. IUnknown FAR * pUnk = &m_pAVIStream->m_Unknown;
  2391. DPF("(S) UnMarshalClass called (context = %lx)\n", dwDestContext);
  2392. *pCid = CLSID_AVISimpleUnMarshal;
  2393. return hr;
  2394. }
  2395. STDMETHODIMP CAVIStream::CMarshalImpl::GetMarshalSizeMax (THIS_ REFIID riid, LPVOID pv,
  2396. DWORD dwDestContext, LPVOID pvDestContext,
  2397. DWORD mshlflags, LPDWORD pSize)
  2398. {
  2399. HRESULT hr = NOERROR;
  2400. IUnknown FAR * pUnk = &m_pAVIStream->m_Unknown;
  2401. *pSize = sizeof(pUnk);
  2402. return hr;
  2403. }
  2404. STDMETHODIMP CAVIStream::CMarshalImpl::MarshalInterface (THIS_ LPSTREAM pStm, REFIID riid,
  2405. LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
  2406. DWORD mshlflags)
  2407. {
  2408. HRESULT hr = NOERROR;
  2409. IUnknown FAR * pUnk = &m_pAVIStream->m_Unknown;
  2410. DPF("MarshalInterface (S) called\n");
  2411. if ((riid != IID_IAVIStream && riid != IID_IAVIStream && riid != IID_IUnknown))
  2412. return ResultFromScode(E_INVALIDARG);
  2413. if ((hr = pStm->Write(&pUnk, sizeof(pUnk), NULL)) == NOERROR)
  2414. AddRef();
  2415. DPF("Returns %lx\n", (DWORD) (LPVOID) hr);
  2416. return hr;
  2417. }
  2418. STDMETHODIMP CAVIStream::CMarshalImpl::UnmarshalInterface (THIS_ LPSTREAM pStm, REFIID riid,
  2419. LPVOID FAR* ppv)
  2420. {
  2421. HRESULT hr = ResultFromScode(E_FAIL);
  2422. DPF("(S) UnMarshalInterface called!!!\n");
  2423. return hr;
  2424. }
  2425. STDMETHODIMP CAVIStream::CMarshalImpl::ReleaseMarshalData (THIS_ LPSTREAM pStm)
  2426. {
  2427. HRESULT hr = NOERROR;
  2428. IUnknown FAR * pUnk;
  2429. hr = pStm->Read(&pUnk,sizeof(pUnk),NULL);
  2430. DPF("(S) ReleaseMarshalData\n");
  2431. if (hr == NOERROR)
  2432. pUnk->Release();
  2433. return hr;
  2434. }
  2435. STDMETHODIMP CAVIStream::CMarshalImpl::DisconnectObject (THIS_ DWORD dwReserved)
  2436. {
  2437. HRESULT hr = NOERROR;
  2438. return hr;
  2439. }
  2440. #endif // CUSTOMMARSHAL only
  2441. /***************************************************************************
  2442. DecodeRle - 'C' version
  2443. Play back a RLE buffer into a DIB buffer
  2444. returns
  2445. none
  2446. ***************************************************************************/
  2447. void DecodeRle(LPBITMAPINFOHEADER lpbi, BYTE _huge *pb, BYTE _huge *prle, DWORD dwInSize)
  2448. {
  2449. BYTE cnt;
  2450. BYTE b;
  2451. WORD x;
  2452. WORD dx,dy;
  2453. DWORD wWidthBytes;
  2454. DWORD dwOutSize;
  2455. DWORD dwJump;
  2456. #define RLE_ESCAPE 0
  2457. #define RLE_EOL 0
  2458. #define RLE_EOF 1
  2459. #define RLE_JMP 2
  2460. #define RLE_RUN 3
  2461. #if 0
  2462. #ifndef _WIN32
  2463. //
  2464. // this uses ASM code found in RLEA.ASM
  2465. //
  2466. if (!(WinFlags & WF_CPU286))
  2467. DecodeRle386(lpbi, pb, prle);
  2468. else if (lpbi->biSizeImage < 65536l)
  2469. DecodeRle286(lpbi, pb, prle);
  2470. else
  2471. #endif
  2472. #endif
  2473. #define EatOutput(_x_) \
  2474. { \
  2475. if (dwOutSize < (_x_)) { \
  2476. return; \
  2477. } \
  2478. dwOutSize -= (_x_); \
  2479. }
  2480. #define EatInput(_x_) \
  2481. { \
  2482. if (dwInSize < (_x_)) { \
  2483. return; \
  2484. } \
  2485. dwInSize -= (_x_); \
  2486. }
  2487. if (lpbi->biHeight <= 0) {
  2488. return;
  2489. }
  2490. {
  2491. wWidthBytes = (WORD)lpbi->biWidth+3 & ~3;
  2492. dwOutSize = wWidthBytes * (DWORD)lpbi->biHeight;
  2493. x = 0;
  2494. for(;;)
  2495. {
  2496. EatInput(2);
  2497. cnt = *prle++;
  2498. b = *prle++;
  2499. if (cnt == RLE_ESCAPE)
  2500. {
  2501. switch (b)
  2502. {
  2503. case RLE_EOF:
  2504. return;
  2505. case RLE_EOL:
  2506. EatOutput(wWidthBytes - x);
  2507. pb += wWidthBytes - x;
  2508. x = 0;
  2509. break;
  2510. case RLE_JMP:
  2511. EatInput(2);
  2512. dx = (WORD)*prle++;
  2513. dy = (WORD)*prle++;
  2514. dwJump = (DWORD)wWidthBytes * dy + dx;
  2515. EatOutput(dwJump);
  2516. pb += dwJump;
  2517. x += dx;
  2518. break;
  2519. default:
  2520. cnt = b;
  2521. EatOutput(cnt);
  2522. EatInput(cnt);
  2523. x += cnt;
  2524. while (cnt-- > 0)
  2525. *pb++ = *prle++;
  2526. if (b & 1) {
  2527. EatInput(1);
  2528. prle++;
  2529. }
  2530. break;
  2531. }
  2532. }
  2533. else
  2534. {
  2535. x += cnt;
  2536. EatOutput(cnt);
  2537. while (cnt-- > 0)
  2538. *pb++ = b;
  2539. }
  2540. }
  2541. }
  2542. }
  2543. CAVIFile::CPersistStorageImpl::CPersistStorageImpl(
  2544. CAVIFile FAR* pAVIFile)
  2545. {
  2546. m_pAVIFile = pAVIFile;
  2547. }
  2548. STDMETHODIMP CAVIFile::CPersistStorageImpl::QueryInterface(
  2549. const IID FAR& iid,
  2550. void FAR* FAR* ppv)
  2551. {
  2552. return m_pAVIFile->m_pUnknownOuter->QueryInterface(iid, ppv);
  2553. }
  2554. /* - - - - - - - - */
  2555. STDMETHODIMP_(ULONG) CAVIFile::CPersistStorageImpl::AddRef()
  2556. {
  2557. return m_pAVIFile->m_pUnknownOuter->AddRef();
  2558. }
  2559. /* - - - - - - - - */
  2560. STDMETHODIMP_(ULONG) CAVIFile::CPersistStorageImpl::Release()
  2561. {
  2562. return m_pAVIFile->m_pUnknownOuter->Release();
  2563. }
  2564. /* - - - - - - - - */
  2565. // *** IPersist methods ***
  2566. STDMETHODIMP CAVIFile::CPersistStorageImpl::GetClassID (LPCLSID lpClassID)
  2567. {
  2568. CAVIFile FAR * pfile = m_pAVIFile;
  2569. return NOERROR;
  2570. }
  2571. // *** IPersistStorage methods ***
  2572. STDMETHODIMP CAVIFile::CPersistStorageImpl::IsDirty ()
  2573. {
  2574. CAVIFile FAR * pfile = m_pAVIFile;
  2575. if (pfile->fDirty)
  2576. return NOERROR;
  2577. else
  2578. return ResultFromScode(S_FALSE);
  2579. }
  2580. STDMETHODIMP CAVIFile::CPersistStorageImpl::InitNew (LPSTORAGE pStg)
  2581. {
  2582. CAVIFile FAR * pfile = m_pAVIFile;
  2583. return NOERROR;
  2584. }
  2585. STDMETHODIMP CAVIFile::CPersistStorageImpl::Load (LPSTORAGE pStg)
  2586. {
  2587. CAVIFile FAR * pfile = m_pAVIFile;
  2588. return NOERROR;
  2589. }
  2590. STDMETHODIMP CAVIFile::CPersistStorageImpl::Save (LPSTORAGE pStgSave, BOOL fSameAsLoad)
  2591. {
  2592. CAVIFile FAR * pfile = m_pAVIFile;
  2593. return NOERROR;
  2594. }
  2595. STDMETHODIMP CAVIFile::CPersistStorageImpl::SaveCompleted (LPSTORAGE pStgNew)
  2596. {
  2597. CAVIFile FAR * pfile = m_pAVIFile;
  2598. return NOERROR;
  2599. }
  2600. STDMETHODIMP CAVIFile::CPersistStorageImpl::HandsOffStorage ()
  2601. {
  2602. CAVIFile FAR * pfile = m_pAVIFile;
  2603. return NOERROR;
  2604. }
  2605. CAVIFile::CPersistFileImpl::CPersistFileImpl(
  2606. CAVIFile FAR* pAVIFile)
  2607. {
  2608. m_pAVIFile = pAVIFile;
  2609. }
  2610. STDMETHODIMP CAVIFile::CPersistFileImpl::QueryInterface(
  2611. const IID FAR& iid,
  2612. void FAR* FAR* ppv)
  2613. {
  2614. return m_pAVIFile->m_pUnknownOuter->QueryInterface(iid, ppv);
  2615. }
  2616. /* - - - - - - - - */
  2617. STDMETHODIMP_(ULONG) CAVIFile::CPersistFileImpl::AddRef()
  2618. {
  2619. return m_pAVIFile->m_pUnknownOuter->AddRef();
  2620. }
  2621. /* - - - - - - - - */
  2622. STDMETHODIMP_(ULONG) CAVIFile::CPersistFileImpl::Release()
  2623. {
  2624. return m_pAVIFile->m_pUnknownOuter->Release();
  2625. }
  2626. /* - - - - - - - - */
  2627. // *** IPersist methods ***
  2628. STDMETHODIMP CAVIFile::CPersistFileImpl::GetClassID (LPCLSID lpClassID)
  2629. {
  2630. CAVIFile FAR * pfile = m_pAVIFile;
  2631. return NOERROR;
  2632. }
  2633. // *** IPersistFile methods ***
  2634. STDMETHODIMP CAVIFile::CPersistFileImpl::IsDirty ()
  2635. {
  2636. CAVIFile FAR * pfile = m_pAVIFile;
  2637. if (pfile->fDirty)
  2638. return NOERROR;
  2639. else
  2640. return ResultFromScode(S_FALSE);
  2641. }
  2642. STDMETHODIMP CAVIFile::CPersistFileImpl::Load (LPCOLESTR lpszFileName, DWORD grfMode)
  2643. {
  2644. CAVIFile FAR * pfile = m_pAVIFile;
  2645. UINT ui;
  2646. CLock tlock(pfile);
  2647. if (pfile->achFile[0])
  2648. return ResultFromScode(-1);
  2649. pfile->mode = grfMode;
  2650. #if defined _WIN32 && !defined UNICODE
  2651. WideCharToMultiByte(CP_ACP, 0, lpszFileName, -1,
  2652. pfile->achFile, NUMELMS(pfile->achFile), NULL, NULL);
  2653. #else
  2654. lstrcpy(pfile->achFile, lpszFileName);
  2655. #endif
  2656. // Assumptions about avilib.cpp:
  2657. // We're assuming that if CREATE is set, WRITE is set too.
  2658. // We're assuming that we'll always see READWRITE instead of just WRITE.
  2659. // If it ain't broke, don't fix it - who do I look like, the share flag
  2660. // standards enforcing committee?
  2661. #if 0
  2662. // force the share flags to the 'correct' values
  2663. if (grfMode & OF_READWRITE) {
  2664. pfile->mode = (grfMode & ~(MMIO_SHAREMODE)) | OF_SHARE_EXCLUSIVE;
  2665. } else {
  2666. pfile->mode = (grfMode & ~(MMIO_SHAREMODE)) | OF_SHARE_DENY_WRITE;
  2667. }
  2668. #endif
  2669. // try to open the actual file
  2670. // If the first attempt fails, no system error box, please.
  2671. ui = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  2672. pfile->hshfile = shfileOpen(pfile->achFile, NULL, pfile->mode);
  2673. if (!pfile->hshfile && ((grfMode & MMIO_RWMODE) == OF_READ)) {
  2674. // if the open fails, try again without the share flags.
  2675. pfile->mode &= ~(MMIO_SHAREMODE);
  2676. pfile->hshfile = shfileOpen(pfile->achFile, NULL, pfile->mode);
  2677. }
  2678. SetErrorMode(ui);
  2679. if (pfile->hshfile) {
  2680. shfileAddRef(pfile->hshfile); // compensate for later release of IPersistFile
  2681. shfileAddRef(pfile->hshfile); // compensate for later release of IPersistFile
  2682. }
  2683. return pfile->OpenInternal(grfMode);
  2684. }
  2685. STDMETHODIMP CAVIFile::CPersistFileImpl::Save (LPCOLESTR lpszFileName, BOOL fRemember)
  2686. {
  2687. CAVIFile FAR * pfile = m_pAVIFile;
  2688. return NOERROR;
  2689. }
  2690. STDMETHODIMP CAVIFile::CPersistFileImpl::SaveCompleted (LPCOLESTR lpszFileName)
  2691. {
  2692. CAVIFile FAR * pfile = m_pAVIFile;
  2693. return NOERROR;
  2694. }
  2695. STDMETHODIMP CAVIFile::CPersistFileImpl::GetCurFile (LPOLESTR FAR * lplpszFileName)
  2696. {
  2697. CAVIFile FAR * pfile = m_pAVIFile;
  2698. return NOERROR;
  2699. }