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 

Generated on Tue Dec 13 14:47:23 2005 for guliverkli by  doxygen 1.4.5