00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include <mmreg.h>
00024 #include "MpaSplitterFile.h"
00025
00026 #include <initguid.h>
00027 #include "..\..\..\..\include\moreuuids.h"
00028
00029
00030
00031 static const LPCTSTR s_genre[] =
00032 {
00033 _T("Blues"), _T("Classic Rock"), _T("Country"), _T("Dance"),
00034 _T("Disco"), _T("Funk"), _T("Grunge"), _T("Hip-Hop"),
00035 _T("Jazz"), _T("Metal"), _T("New Age"), _T("Oldies"),
00036 _T("Other"), _T("Pop"), _T("R&B"), _T("Rap"),
00037 _T("Reggae"), _T("Rock"), _T("Techno"), _T("Industrial"),
00038 _T("Alternative"), _T("Ska"), _T("Death Metal"), _T("Pranks"),
00039 _T("Soundtrack"), _T("Euro-Techno"), _T("Ambient"), _T("Trip-Hop"),
00040 _T("Vocal"), _T("Jazz+Funk"), _T("Fusion"), _T("Trance"),
00041 _T("Classical"), _T("Instrumental"), _T("Acid"), _T("House"),
00042 _T("Game"), _T("Sound Clip"), _T("Gospel"), _T("Noise"),
00043 _T("Alternative Rock"), _T("Bass"), _T("Soul"), _T("Punk"),
00044 _T("Space"), _T("Meditative"), _T("Instrumental Pop"), _T("Instrumental Rock"),
00045 _T("Ethnic"), _T("Gothic"), _T("Darkwave"), _T("Techno-Industrial"),
00046 _T("Electronic"), _T("Pop-Folk"), _T("Eurodance"), _T("Dream"),
00047 _T("Southern Rock"), _T("Comedy"), _T("Cult"), _T("Gangsta"),
00048 _T("Top 40"), _T("Christian Rap"), _T("Pop/Funk"), _T("Jungle"),
00049 _T("Native US"), _T("Cabaret"), _T("New Wave"), _T("Psychadelic"),
00050 _T("Rave"), _T("Showtunes"), _T("Trailer"), _T("Lo-Fi"),
00051 _T("Tribal"), _T("Acid Punk"), _T("Acid Jazz"), _T("Polka"),
00052 _T("Retro"), _T("Musical"), _T("Rock & Roll"), _T("Hard Rock"),
00053 _T("Folk"), _T("Folk-Rock"), _T("National Folk"), _T("Swing"),
00054 _T("Fast Fusion"), _T("Bebob"), _T("Latin"), _T("Revival"),
00055 _T("Celtic"), _T("Bluegrass"), _T("Avantgarde"), _T("Gothic Rock"),
00056 _T("Progressive Rock"), _T("Psychedelic Rock"), _T("Symphonic Rock"), _T("Slow Rock"),
00057 _T("Big Band"), _T("Chorus"), _T("Easy Listening"), _T("Acoustic"),
00058 _T("Humour"), _T("Speech"), _T("Chanson"), _T("Opera"),
00059 _T("Chamber Music"), _T("Sonata"), _T("Symphony"), _T("Booty Bass"),
00060 _T("Primus"), _T("Porn Groove"), _T("Satire"), _T("Slow Jam"),
00061 _T("Club"), _T("Tango"), _T("Samba"), _T("Folklore"),
00062 _T("Ballad"), _T("Power Ballad"), _T("Rhytmic Soul"), _T("Freestyle"),
00063 _T("Duet"), _T("Punk Rock"), _T("Drum Solo"), _T("Acapella"),
00064 _T("Euro-House"), _T("Dance Hall"), _T("Goa"), _T("Drum & Bass"),
00065 _T("Club-House"), _T("Hardcore"), _T("Terror"), _T("Indie"),
00066 _T("BritPop"), _T("Negerpunk"), _T("Polsk Punk"), _T("Beat"),
00067 _T("Christian Gangsta"), _T("Heavy Metal"), _T("Black Metal"),
00068 _T("Crossover"), _T("Contemporary C"), _T("Christian Rock"), _T("Merengue"), _T("Salsa"),
00069 _T("Thrash Metal"), _T("Anime"), _T("JPop"), _T("SynthPop"),
00070 };
00071
00072
00073
00074 CMpaSplitterFile::CMpaSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr)
00075 : CBaseSplitterFileEx(pAsyncReader, hr)
00076 , m_mode(none)
00077 , m_rtDuration(0)
00078 , m_startpos(0)
00079 , m_endpos(0)
00080 , m_totalbps(0)
00081 {
00082 if(SUCCEEDED(hr)) hr = Init();
00083 }
00084
00085 HRESULT CMpaSplitterFile::Init()
00086 {
00087 m_startpos = 0;
00088 m_endpos = GetLength();
00089
00090 if(m_endpos > 128)
00091 {
00092 Seek(m_endpos - 128);
00093
00094 if(BitRead(24) == 'TAG')
00095 {
00096 m_endpos -= 128;
00097
00098 CStringA str;
00099
00100
00101 Read((BYTE*)str.GetBufferSetLength(30), 30);
00102 m_tags['TIT2'] = CString(str).Trim();
00103
00104
00105 Read((BYTE*)str.GetBufferSetLength(30), 30);
00106 m_tags['TPE1'] = CString(str).Trim();
00107
00108
00109 Read((BYTE*)str.GetBufferSetLength(30), 30);
00110 m_tags['TALB'] = CString(str).Trim();
00111
00112
00113 Read((BYTE*)str.GetBufferSetLength(4), 4);
00114 m_tags['TYER'] = CString(str).Trim();
00115
00116
00117 Read((BYTE*)str.GetBufferSetLength(30), 30);
00118 m_tags['COMM'] = CString(str).Trim();
00119
00120
00121 LPCSTR s = str;
00122 if(s[28] == 0 && s[29] != 0)
00123 m_tags['TRCK'].Format(_T("%d"), s[29]);
00124
00125
00126 BYTE genre = (BYTE)BitRead(8);
00127 if(genre < countof(s_genre))
00128 m_tags['TCON'] = s_genre[genre];
00129 }
00130 }
00131
00132 Seek(0);
00133
00134 if(BitRead(24, true) == 'ID3')
00135 {
00136 Seek(3);
00137
00138 BYTE major = (BYTE)BitRead(8);
00139 BYTE revision = (BYTE)BitRead(8);
00140 BYTE flags = (BYTE)BitRead(8);
00141 DWORD size = 0;
00142 if(BitRead(1) != 0) return E_FAIL;
00143 size |= BitRead(7) << 21;
00144 if(BitRead(1) != 0) return E_FAIL;
00145 size |= BitRead(7) << 14;
00146 if(BitRead(1) != 0) return E_FAIL;
00147 size |= BitRead(7) << 7;
00148 if(BitRead(1) != 0) return E_FAIL;
00149 size |= BitRead(7);
00150
00151 m_startpos = GetPos() + size;
00152
00153
00154 }
00155
00156 __int64 startpos;
00157 int nBytesPerSec = 0;
00158
00159 Seek(m_startpos);
00160
00161 if(m_mode == none && Read(m_mpahdr, min(m_endpos - GetPos(), 0x100), true, &m_mt))
00162 {
00163 m_mode = mpa;
00164
00165 startpos = GetPos() - 4;
00166 nBytesPerSec = m_mpahdr.nBytesPerSec;
00167
00168
00169 Seek(startpos + m_mpahdr.FrameSize);
00170 if(!Sync(4)) m_mode = none;
00171 }
00172
00173 Seek(m_startpos);
00174
00175 if(m_mode == none && Read(m_aachdr, min(m_endpos - GetPos(), 0x100), &m_mt))
00176 {
00177 m_mode = mp4a;
00178
00179 startpos = GetPos() - (m_aachdr.fcrc?7:9);
00180 nBytesPerSec = ((WAVEFORMATEX*)m_mt.Format())->nAvgBytesPerSec;
00181
00182
00183 Seek(startpos + m_aachdr.aac_frame_length);
00184 if(!Sync(9)) m_mode = none;
00185 }
00186
00187 if(m_mode == none)
00188 return E_FAIL;
00189
00190 m_startpos = startpos;
00191
00192
00193 m_rtDuration = 10000000i64 * (m_endpos - m_startpos) / nBytesPerSec;
00194
00195 return S_OK;
00196 }
00197
00198 bool CMpaSplitterFile::Sync(int limit)
00199 {
00200 int FrameSize;
00201 REFERENCE_TIME rtDuration;
00202 return Sync(FrameSize, rtDuration, limit);
00203 }
00204
00205 bool CMpaSplitterFile::Sync(int& FrameSize, REFERENCE_TIME& rtDuration, int limit)
00206 {
00207 __int64 endpos = min(m_endpos, GetPos() + limit);
00208
00209 if(m_mode == mpa)
00210 {
00211 while(GetPos() <= endpos - 4)
00212 {
00213 mpahdr h;
00214
00215 if(Read(h, endpos - GetPos(), true)
00216 && m_mpahdr.version == h.version
00217 && m_mpahdr.layer == h.layer
00218 && m_mpahdr.channels == h.channels)
00219 {
00220 Seek(GetPos() - 4);
00221 AdjustDuration(h.nBytesPerSec);
00222
00223 FrameSize = h.FrameSize;
00224 rtDuration = h.rtDuration;
00225
00226 return true;
00227 }
00228 }
00229 }
00230 else if(m_mode == mp4a)
00231 {
00232 while(GetPos() <= endpos - 9)
00233 {
00234 aachdr h;
00235
00236 if(Read(h, endpos - GetPos())
00237 && m_aachdr.version == h.version
00238 && m_aachdr.layer == h.layer
00239 && m_aachdr.channels == h.channels)
00240 {
00241 Seek(GetPos() - (h.fcrc?7:9));
00242 AdjustDuration(h.nBytesPerSec);
00243 Seek(GetPos() + (h.fcrc?7:9));
00244
00245 FrameSize = h.FrameSize;
00246 rtDuration = h.rtDuration;
00247
00248 return true;
00249 }
00250 }
00251 }
00252
00253 return false;
00254 }
00255
00256 void CMpaSplitterFile::AdjustDuration(int nBytesPerSec)
00257 {
00258 ASSERT(nBytesPerSec);
00259
00260 int rValue;
00261 if(!m_pos2bps.Lookup(GetPos(), rValue))
00262 {
00263 m_totalbps += nBytesPerSec;
00264 if(!m_totalbps) return;
00265 m_pos2bps.SetAt(GetPos(), nBytesPerSec);
00266 __int64 avgbps = m_totalbps / m_pos2bps.GetCount();
00267 m_rtDuration = 10000000i64 * (m_endpos - m_startpos) / avgbps;
00268 }
00269 }