- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# MatroskaMuxer.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 "MatroskaMuxer.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 MatroskaWriter;
    00033
    00034 #ifdef REGISTER_FILTER
    00035
    00036 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
    00037 {
    00038         {&MEDIATYPE_Stream, &MEDIASUBTYPE_Matroska}
    00039 };
    00040
    00041 const AMOVIESETUP_PIN sudpPins[] =
    00042 {
    00043     {L"Input", FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, NULL, 0, NULL},
    00044     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}
    00045 };
    00046
    00047 const AMOVIESETUP_FILTER sudFilter[] =
    00048 {
    00049         {&__uuidof(CMatroskaMuxerFilter), L"Matroska Muxer", MERIT_DO_NOT_USE, countof(sudpPins), sudpPins}
    00050 };
    00051
    00052 CFactoryTemplate g_Templates[] =
    00053 {
    00054         {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CMatroskaMuxerFilter>, NULL, &sudFilter[0]}
    00055 };
    00056
    00057 int g_cTemplates = countof(g_Templates);
    00058
    00059 STDAPI DllRegisterServer()
    00060 {
    00061         return AMovieDllRegisterServer2(TRUE);
    00062 }
    00063
    00064 STDAPI DllUnregisterServer()
    00065 {
    00066         return AMovieDllRegisterServer2(FALSE);
    00067 }
    00068
    00069 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
    00070
    00071 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
    00072 {
    00073     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
    00074 }
    00075
    00076 #endif
    00077
    00078 //
    00079 // CMatroskaMuxerFilter
    00080 //
    00081
    00082 CMatroskaMuxerFilter::CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr)
    00083         : CBaseFilter(NAME("CMatroskaMuxerFilter"), pUnk, this, __uuidof(this))
    00084         , m_rtCurrent(0)
    00085         , m_fNegative(true), m_fPositive(false)
    00086 {
    00087         if(phr) *phr = S_OK;
    00088
    00089         m_pOutput.Attach(new CMatroskaMuxerOutputPin(NAME("CMatroskaMuxerOutputPin"), this, this, phr));
    00090
    00091         AddInput();
    00092
    00093         srand(clock());
    00094 }
    00095
    00096 CMatroskaMuxerFilter::~CMatroskaMuxerFilter()
    00097 {
    00098         CAutoLock cAutoLock(this);
    00099 }
    00100
    00101 STDMETHODIMP CMatroskaMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00102 {
    00103         CheckPointer(ppv, E_POINTER);
    00104
    00105         *ppv = NULL;
    00106
    00107         return
    00108 //              QI(IAMFilterMiscFlags)
    00109                 QI(IMediaSeeking)
    00110                 QI(IMatroskaMuxer)
    00111                 __super::NonDelegatingQueryInterface(riid, ppv);
    00112 }
    00113
    00114 UINT CMatroskaMuxerFilter::GetTrackNumber(CBasePin* pPin)
    00115 {
    00116         UINT nTrackNumber = 0;
    00117
    00118         POSITION pos = m_pInputs.GetHeadPosition();
    00119         while(pos)
    00120         {
    00121                 nTrackNumber++;
    00122                 if(m_pInputs.GetNext(pos) == pPin)
    00123                         return nTrackNumber;
    00124         }
    00125
    00126         return 0;
    00127 }
    00128
    00129 void CMatroskaMuxerFilter::AddInput()
    00130 {
    00131         POSITION pos = m_pInputs.GetHeadPosition();
    00132         while(pos)
    00133         {
    00134                 CBasePin* pPin = m_pInputs.GetNext(pos);
    00135                 if(!pPin->IsConnected()) return;
    00136         }
    00137
    00138         CStringW name;
    00139         name.Format(L"Track %d", m_pInputs.GetCount()+1);
    00140
    00141         HRESULT hr;
    00142         CAutoPtr<CMatroskaMuxerInputPin> pPin(new CMatroskaMuxerInputPin(name, this, this, &hr));
    00143         m_pInputs.AddTail(pPin);
    00144 }
    00145
    00146 int CMatroskaMuxerFilter::GetPinCount()
    00147 {
    00148         return m_pInputs.GetCount() + (m_pOutput ? 1 : 0);
    00149 }
    00150
    00151 CBasePin* CMatroskaMuxerFilter::GetPin(int n)
    00152 {
    00153     CAutoLock cAutoLock(this);
    00154
    00155         if(n >= 0 && n < (int)m_pInputs.GetCount())
    00156         {
    00157                 if(POSITION pos = m_pInputs.FindIndex(n))
    00158                         return m_pInputs.GetAt(pos);
    00159         }
    00160
    00161         if(n == m_pInputs.GetCount() && m_pOutput)
    00162         {
    00163                 return m_pOutput;
    00164         }
    00165
    00166         return NULL;
    00167 }
    00168
    00169 STDMETHODIMP CMatroskaMuxerFilter::Stop()
    00170 {
    00171         CAutoLock cAutoLock(this);
    00172
    00173         HRESULT hr;
    00174
    00175         if(FAILED(hr = __super::Stop()))
    00176                 return hr;
    00177
    00178         CallWorker(CMD_EXIT);
    00179
    00180         return hr;
    00181 }
    00182
    00183 STDMETHODIMP CMatroskaMuxerFilter::Pause()
    00184 {
    00185         CAutoLock cAutoLock(this);
    00186
    00187         FILTER_STATE fs = m_State;
    00188
    00189         HRESULT hr;
    00190
    00191         if(FAILED(hr = __super::Pause()))
    00192                 return hr;
    00193
    00194         if(fs == State_Stopped && m_pOutput)
    00195         {
    00196                 CAMThread::Create();
    00197                 CallWorker(CMD_RUN);
    00198         }
    00199
    00200         return hr;
    00201 }
    00202
    00203 STDMETHODIMP CMatroskaMuxerFilter::Run(REFERENCE_TIME tStart)
    00204 {
    00205         CAutoLock cAutoLock(this);
    00206
    00207         HRESULT hr;
    00208
    00209         if(FAILED(hr = __super::Run(tStart)))
    00210                 return hr;
    00211
    00212         return hr;
    00213 }
    00214
    00215 // IAMFilterMiscFlags
    00216
    00217 STDMETHODIMP_(ULONG) CMatroskaMuxerFilter::GetMiscFlags()
    00218 {
    00219         return AM_FILTER_MISC_FLAGS_IS_RENDERER;
    00220 }
    00221
    00222 // IMediaSeeking
    00223
    00224 STDMETHODIMP CMatroskaMuxerFilter::GetCapabilities(DWORD* pCapabilities)
    00225 {
    00226         return pCapabilities ? *pCapabilities =
    00227                 AM_SEEKING_CanGetDuration|
    00228                 AM_SEEKING_CanGetCurrentPos, S_OK : E_POINTER;
    00229 }
    00230 STDMETHODIMP CMatroskaMuxerFilter::CheckCapabilities(DWORD* pCapabilities)
    00231 {
    00232         CheckPointer(pCapabilities, E_POINTER);
    00233         if(*pCapabilities == 0) return S_OK;
    00234         DWORD caps;
    00235         GetCapabilities(&caps);
    00236         caps &= *pCapabilities;
    00237         return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE;
    00238 }
    00239 STDMETHODIMP CMatroskaMuxerFilter::IsFormatSupported(const GUID* pFormat) {return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;}
    00240 STDMETHODIMP CMatroskaMuxerFilter::QueryPreferredFormat(GUID* pFormat) {return GetTimeFormat(pFormat);}
    00241 STDMETHODIMP CMatroskaMuxerFilter::GetTimeFormat(GUID* pFormat) {return pFormat ? *pFormat = TIME_FORMAT_MEDIA_TIME, S_OK : E_POINTER;}
    00242 STDMETHODIMP CMatroskaMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) {return IsFormatSupported(pFormat);}
    00243 STDMETHODIMP CMatroskaMuxerFilter::SetTimeFormat(const GUID* pFormat) {return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG;}
    00244 STDMETHODIMP CMatroskaMuxerFilter::GetDuration(LONGLONG* pDuration)
    00245 {
    00246         CheckPointer(pDuration, E_POINTER);
    00247         *pDuration = 0;
    00248         POSITION pos = m_pInputs.GetHeadPosition();
    00249         while(pos) {REFERENCE_TIME rt = m_pInputs.GetNext(pos)->m_rtDur; if(rt > *pDuration) *pDuration = rt;}
    00250         return S_OK;
    00251 }
    00252 STDMETHODIMP CMatroskaMuxerFilter::GetStopPosition(LONGLONG* pStop) {return E_NOTIMPL;}
    00253 STDMETHODIMP CMatroskaMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent)
    00254 {
    00255         CheckPointer(pCurrent, E_POINTER);
    00256         *pCurrent = m_rtCurrent;
    00257         return S_OK;
    00258 }
    00259 STDMETHODIMP CMatroskaMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) {return E_NOTIMPL;}
    00260 STDMETHODIMP CMatroskaMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) {return E_NOTIMPL;}
    00261 STDMETHODIMP CMatroskaMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) {return E_NOTIMPL;}
    00262 STDMETHODIMP CMatroskaMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) {return E_NOTIMPL;}
    00263 STDMETHODIMP CMatroskaMuxerFilter::SetRate(double dRate) {return E_NOTIMPL;}
    00264 STDMETHODIMP CMatroskaMuxerFilter::GetRate(double* pdRate) {return E_NOTIMPL;}
    00265 STDMETHODIMP CMatroskaMuxerFilter::GetPreroll(LONGLONG* pllPreroll) {return E_NOTIMPL;}
    00266
    00267 // IMatroskaMuxer
    00268
    00269 STDMETHODIMP CMatroskaMuxerFilter::CorrectTimeOffset(bool fNegative, bool fPositive)
    00270 {
    00271         m_fNegative = fNegative;
    00272         m_fPositive = fPositive;
    00273         return S_OK;
    00274 }
    00275
    00276 //
    00277
    00278 ULONGLONG GetStreamPosition(IStream* pStream)
    00279 {
    00280         ULARGE_INTEGER pos = {0, 0};
    00281         pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos);
    00282         return pos.QuadPart;
    00283 }
    00284
    00285 ULONGLONG SetStreamPosition(IStream* pStream, ULONGLONG seekpos)
    00286 {
    00287         LARGE_INTEGER pos;
    00288         pos.QuadPart = seekpos;
    00289         ULARGE_INTEGER posnew;
    00290         posnew.QuadPart = GetStreamPosition(pStream);
    00291         pStream->Seek(pos, STREAM_SEEK_SET, &posnew);
    00292         return posnew.QuadPart;
    00293 }
    00294
    00295 DWORD CMatroskaMuxerFilter::ThreadProc()
    00296 {
    00297         CComQIPtr<IStream> pStream;
    00298
    00299         if(!m_pOutput || !(pStream = m_pOutput->GetConnected()))
    00300         {
    00301                 while(1)
    00302                 {
    00303                         DWORD cmd = GetRequest();
    00304                         if(cmd == CMD_EXIT) CAMThread::m_hThread = NULL;
    00305                         Reply(S_OK);
    00306                         if(cmd == CMD_EXIT) return 0;
    00307                 }
    00308         }
    00309
    00310         REFERENCE_TIME rtDur = 0;
    00311         GetDuration(&rtDur);
    00312
    00313         SetStreamPosition(pStream, 0);
    00314
    00315         ULARGE_INTEGER uli = {0};
    00316         pStream->SetSize(uli);
    00317
    00318         EBML hdr;
    00319         hdr.DocType.Set("matroska");
    00320         hdr.DocTypeVersion.Set(1);
    00321         hdr.DocTypeReadVersion.Set(1);
    00322         hdr.Write(pStream);
    00323
    00324         Segment().Write(pStream);
    00325         ULONGLONG segpos = GetStreamPosition(pStream);
    00326
    00327         // TODO
    00328         QWORD voidlen = 100;
    00329         if(rtDur > 0) voidlen += int(1.0 * rtDur / MAXCLUSTERTIME / 10000 + 0.5) * 20;
    00330         else voidlen += int(1.0 * 1000*60*60*24 / MAXCLUSTERTIME + 0.5) * 20; // when no duration is known, allocate for 24 hours (~340k)
    00331         ULONGLONG voidpos = GetStreamPosition(pStream);
    00332         {
    00333                 Void v(voidlen);
    00334                 voidlen = v.Size();
    00335                 v.Write(pStream);
    00336         }
    00337
    00338         // Meta Seek
    00339
    00340         Seek seek;
    00341         CAutoPtr<SeekHead> sh;
    00342
    00343         // Segment Info
    00344
    00345         sh.Attach(new SeekHead());
    00346         sh->ID.Set(0x1549A966);
    00347         sh->Position.Set(GetStreamPosition(pStream) - segpos);
    00348         seek.SeekHeads.AddTail(sh);
    00349
    00350         ULONGLONG infopos = GetStreamPosition(pStream);
    00351         Info info;
    00352         info.MuxingApp.Set(L"DirectShow Matroska Muxer");
    00353         info.TimeCodeScale.Set(1000000);
    00354         info.Duration.Set((float)rtDur / 10000);
    00355         struct tm _2001 = {0, 0, 0, 1, 0, 101, 0, 0, 1};
    00356         info.DateUTC.Set((_time64(NULL) - _mktime64(&_2001)) * 1000000000);
    00357         info.Write(pStream);
    00358
    00359         // Tracks
    00360
    00361         sh.Attach(new SeekHead());
    00362         sh->ID.Set(0x1654AE6B);
    00363         sh->Position.Set(GetStreamPosition(pStream) - segpos);
    00364         seek.SeekHeads.AddTail(sh);
    00365
    00366         UINT64 TrackNumber = 0;
    00367 /*
    00368         CNode<Track> Tracks;
    00369         CAutoPtr<Track> pT(new Track());
    00370         POSITION pos = m_pInputs.GetHeadPosition();
    00371         for(int i = 1; pos; i++)
    00372         {
    00373                 CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos);
    00374                 if(!pPin->IsConnected()) continue;
    00375
    00376                 CAutoPtr<TrackEntry> pTE(new TrackEntry());
    00377                 *pTE = *pPin->GetTrackEntry();
    00378                 if(TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo)
    00379                         TrackNumber = pTE->TrackNumber;
    00380                 pT->TrackEntries.AddTail(pTE);
    00381         }
    00382         Tracks.AddTail(pT);
    00383         Tracks.Write(pStream);
    00384
    00385         if(TrackNumber == 0) TrackNumber = 1;
    00386 */
    00387         bool fTracksWritten = false;
    00388
    00389         //
    00390
    00391         Cluster c;
    00392         c.TimeCode.Set(0);
    00393
    00394         bool fFirstBlock = true;
    00395         INT64 firstTimeCode = 0;
    00396
    00397         CList<CMatroskaMuxerInputPin*> pActivePins;
    00398
    00399         POSITION pos = m_pInputs.GetHeadPosition();
    00400         while(pos)
    00401         {
    00402                 CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos);
    00403                 if(pPin->IsConnected()) pActivePins.AddTail(pPin);
    00404         }
    00405
    00406         while(1)
    00407         {
    00408                 DWORD cmd = GetRequest();
    00409
    00410                 switch(cmd)
    00411                 {
    00412                 default:
    00413                 case CMD_EXIT:
    00414                         CAMThread::m_hThread = NULL;
    00415                         Reply(S_OK);
    00416                         return 0;
    00417
    00418                 case CMD_RUN:
    00419                         Reply(S_OK);
    00420
    00421                         Cue cue;
    00422                         ULONGLONG lastcueclusterpos = -1;
    00423                         INT64 lastcuetimecode = -1;
    00424                         UINT64 nBlocksInCueTrack = 0;
    00425
    00426                         while(!CheckRequest(NULL))
    00427                         {
    00428                                 if(m_State == State_Paused)
    00429                                 {
    00430                                         Sleep(10);
    00431                                         continue;
    00432                                 }
    00433
    00434                                 int nPinsGotSomething = 0, nPinsNeeded = 0;
    00435                                 CMatroskaMuxerInputPin* pPin = NULL;
    00436                                 REFERENCE_TIME rtMin = _I64_MAX;
    00437
    00438                                 pos = pActivePins.GetHeadPosition();
    00439                                 while(pos)
    00440                                 {
    00441                                         CMatroskaMuxerInputPin* pTmp = pActivePins.GetNext(pos);
    00442
    00443                                         CAutoLock cAutoLock(&pTmp->m_csQueue);
    00444
    00445                                         if(pTmp->m_blocks.GetCount() == 0 && pTmp->m_fEndOfStreamReceived)
    00446                                         {
    00447                                                 pActivePins.RemoveAt(pActivePins.Find(pTmp));
    00448                                                 continue;
    00449                                         }
    00450
    00451                                         if(pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle)
    00452                                                 nPinsNeeded++;
    00453
    00454                                         if(pTmp->m_blocks.GetCount() > 0)
    00455                                         {
    00456                                                 if(pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle)
    00457                                                         nPinsGotSomething++;
    00458
    00459                                                 if(pTmp->m_blocks.GetCount() > 0)
    00460                                                 {
    00461                                                         REFERENCE_TIME rt = pTmp->m_blocks.GetHead()->Block.TimeCode;
    00462                                                         if(rt < rtMin) {rtMin = rt; pPin = pTmp;}
    00463                                                 }
    00464                                         }
    00465                                 }
    00466
    00467                                 if(pActivePins.GetCount() == 0)
    00468                                 {
    00469                                         break;
    00470                                 }
    00471
    00472                                 if(!pPin || nPinsNeeded > nPinsGotSomething || !pPin && nPinsGotSomething == 0)
    00473                                 {
    00474                                         Sleep(1);
    00475                                         continue;
    00476                                 }
    00477
    00478                                 if(!fTracksWritten)
    00479                                 {
    00480                                         CNode<Track> Tracks;
    00481                                         CAutoPtr<Track> pT(new Track());
    00482                                         POSITION pos = pActivePins.GetHeadPosition();
    00483                                         for(int i = 1; pos; i++)
    00484                                         {
    00485                                                 CMatroskaMuxerInputPin* pPin = pActivePins.GetNext(pos);
    00486
    00487                                                 CAutoPtr<TrackEntry> pTE(new TrackEntry());
    00488                                                 *pTE = *pPin->GetTrackEntry();
    00489                                                 if(TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo)
    00490                                                         TrackNumber = pTE->TrackNumber;
    00491                                                 pT->TrackEntries.AddTail(pTE);
    00492                                         }
    00493                                         Tracks.AddTail(pT);
    00494                                         Tracks.Write(pStream);
    00495
    00496                                         if(TrackNumber == 0) TrackNumber = 1;
    00497
    00498                                         fTracksWritten = true;
    00499                                 }
    00500
    00501                                 ASSERT(pPin);
    00502
    00503                                 CAutoPtr<BlockGroup> b;
    00504
    00505                                 {
    00506                                         CAutoLock cAutoLock(&pPin->m_csQueue);
    00507                                         b = pPin->m_blocks.RemoveHead();
    00508                                 }
    00509
    00510                                 if(b)
    00511                                 {
    00512                                         if(fFirstBlock)
    00513                                         {
    00514                                                 if(b->Block.TimeCode < 0 && m_fNegative || b->Block.TimeCode > 0 && m_fPositive)
    00515                                                         firstTimeCode = b->Block.TimeCode;
    00516                                                 fFirstBlock = false;
    00517                                         }
    00518
    00519                                         b->Block.TimeCode -= firstTimeCode;
    00520                                         b->Block.TimeCodeStop -= firstTimeCode;
    00521
    00522 /*
    00523 TRACE(_T("Muxing (%d): %I64d-%I64d dur=%I64d (c=%d, co=%dms), cnt=%d, ref=%d\n"),
    00524         GetTrackNumber(pPin),
    00525         (INT64)b->Block.TimeCode, (INT64)b->Block.TimeCodeStop, (UINT64)b->BlockDuration,
    00526         (int)((b->Block.TimeCode)/MAXCLUSTERTIME), (int)(b->Block.TimeCode%MAXCLUSTERTIME),
    00527         b->Block.BlockData.GetCount(), (int)b->ReferenceBlock);
    00528 */
    00529                                         if(b->Block.TimeCode < SHRT_MIN /*0*/) {ASSERT(0); continue;}
    00530
    00531                                         while((INT64)(c.TimeCode + MAXCLUSTERTIME) < b->Block.TimeCode)
    00532                                         {
    00533                                                 if(!c.BlockGroups.IsEmpty())
    00534                                                 {
    00535                                                         sh.Attach(new SeekHead());
    00536                                                         sh->ID.Set(c.GetID()/*0x1F43B675*/);
    00537                                                         sh->Position.Set(GetStreamPosition(pStream) - segpos);
    00538                                                         seek.SeekHeads.AddTail(sh);
    00539
    00540                                                         c.Write(pStream); // TODO: write blocks
    00541                                                 }
    00542
    00543                                                 c.TimeCode.Set(c.TimeCode + MAXCLUSTERTIME);
    00544                                                 c.BlockGroups.RemoveAll();
    00545                                                 nBlocksInCueTrack = 0;
    00546                                         }
    00547
    00548                                         if(b->Block.TrackNumber == TrackNumber)
    00549                                         {
    00550                                                 nBlocksInCueTrack++;
    00551                                         }
    00552
    00553                                         if(b->ReferenceBlock == 0 && b->Block.TrackNumber == TrackNumber)
    00554                                         {
    00555                                                 ULONGLONG clusterpos = GetStreamPosition(pStream) - segpos;
    00556                                                 if(lastcueclusterpos != clusterpos || lastcuetimecode + 1000 < b->Block.TimeCode)
    00557                                                 {
    00558                                                         CAutoPtr<CueTrackPosition> ctp(new CueTrackPosition());
    00559                                                         ctp->CueTrack.Set(b->Block.TrackNumber);
    00560                                                         ctp->CueClusterPosition.Set(clusterpos);
    00561                                                         if(c.BlockGroups.GetCount() > 0) ctp->CueBlockNumber.Set(nBlocksInCueTrack);
    00562                                                         CAutoPtr<CuePoint> cp(new CuePoint());
    00563                                                         cp->CueTime.Set(b->Block.TimeCode);
    00564                                                         cp->CueTrackPositions.AddTail(ctp);
    00565                                                         cue.CuePoints.AddTail(cp);
    00566                                                         lastcueclusterpos = clusterpos;
    00567                                                         lastcuetimecode = b->Block.TimeCode;
    00568                                                 }
    00569                                         }
    00570
    00571                                         info.Duration.Set(max(info.Duration, (float)b->Block.TimeCodeStop));
    00572
    00573                                         m_rtCurrent = b->Block.TimeCode*10000;
    00574
    00575                                         b->Block.TimeCode -= c.TimeCode;
    00576                                         c.BlockGroups.AddTail(b);
    00577                                 }
    00578                         }
    00579
    00580                         if(!c.BlockGroups.IsEmpty())
    00581                         {
    00582                                 sh.Attach(new SeekHead());
    00583                                 sh->ID.Set(c.GetID()/*0x1F43B675*/);
    00584                                 sh->Position.Set(GetStreamPosition(pStream) - segpos);
    00585                                 seek.SeekHeads.AddTail(sh);
    00586
    00587                                 c.Write(pStream);
    00588                         }
    00589
    00590                         ULONGLONG cuepos = 0;
    00591                         if(!cue.CuePoints.IsEmpty())
    00592                         {
    00593                                 sh.Attach(new SeekHead());
    00594                                 sh->ID.Set(cue.GetID()/*0x1C53BB6B*/);
    00595                                 sh->Position.Set(GetStreamPosition(pStream) - segpos);
    00596                                 seek.SeekHeads.AddTail(sh);
    00597
    00598                                 cue.Write(pStream);
    00599                         }
    00600
    00601                         {
    00602                                 Tags tags;
    00603
    00604                                 sh.Attach(new SeekHead());
    00605                                 sh->ID.Set(tags.GetID());
    00606                                 sh->Position.Set(GetStreamPosition(pStream) - segpos);
    00607                                 seek.SeekHeads.AddTail(sh);
    00608
    00609                                 tags.Write(pStream);
    00610                         }
    00611
    00612                         SetStreamPosition(pStream, voidpos);
    00613                         int len = (int)(voidlen - seek.Size());
    00614                         ASSERT(len >= 0 && len != 1);
    00615                         seek.Write(pStream);
    00616
    00617                         if(len == 0)
    00618                         {
    00619                                 // nothing to do
    00620                         }
    00621                         else if(len >= 2)
    00622                         {
    00623                                 for(int i = 0; i < 8; i++)
    00624                                 {
    00625                                         if(len >= (1<<i*7)-2 && len <= (1<<(i+1)*7)-2)
    00626                                         {
    00627                                                 Void(len-2-i).Write(pStream);
    00628                                                 break;
    00629                                         }
    00630                                 }
    00631                         }
    00632
    00633                         if(abs(m_rtCurrent - (REFERENCE_TIME)info.Duration*10000) > 10000000i64)
    00634                         {
    00635                                 info.Duration.Set(m_rtCurrent / 10000 + 1);
    00636                         }
    00637
    00638                         SetStreamPosition(pStream, infopos);
    00639                         info.Write(pStream);
    00640
    00641                         // TODO: write some tags
    00642
    00643                         m_pOutput->DeliverEndOfStream();
    00644
    00645                         break;
    00646                 }
    00647         }
    00648
    00649         ASSERT(0); // we should only exit via CMD_EXIT
    00650
    00651         CAMThread::m_hThread = NULL;
    00652         return 0;
    00653 }
    00654
    00655 //
    00656 // CMatroskaMuxerInputPin
    00657 //
    00658
    00659 CMatroskaMuxerInputPin::CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
    00660         : CBaseInputPin(NAME("CMatroskaMuxerInputPin"), pFilter, pLock, phr, pName)
    00661         , m_fActive(false)
    00662         , m_fEndOfStreamReceived(false)
    00663         , m_rtDur(0)
    00664 {
    00665 }
    00666
    00667 CMatroskaMuxerInputPin::~CMatroskaMuxerInputPin()
    00668 {
    00669 }
    00670
    00671 STDMETHODIMP CMatroskaMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00672 {
    00673         CheckPointer(ppv, E_POINTER);
    00674
    00675         return
    00676                 __super::NonDelegatingQueryInterface(riid, ppv);
    00677 }
    00678
    00679 HRESULT CMatroskaMuxerInputPin::CheckMediaType(const CMediaType* pmt)
    00680 {
    00681         return pmt->majortype == MEDIATYPE_Video && (pmt->formattype == FORMAT_VideoInfo
    00682                                                                                                 || pmt->formattype == FORMAT_VideoInfo2)
    00683 //              || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG1Payload && pmt->formattype == FORMAT_MPEGVideo
    00684 //              || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO && pmt->formattype == FORMAT_MPEG2_VIDEO
    00685                 || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_DiracVideo && pmt->formattype == FORMAT_DiracVideoInfo
    00686                 || pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->subtype == FOURCCMap(((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag)
    00687                 || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis && pmt->formattype == FORMAT_VorbisFormat
    00688                 || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis2 && pmt->formattype == FORMAT_VorbisFormat2
    00689                 || pmt->majortype == MEDIATYPE_Audio && (pmt->subtype == MEDIASUBTYPE_14_4
    00690                                                                                                 || pmt->subtype == MEDIASUBTYPE_28_8
    00691                                                                                                 || pmt->subtype == MEDIASUBTYPE_ATRC
    00692                                                                                                 || pmt->subtype == MEDIASUBTYPE_COOK
    00693                                                                                                 || pmt->subtype == MEDIASUBTYPE_DNET
    00694                                                                                                 || pmt->subtype == MEDIASUBTYPE_SIPR) && pmt->formattype == FORMAT_WaveFormatEx
    00695                 || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None
    00696                 || pmt->majortype == MEDIATYPE_Subtitle && pmt->formattype == FORMAT_SubtitleInfo
    00697                 ? S_OK
    00698                 : E_INVALIDARG;
    00699 }
    00700
    00701 HRESULT CMatroskaMuxerInputPin::BreakConnect()
    00702 {
    00703         HRESULT hr;
    00704
    00705         if(FAILED(hr = __super::BreakConnect()))
    00706                 return hr;
    00707
    00708         m_pTE.Free();
    00709
    00710         return hr;
    00711 }
    00712
    00713 HRESULT CMatroskaMuxerInputPin::CompleteConnect(IPin* pPin)
    00714 {
    00715         HRESULT hr;
    00716
    00717         if(FAILED(hr = __super::CompleteConnect(pPin)))
    00718                 return hr;
    00719
    00720         m_rtDur = 0;
    00721         CComQIPtr<IMediaSeeking> pMS;
    00722         if((pMS = GetFilterFromPin(pPin)) || (pMS = pPin))
    00723                 pMS->GetDuration(&m_rtDur);
    00724
    00725         m_pTE.Free();
    00726         m_pTE.Attach(new TrackEntry());
    00727
    00728         m_pTE->TrackUID.Set(rand());
    00729         m_pTE->MinCache.Set(1);
    00730         m_pTE->MaxCache.Set(1);
    00731         m_pTE->TrackNumber.Set(((CMatroskaMuxerFilter*)m_pFilter)->GetTrackNumber(this));
    00732
    00733         hr = E_FAIL;
    00734
    00735         if(m_mt.majortype == MEDIATYPE_Video)
    00736         {
    00737                 m_pTE->TrackType.Set(TrackEntry::TypeVideo);
    00738
    00739                 if(m_mt.formattype == FORMAT_VideoInfo
    00740                 && m_mt.subtype == MEDIASUBTYPE_RV10 || m_mt.subtype == MEDIASUBTYPE_RV20
    00741                 || m_mt.subtype == MEDIASUBTYPE_RV30 || m_mt.subtype == MEDIASUBTYPE_RV40)
    00742                 {
    00743                         m_pTE->CodecID.Set("V_REAL/RV00");
    00744                         m_pTE->CodecID[9] = (CHAR)(m_mt.subtype.Data1>>16);
    00745
    00746                         if(m_mt.formattype == FORMAT_VideoInfo)
    00747                         {
    00748                                 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat;
    00749                                 if(m_mt.cbFormat > sizeof(VIDEOINFOHEADER))
    00750                                 {
    00751                                         m_pTE->CodecPrivate.SetSize(m_mt.cbFormat - sizeof(VIDEOINFOHEADER));
    00752                                         memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER), m_pTE->CodecPrivate.GetSize());
    00753                                 }
    00754                                 m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame*100);
    00755                                 m_pTE->DescType = TrackEntry::DescVideo;
    00756                                 m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth);
    00757                                 m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight));
    00758                                 if(vih->AvgTimePerFrame > 0)
    00759                                         m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame));
    00760                         }
    00761                         else if(m_mt.formattype == FORMAT_VideoInfo2)
    00762                         {
    00763                                 VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat;
    00764                                 if(m_mt.cbFormat > sizeof(VIDEOINFOHEADER2))
    00765                                 {
    00766                                         m_pTE->CodecPrivate.SetSize(m_mt.cbFormat - sizeof(VIDEOINFOHEADER2));
    00767                                         memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER2), m_pTE->CodecPrivate.GetSize());
    00768                                 }
    00769                                 m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame*100);
    00770                                 m_pTE->DescType = TrackEntry::DescVideo;
    00771                                 m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth);
    00772                                 m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight));
    00773                                 if(vih->AvgTimePerFrame > 0)
    00774                                         m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame));
    00775                                 m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX);
    00776                                 m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY);
    00777                         }
    00778                         else
    00779                         {
    00780                                 ASSERT(0);
    00781                                 return hr;
    00782                         }
    00783
    00784                         hr = S_OK;
    00785                 }
    00786                 else if(m_mt.formattype == FORMAT_VideoInfo)
    00787                 {
    00788                         m_pTE->CodecID.Set("V_MS/VFW/FOURCC");
    00789
    00790                         VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat;
    00791                         m_pTE->CodecPrivate.SetSize(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader));
    00792                         memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetSize());
    00793                         m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame*100);
    00794                         m_pTE->DescType = TrackEntry::DescVideo;
    00795                         m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth);
    00796                         m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight));
    00797                         if(vih->AvgTimePerFrame > 0)
    00798                                 m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame));
    00799
    00800                         hr = S_OK;
    00801                 }
    00802                 else if(m_mt.formattype == FORMAT_VideoInfo2)
    00803                 {
    00804                         m_pTE->CodecID.Set("V_MS/VFW/FOURCC");
    00805
    00806                         VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat;
    00807                         m_pTE->CodecPrivate.SetSize(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader));
    00808                         memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetSize());
    00809                         m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame*100);
    00810                         m_pTE->DescType = TrackEntry::DescVideo;
    00811                         m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth);
    00812                         m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight));
    00813                         m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX);
    00814                         m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY);
    00815                         if(vih->AvgTimePerFrame > 0)
    00816                                 m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame));
    00817
    00818                         hr = S_OK;
    00819                 }
    00820                 else if(m_mt.formattype == FORMAT_DiracVideoInfo)
    00821                 {
    00822                         m_pTE->CodecID.Set("V_DIRAC");
    00823
    00824                         DIRACINFOHEADER* vih = (DIRACINFOHEADER*)m_mt.pbFormat;
    00825                         m_pTE->CodecPrivate.SetSize(vih->cbSequenceHeader);
    00826                         memcpy(m_pTE->CodecPrivate, (BYTE*)&vih->dwSequenceHeader[0], m_pTE->CodecPrivate.GetSize());
    00827                         m_pTE->DefaultDuration.Set(vih->hdr.AvgTimePerFrame*100);
    00828                         m_pTE->DescType = TrackEntry::DescVideo;
    00829                         m_pTE->v.PixelWidth.Set(vih->hdr.bmiHeader.biWidth);
    00830                         m_pTE->v.PixelHeight.Set(abs(vih->hdr.bmiHeader.biHeight));
    00831                         // m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX);
    00832                         // m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY);
    00833                         if(vih->hdr.AvgTimePerFrame > 0)
    00834                                 m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->hdr.AvgTimePerFrame));
    00835
    00836                         hr = S_OK;
    00837                 }
    00838 /*
    00839                 else if(m_mt.formattype == FORMAT_MPEGVideo)
    00840                 {
    00841                         m_pTE->CodecID.Set("V_DSHOW/MPEG1VIDEO"); // V_MPEG1
    00842
    00843                         MPEG1VIDEOINFO* pm1vi = (MPEG1VIDEOINFO*)m_mt.pbFormat;
    00844                         m_pTE->CodecPrivate.SetSize(m_mt.FormatLength());
    00845                         memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetSize());
    00846                         m_pTE->DefaultDuration.Set(pm1vi->hdr.AvgTimePerFrame*100);
    00847                         m_pTE->DescType = TrackEntry::DescVideo;
    00848                         m_pTE->v.PixelWidth.Set(pm1vi->hdr.bmiHeader.biWidth);
    00849                         m_pTE->v.PixelHeight.Set(abs(pm1vi->hdr.bmiHeader.biHeight));
    00850                         if(pm1vi->hdr.AvgTimePerFrame > 0)
    00851                                 m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm1vi->hdr.AvgTimePerFrame));
    00852
    00853                         hr = S_OK;
    00854                 }
    00855                 else if(m_mt.formattype == FORMAT_MPEG2_VIDEO)
    00856                 {
    00857                         m_pTE->CodecID.Set("V_DSHOW/MPEG2VIDEO"); // V_MPEG2
    00858
    00859                         MPEG2VIDEOINFO* pm2vi = (MPEG2VIDEOINFO*)m_mt.pbFormat;
    00860                         m_pTE->CodecPrivate.SetSize(m_mt.FormatLength());
    00861                         memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetSize());
    00862                         m_pTE->DefaultDuration.Set(pm2vi->hdr.AvgTimePerFrame*100);
    00863                         m_pTE->DescType = TrackEntry::DescVideo;
    00864                         m_pTE->v.PixelWidth.Set(pm2vi->hdr.bmiHeader.biWidth);
    00865                         m_pTE->v.PixelHeight.Set(abs(pm2vi->hdr.bmiHeader.biHeight));
    00866                         if(pm2vi->hdr.AvgTimePerFrame > 0)
    00867                                 m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm2vi->hdr.AvgTimePerFrame));
    00868
    00869                         hr = S_OK;
    00870                 }
    00871 */
    00872         }
    00873         else if(m_mt.majortype == MEDIATYPE_Audio)
    00874         {
    00875                 m_pTE->TrackType.Set(TrackEntry::TypeAudio);
    00876
    00877                 if(m_mt.formattype == FORMAT_WaveFormatEx
    00878                 && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_AAC
    00879                 && m_mt.cbFormat >= sizeof(WAVEFORMATEX)+2)
    00880                 {
    00881                         WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat;
    00882                         BYTE* p = (BYTE*)(wfe+1);
    00883
    00884                         DWORD nSamplesPerSec = wfe->nSamplesPerSec;
    00885
    00886                         int profile = (p[0]>>3)-1;
    00887                         int     rate1 = ((p[0]&7)<<1)|(p[1]>>7);
    00888                         int channels = ((p[1]>>3)&15);
    00889                         int exttype = 0;
    00890                         int rate2 = rate1;
    00891
    00892                         if(wfe->cbSize >= 5)
    00893                         {
    00894                                 profile = 4;
    00895
    00896                                 exttype = (p[2]<<3)|(p[3]>>5);
    00897                                 ASSERT(exttype == 0x2B7);
    00898                                 ASSERT((p[3]&31) == 5);
    00899                                 ASSERT((p[4]>>7) == 1);
    00900                                 rate2 = ((p[4]>>3)&15);
    00901
    00902                                 if(rate2 < rate1)
    00903                                 {
    00904                                         m_pTE->a.OutputSamplingFrequency.Set((float)nSamplesPerSec);
    00905                                         nSamplesPerSec /= 2;
    00906                                 }
    00907                         }
    00908
    00909                         switch(profile)
    00910                         {
    00911                         default:
    00912                         case 0: m_pTE->CodecID.Set("A_AAC/MPEG2/MAIN"); break;
    00913                         case 1: m_pTE->CodecID.Set("A_AAC/MPEG2/LC"); break;
    00914                         case 2: m_pTE->CodecID.Set("A_AAC/MPEG2/SSR"); break;
    00915                         case 3: m_pTE->CodecID.Set("A_AAC/MPEG4/LTP"); break;
    00916                         case 4: m_pTE->CodecID.Set("A_AAC/MPEG4/LC/SBR"); break;
    00917                         }
    00918
    00919                         ASSERT(channels == wfe->nChannels);
    00920
    00921                         m_pTE->DescType = TrackEntry::DescAudio;
    00922                         m_pTE->a.SamplingFrequency.Set((float)nSamplesPerSec);
    00923                         m_pTE->a.Channels.Set(channels);
    00924                         m_pTE->a.BitDepth.Set(wfe->wBitsPerSample);
    00925
    00926                         hr = S_OK;
    00927                 }
    00928                 else if(m_mt.formattype == FORMAT_WaveFormatEx
    00929                 && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3)
    00930                 {
    00931                         m_pTE->CodecID.Set("A_AC3");
    00932
    00933                         WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat;
    00934                         m_pTE->DescType = TrackEntry::DescAudio;
    00935                         m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec);
    00936                         m_pTE->a.Channels.Set(wfe->nChannels);
    00937                         m_pTE->a.BitDepth.Set(wfe->wBitsPerSample);
    00938
    00939                         hr = S_OK;
    00940                 }
    00941                 else if(m_mt.formattype == FORMAT_WaveFormatEx
    00942                 && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS)
    00943                 {
    00944                         m_pTE->CodecID.Set("A_DTS");
    00945
    00946                         WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat;
    00947                         m_pTE->DescType = TrackEntry::DescAudio;
    00948                         m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec);
    00949                         m_pTE->a.Channels.Set(wfe->nChannels);
    00950                         m_pTE->a.BitDepth.Set(wfe->wBitsPerSample);
    00951
    00952                         hr = S_OK;
    00953                 }
    00954                 else if(m_mt.formattype == FORMAT_WaveFormatEx
    00955                 && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_FLAC)
    00956                 {
    00957                         m_pTE->CodecID.Set("A_FLAC");
    00958
    00959                         WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat;
    00960                         m_pTE->DescType = TrackEntry::DescAudio;
    00961                         m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec);
    00962                         m_pTE->a.Channels.Set(wfe->nChannels);
    00963                         m_pTE->a.BitDepth.Set(wfe->wBitsPerSample);
    00964
    00965                         if(wfe->cbSize)
    00966                         {
    00967                                 m_pTE->CodecPrivate.SetSize(wfe->cbSize);
    00968                                 memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(WAVEFORMATEX), wfe->cbSize);
    00969                         }
    00970
    00971                         hr = S_OK;
    00972                 }
    00973                 else if(m_mt.formattype == FORMAT_WaveFormatEx
    00974                 && (m_mt.subtype == MEDIASUBTYPE_14_4
    00975                 || m_mt.subtype == MEDIASUBTYPE_28_8
    00976                 || m_mt.subtype == MEDIASUBTYPE_ATRC
    00977                 || m_mt.subtype == MEDIASUBTYPE_COOK
    00978                 || m_mt.subtype == MEDIASUBTYPE_DNET
    00979                 || m_mt.subtype == MEDIASUBTYPE_SIPR))
    00980                 {
    00981                         CStringA id;
    00982                         id.Format("A_REAL/%c%c%c%c",
    00983                                 (char)((m_mt.subtype.Data1>>0)&0xff),
    00984                                 (char)((m_mt.subtype.Data1>>8)&0xff),
    00985                                 (char)((m_mt.subtype.Data1>>16)&0xff),
    00986                                 (char)((m_mt.subtype.Data1>>24)&0xff));
    00987
    00988                         m_pTE->CodecID.Set(id);
    00989
    00990                         WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat;
    00991                         DWORD cbSize = sizeof(WAVEFORMATEX) + wfe->cbSize;
    00992                         if(m_mt.cbFormat > cbSize)
    00993                         {
    00994                         m_pTE->CodecPrivate.SetSize(m_mt.cbFormat - cbSize);
    00995                         memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + cbSize, m_pTE->CodecPrivate.GetSize());
    00996                         }
    00997                         m_pTE->DescType = TrackEntry::DescAudio;
    00998                         m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec);
    00999                         m_pTE->a.Channels.Set(wfe->nChannels);
    01000                         m_pTE->a.BitDepth.Set(wfe->wBitsPerSample);
    01001
    01002                         hr = S_OK;
    01003                 }
    01004                 else if(m_mt.formattype == FORMAT_WaveFormatEx
    01005                 && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM)
    01006                 {
    01007                         m_pTE->CodecID.Set("A_PCM/INT/LIT");
    01008
    01009                         WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat;
    01010                         m_pTE->DescType = TrackEntry::DescAudio;
    01011                         m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec);
    01012                         m_pTE->a.Channels.Set(wfe->nChannels);
    01013                         m_pTE->a.BitDepth.Set(wfe->wBitsPerSample);
    01014
    01015                         hr = S_OK;
    01016                 }
    01017                 else if(m_mt.formattype == FORMAT_WaveFormatEx)
    01018                 {
    01019                         m_pTE->CodecID.Set("A_MS/ACM");
    01020
    01021                         WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat;
    01022                         m_pTE->CodecPrivate.SetSize(m_mt.cbFormat);
    01023                         memcpy(m_pTE->CodecPrivate, wfe, m_pTE->CodecPrivate.GetSize());
    01024                         m_pTE->DescType = TrackEntry::DescAudio;
    01025                         m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec);
    01026                         m_pTE->a.Channels.Set(wfe->nChannels);
    01027                         m_pTE->a.BitDepth.Set(wfe->wBitsPerSample);
    01028
    01029                         hr = S_OK;
    01030                 }
    01031                 else if(m_mt.formattype == FORMAT_VorbisFormat)
    01032                 {
    01033                         m_pTE->CodecID.Set("A_VORBIS");
    01034
    01035                         VORBISFORMAT* pvf = (VORBISFORMAT*)m_mt.pbFormat;
    01036                         m_pTE->DescType = TrackEntry::DescAudio;
    01037                         m_pTE->a.SamplingFrequency.Set((float)pvf->nSamplesPerSec);
    01038                         m_pTE->a.Channels.Set(pvf->nChannels);
    01039
    01040                         // m_pTE->CodecPrivate will be filled later
    01041
    01042                         hr = S_OK;
    01043                 }
    01044                 else if(m_mt.formattype == FORMAT_VorbisFormat2)
    01045                 {
    01046                         m_pTE->CodecID.Set("A_VORBIS");
    01047
    01048                         VORBISFORMAT2* pvf2 = (VORBISFORMAT2*)m_mt.pbFormat;
    01049                         m_pTE->DescType = TrackEntry::DescAudio;
    01050                         m_pTE->a.SamplingFrequency.Set((float)pvf2->SamplesPerSec);
    01051                         m_pTE->a.Channels.Set(pvf2->Channels);
    01052                         m_pTE->a.BitDepth.Set(pvf2->BitsPerSample);
    01053
    01054                         int len = 1;
    01055                         for(int i = 0; i < 2; i++) len += pvf2->HeaderSize[i]/255 + 1;
    01056                         for(int i = 0; i < 3; i++) len += pvf2->HeaderSize[i];
    01057                         m_pTE->CodecPrivate.SetSize(len);
    01058
    01059                         BYTE* src = (BYTE*)m_mt.pbFormat + sizeof(VORBISFORMAT2);
    01060                         BYTE* dst = m_pTE->CodecPrivate.GetData();
    01061
    01062                         *dst++ = 2;
    01063                         for(int i = 0; i < 2; i++)
    01064                                 for(int len = pvf2->HeaderSize[i]; len >= 0; len -= 255)
    01065                                         *dst++ = min(len, 255);
    01066
    01067                         memcpy(dst, src, pvf2->HeaderSize[0]);
    01068                         dst += pvf2->HeaderSize[0];
    01069                         src += pvf2->HeaderSize[0];
    01070                         memcpy(dst, src, pvf2->HeaderSize[1]);
    01071                         dst += pvf2->HeaderSize[1];
    01072                         src += pvf2->HeaderSize[1];
    01073                         memcpy(dst, src, pvf2->HeaderSize[2]);
    01074                         dst += pvf2->HeaderSize[2];
    01075                         src += pvf2->HeaderSize[2];
    01076
    01077                         ASSERT(src <= m_mt.pbFormat + m_mt.cbFormat);
    01078                         ASSERT(dst <= m_pTE->CodecPrivate.GetData() + m_pTE->CodecPrivate.GetSize());
    01079
    01080                         hr = S_OK;
    01081                 }
    01082         }
    01083         else if(m_mt.majortype == MEDIATYPE_Text)
    01084         {
    01085                 m_pTE->TrackType.Set(TrackEntry::TypeSubtitle);
    01086
    01087                 if(m_mt.formattype == FORMAT_None)
    01088                 {
    01089                         m_pTE->CodecID.Set("S_TEXT/ASCII");
    01090                         hr = S_OK;
    01091                 }
    01092         }
    01093         else if(m_mt.majortype == MEDIATYPE_Subtitle)
    01094         {
    01095                 m_pTE->TrackType.Set(TrackEntry::TypeSubtitle);
    01096
    01097                 m_pTE->CodecID.Set(
    01098                         m_mt.subtype == MEDIASUBTYPE_UTF8 ? "S_TEXT/UTF8" :
    01099                         m_mt.subtype == MEDIASUBTYPE_SSA ? "S_TEXT/SSA" :
    01100                         m_mt.subtype == MEDIASUBTYPE_ASS ? "S_TEXT/ASS" :
    01101                         m_mt.subtype == MEDIASUBTYPE_USF ? "S_TEXT/USF" :
    01102                         m_mt.subtype == MEDIASUBTYPE_VOBSUB ? "S_VOBSUB" :
    01103                         "");
    01104
    01105                 if(!m_pTE->CodecID.IsEmpty())
    01106                 {
    01107                         hr = S_OK;
    01108
    01109                         SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat;
    01110                         if(psi->dwOffset)
    01111                         {
    01112                                 m_pTE->CodecPrivate.SetSize(m_mt.cbFormat - psi->dwOffset);
    01113                                 memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + psi->dwOffset, m_pTE->CodecPrivate.GetSize());
    01114                         }
    01115                 }
    01116         }
    01117
    01118         if(S_OK == hr)
    01119         {
    01120                 ((CMatroskaMuxerFilter*)m_pFilter)->AddInput();
    01121         }
    01122
    01123         return hr;
    01124 }
    01125
    01126 HRESULT CMatroskaMuxerInputPin::Active()
    01127 {
    01128         m_fActive = true;
    01129         m_rtLastStart = m_rtLastStop = -1;
    01130         m_fEndOfStreamReceived = false;
    01131         return __super::Active();
    01132 }
    01133
    01134 HRESULT CMatroskaMuxerInputPin::Inactive()
    01135 {
    01136         m_fActive = false;
    01137         CAutoLock cAutoLock(&m_csQueue);
    01138         m_blocks.RemoveAll();
    01139         m_pVorbisHdrs.RemoveAll();
    01140         return __super::Inactive();
    01141 }
    01142
    01143 STDMETHODIMP CMatroskaMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
    01144 {
    01145         CAutoLock cAutoLock(&m_csReceive);
    01146         return __super::NewSegment(tStart, tStop, dRate);
    01147 }
    01148
    01149 STDMETHODIMP CMatroskaMuxerInputPin::BeginFlush()
    01150 {
    01151         return __super::BeginFlush();
    01152 }
    01153
    01154 STDMETHODIMP CMatroskaMuxerInputPin::EndFlush()
    01155 {
    01156         return __super::EndFlush();
    01157 }
    01158
    01159 STDMETHODIMP CMatroskaMuxerInputPin::Receive(IMediaSample* pSample)
    01160 {
    01161         if(m_fEndOfStreamReceived) {/*ASSERT(0);*/ return S_FALSE;}
    01162
    01163         CAutoLock cAutoLock(&m_csReceive);
    01164
    01165         while(m_fActive)
    01166         {
    01167                 {
    01168                         CAutoLock cAutoLock2(&m_csQueue);
    01169                         if(m_blocks.GetCount() < MAXBLOCKS)
    01170                                 break;
    01171                 }
    01172
    01173                 Sleep(1);
    01174         }
    01175
    01176         if(!m_fActive) return S_FALSE;
    01177
    01178         HRESULT hr;
    01179
    01180         if(FAILED(hr = __super::Receive(pSample)))
    01181                 return hr;
    01182
    01183         BYTE* pData = NULL;
    01184         pSample->GetPointer(&pData);
    01185
    01186         long len = pSample->GetActualDataLength();
    01187
    01188         REFERENCE_TIME rtStart = -1, rtStop = -1;
    01189         hr = pSample->GetTime(&rtStart, &rtStop);
    01190
    01191         if(FAILED(hr) || rtStart == -1 || rtStop == -1)
    01192         {
    01193                 TRACE(_T("No timestamp was set on the sample!!!"));
    01194                 m_pFilter->NotifyEvent(EC_ERRORABORT, VFW_E_SAMPLE_TIME_NOT_SET, 0);
    01195                 return VFW_E_SAMPLE_TIME_NOT_SET;
    01196         }
    01197
    01198 //      rtStart += m_tStart;
    01199 //      rtStop += m_tStart;
    01200
    01201
    01202         TRACE(_T("Received (%d): %I64d-%I64d (c=%d, co=%dms), len=%d, d%d p%d s%d\n"),
    01203                 ((CMatroskaMuxerFilter*)m_pFilter)->GetTrackNumber(this),
    01204                 rtStart, rtStop, (int)((rtStart/10000)/MAXCLUSTERTIME), (int)((rtStart/10000)%MAXCLUSTERTIME),
    01205                 len,
    01206                 pSample->IsDiscontinuity() == S_OK ? 1 : 0,
    01207                 pSample->IsPreroll() == S_OK ? 1 : 0,
    01208                 pSample->IsSyncPoint() == S_OK ? 1 : 0);
    01209
    01210         if(m_mt.subtype == MEDIASUBTYPE_Vorbis && m_pVorbisHdrs.GetCount() < 3)
    01211         {
    01212                 CAutoPtr<CBinary> data(new CBinary(0));
    01213                 data->SetSize(len);
    01214                 memcpy(data->GetData(), pData, len);
    01215                 m_pVorbisHdrs.Add(data);
    01216
    01217                 if(m_pVorbisHdrs.GetCount() == 3)
    01218                 {
    01219                         int len = 1;
    01220                         for(int i = 0; i < 2; i++) len += m_pVorbisHdrs[i]->GetSize()/255 + 1;
    01221                         for(int i = 0; i < 3; i++) len += m_pVorbisHdrs[i]->GetSize();
    01222                         m_pTE->CodecPrivate.SetSize(len);
    01223
    01224                         BYTE* dst = m_pTE->CodecPrivate.GetData();
    01225
    01226                         *dst++ = 2;
    01227                         for(int i = 0; i < 2; i++)
    01228                                 for(int len = m_pVorbisHdrs[i]->GetSize(); len >= 0; len -= 255)
    01229                                         *dst++ = min(len, 255);
    01230
    01231                         for(int i = 0; i < 3; i++)
    01232                         {
    01233                                 memcpy(dst, m_pVorbisHdrs[i]->GetData(), m_pVorbisHdrs[i]->GetSize());
    01234                                 dst += m_pVorbisHdrs[i]->GetSize();
    01235                         }
    01236                 }
    01237
    01238                 return S_OK;
    01239         }
    01240
    01241         if(m_mt.formattype == FORMAT_WaveFormatEx
    01242         && (((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM
    01243         || ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_MPEGLAYER3))
    01244                 pSample->SetSyncPoint(TRUE); // HACK: some capture filters don't set this
    01245
    01246         CAutoPtr<BlockGroup> b(new BlockGroup());
    01247 /*
    01248         // TODO: test this with a longer capture (pcm, mp3)
    01249         if(S_OK == pSample->IsSyncPoint() && rtStart < m_rtLastStart)
    01250         {
    01251                 TRACE(_T("!!! timestamp went backwards, dropping this frame !!! rtStart (%I64) < m_rtLastStart (%I64)"), rtStart, m_rtLastStart);
    01252                 return S_OK;
    01253         }
    01254 */
    01255         if((S_OK != pSample->IsSyncPoint() || m_rtLastStart == rtStart) && m_rtLastStart >= 0 /*&& m_rtLastStart < rtStart*/)
    01256         {
    01257                 ASSERT(m_rtLastStart - rtStart <= 0);
    01258                 REFERENCE_TIME rtDiff = m_rtLastStart - rtStart;
    01259                 b->ReferenceBlock.Set((rtDiff + (rtDiff >= 0 ? 5000 : -5000)) / 10000);
    01260         }
    01261
    01262         b->Block.TrackNumber = ((CMatroskaMuxerFilter*)m_pFilter)->GetTrackNumber(this);
    01263
    01264         b->Block.TimeCode = (rtStart + 5000) / 10000;
    01265         b->Block.TimeCodeStop = (rtStop + 5000) / 10000;
    01266
    01267         if(m_pTE->TrackType == TrackEntry::TypeSubtitle)
    01268         {
    01269                 b->BlockDuration.Set((rtStop - rtStart + 5000) / 10000);
    01270         }
    01271
    01272         CAutoPtr<CBinary> data(new CBinary(0));
    01273         data->SetSize(len);
    01274         memcpy(data->GetData(), pData, len);
    01275         b->Block.BlockData.AddTail(data);
    01276
    01277         CAutoLock cAutoLock2(&m_csQueue);
    01278         m_blocks.AddTail(b); // TODO: lacing for audio
    01279
    01280         m_rtLastStart = rtStart;
    01281         m_rtLastStop = rtStop;
    01282
    01283         return S_OK;
    01284 }
    01285
    01286 STDMETHODIMP CMatroskaMuxerInputPin::EndOfStream()
    01287 {
    01288         HRESULT hr;
    01289
    01290         if(FAILED(hr = __super::EndOfStream()))
    01291                 return hr;
    01292
    01293         CAutoLock cAutoLock(&m_csQueue);
    01294
    01295         m_fEndOfStreamReceived = true;
    01296
    01297         return hr;
    01298 }
    01299
    01300 //
    01301 // CMatroskaMuxerOutputPin
    01302 //
    01303
    01304 CMatroskaMuxerOutputPin::CMatroskaMuxerOutputPin(TCHAR* pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
    01305         : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output")
    01306 {
    01307 }
    01308
    01309 CMatroskaMuxerOutputPin::~CMatroskaMuxerOutputPin()
    01310 {
    01311 }
    01312
    01313 STDMETHODIMP CMatroskaMuxerOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    01314 {
    01315         CheckPointer(ppv, E_POINTER);
    01316
    01317         return
    01318                 __super::NonDelegatingQueryInterface(riid, ppv);
    01319 }
    01320
    01321 HRESULT CMatroskaMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
    01322 {
    01323     ASSERT(pAlloc);
    01324     ASSERT(pProperties);
    01325
    01326     HRESULT hr = NOERROR;
    01327
    01328         pProperties->cBuffers = 1;
    01329         pProperties->cbBuffer = 1;
    01330
    01331     ALLOCATOR_PROPERTIES Actual;
    01332     if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) return hr;
    01333
    01334     if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL;
    01335     ASSERT(Actual.cBuffers == pProperties->cBuffers);
    01336
    01337     return NOERROR;
    01338 }
    01339
    01340 HRESULT CMatroskaMuxerOutputPin::CheckMediaType(const CMediaType* pmt)
    01341 {
    01342         return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_Matroska
    01343                 ? S_OK
    01344                 : E_INVALIDARG;
    01345 }
    01346
    01347 HRESULT CMatroskaMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt)
    01348 {
    01349     CAutoLock cAutoLock(m_pLock);
    01350
    01351         if(iPosition < 0) return E_INVALIDARG;
    01352         if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
    01353
    01354         pmt->ResetFormatBuffer();
    01355         pmt->InitMediaType();
    01356         pmt->majortype = MEDIATYPE_Stream;
    01357         pmt->subtype = MEDIASUBTYPE_Matroska;
    01358         pmt->formattype = FORMAT_None;
    01359
    01360         return S_OK;
    01361 }
    01362
    01363 STDMETHODIMP CMatroskaMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q)
    01364 {
    01365         return E_NOTIMPL;
    01366 }
    01367
    01368