- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# CDDAReader.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    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")); // "RIFFxxxxCDDA"
    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); // "DllMain" of the dshow baseclasses;
    00090 }
    00091
    00092 #endif
    00093
    00094 //
    00095 // CCDDAReader
    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 // IFileSourceFilter
    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 // IAMMediaContent
    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 // CCDDAStream
    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         // MMC-3 Draft Revision 10g: Table 222 – Q Sub-channel control field
    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;//MSF2UINT(m_TOC.TrackData[0].Address);
    00273         m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150;//MSF2UINT(m_TOC.TrackData[0].Address);
    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