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 }

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