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.

1080 lines
27 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1985-1991. All rights reserved.
  3. AVIIDX.C - AVI Index stuff
  4. *****************************************************************************/
  5. #include <win32.h> // Win16/32 porting
  6. #include <avifmt.h> // for stream type
  7. #include "aviidx.h"
  8. #ifdef AVIIDX_READONLY
  9. #include "common.h" // for DEBUG
  10. #else
  11. #include "debug.h" // for DEBUG
  12. #endif
  13. /***************************************************************************
  14. ***************************************************************************/
  15. #define INDEXALLOC 512
  16. #define STACK _based(_segname("_STACK"))
  17. /***************************************************************************
  18. ***************************************************************************/
  19. //
  20. // used by SearchIndex() to return where a sample is
  21. //
  22. typedef struct {
  23. LONG lx; // index position
  24. LONG lPos; // position in samples.
  25. LONG lSize; // size in samples.
  26. LONG lOffset; // file offset.
  27. LONG lLength; // size in bytes.
  28. } IDXPOS;
  29. /***************************************************************************
  30. *
  31. * @doc INTERNAL
  32. *
  33. * @api PAVIINDEX | IndexAddFileIndex
  34. *
  35. * add a bunch of entries from a AVIFILE index to the index.
  36. *
  37. ***************************************************************************/
  38. EXTERN_C PAVIINDEX IndexAddFileIndex(PAVIINDEX px, AVIINDEXENTRY _huge *pidx, LONG cnt, LONG lAdjust, BOOL fRle)
  39. {
  40. LONG lx;
  41. LONG l;
  42. LONG lxRec;
  43. DWORD ckid;
  44. UINT stream;
  45. DWORD offset;
  46. DWORD length;
  47. UINT flags;
  48. Assert(px);
  49. Assert(pidx);
  50. if (px == NULL || pidx == NULL)
  51. return NULL;
  52. Assert(sizeof(AVIINDEXENTRY) > sizeof(AVIIDX));
  53. //
  54. // grow the index if needed.
  55. //
  56. if (px->nIndex + cnt > px->nIndexSize) {
  57. LONG grow = px->nIndex + cnt - px->nIndexSize;
  58. LPVOID p;
  59. if (grow < INDEXALLOC)
  60. grow = INDEXALLOC;
  61. p = (LPVOID)GlobalReAllocPtr(px,sizeof(AVIINDEX) +
  62. (px->nIndexSize + grow) * sizeof(AVIIDX),
  63. GMEM_MOVEABLE | GMEM_SHARE);
  64. if (!p)
  65. return NULL;
  66. px = (PAVIINDEX)p;
  67. px->nIndexSize += grow;
  68. }
  69. for (lxRec=-1,l=0; l < cnt; l++,pidx++) {
  70. lx = px->nIndex + l;
  71. //
  72. // adjust the offset to be absolute
  73. //
  74. offset = pidx->dwChunkOffset + lAdjust;
  75. length = pidx->dwChunkLength;
  76. ckid = pidx->ckid;
  77. stream = StreamFromFOURCC(ckid);
  78. flags = 0;
  79. if (ckid == listtypeAVIRECORD)
  80. stream = STREAM_REC;
  81. if (ckid == listtypeAVIRECORD)
  82. lxRec = lx;
  83. //
  84. // handle over flows in a "sane" way.
  85. //
  86. if (offset >= MAX_OFFSET)
  87. break;
  88. if (stream >= MAX_STREAM)
  89. break;
  90. if (length >= MAX_LENGTH)
  91. length = MAX_LENGTH-1;
  92. if (pidx->dwFlags & AVIIF_KEYFRAME)
  93. flags |= IDX_KEY;
  94. else
  95. flags |= IDX_NONKEY;
  96. //
  97. // length == 0 samples are not real
  98. //
  99. if (length == 0)
  100. flags &= ~(IDX_NONKEY|IDX_KEY);
  101. //
  102. // mark palette changes
  103. //
  104. if (TWOCCFromFOURCC(ckid) == cktypePALchange) {
  105. flags |= IDX_PAL;
  106. flags &= ~(IDX_NONKEY|IDX_KEY);
  107. }
  108. //
  109. // fix up bogus index's by adding any missing KEYFRAME
  110. // bits. ie this only applies for RLE files.
  111. //
  112. if (fRle && length > 0 && TWOCCFromFOURCC(ckid) == cktypeDIBbits)
  113. flags |= IDX_KEY;
  114. //
  115. // do we need to support these?
  116. //
  117. if (fRle && TWOCCFromFOURCC(ckid) == aviTWOCC('d', 'x'))
  118. flags |= IDX_HALF;
  119. //
  120. // audio is always a key.
  121. //
  122. if (TWOCCFromFOURCC(ckid) == cktypeWAVEbytes)
  123. flags |= IDX_KEY|IDX_NONKEY; //hack to get audio back!
  124. //
  125. // make sure records are marked as contining a key
  126. //
  127. //if (lxRec > 0 && (flags & IDX_KEY))
  128. // IndexSetKey(px, lxRec);
  129. IndexSetFlags(px,lx,flags);
  130. IndexSetOffset(px,lx,offset);
  131. IndexSetLength(px,lx,length);
  132. IndexSetStream(px,lx,stream);
  133. }
  134. cnt = l;
  135. px->nIndex += cnt;
  136. return px;
  137. }
  138. /***************************************************************************
  139. ***************************************************************************/
  140. static LONG FAR PASCAL mmioReadProc(HMMIO hmmio, LONG lSeek, LONG lRead, LPVOID lpBuffer)
  141. {
  142. if (mmioSeek(hmmio, lSeek, SEEK_SET) == -1)
  143. return -1;
  144. if (mmioRead(hmmio, (HPSTR)lpBuffer, lRead) != lRead)
  145. return -1;
  146. return lRead;
  147. }
  148. /***************************************************************************
  149. ***************************************************************************/
  150. static LONG FAR PASCAL mmioWriteProc(HMMIO hmmio, LONG lSeek, LONG lWrite, LPVOID lpBuffer)
  151. {
  152. if (mmioSeek(hmmio, lSeek, SEEK_SET) == -1)
  153. return -1;
  154. if (mmioWrite(hmmio, (HPSTR)lpBuffer, lWrite) != lWrite)
  155. return -1;
  156. return lWrite;
  157. }
  158. /***************************************************************************
  159. *
  160. * @doc INTERNAL
  161. *
  162. * @api PSTREAMINDEX | MakeStreamIndex
  163. *
  164. * makes a STREAMINDEX structure that will be used later to read/find
  165. * samples in a stream.
  166. *
  167. ***************************************************************************/
  168. EXTERN_C PSTREAMINDEX MakeStreamIndex(PAVIINDEX px, UINT stream, LONG lStart, LONG lSampleSize, HANDLE hFile, STREAMIOPROC ReadProc, STREAMIOPROC WriteProc)
  169. {
  170. LONG lPos;
  171. LONG lx;
  172. PSTREAMINDEX psx;
  173. Assert(px);
  174. if (px == NULL)
  175. return NULL;
  176. psx = (PSTREAMINDEX)LocalAlloc(LPTR, sizeof(STREAMINDEX));
  177. if (psx == NULL)
  178. return NULL;
  179. //!!! fixed length sample streams should never have this
  180. if (lSampleSize != 0 && lStart < 0) {
  181. #ifdef DEBUG
  182. AssertSz(0, "Audio streams should not have initial frames");
  183. #endif
  184. lStart = 0;
  185. }
  186. psx->px = px;
  187. psx->lStart = lStart;
  188. psx->lSampleSize = lSampleSize;
  189. psx->lMaxSampleSize = 0;
  190. psx->stream = stream;
  191. psx->flags = 0;
  192. psx->lStart = lStart;
  193. psx->lxStart = IndexFirst(px, stream);
  194. psx->lPos = lStart;
  195. psx->lx = psx->lxStart;
  196. psx->lFrames = 0;
  197. psx->lKeyFrames = 0;
  198. psx->lPalFrames = 0;
  199. psx->lNulFrames = 0;
  200. psx->hFile = hFile;
  201. if (ReadProc == NULL)
  202. psx->Read = (STREAMIOPROC)mmioReadProc;
  203. else
  204. psx->Read = ReadProc;
  205. if (WriteProc == NULL)
  206. psx->Write = (STREAMIOPROC)mmioWriteProc;
  207. else
  208. psx->Write = WriteProc;
  209. lPos = lStart;
  210. for (lx = psx->lxStart; lx >= 0 && lx < px->nIndex; lx=IndexNext(px, lx, 0)) {
  211. if (psx->lMaxSampleSize < IndexLength(px, lx))
  212. psx->lMaxSampleSize = IndexLength(px, lx);
  213. //
  214. // make sure the start sample is a key frame (unless it's wave data!)
  215. //
  216. if (lPos == 0 || (lPos >= 0 && lPos == psx->lStart)) {
  217. if ((IndexFlags(px, lx) & (IDX_KEY|IDX_NONKEY)) !=
  218. (IDX_KEY|IDX_NONKEY)) {
  219. IndexSetKey(px, lx);
  220. }
  221. }
  222. //
  223. // make sure sample size is correct
  224. //
  225. if (psx->lSampleSize &&
  226. ((IndexLength(px, lx) % lSampleSize) != 0)) {
  227. DPF("Bad chunk size found: forcing sample size to 0.\n");
  228. psx->lSampleSize = 0;
  229. }
  230. //
  231. // or all the flags together so we can see what a stream has.
  232. //
  233. psx->flags |= IndexFlags(px, lx);
  234. //
  235. // check for all key frames.
  236. //
  237. if (IndexFlags(px, lx) & IDX_KEY)
  238. psx->lKeyFrames++;
  239. //
  240. // check for all palette changes
  241. //
  242. if (IndexFlags(px, lx) & IDX_PAL)
  243. psx->lPalFrames++;
  244. //
  245. // check for empty frames
  246. //
  247. if (IndexLength(px, lx) == 0)
  248. psx->lNulFrames++;
  249. //
  250. // advance the position
  251. //
  252. if (!(IndexFlags(px,lx) & IDX_NOTIME)) {
  253. if (lSampleSize)
  254. lPos += IndexLength(px, lx) / lSampleSize;
  255. else
  256. lPos++;
  257. }
  258. psx->lFrames++;
  259. }
  260. //
  261. // correct the length
  262. //
  263. psx->lEnd = lPos;
  264. DPF("MakeStreamIndex stream=#%d lStart=%ld, lEnd=%ld\n", stream, psx->lStart, psx->lEnd);
  265. DPF(" lFrames = %ld, lKeys = %ld, lPals = %ld, lEmpty = %ld\n", psx->lFrames, psx->lKeyFrames, psx->lPalFrames, psx->lNulFrames);
  266. return psx;
  267. }
  268. #ifndef AVIIDX_READONLY
  269. /***************************************************************************
  270. *
  271. * @doc INTERNAL
  272. *
  273. * @api PAVIINDEX | IndexGetFileIndex
  274. *
  275. * make a file index out of a in memory index
  276. *
  277. ***************************************************************************/
  278. EXTERN_C LONG IndexGetFileIndex(PAVIINDEX px, LONG l, LONG cnt, PAVIINDEXENTRY pidx, LONG lAdjust)
  279. {
  280. LONG lx;
  281. DWORD ckid;
  282. UINT stream;
  283. DWORD offset;
  284. DWORD length;
  285. UINT flags;
  286. DWORD dwFlags;
  287. Assert(pidx);
  288. Assert(px);
  289. if (pidx == NULL || px == NULL)
  290. return NULL;
  291. Assert(sizeof(AVIINDEXENTRY) > sizeof(AVIIDX));
  292. for (lx=l; lx < px->nIndex && lx < l+cnt; lx++) {
  293. //
  294. // adjust the offset to be relative
  295. //
  296. offset = IndexOffset(px,lx) + lAdjust;
  297. length = IndexLength(px,lx);
  298. stream = IndexStream(px,lx);
  299. flags = IndexFlags(px, lx);
  300. if (length == MAX_LENGTH-1) {
  301. }
  302. ckid = MAKEAVICKID(0, stream);
  303. dwFlags = 0;
  304. //
  305. // set the flags, there are only a few flags in file index's
  306. // AVIIF_KEYFRAME, AVIIF_LIST, AVIIF_NOTIME
  307. //
  308. if (flags & IDX_KEY)
  309. dwFlags |= AVIIF_KEYFRAME;
  310. if (flags & IDX_PAL)
  311. dwFlags |= AVIIF_NOTIME;
  312. if (stream == STREAM_REC)
  313. dwFlags |= AVIIF_LIST;
  314. //
  315. // now figure out the ckid
  316. //
  317. if (stream == STREAM_REC)
  318. ckid = listtypeAVIRECORD;
  319. else if ((flags & (IDX_KEY|IDX_NONKEY)) == (IDX_KEY|IDX_NONKEY))
  320. ckid |= MAKELONG(0, aviTWOCC('w', 'b'));
  321. else if (flags & IDX_PAL)
  322. ckid |= MAKELONG(0, aviTWOCC('p', 'c'));
  323. else if (flags & IDX_HALF)
  324. ckid |= MAKELONG(0, aviTWOCC('d', 'x'));
  325. else if (flags & IDX_KEY)
  326. ckid |= MAKELONG(0, aviTWOCC('d', 'b'));
  327. else
  328. ckid |= MAKELONG(0, aviTWOCC('d', 'c'));
  329. //
  330. // set the info
  331. //
  332. pidx->dwChunkOffset = offset;
  333. pidx->dwChunkLength = length;
  334. pidx->dwFlags = dwFlags;
  335. pidx->ckid = ckid;
  336. pidx++;
  337. }
  338. return lx - l; // return count copied
  339. }
  340. /***************************************************************************
  341. *
  342. * @doc INTERNAL
  343. *
  344. * @api PAVIINDEX | IndexCreate | make a index.
  345. *
  346. ***************************************************************************/
  347. EXTERN_C PAVIINDEX IndexCreate(void)
  348. {
  349. PAVIINDEX px;
  350. px = (PAVIINDEX)GlobalAllocPtr(GHND | GMEM_SHARE,
  351. sizeof(AVIINDEX) + INDEXALLOC * sizeof(AVIIDX));
  352. if (px == NULL)
  353. return NULL;
  354. px->nIndex = 0; // index size
  355. px->nIndexSize = INDEXALLOC; // allocated size
  356. return px;
  357. }
  358. #endif // AVIIDX_READONLY
  359. /***************************************************************************
  360. *
  361. * @doc INTERNAL MCIAVI
  362. *
  363. * @api LONG | IndexFirst | returns the first index entry for a stream
  364. *
  365. * @rdesc returns the first index entry, -1 for error
  366. *
  367. ***************************************************************************/
  368. EXTERN_C LONG IndexFirst(PAVIINDEX px, UINT stream)
  369. {
  370. LONG l;
  371. Assert(px);
  372. for (l=0; l<px->nIndex; l++) {
  373. if (IndexStream(px, l) == stream)
  374. return l;
  375. }
  376. return ERR_IDX;
  377. }
  378. /***************************************************************************
  379. *
  380. * @doc INTERNAL MCIAVI
  381. *
  382. * @api LONG | IndexNext | go forward in a index
  383. *
  384. ***************************************************************************/
  385. EXTERN_C LONG IndexNext(PAVIINDEX px, LONG l, UINT f)
  386. {
  387. BYTE bStream;
  388. Assert(px);
  389. if (l < 0 || l >= px->nIndex)
  390. return ERR_IDX;
  391. bStream = IndexStream(px, l);
  392. for (l++; l<px->nIndex; l++) {
  393. if (IndexStream(px, l) != bStream)
  394. continue;
  395. if (!f || (IndexFlags(px, l) & f))
  396. return l;
  397. }
  398. return ERR_IDX;
  399. }
  400. /***************************************************************************
  401. *
  402. * @doc INTERNAL MCIAVI
  403. *
  404. * @api LONG | IndexPrev | step backward in a stream
  405. *
  406. ***************************************************************************/
  407. EXTERN_C LONG IndexPrev(PAVIINDEX px, LONG l, UINT f)
  408. {
  409. BYTE bStream;
  410. Assert(px);
  411. if (l < 0 || l >= px->nIndex)
  412. return ERR_IDX;
  413. bStream = IndexStream(px, l);
  414. for (l--; l>=0; l--) {
  415. if (IndexStream(px, l) != bStream)
  416. continue;
  417. if (!f || (IndexFlags(px, l) & f))
  418. return l;
  419. }
  420. return ERR_IDX;
  421. }
  422. ///////////////////////////////////////////////////////////////////////////
  423. ///////////////////////////////////////////////////////////////////////////
  424. INLINE BOOL StreamNext(PSTREAMINDEX psx, LONG FAR& l, LONG FAR& lPos, UINT flags)
  425. {
  426. BYTE bStream = psx->stream;
  427. LONG lSampleSize = psx->lSampleSize;
  428. LONG lSave = l;
  429. LONG lPosSave = lPos;
  430. PAVIINDEX px = psx->px;
  431. Assert(px && l >= 0 && l < px->nIndex);
  432. if (lSampleSize == 0) {
  433. lPos += 1;
  434. l++;
  435. for (; l<px->nIndex; l++) {
  436. if (IndexStream(px, l) != bStream)
  437. continue;
  438. if (!flags || (IndexFlags(px, l) & flags))
  439. return TRUE;
  440. if (!(IndexFlags(px, l) & IDX_NOTIME))
  441. lPos += 1;
  442. }
  443. }
  444. else {
  445. lPos += IndexLength(px, l) / lSampleSize;
  446. l++;
  447. for (; l<px->nIndex; l++) {
  448. if (IndexStream(px, l) != bStream)
  449. continue;
  450. if (!flags || (IndexFlags(px, l) & flags))
  451. return TRUE;
  452. lPos += IndexLength(px, l) / lSampleSize;
  453. }
  454. }
  455. lPos = lPosSave;
  456. l = lSave;
  457. return FALSE;
  458. }
  459. ///////////////////////////////////////////////////////////////////////////
  460. ///////////////////////////////////////////////////////////////////////////
  461. INLINE BOOL StreamPrev(PSTREAMINDEX psx, LONG FAR& l, LONG FAR& lPos, UINT flags)
  462. {
  463. BYTE bStream = psx->stream;
  464. LONG lSampleSize = psx->lSampleSize;
  465. LONG lSave = l;
  466. LONG lPosSave = lPos;
  467. PAVIINDEX px = psx->px;
  468. Assert(px && l >= 0 && l < px->nIndex);
  469. if (lSampleSize == 0) {
  470. for (l--;l>=0;l--) {
  471. if (IndexStream(px, l) != bStream)
  472. continue;
  473. if (!(IndexFlags(px, l) & IDX_NOTIME))
  474. lPos -= 1;
  475. if (!flags || (IndexFlags(px, l) & flags))
  476. return TRUE;
  477. }
  478. }
  479. else {
  480. for (l--;l>=0;l--) {
  481. if (IndexStream(px, l) != bStream)
  482. continue;
  483. lPos -= IndexLength(px, l) / lSampleSize;
  484. if (!flags || (IndexFlags(px, l) & flags))
  485. return TRUE;
  486. }
  487. }
  488. lPos = lPosSave;
  489. l = lSave;
  490. return FALSE;
  491. }
  492. ///////////////////////////////////////////////////////////////////////////
  493. ///////////////////////////////////////////////////////////////////////////
  494. static LONG SearchIndex(PSTREAMINDEX psx,LONG lPos,UINT uFlags,IDXPOS FAR *pos)
  495. {
  496. LONG l;
  497. LONG lScan;
  498. LONG lFound;
  499. LONG lFoundPos;
  500. LONG lLen;
  501. UINT flags;
  502. PAVIINDEX px = psx->px;
  503. Assert(psx);
  504. Assert(psx->px);
  505. if (psx == NULL)
  506. return ERR_POS;
  507. if (lPos < psx->lStart)
  508. return ERR_POS;
  509. if (lPos >= psx->lEnd)
  510. return ERR_POS;
  511. //
  512. // figure out where to start in the index.
  513. //
  514. if (psx->lx != -1) {
  515. lScan = psx->lPos;
  516. l = psx->lx;
  517. }
  518. else {
  519. DPF3("Starting index search at begining\n");
  520. lScan = psx->lStart;
  521. for (l=0; l<px->nIndex; l++)
  522. if (IndexStream(px, l) == (UINT)psx->stream)
  523. break;
  524. }
  525. Assert(l >= 0 && l < px->nIndex);
  526. Assert(IndexStream(px, l) == psx->stream);
  527. #ifdef DEBUG
  528. if (!(uFlags & FIND_DIR))
  529. uFlags |= FIND_PREV;
  530. switch (uFlags & (FIND_TYPE|FIND_DIR)) {
  531. case FIND_NEXT|FIND_KEY: DPF3("SearchIndex(%d): %ld next key, start=%ld",psx->stream, lPos, lScan); break;
  532. case FIND_NEXT|FIND_ANY: DPF3("SearchIndex(%d): %ld next any, start=%ld",psx->stream, lPos, lScan); break;
  533. case FIND_NEXT|FIND_FORMAT: DPF3("SearchIndex(%d): %ld next fmt, start=%ld",psx->stream, lPos, lScan); break;
  534. case FIND_NEXT: DPF3("SearchIndex(%d): %ld next , start=%ld",psx->stream, lPos, lScan); break;
  535. case FIND_PREV|FIND_KEY: DPF3("SearchIndex(%d): %ld prev key, start=%ld",psx->stream, lPos, lScan); break;
  536. case FIND_PREV|FIND_ANY: DPF3("SearchIndex(%d): %ld prev any, start=%ld",psx->stream, lPos, lScan); break;
  537. case FIND_PREV|FIND_FORMAT: DPF3("SearchIndex(%d): %ld prev fmt, start=%ld",psx->stream, lPos, lScan); break;
  538. case FIND_PREV: DPF3("SearchIndex(%d): %ld prev , start=%ld",psx->stream, lPos, lScan); break;
  539. }
  540. LONG time = timeGetTime();
  541. #endif
  542. lLen = psx->lSampleSize == 0 ? 1 : IndexLength(px, l) / psx->lSampleSize;
  543. if (lScan+lLen <= lPos) {
  544. //
  545. // search forward for this position
  546. //
  547. while (lScan <= lPos) {
  548. lFound = l;
  549. lFoundPos = lScan;
  550. if (lScan == lPos)
  551. break;
  552. if (!StreamNext(psx, l, lScan, IDX_KEY|IDX_NONKEY))
  553. break;
  554. }
  555. if ((lScan > lPos) && !(uFlags & FIND_NEXT)) {
  556. lScan = lFoundPos;
  557. l = lFound;
  558. }
  559. }
  560. else if (lScan > lPos) {
  561. //
  562. // search backward for this position
  563. //
  564. while (lScan > lPos) {
  565. lFound = l;
  566. lFoundPos = lScan;
  567. if (!StreamPrev(psx, l, lScan, IDX_KEY|IDX_NONKEY))
  568. break;
  569. }
  570. if (uFlags & FIND_NEXT) {
  571. lScan = lFoundPos;
  572. l = lFound;
  573. }
  574. }
  575. else {
  576. Assert(lScan <= lPos && lPos < lScan+lLen);
  577. }
  578. Assert(l >= 0 && l < px->nIndex);
  579. Assert(IndexStream(px, l) == psx->stream);
  580. //
  581. // cache what we found.
  582. //
  583. psx->lx = l;
  584. psx->lPos = lScan;
  585. if (uFlags & FIND_TYPE) {
  586. switch (uFlags & FIND_TYPE) {
  587. case FIND_ANY: flags = IDX_KEY|IDX_NONKEY; break;
  588. case FIND_FORMAT: flags = IDX_PAL; break;
  589. case FIND_KEY: flags = IDX_KEY; break;
  590. }
  591. if (!(IndexFlags(px, l) & flags)) {
  592. if (!(uFlags & FIND_NEXT)) {
  593. if (!StreamPrev(psx, l, lScan, flags)) {
  594. DPF3("!, EOI, time = %ld\n", timeGetTime() - time);
  595. return ERR_POS;
  596. }
  597. }
  598. else {
  599. if (!StreamNext(psx, l, lScan, flags)) {
  600. DPF3("!, EOI, time = %ld\n", timeGetTime() - time);
  601. return ERR_POS;
  602. }
  603. }
  604. }
  605. Assert(l >= 0 && l < px->nIndex);
  606. Assert(IndexStream(px, l) == psx->stream);
  607. Assert(IndexFlags(px, l) & flags);
  608. }
  609. Assert(lScan >= psx->lStart && lScan < psx->lEnd);
  610. DPF3("!, found %ld, time = %ld\n", lScan, timeGetTime() - time);
  611. if (pos == NULL)
  612. return lScan;
  613. if (psx->lSampleSize != 0) {
  614. lLen = IndexLength(px, l);
  615. if (lLen == MAX_LENGTH-1)
  616. lLen = 0x7FFFFFFF;
  617. if (psx->lSampleSize > 1)
  618. lLen /= psx->lSampleSize;
  619. }
  620. else {
  621. lLen = 1;
  622. }
  623. pos->lx = l;
  624. pos->lPos = lScan;
  625. pos->lSize = lLen;
  626. pos->lOffset = IndexOffset(px, l);
  627. pos->lLength = IndexLength(px, l);
  628. //
  629. // if the FIND_TYPE is not one of FIND_ANY, FIND_KEY, FIND_FORMAT
  630. // make sure we realy found the wanted sample.
  631. //
  632. if ((uFlags & FIND_TYPE) == 0) {
  633. if (lPos < lScan || lPos >= lScan+lLen) {
  634. pos->lOffset = -1;
  635. pos->lLength = 0;
  636. pos->lSize = 0;
  637. pos->lPos = lPos;
  638. }
  639. else if (psx->lSampleSize > 0) {
  640. pos->lOffset += (lPos - lScan) * psx->lSampleSize;
  641. pos->lLength -= (lPos - lScan) * psx->lSampleSize;
  642. pos->lSize -= (lPos - lScan);
  643. pos->lPos = lPos;
  644. }
  645. }
  646. return pos->lPos;
  647. }
  648. /***************************************************************************
  649. *
  650. * @doc INTERNAL MCIAVI
  651. *
  652. * @api LONG | FindSample | find a sample in a stream
  653. *
  654. ***************************************************************************/
  655. EXTERN_C LONG StreamFindSample(PSTREAMINDEX psx,LONG lPos,UINT uFlags)
  656. {
  657. Assert(psx);
  658. Assert(psx->px);
  659. if (lPos < psx->lStart)
  660. return ERR_POS;
  661. if (lPos >= psx->lEnd)
  662. return ERR_POS;
  663. if ((uFlags & FIND_RET) == FIND_POS) {
  664. switch (uFlags & FIND_TYPE) {
  665. case FIND_FORMAT:
  666. if (psx->lPalFrames == 0) {
  667. if ((uFlags & FIND_NEXT) && lPos > psx->lStart)
  668. return ERR_POS;
  669. else
  670. return psx->lStart;
  671. }
  672. break;
  673. case FIND_ANY:
  674. if (psx->lNulFrames == 0) {
  675. return lPos;
  676. }
  677. break;
  678. case FIND_KEY:
  679. if (psx->lKeyFrames == psx->lFrames) {
  680. return lPos;
  681. }
  682. break;
  683. default:
  684. return lPos;
  685. }
  686. return SearchIndex(psx, lPos, uFlags, NULL);
  687. }
  688. else {
  689. IDXPOS pos;
  690. if (SearchIndex(psx, lPos, uFlags, &pos) == ERR_POS)
  691. return ERR_POS;
  692. switch (uFlags & FIND_RET) {
  693. case FIND_POS:
  694. return pos.lPos;
  695. case FIND_OFFSET:
  696. return pos.lOffset + 8;
  697. case FIND_LENGTH:
  698. return pos.lLength;
  699. case FIND_SIZE:
  700. return pos.lSize;
  701. case FIND_INDEX:
  702. return pos.lx;
  703. }
  704. }
  705. return ERR_POS;
  706. }
  707. /***************************************************************************
  708. *
  709. * @doc INTERNAL MCIAVI
  710. *
  711. * @api LONG | StreamRead | read from a stream
  712. *
  713. ***************************************************************************/
  714. EXTERN_C LONG StreamRead(
  715. PSTREAMINDEX psx,
  716. LONG lStart,
  717. LONG lSamples,
  718. LPVOID lpBuffer,
  719. LONG cbBuffer)
  720. {
  721. LONG lBytes;
  722. LONG lSampleSize;
  723. LONG lSeek;
  724. LONG lRead;
  725. IDXPOS pos;
  726. Assert(psx);
  727. Assert(psx->px);
  728. Assert(psx->hFile);
  729. Assert(psx->Read);
  730. if (lStart < psx->lStart)
  731. return -1;
  732. if (lStart >= psx->lEnd)
  733. return -1;
  734. //
  735. // find nearest chunk
  736. //
  737. if (SearchIndex(psx, lStart, FIND_PREV, &pos) == ERR_POS)
  738. return -1;
  739. //
  740. // only continue if the sample we want is in here.
  741. //
  742. if (lStart < pos.lPos || lStart >= pos.lPos + pos.lSize)
  743. return 0;
  744. //
  745. // if they give us a NULL buffer dummy up the cbBuffer so we return
  746. // what we would have read if we had enough room
  747. //
  748. if (lpBuffer == NULL && cbBuffer == 0 && lSamples != 0)
  749. cbBuffer = 0x7FFFFFFF;
  750. if (lSampleSize = psx->lSampleSize) {
  751. // If they wanted to read/write only a "convenient amount",
  752. // pretend the buffer is only large enough to hold the
  753. // rest of this chunk.
  754. if (lSamples == -1l)
  755. cbBuffer = min(cbBuffer, pos.lLength);
  756. /* Fixed-length samples, if lSamples is zero, just fill the buffer. */
  757. if (lSamples > 0)
  758. lSamples = min(lSamples, cbBuffer / lSampleSize);
  759. else
  760. lSamples = cbBuffer / lSampleSize;
  761. lBytes = lSamples * lSampleSize;
  762. } else {
  763. lBytes = pos.lLength;
  764. }
  765. if (lpBuffer == NULL)
  766. return lBytes;
  767. if (cbBuffer < lBytes)
  768. return -1; // buffer is too small
  769. #define WORDALIGN(x) ((x) + ((x) & 1))
  770. if (lSampleSize == 0)
  771. {
  772. DWORD adw[2];
  773. psx->Read(psx->hFile, pos.lOffset, sizeof(adw), adw);
  774. Assert(StreamFromFOURCC(adw[0]) == psx->stream);
  775. Assert(WORDALIGN(adw[1]) == WORDALIGN((DWORD)pos.lLength));
  776. pos.lLength = adw[1]; // !!! Make netware video work!
  777. lBytes = pos.lLength;
  778. }
  779. else
  780. {
  781. #ifdef DEBUG
  782. IDXPOS x;
  783. DWORD adw[2];
  784. SearchIndex(psx, lStart, FIND_PREV|FIND_ANY, &x);
  785. psx->Read(psx->hFile, x.lOffset, sizeof(adw), adw);
  786. Assert(StreamFromFOURCC(adw[0]) == psx->stream);
  787. Assert(WORDALIGN(adw[1]) == WORDALIGN((DWORD)x.lLength));
  788. #endif
  789. }
  790. cbBuffer = lBytes;
  791. lBytes = 0;
  792. while (cbBuffer > 0) {
  793. lSeek = pos.lOffset + 8;
  794. lRead = min(pos.lLength,cbBuffer);
  795. if (lRead <= 0) {
  796. DPF3("!!!! lRead <= 0 in AVIStreamRead\n");
  797. break;
  798. }
  799. DPF3("StreamRead: %ld bytes @%ld\n", lRead, lSeek);
  800. if (psx->Read(psx->hFile, lSeek, lRead, lpBuffer) != lRead)
  801. return -1;
  802. lBytes += lRead;
  803. cbBuffer -= lRead;
  804. if (cbBuffer > 0) {
  805. if (lSampleSize == 0) {
  806. DPF("%ld bytes to read, but sample size is 0!\n", cbBuffer);
  807. break;
  808. }
  809. lpBuffer = (LPVOID) (((BYTE _huge *)lpBuffer) + lRead);
  810. lStart += lRead / lSampleSize;
  811. lStart = SearchIndex(psx, lStart, FIND_PREV, &pos);
  812. if (lStart == ERR_POS)
  813. break;
  814. }
  815. }
  816. //
  817. // success return number of bytes read
  818. //
  819. return lBytes;
  820. }
  821. /***************************************************************************
  822. *
  823. * @doc INTERNAL MCIAVI
  824. *
  825. * @api LONG | StreamWrite | write to a stream
  826. *
  827. ***************************************************************************/
  828. EXTERN_C LONG StreamWrite(
  829. PSTREAMINDEX psx,
  830. LONG lStart,
  831. LONG lSamples,
  832. LPVOID lpBuffer,
  833. LONG cbBuffer)
  834. {
  835. return -1;
  836. }