AviDecaps.cpp
上传用户:lusi_8715
上传日期:2007-01-08
资源大小:199k
文件大小:21k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /**************************************************************************************
  2.  *                                                                                    *
  3.  * This application contains code from OpenDivX and is released as a "Larger Work"    *
  4.  * under that license. Consistant with that license, this application is released     *
  5.  * under the GNU General Public License.                                              *
  6.  *                                                                                    *
  7.  * The OpenDivX license can be found at: http://www.projectmayo.com/opendivx/docs.php *
  8.  * The GPL can be found at: http://www.gnu.org/copyleft/gpl.html                      *
  9.  *                                                                                    *
  10.  * Copyright (c) 2001 - Project Mayo                                                  *
  11.  *                                                                                    *
  12.  * Authors: Damien Chavarria <adrc at projectmayo.com>                                *
  13.  *                                                                                    *
  14.  **************************************************************************************/
  15. #include "AviDecaps.h"
  16. /*
  17.  * Some useful functions
  18.  */
  19. /*
  20.  * copy n into dst as a 4 byte, 
  21.  * little endian number.
  22.  * should also work on 
  23.  * big endian machines 
  24.  *
  25.  */
  26. static void long2str(char *dst, int n)
  27. {
  28. dst[0] = (n      ) & 0xff;
  29. dst[1] = (n >>  8) & 0xff;
  30. dst[2] = (n >> 16) & 0xff;
  31. dst[3] = (n >> 24) & 0xff;
  32. }
  33. /* Convert a string of 4 
  34.  * or 2 bytes to a number,
  35.  * also working on big 
  36.  * endian machines 
  37.  *
  38.  */
  39. unsigned long str2ulong(char *str)
  40. {
  41.     unsigned long result;
  42. result = ( ((unsigned long) str[0] & 0xFF) | ( ((unsigned long)str[1] &0xFF) << 8) |
  43.   (((unsigned long) str[2] & 0xFF) << 16) | ( ((unsigned long) str[3] & 0xFF) << 24) );
  44. return result;
  45. }
  46. static unsigned long str2ushort(char *str)
  47. {
  48. return ( str[0] | (str[1]<<8) );
  49. }
  50. /*
  51.  * "SMART" AVI Readind Class
  52.  */
  53. /*
  54.  * Constuctor : opens the file and init 
  55.  *              the Mutex for reading
  56.  */
  57. AviDecaps::AviDecaps()
  58. {
  59. this->video_pos  = 0;
  60. this->audio_posc = 0;
  61. this->audio_posb = 0;
  62. this->idx         = NULL;
  63. this->video_index = NULL;
  64. this->audio_index = NULL;
  65. this->input = NULL;
  66. }
  67. /*
  68.  * Desturctor : Cleanup.
  69.  *
  70.  */
  71. AviDecaps::~AviDecaps()
  72. {
  73. delete this->input;
  74. }
  75. /*
  76.  * Reads the first 12 bytes of
  77.  * the file, and returns TRUE
  78.  * if the file is an AVI.
  79.  *
  80.  */
  81. int AviDecaps::IsAVI()
  82. {
  83. char data[24];
  84. if(this->input != NULL) {
  85. if( this->input->Read(data, 12) != 12 ) {
  86. MessageBox(NULL, "Error Reading", "Info", MB_OK);
  87. return 0;
  88. }
  89. if( strncmp(data, "RIFF", 4) !=0 || 
  90. strncmp(data + 8, "AVI ", 4) !=0 ) {
  91. return 0;
  92. }
  93. return 1;
  94. }
  95. return 0;
  96. }
  97. /*
  98.  * Returns the sample size of
  99.  * the first audio stream...
  100.  *
  101.  */
  102. int AviDecaps::SampleSize()
  103. {
  104. int s;
  105. s = ((this->a_bits + 7) / 8) * this->a_chans;
  106. if(s == 0)
  107. s = 1;
  108. return s;
  109. }
  110. /*
  111.  * Add an entry to the gloabl index
  112.  * this function is used while reading.
  113.  *
  114.  */
  115. int AviDecaps::AddIndexEntry(char *tag, 
  116.  long flags, 
  117.  long pos, 
  118.  long len)
  119. {
  120. void *ptr;
  121. if(this->n_idx >= this->max_idx)
  122. {
  123. ptr = realloc((void *)this->idx,
  124. (this->max_idx + 4096) * 16);
  125. if(ptr == 0) {
  126. return -1;
  127. }
  128. this->max_idx += 4096;
  129. this->idx = (char((*)[16]) ) ptr;
  130. }
  131. /* 
  132.     * add the index entry 
  133.     *
  134.     */
  135. memcpy(this->idx[this->n_idx], tag, 4);
  136. long2str(this->idx[this->n_idx]+ 4, flags);
  137. long2str(this->idx[this->n_idx]+ 8, pos);
  138. long2str(this->idx[this->n_idx]+12, len);
  139. /* 
  140.     * update counter
  141.     *
  142.     */
  143. this->n_idx++;
  144. return 0;
  145. }
  146. /*
  147.  * Fill the class with info from headers
  148.  * and reconstruct an index if wanted.
  149.  *
  150.  */
  151. int AviDecaps::FillHeader(int getIndex)
  152. {
  153. unsigned long  i, n, rate; 
  154. long           scale, idx_type;
  155. char          *hdrl_data;
  156. long           hdrl_len = 0;
  157. long           nvi, nai, ioff;
  158. long           tot;
  159. int            lasttag = 0;
  160. int            vids_strh_seen = 0;
  161. int            vids_strf_seen = 0;
  162. int            auds_strh_seen = 0;
  163. int            auds_strf_seen = 0;
  164. int            num_stream = 0;
  165. char           data[256];
  166. /* go through the AVI file and 
  167.     * extract the header list,
  168.     * the start position of the 'movi' 
  169.     * list and an optionally
  170.     * present idx1 tag 
  171.     *
  172.     */
  173. hdrl_data = 0;
  174. while(1)
  175.     {
  176. if( this->input->Read(data, 8) != 8 ) 
  177. break; 
  178. /*
  179.  * we assume it's EOF 
  180.  *
  181.      */
  182. n = str2ulong(data + 4);
  183. n = PAD_EVEN(n);
  184. if(strncmp(data, "LIST", 4) == 0)
  185. {
  186. if( this->input->Read(data, 4) != 4 ) {
  187. return 0;
  188. }
  189. n -= 4;
  190. if(strncmp(data, "hdrl", 4) == 0)
  191. {
  192. hdrl_len = n;
  193. hdrl_data = (char *) malloc(n);
  194. if(hdrl_data == 0) { 
  195. return 0;
  196. }
  197. if( this->input->Read(hdrl_data, n) != n ) {
  198. return 0;
  199. }
  200. }
  201. else if(strncmp(data, "movi", 4) == 0)
  202. {
  203. this->movi_start = this->input->Seek(0, INPUT_SEEK_CUR);
  204. this->input->Seek(n, INPUT_SEEK_CUR);
  205. }
  206. else
  207. this->input->Seek(n, INPUT_SEEK_CUR);
  208. }
  209. else if(strncmp(data,"idx1",4) == 0)
  210. {
  211. /*
  212.  * n must be a multiple of 16, 
  213.  * but the reading does not
  214.  * break if this is not the case 
  215.  *
  216.      */
  217. this->n_idx = this->max_idx = n/16;
  218. this->idx = (char((*)[16]) ) malloc(n);
  219. if(this->idx == NULL) { 
  220. return 0;
  221. }
  222. unsigned long read;
  223. if( (read = this->input->Read((char *) this->idx, n)) != n ) {
  224. break;
  225. }
  226. }
  227. else {
  228.   
  229. this->input->Seek(n, INPUT_SEEK_CUR);
  230. }
  231. }
  232. if(!hdrl_data) {
  233. return 0;
  234. }
  235. if(!this->movi_start) {
  236. return 0;
  237. }
  238. /* 
  239.     * interpret the header list 
  240.     *
  241.     */
  242. for(i=0; i < hdrl_len; )
  243. {
  244. /* 
  245. * list tags are completly ignored 
  246. *
  247. */
  248. if(strncmp(hdrl_data + i, "LIST", 4)==0) 
  249. i+= 12; 
  250. continue; 
  251. }
  252. n = str2ulong(hdrl_data+i+4);
  253. n = PAD_EVEN(n);
  254. /* 
  255. * interpret the tag and its args 
  256. *
  257. */
  258. if(strncmp(hdrl_data + i, "strh", 4)==0)
  259. {
  260. i += 8;
  261. if(strncmp(hdrl_data + i, "vids", 4) == 0 && !vids_strh_seen)
  262. {
  263. memcpy(this->compressor,hdrl_data+i+4,4);
  264. this->compressor[4] = 0;
  265. scale = str2ulong(hdrl_data+i+20);
  266. rate  = str2ulong(hdrl_data+i+24);
  267. if(scale!=0) 
  268. this->fps = (double)rate/(double)scale;
  269. this->video_frames = str2ulong(hdrl_data+i+32);
  270. this->video_strn = num_stream;
  271. vids_strh_seen = 1;
  272. lasttag = 1; 
  273. }
  274. else if (strncmp (hdrl_data + i, "auds", 4) == 0 && ! auds_strh_seen)
  275. {
  276. this->audio_bytes = str2ulong(hdrl_data + i + 32)*this->SampleSize();
  277. this->audio_strn = num_stream;
  278. auds_strh_seen = 1;
  279. lasttag = 2; 
  280. }
  281. else
  282. lasttag = 0;
  283. num_stream++;
  284. }
  285. else if(strncmp(hdrl_data + i, "strf", 4)==0)
  286. {
  287. i += 8;
  288. if(lasttag == 1)
  289. {
  290. /*
  291. * keep a copy of 
  292. * the bitmapinfoheader
  293. *
  294. */
  295. memcpy(&this->bitmapinfoheader, 
  296. hdrl_data + i,
  297. sizeof(BITMAPINFOHEADER));  
  298. this->width  = str2ulong(hdrl_data+i+4);
  299. this->height = str2ulong(hdrl_data+i+8);
  300. vids_strf_seen = 1;
  301. }
  302. else if(lasttag == 2)
  303. {
  304. /*
  305.  * keep a copy of the WAVEFORMATEX
  306.  */
  307. memcpy(&this->waveformatex,
  308.    hdrl_data + i,
  309.    sizeof(WAVEFORMATEX));
  310. this->a_fmt   = str2ushort(hdrl_data + i  );
  311. this->a_chans = str2ushort(hdrl_data + i + 2);
  312. this->a_rate  = str2ulong (hdrl_data + i + 4);
  313. this->a_bits  = str2ushort(hdrl_data + i + 14) == 0 ? 16 : str2ushort(hdrl_data + i + 14);
  314. auds_strf_seen = 1;
  315. }
  316. lasttag = 0;
  317. }
  318. else
  319. {
  320. i += 8;
  321. lasttag = 0;
  322. }
  323. i += n;
  324. }
  325. free(hdrl_data);
  326. if(!vids_strh_seen || !vids_strf_seen || this->video_frames==0) { 
  327. return 0;
  328. }
  329. this->video_tag[0] = this->video_strn/10 + '0';
  330. this->video_tag[1] = this->video_strn%10 + '0';
  331. this->video_tag[2] = 'd';
  332. this->video_tag[3] = 'b';
  333. /* 
  334.     * audio tag is set to "99wb" 
  335.     * if no audio present 
  336.     *
  337.     */
  338. if(!this->a_chans) 
  339. this->audio_strn = 99;
  340. this->audio_tag[0] = this->audio_strn/10 + '0';
  341. this->audio_tag[1] = this->audio_strn%10 + '0';
  342. this->audio_tag[2] = 'w';
  343. this->audio_tag[3] = 'b';
  344. this->input->Seek(this->movi_start, INPUT_SEEK_SET);
  345. /* 
  346.  * get index if wanted 
  347.  *
  348.  */
  349. if(!getIndex) 
  350. return 1;
  351. /* 
  352. * if the file has an idx1, 
  353. * check if this is relative
  354. * to the start of the file or 
  355. * to the start of the movi list 
  356. *
  357.         */
  358. idx_type = 0;
  359. if(this->idx)
  360. {
  361. long pos, len;
  362. /*
  363. * search the first videoframe 
  364. * in the idx1 and look where
  365.         * it is in the file 
  366. *
  367. */
  368. for(i=0;i<this->n_idx;i++) {
  369. if( strncmp(this->idx[i], this->video_tag, 3) == 0 ) 
  370. break;
  371. }
  372. if(i >= this->n_idx) 
  373. return 0;
  374. pos = str2ulong(this->idx[i] + 8);
  375. len = str2ulong(this->idx[i] + 12);
  376. this->input->Seek(pos, INPUT_SEEK_SET);
  377. if(this->input->Read(data, 8)!=8) 
  378. return 0;
  379. if( strncmp(data, this->idx[i], 4) == 0 && str2ulong(data + 4) == len )
  380. {
  381.   /* 
  382.    * index from start of file
  383.    *
  384.    */
  385. idx_type = 1; 
  386. }
  387. else
  388. {
  389. this->input->Seek(pos + this->movi_start - 4,INPUT_SEEK_SET);
  390. if(this->input->Read(data, 8) != 8) 
  391. return 0;
  392. if( strncmp(data, this->idx[i], 4) == 0 && str2ulong(data + 4) == len )
  393. {
  394.  /* 
  395.   * index from start of movi list 
  396.   *
  397.   */
  398. idx_type = 2; 
  399. }
  400. }
  401. /* 
  402. * idx_type remains 0 if neither 
  403. * of the two tests above succeeds 
  404. *
  405. */
  406. }
  407. if(idx_type == 0)
  408. {
  409. /* 
  410.    * we must search through 
  411.  * the file to get the index 
  412.  *
  413.  */
  414. this->input->Seek(this->movi_start, INPUT_SEEK_SET);
  415. this->n_idx = 0;
  416. while(1)
  417. {
  418. if( this->input->Read(data, 8) != 8 ) 
  419. break;
  420. n = str2ulong(data + 4);
  421. /* 
  422. * the movi list may contain sub-lists, 
  423. * ignore them 
  424. *
  425. */
  426. if(strncmp(data,"LIST", 4) == 0)
  427. {
  428. this->input->Seek(4, INPUT_SEEK_CUR);
  429. continue;
  430. }
  431. /* 
  432. * check if we got a tag ##db, 
  433. * ##dc or ##wb 
  434. */
  435. if( ( (data[2]=='d' || data[2]=='D') &&
  436. (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) || 
  437. ( (data[2]=='w' || data[2]=='W') &&
  438. (data[3]=='b' || data[3]=='B') ) )
  439. {
  440. this->AddIndexEntry(data,
  441. 0, 
  442. this->input->Seek(0, INPUT_SEEK_CUR) - 8, 
  443. n);
  444. }
  445. this->input->Seek(PAD_EVEN(n),
  446. INPUT_SEEK_CUR);
  447. }
  448. idx_type = 1;
  449. }
  450. /* 
  451.     * now generate the video index 
  452.     * and audio index arrays 
  453.     *
  454.     */
  455. nvi = 0;
  456. nai = 0;
  457. for(i=0; i < this->n_idx; i++)
  458. {
  459. if(strncmp(this->idx[i], this->video_tag, 3) == 0) 
  460. nvi++;
  461. if(strncmp(this->idx[i], this->audio_tag, 4) == 0) 
  462. nai++;
  463. }
  464. this->video_frames = nvi;
  465. this->audio_chunks = nai;
  466. if(this->video_frames == 0) 
  467. return 0;
  468. this->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry));
  469. if(this->video_index == 0) 
  470. return 0;
  471. if(this->audio_chunks)
  472. {
  473. this->audio_index = (audio_index_entry *) malloc(nai*sizeof(audio_index_entry));
  474. if(this->audio_index==0) 
  475. return 0;
  476. }
  477. nvi = 0;
  478. nai = 0;
  479. tot = 0;
  480. ioff = idx_type == 1 ? 8 : this->movi_start+4;
  481. for(i=0; i < this->n_idx; i++)
  482. {
  483. if(strncmp(this->idx[i], this->video_tag, 3) == 0)
  484. {
  485. this->video_index[nvi].flags = str2ulong(this->idx[i]+ 4);
  486. this->video_index[nvi].pos   = str2ulong(this->idx[i]+ 8)+ioff;
  487. this->video_index[nvi].len   = str2ulong(this->idx[i]+12);
  488. nvi++;
  489. }
  490. if(strncmp(this->idx[i], this->audio_tag, 4) == 0)
  491. {
  492. this->audio_index[nai].pos = str2ulong(this->idx[i]+ 8)+ioff;
  493. this->audio_index[nai].len = str2ulong(this->idx[i]+12);
  494. this->audio_index[nai].tot = tot;
  495. tot += this->audio_index[nai].len;
  496. nai++;
  497. }
  498. }
  499. this->audio_bytes = tot;
  500. /* 
  501.      * reposition the file 
  502.      *
  503.      */
  504. this->input->Seek(this->movi_start, 
  505. INPUT_SEEK_SET);
  506. this->video_pos = 0;
  507. return 1;
  508. }
  509. /*
  510.  * Reading Functions
  511.  *
  512.  */
  513. /*
  514.  * Tries to open an AVI
  515.  * with and without an index
  516.  */
  517. int AviDecaps::Open(char *lpFilename, int type)
  518. {
  519. if(lpFilename) {
  520. this->input = new InputMedia();
  521. this->hIOMutex = CreateMutex (NULL, FALSE, NULL);
  522. }
  523. if(!this->input->Open(lpFilename, INPUT_OPEN_BINARY, type)) {
  524. delete this->input;
  525. return 0;
  526. }
  527. this->video_pos  = 0;
  528. this->audio_posc = 0;
  529. this->audio_posb = 0;
  530. this->idx         = NULL;
  531. this->video_index = NULL;
  532. this->audio_index = NULL;
  533. if(!this->input->isOK()) {
  534. delete this->input;
  535. this->input = NULL;
  536. return 0;
  537. }
  538. if(this->IsAVI()) {
  539. if(this->FillHeader(1)) {
  540. return 1;
  541. }
  542. else {
  543. this->input->Seek(0, INPUT_SEEK_SET);
  544. this->IsAVI();
  545. if(this->FillHeader(0)) {
  546. return 1;
  547. }
  548. }
  549. }
  550. return 0;
  551. }
  552. /*
  553.  * Returns the video width
  554.  *
  555.  */
  556. int AviDecaps::Width()
  557. {
  558. return this->width;
  559. }
  560. /*
  561.  * Returns the video height
  562.  *
  563.  */
  564. int AviDecaps::Height()
  565. {
  566. return this->height;
  567. }
  568. /*
  569.  * Gives the size of 
  570.  * a particular frame
  571.  */
  572. int AviDecaps::FrameSize(unsigned long frame_number)
  573. {
  574.  if(!this->video_index)         
  575.  { 
  576.  return -1; 
  577.  }
  578.  if(frame_number < 0 || frame_number >= this->video_frames) {
  579.     return -1;
  580.   }
  581.   return(this->video_index[frame_number].len);
  582. }
  583. /*
  584.  * Returns the total
  585.  * number of video streams
  586.  *
  587.  */
  588. int AviDecaps::VideoStreams()
  589. {
  590. return this->video_strn;
  591. }
  592. /*
  593.  * Returns the total
  594.  * number of audio streams
  595.  *
  596.  */
  597. int AviDecaps::AudioStreams()
  598. {
  599. return this->audio_strn;
  600. }
  601. /*
  602.  * Returns the bitmapinfoheader
  603.  * associated with the first video 
  604.  * stream.
  605.  */
  606. BITMAPINFOHEADER *AviDecaps::BitmapInfoHeader()
  607. {
  608. return &this->bitmapinfoheader;
  609. }
  610. /*
  611.  * Returns the wavefromatex
  612.  * associated with the first audio 
  613.  * stream.
  614.  */
  615. WAVEFORMATEX     *AviDecaps::WaveFormatEx()
  616. {
  617. return &this->waveformatex;
  618. }
  619. /*
  620.  * Reads the next video Frame into
  621.  * buffer, return the actual size of
  622.  * the frame.
  623.  *
  624.  */
  625. int AviDecaps::NextVideoFrame(char *buffer)
  626. {
  627.    int m;
  628.    unsigned int n;
  629.    /*
  630.     * Security checks
  631.     *
  632.     */
  633.    if(!this->video_index)         
  634.      { 
  635.        return -1; 
  636.      }
  637.    if(this->video_pos < 0 || this->video_pos >= this->video_frames) {
  638.      
  639.    return -2;
  640.    }
  641.    /*
  642.     * Request the mutex 
  643.     * for reading the file;
  644.     */
  645.    WaitForSingleObject(this->hIOMutex, INFINITE);
  646.    n = this->video_index[this->video_pos].len;
  647.    this->input->Seek(this->video_index[this->video_pos].pos, INPUT_SEEK_SET);
  648.    if ((m = this->input->Read(buffer, n)) != n)
  649.      {
  650.    this->video_pos++;
  651.    ReleaseMutex(this->hIOMutex);
  652.        return n;
  653.      }
  654.    this->video_pos++;
  655.    /*
  656.     * Release the Mutex.
  657.     */
  658.    ReleaseMutex(this->hIOMutex);
  659.    return n;
  660. }
  661. /*
  662.  * Reads any amount of audio
  663.  * data. FIXME : should return
  664.  * the actual number read.
  665.  */
  666. int AviDecaps::ReadAudio(char *audbuf, int bytes)
  667. {
  668. int nr, pos, left = 0, todo;
  669.    if(!this->audio_index)         
  670.      { 
  671.    MessageBox(NULL, "No audio index", "", MB_OK);
  672.        return -1; 
  673.      }
  674.    nr = 0; 
  675.    /*
  676.     * Request the read Mutex 
  677.     */
  678.    WaitForSingleObject(this->hIOMutex, INFINITE);
  679.    /*
  680.     * We loop until we parsed enough
  681. * chunks for the amount we want
  682.     *
  683.     */
  684.    while(bytes > 0)
  685.    {
  686.       left = this->audio_index[this->audio_posc].len - this->audio_posb;
  687.       if(left == 0)
  688.       {
  689.          if(this->audio_posc>=this->audio_chunks-1) 
  690.  {
  691. ReleaseMutex(this->hIOMutex);
  692. return nr;
  693.  }
  694.          this->audio_posc++;
  695.          this->audio_posb = 0;
  696.          continue;
  697.       }
  698.       if(bytes<left)
  699.          todo = bytes;
  700.       else
  701.          todo = left;
  702.       pos = this->audio_index[this->audio_posc].pos + this->audio_posb;
  703.       
  704.   this->input->Seek(pos, INPUT_SEEK_SET);
  705.       if (this->input->Read(audbuf + nr, todo) != todo)
  706.       {
  707.  MessageBox(NULL, "Can't read enough!", "", MB_OK);
  708.          ReleaseMutex(this->hIOMutex);
  709.  return -1;
  710.       }
  711.       bytes -= todo;
  712.       nr    += todo;
  713.       this->audio_posb += todo;
  714.    }
  715.    /*
  716.     * And release the Mutex.
  717.     */
  718.    ReleaseMutex(this->hIOMutex);
  719.    return nr;
  720. }
  721. /*
  722.  * Return the actual framerate
  723.  * FIXME : should be a double...
  724.  *
  725.  */
  726. double AviDecaps::FrameRate()
  727. {
  728. /*
  729.  * Fix for some trailers
  730.  */
  731. if(this->fps == 0)
  732. this->fps = 25;
  733. if(this->fps == 23)
  734. this->fps = 25;
  735. return (double) this->fps;
  736. }
  737. long AviDecaps::TotalFrames() {
  738. return this->video_frames;
  739. }
  740. /*
  741.  * Seek to a particular 
  742.  * video frame.
  743.  */
  744. int AviDecaps::VideoSeek(long frame)
  745. {
  746. if(!this->video_index) {
  747. return -1; 
  748.     }
  749.    if (frame < 0 ) frame = 0;
  750.    
  751.    this->video_pos = frame;
  752.    return 1;
  753. }
  754. int AviDecaps::AudioSeek(long bytes)
  755. {
  756.    long n0, n1, n;
  757.    if(!this->audio_index) { 
  758.        return -1; 
  759.    }
  760.    if(bytes < 0) 
  761.    bytes = 0;
  762.    n0 = 0;
  763.    n1 = this->audio_chunks;
  764.    while(n0 < n1 - 1)
  765.    {
  766.       n = (n0 + n1) / 2;
  767.       if(this->audio_index[n].tot > bytes)
  768.          n1 = n;
  769.       else
  770.          n0 = n;
  771.    }
  772.    this->audio_posc = n0;
  773.    if(this->audio_index[n0].len > 1000) {
  774.      this->audio_posb = bytes - this->audio_index[n0].tot;
  775.    }
  776.    else {
  777.      this->audio_posb = 0;
  778.    }
  779.    return 0;
  780. }
  781. BOOL AviDecaps::isKeyframe(long frame)
  782. {
  783.   if(frame < 0)
  784.     frame = 0;
  785.   if(!this->video_index)         
  786.     { 
  787.       /*
  788.        * we still return 1 to avoid looping
  789.        * on waiting for a keyframe.
  790.        *
  791.        */
  792.       return 1; 
  793.     }
  794.   return this->video_index[frame].flags & AVIIF_KEYFRAME;
  795. }
  796. int AviDecaps::NextKeyFrame()
  797. {
  798. WaitForSingleObject(this->hIOMutex, INFINITE);
  799. /*
  800.  * Allways increment by one
  801.  */
  802. this->video_pos++;
  803. while(!isKeyframe(this->video_pos) && this->video_pos < this->video_frames)
  804. this->video_pos++;
  805.     ReleaseMutex(this->hIOMutex);
  806. return 1;
  807. }
  808. int AviDecaps::PreviousKeyFrame()
  809. {
  810. WaitForSingleObject(this->hIOMutex, INFINITE);
  811. /*
  812.  * Allways decrement by two
  813.  * since we read the last frame
  814.  */
  815. this->video_pos--;
  816. this->video_pos--;
  817. while(!isKeyframe(this->video_pos) && this->video_pos > 0)
  818. this->video_pos--;
  819.     ReleaseMutex(this->hIOMutex);
  820. return 1;
  821. }
  822. int AviDecaps::Seek(int percent)
  823. {
  824. long frame;
  825. double ratio;
  826. long audio_bytes;
  827. char msg[256];
  828.   
  829. WaitForSingleObject(this->hIOMutex, INFINITE);
  830. /*
  831.      * compute the desired 
  832.      * frame number
  833.      *
  834.      */
  835.     frame = (long) (percent * this->video_frames / 100);
  836.     /*
  837.      * and go to the next 
  838.      * keyframe.
  839.      *
  840.      */
  841.   
  842.     while(!this->isKeyframe(frame)) {
  843.       frame++;
  844.     }
  845.     /*
  846.      * now set video 
  847.      * position.
  848.      *
  849.      */
  850.     
  851. this->VideoSeek(frame);
  852.     /*
  853.      * calculate what ratio 
  854.      * it corresponds to
  855.      *
  856.      */
  857.     if(this->AudioStreams() > 0) {
  858.       
  859.       ratio = (double) ((double) frame / (double) this->video_frames);
  860.       
  861.       /*
  862.        * and set audio 
  863.        * position
  864.        *
  865.        */
  866.       audio_bytes  = (long) (ratio * this->audio_bytes);
  867.       audio_bytes  += audio_bytes % 4;
  868.       this->AudioSeek(audio_bytes);
  869.       ReleaseMutex(this->hIOMutex);
  870.       return 1;
  871. }
  872. return 1;
  873. }
  874. int AviDecaps::ReSeekAudio()
  875. {
  876. double ratio;
  877. long audio_bytes;
  878.     if(this->AudioStreams() > 0) {
  879.   WaitForSingleObject(this->hIOMutex, INFINITE);
  880.       ratio = (double) ((double) this->video_pos / (double) this->video_frames);
  881.       
  882.       /*
  883.        * and set audio 
  884.        * position
  885.        *
  886.        */
  887.       audio_bytes  = (long) (ratio * this->audio_bytes);
  888.       audio_bytes  += audio_bytes % 4;
  889.       this->AudioSeek(audio_bytes);
  890.       ReleaseMutex(this->hIOMutex);
  891. }
  892.     return 1;
  893. }
  894. int AviDecaps::Rewind()
  895. {
  896. this->video_pos  = 0;
  897. this->audio_posc = 0;
  898. this->audio_posb = 0;
  899. return 1;
  900. }
  901. double AviDecaps::GetProgress()
  902. {
  903. return (double) ((double)(this->video_pos))*100.0/((double)this->video_frames);
  904. }
  905. int AviDecaps::GetBufferingState() {
  906. if(this->input != NULL) {
  907. return this->input->getBufferState();
  908. }
  909. return 0;
  910. }
  911. int AviDecaps::Close()
  912. {
  913. if(this->input) {
  914. this->input->Close();
  915. delete this->input;
  916. this->input = NULL;
  917. }
  918. if(this->idx)
  919. free(this->idx);
  920. if(this->video_index)
  921. free(this->video_index);
  922. if(this->audio_index)
  923. free(this->audio_index);
  924. CloseHandle(this->hIOMutex);
  925. return 1;
  926. }