Leaked source code of windows server 2003
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.

1090 lines
28 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1985-1995. All rights reserved.
  3. AVIIDX.C - AVI Index stuff
  4. *****************************************************************************/
  5. #include <win32.h> // Win16/32 porting
  6. #include <vfw.h>
  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: force sample size to 0???\n");
  228. // psx->lSampleSize = 0; !!! turned off because of possible
  229. // partial audio chunks at file's end.....
  230. }
  231. //
  232. // or all the flags together so we can see what a stream has.
  233. //
  234. psx->flags |= IndexFlags(px, lx);
  235. //
  236. // check for all key frames.
  237. //
  238. if (IndexFlags(px, lx) & IDX_KEY)
  239. psx->lKeyFrames++;
  240. //
  241. // check for all palette changes
  242. //
  243. if (IndexFlags(px, lx) & IDX_PAL)
  244. psx->lPalFrames++;
  245. //
  246. // check for empty frames
  247. //
  248. if (IndexLength(px, lx) == 0)
  249. psx->lNulFrames++;
  250. //
  251. // advance the position
  252. //
  253. if (!(IndexFlags(px,lx) & IDX_NOTIME)) {
  254. if (lSampleSize)
  255. lPos += IndexLength(px, lx) / lSampleSize;
  256. else
  257. lPos++;
  258. }
  259. psx->lFrames++;
  260. }
  261. //
  262. // correct the length
  263. //
  264. psx->lEnd = lPos;
  265. DPF("MakeStreamIndex stream=#%d lStart=%ld, lEnd=%ld\n", stream, psx->lStart, psx->lEnd);
  266. DPF(" lFrames = %ld, lKeys = %ld, lPals = %ld, lEmpty = %ld\n", psx->lFrames, psx->lKeyFrames, psx->lPalFrames, psx->lNulFrames);
  267. return psx;
  268. }
  269. #ifndef AVIIDX_READONLY
  270. /***************************************************************************
  271. *
  272. * @doc INTERNAL
  273. *
  274. * @api PAVIINDEX | IndexGetFileIndex
  275. *
  276. * make a file index out of a in memory index
  277. *
  278. ***************************************************************************/
  279. EXTERN_C LONG IndexGetFileIndex(PAVIINDEX px, LONG l, LONG cnt, PAVIINDEXENTRY pidx, LONG lAdjust)
  280. {
  281. LONG lx;
  282. DWORD ckid;
  283. UINT stream;
  284. DWORD offset;
  285. DWORD length;
  286. UINT flags;
  287. DWORD dwFlags;
  288. Assert(pidx);
  289. Assert(px);
  290. if (pidx == NULL || px == NULL)
  291. return NULL;
  292. Assert(sizeof(AVIINDEXENTRY) > sizeof(AVIIDX));
  293. for (lx=l; lx < px->nIndex && lx < l+cnt; lx++) {
  294. //
  295. // adjust the offset to be relative
  296. //
  297. offset = IndexOffset(px,lx) + lAdjust;
  298. length = IndexLength(px,lx);
  299. stream = IndexStream(px,lx);
  300. flags = IndexFlags(px, lx);
  301. if (length == MAX_LENGTH-1) {
  302. }
  303. ckid = MAKEAVICKID(0, stream);
  304. dwFlags = 0;
  305. //
  306. // set the flags, there are only a few flags in file index's
  307. // AVIIF_KEYFRAME, AVIIF_LIST, AVIIF_NOTIME
  308. //
  309. if (flags & IDX_KEY)
  310. dwFlags |= AVIIF_KEYFRAME;
  311. if (flags & IDX_PAL)
  312. dwFlags |= AVIIF_NOTIME;
  313. if (stream == STREAM_REC)
  314. dwFlags |= AVIIF_LIST;
  315. //
  316. // now figure out the ckid
  317. //
  318. if (stream == STREAM_REC)
  319. ckid = listtypeAVIRECORD;
  320. else if ((flags & (IDX_KEY|IDX_NONKEY)) == (IDX_KEY|IDX_NONKEY))
  321. ckid |= MAKELONG(0, aviTWOCC('w', 'b'));
  322. else if (flags & IDX_PAL)
  323. ckid |= MAKELONG(0, aviTWOCC('p', 'c'));
  324. else if (flags & IDX_HALF)
  325. ckid |= MAKELONG(0, aviTWOCC('d', 'x'));
  326. else if (flags & IDX_KEY)
  327. ckid |= MAKELONG(0, aviTWOCC('d', 'b'));
  328. else
  329. ckid |= MAKELONG(0, aviTWOCC('d', 'c'));
  330. //
  331. // set the info
  332. //
  333. pidx->dwChunkOffset = offset;
  334. pidx->dwChunkLength = length;
  335. pidx->dwFlags = dwFlags;
  336. pidx->ckid = ckid;
  337. pidx++;
  338. }
  339. return lx - l; // return count copied
  340. }
  341. /***************************************************************************
  342. *
  343. * @doc INTERNAL
  344. *
  345. * @api PAVIINDEX | IndexCreate | make a index.
  346. *
  347. ***************************************************************************/
  348. EXTERN_C PAVIINDEX IndexCreate(void)
  349. {
  350. PAVIINDEX px;
  351. px = (PAVIINDEX)GlobalAllocPtr(GHND | GMEM_SHARE,
  352. sizeof(AVIINDEX) + INDEXALLOC * sizeof(AVIIDX));
  353. if (px == NULL)
  354. return NULL;
  355. px->nIndex = 0; // index size
  356. px->nIndexSize = INDEXALLOC; // allocated size
  357. return px;
  358. }
  359. #endif // AVIIDX_READONLY
  360. /***************************************************************************
  361. *
  362. * @doc INTERNAL MCIAVI
  363. *
  364. * @api LONG | IndexFirst | returns the first index entry for a stream
  365. *
  366. * @rdesc returns the first index entry, -1 for error
  367. *
  368. ***************************************************************************/
  369. EXTERN_C LONG IndexFirst(PAVIINDEX px, UINT stream)
  370. {
  371. LONG l;
  372. Assert(px);
  373. for (l=0; l<px->nIndex; l++) {
  374. if (IndexStream(px, l) == stream)
  375. return l;
  376. }
  377. return ERR_IDX;
  378. }
  379. /***************************************************************************
  380. *
  381. * @doc INTERNAL MCIAVI
  382. *
  383. * @api LONG | IndexNext | go forward in a index
  384. *
  385. ***************************************************************************/
  386. EXTERN_C LONG IndexNext(PAVIINDEX px, LONG l, UINT f)
  387. {
  388. WORD bStream;
  389. Assert(px);
  390. if (l < 0 || l >= px->nIndex)
  391. return ERR_IDX;
  392. bStream = IndexStream(px, l);
  393. for (l++; l<px->nIndex; l++) {
  394. if (IndexStream(px, l) != bStream)
  395. continue;
  396. if (!f || (IndexFlags(px, l) & f))
  397. return l;
  398. }
  399. return ERR_IDX;
  400. }
  401. /***************************************************************************
  402. *
  403. * @doc INTERNAL MCIAVI
  404. *
  405. * @api LONG | IndexPrev | step backward in a stream
  406. *
  407. ***************************************************************************/
  408. EXTERN_C LONG IndexPrev(PAVIINDEX px, LONG l, UINT f)
  409. {
  410. WORD bStream;
  411. Assert(px);
  412. if (l < 0 || l >= px->nIndex)
  413. return ERR_IDX;
  414. bStream = IndexStream(px, l);
  415. for (l--; l>=0; l--) {
  416. if (IndexStream(px, l) != bStream)
  417. continue;
  418. if (!f || (IndexFlags(px, l) & f))
  419. return l;
  420. }
  421. return ERR_IDX;
  422. }
  423. ///////////////////////////////////////////////////////////////////////////
  424. ///////////////////////////////////////////////////////////////////////////
  425. INLINE BOOL StreamNext(PSTREAMINDEX psx, LONG FAR& l, LONG FAR& lPos, UINT flags)
  426. {
  427. BYTE bStream = (BYTE) psx->stream;
  428. LONG lSampleSize = psx->lSampleSize;
  429. LONG lSave = l;
  430. LONG lPosSave = lPos;
  431. PAVIINDEX px = psx->px;
  432. Assert(px && l >= 0 && l < px->nIndex);
  433. if (lSampleSize == 0) {
  434. lPos += 1;
  435. l++;
  436. for (; l<px->nIndex; l++) {
  437. if (IndexStream(px, l) != bStream)
  438. continue;
  439. if (!flags || (IndexFlags(px, l) & flags))
  440. return TRUE;
  441. if (!(IndexFlags(px, l) & IDX_NOTIME))
  442. lPos += 1;
  443. }
  444. }
  445. else {
  446. lPos += IndexLength(px, l) / lSampleSize;
  447. l++;
  448. for (; l<px->nIndex; l++) {
  449. if (IndexStream(px, l) != bStream)
  450. continue;
  451. if (!flags || (IndexFlags(px, l) & flags))
  452. return TRUE;
  453. lPos += IndexLength(px, l) / lSampleSize;
  454. }
  455. }
  456. lPos = lPosSave;
  457. l = lSave;
  458. return FALSE;
  459. }
  460. ///////////////////////////////////////////////////////////////////////////
  461. ///////////////////////////////////////////////////////////////////////////
  462. INLINE BOOL StreamPrev(PSTREAMINDEX psx, LONG FAR& l, LONG FAR& lPos, UINT flags)
  463. {
  464. BYTE bStream = (BYTE) psx->stream;
  465. LONG lSampleSize = psx->lSampleSize;
  466. LONG lSave = l;
  467. LONG lPosSave = lPos;
  468. PAVIINDEX px = psx->px;
  469. Assert(px && l >= 0 && l < px->nIndex);
  470. if (lSampleSize == 0) {
  471. for (l--;l>=0;l--) {
  472. if (IndexStream(px, l) != bStream)
  473. continue;
  474. if (!(IndexFlags(px, l) & IDX_NOTIME))
  475. lPos -= 1;
  476. if (!flags || (IndexFlags(px, l) & flags))
  477. return TRUE;
  478. }
  479. }
  480. else {
  481. for (l--;l>=0;l--) {
  482. if (IndexStream(px, l) != bStream)
  483. continue;
  484. lPos -= IndexLength(px, l) / lSampleSize;
  485. if (!flags || (IndexFlags(px, l) & flags))
  486. return TRUE;
  487. }
  488. }
  489. lPos = lPosSave;
  490. l = lSave;
  491. return FALSE;
  492. }
  493. ///////////////////////////////////////////////////////////////////////////
  494. ///////////////////////////////////////////////////////////////////////////
  495. static LONG SearchIndex(PSTREAMINDEX psx,LONG lPos,UINT uFlags,IDXPOS FAR *pos)
  496. {
  497. LONG l;
  498. LONG lScan;
  499. LONG lFound;
  500. LONG lFoundPos;
  501. LONG lLen;
  502. UINT flags;
  503. PAVIINDEX px = psx->px;
  504. Assert(psx);
  505. Assert(psx->px);
  506. if (psx == NULL)
  507. return ERR_POS;
  508. if (lPos < psx->lStart)
  509. return ERR_POS;
  510. if (lPos >= psx->lEnd)
  511. return ERR_POS;
  512. //
  513. // figure out where to start in the index.
  514. //
  515. if (psx->lx != -1) {
  516. lScan = psx->lPos;
  517. l = psx->lx;
  518. }
  519. else {
  520. DPF3("Starting index search at begining\n");
  521. lScan = psx->lStart;
  522. for (l=0; l<px->nIndex; l++)
  523. if (IndexStream(px, l) == (UINT)psx->stream)
  524. break;
  525. }
  526. Assert(l >= 0 && l < px->nIndex);
  527. Assert(IndexStream(px, l) == psx->stream);
  528. #ifdef DEBUG
  529. if (!(uFlags & FIND_DIR))
  530. uFlags |= FIND_PREV;
  531. switch (uFlags & (FIND_TYPE|FIND_DIR)) {
  532. case FIND_NEXT|FIND_KEY: DPF3("SearchIndex(%d): %ld next key, start=%ld",psx->stream, lPos, lScan); break;
  533. case FIND_NEXT|FIND_ANY: DPF3("SearchIndex(%d): %ld next any, start=%ld",psx->stream, lPos, lScan); break;
  534. case FIND_NEXT|FIND_FORMAT: DPF3("SearchIndex(%d): %ld next fmt, start=%ld",psx->stream, lPos, lScan); break;
  535. case FIND_NEXT: DPF3("SearchIndex(%d): %ld next , start=%ld",psx->stream, lPos, lScan); break;
  536. case FIND_PREV|FIND_KEY: DPF3("SearchIndex(%d): %ld prev key, start=%ld",psx->stream, lPos, lScan); break;
  537. case FIND_PREV|FIND_ANY: DPF3("SearchIndex(%d): %ld prev any, start=%ld",psx->stream, lPos, lScan); break;
  538. case FIND_PREV|FIND_FORMAT: DPF3("SearchIndex(%d): %ld prev fmt, start=%ld",psx->stream, lPos, lScan); break;
  539. case FIND_PREV: DPF3("SearchIndex(%d): %ld prev , start=%ld",psx->stream, lPos, lScan); break;
  540. }
  541. LONG time = timeGetTime();
  542. #endif
  543. lLen = psx->lSampleSize == 0 ? 1 : IndexLength(px, l) / psx->lSampleSize;
  544. if (lScan+lLen <= lPos) {
  545. //
  546. // search forward for this position
  547. //
  548. while (lScan <= lPos) {
  549. lFound = l;
  550. lFoundPos = lScan;
  551. if (lScan == lPos)
  552. break;
  553. if (!StreamNext(psx, l, lScan, IDX_KEY|IDX_NONKEY))
  554. break;
  555. }
  556. if ((lScan > lPos) && !(uFlags & FIND_NEXT)) {
  557. lScan = lFoundPos;
  558. l = lFound;
  559. }
  560. }
  561. else if (lScan > lPos) {
  562. //
  563. // search backward for this position
  564. //
  565. while (lScan >= lPos) {
  566. lFound = l;
  567. lFoundPos = lScan;
  568. if (lScan == lPos)
  569. break;
  570. if (!StreamPrev(psx, l, lScan, IDX_KEY|IDX_NONKEY))
  571. break;
  572. }
  573. if (uFlags & FIND_NEXT) {
  574. lScan = lFoundPos;
  575. l = lFound;
  576. }
  577. }
  578. else {
  579. Assert(lScan <= lPos && lPos < lScan+lLen);
  580. }
  581. Assert(l >= 0 && l < px->nIndex);
  582. Assert(IndexStream(px, l) == psx->stream);
  583. //
  584. // cache what we found.
  585. //
  586. psx->lx = l;
  587. psx->lPos = lScan;
  588. if (uFlags & FIND_TYPE) {
  589. switch (uFlags & FIND_TYPE) {
  590. case FIND_ANY: flags = IDX_KEY|IDX_NONKEY; break;
  591. case FIND_FORMAT: flags = IDX_PAL; break;
  592. case FIND_KEY: flags = IDX_KEY; break;
  593. }
  594. if (!(IndexFlags(px, l) & flags)) {
  595. if (!(uFlags & FIND_NEXT)) {
  596. if (!StreamPrev(psx, l, lScan, flags)) {
  597. DPF3("!, EOI, time = %ld\n", timeGetTime() - time);
  598. return ERR_POS;
  599. }
  600. }
  601. else {
  602. if (!StreamNext(psx, l, lScan, flags)) {
  603. DPF3("!, EOI, time = %ld\n", timeGetTime() - time);
  604. return ERR_POS;
  605. }
  606. }
  607. }
  608. Assert(l >= 0 && l < px->nIndex);
  609. Assert(IndexStream(px, l) == psx->stream);
  610. Assert(IndexFlags(px, l) & flags);
  611. }
  612. Assert(lScan >= psx->lStart && lScan < psx->lEnd);
  613. DPF3("!, found %ld, time = %ld\n", lScan, timeGetTime() - time);
  614. if (pos == NULL)
  615. return lScan;
  616. if (psx->lSampleSize != 0) {
  617. lLen = IndexLength(px, l);
  618. if (lLen == MAX_LENGTH-1)
  619. lLen = 0x7FFFFFFF;
  620. if (psx->lSampleSize > 1)
  621. lLen /= psx->lSampleSize;
  622. }
  623. else {
  624. lLen = 1;
  625. }
  626. pos->lx = l;
  627. pos->lPos = lScan;
  628. pos->lSize = lLen;
  629. pos->lOffset = IndexOffset(px, l);
  630. pos->lLength = IndexLength(px, l);
  631. //
  632. // if the FIND_TYPE is not one of FIND_ANY, FIND_KEY, FIND_FORMAT
  633. // make sure we realy found the wanted sample.
  634. //
  635. if ((uFlags & FIND_TYPE) == 0) {
  636. if (lPos < lScan || lPos >= lScan+lLen) {
  637. pos->lOffset = -1;
  638. pos->lLength = 0;
  639. pos->lSize = 0;
  640. pos->lPos = lPos;
  641. }
  642. else if (psx->lSampleSize > 0) {
  643. pos->lOffset += (lPos - lScan) * psx->lSampleSize;
  644. pos->lLength -= (lPos - lScan) * psx->lSampleSize;
  645. pos->lSize -= (lPos - lScan);
  646. pos->lPos = lPos;
  647. }
  648. }
  649. return pos->lPos;
  650. }
  651. /***************************************************************************
  652. *
  653. * @doc INTERNAL MCIAVI
  654. *
  655. * @api LONG | FindSample | find a sample in a stream
  656. *
  657. ***************************************************************************/
  658. EXTERN_C LONG StreamFindSample(PSTREAMINDEX psx,LONG lPos,UINT uFlags)
  659. {
  660. Assert(psx);
  661. Assert(psx->px);
  662. if (lPos < psx->lStart)
  663. return ERR_POS;
  664. if (lPos >= psx->lEnd)
  665. return ERR_POS;
  666. if ((uFlags & FIND_RET) == FIND_POS) {
  667. switch (uFlags & FIND_TYPE) {
  668. case FIND_FORMAT:
  669. if (psx->lPalFrames == 0) {
  670. if ((uFlags & FIND_NEXT) && lPos > psx->lStart)
  671. return ERR_POS;
  672. else
  673. return psx->lStart;
  674. }
  675. break;
  676. case FIND_ANY:
  677. if (psx->lNulFrames == 0) {
  678. return lPos;
  679. }
  680. break;
  681. case FIND_KEY:
  682. if (psx->lKeyFrames == psx->lFrames) {
  683. return lPos;
  684. }
  685. break;
  686. default:
  687. return lPos;
  688. }
  689. return SearchIndex(psx, lPos, uFlags, NULL);
  690. }
  691. else {
  692. IDXPOS pos;
  693. if (SearchIndex(psx, lPos, uFlags, &pos) == ERR_POS)
  694. return ERR_POS;
  695. switch (uFlags & FIND_RET) {
  696. case FIND_POS:
  697. return pos.lPos;
  698. case FIND_OFFSET:
  699. return pos.lOffset + 8;
  700. case FIND_LENGTH:
  701. return pos.lLength;
  702. case FIND_SIZE:
  703. return pos.lSize;
  704. case FIND_INDEX:
  705. return pos.lx;
  706. }
  707. }
  708. return ERR_POS;
  709. }
  710. /***************************************************************************
  711. *
  712. * @doc INTERNAL MCIAVI
  713. *
  714. * @api LONG | StreamRead | read from a stream
  715. *
  716. ***************************************************************************/
  717. EXTERN_C LONG StreamRead(
  718. PSTREAMINDEX psx,
  719. LONG lStart,
  720. LONG lSamples,
  721. LPVOID lpBuffer,
  722. LONG cbBuffer)
  723. {
  724. LONG lBytes;
  725. LONG lSampleSize;
  726. LONG lSeek;
  727. LONG lRead;
  728. IDXPOS pos;
  729. Assert(psx);
  730. Assert(psx->px);
  731. Assert(psx->hFile);
  732. Assert(psx->Read);
  733. if (lStart < psx->lStart)
  734. return -1;
  735. if (lStart >= psx->lEnd)
  736. return -1;
  737. //DPF("%cst: %d : %d\n", psx->stream ? '\t':' ', psx->stream, lStart);
  738. //
  739. // find nearest chunk
  740. //
  741. if (SearchIndex(psx, lStart, FIND_PREV, &pos) == ERR_POS)
  742. return -1;
  743. //
  744. // only continue if the sample we want is in here.
  745. //
  746. if (lStart < pos.lPos || lStart >= pos.lPos + pos.lSize)
  747. return 0;
  748. //
  749. // if they give us a NULL buffer dummy up the cbBuffer so we return
  750. // what we would have read if we had enough room
  751. //
  752. if (lpBuffer == NULL && cbBuffer == 0 && lSamples != 0)
  753. cbBuffer = 0x7FFFFFFF;
  754. if (lSampleSize = psx->lSampleSize) {
  755. // If they wanted to read/write only a "convenient amount",
  756. // pretend the buffer is only large enough to hold the
  757. // rest of this chunk.
  758. if (lSamples == -1l)
  759. cbBuffer = min(cbBuffer, pos.lLength);
  760. /* Fixed-length samples, if lSamples is zero, just fill the buffer. */
  761. if (lSamples > 0)
  762. lSamples = min(lSamples, cbBuffer / lSampleSize);
  763. else
  764. lSamples = cbBuffer / lSampleSize;
  765. lBytes = lSamples * lSampleSize;
  766. } else {
  767. lBytes = pos.lLength;
  768. }
  769. if (lpBuffer == NULL)
  770. return lBytes;
  771. if (cbBuffer < lBytes)
  772. return -1; // buffer is too small
  773. #define WORDALIGN(x) ((x) + ((x) & 1))
  774. if (lSampleSize == 0)
  775. {
  776. DWORD adw[2];
  777. psx->Read(psx->hFile, pos.lOffset, sizeof(adw), adw);
  778. if (StreamFromFOURCC(adw[0]) != psx->stream) {
  779. Assert(0);
  780. } else {
  781. Assert(WORDALIGN(adw[1]) == WORDALIGN((DWORD)pos.lLength));
  782. pos.lLength = adw[1]; // !!! Make netware video work!
  783. lBytes = pos.lLength;
  784. }
  785. }
  786. else
  787. {
  788. #ifdef DEBUG
  789. IDXPOS x;
  790. DWORD adw[2];
  791. SearchIndex(psx, lStart, FIND_PREV|FIND_ANY, &x);
  792. psx->Read(psx->hFile, x.lOffset, sizeof(adw), adw);
  793. Assert(StreamFromFOURCC(adw[0]) == psx->stream);
  794. Assert(WORDALIGN(adw[1]) == WORDALIGN((DWORD)x.lLength));
  795. #endif
  796. }
  797. cbBuffer = lBytes;
  798. lBytes = 0;
  799. while (cbBuffer > 0) {
  800. lSeek = pos.lOffset + 8;
  801. lRead = min(pos.lLength,cbBuffer);
  802. if (lRead <= 0) {
  803. DPF3("!!!! lRead <= 0 in AVIStreamRead\n");
  804. break;
  805. }
  806. DPF3("StreamRead: %ld bytes @%ld\n", lRead, lSeek);
  807. if (psx->Read(psx->hFile, lSeek, lRead, lpBuffer) != lRead)
  808. return -1;
  809. lBytes += lRead;
  810. cbBuffer -= lRead;
  811. if (cbBuffer > 0) {
  812. if (lSampleSize == 0) {
  813. DPF("%ld bytes to read, but sample size is 0!\n", cbBuffer);
  814. break;
  815. }
  816. lpBuffer = (LPVOID) (((BYTE _huge *)lpBuffer) + lRead);
  817. lStart += lRead / lSampleSize;
  818. lStart = SearchIndex(psx, lStart, FIND_PREV, &pos);
  819. if (lStart == ERR_POS)
  820. break;
  821. }
  822. }
  823. //
  824. // success return number of bytes read
  825. //
  826. return lBytes;
  827. }
  828. /***************************************************************************
  829. *
  830. * @doc INTERNAL MCIAVI
  831. *
  832. * @api LONG | StreamWrite | write to a stream
  833. *
  834. ***************************************************************************/
  835. EXTERN_C LONG StreamWrite(
  836. PSTREAMINDEX psx,
  837. LONG lStart,
  838. LONG lSamples,
  839. LPVOID lpBuffer,
  840. LONG cbBuffer)
  841. {
  842. return -1;
  843. }