- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# RealMediaSplitter.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 <Shlwapi.h>
    00024 #include <atlpath.h>
    00025 #include <mmreg.h>
    00026 #include <ks.h>
    00027 #include <ksmedia.h>
    00028 #include "..\..\..\DSUtil\DSUtil.h"
    00029 #include "..\..\..\DSUtil\MediaTypes.h"
    00030 #include "RealMediaSplitter.h"
    00031 #include "..\..\..\subtitles\SubtitleInputPin.h"
    00032
    00033 //
    00034
    00035 #include <initguid.h>
    00036 #include "..\..\..\..\include\moreuuids.h"
    00037
    00038 template<typename T>
    00039 static void bswap(T& var)
    00040 {
    00041         BYTE* s = (BYTE*)&var;
    00042         for(BYTE* d = s + sizeof(var)-1; s < d; s++, d--)
    00043                 *s ^= *d, *d ^= *s, *s ^= *d;
    00044 }
    00045
    00046 void rvinfo::bswap()
    00047 {
    00048 	::bswap(dwSize);
    00049         ::bswap(w); ::bswap(h); ::bswap(bpp);
    00050 	::bswap(unk1); ::bswap(fps);
    00051 	::bswap(type1); ::bswap(type2);
    00052 }
    00053
    00054 void rainfo::bswap()
    00055 {
    00056 	::bswap(version1);
    00057         ::bswap(version2);
    00058 	::bswap(header_size);
    00059         ::bswap(flavor);
    00060 	::bswap(coded_frame_size);
    00061         ::bswap(sub_packet_h);
    00062 	::bswap(frame_size);
    00063         ::bswap(sub_packet_size);
    00064 }
    00065
    00066 void rainfo4::bswap()
    00067 {
    00068         __super::bswap();
    00069 	::bswap(sample_rate);
    00070         ::bswap(sample_size);
    00071 	::bswap(channels);
    00072 }
    00073
    00074 void rainfo5::bswap()
    00075 {
    00076         __super::bswap();
    00077 	::bswap(sample_rate);
    00078         ::bswap(sample_size);
    00079 	::bswap(channels);
    00080 }
    00081
    00082 using namespace RMFF;
    00083
    00084 #ifdef REGISTER_FILTER
    00085
    00086 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
    00087 {
    00088         {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL},
    00089 };
    00090
    00091 const AMOVIESETUP_PIN sudpPins[] =
    00092 {
    00093     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
    00094     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 0, NULL}
    00095 };
    00096
    00097 const AMOVIESETUP_MEDIATYPE sudPinTypesIn2[] =
    00098 {
    00099         {&MEDIATYPE_Video, &MEDIASUBTYPE_RV20},
    00100         {&MEDIATYPE_Video, &MEDIASUBTYPE_RV30},
    00101         {&MEDIATYPE_Video, &MEDIASUBTYPE_RV40},
    00102         {&MEDIATYPE_Video, &MEDIASUBTYPE_RV41},
    00103 };
    00104
    00105 const AMOVIESETUP_MEDIATYPE sudPinTypesOut2[] =
    00106 {
    00107         {&MEDIATYPE_Video, &MEDIASUBTYPE_NULL},
    00108 };
    00109
    00110 const AMOVIESETUP_PIN sudpPins2[] =
    00111 {
    00112     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn2), sudPinTypesIn2},
    00113     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut2), sudPinTypesOut2}
    00114 };
    00115
    00116 const AMOVIESETUP_MEDIATYPE sudPinTypesIn3[] =
    00117 {
    00118         {&MEDIATYPE_Audio, &MEDIASUBTYPE_14_4},
    00119         {&MEDIATYPE_Audio, &MEDIASUBTYPE_28_8},
    00120         {&MEDIATYPE_Audio, &MEDIASUBTYPE_ATRC},
    00121         {&MEDIATYPE_Audio, &MEDIASUBTYPE_COOK},
    00122         {&MEDIATYPE_Audio, &MEDIASUBTYPE_DNET},
    00123         {&MEDIATYPE_Audio, &MEDIASUBTYPE_SIPR},
    00124         {&MEDIATYPE_Audio, &MEDIASUBTYPE_AAC},
    00125         {&MEDIATYPE_Audio, &MEDIASUBTYPE_RAAC},
    00126         {&MEDIATYPE_Audio, &MEDIASUBTYPE_RACP},
    00127 };
    00128
    00129 const AMOVIESETUP_MEDIATYPE sudPinTypesOut3[] =
    00130 {
    00131         {&MEDIATYPE_Audio, &MEDIASUBTYPE_PCM},
    00132 };
    00133
    00134 const AMOVIESETUP_PIN sudpPins3[] =
    00135 {
    00136     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn3), sudPinTypesIn3},
    00137     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut3), sudPinTypesOut3}
    00138 };
    00139
    00140 const AMOVIESETUP_FILTER sudFilter[] =
    00141 {
    00142         {&__uuidof(CRealMediaSplitterFilter), L"RealMedia Splitter", MERIT_NORMAL, countof(sudpPins), sudpPins},
    00143         {&__uuidof(CRealMediaSourceFilter), L"RealMedia Source", MERIT_NORMAL, 0, NULL},
    00144         {&__uuidof(CRealVideoDecoder), L"RealVideo Decoder", MERIT_UNLIKELY, countof(sudpPins2), sudpPins2},
    00145         {&__uuidof(CRealAudioDecoder), L"RealAudio Decoder", MERIT_UNLIKELY, countof(sudpPins3), sudpPins3},
    00146 };
    00147
    00148 CFactoryTemplate g_Templates[] =
    00149 {
    00150         {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CRealMediaSplitterFilter>, NULL, &sudFilter[0]},
    00151         {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance<CRealMediaSourceFilter>, NULL, &sudFilter[1]},
    00152     {sudFilter[2].strName, sudFilter[2].clsID, CreateInstance<CRealVideoDecoder>, NULL, &sudFilter[2]},
    00153     {sudFilter[3].strName, sudFilter[3].clsID, CreateInstance<CRealAudioDecoder>, NULL, &sudFilter[3]},
    00154 };
    00155
    00156 int g_cTemplates = countof(g_Templates);
    00157
    00158 STDAPI DllRegisterServer()
    00159 {
    00160         RegisterSourceFilter(
    00161                 CLSID_AsyncReader,
    00162                 MEDIASUBTYPE_RealMedia,
    00163                 _T("0,4,,2E524D46"),
    00164                 _T(".rm"), _T(".rmvb"), _T(".ram"), NULL);
    00165
    00166         return AMovieDllRegisterServer2(TRUE);
    00167 }
    00168
    00169 STDAPI DllUnregisterServer()
    00170 {
    00171         UnRegisterSourceFilter(MEDIASUBTYPE_RealMedia);
    00172
    00173         return AMovieDllRegisterServer2(FALSE);
    00174 }
    00175
    00176 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
    00177
    00178 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
    00179 {
    00180     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
    00181 }
    00182
    00183 #endif
    00184
    00185 //
    00186 // CRealMediaSplitterFilter
    00187 //
    00188
    00189 CRealMediaSplitterFilter::CRealMediaSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr)
    00190         : CBaseSplitterFilter(NAME("CRealMediaSplitterFilter"), pUnk, phr, __uuidof(this))
    00191 {
    00192 }
    00193
    00194 CRealMediaSplitterFilter::~CRealMediaSplitterFilter()
    00195 {
    00196 }
    00197
    00198 HRESULT CRealMediaSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader)
    00199 {
    00200         CheckPointer(pAsyncReader, E_POINTER);
    00201
    00202         {
    00203                 DWORD dw;
    00204                 if(FAILED(pAsyncReader->SyncRead(0, 4, (BYTE*)&dw)) || dw != 'FMR.')
    00205                         return E_FAIL;
    00206         }
    00207
    00208         HRESULT hr = E_FAIL;
    00209
    00210         m_pFile.Free();
    00211
    00212         m_pFile.Attach(new CRMFile(pAsyncReader, hr));
    00213         if(!m_pFile) return E_OUTOFMEMORY;
    00214         if(FAILED(hr)) {m_pFile.Free(); return hr;}
    00215
    00216         m_rtNewStart = m_rtCurrent = 0;
    00217         m_rtNewStop = m_rtStop = 0;
    00218
    00219         m_rtStop = 10000i64*m_pFile->m_p.tDuration;
    00220
    00221         POSITION pos = m_pFile->m_mps.GetHeadPosition();
    00222         while(pos)
    00223         {
    00224                 MediaProperies* pmp = m_pFile->m_mps.GetNext(pos);
    00225
    00226                 CStringW name;
    00227                 name.Format(L"Output %02d", pmp->stream);
    00228                 if(!pmp->name.IsEmpty()) name += L" (" + CStringW(pmp->name) + L")";
    00229
    00230                 CArray<CMediaType> mts;
    00231
    00232                 CMediaType mt;
    00233                 mt.SetSampleSize(max(pmp->maxPacketSize*16, 1));
    00234
    00235                 if(pmp->mime == "video/x-pn-realvideo")
    00236                 {
    00237                         mt.majortype = MEDIATYPE_Video;
    00238                         mt.formattype = FORMAT_VideoInfo;
    00239
    00240                         VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + pmp->typeSpecData.GetCount());
    00241                         memset(mt.Format(), 0, mt.FormatLength());
    00242                         memcpy(pvih + 1, pmp->typeSpecData.GetData(), pmp->typeSpecData.GetCount());
    00243
    00244                         rvinfo rvi = *(rvinfo*)pmp->typeSpecData.GetData();
    00245                         rvi.bswap();
    00246
    00247                         ASSERT(rvi.dwSize >= FIELD_OFFSET(rvinfo, morewh));
    00248                         ASSERT(rvi.fcc1 == 'ODIV');
    00249
    00250                         mt.subtype = FOURCCMap(rvi.fcc2);
    00251                         if(rvi.fps > 0x10000) pvih->AvgTimePerFrame = REFERENCE_TIME(10000000i64 / ((float)rvi.fps/0x10000));
    00252                         pvih->dwBitRate = pmp->avgBitRate;
    00253                         pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader);
    00254                         pvih->bmiHeader.biWidth = rvi.w;
    00255                         pvih->bmiHeader.biHeight = rvi.h;
    00256                         pvih->bmiHeader.biPlanes = 3;
    00257                         pvih->bmiHeader.biBitCount = rvi.bpp;
    00258                         pvih->bmiHeader.biCompression = rvi.fcc2;
    00259                         pvih->bmiHeader.biSizeImage = rvi.w*rvi.h*3/2;
    00260
    00261                         mts.Add(mt);
    00262
    00263                         if(pmp->width > 0 && pmp->height > 0)
    00264                         {
    00265                                 BITMAPINFOHEADER bmi = pvih->bmiHeader;
    00266                                 mt.formattype = FORMAT_VideoInfo2;
    00267                                 VIDEOINFOHEADER2* pvih2 = (VIDEOINFOHEADER2*)mt.ReallocFormatBuffer(sizeof(VIDEOINFOHEADER2) + pmp->typeSpecData.GetCount());
    00268                                 memset(mt.Format() + FIELD_OFFSET(VIDEOINFOHEADER2, dwInterlaceFlags), 0, mt.FormatLength() - FIELD_OFFSET(VIDEOINFOHEADER2, dwInterlaceFlags));
    00269                                 memcpy(pvih2 + 1, pmp->typeSpecData.GetData(), pmp->typeSpecData.GetCount());
    00270                                 pvih2->bmiHeader = bmi;
    00271                                 pvih2->bmiHeader.biWidth = (DWORD)pmp->width;
    00272                                 pvih2->bmiHeader.biHeight = (DWORD)pmp->height;
    00273                                 pvih2->dwPictAspectRatioX = rvi.w;
    00274                                 pvih2->dwPictAspectRatioY = rvi.h;
    00275
    00276                                 mts.InsertAt(0, mt);
    00277                         }
    00278                 }
    00279                 else if(pmp->mime == "audio/x-pn-realaudio")
    00280                 {
    00281                         mt.majortype = MEDIATYPE_Audio;
    00282                         mt.formattype = FORMAT_WaveFormatEx;
    00283                         mt.bTemporalCompression = 1;
    00284
    00285                         WAVEFORMATEX* pwfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX) + pmp->typeSpecData.GetCount());
    00286                         memset(mt.Format(), 0, mt.FormatLength());
    00287                         memcpy(pwfe + 1, pmp->typeSpecData.GetData(), pmp->typeSpecData.GetCount());
    00288
    00289                         union {
    00290                         DWORD fcc;
    00291                         char fccstr[5];
    00292                         };
    00293
    00294                         fcc = 0;
    00295                         fccstr[4] = 0;
    00296
    00297                         BYTE* fmt = pmp->typeSpecData.GetData();
    00298                         for(int i = 0; i < pmp->typeSpecData.GetSize()-4; i++, fmt++)
    00299                         {
    00300                                 if(fmt[0] == '.' || fmt[1] == 'r' || fmt[2] == 'a')
    00301                                         break;
    00302                         }
    00303
    00304                         rainfo rai = *(rainfo*)fmt;
    00305                         rai.bswap();
    00306
    00307                         BYTE* extra = NULL;
    00308
    00309                         if(rai.version2 == 4)
    00310                         {
    00311                                 rainfo4 rai4 = *(rainfo4*)fmt;
    00312                                 rai4.bswap();
    00313                                 pwfe->nChannels = rai4.channels;
    00314                                 pwfe->wBitsPerSample = rai4.sample_size;
    00315                                 pwfe->nSamplesPerSec = rai4.sample_rate;
    00316                                 pwfe->nBlockAlign = rai4.frame_size;
    00317                                 BYTE* p = (BYTE*)((rainfo4*)fmt+1);
    00318                                 int len = *p++; p += len; len = *p++; ASSERT(len == 4);
    00319                                 if(len == 4)
    00320                                 fcc = MAKEFOURCC(p[0],p[1],p[2],p[3]);
    00321                                 extra = p + len + 3;
    00322                         }
    00323                         else if(rai.version2 == 5)
    00324                         {
    00325                                 rainfo5 rai5 = *(rainfo5*)fmt;
    00326                                 rai5.bswap();
    00327                                 pwfe->nChannels = rai5.channels;
    00328                                 pwfe->wBitsPerSample = rai5.sample_size;
    00329                                 pwfe->nSamplesPerSec = rai5.sample_rate;
    00330                                 pwfe->nBlockAlign = rai5.frame_size;
    00331                                 fcc = rai5.fourcc3;
    00332                                 extra = fmt + sizeof(rainfo5) + 4;
    00333                         }
    00334                         else
    00335                         {
    00336                                 continue;
    00337                         }
    00338
    00339                         _strupr(fccstr);
    00340
    00341                         mt.subtype = FOURCCMap(fcc);
    00342
    00343                         bswap(fcc);
    00344
    00345                         switch(fcc)
    00346                         {
    00347                         case '14_4': pwfe->wFormatTag = WAVE_FORMAT_14_4; break;
    00348                         case '28_8': pwfe->wFormatTag = WAVE_FORMAT_28_8; break;
    00349                         case 'ATRC': pwfe->wFormatTag = WAVE_FORMAT_ATRC; break;
    00350                         case 'COOK': pwfe->wFormatTag = WAVE_FORMAT_COOK; break;
    00351                         case 'DNET': pwfe->wFormatTag = WAVE_FORMAT_DNET; break;
    00352                         case 'SIPR': pwfe->wFormatTag = WAVE_FORMAT_SIPR; break;
    00353                         case 'RAAC': pwfe->wFormatTag = WAVE_FORMAT_RAAC; break;
    00354                         case 'RACP': pwfe->wFormatTag = WAVE_FORMAT_RACP; break;
    00355                         }
    00356
    00357                         if(pwfe->wFormatTag)
    00358                         {
    00359                                 mts.Add(mt);
    00360
    00361                                 if(fcc == 'DNET')
    00362                                 {
    00363                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3);
    00364                                         mts.InsertAt(0, mt);
    00365                                 }
    00366                                 else if(fcc == 'RAAC' || fcc == 'RACP')
    00367                                 {
    00368                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_AAC);
    00369                                         int extralen = *(DWORD*)extra; extra += 4;
    00370                                         ::bswap(extralen);
    00371                                         ASSERT(*extra == 2); // always 2? why? what does it mean?
    00372                                         if(*extra == 2)
    00373                                         {
    00374                                                 extra++; extralen--;
    00375                                                 WAVEFORMATEX* pwfe = (WAVEFORMATEX*)mt.ReallocFormatBuffer(sizeof(WAVEFORMATEX) + extralen);
    00376                                                 pwfe->cbSize = extralen;
    00377                                                 memcpy(pwfe + 1, extra, extralen);
    00378                                         }
    00379                                         else
    00380                                         {
    00381                                                 WAVEFORMATEX* pwfe = (WAVEFORMATEX*)mt.ReallocFormatBuffer(sizeof(WAVEFORMATEX) + 5);
    00382                                                 pwfe->cbSize = MakeAACInitData((BYTE*)(pwfe+1), 0, pwfe->nSamplesPerSec, pwfe->nChannels);
    00383                                         }
    00384                                         mts.InsertAt(0, mt);
    00385                                 }
    00386                         }
    00387                 }
    00388                 else if(pmp->mime == "logical-fileinfo")
    00389                 {
    00390                         CMap<CStringA,LPCSTR,CStringA,LPCSTR> lfi;
    00391                         CStringA key, value;
    00392
    00393                         BYTE* p = pmp->typeSpecData.GetData();
    00394                         BYTE* end = p + pmp->typeSpecData.GetCount();
    00395                         p += 8;
    00396
    00397                         DWORD cnt = p <= end-4 ? *(DWORD*)p : 0; bswap(cnt); p += 4;
    00398
    00399                         if(cnt > 0xffff) // different format?
    00400                         {
    00401                                 p += 2;
    00402                                 cnt = p <= end-4 ? *(DWORD*)p : 0; bswap(cnt); p += 4;
    00403                         }
    00404
    00405                         while(p < end-4 && cnt-- > 0)
    00406                         {
    00407                                 BYTE* base = p;
    00408                                 DWORD len = *(DWORD*)p; bswap(len); p += 4;
    00409                                 if(base + len > end) break;
    00410
    00411                                 p++;
    00412                                 WORD keylen = *(WORD*)p; bswap(keylen); p += 2;
    00413                                 memcpy(key.GetBufferSetLength(keylen), p, keylen);
    00414                                 p += keylen;
    00415
    00416                                 p+=4;
    00417                                 WORD valuelen = *(WORD*)p; bswap(valuelen); p += 2;
    00418                                 memcpy(value.GetBufferSetLength(valuelen), p, valuelen);
    00419                                 p += valuelen;
    00420
    00421                                 ASSERT(p == base + len);
    00422                                 p = base + len;
    00423
    00424                                 lfi[key] = value;
    00425                         }
    00426
    00427                         POSITION pos = lfi.GetStartPosition();
    00428                         while(pos)
    00429                         {
    00430                                 lfi.GetNextAssoc(pos, key, value);
    00431
    00432                                 int n;
    00433                                 if(key.Find("CHAPTER") == 0 && key.Find("TIME") == key.GetLength()-4
    00434                                 && (n = strtol(key.Mid(7), NULL, 10)) > 0)
    00435                                 {
    00436                                         int h, m, s, ms;
    00437                                         char c;
    00438                                         if(7 != sscanf(value, "%d%c%d%c%d%c%d", &h, &c, &m, &c, &s, &c, &ms))
    00439                                                 continue;
    00440
    00441                                         key.Format("CHAPTER%02dNAME", n);
    00442                                         if(!lfi.Lookup(key, value) || value.IsEmpty())
    00443                                                 value.Format("Chapter %d", n);
    00444
    00445                                         ChapAppend(
    00446                                                 ((((REFERENCE_TIME)h*60+m)*60+s)*1000+ms)*10000,
    00447                                                 CStringW(CString(value)));
    00448                                 }
    00449                         }
    00450                 }
    00451
    00452                 if(mts.IsEmpty())
    00453                 {
    00454                         TRACE(_T("Unsupported RealMedia stream (%d): %s\n"), pmp->stream, CString(pmp->mime));
    00455                         continue;
    00456                 }
    00457
    00458                 HRESULT hr;
    00459
    00460                 CAutoPtr<CBaseSplitterOutputPin> pPinOut(new CRealMediaSplitterOutputPin(mts, name, this, this, &hr));
    00461                 if(SUCCEEDED(AddOutputPin((DWORD)pmp->stream, pPinOut)))
    00462                 {
    00463                         if(!m_rtStop)
    00464                                 m_pFile->m_p.tDuration = max(m_pFile->m_p.tDuration, pmp->tDuration);
    00465                 }
    00466         }
    00467
    00468         pos = m_pFile->m_subs.GetHeadPosition();
    00469         for(DWORD stream = 0; pos; stream++)
    00470         {
    00471                 CRMFile::subtitle& s = m_pFile->m_subs.GetNext(pos);
    00472
    00473                 CStringW name;
    00474                 name.Format(L"Subtitle %02d", stream);
    00475                 if(!s.name.IsEmpty()) name += L" (" + CStringW(CString(s.name)) + L")";
    00476
    00477                 CMediaType mt;
    00478                 mt.SetSampleSize(1);
    00479                 mt.majortype = MEDIATYPE_Text;
    00480
    00481                 CArray<CMediaType> mts;
    00482                 mts.Add(mt);
    00483
    00484                 HRESULT hr;
    00485
    00486                 CAutoPtr<CBaseSplitterOutputPin> pPinOut(new CRealMediaSplitterOutputPin(mts, name, this, this, &hr));
    00487                 AddOutputPin((DWORD)~stream, pPinOut);
    00488         }
    00489
    00490         m_rtDuration = m_rtNewStop = m_rtStop = 10000i64*m_pFile->m_p.tDuration;
    00491
    00492         SetProperty(L"TITL", CStringW(m_pFile->m_cd.title));
    00493         SetProperty(L"AUTH", CStringW(m_pFile->m_cd.author));
    00494         SetProperty(L"CPYR", CStringW(m_pFile->m_cd.copyright));
    00495         SetProperty(L"DESC", CStringW(m_pFile->m_cd.comment));
    00496
    00497         return m_pOutputs.GetCount() > 0 ? S_OK : E_FAIL;
    00498 }
    00499
    00500 bool CRealMediaSplitterFilter::DemuxInit()
    00501 {
    00502         if(!m_pFile) return(false);
    00503
    00504         // reindex if needed
    00505
    00506         if(m_pFile->m_irs.GetCount() == 0)
    00507         {
    00508                 m_nOpenProgress = 0;
    00509                 m_rtDuration = 0;
    00510
    00511                 int stream = m_pFile->GetMasterStream();
    00512
    00513                 UINT32 tLastStart = -1;
    00514                 UINT32 nPacket = 0;
    00515
    00516                 POSITION pos = m_pFile->m_dcs.GetHeadPosition();
    00517                 while(pos && !m_fAbort)
    00518                 {
    00519                         DataChunk* pdc = m_pFile->m_dcs.GetNext(pos);
    00520
    00521                         m_pFile->Seek(pdc->pos);
    00522
    00523                         for(UINT32 i = 0; i < pdc->nPackets && !m_fAbort; i++, nPacket++)
    00524                         {
    00525                                 UINT64 filepos = m_pFile->GetPos();
    00526
    00527                                 HRESULT hr;
    00528
    00529                                 MediaPacketHeader mph;
    00530                                 if(S_OK != (hr = m_pFile->Read(mph, false)))
    00531                                         break;
    00532
    00533                                 if(mph.stream == stream && (mph.flags&MediaPacketHeader::PN_KEYFRAME_FLAG) && tLastStart != mph.tStart)
    00534                                 {
    00535                                         m_rtDuration = max((__int64)(10000i64*mph.tStart), m_rtDuration);
    00536
    00537                                         CAutoPtr<IndexRecord> pir(new IndexRecord());
    00538                                         pir->tStart = mph.tStart;
    00539                                         pir->ptrFilePos = (UINT32)filepos;
    00540                                         pir->packet = nPacket;
    00541                                         m_pFile->m_irs.AddTail(pir);
    00542
    00543                                         tLastStart = mph.tStart;
    00544                                 }
    00545
    00546                                 m_nOpenProgress = m_pFile->GetPos()*100/m_pFile->GetLength();
    00547
    00548                                 DWORD cmd;
    00549                                 if(CheckRequest(&cmd))
    00550                                 {
    00551                                         if(cmd == CMD_EXIT) m_fAbort = true;
    00552                                         else Reply(S_OK);
    00553                                 }
    00554                         }
    00555                 }
    00556
    00557                 m_nOpenProgress = 100;
    00558
    00559                 if(m_fAbort) m_pFile->m_irs.RemoveAll();
    00560
    00561                 m_fAbort = false;
    00562         }
    00563
    00564         m_seekpos = NULL;
    00565         m_seekpacket = 0;
    00566         m_seekfilepos = 0;
    00567
    00568         return(true);
    00569 }
    00570
    00571 void CRealMediaSplitterFilter::DemuxSeek(REFERENCE_TIME rt)
    00572 {
    00573         if(rt <= 0)
    00574         {
    00575                 m_seekpos = m_pFile->m_dcs.GetHeadPosition();
    00576                 m_seekpacket = 0;
    00577                 m_seekfilepos = m_pFile->m_dcs.GetHead()->pos;
    00578         }
    00579         else
    00580         {
    00581                 m_seekpos = NULL;
    00582
    00583                 POSITION pos = m_pFile->m_irs.GetTailPosition();
    00584                 while(pos && !m_seekpos)
    00585                 {
    00586                         IndexRecord* pir = m_pFile->m_irs.GetPrev(pos);
    00587                         if(pir->tStart <= rt/10000)
    00588                         {
    00589                                 m_seekpacket = pir->packet;
    00590
    00591                                 pos = m_pFile->m_dcs.GetTailPosition();
    00592                                 while(pos && !m_seekpos)
    00593                                 {
    00594                                         POSITION tmp = pos;
    00595
    00596                                         DataChunk* pdc = m_pFile->m_dcs.GetPrev(pos);
    00597
    00598                                         if(pdc->pos <= pir->ptrFilePos)
    00599                                         {
    00600                                                 m_seekpos = tmp;
    00601                                                 m_seekfilepos = pir->ptrFilePos;
    00602
    00603                                                 POSITION pos = m_pFile->m_dcs.GetHeadPosition();
    00604                                                 while(pos != m_seekpos)
    00605                                                 {
    00606                                                         m_seekpacket -= m_pFile->m_dcs.GetNext(pos)->nPackets;
    00607                                                 }
    00608                                         }
    00609                                 }
    00610
    00611                                 // search the closest keyframe to the seek time (commented out 'cause rm seems to index all of its keyframes...)
    00612 /*
    00613                                 if(m_seekpos)
    00614                                 {
    00615                                         DataChunk* pdc = m_pFile->m_dcs.GetAt(m_seekpos);
    00616
    00617                                         m_pFile->Seek(m_seekfilepos);
    00618
    00619                                         REFERENCE_TIME seektime = -1;
    00620                                         UINT32 seekstream = -1;
    00621
    00622                                         for(UINT32 i = m_seekpacket; i < pdc->nPackets; i++)
    00623                                         {
    00624                                                 UINT64 filepos = m_pFile->GetPos();
    00625
    00626                                                 MediaPacketHeader mph;
    00627                                                 if(S_OK != m_pFile->Read(mph, false))
    00628                                                         break;
    00629
    00630                                                 if(seekstream == -1) seekstream = mph.stream;
    00631                                                 if(seekstream != mph.stream) continue;
    00632
    00633                                                 if(seektime == 10000i64*mph.tStart) continue;
    00634                                                 if(rt < 10000i64*mph.tStart) break;
    00635
    00636                                                 if((mph.flags&MediaPacketHeader::PN_KEYFRAME_FLAG))
    00637                                                 {
    00638                                                         m_seekpacket = i;
    00639                                                         m_seekfilepos = filepos;
    00640                                                         seektime = 10000i64*mph.tStart;
    00641                                                 }
    00642                                         }
    00643                                 }
    00644 */
    00645                         }
    00646                 }
    00647
    00648                 if(!m_seekpos)
    00649                 {
    00650                         m_seekpos = m_pFile->m_dcs.GetHeadPosition();
    00651                         m_seekpacket = 0;
    00652                         m_seekfilepos = m_pFile->m_dcs.GetAt(m_seekpos)->pos;
    00653                 }
    00654         }
    00655 }
    00656
    00657 bool CRealMediaSplitterFilter::DemuxLoop()
    00658 {
    00659         HRESULT hr = S_OK;
    00660         POSITION pos;
    00661
    00662         pos = m_pFile->m_subs.GetHeadPosition();
    00663         for(DWORD stream = 0; pos && SUCCEEDED(hr) && !CheckRequest(NULL); stream++)
    00664         {
    00665                 CRMFile::subtitle& s = m_pFile->m_subs.GetNext(pos);
    00666
    00667                 CAutoPtr<Packet> p(new Packet);
    00668
    00669                 p->TrackNumber = ~stream;
    00670                 p->bSyncPoint = TRUE;
    00671                 p->rtStart = 0;
    00672                 p->rtStop = 1;
    00673
    00674                 p->pData.SetSize((4+1) + (2+4+(s.name.GetLength()+1)*2) + (2+4+s.data.GetLength()));
    00675                 BYTE* ptr = p->pData.GetData();
    00676
    00677                 strcpy((char*)ptr, "GAB2"); ptr += 4+1;
    00678
    00679                 *(WORD*)ptr = 2; ptr += 2;
    00680                 *(DWORD*)ptr = (s.name.GetLength()+1)*2; ptr += 4;
    00681                 wcscpy((WCHAR*)ptr, CStringW(s.name)); ptr += (s.name.GetLength()+1)*2;
    00682
    00683                 *(WORD*)ptr = 4; ptr += 2;
    00684                 *(DWORD*)ptr = s.data.GetLength(); ptr += 4;
    00685                 memcpy((char*)ptr, s.data, s.data.GetLength()); ptr += s.name.GetLength();
    00686
    00687                 hr = DeliverPacket(p);
    00688         }
    00689
    00690         pos = m_seekpos;
    00691         while(pos && SUCCEEDED(hr) && !CheckRequest(NULL))
    00692         {
    00693                 DataChunk* pdc = m_pFile->m_dcs.GetNext(pos);
    00694
    00695                 m_pFile->Seek(m_seekfilepos > 0 ? m_seekfilepos : pdc->pos);
    00696
    00697                 for(UINT32 i = m_seekpacket; i < pdc->nPackets && SUCCEEDED(hr) && !CheckRequest(NULL); i++)
    00698                 {
    00699                         MediaPacketHeader mph;
    00700                         if(S_OK != (hr = m_pFile->Read(mph)))
    00701                                 break;
    00702
    00703                         CAutoPtr<Packet> p(new Packet);
    00704                         p->TrackNumber = mph.stream;
    00705                         p->bSyncPoint = !!(mph.flags&MediaPacketHeader::PN_KEYFRAME_FLAG);
    00706                         p->rtStart = 10000i64*(mph.tStart);
    00707                         p->rtStop = p->rtStart+1;
    00708                         p->pData.Copy(mph.pData);
    00709                         hr = DeliverPacket(p);
    00710                 }
    00711
    00712                 m_seekpacket = 0;
    00713                 m_seekfilepos = 0;
    00714         }
    00715
    00716         return(true);
    00717 }
    00718
    00719 // IKeyFrameInfo
    00720
    00721 STDMETHODIMP CRealMediaSplitterFilter::GetKeyFrameCount(UINT& nKFs)
    00722 {
    00723         if(!m_pFile) return E_UNEXPECTED;
    00724         nKFs = m_pFile->m_irs.GetCount();
    00725         return S_OK;
    00726 }
    00727
    00728 STDMETHODIMP CRealMediaSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs)
    00729 {
    00730         CheckPointer(pFormat, E_POINTER);
    00731         CheckPointer(pKFs, E_POINTER);
    00732
    00733         if(!m_pFile) return E_UNEXPECTED;
    00734         if(*pFormat != TIME_FORMAT_MEDIA_TIME) return E_INVALIDARG;
    00735
    00736         UINT nKFsTmp = 0;
    00737         POSITION pos = m_pFile->m_irs.GetHeadPosition();
    00738         for(int i = 0; pos && nKFsTmp < nKFs; i++)
    00739                 pKFs[nKFsTmp++] = 10000i64*m_pFile->m_irs.GetNext(pos)->tStart;
    00740         nKFs = nKFsTmp;
    00741
    00742         return S_OK;
    00743 }
    00744
    00745 //
    00746 // CRealMediaSplitterOutputPin
    00747 //
    00748
    00749 CRealMediaSplitterOutputPin::CRealMediaSplitterOutputPin(CArray<CMediaType>& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
    00750         : CBaseSplitterOutputPin(mts, pName, pFilter, pLock, phr)
    00751 {
    00752 }
    00753
    00754 CRealMediaSplitterOutputPin::~CRealMediaSplitterOutputPin()
    00755 {
    00756 }
    00757
    00758 HRESULT CRealMediaSplitterOutputPin::DeliverEndFlush()
    00759 {
    00760         {
    00761                 CAutoLock cAutoLock(&m_csQueue);
    00762                 m_segments.Clear();
    00763         }
    00764
    00765         return __super::DeliverEndFlush();
    00766 }
    00767
    00768 HRESULT CRealMediaSplitterOutputPin::DeliverSegments()
    00769 {
    00770         HRESULT hr;
    00771
    00772         if(m_segments.GetCount() == 0)
    00773         {
    00774                 m_segments.Clear();
    00775                 return S_OK;
    00776         }
    00777
    00778         CAutoPtr<Packet> p(new Packet());
    00779
    00780         p->TrackNumber = -1;
    00781         p->bDiscontinuity = m_segments.fDiscontinuity;
    00782         p->bSyncPoint = m_segments.fSyncPoint;
    00783         p->rtStart = m_segments.rtStart;
    00784         p->rtStop = m_segments.rtStart+1;
    00785
    00786         DWORD len = 0, total = 0;
    00787         POSITION pos = m_segments.GetHeadPosition();
    00788         while(pos)
    00789         {
    00790                 segment* s = m_segments.GetNext(pos);
    00791                 len = max(len, s->offset + s->data.GetCount());
    00792                 total += s->data.GetCount();
    00793         }
    00794         ASSERT(len == total);
    00795         len += 1 + 2*4*(!m_segments.fMerged ? m_segments.GetCount() : 1);
    00796
    00797         p->pData.SetSize(len);
    00798
    00799         BYTE* pData = p->pData.GetData();
    00800
    00801         *pData++ = m_segments.fMerged ? 0 : m_segments.GetCount()-1;
    00802
    00803         if(m_segments.fMerged)
    00804         {
    00805                 *((DWORD*)pData) = 1; pData += 4;
    00806                 *((DWORD*)pData) = 0; pData += 4;
    00807         }
    00808         else
    00809         {
    00810                 pos = m_segments.GetHeadPosition();
    00811                 while(pos)
    00812                 {
    00813                         *((DWORD*)pData) = 1; pData += 4;
    00814                         *((DWORD*)pData) = m_segments.GetNext(pos)->offset; pData += 4;
    00815                 }
    00816         }
    00817
    00818         pos = m_segments.GetHeadPosition();
    00819         while(pos)
    00820         {
    00821                 segment* s = m_segments.GetNext(pos);
    00822                 memcpy(pData + s->offset, s->data.GetData(), s->data.GetCount());
    00823         }
    00824
    00825         hr = __super::DeliverPacket(p);
    00826
    00827         m_segments.Clear();
    00828
    00829         return hr;
    00830 }
    00831
    00832 HRESULT CRealMediaSplitterOutputPin::DeliverPacket(CAutoPtr<Packet> p)
    00833 {
    00834         HRESULT hr = S_OK;
    00835
    00836         ASSERT(p->rtStart < p->rtStop);
    00837
    00838         if(m_mt.subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3)
    00839         {
    00840                 WORD* s = (WORD*)p->pData.GetData();
    00841                 WORD* e = s + p->pData.GetSize()/2;
    00842                 while(s < e) bswap(*s++);
    00843         }
    00844
    00845         if(m_mt.subtype == MEDIASUBTYPE_RV10 || m_mt.subtype == MEDIASUBTYPE_RV20
    00846         || m_mt.subtype == MEDIASUBTYPE_RV30 || m_mt.subtype == MEDIASUBTYPE_RV40
    00847         || m_mt.subtype == MEDIASUBTYPE_RV41)
    00848         {
    00849                 CAutoLock cAutoLock(&m_csQueue);
    00850
    00851                 int len = p->pData.GetCount();
    00852                 BYTE* pIn = p->pData.GetData();
    00853                 BYTE* pInOrg = pIn;
    00854
    00855                 if(m_segments.rtStart != p->rtStart)
    00856                 {
    00857                         if(S_OK != (hr = DeliverSegments()))
    00858                                 return hr;
    00859                 }
    00860
    00861                 if(!m_segments.fDiscontinuity && p->bDiscontinuity)
    00862                         m_segments.fDiscontinuity = true;
    00863                 m_segments.fSyncPoint = !!p->bSyncPoint;
    00864                 m_segments.rtStart = p->rtStart;
    00865
    00866                 while(pIn - pInOrg < len)
    00867                 {
    00868                         BYTE hdr = *pIn++, subseq = 0, seqnum = 0;
    00869                         DWORD packetlen = 0, packetoffset = 0;
    00870
    00871                         if((hdr&0xc0) == 0x40)
    00872                         {
    00873                                 pIn++;
    00874                                 packetlen = len - (pIn - pInOrg);
    00875                         }
    00876                         else
    00877                         {
    00878                                 if((hdr&0x40) == 0)
    00879                                         subseq = (*pIn++)&0x7f;
    00880
    00881                                 #define GetWORD(var) \
    00882                                         var = (var<<8)|(*pIn++); \
    00883                                         var = (var<<8)|(*pIn++); \
    00884
    00885                                 GetWORD(packetlen);
    00886                                 if(packetlen&0x8000) m_segments.fMerged = true;
    00887                                 if((packetlen&0x4000) == 0) {GetWORD(packetlen); packetlen &= 0x3fffffff;}
    00888                                 else packetlen &= 0x3fff;
    00889
    00890                                 GetWORD(packetoffset);
    00891                                 if((packetoffset&0x4000) == 0) {GetWORD(packetoffset); packetoffset &= 0x3fffffff;}
    00892                                 else packetoffset &= 0x3fff;
    00893
    00894                                 #undef GetWORD
    00895
    00896                                 if((hdr&0xc0) == 0xc0)
    00897                                         m_segments.rtStart = 10000i64*packetoffset - m_rtStart, packetoffset = 0;
    00898                                 else if((hdr&0xc0) == 0x80)
    00899                                         packetoffset = packetlen - packetoffset;
    00900
    00901                                 seqnum = *pIn++;
    00902                         }
    00903
    00904             int len2 = min(len - (pIn - pInOrg), packetlen - packetoffset);
    00905
    00906                         CAutoPtr<segment> s(new segment);
    00907                         s->offset = packetoffset;
    00908                         s->data.SetSize(len2);
    00909                         memcpy(s->data.GetData(), pIn, len2);
    00910                         m_segments.AddTail(s);
    00911
    00912                         pIn += len2;
    00913
    00914                         if((hdr&0x80) || packetoffset+len2 >= packetlen)
    00915                         {
    00916                             if(S_OK != (hr = DeliverSegments()))
    00917                                         return hr;
    00918                         }
    00919                 }
    00920         }
    00921         else if(m_mt.subtype == MEDIASUBTYPE_RAAC || m_mt.subtype == MEDIASUBTYPE_RACP
    00922                  || m_mt.subtype == MEDIASUBTYPE_AAC)
    00923         {
    00924                 BYTE* ptr = p->pData.GetData()+2;
    00925
    00926                 CList<WORD> sizes;
    00927                 int total = 0;
    00928                 int remaining = p->pData.GetSize()-2;
    00929                 int expected = *(ptr-1)>>4;
    00930
    00931                 while(total < remaining)
    00932                 {
    00933                         int size = (ptr[0]<<8)|(ptr[1]);
    00934                         sizes.AddTail(size);
    00935                         total += size;
    00936                         ptr += 2;
    00937                         remaining -= 2;
    00938                         expected--;
    00939                 }
    00940
    00941                 ASSERT(total == remaining);
    00942                 ASSERT(expected == 0);
    00943
    00944                 WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat;
    00945                 REFERENCE_TIME rtDur = 10240000000i64/wfe->nSamplesPerSec * (wfe->cbSize>2?2:1);
    00946                 REFERENCE_TIME rtStart = p->rtStart;
    00947                 BOOL bDiscontinuity = p->bDiscontinuity;
    00948
    00949                 POSITION pos = sizes.GetHeadPosition();
    00950                 while(pos)
    00951                 {
    00952                         CAutoPtr<Packet> p(new Packet);
    00953                         p->bDiscontinuity = bDiscontinuity;
    00954                         p->bSyncPoint = true;
    00955                         p->rtStart = rtStart;
    00956                         p->rtStop = rtStart + rtDur;
    00957                         p->pData.SetSize(sizes.GetNext(pos));
    00958                         memcpy(p->pData.GetData(), ptr, p->pData.GetSize());
    00959                         ptr += p->pData.GetSize();
    00960                         rtStart = p->rtStop;
    00961                         bDiscontinuity = false;
    00962                         if(S_OK != (hr = __super::DeliverPacket(p)))
    00963                                 break;
    00964                 }
    00965         }
    00966         else
    00967         {
    00968                 hr = __super::DeliverPacket(p);
    00969         }
    00970
    00971         return hr;
    00972 }
    00973
    00974 //
    00975 // CRealMediaSourceFilter
    00976 //
    00977
    00978 CRealMediaSourceFilter::CRealMediaSourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
    00979         : CRealMediaSplitterFilter(pUnk, phr)
    00980 {
    00981         m_clsid = __uuidof(this);
    00982         m_pInput.Free();
    00983 }
    00984
    00985 //
    00986 // CRMFile
    00987 //
    00988
    00989 CRMFile::CRMFile(IAsyncReader* pAsyncReader, HRESULT& hr)
    00990         : CBaseSplitterFile(pAsyncReader, hr)
    00991 {
    00992         if(FAILED(hr)) return;
    00993         hr = Init();
    00994 }
    00995
    00996 template<typename T>
    00997 HRESULT CRMFile::Read(T& var)
    00998 {
    00999         HRESULT hr = Read((BYTE*)&var, sizeof(var));
    01000         bswap(var);
    01001         return hr;
    01002 }
    01003
    01004 HRESULT CRMFile::Read(ChunkHdr& hdr)
    01005 {
    01006         memset(&hdr, 0, sizeof(hdr));
    01007         HRESULT hr;
    01008         if(S_OK != (hr = Read(hdr.object_id))
    01009         || S_OK != (hr = Read(hdr.size))
    01010         || S_OK != (hr = Read(hdr.object_version)))
    01011                 return hr;
    01012         return S_OK;
    01013 }
    01014
    01015 HRESULT CRMFile::Read(MediaPacketHeader& mph, bool fFull)
    01016 {
    01017         memset(&mph, 0, FIELD_OFFSET(MediaPacketHeader, pData));
    01018         mph.stream = -1;
    01019
    01020         HRESULT hr;
    01021
    01022         UINT16 object_version;
    01023         if(S_OK != (hr = Read(object_version))) return hr;
    01024         if(object_version != 0 && object_version != 1) return S_OK;
    01025
    01026         UINT8 flags;
    01027         if(S_OK != (hr = Read(mph.len))
    01028         || S_OK != (hr = Read(mph.stream))
    01029         || S_OK != (hr = Read(mph.tStart))
    01030         || S_OK != (hr = Read(mph.reserved))
    01031         || S_OK != (hr = Read(flags)))
    01032                 return hr;
    01033         mph.flags = (MediaPacketHeader::flag_t)flags;
    01034
    01035         LONG len = mph.len;
    01036         len -= sizeof(object_version);
    01037         len -= FIELD_OFFSET(MediaPacketHeader, flags);
    01038         len -= sizeof(flags);
    01039         ASSERT(len >= 0);
    01040         len = max(len, 0);
    01041
    01042         if(fFull)
    01043         {
    01044                 mph.pData.SetSize(len);
    01045                 if(mph.len > 0 && S_OK != (hr = Read(mph.pData.GetData(), len)))
    01046                         return hr;
    01047         }
    01048         else
    01049         {
    01050                 Seek(GetPos() + len);
    01051         }
    01052
    01053         return S_OK;
    01054 }
    01055
    01056
    01057 HRESULT CRMFile::Init()
    01058 {
    01059         Seek(0);
    01060
    01061         bool fFirstChunk = true;
    01062
    01063         HRESULT hr;
    01064
    01065         ChunkHdr hdr;
    01066         while(GetPos() < GetLength() && S_OK == (hr = Read(hdr)))
    01067         {
    01068                 __int64 pos = GetPos() - sizeof(hdr);
    01069
    01070                 if(fFirstChunk && hdr.object_id != '.RMF')
    01071                         return E_FAIL;
    01072
    01073                 fFirstChunk = false;
    01074
    01075                 if(pos + hdr.size > GetLength() && hdr.object_id != 'DATA') // truncated?
    01076                         break;
    01077
    01078                 if(hdr.object_id == 0x2E7261FD) // '.ra+0xFD'
    01079                         return E_FAIL;
    01080
    01081                 if(hdr.object_version == 0)
    01082                 {
    01083                         switch(hdr.object_id)
    01084                         {
    01085                         case '.RMF':
    01086                                 if(S_OK != (hr = Read(m_fh.version))) return hr;
    01087                                 if(hdr.size == 0x10) {WORD w = 0; if(S_OK != (hr = Read(w))) return hr; m_fh.nHeaders = w;}
    01088                                 else if(S_OK != (hr = Read(m_fh.nHeaders))) return hr;
    01089                                 break;
    01090                         case 'CONT':
    01091                                 UINT16 slen;
    01092                                 if(S_OK != (hr = Read(slen))) return hr;
    01093                                 if(slen > 0 && S_OK != (hr = Read((BYTE*)m_cd.title.GetBufferSetLength(slen), slen))) return hr;
    01094                                 if(S_OK != (hr = Read(slen))) return hr;
    01095                                 if(slen > 0 && S_OK != (hr = Read((BYTE*)m_cd.author.GetBufferSetLength(slen), slen))) return hr;
    01096                                 if(S_OK != (hr = Read(slen))) return hr;
    01097                                 if(slen > 0 && S_OK != (hr = Read((BYTE*)m_cd.copyright.GetBufferSetLength(slen), slen))) return hr;
    01098                                 if(S_OK != (hr = Read(slen))) return hr;
    01099                                 if(slen > 0 && S_OK != (hr = Read((BYTE*)m_cd.comment.GetBufferSetLength(slen), slen))) return hr;
    01100                                 break;
    01101                         case 'PROP':
    01102                                 if(S_OK != (hr = Read(m_p.maxBitRate))) return hr;
    01103                                 if(S_OK != (hr = Read(m_p.avgBitRate))) return hr;
    01104                                 if(S_OK != (hr = Read(m_p.maxPacketSize))) return hr;
    01105                                 if(S_OK != (hr = Read(m_p.avgPacketSize))) return hr;
    01106                                 if(S_OK != (hr = Read(m_p.nPackets))) return hr;
    01107                                 if(S_OK != (hr = Read(m_p.tDuration))) return hr;
    01108                                 if(S_OK != (hr = Read(m_p.tPreroll))) return hr;
    01109                                 if(S_OK != (hr = Read(m_p.ptrIndex))) return hr;
    01110                                 if(S_OK != (hr = Read(m_p.ptrData))) return hr;
    01111                                 if(S_OK != (hr = Read(m_p.nStreams))) return hr;
    01112                                 UINT16 flags;
    01113                                 if(S_OK != (hr = Read(flags))) return hr;
    01114                                 m_p.flags = (Properies::flags_t)flags;
    01115                                 break;
    01116                         case 'MDPR':
    01117                                 {
    01118                                 CAutoPtr<MediaProperies> mp(new MediaProperies);
    01119                                 if(S_OK != (hr = Read(mp->stream))) return hr;
    01120                                 if(S_OK != (hr = Read(mp->maxBitRate))) return hr;
    01121                                 if(S_OK != (hr = Read(mp->avgBitRate))) return hr;
    01122                                 if(S_OK != (hr = Read(mp->maxPacketSize))) return hr;
    01123                                 if(S_OK != (hr = Read(mp->avgPacketSize))) return hr;
    01124                                 if(S_OK != (hr = Read(mp->tStart))) return hr;
    01125                                 if(S_OK != (hr = Read(mp->tPreroll))) return hr;
    01126                                 if(S_OK != (hr = Read(mp->tDuration))) return hr;
    01127                                 UINT8 slen;
    01128                                 if(S_OK != (hr = Read(slen))) return hr;
    01129                                 if(slen > 0 && S_OK != (hr = Read((BYTE*)mp->name.GetBufferSetLength(slen), slen))) return hr;
    01130                                 if(S_OK != (hr = Read(slen))) return hr;
    01131                                 if(slen > 0 && S_OK != (hr = Read((BYTE*)mp->mime.GetBufferSetLength(slen), slen))) return hr;
    01132                                 UINT32 tsdlen;
    01133                                 if(S_OK != (hr = Read(tsdlen))) return hr;
    01134                                 mp->typeSpecData.SetSize(tsdlen);
    01135                                 if(tsdlen > 0 && S_OK != (hr = Read(mp->typeSpecData.GetData(), tsdlen))) return hr;
    01136                                 mp->width = mp->height = 0;
    01137                                 mp->interlaced = mp->top_field_first = false;
    01138                                 m_mps.AddTail(mp);
    01139                                 break;
    01140                                 }
    01141                         case 'DATA':
    01142                                 {
    01143                                 CAutoPtr<DataChunk> dc(new DataChunk);
    01144                                 if(S_OK != (hr = Read(dc->nPackets))) return hr;
    01145                                 if(S_OK != (hr = Read(dc->ptrNext))) return hr;
    01146                                 dc->pos = GetPos();
    01147                                 m_dcs.AddTail(dc);
    01148                 GetDimensions();
    01149                                 break;
    01150                                 }
    01151                         case 'INDX':
    01152                                 {
    01153                                 IndexChunkHeader ich;
    01154                                 if(S_OK != (hr = Read(ich.nIndices))) return hr;
    01155                                 if(S_OK != (hr = Read(ich.stream))) return hr;
    01156                                 if(S_OK != (hr = Read(ich.ptrNext))) return hr;
    01157                                 int stream = GetMasterStream();
    01158                                 while(ich.nIndices-- > 0)
    01159                                 {
    01160                                         UINT16 object_version;
    01161                                         if(S_OK != (hr = Read(object_version))) return hr;
    01162                                         if(object_version == 0)
    01163                                         {
    01164                                                 CAutoPtr<IndexRecord> ir(new IndexRecord);
    01165                                                 if(S_OK != (hr = Read(ir->tStart))) return hr;
    01166                                                 if(S_OK != (hr = Read(ir->ptrFilePos))) return hr;
    01167                                                 if(S_OK != (hr = Read(ir->packet))) return hr;
    01168                                                 if(ich.stream == stream) m_irs.AddTail(ir);
    01169                                         }
    01170                                 }
    01171                                 break;
    01172                                 }
    01173                         case '.SUB':
    01174                                 if(hdr.size > sizeof(hdr))
    01175                                 {
    01176                                         int size = hdr.size - sizeof(hdr);
    01177                                         CAutoVectorPtr<char> buff;
    01178                                         if(!buff.Allocate(size)) return E_OUTOFMEMORY;
    01179                                         char* p = buff;
    01180                                         if(S_OK != (hr = Read((BYTE*)p, size))) return hr;
    01181                                         for(char* end = p + size; p < end; )
    01182                                         {
    01183                                                 subtitle s;
    01184                                                 s.name = p; p += s.name.GetLength()+1;
    01185                                                 CStringA len(p); p += len.GetLength()+1;
    01186                                                 s.data = CStringA(p, strtol(len, NULL, 10)); p += s.data.GetLength();
    01187                                                 m_subs.AddTail(s);
    01188                                         }
    01189                                 }
    01190                                 break;
    01191                         }
    01192                 }
    01193
    01194                 ASSERT(hdr.object_id == 'DATA'
    01195                         || GetPos() == pos + hdr.size
    01196                         || GetPos() == pos + sizeof(hdr));
    01197
    01198                 pos += hdr.size;
    01199                 if(pos > GetPos())
    01200                         Seek(pos);
    01201         }
    01202
    01203         return S_OK;
    01204 }
    01205
    01206 #define GetBits(n) GetBits2(n, p, bit_offset, bit_buffer)
    01207
    01208 unsigned int GetBits2(int n, unsigned char*& p, unsigned int& bit_offset, unsigned int& bit_buffer)
    01209 {
    01210         unsigned int ret = ((unsigned int)bit_buffer >> (32-(n)));
    01211
    01212         bit_offset += n;
    01213         bit_buffer <<= n;
    01214         if(bit_offset > (32-16))
    01215         {
    01216                 p += bit_offset >> 3;
    01217                 bit_offset &= 7;
    01218                 bit_buffer = (unsigned int)p[0] << 24;
    01219                 bit_buffer |= (unsigned int)p[1] << 16;
    01220                 bit_buffer |= (unsigned int)p[2] << 8;
    01221                 bit_buffer |= (unsigned int)p[3];
    01222                 bit_buffer <<= bit_offset;
    01223         }
    01224
    01225         return ret;
    01226 }
    01227
    01228 void GetDimensions(unsigned char* p, unsigned int* wi, unsigned int* hi)
    01229 {
    01230         unsigned int w, h, c;
    01231
    01232         const unsigned int cw[8] = {160, 176, 240, 320, 352, 640, 704, 0};
    01233         const unsigned int ch1[8] = {120, 132, 144, 240, 288, 480, 0, 0};
    01234         const unsigned int ch2[4] = {180, 360, 576, 0};
    01235
    01236         unsigned int bit_offset = 0;
    01237         unsigned int bit_buffer = *(unsigned int*)p;
    01238         bswap(bit_buffer);
    01239
    01240         GetBits(13);
    01241
    01242         GetBits(13);
    01243
    01244         w = cw[GetBits(3)];
    01245         if(w == 0)
    01246         {
    01247                 do
    01248                 {
    01249                         c = GetBits(8);
    01250                         w += (c << 2);
    01251                 }
    01252                 while(c == 255);
    01253         }
    01254
    01255         c = GetBits(3);
    01256
    01257         h = ch1[c];
    01258         if(h == 0)
    01259         {
    01260                 c = ((c << 1) | GetBits(1)) & 3;
    01261
    01262                 h = ch2[c];
    01263                 if(h == 0)
    01264                 {
    01265                         do
    01266                         {
    01267                                 c = GetBits(8);
    01268                                 h += (c << 2);
    01269                         }
    01270                         while(c == 255);
    01271                 }
    01272         }
    01273
    01274         *wi = w;
    01275         *hi = h;
    01276 }
    01277
    01278 void GetDimensions_X10(unsigned char* p, unsigned int* wi, unsigned int* hi,
    01279                                            bool *interlaced, bool *top_field_first, bool *repeat_field)
    01280 {
    01281         unsigned int w, h, c;
    01282
    01283         const unsigned int cw[8] = {160, 176, 240, 320, 352, 640, 704, 0};
    01284         const unsigned int ch1[8] = {120, 132, 144, 240, 288, 480, 0, 0};
    01285         const unsigned int ch2[4] = {180, 360, 576, 0};
    01286
    01287         unsigned int bit_offset = 0;
    01288         unsigned int bit_buffer = *(unsigned int*)p;
    01289         bswap(bit_buffer);
    01290
    01291         GetBits(9);
    01292
    01293         *interlaced = false;
    01294         *top_field_first = false;
    01295         *repeat_field = false;
    01296         c = GetBits(1);
    01297         if (c)
    01298         {
    01299                 c = GetBits(1);
    01300                 if (c)
    01301                         *interlaced = true;
    01302                 c = GetBits(1);
    01303                 if (c)
    01304                         *top_field_first = true;
    01305                 c = GetBits(1);
    01306                 if (c)
    01307                         *repeat_field = true;
    01308
    01309                 c = GetBits(1);
    01310                 c = GetBits(1);
    01311                 if (c)
    01312                         GetBits(2);
    01313         }
    01314
    01315         GetBits(16);
    01316
    01317         w = cw[GetBits(3)];
    01318         if(w == 0)
    01319         {
    01320                 do
    01321                 {
    01322                         c = GetBits(8);
    01323                         w += (c << 2);
    01324                 }
    01325                 while(c == 255);
    01326         }
    01327
    01328         c = GetBits(3);
    01329
    01330         h = ch1[c];
    01331         if(h == 0)
    01332         {
    01333                 c = ((c << 1) | GetBits(1)) & 3;
    01334
    01335                 h = ch2[c];
    01336                 if(h == 0)
    01337                 {
    01338                         do
    01339                         {
    01340                                 c = GetBits(8);
    01341                                 h += (c << 2);
    01342                         }
    01343                         while(c == 255);
    01344                 }
    01345         }
    01346
    01347         *wi = w;
    01348         *hi = h;
    01349 }
    01350
    01351 void CRMFile::GetDimensions()
    01352 {
    01353         POSITION pos = m_mps.GetHeadPosition();
    01354         while(pos)
    01355         {
    01356                 UINT64 filepos = GetPos();
    01357
    01358                 MediaProperies* pmp = m_mps.GetNext(pos);
    01359                 if(pmp->mime == "video/x-pn-realvideo")
    01360                 {
    01361                         pmp->width = pmp->height = 0;
    01362
    01363                         rvinfo rvi = *(rvinfo*)pmp->typeSpecData.GetData();
    01364                         rvi.bswap();
    01365
    01366                         if(rvi.fcc2 != '04VR' && rvi.fcc2 != '14VR')
    01367                                 continue;
    01368
    01369                         MediaPacketHeader mph;
    01370                         while(S_OK == Read(mph))
    01371                         {
    01372                                 if(mph.stream != pmp->stream || mph.len == 0
    01373                                 || !(mph.flags&MediaPacketHeader::PN_KEYFRAME_FLAG))
    01374                                         continue;
    01375
    01376                                 BYTE* p = mph.pData.GetData();
    01377                                 BYTE* p0 = p;
    01378                                 int len = mph.pData.GetCount();
    01379
    01380                                 BYTE hdr = *p++;
    01381                                 DWORD packetlen = 0, packetoffset = 0;
    01382
    01383                                 if((hdr&0xc0) == 0x40)
    01384                                 {
    01385                                         packetlen = len - (++p - p0);
    01386                                 }
    01387                                 else
    01388                                 {
    01389                                         if((hdr&0x40) == 0) p++;
    01390
    01391                                         #define GetWORD(var) \
    01392                                                 var = (var<<8)|(*p++); \
    01393                                                 var = (var<<8)|(*p++); \
    01394
    01395                                         GetWORD(packetlen);
    01396                                         if((packetlen&0x4000) == 0) {GetWORD(packetlen); packetlen &= 0x3fffffff;}
    01397                                         else packetlen &= 0x3fff;
    01398
    01399                                         GetWORD(packetoffset);
    01400                                         if((packetoffset&0x4000) == 0) {GetWORD(packetoffset); packetoffset &= 0x3fffffff;}
    01401                                         else packetoffset &= 0x3fff;
    01402
    01403                                         #undef GetWORD
    01404
    01405                                         if((hdr&0xc0) == 0xc0) packetoffset = 0;
    01406                                         else if((hdr&0xc0) == 0x80) packetoffset = packetlen - packetoffset;
    01407
    01408                                         p++;
    01409                                 }
    01410
    01411                                 len = min(len - (p - p0), packetlen - packetoffset);
    01412
    01413                                 if(len > 0)
    01414                                 {
    01415                                         bool repeat_field;
    01416                                         if(rvi.fcc2 == '14VR') ::GetDimensions_X10(p, &pmp->width, &pmp->height, &pmp->interlaced, &pmp->top_field_first, &repeat_field);
    01417                                         else ::GetDimensions(p, &pmp->width, &pmp->height);
    01418
    01419                                         if(rvi.w == pmp->width && rvi.h == pmp->height)
    01420                                                 pmp->width = pmp->height = 0;
    01421
    01422                                         break;
    01423                                 }
    01424                         }
    01425                 }
    01426
    01427                 Seek(filepos);
    01428         }
    01429 }
    01430
    01431 int CRMFile::GetMasterStream()
    01432 {
    01433         int s1 = -1, s2 = -1;
    01434
    01435         POSITION pos = m_mps.GetHeadPosition();
    01436         while(pos)
    01437         {
    01438                 MediaProperies* pmp = m_mps.GetNext(pos);
    01439                 if(pmp->mime == "video/x-pn-realvideo") {s1 = pmp->stream; break;}
    01440                 else if(pmp->mime == "audio/x-pn-realaudio" && s2 == -1) s2 = pmp->stream;
    01441         }
    01442
    01443         if(s1 == -1)
    01444                 s1 = s2;
    01445
    01446         return s1;
    01447 }
    01448
    01449
    01451
    01452 //
    01453 // CRealVideoDecoder
    01454 //
    01455
    01456 CRealVideoDecoder::CRealVideoDecoder(LPUNKNOWN lpunk, HRESULT* phr)
    01457         : CBaseVideoFilter(NAME("CRealVideoDecoder"), lpunk, phr, __uuidof(this))
    01458         , m_hDrvDll(NULL)
    01459         , m_dwCookie(0)
    01460 {
    01461 }
    01462
    01463 CRealVideoDecoder::~CRealVideoDecoder()
    01464 {
    01465         if(m_hDrvDll) FreeLibrary(m_hDrvDll);
    01466 }
    01467
    01468 HRESULT CRealVideoDecoder::InitRV(const CMediaType* pmt)
    01469 {
    01470         FreeRV();
    01471
    01472         HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
    01473
    01474         rvinfo rvi = *(rvinfo*)(pmt->Format() + (pmt->formattype == FORMAT_VideoInfo ? sizeof(VIDEOINFOHEADER) : sizeof(VIDEOINFOHEADER2)));
    01475         rvi.bswap();
    01476
    01477         #pragma pack(push, 1)
    01478         struct {WORD unk1, w, h, unk3; DWORD unk2, subformat, unk5, format;} i =
    01479                 {11, rvi.w, rvi.h, 0, 0, rvi.type1, 1, rvi.type2};
    01480         #pragma pack(pop)
    01481
    01482         if(FAILED(hr = RVInit(&i, &m_dwCookie)))
    01483                 return hr;
    01484
    01485         if(rvi.fcc2 <= '03VR' && rvi.type2 >= 0x20200002)
    01486         {
    01487                 int nWidthHeight = (1+((rvi.type1>>16)&7));
    01488                 UINT32* pWH = new UINT32[nWidthHeight*2];
    01489                 pWH[0] = rvi.w; pWH[1] = rvi.h;
    01490                 for(int i = 2; i < nWidthHeight*2; i++)
    01491                         pWH[i] = rvi.morewh[i-2]*4;
    01492                 #pragma pack(push, 1)
    01493                 struct {UINT32 data1; UINT32 data2; UINT32* dimensions;} cmsg_data =
    01494                         {0x24, nWidthHeight, pWH};
    01495                 #pragma pack(pop)
    01496                 hr = RVCustomMessage(&cmsg_data, m_dwCookie);
    01497                 delete [] pWH;
    01498         }
    01499
    01500         return hr;
    01501 }
    01502
    01503 void CRealVideoDecoder::FreeRV()
    01504 {
    01505         if(m_dwCookie)
    01506         {
    01507                 RVFree(m_dwCookie);
    01508                 m_dwCookie = 0;
    01509         }
    01510 }
    01511
    01512 HRESULT CRealVideoDecoder::Transform(IMediaSample* pIn)
    01513 {
    01514         CAutoLock cAutoLock(&m_csReceive);
    01515
    01516         HRESULT hr;
    01517
    01518         BYTE* pDataIn = NULL;
    01519         if(FAILED(hr = pIn->GetPointer(&pDataIn)))
    01520                 return hr;
    01521
    01522         long len = pIn->GetActualDataLength();
    01523         if(len <= 0) return S_OK; // nothing to do
    01524
    01525         REFERENCE_TIME rtStart, rtStop;
    01526         pIn->GetTime(&rtStart, &rtStop);
    01527
    01528         rtStart += m_tStart;
    01529
    01530         int offset = 1+((*pDataIn)+1)*8;
    01531
    01532         #pragma pack(push, 1)
    01533         struct {DWORD len, unk1, chunks; DWORD* extra; DWORD unk2, timestamp;} transform_in =
    01534                 {len - offset, 0, *pDataIn, (DWORD*)(pDataIn+1), 0, (DWORD)(rtStart/10000)};
    01535         struct {DWORD unk1, unk2, timestamp, w, h;} transform_out =
    01536                 {0,0,0,0,0};
    01537         #pragma pack(pop)
    01538
    01539         pDataIn += offset;
    01540
    01541         if(m_fDropFrames && m_timestamp+1 == transform_in.timestamp)
    01542         {
    01543                 m_timestamp = transform_in.timestamp;
    01544                 return S_OK;
    01545         }
    01546
    01547         hr = RVTransform(pDataIn, (BYTE*)m_pI420, &transform_in, &transform_out, m_dwCookie);
    01548
    01549         unsigned int tmp1, tmp2;
    01550         bool interlaced = false, tmp3, tmp4;
    01551         ::GetDimensions_X10(pDataIn, &tmp1, &tmp2, &interlaced, &tmp3, &tmp4);
    01552
    01553         m_timestamp = transform_in.timestamp;
    01554
    01555         if(FAILED(hr))
    01556         {
    01557                 TRACE(_T("RV returned an error code!!!\n"));
    01558                 ASSERT(!(transform_out.unk1&1)); // error allowed when the "render" flag is not set
    01559 //              return hr;
    01560         }
    01561
    01562         if(pIn->IsPreroll() == S_OK || rtStart < 0 || !(transform_out.unk1&1))
    01563                 return S_OK;
    01564
    01565         CComPtr<IMediaSample> pOut;
    01566         BYTE* pDataOut = NULL;
    01567         if(/*FAILED(hr = GetDeliveryBuffer(transform_out.w, transform_out.h, &pOut)) // TODO
    01568         && */ FAILED(hr = GetDeliveryBuffer(m_w, m_h, &pOut))
    01569         || FAILED(hr = pOut->GetPointer(&pDataOut)))
    01570                 return hr;
    01571
    01572         BYTE* pI420[3] = {m_pI420, m_pI420Tmp, NULL};
    01573
    01574         if(interlaced)
    01575         {
    01576                 int size = m_w*m_h;
    01577                 DeinterlaceBlend(pI420[1], pI420[0], m_w, m_h, m_w, m_w);
    01578                 DeinterlaceBlend(pI420[1]+size, pI420[0]+size, m_w/2, m_h/2, m_w/2, m_w/2);
    01579                 DeinterlaceBlend(pI420[1]+size*5/4, pI420[0]+size*5/4, m_w/2, m_h/2, m_w/2, m_w/2);
    01580                 pI420[2] = pI420[1], pI420[1] = pI420[0], pI420[0] = pI420[2];
    01581         }
    01582
    01583         if(transform_out.w != m_w || transform_out.h != m_h)
    01584         {
    01585                 Resize(pI420[0], transform_out.w, transform_out.h, pI420[1], m_w, m_h);
    01586                 // only one of these can be true, and when it happens the result image must be in the tmp buffer
    01587                 if(transform_out.w == m_w || transform_out.h == m_h)
    01588                         pI420[2] = pI420[1], pI420[1] = pI420[0], pI420[0] = pI420[2];
    01589         }
    01590
    01591         rtStart = 10000i64*transform_out.timestamp - m_tStart;
    01592         rtStop = rtStart + 1;
    01593         pOut->SetTime(&rtStart, /*NULL*/&rtStop);
    01594
    01595         pOut->SetDiscontinuity(pIn->IsDiscontinuity() == S_OK);
    01596
    01597         CopyBuffer(pDataOut, pI420[0], m_w, m_h, m_w, MEDIASUBTYPE_I420);
    01598
    01599 DbgLog((LOG_TRACE, 0, _T("V: rtStart=%I64d, rtStop=%I64d, disc=%d, sync=%d"),
    01600            rtStart, rtStop, pOut->IsDiscontinuity() == S_OK, pOut->IsSyncPoint() == S_OK));
    01601
    01602         return m_pOutput->Deliver(pOut);
    01603 }
    01604
    01605 void CRealVideoDecoder::Resize(BYTE* pIn, DWORD wi, DWORD hi, BYTE* pOut, DWORD wo, DWORD ho)
    01606 {
    01607         int si = wi*hi, so = wo*ho;
    01608         ASSERT(((si*so)&3) == 0);
    01609
    01610         if(wi < wo)
    01611         {
    01612                 ResizeWidth(pIn, wi, hi, pOut, wo, ho);
    01613                 ResizeWidth(pIn + si, wi/2, hi/2, pOut + so, wo/2, ho/2);
    01614                 ResizeWidth(pIn + si + si/4, wi/2, hi/2, pOut + so + so/4, wo/2, ho/2);
    01615                 if(hi == ho) return;
    01616                 ResizeHeight(pOut, wo, hi, pIn, wo, ho);
    01617                 ResizeHeight(pOut + so, wo/2, hi/2, pIn + so, wo/2, ho/2);
    01618                 ResizeHeight(pOut + so + so/4, wo/2, hi/2, pIn + so + so/4, wo/2, ho/2);
    01619         }
    01620         else if(hi < ho)
    01621         {
    01622                 ResizeHeight(pIn, wi, hi, pOut, wo, ho);
    01623                 ResizeHeight(pIn + si, wi/2, hi/2, pOut + so, wo/2, ho/2);
    01624                 ResizeHeight(pIn + si + si/4, wi/2, hi/2, pOut + so + so/4, wo/2, ho/2);
    01625                 if(wi == wo) return;
    01626                 ASSERT(0); // this is uncreachable code, but anyway... looks nice being so symmetric
    01627                 ResizeWidth(pOut, wi, ho, pIn, wo, ho);
    01628                 ResizeWidth(pOut + so, wi/2, ho/2, pIn + so, wo/2, ho/2);
    01629                 ResizeWidth(pOut + so + so/4, wi/2, ho/2, pIn + so + so/4, wo/2, ho/2);
    01630         }
    01631 }
    01632
    01633 void CRealVideoDecoder::ResizeWidth(BYTE* pIn, DWORD wi, DWORD hi, BYTE* pOut, DWORD wo, DWORD ho)
    01634 {
    01635         for(DWORD y = 0; y < hi; y++, pIn += wi, pOut += wo)
    01636         {
    01637                 if(wi == wo) memcpy_accel(pOut, pIn, wo);
    01638                 else ResizeRow(pIn, wi, 1, pOut, wo, 1);
    01639         }
    01640 }
    01641
    01642 void CRealVideoDecoder::ResizeHeight(BYTE* pIn, DWORD wi, DWORD hi, BYTE* pOut, DWORD wo, DWORD ho)
    01643 {
    01644         if(hi == ho)
    01645         {
    01646                 memcpy_accel(pOut, pIn, wo*ho);
    01647         }
    01648         else
    01649         {
    01650                 for(DWORD x = 0; x < wo; x++, pIn++, pOut++)
    01651                         ResizeRow(pIn, hi, wo, pOut, ho, wo);
    01652         }
    01653 }
    01654
    01655 void CRealVideoDecoder::ResizeRow(BYTE* pIn, DWORD wi, DWORD dpi, BYTE* pOut, DWORD wo, DWORD dpo)
    01656 {
    01657         ASSERT(wi < wo);
    01658
    01659     if(dpo == 1)
    01660         {
    01661                 for(DWORD i = 0, j = 0, dj = (wi<<16)/wo; i < wo-1; i++, pOut++, j += dj)
    01662 //                      pOut[i] = pIn[j>>16];
    01663                 {
    01664                         BYTE* p = &pIn[j>>16];
    01665                         DWORD jf = j&0xffff;
    01666                         *pOut = ((p[0]*(0xffff-jf) + p[1]*jf) + 0x7fff) >> 16;
    01667                 }
    01668
    01669                 *pOut = pIn[wi-1];
    01670         }
    01671         else
    01672         {
    01673                 for(DWORD i = 0, j = 0, dj = (wi<<16)/wo; i < wo-1; i++, pOut += dpo, j += dj)
    01674 //                      *pOut = pIn[dpi*(j>>16)];
    01675                 {
    01676                         BYTE* p = &pIn[dpi*(j>>16)];
    01677                         DWORD jf = j&0xffff;
    01678                         *pOut = ((p[0]*(0xffff-jf) + p[dpi]*jf) + 0x7fff) >> 16;
    01679                 }
    01680
    01681                 *pOut = pIn[dpi*(wi-1)];
    01682         }
    01683 }
    01684
    01685 HRESULT CRealVideoDecoder::CheckInputType(const CMediaType* mtIn)
    01686 {
    01687         if(mtIn->majortype != MEDIATYPE_Video
    01688         || mtIn->subtype != MEDIASUBTYPE_RV20
    01689         && mtIn->subtype != MEDIASUBTYPE_RV30
    01690         && mtIn->subtype != MEDIASUBTYPE_RV40
    01691         && mtIn->subtype != MEDIASUBTYPE_RV41)
    01692                 return VFW_E_TYPE_NOT_ACCEPTED;
    01693
    01694         if(mtIn->formattype == FORMAT_VideoInfo2)
    01695         {
    01696                 VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mtIn->Format();
    01697                 if(vih2->dwPictAspectRatioX < vih2->bmiHeader.biWidth
    01698                 || vih2->dwPictAspectRatioY < vih2->bmiHeader.biHeight)
    01699                         return VFW_E_TYPE_NOT_ACCEPTED;
    01700         }
    01701
    01702         if(!m_pInput->IsConnected())
    01703         {
    01704                 if(m_hDrvDll) {FreeLibrary(m_hDrvDll); m_hDrvDll = NULL;}
    01705
    01706                 CList<CString> paths;
    01707                 CString olddll, newdll, oldpath, newpath;
    01708
    01709                 olddll.Format(_T("drv%c3260.dll"), (TCHAR)((mtIn->subtype.Data1>>16)&0xff));
    01710                 newdll =
    01711                         mtIn->subtype == FOURCCMap('14VR') ? _T("drvi.dll") :
    01712                         mtIn->subtype == FOURCCMap('02VR') ? _T("drv2.dll") :
    01713                         _T("drvc.dll");
    01714
    01715                 CRegKey key;
    01716                 TCHAR buff[MAX_PATH];
    01717                 ULONG len = sizeof(buff);
    01718                 if(ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Software\\RealNetworks\\Preferences\\DT_Codecs"), KEY_READ)
    01719                 && ERROR_SUCCESS == key.QueryStringValue(NULL, buff, &len) && _tcslen(buff) > 0)
    01720                 {
    01721                         oldpath = buff;
    01722                         TCHAR c = oldpath[oldpath.GetLength()-1];
    01723                         if(c != '\\' && c != '/') oldpath += '\\';
    01724                         key.Close();
    01725                 }
    01726                 len = sizeof(buff);
    01727                 if(ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Helix\\HelixSDK\\10.0\\Preferences\\DT_Codecs"), KEY_READ)
    01728                 && ERROR_SUCCESS == key.QueryStringValue(NULL, buff, &len) && _tcslen(buff) > 0)
    01729                 {
    01730                         newpath = buff;
    01731                         TCHAR c = newpath[newpath.GetLength()-1];
    01732                         if(c != '\\' && c != '/') newpath += '\\';
    01733                         key.Close();
    01734                 }
    01735
    01736                 if(!newpath.IsEmpty()) paths.AddTail(newpath + newdll);
    01737                 if(!oldpath.IsEmpty()) paths.AddTail(oldpath + newdll);
    01738                 paths.AddTail(newdll); // default dll paths
    01739                 if(!newpath.IsEmpty()) paths.AddTail(newpath + olddll);
    01740                 if(!oldpath.IsEmpty()) paths.AddTail(oldpath + olddll);
    01741                 paths.AddTail(olddll); // default dll paths
    01742
    01743                 POSITION pos = paths.GetHeadPosition();
    01744                 while(pos && !(m_hDrvDll = LoadLibrary(paths.GetNext(pos))));
    01745
    01746                 if(m_hDrvDll)
    01747                 {
    01748                         RVCustomMessage = (PRVCustomMessage)GetProcAddress(m_hDrvDll, "RV20toYUV420CustomMessage");
    01749                         RVFree = (PRVFree)GetProcAddress(m_hDrvDll, "RV20toYUV420Free");
    01750                         RVHiveMessage = (PRVHiveMessage)GetProcAddress(m_hDrvDll, "RV20toYUV420HiveMessage");
    01751                         RVInit = (PRVInit)GetProcAddress(m_hDrvDll, "RV20toYUV420Init");
    01752                         RVTransform = (PRVTransform)GetProcAddress(m_hDrvDll, "RV20toYUV420Transform");
    01753
    01754                         if(!RVCustomMessage) RVCustomMessage = (PRVCustomMessage)GetProcAddress(m_hDrvDll, "RV40toYUV420CustomMessage");
    01755                         if(!RVFree) RVFree = (PRVFree)GetProcAddress(m_hDrvDll, "RV40toYUV420Free");
    01756                         if(!RVHiveMessage) RVHiveMessage = (PRVHiveMessage)GetProcAddress(m_hDrvDll, "RV40toYUV420HiveMessage");
    01757                         if(!RVInit) RVInit = (PRVInit)GetProcAddress(m_hDrvDll, "RV40toYUV420Init");
    01758                         if(!RVTransform) RVTransform = (PRVTransform)GetProcAddress(m_hDrvDll, "RV40toYUV420Transform");
    01759                 }
    01760
    01761                 if(!m_hDrvDll || !RVCustomMessage
    01762                 || !RVFree || !RVHiveMessage
    01763                 || !RVInit || !RVTransform)
    01764                         return VFW_E_TYPE_NOT_ACCEPTED;
    01765
    01766                 if(FAILED(InitRV(mtIn)))
    01767                         return VFW_E_TYPE_NOT_ACCEPTED;
    01768         }
    01769
    01770         return S_OK;
    01771 }
    01772
    01773 HRESULT CRealVideoDecoder::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
    01774 {
    01775         if(m_pOutput && m_pOutput->IsConnected())
    01776         {
    01777                 BITMAPINFOHEADER bih1, bih2;
    01778                 if(ExtractBIH(mtOut, &bih1) && ExtractBIH(&m_pOutput->CurrentMediaType(), &bih2)
    01779                 && abs(bih1.biHeight) != abs(bih2.biHeight))
    01780                         return VFW_E_TYPE_NOT_ACCEPTED;
    01781         }
    01782
    01783         return __super::CheckTransform(mtIn, mtOut);
    01784 }
    01785
    01786 HRESULT CRealVideoDecoder::StartStreaming()
    01787 {
    01788         const CMediaType& mt = m_pInput->CurrentMediaType();
    01789         if(FAILED(InitRV(&mt)))
    01790                 return E_FAIL;
    01791
    01792         int size = m_w*m_h;
    01793         m_pI420.Allocate(size*3/2);
    01794         memset(m_pI420, 0, size);
    01795         memset(m_pI420 + size, 0x80, size/2);
    01796         m_pI420Tmp.Allocate(size*3/2);
    01797         memset(m_pI420Tmp, 0, size);
    01798         memset(m_pI420Tmp + size, 0x80, size/2);
    01799
    01800         return __super::StartStreaming();
    01801 }
    01802
    01803 HRESULT CRealVideoDecoder::StopStreaming()
    01804 {
    01805         m_pI420.Free();
    01806         m_pI420Tmp.Free();
    01807
    01808         FreeRV();
    01809
    01810         return __super::StopStreaming();
    01811 }
    01812
    01813 HRESULT CRealVideoDecoder::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
    01814 {
    01815         CAutoLock cAutoLock(&m_csReceive);
    01816
    01817         m_timestamp = ~0;
    01818         m_fDropFrames = false;
    01819
    01820         DWORD tmp[2] = {20, 0};
    01821         RVHiveMessage(tmp, m_dwCookie);
    01822
    01823         m_tStart = tStart;
    01824         return __super::NewSegment(tStart, tStop, dRate);
    01825 }
    01826
    01827 HRESULT CRealVideoDecoder::AlterQuality(Quality q)
    01828 {
    01829         if(q.Late > 500*10000i64) m_fDropFrames = true;
    01830         if(q.Late <= 0) m_fDropFrames = false;
    01831 //      TRACE(_T("CRealVideoDecoder::AlterQuality: Type=%d, Proportion=%d, Late=%I64d, TimeStamp=%I64d\n"), q.Type, q.Proportion, q.Late, q.TimeStamp);
    01832         return E_NOTIMPL;
    01833 }
    01834
    01836
    01837 //
    01838 // CRealAudioDecoder
    01839 //
    01840
    01841 CRealAudioDecoder::CRealAudioDecoder(LPUNKNOWN lpunk, HRESULT* phr)
    01842         : CTransformFilter(NAME("CRealAudioDecoder"), lpunk, __uuidof(this))
    01843         , m_hDrvDll(NULL)
    01844         , m_dwCookie(0)
    01845 {
    01846         if(phr) *phr = S_OK;
    01847 }
    01848
    01849 CRealAudioDecoder::~CRealAudioDecoder()
    01850 {
    01851 //      FreeRA();
    01852         if(m_hDrvDll) FreeLibrary(m_hDrvDll);
    01853 }
    01854
    01855 HRESULT CRealAudioDecoder::InitRA(const CMediaType* pmt)
    01856 {
    01857         FreeRA();
    01858
    01859         HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
    01860
    01861         if(RAOpenCodec2 && FAILED(hr = RAOpenCodec2(&m_dwCookie, m_dllpath))
    01862         || RAOpenCodec && FAILED(hr = RAOpenCodec(&m_dwCookie)))
    01863                 return hr;
    01864
    01865         WAVEFORMATEX* pwfe = (WAVEFORMATEX*)pmt->Format();
    01866
    01867         // someone might be doing cbSize = sizeof(WAVEFORMATEX), chances of
    01868         // cbSize being really sizeof(WAVEFORMATEX) is less than this,
    01869         // especially with our rm splitter ;)
    01870         DWORD cbSize = pwfe->cbSize;
    01871         if(cbSize == sizeof(WAVEFORMATEX)) {ASSERT(0); cbSize = 0;}
    01872
    01873         WORD wBitsPerSample = pwfe->wBitsPerSample;
    01874         if(!wBitsPerSample) wBitsPerSample = 16;
    01875
    01876         #pragma pack(push, 1)
    01877         struct {DWORD freq; WORD bpsample, channels, quality; DWORD bpframe, packetsize, extralen; void* extra;} initdata =
    01878                 {pwfe->nSamplesPerSec, wBitsPerSample, pwfe->nChannels, 100,
    01879                 0, 0, 0, NULL};
    01880         #pragma pack(pop)
    01881
    01882         CAutoVectorPtr<BYTE> pBuff;
    01883
    01884         if(pmt->subtype == MEDIASUBTYPE_AAC)
    01885         {
    01886                 pBuff.Allocate(cbSize+1);
    01887                 pBuff[0] = 0x02;
    01888                 memcpy(pBuff+1, pwfe+1, cbSize);
    01889                 initdata.extralen = cbSize+1;
    01890                 initdata.extra = pBuff;
    01891         }
    01892         else
    01893         {
    01894                 if(pmt->FormatLength() <= sizeof(WAVEFORMATEX) + cbSize) // must have type_specific_data appended
    01895                         return hr;
    01896
    01897                 BYTE* fmt = pmt->Format() + sizeof(WAVEFORMATEX) + cbSize;
    01898
    01899                 for(int i = 0, len = pmt->FormatLength() - (sizeof(WAVEFORMATEX) + cbSize); i < len-4; i++, fmt++)
    01900                 {
    01901                         if(fmt[0] == '.' || fmt[1] == 'r' || fmt[2] == 'a')
    01902                                 break;
    01903                 }
    01904
    01905                 m_rai = *(rainfo*)fmt;
    01906                 m_rai.bswap();
    01907
    01908                 BYTE* p;
    01909
    01910                 if(m_rai.version2 == 4)
    01911                 {
    01912                         p = (BYTE*)((rainfo4*)fmt+1);
    01913                         int len = *p++; p += len; len = *p++; p += len;
    01914                         ASSERT(len == 4);
    01915                 }
    01916                 else if(m_rai.version2 == 5)
    01917                 {
    01918                         p = (BYTE*)((rainfo5*)fmt+1);
    01919                 }
    01920                 else
    01921                 {
    01922                         return hr;
    01923                 }
    01924
    01925                 p += 3;
    01926                 if(m_rai.version2 == 5) p++;
    01927
    01928                 initdata.bpframe = m_rai.sub_packet_size;
    01929                 initdata.packetsize = m_rai.coded_frame_size;
    01930                 initdata.extralen = *(DWORD*)p;
    01931                 initdata.extra = p + 4;
    01932         }
    01933
    01934         if(FAILED(hr = RAInitDecoder(m_dwCookie, &initdata)))
    01935                 return hr;
    01936
    01937         if(RASetPwd)
    01938                 RASetPwd(m_dwCookie, "Ardubancel Quazanga");
    01939
    01940         if(RASetFlavor && FAILED(hr = RASetFlavor(m_dwCookie, m_rai.flavor)))
    01941                 return hr;
    01942
    01943         return hr;
    01944 }
    01945
    01946 void CRealAudioDecoder::FreeRA()
    01947 {
    01948         if(m_dwCookie)
    01949         {
    01950                 RAFreeDecoder(m_dwCookie);
    01951                 RACloseCodec(m_dwCookie);
    01952                 m_dwCookie = 0;
    01953         }
    01954 }
    01955
    01956 HRESULT CRealAudioDecoder::Receive(IMediaSample* pIn)
    01957 {
    01958         CAutoLock cAutoLock(&m_csReceive);
    01959
    01960         HRESULT hr;
    01961
    01962     AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps();
    01963     if(pProps->dwStreamId != AM_STREAM_MEDIA)
    01964                 return m_pOutput->Deliver(pIn);
    01965
    01966         BYTE* pDataIn = NULL;
    01967         if(FAILED(hr = pIn->GetPointer(&pDataIn))) return hr;
    01968         BYTE* pDataInOrg = pDataIn;
    01969
    01970         long len = pIn->GetActualDataLength();
    01971         if(len <= 0) return S_OK;
    01972
    01973         REFERENCE_TIME rtStart, rtStop;
    01974         pIn->GetTime(&rtStart, &rtStop);
    01975 /*
    01976         if(pIn->IsPreroll() == S_OK || rtStart < 0)
    01977                 return S_OK;
    01978 */
    01979         //
    01980
    01981         if(S_OK == pIn->IsSyncPoint())
    01982         {
    01983                 m_bufflen = 0;
    01984                 m_rtBuffStart = rtStart;
    01985                 m_fBuffDiscontinuity = pIn->IsDiscontinuity() == S_OK;
    01986         }
    01987
    01988         BYTE* src = NULL;
    01989         BYTE* dst = NULL;
    01990
    01991         int w = m_rai.coded_frame_size;
    01992         int h = m_rai.sub_packet_h;
    01993         int sps = m_rai.sub_packet_size;
    01994
    01995         if(m_pInput->CurrentMediaType().subtype == MEDIASUBTYPE_RAAC
    01996         || m_pInput->CurrentMediaType().subtype == MEDIASUBTYPE_RACP
    01997         || m_pInput->CurrentMediaType().subtype == MEDIASUBTYPE_AAC)
    01998         {
    01999                 src = pDataIn;
    02000                 dst = pDataIn + len;
    02001                 w = len;
    02002         }
    02003         else
    02004         {
    02005                 memcpy(&m_buff[m_bufflen], pDataIn, len);
    02006                 m_bufflen += len;
    02007
    02008                 len = w*h;
    02009
    02010                 if(m_bufflen >= len)
    02011                 {
    02012                         ASSERT(m_bufflen == len);
    02013
    02014                         src = m_buff;
    02015                         dst = m_buff + len;
    02016
    02017                         if(sps > 0
    02018                         && (m_pInput->CurrentMediaType().subtype == MEDIASUBTYPE_COOK
    02019                         || m_pInput->CurrentMediaType().subtype == MEDIASUBTYPE_ATRC))
    02020                         {
    02021                                 for(int y = 0; y < h; y++)
    02022                                 {
    02023                                         for(int x = 0, w2 = w / sps; x < w2; x++)
    02024                                         {
    02025                                                 // TRACE(_T("--- %d, %d\n"), (h*x+((h+1)/2)*(y&1)+(y>>1)), sps*(h*x+((h+1)/2)*(y&1)+(y>>1)));
    02026                                                 memcpy(dst + sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), src, sps);
    02027                                                 src += sps;
    02028                                         }
    02029                                 }
    02030
    02031                                 src = m_buff + len;
    02032                                 dst = m_buff + len*2;
    02033                         }
    02034                         else if(m_pInput->CurrentMediaType().subtype == MEDIASUBTYPE_SIPR)
    02035                         {
    02036                                 // http://mplayerhq.hu/pipermail/mplayer-dev-eng/2002-August/010569.html
    02037
    02038                                 static BYTE sipr_swaps[38][2]={
    02039                                         {0,63},{1,22},{2,44},{3,90},{5,81},{7,31},{8,86},{9,58},{10,36},{12,68},
    02040                                         {13,39},{14,73},{15,53},{16,69},{17,57},{19,88},{20,34},{21,71},{24,46},
    02041                                         {25,94},{26,54},{28,75},{29,50},{32,70},{33,92},{35,74},{38,85},{40,56},
    02042                                         {42,87},{43,65},{45,59},{48,79},{49,93},{51,89},{55,95},{61,76},{67,83},
    02043                                         {77,80} };
    02044
    02045                                 int bs=h*w*2/96; // nibbles per subpacket
    02046                                 for(int n=0;n<38;n++){
    02047                                         int i=bs*sipr_swaps[n][0];
    02048                                         int o=bs*sipr_swaps[n][1];
    02049                                 // swap nibbles of block 'i' with 'o'      TODO: optimize
    02050                                         for(int j=0;j<bs;j++){
    02051                                                 int x=(i&1) ? (src[(i>>1)]>>4) : (src[(i>>1)]&15);
    02052                                                 int y=(o&1) ? (src[(o>>1)]>>4) : (src[(o>>1)]&15);
    02053                                                 if(o&1) src[(o>>1)]=(src[(o>>1)]&0x0F)|(x<<4);
    02054                                                         else  src[(o>>1)]=(src[(o>>1)]&0xF0)|x;
    02055                                                 if(i&1) src[(i>>1)]=(src[(i>>1)]&0x0F)|(y<<4);
    02056                                                         else  src[(i>>1)]=(src[(i>>1)]&0xF0)|y;
    02057                                                 ++i;++o;
    02058                                         }
    02059                                 }
    02060                         }
    02061
    02062                         m_bufflen = 0;
    02063                 }
    02064         }
    02065
    02066         rtStart = m_rtBuffStart;
    02067
    02068         for(; src < dst; src += w)
    02069         {
    02070                 CComPtr<IMediaSample> pOut;
    02071                 BYTE* pDataOut = NULL;
    02072                 if(FAILED(hr = m_pOutput->GetDeliveryBuffer(&pOut, NULL, NULL, 0))
    02073                 || FAILED(hr = pOut->GetPointer(&pDataOut)))
    02074                         return hr;
    02075
    02076                 AM_MEDIA_TYPE* pmt;
    02077                 if(SUCCEEDED(pOut->GetMediaType(&pmt)) && pmt)
    02078                 {
    02079                         CMediaType mt(*pmt);
    02080                         m_pOutput->SetMediaType(&mt);
    02081                         DeleteMediaType(pmt);
    02082                 }
    02083
    02084                 hr = RADecode(m_dwCookie, src, w, pDataOut, &len, -1);
    02085
    02086                 if(FAILED(hr))
    02087                 {
    02088                         TRACE(_T("RA returned an error code!!!\n"));
    02089                         continue;
    02090 //                      return hr;
    02091                 }
    02092
    02093                 WAVEFORMATEX* pwfe = (WAVEFORMATEX*)m_pOutput->CurrentMediaType().Format();
    02094
    02095                 rtStop = rtStart + 1000i64*len/pwfe->nAvgBytesPerSec*10000;
    02096                 pOut->SetTime(&rtStart, &rtStop);
    02097                 pOut->SetMediaTime(NULL, NULL);
    02098
    02099                 pOut->SetDiscontinuity(m_fBuffDiscontinuity); m_fBuffDiscontinuity = false;
    02100                 pOut->SetSyncPoint(TRUE);
    02101
    02102                 pOut->SetActualDataLength(len);
    02103
    02104 DbgLog((LOG_TRACE, 0, _T("A: rtStart=%I64d, rtStop=%I64d, disc=%d, sync=%d"),
    02105 rtStart, rtStop, pOut->IsDiscontinuity() == S_OK, pOut->IsSyncPoint() == S_OK));
    02106
    02107                 if(rtStart >= 0 && S_OK != (hr = m_pOutput->Deliver(pOut)))
    02108                         return hr;
    02109
    02110                 rtStart = rtStop;
    02111         }
    02112
    02113         m_rtBuffStart = rtStart;
    02114
    02115         return S_OK;
    02116 }
    02117
    02118 HRESULT CRealAudioDecoder::CheckInputType(const CMediaType* mtIn)
    02119 {
    02120         if(mtIn->majortype != MEDIATYPE_Audio
    02121         || mtIn->subtype != MEDIASUBTYPE_14_4
    02122         && mtIn->subtype != MEDIASUBTYPE_28_8
    02123         && mtIn->subtype != MEDIASUBTYPE_ATRC
    02124         && mtIn->subtype != MEDIASUBTYPE_COOK
    02125         && mtIn->subtype != MEDIASUBTYPE_DNET
    02126         && mtIn->subtype != MEDIASUBTYPE_SIPR
    02127         && mtIn->subtype != MEDIASUBTYPE_RAAC
    02128         && mtIn->subtype != MEDIASUBTYPE_RACP
    02129         && mtIn->subtype != MEDIASUBTYPE_AAC)
    02130                 return VFW_E_TYPE_NOT_ACCEPTED;
    02131
    02132         if(!m_pInput->IsConnected())
    02133         {
    02134                 if(m_hDrvDll) {FreeLibrary(m_hDrvDll); m_hDrvDll = NULL;}
    02135
    02136                 CList<CString> paths;
    02137                 CString olddll, newdll, oldpath, newpath;
    02138
    02139                 TCHAR fourcc[5] =
    02140                 {
    02141                         (TCHAR)((mtIn->subtype.Data1>>0)&0xff),
    02142                         (TCHAR)((mtIn->subtype.Data1>>8)&0xff),
    02143                         (TCHAR)((mtIn->subtype.Data1>>16)&0xff),
    02144                         (TCHAR)((mtIn->subtype.Data1>>24)&0xff),
    02145                         0
    02146                 };
    02147
    02148                 if(!_tcscmp(_T("RACP"), fourcc) || !_tcscmp(_T("\xff"), fourcc))
    02149                         _tcscpy(fourcc, _T("RAAC"));
    02150
    02151                 olddll.Format(_T("%s3260.dll"), fourcc);
    02152                 newdll.Format(_T("%s.dll"), fourcc);
    02153
    02154                 CRegKey key;
    02155                 TCHAR buff[MAX_PATH];
    02156                 ULONG len = sizeof(buff);
    02157                 if(ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Software\\RealNetworks\\Preferences\\DT_Codecs"), KEY_READ)
    02158                 && ERROR_SUCCESS == key.QueryStringValue(NULL, buff, &len) && _tcslen(buff) > 0)
    02159                 {
    02160                         oldpath = buff;
    02161                         TCHAR c = oldpath[oldpath.GetLength()-1];
    02162                         if(c != '\\' && c != '/') oldpath += '\\';
    02163                         key.Close();
    02164                 }
    02165                 len = sizeof(buff);
    02166                 if(ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Helix\\HelixSDK\\10.0\\Preferences\\DT_Codecs"), KEY_READ)
    02167                 && ERROR_SUCCESS == key.QueryStringValue(NULL, buff, &len) && _tcslen(buff) > 0)
    02168                 {
    02169                         newpath = buff;
    02170                         TCHAR c = newpath[newpath.GetLength()-1];
    02171                         if(c != '\\' && c != '/') newpath += '\\';
    02172                         key.Close();
    02173                 }
    02174
    02175                 if(!newpath.IsEmpty()) paths.AddTail(newpath + newdll);
    02176                 if(!oldpath.IsEmpty()) paths.AddTail(oldpath + newdll);
    02177                 paths.AddTail(newdll); // default dll paths
    02178                 if(!newpath.IsEmpty()) paths.AddTail(newpath + olddll);
    02179                 if(!oldpath.IsEmpty()) paths.AddTail(oldpath + olddll);
    02180                 paths.AddTail(olddll); // default dll paths
    02181
    02182                 POSITION pos = paths.GetHeadPosition();
    02183                 while(pos && !(m_hDrvDll = LoadLibrary(paths.GetNext(pos))));
    02184
    02185                 if(m_hDrvDll)
    02186                 {
    02187                         RACloseCodec = (PCloseCodec)GetProcAddress(m_hDrvDll, "RACloseCodec");
    02188                         RADecode = (PDecode)GetProcAddress(m_hDrvDll, "RADecode");
    02189                         RAFlush = (PFlush)GetProcAddress(m_hDrvDll, "RAFlush");
    02190                         RAFreeDecoder = (PFreeDecoder)GetProcAddress(m_hDrvDll, "RAFreeDecoder");
    02191                         RAGetFlavorProperty = (PGetFlavorProperty)GetProcAddress(m_hDrvDll, "RAGetFlavorProperty");
    02192                         RAInitDecoder = (PInitDecoder)GetProcAddress(m_hDrvDll, "RAInitDecoder");
    02193                         RAOpenCodec = (POpenCodec)GetProcAddress(m_hDrvDll, "RAOpenCodec");
    02194                         RAOpenCodec2 = (POpenCodec2)GetProcAddress(m_hDrvDll, "RAOpenCodec2");
    02195                         RASetFlavor = (PSetFlavor)GetProcAddress(m_hDrvDll, "RASetFlavor");
    02196                         RASetDLLAccessPath = (PSetDLLAccessPath)GetProcAddress(m_hDrvDll, "RASetDLLAccessPath");
    02197                         RASetPwd = (PSetPwd)GetProcAddress(m_hDrvDll, "RASetPwd");
    02198                 }
    02199
    02200                 if(!m_hDrvDll || !RACloseCodec || !RADecode /*|| !RAFlush*/
    02201                 || !RAFreeDecoder || !RAGetFlavorProperty || !RAInitDecoder
    02202                 || !(RAOpenCodec || RAOpenCodec2) /*|| !RASetFlavor*/)
    02203                         return VFW_E_TYPE_NOT_ACCEPTED;
    02204
    02205                 if(m_hDrvDll)
    02206                 {
    02207                         char buff[MAX_PATH];
    02208                         GetModuleFileNameA(m_hDrvDll, buff, MAX_PATH);
    02209                         CPathA p(buff);
    02210                         p.RemoveFileSpec();
    02211                         p.AddBackslash();
    02212                         m_dllpath = p.m_strPath;
    02213                         if(RASetDLLAccessPath)
    02214                                 RASetDLLAccessPath("DT_Codecs=" + m_dllpath);
    02215                 }
    02216
    02217                 if(FAILED(InitRA(mtIn)))
    02218                         return VFW_E_TYPE_NOT_ACCEPTED;
    02219         }
    02220
    02221         return S_OK;
    02222 }
    02223
    02224 HRESULT CRealAudioDecoder::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
    02225 {
    02226         return mtIn->majortype == MEDIATYPE_Audio && (mtIn->subtype == MEDIASUBTYPE_14_4
    02227                                                                                                 || mtIn->subtype == MEDIASUBTYPE_28_8
    02228                                                                                                 || mtIn->subtype == MEDIASUBTYPE_ATRC
    02229                                                                                                 || mtIn->subtype == MEDIASUBTYPE_COOK
    02230                                                                                                 || mtIn->subtype == MEDIASUBTYPE_DNET
    02231                                                                                                 || mtIn->subtype == MEDIASUBTYPE_SIPR
    02232                                                                                                 || mtIn->subtype == MEDIASUBTYPE_RAAC
    02233                                                                                                 || mtIn->subtype == MEDIASUBTYPE_RACP
    02234                                                                                                 || mtIn->subtype == MEDIASUBTYPE_AAC)
    02235                 && mtOut->majortype == MEDIATYPE_Audio && mtOut->subtype == MEDIASUBTYPE_PCM
    02236                 ? S_OK
    02237                 : VFW_E_TYPE_NOT_ACCEPTED;
    02238 }
    02239
    02240 HRESULT CRealAudioDecoder::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
    02241 {
    02242         if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
    02243
    02244         CComPtr<IMemAllocator> pAllocatorIn;
    02245         m_pInput->GetAllocator(&pAllocatorIn);
    02246         if(!pAllocatorIn) return E_UNEXPECTED;
    02247
    02248         WAVEFORMATEX* pwfe = (WAVEFORMATEX*)m_pOutput->CurrentMediaType().Format();
    02249
    02250         WORD wBitsPerSample = pwfe->wBitsPerSample;
    02251         if(!wBitsPerSample) wBitsPerSample = 16;
    02252
    02253         // ok, maybe this is too much...
    02254         pProperties->cBuffers = 8;
    02255         pProperties->cbBuffer = pwfe->nChannels*pwfe->nSamplesPerSec*wBitsPerSample>>3; // nAvgBytesPerSec;
    02256         pProperties->cbAlign = 1;
    02257         pProperties->cbPrefix = 0;
    02258
    02259         HRESULT hr;
    02260         ALLOCATOR_PROPERTIES Actual;
    02261     if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
    02262                 return hr;
    02263
    02264     return(pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
    02265                 ? E_FAIL
    02266                 : NOERROR);
    02267 }
    02268
    02269 HRESULT CRealAudioDecoder::GetMediaType(int iPosition, CMediaType* pmt)
    02270 {
    02271     if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
    02272
    02273         *pmt = m_pInput->CurrentMediaType();
    02274         pmt->subtype = MEDIASUBTYPE_PCM;
    02275         WAVEFORMATEX* pwfe = (WAVEFORMATEX*)pmt->ReallocFormatBuffer(sizeof(WAVEFORMATEX));
    02276
    02277         if(iPosition < 0) return E_INVALIDARG;
    02278         if(iPosition > (pwfe->nChannels > 2 && pwfe->nChannels <= 6 ? 1 : 0)) return VFW_S_NO_MORE_ITEMS;
    02279
    02280         if(!pwfe->wBitsPerSample) pwfe->wBitsPerSample = 16;
    02281
    02282         pwfe->cbSize = 0;
    02283         pwfe->wFormatTag = WAVE_FORMAT_PCM;
    02284         pwfe->nBlockAlign = pwfe->nChannels*pwfe->wBitsPerSample>>3;
    02285         pwfe->nAvgBytesPerSec = pwfe->nSamplesPerSec*pwfe->nBlockAlign;
    02286
    02287         if(iPosition == 0 && pwfe->nChannels > 2 && pwfe->nChannels <= 6)
    02288         {
    02289                 static DWORD chmask[] =
    02290                 {
    02291                         KSAUDIO_SPEAKER_DIRECTOUT,
    02292                         KSAUDIO_SPEAKER_MONO,
    02293                         KSAUDIO_SPEAKER_STEREO,
    02294                         KSAUDIO_SPEAKER_STEREO|SPEAKER_FRONT_CENTER,
    02295                         KSAUDIO_SPEAKER_QUAD,
    02296                         KSAUDIO_SPEAKER_QUAD|SPEAKER_FRONT_CENTER,
    02297                         KSAUDIO_SPEAKER_5POINT1
    02298                 };
    02299
    02300                 WAVEFORMATEXTENSIBLE* pwfex = (WAVEFORMATEXTENSIBLE*)pmt->ReallocFormatBuffer(sizeof(WAVEFORMATEXTENSIBLE));
    02301                 pwfex->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
    02302                 pwfex->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
    02303                 pwfex->dwChannelMask = chmask[pwfex->Format.nChannels];
    02304                 pwfex->Samples.wValidBitsPerSample = pwfex->Format.wBitsPerSample;
    02305                 pwfex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
    02306         }
    02307
    02308         return S_OK;
    02309 }
    02310
    02311 HRESULT CRealAudioDecoder::StartStreaming()
    02312 {
    02313         int w = m_rai.coded_frame_size;
    02314         int h = m_rai.sub_packet_h;
    02315         int sps = m_rai.sub_packet_size;
    02316
    02317         int len = w*h;
    02318
    02319         m_buff.Allocate(len*2);
    02320         m_bufflen = 0;
    02321         m_rtBuffStart = 0;
    02322
    02323         return __super::StartStreaming();
    02324 }
    02325
    02326 HRESULT CRealAudioDecoder::StopStreaming()
    02327 {
    02328         m_buff.Free();
    02329         m_bufflen = 0;
    02330
    02331         return __super::StopStreaming();
    02332 }
    02333
    02334 HRESULT CRealAudioDecoder::EndOfStream()
    02335 {
    02336         return __super::EndOfStream();
    02337 }
    02338
    02339 HRESULT CRealAudioDecoder::BeginFlush()
    02340 {
    02341         return __super::BeginFlush();
    02342 }
    02343
    02344 HRESULT CRealAudioDecoder::EndFlush()
    02345 {
    02346         return __super::EndFlush();
    02347 }
    02348
    02349 HRESULT CRealAudioDecoder::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
    02350 {
    02351         CAutoLock cAutoLock(&m_csReceive);
    02352         m_tStart = tStart;
    02353         m_bufflen = 0;
    02354         m_rtBuffStart = 0;
    02355         return __super::NewSegment(tStart, tStop, dRate);
    02356 }