KLAviFile.cpp
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:18k
源码类别:

模拟服务器

开发平台:

C/C++

  1. #include <stdafx.h>
  2. #include "KLAviFile.h"
  3. //---------------------------------------------------------------------------
  4. // Convert a string of 4 or 2 bytes to a number,
  5. // also working on big endian machines 
  6. //---------------------------------------------------------------------------
  7. static unsigned long str2ulong(char *str)
  8. {
  9. unsigned long result;
  10. result = (((unsigned long)str[0] & 0xFF) |
  11. (((unsigned long)str[1] & 0xFF) << 8) |
  12. (((unsigned long)str[2] & 0xFF) << 16) | 
  13. (((unsigned long)str[3] & 0xFF) << 24));
  14. return result;
  15. }
  16. //---------------------------------------------------------------------------
  17. // Convert a string of 4 or 2 bytes to a number,
  18. // also working on big endian machines 
  19. //---------------------------------------------------------------------------
  20. static unsigned long str2ushort(char *str)
  21. {
  22. return (str[0] | (str[1] << 8));
  23. }
  24. //---------------------------------------------------------------------------
  25. // 函数: KAviFile
  26. // 功能: 购造函数
  27. // 参数: void
  28. // 返回: void
  29. //---------------------------------------------------------------------------
  30. KLAviFile::KLAviFile()
  31. {
  32. m_video_pos   = 0;
  33. m_audio_posc  = 0;
  34. m_audio_posb  = 0;
  35. m_idx   = NULL;
  36. m_video_index = NULL;
  37. m_audio_index = NULL;
  38. }
  39. //---------------------------------------------------------------------------
  40. // 函数: ~KAviFile
  41. // 功能: 析购函数
  42. // 参数: void
  43. // 返回: void
  44. //---------------------------------------------------------------------------
  45. KLAviFile::~KLAviFile()
  46. {
  47. Close();
  48. }
  49. //---------------------------------------------------------------------------
  50. // 函数: Open
  51. // 功能: Try to open an AVI file
  52. // 参数: void
  53. // 返回: BOOL
  54. //---------------------------------------------------------------------------
  55. BOOL KLAviFile::Open(char* Filename)
  56. {
  57. char head[16];
  58. Close();
  59. if (!m_AviFile.Open(Filename))
  60. return FALSE;
  61. m_AviFile.Read(head, 12);
  62. if (memcmp(head, "RIFF", 4) !=0 || 
  63. memcmp(head + 8, "AVI ", 4) !=0 )
  64. return FALSE;
  65. m_video_pos   = 0;
  66. m_audio_posc  = 0;
  67. m_audio_posb  = 0;
  68. m_idx   = NULL;
  69. m_video_index = NULL;
  70. m_audio_index = NULL;
  71. return TRUE;
  72. }
  73. //---------------------------------------------------------------------------
  74. // 函数: FillHeader
  75. // 功能: Fill the class with info from headers
  76. // and reconstruct an index if wanted.
  77. // 参数:
  78. // 返回: BOOL
  79. //---------------------------------------------------------------------------
  80. BOOL KLAviFile::FillHeader()
  81. {
  82. DWORD n;
  83. int i;
  84. long rate;
  85. long scale;
  86. char* hdrl_data;
  87. char* hdrl_ptr;
  88. char* hdrl_end;
  89. long hdrl_len;
  90. int  lasttag = 0;
  91. int  vids_strh_seen = 0;
  92. int  vids_strf_seen = 0;
  93. int  auds_strh_seen = 0;
  94. int  auds_strf_seen = 0;
  95. int  num_stream = 0;
  96. char data[16];
  97. // go through the AVI file and extract the header list,
  98. // the start position of the 'movi' list 
  99. // and an optionally present idx1 tag 
  100. hdrl_data = 0;
  101. hdrl_len = 0;
  102. m_movi_start = 0;
  103. // seek to first LIST chunk
  104. m_AviFile.Seek(12, FILE_BEGIN);
  105. // read two LIST chunks and idx1 chunks
  106. while (1)
  107. {
  108. if (m_AviFile.Read(data, 8) != 8)
  109. break; 
  110. // we assume it's EOF 
  111. n = str2ulong(data + 4);
  112. n = PAD_EVEN(n);
  113. if (memcmp(data, "LIST", 4) == 0)
  114. {
  115. if (m_AviFile.Read(data, 4) != 4 )
  116. return FALSE;
  117. n -= 4;
  118. if (memcmp(data, "hdrl", 4) == 0)
  119. {
  120. hdrl_len = n;
  121. hdrl_data = new char[n];
  122. if (hdrl_data == NULL)
  123. return FALSE;
  124. if (m_AviFile.Read(hdrl_data, n) != n)
  125. return FALSE;
  126. }
  127. else if (memcmp(data, "movi", 4) == 0)
  128. {
  129. m_movi_start = m_AviFile.Tell();
  130. m_AviFile.Seek(n, FILE_CURRENT);
  131. }
  132. else // skip n bytes
  133. {
  134. m_AviFile.Seek(n, FILE_CURRENT);
  135. }
  136. }
  137. else if (memcmp(data, "idx1", 4) == 0)
  138. {
  139. // n must be a multiple of 16, 
  140. // but the reading does not
  141. // break if this is not the case 
  142. m_idx_num = n / 16;
  143. m_idx = (char(*)[16])new char[n];
  144. if (m_idx == NULL)
  145. return FALSE;
  146. if (m_AviFile.Read((char *)m_idx, n) != n)
  147. break;
  148. }
  149. else // skip n bytes
  150. {
  151. m_AviFile.Seek(n, FILE_CURRENT);
  152. }
  153. }
  154. if (hdrl_data == NULL)
  155. return FALSE;
  156. if (m_movi_start == 0)
  157. return FALSE;
  158. // interpret the header list 
  159. hdrl_ptr = hdrl_data;
  160. hdrl_end = hdrl_data + hdrl_len;
  161. while (hdrl_ptr < hdrl_end)
  162. {
  163. // list tags are completly ignored 
  164. if (memcmp(hdrl_ptr, "LIST", 4) == 0)
  165. hdrl_ptr += 12;
  166. continue;
  167. }
  168. n = str2ulong(hdrl_ptr + 4);
  169. n = PAD_EVEN(n);
  170. // interpret the tag and its args 
  171. if (memcmp(hdrl_ptr, "strh", 4) == 0)
  172. {
  173. hdrl_ptr += 8;
  174. if (memcmp(hdrl_ptr, "vids", 4) == 0 && !vids_strh_seen)
  175. {
  176. memcpy(m_compressor, hdrl_ptr + 4, 4);
  177. m_compressor[4] = 0;
  178. scale = str2ulong(hdrl_ptr + 20);
  179. rate  = str2ulong(hdrl_ptr + 24);
  180. if (scale != 0) 
  181. m_fps = rate / scale;
  182. m_video_frames = str2ulong(hdrl_ptr + 32);
  183. m_video_strn = num_stream;
  184. vids_strh_seen = 1;
  185. lasttag = 1;
  186. }
  187. else if (memcmp(hdrl_ptr, "auds", 4) == 0 && !auds_strh_seen)
  188. {
  189. m_audio_strn = num_stream;
  190. auds_strh_seen = 1;
  191. lasttag = 2;
  192. }
  193. else
  194. {
  195. lasttag = 0;
  196. }
  197. num_stream++;
  198. }
  199. else if (memcmp(hdrl_ptr, "strf", 4) == 0)
  200. {
  201. hdrl_ptr += 8;
  202. if (lasttag == 1)
  203. {
  204. // keep a copy of the bitmapinfoheader
  205. memcpy(&m_BitmapInfoHeader, 
  206. hdrl_ptr,
  207. sizeof(BITMAPINFOHEADER));
  208. vids_strf_seen = 1;
  209. }
  210. else if (lasttag == 2)
  211. {
  212. // keep a copy of the WAVEFORMATEX
  213. memcpy(&m_WaveFormatEx,
  214. hdrl_ptr,
  215. sizeof(WAVEFORMATEX));
  216. auds_strf_seen = 1;
  217. }
  218. lasttag = 0;
  219. }
  220. else
  221. {
  222. hdrl_ptr += 8;
  223. lasttag = 0;
  224. }
  225. hdrl_ptr += n;
  226. }
  227. delete[] hdrl_data;
  228. if (!vids_strh_seen || !vids_strf_seen || m_video_frames == 0)
  229. return FALSE;
  230. }
  231. m_video_tag[0] = m_video_strn / 10 + '0';
  232. m_video_tag[1] = m_video_strn % 10 + '0';
  233. m_video_tag[2] = 'd';
  234. m_video_tag[3] = 'b';
  235. // audio tag is set to "99wb" if no audio present 
  236. if (m_WaveFormatEx.nChannels == 0)
  237. m_audio_strn = 99;
  238. m_audio_tag[0] = m_audio_strn / 10 + '0';
  239. m_audio_tag[1] = m_audio_strn % 10 + '0';
  240. m_audio_tag[2] = 'w';
  241. m_audio_tag[3] = 'b';
  242. // check m_idx
  243. if (m_idx == NULL)
  244. return FALSE;
  245. // if the file has an idx1, check if this is relative
  246. // to the start of the file or to the start of the movi list 
  247. m_idx_type = 0;
  248. // search the first videoframe in the idx1 
  249. // and look where it is in the file
  250. for (i = 0; i < m_idx_num; i++)
  251. {
  252. if (memcmp(m_idx[i], m_video_tag, 3) == 0)
  253. break;
  254. }
  255. if (i >= m_idx_num)
  256. return FALSE;
  257. unsigned long pos = str2ulong(m_idx[i] + 8);
  258. unsigned long len = str2ulong(m_idx[i] + 12);
  259. m_AviFile.Seek(pos, FILE_BEGIN);
  260. if (m_AviFile.Read(data, 8) != 8) 
  261. return FALSE;
  262. if (memcmp(data, m_idx[i], 4) == 0 && str2ulong(data + 4) == len)
  263. {
  264. // index from start of file
  265. m_idx_type = 1; 
  266. }
  267. else
  268. {
  269. m_AviFile.Seek(pos + m_movi_start - 4, FILE_BEGIN);
  270. if (m_AviFile.Read(data, 8) != 8)
  271. return FALSE;
  272. if (memcmp(data, m_idx[i], 4) == 0 && str2ulong(data + 4) == len)
  273. {
  274. // index from start of movi list 
  275. m_idx_type = 2; 
  276. }
  277. }
  278. // m_idx_type remains 0 if neither of the two tests above succeeds 
  279. if (m_idx_type == 0)
  280. return FALSE;
  281. return TRUE;
  282. }
  283. //---------------------------------------------------------------------------
  284. // 函数: GetAudioIndex
  285. // 功能: Generate the audio index arrays
  286. // 参数:
  287. // 返回: BOOL
  288. //---------------------------------------------------------------------------
  289. BOOL KLAviFile::GetAudioIndex()
  290. {
  291. int i, nai, ioff, tot;
  292. if (!FillHeader())
  293. return FALSE;
  294. nai = 0;
  295. for (i = 0; i < m_idx_num; i++)
  296. {
  297. if (memcmp(m_idx[i], m_audio_tag, 4) == 0) 
  298. nai++;
  299. }
  300. m_audio_chunks = nai;
  301. if (m_audio_chunks == 0)
  302. return FALSE;
  303. m_audio_index = (audio_index_entry *)new char[nai * sizeof(audio_index_entry)];
  304. if (m_audio_index == 0)
  305. return FALSE;
  306. nai = 0;
  307. tot = 0;
  308. ioff = (m_idx_type == 1)? 8 : m_movi_start + 4;
  309. for (i = 0; i < m_idx_num; i++)
  310. {
  311. if (memcmp(m_idx[i], m_audio_tag, 4) == 0)
  312. {
  313. m_audio_index[nai].pos = str2ulong(m_idx[i] + 8) + ioff;
  314. m_audio_index[nai].len = str2ulong(m_idx[i] + 12);
  315. m_audio_index[nai].tot = tot;
  316. tot += m_audio_index[nai].len;
  317. nai++;
  318. }
  319. }
  320. m_audio_bytes = tot;
  321. delete[] m_idx;
  322. m_idx = NULL;
  323. return TRUE;
  324. }
  325. //---------------------------------------------------------------------------
  326. // 函数: GetVideoIndex
  327. // 功能: generate the video index arrays 
  328. // 参数:
  329. // 返回: BOOL
  330. //---------------------------------------------------------------------------
  331. BOOL KLAviFile::GetVideoIndex()
  332. {
  333. int i, nvi, ioff;
  334. if (!FillHeader())
  335. return FALSE;
  336. nvi = 0;
  337. for (i = 0; i < m_idx_num; i++)
  338. {
  339. if (memcmp(m_idx[i], m_video_tag, 3) == 0) 
  340. nvi++;
  341. }
  342. m_video_frames = nvi;
  343. if (m_video_frames == 0) 
  344. return FALSE;
  345. m_video_index = (video_index_entry *)new char[nvi * sizeof(video_index_entry)];
  346. if (m_video_index == 0)
  347. return FALSE;
  348. nvi = 0;
  349. ioff = (m_idx_type == 1)? 8 : m_movi_start + 4;
  350. for (i = 0; i < m_idx_num; i++)
  351. {
  352. if (memcmp(m_idx[i], m_video_tag, 3) == 0)
  353. {
  354. m_video_index[nvi].flags = str2ulong(m_idx[i] + 4);
  355. m_video_index[nvi].pos  = str2ulong(m_idx[i] + 8) + ioff;
  356. m_video_index[nvi].len  = str2ulong(m_idx[i] + 12);
  357. nvi++;
  358. }
  359. }
  360. m_video_pos = 0;
  361. delete[] m_idx;
  362. m_idx = NULL;
  363. return TRUE;
  364. }
  365. //---------------------------------------------------------------------------
  366. // 函数: VideoStreams
  367. // 功能: Returns the total number of video streams
  368. // 参数:
  369. // 返回:
  370. //---------------------------------------------------------------------------
  371. int KLAviFile::VideoStreams()
  372. {
  373. return m_video_strn;
  374. }
  375. //---------------------------------------------------------------------------
  376. // 函数: AudioStreams
  377. // 功能: Returns the total number of audio streams
  378. // 参数:
  379. // 返回:
  380. //---------------------------------------------------------------------------
  381. int KLAviFile::AudioStreams()
  382. {
  383. return m_audio_strn;
  384. }
  385. //---------------------------------------------------------------------------
  386. // 函数: GetBitmapInfoHeader
  387. // 功能: Returns the bitmapinfoheader associated with the first video stream
  388. // 参数:
  389. // 返回:
  390. //---------------------------------------------------------------------------
  391. void KLAviFile::GetBitmapInfoHeader(PBITMAPINFOHEADER pBmpInfoHead)
  392. {
  393. *pBmpInfoHead = m_BitmapInfoHeader;
  394. }
  395. //---------------------------------------------------------------------------
  396. // 函数: GetWaveFormat
  397. // 功能: Returns the wavefromatex associated with the first audio stream.
  398. // 参数:
  399. // 返回:
  400. //---------------------------------------------------------------------------
  401. void KLAviFile::GetWaveFormat(PWAVEFORMATEX pWavFmt)
  402. {
  403. *pWavFmt = m_WaveFormatEx;
  404. }
  405. //---------------------------------------------------------------------------
  406. // 函数: GetCompressMethod
  407. // 功能: 取得压缩方法
  408. // 参数: method at least 5 char buffer
  409. // 返回: void
  410. //---------------------------------------------------------------------------
  411. void KLAviFile::GetCompressMethod(char* method)
  412. {
  413. memcpy(method, m_compressor, 5);
  414. }
  415. //---------------------------------------------------------------------------
  416. // 函数: NextFrame
  417. // 功能: Reads the next video Frame into buffer
  418. // 参数:
  419. // 返回: return the actual size of the frame
  420. //---------------------------------------------------------------------------
  421. int KLAviFile::NextFrame(unsigned char* buffer)
  422. {
  423. int nNeedBytes;
  424. int nReadBytes;
  425. if (!m_video_index)    
  426. return -1;
  427. if (m_video_pos < 0 || m_video_pos >= m_video_frames)
  428. return -2;
  429. nNeedBytes = m_video_index[m_video_pos].len;
  430. m_AviFile.Seek(m_video_index[m_video_pos].pos, FILE_BEGIN);
  431. nReadBytes = m_AviFile.Read(buffer, nNeedBytes);
  432. m_video_pos++;
  433. return nReadBytes;
  434. }
  435. //---------------------------------------------------------------------------
  436. // 函数: ReadAudio
  437. // 功能: Reads any amount of audio data
  438. // 参数:
  439. // 返回: FIXME : should return the actual number read.
  440. //---------------------------------------------------------------------------
  441. int KLAviFile::ReadAudio(unsigned char* audbuf, int bytes)
  442. {
  443. int nr, pos, left, todo;
  444. if (!m_audio_index)
  445. return -1;
  446. nr = 0; 
  447. // We loop until we parsed enough
  448. // chunks for the amount we want
  449. while (bytes > 0)
  450. {
  451. left = m_audio_index[m_audio_posc].len - m_audio_posb;
  452. if (left == 0)
  453. {
  454. if (m_audio_posc >= m_audio_chunks - 1)
  455. {
  456. return nr;
  457. }
  458. m_audio_posc++;
  459. m_audio_posb = 0;
  460. continue;
  461. }
  462. if (bytes < left)
  463. todo = bytes;
  464. else
  465. todo = left;
  466. pos = m_audio_index[m_audio_posc].pos + m_audio_posb;
  467. m_AviFile.Seek(pos, FILE_BEGIN);
  468. m_AviFile.Read(audbuf + nr, todo);
  469. bytes -= todo;
  470. nr   += todo;
  471. m_audio_posb += todo;
  472. }
  473. return nr;
  474. }
  475. //---------------------------------------------------------------------------
  476. // 函数: FrameRate
  477. // 功能: Return the actual framerate
  478. // 参数:
  479. // 返回: FIXME : should be a double...
  480. //---------------------------------------------------------------------------
  481. int KLAviFile::FrameRate()
  482. {
  483. // Fix for some trailers
  484. if (m_fps == 0)
  485. m_fps = 25;
  486. if (m_fps == 23)
  487. m_fps = 25;
  488. return m_fps;
  489. }
  490. //---------------------------------------------------------------------------
  491. // 函数: CurrentFrame
  492. // 功能:
  493. // 参数:
  494. // 返回:
  495. //---------------------------------------------------------------------------
  496. int KLAviFile::CurrentFrame()
  497. {
  498. return m_video_pos;
  499. }
  500. //---------------------------------------------------------------------------
  501. // 函数: TotalFrames
  502. // 功能: Return the total frames
  503. // 参数:
  504. // 返回:
  505. //---------------------------------------------------------------------------
  506. int KLAviFile::TotalFrames()
  507. {
  508. return m_video_frames;
  509. }
  510. //---------------------------------------------------------------------------
  511. // 函数: VideoSeek
  512. // 功能: Seek to a particular video frame.
  513. // 参数: frame number to seek
  514. // 返回: frame number
  515. //---------------------------------------------------------------------------
  516. int KLAviFile::VideoSeek(int percent)
  517. {
  518. int frame;
  519. if (!m_video_index)
  520. return -1; 
  521. // limit to 0-100
  522. if (percent < 0)
  523. percent = 0;
  524. if (percent > 100)
  525. frame = 100;
  526. // compute the desired frame number
  527. frame = percent * m_video_frames / 100;
  528. // and go to the next keyframe.
  529. while (!IsKeyframe(frame))
  530. {
  531. frame++;
  532. }
  533. m_video_pos = frame;
  534. return frame;
  535. }
  536. //---------------------------------------------------------------------------
  537. // 函数: AudioSeek
  538. // 功能: Seek to a particular audio frame.
  539. // 参数: percet
  540. // 返回:
  541. //---------------------------------------------------------------------------
  542. int KLAviFile::AudioSeek(int percent)
  543. {
  544. int frame;
  545. int bytes;
  546. int n0, n1, n;
  547. if (!m_audio_index)
  548. return -1; 
  549. // limit to 0-100
  550. if (percent < 0)
  551. percent = 0;
  552. if (percent > 100)
  553. frame = 100;
  554. // compute the desired frame number
  555. frame = percent * m_video_frames / 100;
  556. // and set audio position
  557. bytes = frame * m_audio_bytes / m_video_frames;
  558. bytes += bytes % 4;
  559. if (bytes < 0) 
  560. bytes = 0;
  561. n0 = 0;
  562. n1 = m_audio_chunks;
  563. while (n0 < n1 - 1)
  564. {
  565. n = (n0 + n1) / 2;
  566. if (m_audio_index[n].tot > bytes)
  567. n1 = n;
  568. else
  569. n0 = n;
  570. }
  571. m_audio_posc = n0;
  572. if (m_audio_index[n0].len > 1000)
  573. {
  574. m_audio_posb = bytes - m_audio_index[n0].tot;
  575. }
  576. else
  577. {
  578. m_audio_posb = 0;
  579. }
  580. return frame;
  581. }
  582. //---------------------------------------------------------------------------
  583. // 函数: IsKeyFrame
  584. // 功能:
  585. // 参数:
  586. // 返回:
  587. //---------------------------------------------------------------------------
  588. BOOL KLAviFile::IsKeyframe(int frame)
  589. {
  590. // we still return 1 to avoid looping on waiting for a keyframe.
  591. if (!m_video_index)    
  592. return 1; 
  593. if (frame < 0)
  594. frame = 0;
  595. return m_video_index[frame].flags & AVIIF_KEYFRAME;
  596. }
  597. //---------------------------------------------------------------------------
  598. // 函数: NextKeyFrame
  599. // 功能:
  600. // 参数:
  601. // 返回:
  602. //---------------------------------------------------------------------------
  603. int KLAviFile::NextKeyFrame()
  604. {
  605. // Allways increment by one
  606. m_video_pos++;
  607. while (!IsKeyframe(m_video_pos) && m_video_pos < m_video_frames)
  608. m_video_pos++;
  609. return 1;
  610. }
  611. //---------------------------------------------------------------------------
  612. // 函数: PreviousKeyFrame
  613. // 功能:
  614. // 参数:
  615. // 返回:
  616. //---------------------------------------------------------------------------
  617. int KLAviFile::PreviousKeyFrame()
  618. {
  619. // Allways decrement by two since we read the last frame
  620. m_video_pos--;
  621. m_video_pos--;
  622. while (!IsKeyframe(m_video_pos) && m_video_pos > 0)
  623. m_video_pos--;
  624. return 1;
  625. }
  626. //---------------------------------------------------------------------------
  627. // 函数: Rewind
  628. // 功能:
  629. // 参数:
  630. // 返回:
  631. //---------------------------------------------------------------------------
  632. int KLAviFile::Rewind()
  633. {
  634. m_video_pos  = 0;
  635. m_audio_posc = 0;
  636. m_audio_posb = 0;
  637. return 1;
  638. }
  639. //---------------------------------------------------------------------------
  640. // 函数: Close
  641. // 功能:
  642. // 参数:
  643. // 返回:
  644. //---------------------------------------------------------------------------
  645. void KLAviFile::Close()
  646. {
  647. if (m_video_index)
  648. {
  649. delete[] m_video_index;
  650. m_video_index = NULL;
  651. }
  652. if (m_audio_index)
  653. {
  654. delete[] m_audio_index;
  655. m_audio_index = NULL;
  656. }
  657. }