- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# MatroskaSplitter.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 <mmreg.h>
    00024 #include "MatroskaSplitter.h"
    00025 #include "..\..\..\DSUtil\DSUtil.h"
    00026
    00027 #include <initguid.h>
    00028 #include "..\..\..\..\include\matroska\matroska.h"
    00029 #include "..\..\..\..\include\ogg\OggDS.h"
    00030 #include "..\..\..\..\include\moreuuids.h"
    00031
    00032 using namespace MatroskaReader;
    00033
    00034 #ifdef REGISTER_FILTER
    00035
    00036 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
    00037 {
    00038         {&MEDIATYPE_Stream, &MEDIASUBTYPE_Matroska},
    00039         {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}
    00040 };
    00041
    00042 const AMOVIESETUP_PIN sudpPins[] =
    00043 {
    00044     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
    00045     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 0, NULL}
    00046 };
    00047
    00048 const AMOVIESETUP_FILTER sudFilter[] =
    00049 {
    00050         {&__uuidof(CMatroskaSplitterFilter), L"Matroska Splitter", MERIT_NORMAL, countof(sudpPins), sudpPins},
    00051         {&__uuidof(CMatroskaSourceFilter), L"Matroska Source", MERIT_NORMAL, 0, NULL},
    00052 };
    00053
    00054 CFactoryTemplate g_Templates[] =
    00055 {
    00056         {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CMatroskaSplitterFilter>, NULL, &sudFilter[0]},
    00057         {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance<CMatroskaSourceFilter>, NULL, &sudFilter[1]},
    00058 };
    00059
    00060 int g_cTemplates = countof(g_Templates);
    00061
    00062 STDAPI DllRegisterServer()
    00063 {
    00064         RegisterSourceFilter(
    00065                 CLSID_AsyncReader,
    00066                 MEDIASUBTYPE_Matroska,
    00067                 _T("0,4,,1A45DFA3"),
    00068                 _T(".mkv"), _T(".mka"), _T(".mks"), NULL);
    00069
    00070         return AMovieDllRegisterServer2(TRUE);
    00071 }
    00072
    00073 STDAPI DllUnregisterServer()
    00074 {
    00075         UnRegisterSourceFilter(MEDIASUBTYPE_Matroska);
    00076
    00077         return AMovieDllRegisterServer2(FALSE);
    00078 }
    00079
    00080 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
    00081
    00082 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
    00083 {
    00084     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
    00085 }
    00086
    00087 #endif
    00088
    00089 //
    00090 // CMatroskaSplitterFilter
    00091 //
    00092
    00093 CMatroskaSplitterFilter::CMatroskaSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr)
    00094         : CBaseSplitterFilter(NAME("CMatroskaSplitterFilter"), pUnk, phr, __uuidof(this))
    00095 {
    00096 }
    00097
    00098 CMatroskaSplitterFilter::~CMatroskaSplitterFilter()
    00099 {
    00100 }
    00101
    00102 STDMETHODIMP CMatroskaSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00103 {
    00104         CheckPointer(ppv, E_POINTER);
    00105
    00106         return
    00107                 QI(ITrackInfo)
    00108                 __super::NonDelegatingQueryInterface(riid, ppv);
    00109 }
    00110
    00111 #include <vector>
    00112
    00113 HRESULT CMatroskaSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader)
    00114 {
    00115         CheckPointer(pAsyncReader, E_POINTER);
    00116
    00117         HRESULT hr = E_FAIL;
    00118
    00119         m_pFile.Free();
    00120         m_pTrackEntryMap.RemoveAll();
    00121         m_pOrderedTrackArray.RemoveAll();
    00122
    00123         m_pFile.Attach(new CMatroskaFile(pAsyncReader, hr));
    00124         if(!m_pFile) return E_OUTOFMEMORY;
    00125         if(FAILED(hr)) {m_pFile.Free(); return hr;}
    00126
    00127         m_rtNewStart = m_rtCurrent = 0;
    00128         m_rtNewStop = m_rtStop = 0;
    00129
    00130         int iVideo = 1, iAudio = 1, iSubtitle = 1;
    00131
    00132         POSITION pos = m_pFile->m_segment.Tracks.GetHeadPosition();
    00133         while(pos)
    00134         {
    00135                 Track* pT = m_pFile->m_segment.Tracks.GetNext(pos);
    00136
    00137                 POSITION pos2 = pT->TrackEntries.GetHeadPosition();
    00138                 while(pos2)
    00139                 {
    00140                         TrackEntry* pTE = pT->TrackEntries.GetNext(pos2);
    00141
    00142                         if(!pTE->Expand(pTE->CodecPrivate, ContentEncoding::TracksPrivateData))
    00143                                 continue;
    00144
    00145                         CStringA CodecID = pTE->CodecID.ToString();
    00146
    00147                         CStringW Name;
    00148                         Name.Format(L"Output %I64d", (UINT64)pTE->TrackNumber);
    00149
    00150                         CMediaType mt;
    00151                         CArray<CMediaType> mts;
    00152
    00153                         mt.SetSampleSize(1);
    00154
    00155                         if(pTE->TrackType == TrackEntry::TypeVideo)
    00156                         {
    00157                                 Name.Format(L"Video %d", iVideo++);
    00158
    00159                                 mt.majortype = MEDIATYPE_Video;
    00160
    00161                                 if(CodecID == "V_MS/VFW/FOURCC")
    00162                                 {
    00163                                         mt.formattype = FORMAT_VideoInfo;
    00164                                         VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + pTE->CodecPrivate.GetCount() - sizeof(BITMAPINFOHEADER));
    00165                                         memset(mt.Format(), 0, mt.FormatLength());
    00166                                         memcpy(&pvih->bmiHeader, (BYTE*)pTE->CodecPrivate, pTE->CodecPrivate.GetCount());
    00167                                         mt.subtype = FOURCCMap(pvih->bmiHeader.biCompression);
    00168                                         switch(pvih->bmiHeader.biCompression)
    00169                                         {
    00170                                         case BI_RGB: case BI_BITFIELDS: mt.subtype =
    00171                                                 pvih->bmiHeader.biBitCount == 1 ? MEDIASUBTYPE_RGB1 :
    00172                                                 pvih->bmiHeader.biBitCount == 4 ? MEDIASUBTYPE_RGB4 :
    00173                                                 pvih->bmiHeader.biBitCount == 8 ? MEDIASUBTYPE_RGB8 :
    00174                                                 pvih->bmiHeader.biBitCount == 16 ? MEDIASUBTYPE_RGB565 :
    00175                                                 pvih->bmiHeader.biBitCount == 24 ? MEDIASUBTYPE_RGB24 :
    00176                                                 pvih->bmiHeader.biBitCount == 32 ? MEDIASUBTYPE_ARGB32 :
    00177                                                 MEDIASUBTYPE_NULL;
    00178                                                 break;
    00179 //                                      case BI_RLE8: mt.subtype = MEDIASUBTYPE_RGB8; break;
    00180 //                                      case BI_RLE4: mt.subtype = MEDIASUBTYPE_RGB4; break;
    00181                                         }
    00182                                         mts.Add(mt);
    00183                                 }
    00184                                 else if(CodecID == "V_UNCOMPRESSED")
    00185                                 {
    00186                                 }
    00187                                 else if(CodecID.Find("V_MPEG4/ISO/AVC") == 0)
    00188                                 {
    00189                                         if(pTE->CodecPrivate.GetSize() >= 6)
    00190                                         {
    00191                                         BYTE sps = pTE->CodecPrivate[5] & 0x1f;
    00192
    00193
    00194         std::vector<BYTE> avcC;
    00195         for(int i = 0, j = pTE->CodecPrivate.GetSize(); i < j; i++)
    00196                 avcC.push_back(pTE->CodecPrivate[i]);
    00197
    00198         std::vector<BYTE> sh;
    00199
    00200         unsigned jj = 6;
    00201
    00202         while (sps--) {
    00203           if (jj + 2 > avcC.size())
    00204             goto avcfail;
    00205           unsigned spslen = ((unsigned)avcC[jj] << 8) | avcC[jj+1];
    00206           if (jj + 2 + spslen > avcC.size())
    00207             goto avcfail;
    00208           unsigned cur = sh.size();
    00209           sh.resize(cur + spslen + 2, 0);
    00210           std::copy(avcC.begin() + jj, avcC.begin() + jj + 2 + spslen,sh.begin() + cur);
    00211           jj += 2 + spslen;
    00212         }
    00213
    00214         if (jj + 1 > avcC.size())
    00215           continue;
    00216
    00217         unsigned pps = avcC[jj++];
    00218
    00219         while (pps--) {
    00220           if (jj + 2 > avcC.size())
    00221             goto avcfail;
    00222           unsigned ppslen = ((unsigned)avcC[jj] << 8) | avcC[jj+1];
    00223           if (jj + 2 + ppslen > avcC.size())
    00224             goto avcfail;
    00225           unsigned cur = sh.size();
    00226           sh.resize(cur + ppslen + 2, 0);
    00227           std::copy(avcC.begin() + jj, avcC.begin() + jj + 2 + ppslen, sh.begin() + cur);
    00228           jj += 2 + ppslen;
    00229         }
    00230
    00231         goto avcsuccess;
    00232 avcfail:
    00233         continue;
    00234 avcsuccess:
    00235
    00236                                         CArray<BYTE> data;
    00237                                         data.SetSize(sh.size());
    00238                                         std::copy(sh.begin(), sh.end(), (BYTE*)data.GetData());
    00239
    00240                                         mt.subtype = FOURCCMap('1CVA');
    00241                                         mt.formattype = FORMAT_MPEG2Video;
    00242                                         MPEG2VIDEOINFO* pm2vi = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + data.GetSize());
    00243                                         memset(mt.Format(), 0, mt.FormatLength());
    00244                                         pm2vi->hdr.bmiHeader.biSize = sizeof(pm2vi->hdr.bmiHeader);
    00245                                         pm2vi->hdr.bmiHeader.biWidth = (LONG)pTE->v.PixelWidth;
    00246                                         pm2vi->hdr.bmiHeader.biHeight = (LONG)pTE->v.PixelHeight;
    00247                                         pm2vi->hdr.bmiHeader.biCompression = '1cva';
    00248                                         pm2vi->hdr.bmiHeader.biPlanes = 1;
    00249                                         pm2vi->hdr.bmiHeader.biBitCount = 24;
    00250
    00251                                         pm2vi->dwProfile = pTE->CodecPrivate[1];
    00252                                         pm2vi->dwLevel = pTE->CodecPrivate[3];
    00253                                         pm2vi->dwFlags = (pTE->CodecPrivate[4] & 3) + 1;
    00254
    00255                                         BYTE* pSequenceHeader = (BYTE*)pm2vi->dwSequenceHeader;
    00256                                         memcpy(pSequenceHeader, data.GetData(), data.GetSize());
    00257                                         pm2vi->cbSequenceHeader = data.GetSize();
    00258
    00259                                         mts.Add(mt);
    00260
    00261                                         }
    00262                                 }
    00263                                 else if(CodecID.Find("V_MPEG4/") == 0) // TODO: find out which V_MPEG4/*/* ids can be mapped to 'mp4v'
    00264                                 {
    00265                                         mt.subtype = FOURCCMap('v4pm');
    00266                                         mt.formattype = FORMAT_VideoInfo;
    00267                                         VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
    00268                                         memset(pvih, 0, mt.FormatLength());
    00269                                         pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader);
    00270                                         pvih->bmiHeader.biWidth = (LONG)pTE->v.PixelWidth;
    00271                                         pvih->bmiHeader.biHeight = (LONG)pTE->v.PixelHeight;
    00272                                         pvih->bmiHeader.biCompression = 'v4pm';
    00273                                         mts.Add(mt);
    00274
    00275                                         // TODO: add (-1,0) dummy frame to timeoverride when it is /asp (that is having b-frames almost certainly)
    00276                                 }
    00277                                 else if(CodecID.Find("V_REAL/RV") == 0)
    00278                                 {
    00279                                         mt.subtype = FOURCCMap('00VR' + ((CodecID[9]-0x30)<<16));
    00280                                         mt.formattype = FORMAT_VideoInfo;
    00281                                         VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + pTE->CodecPrivate.GetCount());
    00282                                         memset(mt.Format(), 0, mt.FormatLength());
    00283                                         memcpy(mt.Format() + sizeof(VIDEOINFOHEADER), pTE->CodecPrivate.GetData(), pTE->CodecPrivate.GetCount());
    00284                                         pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader);
    00285                                         pvih->bmiHeader.biWidth = (LONG)pTE->v.PixelWidth;
    00286                                         pvih->bmiHeader.biHeight = (LONG)pTE->v.PixelHeight;
    00287                                         pvih->bmiHeader.biCompression = mt.subtype.Data1;
    00288                                         mts.Add(mt);
    00289                                 }
    00290                                 else if(CodecID == "V_DIRAC")
    00291                                 {
    00292                                         mt.subtype = MEDIASUBTYPE_DiracVideo;
    00293                                         mt.formattype = FORMAT_DiracVideoInfo;
    00294                                         DIRACINFOHEADER* dvih = (DIRACINFOHEADER*)mt.AllocFormatBuffer(FIELD_OFFSET(DIRACINFOHEADER, dwSequenceHeader) + pTE->CodecPrivate.GetSize());
    00295                                         memset(mt.Format(), 0, mt.FormatLength());
    00296                                         dvih->hdr.bmiHeader.biSize = sizeof(dvih->hdr.bmiHeader);
    00297                                         dvih->hdr.bmiHeader.biWidth = (LONG)pTE->v.PixelWidth;
    00298                                         dvih->hdr.bmiHeader.biHeight = (LONG)pTE->v.PixelHeight;
    00299                                         dvih->hdr.dwPictAspectRatioX = dvih->hdr.bmiHeader.biWidth;
    00300                                         dvih->hdr.dwPictAspectRatioY = dvih->hdr.bmiHeader.biHeight;
    00301
    00302                                         BYTE* pSequenceHeader = (BYTE*)dvih->dwSequenceHeader;
    00303                                         memcpy(pSequenceHeader, pTE->CodecPrivate.GetData(), pTE->CodecPrivate.GetSize());
    00304                                         dvih->cbSequenceHeader = pTE->CodecPrivate.GetSize();
    00305
    00306                                         mts.Add(mt);
    00307                                 }
    00308                                 else if(CodecID == "V_MPEG2")
    00309                                 {
    00310                                         BYTE* seqhdr = pTE->CodecPrivate.GetData();
    00311                                         DWORD len = pTE->CodecPrivate.GetSize();
    00312                                         int w = pTE->v.PixelWidth;
    00313                                         int h = pTE->v.PixelHeight;
    00314
    00315                                         if(MakeMPEG2MediaType(mt, seqhdr, len, w, h))
    00316                                                 mts.Add(mt);
    00317                                 }
    00318 /*
    00319                                 else if(CodecID == "V_DSHOW/MPEG1VIDEO") // V_MPEG1
    00320                                 {
    00321                                         mt.majortype = MEDIATYPE_Video;
    00322                                         mt.subtype = MEDIASUBTYPE_MPEG1Payload;
    00323                                         mt.formattype = FORMAT_MPEGVideo;
    00324                                         MPEG1VIDEOINFO* pm1vi = (MPEG1VIDEOINFO*)mt.AllocFormatBuffer(pTE->CodecPrivate.GetSize());
    00325                                         memcpy(pm1vi, pTE->CodecPrivate.GetData(), pTE->CodecPrivate.GetSize());
    00326                                         mt.SetSampleSize(pm1vi->hdr.bmiHeader.biWidth*pm1vi->hdr.bmiHeader.biHeight*4);
    00327                                         mts.Add(mt);
    00328                                 }
    00329 */
    00330                                 REFERENCE_TIME AvgTimePerFrame = 0;
    00331
    00332                 if(pTE->v.FramePerSec > 0)
    00333                                         AvgTimePerFrame = (REFERENCE_TIME)(10000000i64 / pTE->v.FramePerSec);
    00334                                 else if(pTE->DefaultDuration > 0)
    00335                                         AvgTimePerFrame = (REFERENCE_TIME)pTE->DefaultDuration / 100;
    00336
    00337                                 if(AvgTimePerFrame)
    00338                                 {
    00339                                         for(int i = 0; i < mts.GetCount(); i++)
    00340                                         {
    00341                                                 if(mts[i].formattype == FORMAT_VideoInfo
    00342                                                 || mts[i].formattype == FORMAT_VideoInfo2
    00343                                                 || mts[i].formattype == FORMAT_MPEG2Video)
    00344                                                 {
    00345                                                         ((VIDEOINFOHEADER*)mts[i].Format())->AvgTimePerFrame = AvgTimePerFrame;
    00346                                                 }
    00347                                         }
    00348                                 }
    00349
    00350                                 if(pTE->v.DisplayWidth != 0 && pTE->v.DisplayHeight != 0)
    00351                                 {
    00352                                         for(int i = 0; i < mts.GetCount(); i++)
    00353                                         {
    00354                                                 if(mts[i].formattype == FORMAT_VideoInfo)
    00355                                                 {
    00356                                                         DWORD vih1 = FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader);
    00357                                                         DWORD vih2 = FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader);
    00358                                                         DWORD bmi = mts[i].FormatLength() - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader);
    00359                                                         mt.formattype = FORMAT_VideoInfo2;
    00360                                                         mt.AllocFormatBuffer(vih2 + bmi);
    00361                                                         memcpy(mt.Format(), mts[i].Format(), vih1);
    00362                                                         memset(mt.Format() + vih1, 0, vih2 - vih1);
    00363                                                         memcpy(mt.Format() + vih2, mts[i].Format() + vih1, bmi);
    00364                                                         ((VIDEOINFOHEADER2*)mt.Format())->dwPictAspectRatioX = (DWORD)pTE->v.DisplayWidth;
    00365                                                         ((VIDEOINFOHEADER2*)mt.Format())->dwPictAspectRatioY = (DWORD)pTE->v.DisplayHeight;
    00366                                                         mts.InsertAt(i++, mt);
    00367                                                 }
    00368                                                 else if(mts[i].formattype == FORMAT_MPEG2Video)
    00369                                                 {
    00370                                                         ((MPEG2VIDEOINFO*)mts[i].Format())->hdr.dwPictAspectRatioX = (DWORD)pTE->v.DisplayWidth;
    00371                                                         ((MPEG2VIDEOINFO*)mts[i].Format())->hdr.dwPictAspectRatioY = (DWORD)pTE->v.DisplayHeight;
    00372                                                 }
    00373                                         }
    00374                                 }
    00375                         }
    00376                         else if(pTE->TrackType == TrackEntry::TypeAudio)
    00377                         {
    00378                                 Name.Format(L"Audio %d", iAudio++);
    00379
    00380                                 mt.majortype = MEDIATYPE_Audio;
    00381                                 mt.formattype = FORMAT_WaveFormatEx;
    00382                                 WAVEFORMATEX* pwfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX));
    00383                                 memset(pwfe, 0, mt.FormatLength());
    00384                                 pwfe->nChannels = (WORD)pTE->a.Channels;
    00385                                 pwfe->nSamplesPerSec = (DWORD)pTE->a.SamplingFrequency;
    00386                                 pwfe->wBitsPerSample = (WORD)pTE->a.BitDepth;
    00387                                 pwfe->nBlockAlign = (WORD)((pwfe->nChannels * pwfe->wBitsPerSample) / 8);
    00388                                 pwfe->nAvgBytesPerSec = pwfe->nSamplesPerSec * pwfe->nBlockAlign;
    00389                                 mt.SetSampleSize(256000);
    00390
    00391                                 if(CodecID == "A_VORBIS")
    00392                                 {
    00393                                         BYTE* p = (BYTE*)pTE->CodecPrivate;
    00394                                         CArray<long> sizes;
    00395                                         for(BYTE n = *p++; n > 0; n--)
    00396                                         {
    00397                                                 long size = 0;
    00398                                                 do {size += *p;} while(*p++ == 0xff);
    00399                                                 sizes.Add(size);
    00400                                         }
    00401
    00402                                         long totalsize = 0;
    00403                                         for(int i = 0; i < sizes.GetCount(); i++)
    00404                                                 totalsize += sizes[i];
    00405
    00406                                         sizes.Add(pTE->CodecPrivate.GetSize() - (p - (BYTE*)pTE->CodecPrivate) - totalsize);
    00407                                         totalsize += sizes[sizes.GetCount()-1];
    00408
    00409                                         if(sizes.GetCount() == 3)
    00410                                         {
    00411                                                 mt.subtype = MEDIASUBTYPE_Vorbis2;
    00412                                                 mt.formattype = FORMAT_VorbisFormat2;
    00413                                                 VORBISFORMAT2* pvf2 = (VORBISFORMAT2*)mt.AllocFormatBuffer(sizeof(VORBISFORMAT2) + totalsize);
    00414                                                 memset(pvf2, 0, mt.FormatLength());
    00415                                                 pvf2->Channels = (WORD)pTE->a.Channels;
    00416                                                 pvf2->SamplesPerSec = (DWORD)pTE->a.SamplingFrequency;
    00417                                                 pvf2->BitsPerSample = (DWORD)pTE->a.BitDepth;
    00418                                                 BYTE* p2 = mt.Format() + sizeof(VORBISFORMAT2);
    00419                                                 for(int i = 0; i < sizes.GetCount(); p += sizes[i], p2 += sizes[i], i++)
    00420                                                         memcpy(p2, p, pvf2->HeaderSize[i] = sizes[i]);
    00421
    00422                                                 mts.Add(mt);
    00423                                         }
    00424
    00425                                         mt.subtype = MEDIASUBTYPE_Vorbis;
    00426                                         mt.formattype = FORMAT_VorbisFormat;
    00427                                         VORBISFORMAT* pvf = (VORBISFORMAT*)mt.AllocFormatBuffer(sizeof(VORBISFORMAT));
    00428                                         memset(pvf, 0, mt.FormatLength());
    00429                                         pvf->nChannels = (WORD)pTE->a.Channels;
    00430                                         pvf->nSamplesPerSec = (DWORD)pTE->a.SamplingFrequency;
    00431                                         pvf->nMinBitsPerSec = pvf->nMaxBitsPerSec = pvf->nAvgBitsPerSec = -1;
    00432                                         mts.Add(mt);
    00433                                 }
    00434                                 else if(CodecID == "A_MPEG/L3")
    00435                                 {
    00436                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_MP3);
    00437                                         mts.Add(mt);
    00438                                 }
    00439                                 else if(CodecID == "A_MPEG/L2")
    00440                                 {
    00441                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_MPEG);
    00442                                         mts.Add(mt);
    00443                                         // TODO : add MPEG1WAVEFORMAT
    00444                                 }
    00445                                 else if(CodecID == "A_AC3")
    00446                                 {
    00447                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3);
    00448                                         mts.Add(mt);
    00449                                 }
    00450                                 else if(CodecID == "A_DTS")
    00451                                 {
    00452                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_DVD_DTS);
    00453                                         mts.Add(mt);
    00454                                 }
    00455                                 else if(CodecID == "A_FLAC")
    00456                                 {
    00457                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_FLAC);
    00458                                         pwfe->cbSize = pTE->CodecPrivate.GetCount();
    00459                                         BYTE* pExtra = mt.ReallocFormatBuffer(sizeof(WAVEFORMATEX) + pTE->CodecPrivate.GetCount()) + sizeof(WAVEFORMATEX);
    00460                                         memcpy(pExtra, pTE->CodecPrivate.GetData(), pTE->CodecPrivate.GetCount());
    00461                                         mts.Add(mt);
    00462
    00463                                         mt.subtype = MEDIASUBTYPE_FLAC_FRAMED;
    00464                                         mts.InsertAt(0, mt);
    00465                                 }
    00466                                 else if(CodecID == "A_TTA1")
    00467                                 {
    00468                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_TTA1);
    00469                                         mts.Add(mt);
    00470                                 }
    00471                                 else if(CodecID == "A_MS/ACM")
    00472                                 {
    00473                                         pwfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(pTE->CodecPrivate.GetCount());
    00474                                         memcpy(pwfe, (WAVEFORMATEX*)(BYTE*)pTE->CodecPrivate, pTE->CodecPrivate.GetCount());
    00475                                         mt.subtype = FOURCCMap(pwfe->wFormatTag);
    00476                                         mts.Add(mt);
    00477                                 }
    00478                                 else if(CodecID == "A_PCM/INT/LIT")
    00479                                 {
    00480                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_PCM);
    00481                                         mts.Add(mt);
    00482                                 }
    00483                                 else if(CodecID == "A_PCM/FLOAT/IEEE")
    00484                                 {
    00485                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_IEEE_FLOAT);
    00486                                         mts.Add(mt);
    00487                                 }
    00488                                 else if(CodecID.Find("A_AAC/") == 0)
    00489                                 {
    00490                                         mt.subtype = FOURCCMap(pwfe->wFormatTag = WAVE_FORMAT_AAC);
    00491                                         BYTE* pExtra = mt.ReallocFormatBuffer(sizeof(WAVEFORMATEX)+5) + sizeof(WAVEFORMATEX);
    00492                                         (pwfe = (WAVEFORMATEX*)mt.pbFormat)->cbSize = 2;
    00493
    00494                                         int profile;
    00495
    00496                                         if(CodecID.Find("/MAIN") > 0) profile = 0;
    00497                                         else if(CodecID.Find("/SBR") > 0) profile = -1;
    00498                                         else if(CodecID.Find("/LC") > 0) profile = 1;
    00499                                         else if(CodecID.Find("/SSR") > 0) profile = 2;
    00500                                         else if(CodecID.Find("/LTP") > 0) profile = 3;
    00501                                         else continue;
    00502
    00503                                         WORD cbSize = MakeAACInitData(pExtra, profile, pwfe->nSamplesPerSec, pTE->a.Channels);
    00504
    00505                                         mts.Add(mt);
    00506
    00507                                         if(profile < 0)
    00508                                         {
    00509                                                 pwfe->cbSize = cbSize;
    00510                                                 pwfe->nSamplesPerSec *= 2;
    00511                                                 pwfe->nAvgBytesPerSec *= 2;
    00512
    00513                                                 mts.InsertAt(0, mt);
    00514                                         }
    00515                                 }
    00516                                 else if(CodecID.Find("A_REAL/") == 0 && CodecID.GetLength() >= 11)
    00517                                 {
    00518                                         mt.bTemporalCompression = TRUE;
    00519                                         mt.subtype = FOURCCMap((DWORD)CodecID[7]|((DWORD)CodecID[8]<<8)|((DWORD)CodecID[9]<<16)|((DWORD)CodecID[10]<<24));
    00520                                         BYTE* p = mt.ReallocFormatBuffer(sizeof(WAVEFORMATEX) + pTE->CodecPrivate.GetCount());
    00521                                         memcpy(p + sizeof(WAVEFORMATEX), pTE->CodecPrivate.GetData(), pTE->CodecPrivate.GetCount());
    00522
    00523                                         mts.Add(mt);
    00524                                 }
    00525                         }
    00526                         else if(pTE->TrackType == TrackEntry::TypeSubtitle)
    00527                         {
    00528                                 if(iSubtitle == 1) InstallFonts();
    00529
    00530                                 Name.Format(L"Subtitle %d", iSubtitle++);
    00531
    00532                                 mt.SetSampleSize(1);
    00533
    00534                                 if(CodecID == "S_TEXT/ASCII")
    00535                                 {
    00536                                         mt.majortype = MEDIATYPE_Text;
    00537                                         mt.subtype = MEDIASUBTYPE_NULL;
    00538                                         mt.formattype = FORMAT_None;
    00539                                         mts.Add(mt);
    00540                                 }
    00541                                 else
    00542                                 {
    00543                                         mt.majortype = MEDIATYPE_Subtitle;
    00544                                         mt.formattype = FORMAT_SubtitleInfo;
    00545                                         SUBTITLEINFO* psi = (SUBTITLEINFO*)mt.AllocFormatBuffer(sizeof(SUBTITLEINFO) + pTE->CodecPrivate.GetSize());
    00546                                         memset(psi, 0, mt.FormatLength());
    00547                                         strncpy(psi->IsoLang, pTE->Language, countof(psi->IsoLang)-1);
    00548                                         wcsncpy(psi->TrackName, pTE->Name, countof(psi->TrackName)-1);
    00549                                         memcpy(mt.pbFormat + (psi->dwOffset = sizeof(SUBTITLEINFO)), pTE->CodecPrivate.GetData(), pTE->CodecPrivate.GetSize());
    00550
    00551                                         mt.subtype =
    00552                                                 CodecID == "S_TEXT/UTF8" ? MEDIASUBTYPE_UTF8 :
    00553                                                 CodecID == "S_TEXT/SSA" || CodecID == "S_SSA" ? MEDIASUBTYPE_SSA :
    00554                                                 CodecID == "S_TEXT/ASS" || CodecID == "S_ASS" ? MEDIASUBTYPE_ASS :
    00555                                                 CodecID == "S_TEXT/USF" || CodecID == "S_USF" ? MEDIASUBTYPE_USF :
    00556                                                 CodecID == "S_VOBSUB" ? MEDIASUBTYPE_VOBSUB :
    00557                                                 MEDIASUBTYPE_NULL;
    00558
    00559                                         if(mt.subtype != MEDIASUBTYPE_NULL)
    00560                                                 mts.Add(mt);
    00561                                 }
    00562                         }
    00563
    00564                         if(mts.IsEmpty())
    00565                         {
    00566                                 TRACE(_T("CMatroskaSourceFilter: Unsupported TrackType %s (%I64d)\n"), CString(CodecID), (UINT64)pTE->TrackType);
    00567                                 continue;
    00568                         }
    00569
    00570                         Name = CStringW(pTE->Language.IsEmpty() ? L"English" : CStringW(ISO6392ToLanguage(pTE->Language)))
    00571                                 + (pTE->Name.IsEmpty() ? L"" : L", " + pTE->Name)
    00572                                 + (L" (" + Name + L")");
    00573
    00574                         HRESULT hr;
    00575
    00576                         CAutoPtr<CBaseSplitterOutputPin> pPinOut(new CMatroskaSplitterOutputPin((int)pTE->MinCache, pTE->DefaultDuration/100, mts, Name, this, this, &hr));
    00577                         if(!pTE->Name.IsEmpty()) pPinOut->SetProperty(L"NAME", pTE->Name);
    00578                         if(pTE->Language.GetLength() == 3) pPinOut->SetProperty(L"LANG", CStringW(CString(pTE->Language)));
    00579                         AddOutputPin((DWORD)pTE->TrackNumber, pPinOut);
    00580
    00581                         m_pTrackEntryMap[(DWORD)pTE->TrackNumber] = pTE;
    00582                         m_pOrderedTrackArray.Add(pTE);
    00583                 }
    00584         }
    00585
    00586         Info& info = m_pFile->m_segment.SegmentInfo;
    00587         m_rtNewStart = m_rtCurrent = 0;
    00588         m_rtNewStop = m_rtStop = (REFERENCE_TIME)(info.Duration*info.TimeCodeScale/100);
    00589
    00590 #ifdef DEBUG
    00591         /*
    00592         for(int i = 1, j = GetChapterCount(CHAPTER_ROOT_ID); i <= j; i++)
    00593         {
    00594                 UINT id = GetChapterId(CHAPTER_ROOT_ID, i);
    00595                 struct ChapterElement ce;
    00596                 BOOL b = GetChapterInfo(id, &ce);
    00597                 BSTR bstr = GetChapterStringInfo(id, "eng", "");
    00598                 if(bstr) ::SysFreeString(bstr);
    00599         }
    00600         */
    00601 #endif
    00602
    00603         SetProperty(L"TITL", info.Title);
    00604         // TODO
    00605
    00606         // resources
    00607
    00608         {
    00609                 POSITION pos = m_pFile->m_segment.Attachments.GetHeadPosition();
    00610                 while(pos)
    00611                 {
    00612                         Attachment* pA = m_pFile->m_segment.Attachments.GetNext(pos);
    00613
    00614                         POSITION pos = pA->AttachedFiles.GetHeadPosition();
    00615                         while(pos)
    00616                         {
    00617                                 AttachedFile* pF = pA->AttachedFiles.GetNext(pos);
    00618
    00619                                 CArray<BYTE> pData;
    00620                                 pData.SetSize(pF->FileDataLen);
    00621                                 m_pFile->Seek(pF->FileDataPos);
    00622                                 if(SUCCEEDED(m_pFile->Read(pData.GetData(), pData.GetSize())))
    00623                                         ResAppend(pF->FileName, pF->FileDescription, CStringW(pF->FileMimeType), pData.GetData(), pData.GetSize());
    00624                         }
    00625                 }
    00626         }
    00627
    00628         // chapters
    00629
    00630         if(ChapterAtom* caroot = m_pFile->m_segment.FindChapterAtom(0))
    00631         {
    00632                 CStringA str;
    00633                 str.ReleaseBufferSetLength(GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, str.GetBuffer(3), 3));
    00634                 CStringA ChapLanguage = CStringA(ISO6391To6392(str));
    00635                 if(ChapLanguage.GetLength() < 3) ChapLanguage = "eng";
    00636
    00637                 POSITION pos = caroot->ChapterAtoms.GetHeadPosition();
    00638                 while(pos)
    00639                 {
    00640                         // ca == caroot->ChapterAtoms.GetNext(pos) ?
    00641                         if(ChapterAtom* ca = m_pFile->m_segment.FindChapterAtom(caroot->ChapterAtoms.GetNext(pos)->ChapterUID))
    00642                         {
    00643                                 CStringW name, first;
    00644
    00645                                 POSITION pos = ca->ChapterDisplays.GetHeadPosition();
    00646                                 while(pos)
    00647                                 {
    00648                                         ChapterDisplay* cd = ca->ChapterDisplays.GetNext(pos);
    00649                                         if(first.IsEmpty()) first = cd->ChapString;
    00650                                         if(cd->ChapLanguage == ChapLanguage) name = cd->ChapString;
    00651                                 }
    00652
    00653                                 ChapAppend(ca->ChapterTimeStart / 100 - m_pFile->m_rtOffset, !name.IsEmpty() ? name : first);
    00654                         }
    00655                 }
    00656         }
    00657
    00658         return m_pOutputs.GetCount() > 0 ? S_OK : E_FAIL;
    00659 }
    00660
    00661 void CMatroskaSplitterFilter::InstallFonts()
    00662 {
    00663         POSITION pos = m_pFile->m_segment.Attachments.GetHeadPosition();
    00664         while(pos)
    00665         {
    00666                 Attachment* pA = m_pFile->m_segment.Attachments.GetNext(pos);
    00667
    00668                 POSITION p2 = pA->AttachedFiles.GetHeadPosition();
    00669                 while(p2)
    00670                 {
    00671                         AttachedFile* pF = pA->AttachedFiles.GetNext(p2);
    00672
    00673                         if(pF->FileMimeType == "application/x-truetype-font")
    00674                         {
    00675                                 // assume this is a font resource
    00676
    00677                                 if(BYTE* pData = new BYTE[(UINT)pF->FileDataLen])
    00678                                 {
    00679                                         m_pFile->Seek(pF->FileDataPos);
    00680
    00681                                         if(SUCCEEDED(m_pFile->Read(pData, pF->FileDataLen)))
    00682                                                 m_fontinst.InstallFont(pData, (UINT)pF->FileDataLen);
    00683
    00684                                         delete [] pData;
    00685                                 }
    00686                         }
    00687                 }
    00688         }
    00689 }
    00690
    00691 void CMatroskaSplitterFilter::SendVorbisHeaderSample()
    00692 {
    00693         HRESULT hr;
    00694
    00695         POSITION pos = m_pTrackEntryMap.GetStartPosition();
    00696         while(pos)
    00697         {
    00698                 DWORD TrackNumber = 0;
    00699                 TrackEntry* pTE = NULL;
    00700                 m_pTrackEntryMap.GetNextAssoc(pos, TrackNumber, pTE);
    00701
    00702                 CBaseSplitterOutputPin* pPin = GetOutputPin(TrackNumber);
    00703
    00704                 if(!(pTE && pPin && pPin->IsConnected()))
    00705                         continue;
    00706
    00707                 if(pTE->CodecID.ToString() == "A_VORBIS" && pPin->CurrentMediaType().subtype == MEDIASUBTYPE_Vorbis
    00708                 && pTE->CodecPrivate.GetSize() > 0)
    00709                 {
    00710                         BYTE* ptr = (BYTE*)pTE->CodecPrivate;
    00711
    00712                         CList<long> sizes;
    00713                         long last = 0;
    00714                         for(BYTE n = *ptr++; n > 0; n--)
    00715                         {
    00716                                 long size = 0;
    00717                                 do {size += *ptr;} while(*ptr++ == 0xff);
    00718                                 sizes.AddTail(size);
    00719                                 last += size;
    00720                         }
    00721                         sizes.AddTail(pTE->CodecPrivate.GetSize() - (ptr - (BYTE*)pTE->CodecPrivate) - last);
    00722
    00723                         hr = S_OK;
    00724
    00725                         POSITION pos = sizes.GetHeadPosition();
    00726                         while(pos && SUCCEEDED(hr))
    00727                         {
    00728                                 long len = sizes.GetNext(pos);
    00729
    00730                                 CAutoPtr<Packet> p(new Packet());
    00731                                 p->TrackNumber = (DWORD)pTE->TrackNumber;
    00732                                 p->rtStart = 0; p->rtStop = 1;
    00733                                 p->bSyncPoint = FALSE;
    00734                                 p->pData.SetSize(len);
    00735                                 memcpy(p->pData.GetData(), ptr, len);
    00736                                 ptr += len;
    00737
    00738                                 hr = DeliverPacket(p);
    00739                         }
    00740
    00741                         if(FAILED(hr))
    00742                                 TRACE(_T("ERROR: Vorbis initialization failed for stream %I64d\n"), TrackNumber);
    00743                 }
    00744         }
    00745 }
    00746
    00747 bool CMatroskaSplitterFilter::DemuxInit()
    00748 {
    00749         CMatroskaNode Root(m_pFile);
    00750         if(!m_pFile
    00751         || !(m_pSegment = Root.Child(0x18538067))
    00752         || !(m_pCluster = m_pSegment->Child(0x1F43B675)))
    00753                 return(false);
    00754
    00755         // reindex if needed
    00756
    00757         if(m_pFile->m_segment.Cues.GetCount() == 0)
    00758         {
    00759                 m_nOpenProgress = 0;
    00760                 m_pFile->m_segment.SegmentInfo.Duration.Set(0);
    00761
    00762                 UINT64 TrackNumber = m_pFile->m_segment.GetMasterTrack();
    00763
    00764                 CAutoPtr<Cue> pCue(new Cue());
    00765
    00766                 do
    00767                 {
    00768                         Cluster c;
    00769                         c.ParseTimeCode(m_pCluster);
    00770
    00771                         m_pFile->m_segment.SegmentInfo.Duration.Set((float)c.TimeCode - m_pFile->m_rtOffset/10000);
    00772
    00773                         CAutoPtr<CuePoint> pCuePoint(new CuePoint());
    00774                         CAutoPtr<CueTrackPosition> pCueTrackPosition(new CueTrackPosition());
    00775                         pCuePoint->CueTime.Set(c.TimeCode);
    00776                         pCueTrackPosition->CueTrack.Set(TrackNumber);
    00777                         pCueTrackPosition->CueClusterPosition.Set(m_pCluster->m_filepos - m_pSegment->m_start);
    00778                         pCuePoint->CueTrackPositions.AddTail(pCueTrackPosition);
    00779                         pCue->CuePoints.AddTail(pCuePoint);
    00780
    00781                         m_nOpenProgress = m_pFile->GetPos()*100/m_pFile->GetLength();
    00782
    00783                         DWORD cmd;
    00784                         if(CheckRequest(&cmd))
    00785                         {
    00786                                 if(cmd == CMD_EXIT) m_fAbort = true;
    00787                                 else Reply(S_OK);
    00788                         }
    00789                 }
    00790                 while(!m_fAbort && m_pCluster->Next(true));
    00791
    00792                 m_nOpenProgress = 100;
    00793
    00794                 if(!m_fAbort) m_pFile->m_segment.Cues.AddTail(pCue);
    00795
    00796                 m_fAbort = false;
    00797         }
    00798
    00799         m_pCluster.Free();
    00800         m_pBlock.Free();
    00801
    00802         return(true);
    00803 }
    00804
    00805 void CMatroskaSplitterFilter::DemuxSeek(REFERENCE_TIME rt)
    00806 {
    00807         m_pCluster = m_pSegment->Child(0x1F43B675);
    00808         m_pBlock.Free();
    00809
    00810         if(rt > 0)
    00811         {
    00812                 rt += m_pFile->m_rtOffset;
    00813
    00814                 QWORD lastCueClusterPosition = -1;
    00815
    00816                 Segment& s = m_pFile->m_segment;
    00817
    00818                 UINT64 TrackNumber = s.GetMasterTrack();
    00819
    00820                 POSITION pos1 = s.Cues.GetHeadPosition();
    00821                 while(pos1)
    00822                 {
    00823                         Cue* pCue = s.Cues.GetNext(pos1);
    00824
    00825                         POSITION pos2 = pCue->CuePoints.GetTailPosition();
    00826                         while(pos2)
    00827                         {
    00828                                 CuePoint* pCuePoint = pCue->CuePoints.GetPrev(pos2);
    00829
    00830                                 if(rt < s.GetRefTime(pCuePoint->CueTime))
    00831                                         continue;
    00832
    00833                                 POSITION pos3 = pCuePoint->CueTrackPositions.GetHeadPosition();
    00834                                 while(pos3)
    00835                                 {
    00836                                         CueTrackPosition* pCueTrackPositions = pCuePoint->CueTrackPositions.GetNext(pos3);
    00837
    00838                                         if(TrackNumber != pCueTrackPositions->CueTrack)
    00839                                                 continue;
    00840
    00841                                         if(lastCueClusterPosition == pCueTrackPositions->CueClusterPosition)
    00842                                                 continue;
    00843
    00844                                         lastCueClusterPosition = pCueTrackPositions->CueClusterPosition;
    00845
    00846                                         m_pCluster->SeekTo(m_pSegment->m_start + pCueTrackPositions->CueClusterPosition);
    00847                                         m_pCluster->Parse();
    00848
    00849                                         bool fFoundKeyFrame = false;
    00850 /*
    00851                                         if(pCueTrackPositions->CueBlockNumber > 0)
    00852                                         {
    00853                                                 // TODO: CueBlockNumber only tells the block num of the track and not for all mixed in the cluster
    00854                                                 m_nLastBlock = (int)pCueTrackPositions->CueBlockNumber;
    00855                                                 fFoundKeyFrame = true;
    00856                                         }
    00857                                         else
    00858 */
    00859                                         {
    00860                                                 Cluster c;
    00861                                                 c.ParseTimeCode(m_pCluster);
    00862
    00863                                                 if(CAutoPtr<CMatroskaNode> pBlock = m_pCluster->GetFirstBlock())
    00864                                                 {
    00865                                                         bool fPassedCueTime = false;
    00866
    00867                                                         do
    00868                                                         {
    00869                                                                 CBlockGroupNode bgn;
    00870
    00871                                                                 if(pBlock->m_id == 0xA0)
    00872                                                                 {
    00873                                                                         bgn.Parse(pBlock, true);
    00874                                                                 }
    00875                                                                 else if(pBlock->m_id == 0xA3)
    00876                                                                 {
    00877                                                                         CAutoPtr<BlockGroup> bg(new BlockGroup());
    00878                                                                         bg->Block.Parse(pBlock, true);
    00879                                                                         if(!(bg->Block.Lacing & 0x80)) bg->ReferenceBlock.Set(0); // not a kf
    00880                                                                         bgn.AddTail(bg);
    00881                                                                 }
    00882
    00883                                                                 POSITION pos4 = bgn.GetHeadPosition();
    00884                                                                 while(!fPassedCueTime && pos4)
    00885                                                                 {
    00886                                                                         BlockGroup* bg = bgn.GetNext(pos4);
    00887
    00888                                                                         if(bg->Block.TrackNumber == pCueTrackPositions->CueTrack && rt < s.GetRefTime(c.TimeCode + bg->Block.TimeCode)
    00889                                                                         || rt + 5000000i64 < s.GetRefTime(c.TimeCode + bg->Block.TimeCode)) // allow 500ms difference between tracks, just in case intreleaving wasn't that much precise
    00890                                                                         {
    00891                                                                                 fPassedCueTime = true;
    00892                                                                         }
    00893                                                                         else if(bg->Block.TrackNumber == pCueTrackPositions->CueTrack && !bg->ReferenceBlock.IsValid())
    00894                                                                         {
    00895                                                                                 fFoundKeyFrame = true;
    00896                                                                                 m_pBlock = pBlock->Copy();
    00897                                                                         }
    00898                                                                 }
    00899                                                         }
    00900                                                         while(!fPassedCueTime && pBlock->NextBlock());
    00901                                                 }
    00902                                         }
    00903
    00904                                         if(fFoundKeyFrame)
    00905                                                 pos1 = pos2 = pos3 = NULL;
    00906                                 }
    00907                         }
    00908                 }
    00909
    00910                 if(!m_pBlock)
    00911                 {
    00912                         m_pCluster = m_pSegment->Child(0x1F43B675);
    00913                 }
    00914         }
    00915 }
    00916
    00917 bool CMatroskaSplitterFilter::DemuxLoop()
    00918 {
    00919         HRESULT hr = S_OK;
    00920
    00921         SendVorbisHeaderSample(); // HACK: init vorbis decoder with the headers
    00922
    00923         do
    00924         {
    00925                 Cluster c;
    00926                 c.ParseTimeCode(m_pCluster);
    00927
    00928                 if(!m_pBlock) m_pBlock = m_pCluster->GetFirstBlock();
    00929                 if(!m_pBlock) continue;
    00930
    00931                 do
    00932                 {
    00933                         CBlockGroupNode bgn;
    00934
    00935                         if(m_pBlock->m_id == 0xA0)
    00936                         {
    00937                                 bgn.Parse(m_pBlock, true);
    00938                         }
    00939                         else if(m_pBlock->m_id == 0xA3)
    00940                         {
    00941                                 CAutoPtr<BlockGroup> bg(new BlockGroup());
    00942                                 bg->Block.Parse(m_pBlock, true);
    00943                                 if(!(bg->Block.Lacing & 0x80)) bg->ReferenceBlock.Set(0); // not a kf
    00944                                 bgn.AddTail(bg);
    00945                         }
    00946
    00947                         while(bgn.GetCount())
    00948                         {
    00949                                 CAutoPtr<MatroskaPacket> p(new MatroskaPacket());
    00950                                 p->bg = bgn.RemoveHead();
    00951
    00952                                 p->bSyncPoint = !p->bg->ReferenceBlock.IsValid();
    00953                                 p->TrackNumber = (DWORD)p->bg->Block.TrackNumber;
    00954
    00955                                 TrackEntry *pTE = m_pTrackEntryMap[p->TrackNumber];
    00956                                 p->rtStart = m_pFile->m_segment.GetRefTime((REFERENCE_TIME)c.TimeCode + p->bg->Block.TimeCode);
    00957                                 p->rtStop = p->rtStart + (p->bg->BlockDuration.IsValid() ? m_pFile->m_segment.GetRefTime(p->bg->BlockDuration) : 1);
    00958
    00959                                 // Fix subtitle with duration = 0
    00960                                 if(pTE && (pTE->TrackType == TrackEntry::TypeSubtitle) && (!p->bg->BlockDuration.IsValid()))
    00961                                 {
    00962                                         p->bg->BlockDuration.Set(1); // just setting it to be valid
    00963                                         p->rtStop = p->rtStart;
    00964                                 }
    00965
    00966                                 POSITION pos = p->bg->Block.BlockData.GetHeadPosition();
    00967                                 while(pos)
    00968                                 {
    00969                                         CBinary* pb = p->bg->Block.BlockData.GetNext(pos);
    00970                                         m_pTrackEntryMap[p->TrackNumber]->Expand(*pb, ContentEncoding::AllFrameContents);
    00971                                 }
    00972
    00973                                 // HACK
    00974                                 p->rtStart -= m_pFile->m_rtOffset;
    00975                                 p->rtStop -= m_pFile->m_rtOffset;
    00976
    00977                                 hr = DeliverPacket(p);
    00978                         }
    00979                 }
    00980                 while(m_pBlock->NextBlock() && SUCCEEDED(hr) && !CheckRequest(NULL));
    00981
    00982                 m_pBlock.Free();
    00983         }
    00984         while(m_pFile->GetPos() < m_pFile->m_segment.pos + m_pFile->m_segment.len
    00985                 && m_pCluster->Next(true) && SUCCEEDED(hr) && !CheckRequest(NULL));
    00986
    00987         m_pCluster.Free();
    00988
    00989         return(true);
    00990 }
    00991
    00992 // IMediaSeeking
    00993
    00994 STDMETHODIMP CMatroskaSplitterFilter::GetDuration(LONGLONG* pDuration)
    00995 {
    00996         CheckPointer(pDuration, E_POINTER);
    00997         CheckPointer(m_pFile, VFW_E_NOT_CONNECTED);
    00998
    00999         Segment& s = m_pFile->m_segment;
    01000         *pDuration = s.GetRefTime((INT64)s.SegmentInfo.Duration);
    01001
    01002         return S_OK;
    01003 }
    01004
    01005 // IKeyFrameInfo
    01006
    01007 STDMETHODIMP CMatroskaSplitterFilter::GetKeyFrameCount(UINT& nKFs)
    01008 {
    01009         if(!m_pFile) return E_UNEXPECTED;
    01010
    01011         HRESULT hr = S_OK;
    01012
    01013         nKFs = 0;
    01014
    01015         POSITION pos = m_pFile->m_segment.Cues.GetHeadPosition();
    01016         while(pos) nKFs += m_pFile->m_segment.Cues.GetNext(pos)->CuePoints.GetCount();
    01017
    01018         return hr;
    01019 }
    01020
    01021 STDMETHODIMP CMatroskaSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs)
    01022 {
    01023         CheckPointer(pFormat, E_POINTER);
    01024         CheckPointer(pKFs, E_POINTER);
    01025
    01026         if(!m_pFile) return E_UNEXPECTED;
    01027         if(*pFormat != TIME_FORMAT_MEDIA_TIME) return E_INVALIDARG;
    01028
    01029         UINT nKFsTmp = 0;
    01030
    01031         POSITION pos1 = m_pFile->m_segment.Cues.GetHeadPosition();
    01032         while(pos1 && nKFsTmp < nKFs)
    01033         {
    01034                 Cue* pCue = m_pFile->m_segment.Cues.GetNext(pos1);
    01035
    01036                 POSITION pos2 = pCue->CuePoints.GetHeadPosition();
    01037                 while(pos2 && nKFsTmp < nKFs)
    01038                         pKFs[nKFsTmp++] = m_pFile->m_segment.GetRefTime(pCue->CuePoints.GetNext(pos2)->CueTime);
    01039         }
    01040
    01041         nKFs = nKFsTmp;
    01042
    01043         return S_OK;
    01044 }
    01045
    01046 //
    01047 // CMatroskaSourceFilter
    01048 //
    01049
    01050 CMatroskaSourceFilter::CMatroskaSourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
    01051         : CMatroskaSplitterFilter(pUnk, phr)
    01052 {
    01053         m_clsid = __uuidof(this);
    01054         m_pInput.Free();
    01055 }
    01056
    01057 //
    01058 // CMatroskaSplitterOutputPin
    01059 //
    01060
    01061 CMatroskaSplitterOutputPin::CMatroskaSplitterOutputPin(
    01062                 int nMinCache, REFERENCE_TIME rtDefaultDuration,
    01063                 CArray<CMediaType>& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
    01064         : CBaseSplitterOutputPin(mts, pName, pFilter, pLock, phr)
    01065         , m_nMinCache(nMinCache), m_rtDefaultDuration(rtDefaultDuration)
    01066 {
    01067         m_nMinCache = max(m_nMinCache, 1);
    01068 }
    01069
    01070 CMatroskaSplitterOutputPin::~CMatroskaSplitterOutputPin()
    01071 {
    01072 }
    01073
    01074 HRESULT CMatroskaSplitterOutputPin::DeliverEndFlush()
    01075 {
    01076         {
    01077                 CAutoLock cAutoLock(&m_csQueue);
    01078                 m_packets.RemoveAll();
    01079                 m_rob.RemoveAll();
    01080                 m_tos.RemoveAll();
    01081         }
    01082
    01083         return __super::DeliverEndFlush();
    01084 }
    01085
    01086 HRESULT CMatroskaSplitterOutputPin::DeliverEndOfStream()
    01087 {
    01088         CAutoLock cAutoLock(&m_csQueue);
    01089
    01090         // send out the last remaining packets from the queue
    01091
    01092         while(m_rob.GetCount())
    01093         {
    01094                 MatroskaPacket* mp = m_rob.RemoveHead();
    01095                 if(m_rob.GetCount() && !mp->bg->BlockDuration.IsValid())
    01096                         mp->rtStop = m_rob.GetHead()->rtStart;
    01097                 else if(m_rob.GetCount() == 0 && m_rtDefaultDuration > 0)
    01098                         mp->rtStop = mp->rtStart + m_rtDefaultDuration;
    01099
    01100                 timeoverride to = {mp->rtStart, mp->rtStop};
    01101                 m_tos.AddTail(to);
    01102         }
    01103
    01104         while(m_packets.GetCount())
    01105         {
    01106                 HRESULT hr = DeliverBlock(m_packets.RemoveHead());
    01107                 if(hr != S_OK) return hr;
    01108         }
    01109
    01110         return __super::DeliverEndOfStream();
    01111 }
    01112
    01113 HRESULT CMatroskaSplitterOutputPin::DeliverPacket(CAutoPtr<Packet> p)
    01114 {
    01115         MatroskaPacket* mp = dynamic_cast<MatroskaPacket*>(p.m_p);
    01116         if(!mp) return __super::DeliverPacket(p);
    01117
    01118         // don't try to understand what's happening here, it's magic
    01119
    01120         CAutoLock cAutoLock(&m_csQueue);
    01121
    01122         CAutoPtr<MatroskaPacket> p2;
    01123         p.Detach();
    01124         p2.Attach(mp);
    01125         m_packets.AddTail(p2);
    01126
    01127         POSITION pos = m_rob.GetTailPosition();
    01128         for(int i = m_nMinCache-1; i > 0 && pos && mp->bg->ReferencePriority < m_rob.GetAt(pos)->bg->ReferencePriority; i--)
    01129                 m_rob.GetPrev(pos);
    01130
    01131         if(!pos) m_rob.AddHead(mp);
    01132         else m_rob.InsertAfter(pos, mp);
    01133
    01134         mp = NULL;
    01135
    01136         if(m_rob.GetCount() == m_nMinCache+1)
    01137         {
    01138                 ASSERT(m_nMinCache > 0);
    01139                 pos = m_rob.GetHeadPosition();
    01140                 MatroskaPacket* mp1 = m_rob.GetNext(pos);
    01141                 MatroskaPacket* mp2 = m_rob.GetNext(pos);
    01142                 if(!mp1->bg->BlockDuration.IsValid())
    01143                 {
    01144                         mp1->bg->BlockDuration.Set(1); // just to set it valid
    01145
    01146                         if(mp1->rtStart >= mp2->rtStart)
    01147                         {
    01148 /*                              CString str;
    01149                                 str.Format(_T("mp1->rtStart (%I64d) >= mp2->rtStart (%I64d)!!!\n"), mp1->rtStart, mp2->rtStart);
    01150                                 AfxMessageBox(str);
    01151 */
    01152                                 // TRACE(_T("mp1->rtStart (%I64d) >= mp2->rtStart (%I64d)!!!\n"), mp1->rtStart, mp2->rtStart);
    01153                         }
    01154                         else
    01155                         {
    01156                                 mp1->rtStop = mp2->rtStart;
    01157                         }
    01158                 }
    01159         }
    01160
    01161         while(m_packets.GetCount())
    01162         {
    01163                 mp = m_packets.GetHead();
    01164                 if(!mp->bg->BlockDuration.IsValid()) break;
    01165
    01166                 mp = m_rob.RemoveHead();
    01167                 timeoverride to = {mp->rtStart, mp->rtStop};
    01168                 m_tos.AddTail(to);
    01169
    01170                 HRESULT hr = DeliverBlock(m_packets.RemoveHead());
    01171                 if(hr != S_OK) return hr;
    01172         }
    01173
    01174         return S_OK;
    01175 }
    01176
    01177 HRESULT CMatroskaSplitterOutputPin::DeliverBlock(MatroskaPacket* p)
    01178 {
    01179         HRESULT hr = S_FALSE;
    01180
    01181         if(m_tos.GetCount())
    01182         {
    01183                 timeoverride to = m_tos.RemoveHead();
    01184 //              if(p->TrackNumber == 2)
    01185                 TRACE(_T("(track=%d) %I64d, %I64d -> %I64d, %I64d (buffcnt=%d)\n"),
    01186                         p->TrackNumber, p->rtStart, p->rtStop, to.rtStart, to.rtStop,
    01187                         QueueCount());
    01188
    01189                 p->rtStart = to.rtStart;
    01190                 p->rtStop = to.rtStop;
    01191         }
    01192
    01193         REFERENCE_TIME
    01194                 rtStart = p->rtStart,
    01195                 rtDelta = (p->rtStop - p->rtStart) / p->bg->Block.BlockData.GetCount(),
    01196                 rtStop = p->rtStart + rtDelta;
    01197
    01198         POSITION pos = p->bg->Block.BlockData.GetHeadPosition();
    01199         while(pos)
    01200         {
    01201                 CAutoPtr<Packet> tmp(new Packet());
    01202                 tmp->TrackNumber = p->TrackNumber;
    01203                 tmp->bDiscontinuity = p->bDiscontinuity;
    01204                 tmp->bSyncPoint = p->bSyncPoint;
    01205                 tmp->rtStart = rtStart;
    01206                 tmp->rtStop = rtStop;
    01207                 tmp->pData.Copy(*p->bg->Block.BlockData.GetNext(pos));
    01208                 if(S_OK != (hr = DeliverPacket(tmp))) break;
    01209
    01210                 rtStart += rtDelta;
    01211                 rtStop += rtDelta;
    01212
    01213                 p->bSyncPoint = false;
    01214                 p->bDiscontinuity = false;
    01215         }
    01216
    01217         return hr;
    01218 }
    01219
    01220 // ITrackInfo
    01221
    01222 TrackEntry* CMatroskaSplitterFilter::GetTrackEntryAt(UINT aTrackIdx)
    01223 {
    01224         if(aTrackIdx < 0 || aTrackIdx >= m_pOrderedTrackArray.GetCount())
    01225                 return NULL;
    01226         return m_pOrderedTrackArray[aTrackIdx];
    01227 }
    01228
    01229 STDMETHODIMP_(UINT) CMatroskaSplitterFilter::GetTrackCount()
    01230 {
    01231         return m_pTrackEntryMap.GetCount();
    01232 }
    01233
    01234 STDMETHODIMP_(BOOL) CMatroskaSplitterFilter::GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill)
    01235 {
    01236         TrackEntry* pTE = GetTrackEntryAt(aTrackIdx);
    01237         if(pTE == NULL)
    01238                 return FALSE;
    01239
    01240         pStructureToFill->FlagDefault = !!pTE->FlagDefault;
    01241         pStructureToFill->FlagLacing = !!pTE->FlagLacing;
    01242         strncpy(pStructureToFill->Language, pTE->Language, 3);
    01243         if(pStructureToFill->Language[0] == '\0')
    01244                 strncpy(pStructureToFill->Language, "eng", 3);
    01245         pStructureToFill->Language[3] = '\0';
    01246         pStructureToFill->MaxCache = (UINT)pTE->MaxCache;
    01247         pStructureToFill->MinCache = (UINT)pTE->MinCache;
    01248         pStructureToFill->Type = (BYTE)pTE->TrackType;
    01249         return TRUE;
    01250 }
    01251
    01252 STDMETHODIMP_(BOOL) CMatroskaSplitterFilter::GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill)
    01253 {
    01254         TrackEntry* pTE = GetTrackEntryAt(aTrackIdx);
    01255         if(pTE == NULL)
    01256                 return FALSE;
    01257
    01258         if(pTE->TrackType == TrackEntry::TypeVideo)
    01259         {
    01260                 TrackExtendedInfoVideo* pTEIV = (TrackExtendedInfoVideo*)pStructureToFill;
    01261                 pTEIV->AspectRatioType = (BYTE)pTE->v.AspectRatioType;
    01262                 pTEIV->DisplayUnit = (BYTE)pTE->v.DisplayUnit;
    01263                 pTEIV->DisplayWidth = (UINT)pTE->v.DisplayWidth;
    01264                 pTEIV->DisplayHeight = (UINT)pTE->v.DisplayHeight;
    01265                 pTEIV->Interlaced = !!pTE->v.FlagInterlaced;
    01266                 pTEIV->PixelWidth = (UINT)pTE->v.PixelWidth;
    01267                 pTEIV->PixelHeight = (UINT)pTE->v.PixelHeight;
    01268         } else if(pTE->TrackType == TrackEntry::TypeAudio) {
    01269                 TrackExtendedInfoAudio* pTEIA = (TrackExtendedInfoAudio*)pStructureToFill;
    01270                 pTEIA->BitDepth = (UINT)pTE->a.BitDepth;
    01271                 pTEIA->Channels = (UINT)pTE->a.Channels;
    01272                 pTEIA->OutputSamplingFrequency = pTE->a.OutputSamplingFrequency;
    01273                 pTEIA->SamplingFreq = pTE->a.SamplingFrequency;
    01274         } else {
    01275                 return FALSE;
    01276         }
    01277
    01278         return TRUE;
    01279 }
    01280
    01281 STDMETHODIMP_(BSTR) CMatroskaSplitterFilter::GetTrackName(UINT aTrackIdx)
    01282 {
    01283         TrackEntry* pTE = GetTrackEntryAt(aTrackIdx);
    01284         if(pTE == NULL)
    01285                 return NULL;
    01286         return pTE->Name.AllocSysString();
    01287 }
    01288
    01289 STDMETHODIMP_(BSTR) CMatroskaSplitterFilter::GetTrackCodecID(UINT aTrackIdx)
    01290 {
    01291         TrackEntry* pTE = GetTrackEntryAt(aTrackIdx);
    01292         if(pTE == NULL)
    01293                 return NULL;
    01294         return pTE->CodecID.ToString().AllocSysString();
    01295 }
    01296
    01297 STDMETHODIMP_(BSTR) CMatroskaSplitterFilter::GetTrackCodecName(UINT aTrackIdx)
    01298 {
    01299         TrackEntry* pTE = GetTrackEntryAt(aTrackIdx);
    01300         if(pTE == NULL)
    01301                 return NULL;
    01302         return pTE->CodecName.AllocSysString();
    01303 }
    01304
    01305 STDMETHODIMP_(BSTR) CMatroskaSplitterFilter::GetTrackCodecInfoURL(UINT aTrackIdx)
    01306 {
    01307         TrackEntry* pTE = GetTrackEntryAt(aTrackIdx);
    01308         if(pTE == NULL)
    01309                 return NULL;
    01310         return pTE->CodecInfoURL.AllocSysString();
    01311 }
    01312
    01313 STDMETHODIMP_(BSTR) CMatroskaSplitterFilter::GetTrackCodecDownloadURL(UINT aTrackIdx)
    01314 {
    01315         TrackEntry* pTE = GetTrackEntryAt(aTrackIdx);
    01316         if(pTE == NULL)
    01317                 return NULL;
    01318         return pTE->CodecDownloadURL.AllocSysString();
    01319 }