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 <initguid.h>
00024 #include "cddareader.h"
00025 #include "..\..\..\DSUtil\DSUtil.h"
00026
00027 #define RAW_SECTOR_SIZE 2352
00028 #define MSF2UINT(hgs) ((hgs[1]*4500)+(hgs[2]*75)+(hgs[3]))
00029
00030 #ifdef REGISTER_FILTER
00031
00032 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
00033 {
00034 {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE},
00035 };
00036
00037 const AMOVIESETUP_PIN sudOpPin[] =
00038 {
00039 {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut},
00040 };
00041
00042 const AMOVIESETUP_FILTER sudFilter[] =
00043 {
00044 {&__uuidof(CCDDAReader), L"CDDA Reader", MERIT_UNLIKELY, countof(sudOpPin), sudOpPin}
00045 };
00046
00047 CFactoryTemplate g_Templates[] =
00048 {
00049 {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CCDDAReader>, NULL, &sudFilter[0]}
00050 };
00051
00052 int g_cTemplates = countof(g_Templates);
00053
00054 STDAPI DllRegisterServer()
00055 {
00056 if(GetVersion()&0x80000000)
00057 {
00058 ::MessageBox(NULL, _T("Sorry, this will only run on Windows NT based operating system."), _T("CDDA Reader"), MB_OK);
00059 return E_NOTIMPL;
00060 }
00061
00062 SetRegKeyValue(
00063 _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"),
00064 _T("0"), _T("0,4,,52494646,8,4,,43444441"));
00065
00066 SetRegKeyValue(
00067 _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"),
00068 _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"));
00069
00070 SetRegKeyValue(
00071 _T("Media Type\\Extensions"), _T(".cda"),
00072 _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"));
00073
00074 return AMovieDllRegisterServer2(TRUE);
00075 }
00076
00077 STDAPI DllUnregisterServer()
00078 {
00079 DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"));
00080 DeleteRegKey(_T("Media Type\\Extensions"), _T(".cda"));
00081
00082 return AMovieDllRegisterServer2(FALSE);
00083 }
00084
00085 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
00086
00087 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
00088 {
00089 return DllEntryPoint((HINSTANCE)hModule, dwReason, 0);
00090 }
00091
00092 #endif
00093
00094
00095
00096
00097
00098 CCDDAReader::CCDDAReader(IUnknown* pUnk, HRESULT* phr)
00099 : CAsyncReader(NAME("CCDDAReader"), pUnk, &m_stream, phr, __uuidof(this))
00100 {
00101 if(phr) *phr = S_OK;
00102
00103 if(GetVersion()&0x80000000)
00104 {
00105 if(phr) *phr = E_NOTIMPL;
00106 return;
00107 }
00108 }
00109
00110 CCDDAReader::~CCDDAReader()
00111 {
00112 }
00113
00114 STDMETHODIMP CCDDAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00115 {
00116 CheckPointer(ppv, E_POINTER);
00117
00118 return
00119 QI(IFileSourceFilter)
00120 QI2(IAMMediaContent)
00121 __super::NonDelegatingQueryInterface(riid, ppv);
00122 }
00123
00124
00125
00126 STDMETHODIMP CCDDAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt)
00127 {
00128 if(!m_stream.Load(pszFileName))
00129 return E_FAIL;
00130
00131 m_fn = pszFileName;
00132
00133 CMediaType mt;
00134 mt.majortype = MEDIATYPE_Stream;
00135 mt.subtype = MEDIASUBTYPE_WAVE;
00136 m_mt = mt;
00137
00138 return S_OK;
00139 }
00140
00141 STDMETHODIMP CCDDAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt)
00142 {
00143 CheckPointer(ppszFileName, E_POINTER);
00144
00145 if(!(*ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength()+1)*sizeof(WCHAR))))
00146 return E_OUTOFMEMORY;
00147
00148 wcscpy(*ppszFileName, m_fn);
00149
00150 return S_OK;
00151 }
00152
00153
00154
00155 STDMETHODIMP CCDDAReader::GetTypeInfoCount(UINT* pctinfo) {return E_NOTIMPL;}
00156 STDMETHODIMP CCDDAReader::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) {return E_NOTIMPL;}
00157 STDMETHODIMP CCDDAReader::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) {return E_NOTIMPL;}
00158 STDMETHODIMP CCDDAReader::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) {return E_NOTIMPL;}
00159
00160 STDMETHODIMP CCDDAReader::get_AuthorName(BSTR* pbstrAuthorName)
00161 {
00162 CheckPointer(pbstrAuthorName, E_POINTER);
00163 CString str = m_stream.m_trackArtist;
00164 if(str.IsEmpty()) str = m_stream.m_discArtist;
00165 *pbstrAuthorName = str.AllocSysString();
00166 return S_OK;
00167 }
00168
00169 STDMETHODIMP CCDDAReader::get_Title(BSTR* pbstrTitle)
00170 {
00171 CheckPointer(pbstrTitle, E_POINTER);
00172 CString str = m_stream.m_trackTitle;
00173 if(str.IsEmpty()) str = m_stream.m_discTitle;
00174 *pbstrTitle = str.AllocSysString();
00175 return S_OK;
00176 }
00177
00178 STDMETHODIMP CCDDAReader::get_Rating(BSTR* pbstrRating) {return E_NOTIMPL;}
00179 STDMETHODIMP CCDDAReader::get_Description(BSTR* pbstrDescription) {return E_NOTIMPL;}
00180 STDMETHODIMP CCDDAReader::get_Copyright(BSTR* pbstrCopyright) {return E_NOTIMPL;}
00181 STDMETHODIMP CCDDAReader::get_BaseURL(BSTR* pbstrBaseURL) {return E_NOTIMPL;}
00182 STDMETHODIMP CCDDAReader::get_LogoURL(BSTR* pbstrLogoURL) {return E_NOTIMPL;}
00183 STDMETHODIMP CCDDAReader::get_LogoIconURL(BSTR* pbstrLogoURL) {return E_NOTIMPL;}
00184 STDMETHODIMP CCDDAReader::get_WatermarkURL(BSTR* pbstrWatermarkURL) {return E_NOTIMPL;}
00185 STDMETHODIMP CCDDAReader::get_MoreInfoURL(BSTR* pbstrMoreInfoURL) {return E_NOTIMPL;}
00186 STDMETHODIMP CCDDAReader::get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) {return E_NOTIMPL;}
00187 STDMETHODIMP CCDDAReader::get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) {return E_NOTIMPL;}
00188 STDMETHODIMP CCDDAReader::get_MoreInfoText(BSTR* pbstrMoreInfoText) {return E_NOTIMPL;}
00189
00190
00191
00192 CCDDAStream::CCDDAStream()
00193 {
00194 m_hDrive = INVALID_HANDLE_VALUE;
00195
00196 m_llPosition = m_llLength = 0;
00197
00198 memset(&m_TOC, 0, sizeof(m_TOC));
00199 m_nStartSector = m_nStopSector = 0;
00200
00201 memset(&m_header, 0, sizeof(m_header));
00202 m_header.riff.hdr.chunkID = RIFFID;
00203 m_header.riff.WAVE = WAVEID;
00204 m_header.frm.hdr.chunkID = FormatID;
00205 m_header.frm.hdr.chunkSize = sizeof(m_header.frm.pcm);
00206 m_header.frm.pcm.wf.wFormatTag = WAVE_FORMAT_PCM;
00207 m_header.frm.pcm.wf.nSamplesPerSec = 44100;
00208 m_header.frm.pcm.wf.nChannels = 2;
00209 m_header.frm.pcm.wBitsPerSample = 16;
00210 m_header.frm.pcm.wf.nBlockAlign = m_header.frm.pcm.wf.nChannels * m_header.frm.pcm.wBitsPerSample / 8;
00211 m_header.frm.pcm.wf.nAvgBytesPerSec = m_header.frm.pcm.wf.nSamplesPerSec * m_header.frm.pcm.wf.nBlockAlign;
00212 m_header.data.hdr.chunkID = DataID;
00213 }
00214
00215 CCDDAStream::~CCDDAStream()
00216 {
00217 if(m_hDrive != INVALID_HANDLE_VALUE)
00218 {
00219 CloseHandle(m_hDrive);
00220 m_hDrive = INVALID_HANDLE_VALUE;
00221 }
00222 }
00223
00224 bool CCDDAStream::Load(const WCHAR* fnw)
00225 {
00226 CString path(fnw);
00227
00228 int iDriveLetter = path.Find(_T(":\\"))-1;
00229 int iTrackIndex = CString(path).MakeLower().Find(_T(".cda"))-1;
00230 if(iDriveLetter < 0 || iTrackIndex <= iDriveLetter)
00231 return(false);
00232
00233 CString drive = CString(_T("\\\\.\\")) + path[iDriveLetter] + _T(":");
00234 while(iTrackIndex > 0 && _istdigit(path[iTrackIndex-1])) iTrackIndex--;
00235 if(1 != _stscanf(path.Mid(iTrackIndex), _T("%d"), &iTrackIndex))
00236 return(false);
00237
00238 if(m_hDrive != INVALID_HANDLE_VALUE)
00239 {
00240 CloseHandle(m_hDrive);
00241 m_hDrive = INVALID_HANDLE_VALUE;
00242 }
00243
00244 m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, NULL,
00245 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)NULL);
00246 if(m_hDrive == INVALID_HANDLE_VALUE)
00247 {
00248 return(false);
00249 }
00250
00251 DWORD BytesReturned;
00252 if(!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC, NULL, 0, &m_TOC, sizeof(m_TOC), &BytesReturned, 0)
00253 || !(m_TOC.FirstTrack <= iTrackIndex && iTrackIndex <= m_TOC.LastTrack))
00254 {
00255 CloseHandle(m_hDrive);
00256 m_hDrive = INVALID_HANDLE_VALUE;
00257 return(false);
00258 }
00259
00260
00261 m_TOC.TrackData[iTrackIndex-1].Control &= 5;
00262 if(!(m_TOC.TrackData[iTrackIndex-1].Control == 0 || m_TOC.TrackData[iTrackIndex-1].Control == 1))
00263 {
00264 CloseHandle(m_hDrive);
00265 m_hDrive = INVALID_HANDLE_VALUE;
00266 return(false);
00267 }
00268
00269 if(m_TOC.TrackData[iTrackIndex-1].Control&8)
00270 m_header.frm.pcm.wf.nChannels = 4;
00271
00272 m_nStartSector = MSF2UINT(m_TOC.TrackData[iTrackIndex-1].Address) - 150;
00273 m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150;
00274
00275 m_llLength = (m_nStopSector-m_nStartSector)*RAW_SECTOR_SIZE;
00276
00277 m_header.riff.hdr.chunkSize = (long)(m_llLength + sizeof(m_header) - 8);
00278 m_header.data.hdr.chunkSize = (long)(m_llLength);
00279
00280 do
00281 {
00282 CDROM_READ_TOC_EX TOCEx;
00283 memset(&TOCEx, 0, sizeof(TOCEx));
00284 TOCEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT;
00285 TOCEx.SessionTrack = iTrackIndex;
00286 WORD size = 0;
00287 ASSERT(MINIMUM_CDROM_READ_TOC_EX_SIZE == sizeof(size));
00288 if(!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), &size, sizeof(size), &BytesReturned, 0))
00289 break;
00290
00291 size = ((size>>8)|(size<<8)) + sizeof(size);
00292
00293 CAutoVectorPtr<BYTE> pCDTextData;
00294 pCDTextData.Allocate(size);
00295 memset(pCDTextData, 0, size);
00296
00297 if(!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), pCDTextData, size, &BytesReturned, 0))
00298 break;
00299
00300 size = (WORD)(BytesReturned - sizeof(CDROM_TOC_CD_TEXT_DATA));
00301 CDROM_TOC_CD_TEXT_DATA_BLOCK* pDesc = ((CDROM_TOC_CD_TEXT_DATA*)(BYTE*)pCDTextData)->Descriptors;
00302
00303 CStringArray str[16];
00304 for(int i = 0; i < 16; i++) str[i].SetSize(1+m_TOC.LastTrack);
00305 CString last;
00306
00307 for(int i = 0; size >= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK); i++, size -= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK), pDesc++)
00308 {
00309 if(pDesc->TrackNumber > m_TOC.LastTrack)
00310 continue;
00311
00312 const int len = countof(pDesc->Text);
00313
00314 CString text = !pDesc->Unicode
00315 ? CString(CStringA((CHAR*)pDesc->Text, len))
00316 : CString(CStringW((WCHAR*)pDesc->WText, len));
00317
00318 int tlen = text.GetLength();
00319 CString tmp = (tlen < 12-1)
00320 ? (!pDesc->Unicode
00321 ? CString(CStringA((CHAR*)pDesc->Text+tlen+1, len-(tlen+1)))
00322 : CString(CStringW((WCHAR*)pDesc->WText+tlen+1, len-(tlen+1))))
00323 : _T("");
00324
00325 if((pDesc->PackType -= 0x80) >= 0x10)
00326 continue;
00327
00328 if(pDesc->CharacterPosition == 0)
00329 {
00330 str[pDesc->PackType][pDesc->TrackNumber] = text;
00331 }
00332 else if(pDesc->CharacterPosition <= 0xf)
00333 {
00334 if(pDesc->CharacterPosition < 0xf && last.GetLength() > 0)
00335 {
00336 str[pDesc->PackType][pDesc->TrackNumber] = last + text;
00337 }
00338 else
00339 {
00340 str[pDesc->PackType][pDesc->TrackNumber] += text;
00341 }
00342 }
00343
00344 last = tmp;
00345 }
00346
00347 m_discTitle = str[0][0];
00348 m_trackTitle = str[0][iTrackIndex];
00349 m_discArtist = str[1][0];
00350 m_trackArtist = str[1][iTrackIndex];
00351 }
00352 while(0);
00353
00354
00355 return(true);
00356 }
00357
00358 HRESULT CCDDAStream::SetPointer(LONGLONG llPos)
00359 {
00360 if(llPos < 0 || llPos > m_llLength) return S_FALSE;
00361 m_llPosition = llPos;
00362 return S_OK;
00363 }
00364
00365 HRESULT CCDDAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead)
00366 {
00367 CAutoLock lck(&m_csLock);
00368
00369 BYTE buff[RAW_SECTOR_SIZE];
00370
00371 PBYTE pbBufferOrg = pbBuffer;
00372 LONGLONG pos = m_llPosition;
00373 size_t len = (size_t)dwBytesToRead;
00374
00375 if(pos < sizeof(m_header) && len > 0)
00376 {
00377 size_t l = (size_t)min(len, sizeof(m_header) - pos);
00378 memcpy(pbBuffer, &((BYTE*)&m_header)[pos], l);
00379 pbBuffer += l;
00380 pos += l;
00381 len -= l;
00382 }
00383
00384 pos -= sizeof(m_header);
00385
00386 while(pos >= 0 && pos < m_llLength && len > 0)
00387 {
00388 RAW_READ_INFO rawreadinfo;
00389 rawreadinfo.SectorCount = 1;
00390 rawreadinfo.TrackMode = CDDA;
00391
00392 UINT sector = m_nStartSector + int(pos/RAW_SECTOR_SIZE);
00393 __int64 offset = pos%RAW_SECTOR_SIZE;
00394
00395 rawreadinfo.DiskOffset.QuadPart = sector*2048;
00396 DWORD BytesReturned = 0;
00397 BOOL b = DeviceIoControl(
00398 m_hDrive, IOCTL_CDROM_RAW_READ,
00399 &rawreadinfo, sizeof(rawreadinfo),
00400 buff, RAW_SECTOR_SIZE,
00401 &BytesReturned, 0);
00402
00403 size_t l = (size_t)min(min(len, RAW_SECTOR_SIZE - offset), m_llLength - pos);
00404 memcpy(pbBuffer, &buff[offset], l);
00405
00406 pbBuffer += l;
00407 pos += l;
00408 len -= l;
00409 }
00410
00411 if(pdwBytesRead) *pdwBytesRead = pbBuffer - pbBufferOrg;
00412 m_llPosition += pbBuffer - pbBufferOrg;
00413
00414 return S_OK;
00415 }
00416
00417 LONGLONG CCDDAStream::Size(LONGLONG* pSizeAvailable)
00418 {
00419 LONGLONG size = sizeof(m_header) + m_llLength;
00420 if(pSizeAvailable) *pSizeAvailable = size;
00421 return size;
00422 }
00423
00424 DWORD CCDDAStream::Alignment()
00425 {
00426 return 1;
00427 }
00428
00429 void CCDDAStream::Lock()
00430 {
00431 m_csLock.Lock();
00432 }
00433
00434 void CCDDAStream::Unlock()
00435 {
00436 m_csLock.Unlock();
00437 }
00438