MpaSplitterFile.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:8k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "StdAfx.h"
  22. #include <mmreg.h>
  23. #include "MpaSplitterFile.h"
  24. #include <initguid.h>
  25. #include "........includemoreuuids.h"
  26. //
  27. static const LPCTSTR s_genre[] = 
  28. {
  29. _T("Blues"), _T("Classic Rock"), _T("Country"), _T("Dance"),
  30. _T("Disco"), _T("Funk"), _T("Grunge"), _T("Hip-Hop"),
  31. _T("Jazz"), _T("Metal"), _T("New Age"), _T("Oldies"), 
  32. _T("Other"), _T("Pop"), _T("R&B"), _T("Rap"),
  33. _T("Reggae"), _T("Rock"), _T("Techno"), _T("Industrial"), 
  34. _T("Alternative"), _T("Ska"), _T("Death Metal"), _T("Pranks"),
  35. _T("Soundtrack"), _T("Euro-Techno"), _T("Ambient"), _T("Trip-Hop"),
  36. _T("Vocal"), _T("Jazz+Funk"), _T("Fusion"), _T("Trance"),
  37. _T("Classical"), _T("Instrumental"), _T("Acid"), _T("House"), 
  38. _T("Game"), _T("Sound Clip"), _T("Gospel"), _T("Noise"),
  39. _T("Alternative Rock"), _T("Bass"), _T("Soul"), _T("Punk"), 
  40. _T("Space"), _T("Meditative"), _T("Instrumental Pop"), _T("Instrumental Rock"),
  41. _T("Ethnic"), _T("Gothic"), _T("Darkwave"), _T("Techno-Industrial"),
  42. _T("Electronic"), _T("Pop-Folk"), _T("Eurodance"), _T("Dream"),
  43. _T("Southern Rock"), _T("Comedy"), _T("Cult"), _T("Gangsta"),
  44. _T("Top 40"), _T("Christian Rap"), _T("Pop/Funk"), _T("Jungle"),
  45. _T("Native US"), _T("Cabaret"), _T("New Wave"), _T("Psychadelic"), 
  46. _T("Rave"), _T("Showtunes"), _T("Trailer"), _T("Lo-Fi"),
  47. _T("Tribal"), _T("Acid Punk"), _T("Acid Jazz"), _T("Polka"),
  48. _T("Retro"), _T("Musical"), _T("Rock & Roll"), _T("Hard Rock"),
  49. _T("Folk"), _T("Folk-Rock"), _T("National Folk"), _T("Swing"),
  50. _T("Fast Fusion"), _T("Bebob"), _T("Latin"), _T("Revival"),
  51. _T("Celtic"), _T("Bluegrass"), _T("Avantgarde"), _T("Gothic Rock"), 
  52. _T("Progressive Rock"), _T("Psychedelic Rock"), _T("Symphonic Rock"), _T("Slow Rock"),
  53. _T("Big Band"), _T("Chorus"), _T("Easy Listening"), _T("Acoustic"),
  54. _T("Humour"), _T("Speech"), _T("Chanson"), _T("Opera"), 
  55. _T("Chamber Music"), _T("Sonata"), _T("Symphony"), _T("Booty Bass"), 
  56. _T("Primus"), _T("Porn Groove"), _T("Satire"), _T("Slow Jam"),
  57. _T("Club"), _T("Tango"), _T("Samba"), _T("Folklore"), 
  58. _T("Ballad"), _T("Power Ballad"), _T("Rhytmic Soul"), _T("Freestyle"),
  59. _T("Duet"), _T("Punk Rock"), _T("Drum Solo"), _T("Acapella"), 
  60. _T("Euro-House"), _T("Dance Hall"), _T("Goa"), _T("Drum & Bass"),
  61. _T("Club-House"), _T("Hardcore"), _T("Terror"), _T("Indie"),
  62. _T("BritPop"), _T("Negerpunk"), _T("Polsk Punk"), _T("Beat"),
  63. _T("Christian Gangsta"), _T("Heavy Metal"), _T("Black Metal"), 
  64. _T("Crossover"), _T("Contemporary C"), _T("Christian Rock"), _T("Merengue"), _T("Salsa"),
  65. _T("Thrash Metal"), _T("Anime"), _T("JPop"), _T("SynthPop"),
  66. };
  67. //
  68. CMpaSplitterFile::CMpaSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr)
  69. : CBaseSplitterFileEx(pAsyncReader, hr)
  70. , m_mode(none)
  71. , m_rtDuration(0)
  72. , m_startpos(0)
  73. , m_endpos(0)
  74. , m_totalbps(0)
  75. {
  76. if(SUCCEEDED(hr)) hr = Init();
  77. }
  78. HRESULT CMpaSplitterFile::Init()
  79. {
  80. m_startpos = 0;
  81. m_endpos = GetLength();
  82. if(m_endpos > 128)
  83. {
  84. Seek(m_endpos - 128);
  85. if(BitRead(24) == 'TAG')
  86. {
  87. m_endpos -= 128;
  88. CStringA str;
  89. // title
  90. Read((BYTE*)str.GetBufferSetLength(30), 30);
  91. m_tags['TIT2'] = CString(str).Trim();
  92. // artist
  93. Read((BYTE*)str.GetBufferSetLength(30), 30);
  94. m_tags['TPE1'] = CString(str).Trim();
  95. // album
  96. Read((BYTE*)str.GetBufferSetLength(30), 30);
  97. m_tags['TALB'] = CString(str).Trim();
  98. // year
  99. Read((BYTE*)str.GetBufferSetLength(4), 4);
  100. m_tags['TYER'] = CString(str).Trim();
  101. // comment
  102. Read((BYTE*)str.GetBufferSetLength(30), 30);
  103. m_tags['COMM'] = CString(str).Trim(); 
  104. // track
  105. LPCSTR s = str;
  106. if(s[28] == 0 && s[29] != 0)
  107. m_tags['TRCK'].Format(_T("%d"), s[29]); 
  108. // genre
  109. BYTE genre = (BYTE)BitRead(8);
  110. if(genre < countof(s_genre))
  111. m_tags['TCON'] = s_genre[genre];
  112. }
  113. }
  114. Seek(0);
  115. if(BitRead(24, true) == 'ID3')
  116. {
  117. Seek(3);
  118. BYTE major = (BYTE)BitRead(8);
  119. BYTE revision = (BYTE)BitRead(8);
  120. BYTE flags = (BYTE)BitRead(8);
  121. DWORD size = 0;
  122. if(BitRead(1) != 0) return E_FAIL;
  123. size |= BitRead(7) << 21;
  124. if(BitRead(1) != 0) return E_FAIL;
  125. size |= BitRead(7) << 14;
  126. if(BitRead(1) != 0) return E_FAIL;
  127. size |= BitRead(7) << 7;
  128. if(BitRead(1) != 0) return E_FAIL;
  129. size |= BitRead(7);
  130. m_startpos = GetPos() + size;
  131. // TODO: read tags
  132. }
  133. __int64 startpos;
  134. int nBytesPerSec = 0;
  135. Seek(m_startpos);
  136. if(m_mode == none && Read(m_mpahdr, min(m_endpos - GetPos(), 0x100), true, &m_mt))
  137. {
  138. m_mode = mpa;
  139. startpos = GetPos() - 4;
  140. nBytesPerSec = m_mpahdr.nBytesPerSec;
  141. // make sure the first frame is followed by another of the same kind (validates m_mpahdr basically)
  142. Seek(startpos + m_mpahdr.FrameSize);
  143. if(!Sync(4)) m_mode = none;
  144. }
  145. Seek(m_startpos);
  146. if(m_mode == none && Read(m_aachdr, min(m_endpos - GetPos(), 0x100), &m_mt))
  147. {
  148. m_mode = mp4a;
  149. startpos = GetPos() - (m_aachdr.fcrc?7:9);
  150. nBytesPerSec = ((WAVEFORMATEX*)m_mt.Format())->nAvgBytesPerSec;
  151. // make sure the first frame is followed by another of the same kind (validates m_aachdr basically)
  152. Seek(startpos + m_aachdr.aac_frame_length);
  153. if(!Sync(9)) m_mode = none;
  154. }
  155. if(m_mode == none)
  156. return E_FAIL;
  157. m_startpos = startpos;
  158. // initial duration, may not be correct (VBR files...)
  159. m_rtDuration = 10000000i64 * (m_endpos - m_startpos) / nBytesPerSec;
  160. return S_OK;
  161. }
  162. bool CMpaSplitterFile::Sync(int limit)
  163. {
  164. int FrameSize;
  165. REFERENCE_TIME rtDuration;
  166. return Sync(FrameSize, rtDuration, limit);
  167. }
  168. bool CMpaSplitterFile::Sync(int& FrameSize, REFERENCE_TIME& rtDuration, int limit)
  169. {
  170. __int64 endpos = min(m_endpos, GetPos() + limit);
  171. if(m_mode == mpa)
  172. {
  173. while(GetPos() <= endpos - 4)
  174. {
  175. mpahdr h;
  176. if(Read(h, endpos - GetPos(), true)
  177. && m_mpahdr.version == h.version
  178. && m_mpahdr.layer == h.layer
  179. && m_mpahdr.channels == h.channels)
  180. {
  181. Seek(GetPos() - 4);
  182. AdjustDuration(h.nBytesPerSec);
  183. FrameSize = h.FrameSize;
  184. rtDuration = h.rtDuration;
  185. return true;
  186. }
  187. }
  188. }
  189. else if(m_mode == mp4a)
  190. {
  191. while(GetPos() <= endpos - 9)
  192. {
  193. aachdr h;
  194. if(Read(h, endpos - GetPos())
  195. && m_aachdr.version == h.version
  196. && m_aachdr.layer == h.layer
  197. && m_aachdr.channels == h.channels)
  198. {
  199. Seek(GetPos() - (h.fcrc?7:9));
  200. AdjustDuration(h.nBytesPerSec);
  201. Seek(GetPos() + (h.fcrc?7:9));
  202. FrameSize = h.FrameSize;
  203. rtDuration = h.rtDuration;
  204. return true;
  205. }
  206. }
  207. }
  208. return false;
  209. }
  210. void CMpaSplitterFile::AdjustDuration(int nBytesPerSec)
  211. {
  212. ASSERT(nBytesPerSec);
  213. int rValue;
  214. if(!m_pos2bps.Lookup(GetPos(), rValue))
  215. {
  216. m_totalbps += nBytesPerSec;
  217. if(!m_totalbps) return;
  218. m_pos2bps.SetAt(GetPos(), nBytesPerSec);
  219. __int64 avgbps = m_totalbps / m_pos2bps.GetCount();
  220. m_rtDuration = 10000000i64 * (m_endpos - m_startpos) / avgbps;
  221. }
  222. }