webmdshow clean-up: Mass EoL convert (CRLF -> LF) in libmkvparser.

Change-Id: I8e8f1036f76e6eedbc4a09eddeaeadf2f7965072
diff --git a/libmkvparser/mkvparserstream.cc b/libmkvparser/mkvparserstream.cc
index 139d220..05e7bc7 100644
--- a/libmkvparser/mkvparserstream.cc
+++ b/libmkvparser/mkvparserstream.cc
@@ -1,670 +1,670 @@
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.

-//

-// Use of this source code is governed by a BSD-style license

-// that can be found in the LICENSE file in the root of the source

-// tree. An additional intellectual property rights grant can be found

-// in the file PATENTS.  All contributing project authors may

-// be found in the AUTHORS file in the root of the source tree.

-

-#include <strmif.h>

-#include "mkvparserstream.h"

-#include "mkvparser.hpp"

-#include "mkvparserstreamreader.h"

-#include <cassert>

-#include <sstream>

-#include <iomanip>

-#include <vfwmsgs.h>

-#ifdef _DEBUG

-#include "odbgstream.h"

-using std::endl;

-#endif

-

-namespace mkvparser

-{

-

-

-Stream::Stream(const Track* pTrack) :

-    m_pTrack(pTrack),

-    m_pLocked(0)

-{

-    Init();

-}

-

-

-Stream::~Stream()

-{

-    SetCurr(0);

-}

-

-

-void Stream::Init()

-{

-    m_base_time_ns = -1;

-    //m_pBase = 0;

-    SetCurr(0);  //lazy init this later

-    m_pStop = m_pTrack->GetEOS();  //means play entire stream

-    m_bDiscontinuity = true;

-}

-

-

-void Stream::Stop()

-{

-    IMkvReader* const pReader_ = m_pTrack->m_pSegment->m_pReader;

-

-    using mkvparser::IStreamReader;

-    IStreamReader* const pReader = static_cast<IStreamReader*>(pReader_);

-

-    pReader->UnlockPages(m_pLocked);

-    m_pLocked = 0;

-}

-

-

-HRESULT Stream::SetCurr(const mkvparser::BlockEntry* pNext)

-{

-    IMkvReader* const pReader_ = m_pTrack->m_pSegment->m_pReader;

-

-    using mkvparser::IStreamReader;

-    IStreamReader* const pReader = static_cast<IStreamReader*>(pReader_);

-

-    m_pCurr = pNext;

-

-    pReader->UnlockPages(m_pLocked);

-    m_pLocked = m_pCurr;

-

-    const HRESULT hr = pReader->LockPages(m_pLocked);

-    assert(SUCCEEDED(hr));

-    return hr;

-}

-

-

-std::wstring Stream::GetId() const

-{

-    std::wostringstream os;

-

-    GetKind(os);  //"Video" or "Audio"

-

-    os << std::setw(3) << std::setfill(L'0') << m_pTrack->GetNumber();

-

-    return os.str();

-}

-

-

-std::wstring Stream::GetName() const

-{

-    const Track* const t = m_pTrack;

-    assert(t);

-

-    if (const char* codecName = t->GetCodecNameAsUTF8())

-        return ConvertFromUTF8(codecName);

-

-    if (const char* name = t->GetNameAsUTF8())

-        return ConvertFromUTF8(name);

-

-    if (LONGLONG tn = t->GetNumber())

-    {

-        std::wostringstream os;

-        os << L"Track" << tn;

-        return os.str();

-    }

-

-    if (const char* codecId = t->GetCodecId())

-    {

-        std::wstring result;

-

-        const char* p = codecId;

-

-        while (*p)

-            result += wchar_t(*p++);  //TODO: is this cast meaningful?

-

-        return result;

-    }

-

-    return GetId();

-}

-

-

-#if 0

-__int64 Stream::GetDuration() const

-{

-    Segment* const pSegment = m_pTrack->m_pSegment;

-    assert(pSegment);

-

-    const __int64 ns = pSegment->GetDuration();  //scaled (nanoseconds)

-    assert(ns >= 0);

-

-    const __int64 d = ns / 100;  //100-ns ticks

-

-    return d;

-}

-#endif

-

-

-#if 0

-HRESULT Stream::GetAvailable(LONGLONG* pLatest) const

-{

-    if (pLatest == 0)

-        return E_POINTER;

-

-    LONGLONG& pos = *pLatest;  //units are current time format

-

-    Segment* const pSegment = m_pTrack->m_pSegment;

-

-    if (pSegment->Unparsed() <= 0)

-        pos = GetDuration();

-    else

-    {

-        const Cluster* const pCluster = pSegment->GetLast();

-

-        if ((pCluster == 0) || pCluster->EOS())

-            pos = 0;

-        else

-        {

-            const __int64 ns = pCluster->GetTime();

-            pos = ns / 100;  //TODO: reftime units are assumed here

-        }

-    }

-

-    return S_OK;

-}

-#endif

-

-

-//__int64 Stream::GetCurrPosition() const

-//{

-//    return GetCurrTime();  //TODO: for now only support reftime units

-//}

-

-

-__int64 Stream::GetCurrTime() const

-{

-    if (m_pCurr == 0)  //NULL means lazy init hasn't happened yet

-        return 0;      //TODO: assumes track starts with t=0

-

-    if (m_pCurr->EOS())

-        return -1;

-

-    const Block* const pBlock = m_pCurr->GetBlock();

-    assert(pBlock);

-

-    const __int64 ns = pBlock->GetTime(m_pCurr->GetCluster());

-    assert(ns >= 0);

-

-    const __int64 reftime = ns / 100;  //100-ns ticks

-

-    return reftime;

-}

-

-

-//__int64 Stream::GetStopPosition() const

-//{

-//    return GetStopTime();  //TODO: for now we only support reftime units

-//}

-

-

-__int64 Stream::GetStopTime() const

-{

-    if (m_pStop == 0)  //interpreted to mean "play to end of stream"

-        return -1;

-

-    if (m_pStop->EOS())

-        return -1;

-

-    const Block* const pBlock = m_pStop->GetBlock();

-    assert(pBlock);

-

-    const __int64 ns = pBlock->GetTime(m_pStop->GetCluster());

-    assert(ns >= 0);

-

-    const __int64 reftime = ns / 100;  //100-ns ticks

-

-    return reftime;

-}

-

-

-LONGLONG Stream::GetSeekTime(

-    LONGLONG currpos_reftime,

-    DWORD dwCurr_) const

-{

-    const DWORD dwCurrPos = dwCurr_ & AM_SEEKING_PositioningBitsMask;

-    assert(dwCurrPos != AM_SEEKING_NoPositioning);  //handled by caller

-

-    Segment* const pSegment = m_pTrack->m_pSegment;

-

-    const __int64 currpos_ns = currpos_reftime * 100;

-    //__int64 tCurr_ns;

-

-    switch (dwCurrPos)

-    {

-        case AM_SEEKING_IncrementalPositioning:  //applies only to stop pos

-        default:

-            assert(false);

-            return 0;

-

-        case AM_SEEKING_AbsolutePositioning:

-            return currpos_ns;

-

-        case AM_SEEKING_RelativePositioning:

-        {

-            if (m_pCurr == 0)  //lazy init

-                return currpos_ns;  //t=0 is assumed here

-

-            else if (m_pCurr->EOS())

-            {

-                const __int64 duration_ns = pSegment->GetDuration();

-

-                if (duration_ns >= 0)  //actually have a duration

-                    return duration_ns + currpos_ns;

-

-                return 0;  //TODO: is there a better value we can return here?

-            }

-            else

-            {

-                const Block* const pBlock = m_pCurr->GetBlock();

-                assert(pBlock);

-

-                return pBlock->GetTime(m_pCurr->GetCluster()) + currpos_ns;

-            }

-        }

-    }

-}

-

-

-void Stream::SetCurrPosition(

-    //const Cluster* pBase,

-    LONGLONG base_time_ns,

-    const BlockEntry* pCurr)

-{

-    //m_pBase = pBase;

-    SetCurr(pCurr);

-    m_base_time_ns = base_time_ns;

-    m_bDiscontinuity = true;

-}

-

-

-void Stream::SetStopPosition(

-    LONGLONG stoppos_reftime,

-    DWORD dwStop_)

-{

-    const DWORD dwStopPos = dwStop_ & AM_SEEKING_PositioningBitsMask;

-    assert(dwStopPos != AM_SEEKING_NoPositioning);  //handled by caller

-

-    Segment* const pSegment = m_pTrack->m_pSegment;

-

-    if (pSegment->GetCount() == 0)

-    {

-        m_pStop = m_pTrack->GetEOS();  //means "play to end"

-        return;

-    }

-

-    if ((m_pCurr != 0) && m_pCurr->EOS())

-    {

-        m_pStop = m_pTrack->GetEOS();

-        return;

-    }

-

-    __int64 tCurr_ns;

-

-    if (m_pCurr == 0)  //lazy init

-        tCurr_ns = 0;  //nanoseconds

-    else

-    {

-        const Block* const pBlock = m_pCurr->GetBlock();

-

-        tCurr_ns = pBlock->GetTime(m_pCurr->GetCluster());

-        assert(tCurr_ns >= 0);

-    }

-

-    //const Cluster* const pFirst = pSegment->GetFirst();

-    //const Cluster* const pCurrCluster = m_pBase ? m_pBase : pFirst;

-    //pCurrCluster;

-    //assert(pCurrCluster);

-    //assert(!pCurrCluster->EOS());

-    //assert(tCurr_ns >= pCurrCluster->GetTime());

-

-    //const __int64 duration_ns = pSegment->GetDuration();

-    //assert(duration_ns >= 0);

-

-    const __int64 stoppos_ns = stoppos_reftime * 100;

-    __int64 tStop_ns;

-

-    switch (dwStopPos)

-    {

-        default:

-            assert(false);

-            return;

-

-        case AM_SEEKING_AbsolutePositioning:

-        {

-            tStop_ns = stoppos_reftime;

-            break;

-        }

-        case AM_SEEKING_RelativePositioning:

-        {

-            if ((m_pStop == 0) || m_pStop->EOS())

-            {

-                const __int64 duration_ns = pSegment->GetDuration();

-

-                if (duration_ns <= 0)  //don't have a duration

-                {

-                    m_pStop = m_pTrack->GetEOS();  //means "play to end"

-                    return;

-                }

-

-                tStop_ns = duration_ns + stoppos_ns;

-            }

-            else

-            {

-                const Block* const pBlock = m_pStop->GetBlock();

-                assert(pBlock);

-

-                tStop_ns = pBlock->GetTime(m_pStop->GetCluster()) + stoppos_ns;

-            }

-

-            break;

-        }

-        case AM_SEEKING_IncrementalPositioning:

-        {

-            if (stoppos_reftime <= 0)

-            {

-                m_pStop = m_pCurr;

-                return;

-            }

-

-            tStop_ns = tCurr_ns + stoppos_ns;

-            break;

-        }

-    }

-

-    if (tStop_ns <= tCurr_ns)

-    {

-        m_pStop = m_pCurr;

-        return;

-    }

-

-    //if (tStop_ns >= duration_ns)

-    //{

-    //    m_pStop = m_pTrack->GetEOS();

-    //    return;

-    //}

-

-    //TODO: here we find a stop block whose time is aligned with

-    //a cluster time.  We should really do better here, and find

-    //the exact block that corresponds to the requested time.

-

-    const Cluster* pStopCluster = pSegment->FindCluster(tStop_ns);

-    assert(pStopCluster);

-

-    if (pStopCluster == m_pCurr->GetCluster())

-        pStopCluster = pSegment->GetNext(pStopCluster);

-

-    m_pStop = pStopCluster->GetEntry(m_pTrack);

-    assert((m_pStop == 0) ||

-           m_pStop->EOS() ||

-           (m_pStop->GetBlock()->GetTime(m_pStop->GetCluster()) >= tCurr_ns));

-}

-

-

-void Stream::SetStopPositionEOS()

-{

-    m_pStop = m_pTrack->GetEOS();

-}

-

-

-#if 0

-HRESULT Stream::Preload()

-{

-    Segment* const pSegment = m_pTrack->m_pSegment;

-

-    const long status = pSegment->LoadCluster();

-

-    if (status < 0)  //error

-        return E_FAIL;

-

-    return S_OK;

-}

-#endif

-

-

-HRESULT Stream::InitCurr()

-{

-    if (m_pCurr)

-        return S_OK;

-

-    //lazy-init of first block

-

-    Segment* const pSegment = m_pTrack->m_pSegment;

-

-    if (pSegment->GetCount() <= 0)

-        return VFW_E_BUFFER_UNDERFLOW;

-

-    const mkvparser::BlockEntry* pCurr;

-

-    const long status = m_pTrack->GetFirst(pCurr);

-

-    if (status == E_BUFFER_NOT_FULL)

-        return VFW_E_BUFFER_UNDERFLOW;

-

-    assert(status >= 0);  //success

-    assert(pCurr);

-    assert(pCurr->EOS() ||

-           (m_pTrack->GetType() == 2) ||

-           pCurr->GetBlock()->IsKey());

-

-    SetCurr(pCurr);

-

-    const Cluster* const pBase = pSegment->GetFirst();

-    assert(pBase);

-    assert(!pBase->EOS());

-

-    m_base_time_ns = pBase->GetFirstTime();

-    //assert(m_base_time_ns >= 0);

-

-#ifdef _DEBUG

-    if (!m_pCurr->EOS())

-    {

-        const Block* const pBlock = m_pCurr->GetBlock();

-

-        const LONGLONG time_ns = pBlock->GetTime(m_pCurr->GetCluster());

-

-        const LONGLONG dt_ns = time_ns - m_base_time_ns;

-        assert(dt_ns >= 0);

-

-        const double dt_sec = double(dt_ns) / 1000000000;

-        assert(dt_sec >= 0);

-    }

-#endif

-

-    return S_OK;

-}

-

-

-HRESULT Stream::UpdateAllocatorProperties(

-    ALLOCATOR_PROPERTIES& props) const

-{

-    const long cBuffers = GetBufferCount();

-

-    if (props.cBuffers <= cBuffers)  //to handle laced frames

-        props.cBuffers = cBuffers;

-

-    const long cbBuffer = GetBufferSize();

-

-    if (props.cbBuffer < cbBuffer)

-        props.cbBuffer = cbBuffer;

-

-    if (props.cbAlign <= 0)

-        props.cbAlign = 1;

-

-    if (props.cbPrefix < 0)

-        props.cbPrefix = 0;

-

-    return S_OK;

-}

-

-

-void Stream::Clear(samples_t& samples)

-{

-    while (!samples.empty())

-    {

-        IMediaSample* const p = samples.back();

-        assert(p);

-

-        samples.pop_back();

-

-        p->Release();

-    }

-}

-

-

-HRESULT Stream::GetSampleCount(long& count)

-{

-    count = 0;

-

-    HRESULT hr = InitCurr();

-

-    if (FAILED(hr))

-        return hr;

-

-    if (m_pStop == 0)  //TODO: this test might not be req'd

-    {

-        if (m_pCurr->EOS())

-            return S_FALSE;  //send EOS downstream

-    }

-    else if (m_pCurr == m_pStop)

-    {

-        return S_FALSE;  //EOS

-    }

-

-    const Block* const pCurrBlock = m_pCurr->GetBlock();

-    assert(pCurrBlock);

-    assert(pCurrBlock->GetTrackNumber() == m_pTrack->GetNumber());

-

-    count = pCurrBlock->GetFrameCount();

-    assert(count <= GetBufferCount());

-

-    return S_OK;

-}

-

-

-HRESULT Stream::PopulateSamples(const samples_t& samples)

-{

-    //if (SendPreroll(pSample))

-    //    return S_OK;

-

-    HRESULT hr = InitCurr();

-

-    if (FAILED(hr))

-        return hr;

-

-    if (m_pStop == 0)  //TODO: this test might not be req'd

-    {

-        if (m_pCurr->EOS())

-            return S_FALSE;  //send EOS downstream

-    }

-    else if (m_pCurr == m_pStop)

-    {

-        return S_FALSE;  //EOS

-    }

-

-    assert(!m_pCurr->EOS());

-

-    const BlockEntry* pNext;

-    const long status = m_pTrack->GetNext(m_pCurr, pNext);

-

-    if (status == E_BUFFER_NOT_FULL)

-        return VFW_E_BUFFER_UNDERFLOW;

-

-    assert(status >= 0);  //success

-    assert(pNext);

-

-    const Block* const pCurrBlock = m_pCurr->GetBlock();

-

-    const Cluster* const pCurrCluster = m_pCurr->GetCluster();

-    assert(pCurrCluster);

-

-    const __int64 start_ns = pCurrBlock->GetTime(pCurrCluster);

-

-    if (start_ns < 0)

-    {

-        SetCurr(pNext);  //throw curr block away

-        return 2;  //no samples, but not EOS either

-    }

-

-    const LONGLONG base_ns = m_base_time_ns;

-    //assert(base_ns >= 0);

-

-    if (start_ns < base_ns)

-    {

-        SetCurr(pNext);  //throw curr block away

-        return 2;  //no samples, but not EOS either

-    }

-

-    const int nFrames = pCurrBlock->GetFrameCount();

-

-    if (nFrames <= 0)   //should never happen

-    {

-        SetCurr(pNext);  //throw curr block away

-        return 2;  //no samples, but not EOS either

-    }

-

-    if (samples.size() != samples_t::size_type(nFrames))

-        return 2;   //try again

-

-    OnPopulateSample(pNext, samples);

-

-    hr = SetCurr(pNext);

-    m_bDiscontinuity = false;

-

-    return hr;

-}

-

-

-//bool Stream::SendPreroll(IMediaSample*)

-//{

-//    return false;

-//}

-

-

-ULONG Stream::GetClusterCount() const

-{

-    return m_pTrack->m_pSegment->GetCount();

-}

-

-

-HRESULT Stream::SetConnectionMediaType(const AM_MEDIA_TYPE&)

-{

-    return S_OK;

-}

-

-

-std::wstring Stream::ConvertFromUTF8(const char* str)

-{

-    const int cch = MultiByteToWideChar(

-                        CP_UTF8,

-                        0,  //TODO: MB_ERR_INVALID_CHARS

-                        str,

-                        -1,  //include NUL terminator in result

-                        0,

-                        0);  //request length

-

-    assert(cch > 0);

-

-    const size_t cb = cch * sizeof(wchar_t);

-    wchar_t* const wstr = (wchar_t*)_malloca(cb);

-

-    const int cch2 = MultiByteToWideChar(

-                        CP_UTF8,

-                        0,  //TODO: MB_ERR_INVALID_CHARS

-                        str,

-                        -1,

-                        wstr,

-                        cch);

-

-    cch2;

-    assert(cch2 > 0);

-    assert(cch2 == cch);

-

-    return wstr;

-}

-

-

-}  //end namespace mkvparser

+// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#include <strmif.h>
+#include "mkvparserstream.h"
+#include "mkvparser.hpp"
+#include "mkvparserstreamreader.h"
+#include <cassert>
+#include <sstream>
+#include <iomanip>
+#include <vfwmsgs.h>
+#ifdef _DEBUG
+#include "odbgstream.h"
+using std::endl;
+#endif
+
+namespace mkvparser
+{
+
+
+Stream::Stream(const Track* pTrack) :
+    m_pTrack(pTrack),
+    m_pLocked(0)
+{
+    Init();
+}
+
+
+Stream::~Stream()
+{
+    SetCurr(0);
+}
+
+
+void Stream::Init()
+{
+    m_base_time_ns = -1;
+    //m_pBase = 0;
+    SetCurr(0);  //lazy init this later
+    m_pStop = m_pTrack->GetEOS();  //means play entire stream
+    m_bDiscontinuity = true;
+}
+
+
+void Stream::Stop()
+{
+    IMkvReader* const pReader_ = m_pTrack->m_pSegment->m_pReader;
+
+    using mkvparser::IStreamReader;
+    IStreamReader* const pReader = static_cast<IStreamReader*>(pReader_);
+
+    pReader->UnlockPages(m_pLocked);
+    m_pLocked = 0;
+}
+
+
+HRESULT Stream::SetCurr(const mkvparser::BlockEntry* pNext)
+{
+    IMkvReader* const pReader_ = m_pTrack->m_pSegment->m_pReader;
+
+    using mkvparser::IStreamReader;
+    IStreamReader* const pReader = static_cast<IStreamReader*>(pReader_);
+
+    m_pCurr = pNext;
+
+    pReader->UnlockPages(m_pLocked);
+    m_pLocked = m_pCurr;
+
+    const HRESULT hr = pReader->LockPages(m_pLocked);
+    assert(SUCCEEDED(hr));
+    return hr;
+}
+
+
+std::wstring Stream::GetId() const
+{
+    std::wostringstream os;
+
+    GetKind(os);  //"Video" or "Audio"
+
+    os << std::setw(3) << std::setfill(L'0') << m_pTrack->GetNumber();
+
+    return os.str();
+}
+
+
+std::wstring Stream::GetName() const
+{
+    const Track* const t = m_pTrack;
+    assert(t);
+
+    if (const char* codecName = t->GetCodecNameAsUTF8())
+        return ConvertFromUTF8(codecName);
+
+    if (const char* name = t->GetNameAsUTF8())
+        return ConvertFromUTF8(name);
+
+    if (LONGLONG tn = t->GetNumber())
+    {
+        std::wostringstream os;
+        os << L"Track" << tn;
+        return os.str();
+    }
+
+    if (const char* codecId = t->GetCodecId())
+    {
+        std::wstring result;
+
+        const char* p = codecId;
+
+        while (*p)
+            result += wchar_t(*p++);  //TODO: is this cast meaningful?
+
+        return result;
+    }
+
+    return GetId();
+}
+
+
+#if 0
+__int64 Stream::GetDuration() const
+{
+    Segment* const pSegment = m_pTrack->m_pSegment;
+    assert(pSegment);
+
+    const __int64 ns = pSegment->GetDuration();  //scaled (nanoseconds)
+    assert(ns >= 0);
+
+    const __int64 d = ns / 100;  //100-ns ticks
+
+    return d;
+}
+#endif
+
+
+#if 0
+HRESULT Stream::GetAvailable(LONGLONG* pLatest) const
+{
+    if (pLatest == 0)
+        return E_POINTER;
+
+    LONGLONG& pos = *pLatest;  //units are current time format
+
+    Segment* const pSegment = m_pTrack->m_pSegment;
+
+    if (pSegment->Unparsed() <= 0)
+        pos = GetDuration();
+    else
+    {
+        const Cluster* const pCluster = pSegment->GetLast();
+
+        if ((pCluster == 0) || pCluster->EOS())
+            pos = 0;
+        else
+        {
+            const __int64 ns = pCluster->GetTime();
+            pos = ns / 100;  //TODO: reftime units are assumed here
+        }
+    }
+
+    return S_OK;
+}
+#endif
+
+
+//__int64 Stream::GetCurrPosition() const
+//{
+//    return GetCurrTime();  //TODO: for now only support reftime units
+//}
+
+
+__int64 Stream::GetCurrTime() const
+{
+    if (m_pCurr == 0)  //NULL means lazy init hasn't happened yet
+        return 0;      //TODO: assumes track starts with t=0
+
+    if (m_pCurr->EOS())
+        return -1;
+
+    const Block* const pBlock = m_pCurr->GetBlock();
+    assert(pBlock);
+
+    const __int64 ns = pBlock->GetTime(m_pCurr->GetCluster());
+    assert(ns >= 0);
+
+    const __int64 reftime = ns / 100;  //100-ns ticks
+
+    return reftime;
+}
+
+
+//__int64 Stream::GetStopPosition() const
+//{
+//    return GetStopTime();  //TODO: for now we only support reftime units
+//}
+
+
+__int64 Stream::GetStopTime() const
+{
+    if (m_pStop == 0)  //interpreted to mean "play to end of stream"
+        return -1;
+
+    if (m_pStop->EOS())
+        return -1;
+
+    const Block* const pBlock = m_pStop->GetBlock();
+    assert(pBlock);
+
+    const __int64 ns = pBlock->GetTime(m_pStop->GetCluster());
+    assert(ns >= 0);
+
+    const __int64 reftime = ns / 100;  //100-ns ticks
+
+    return reftime;
+}
+
+
+LONGLONG Stream::GetSeekTime(
+    LONGLONG currpos_reftime,
+    DWORD dwCurr_) const
+{
+    const DWORD dwCurrPos = dwCurr_ & AM_SEEKING_PositioningBitsMask;
+    assert(dwCurrPos != AM_SEEKING_NoPositioning);  //handled by caller
+
+    Segment* const pSegment = m_pTrack->m_pSegment;
+
+    const __int64 currpos_ns = currpos_reftime * 100;
+    //__int64 tCurr_ns;
+
+    switch (dwCurrPos)
+    {
+        case AM_SEEKING_IncrementalPositioning:  //applies only to stop pos
+        default:
+            assert(false);
+            return 0;
+
+        case AM_SEEKING_AbsolutePositioning:
+            return currpos_ns;
+
+        case AM_SEEKING_RelativePositioning:
+        {
+            if (m_pCurr == 0)  //lazy init
+                return currpos_ns;  //t=0 is assumed here
+
+            else if (m_pCurr->EOS())
+            {
+                const __int64 duration_ns = pSegment->GetDuration();
+
+                if (duration_ns >= 0)  //actually have a duration
+                    return duration_ns + currpos_ns;
+
+                return 0;  //TODO: is there a better value we can return here?
+            }
+            else
+            {
+                const Block* const pBlock = m_pCurr->GetBlock();
+                assert(pBlock);
+
+                return pBlock->GetTime(m_pCurr->GetCluster()) + currpos_ns;
+            }
+        }
+    }
+}
+
+
+void Stream::SetCurrPosition(
+    //const Cluster* pBase,
+    LONGLONG base_time_ns,
+    const BlockEntry* pCurr)
+{
+    //m_pBase = pBase;
+    SetCurr(pCurr);
+    m_base_time_ns = base_time_ns;
+    m_bDiscontinuity = true;
+}
+
+
+void Stream::SetStopPosition(
+    LONGLONG stoppos_reftime,
+    DWORD dwStop_)
+{
+    const DWORD dwStopPos = dwStop_ & AM_SEEKING_PositioningBitsMask;
+    assert(dwStopPos != AM_SEEKING_NoPositioning);  //handled by caller
+
+    Segment* const pSegment = m_pTrack->m_pSegment;
+
+    if (pSegment->GetCount() == 0)
+    {
+        m_pStop = m_pTrack->GetEOS();  //means "play to end"
+        return;
+    }
+
+    if ((m_pCurr != 0) && m_pCurr->EOS())
+    {
+        m_pStop = m_pTrack->GetEOS();
+        return;
+    }
+
+    __int64 tCurr_ns;
+
+    if (m_pCurr == 0)  //lazy init
+        tCurr_ns = 0;  //nanoseconds
+    else
+    {
+        const Block* const pBlock = m_pCurr->GetBlock();
+
+        tCurr_ns = pBlock->GetTime(m_pCurr->GetCluster());
+        assert(tCurr_ns >= 0);
+    }
+
+    //const Cluster* const pFirst = pSegment->GetFirst();
+    //const Cluster* const pCurrCluster = m_pBase ? m_pBase : pFirst;
+    //pCurrCluster;
+    //assert(pCurrCluster);
+    //assert(!pCurrCluster->EOS());
+    //assert(tCurr_ns >= pCurrCluster->GetTime());
+
+    //const __int64 duration_ns = pSegment->GetDuration();
+    //assert(duration_ns >= 0);
+
+    const __int64 stoppos_ns = stoppos_reftime * 100;
+    __int64 tStop_ns;
+
+    switch (dwStopPos)
+    {
+        default:
+            assert(false);
+            return;
+
+        case AM_SEEKING_AbsolutePositioning:
+        {
+            tStop_ns = stoppos_reftime;
+            break;
+        }
+        case AM_SEEKING_RelativePositioning:
+        {
+            if ((m_pStop == 0) || m_pStop->EOS())
+            {
+                const __int64 duration_ns = pSegment->GetDuration();
+
+                if (duration_ns <= 0)  //don't have a duration
+                {
+                    m_pStop = m_pTrack->GetEOS();  //means "play to end"
+                    return;
+                }
+
+                tStop_ns = duration_ns + stoppos_ns;
+            }
+            else
+            {
+                const Block* const pBlock = m_pStop->GetBlock();
+                assert(pBlock);
+
+                tStop_ns = pBlock->GetTime(m_pStop->GetCluster()) + stoppos_ns;
+            }
+
+            break;
+        }
+        case AM_SEEKING_IncrementalPositioning:
+        {
+            if (stoppos_reftime <= 0)
+            {
+                m_pStop = m_pCurr;
+                return;
+            }
+
+            tStop_ns = tCurr_ns + stoppos_ns;
+            break;
+        }
+    }
+
+    if (tStop_ns <= tCurr_ns)
+    {
+        m_pStop = m_pCurr;
+        return;
+    }
+
+    //if (tStop_ns >= duration_ns)
+    //{
+    //    m_pStop = m_pTrack->GetEOS();
+    //    return;
+    //}
+
+    //TODO: here we find a stop block whose time is aligned with
+    //a cluster time.  We should really do better here, and find
+    //the exact block that corresponds to the requested time.
+
+    const Cluster* pStopCluster = pSegment->FindCluster(tStop_ns);
+    assert(pStopCluster);
+
+    if (pStopCluster == m_pCurr->GetCluster())
+        pStopCluster = pSegment->GetNext(pStopCluster);
+
+    m_pStop = pStopCluster->GetEntry(m_pTrack);
+    assert((m_pStop == 0) ||
+           m_pStop->EOS() ||
+           (m_pStop->GetBlock()->GetTime(m_pStop->GetCluster()) >= tCurr_ns));
+}
+
+
+void Stream::SetStopPositionEOS()
+{
+    m_pStop = m_pTrack->GetEOS();
+}
+
+
+#if 0
+HRESULT Stream::Preload()
+{
+    Segment* const pSegment = m_pTrack->m_pSegment;
+
+    const long status = pSegment->LoadCluster();
+
+    if (status < 0)  //error
+        return E_FAIL;
+
+    return S_OK;
+}
+#endif
+
+
+HRESULT Stream::InitCurr()
+{
+    if (m_pCurr)
+        return S_OK;
+
+    //lazy-init of first block
+
+    Segment* const pSegment = m_pTrack->m_pSegment;
+
+    if (pSegment->GetCount() <= 0)
+        return VFW_E_BUFFER_UNDERFLOW;
+
+    const mkvparser::BlockEntry* pCurr;
+
+    const long status = m_pTrack->GetFirst(pCurr);
+
+    if (status == E_BUFFER_NOT_FULL)
+        return VFW_E_BUFFER_UNDERFLOW;
+
+    assert(status >= 0);  //success
+    assert(pCurr);
+    assert(pCurr->EOS() ||
+           (m_pTrack->GetType() == 2) ||
+           pCurr->GetBlock()->IsKey());
+
+    SetCurr(pCurr);
+
+    const Cluster* const pBase = pSegment->GetFirst();
+    assert(pBase);
+    assert(!pBase->EOS());
+
+    m_base_time_ns = pBase->GetFirstTime();
+    //assert(m_base_time_ns >= 0);
+
+#ifdef _DEBUG
+    if (!m_pCurr->EOS())
+    {
+        const Block* const pBlock = m_pCurr->GetBlock();
+
+        const LONGLONG time_ns = pBlock->GetTime(m_pCurr->GetCluster());
+
+        const LONGLONG dt_ns = time_ns - m_base_time_ns;
+        assert(dt_ns >= 0);
+
+        const double dt_sec = double(dt_ns) / 1000000000;
+        assert(dt_sec >= 0);
+    }
+#endif
+
+    return S_OK;
+}
+
+
+HRESULT Stream::UpdateAllocatorProperties(
+    ALLOCATOR_PROPERTIES& props) const
+{
+    const long cBuffers = GetBufferCount();
+
+    if (props.cBuffers <= cBuffers)  //to handle laced frames
+        props.cBuffers = cBuffers;
+
+    const long cbBuffer = GetBufferSize();
+
+    if (props.cbBuffer < cbBuffer)
+        props.cbBuffer = cbBuffer;
+
+    if (props.cbAlign <= 0)
+        props.cbAlign = 1;
+
+    if (props.cbPrefix < 0)
+        props.cbPrefix = 0;
+
+    return S_OK;
+}
+
+
+void Stream::Clear(samples_t& samples)
+{
+    while (!samples.empty())
+    {
+        IMediaSample* const p = samples.back();
+        assert(p);
+
+        samples.pop_back();
+
+        p->Release();
+    }
+}
+
+
+HRESULT Stream::GetSampleCount(long& count)
+{
+    count = 0;
+
+    HRESULT hr = InitCurr();
+
+    if (FAILED(hr))
+        return hr;
+
+    if (m_pStop == 0)  //TODO: this test might not be req'd
+    {
+        if (m_pCurr->EOS())
+            return S_FALSE;  //send EOS downstream
+    }
+    else if (m_pCurr == m_pStop)
+    {
+        return S_FALSE;  //EOS
+    }
+
+    const Block* const pCurrBlock = m_pCurr->GetBlock();
+    assert(pCurrBlock);
+    assert(pCurrBlock->GetTrackNumber() == m_pTrack->GetNumber());
+
+    count = pCurrBlock->GetFrameCount();
+    assert(count <= GetBufferCount());
+
+    return S_OK;
+}
+
+
+HRESULT Stream::PopulateSamples(const samples_t& samples)
+{
+    //if (SendPreroll(pSample))
+    //    return S_OK;
+
+    HRESULT hr = InitCurr();
+
+    if (FAILED(hr))
+        return hr;
+
+    if (m_pStop == 0)  //TODO: this test might not be req'd
+    {
+        if (m_pCurr->EOS())
+            return S_FALSE;  //send EOS downstream
+    }
+    else if (m_pCurr == m_pStop)
+    {
+        return S_FALSE;  //EOS
+    }
+
+    assert(!m_pCurr->EOS());
+
+    const BlockEntry* pNext;
+    const long status = m_pTrack->GetNext(m_pCurr, pNext);
+
+    if (status == E_BUFFER_NOT_FULL)
+        return VFW_E_BUFFER_UNDERFLOW;
+
+    assert(status >= 0);  //success
+    assert(pNext);
+
+    const Block* const pCurrBlock = m_pCurr->GetBlock();
+
+    const Cluster* const pCurrCluster = m_pCurr->GetCluster();
+    assert(pCurrCluster);
+
+    const __int64 start_ns = pCurrBlock->GetTime(pCurrCluster);
+
+    if (start_ns < 0)
+    {
+        SetCurr(pNext);  //throw curr block away
+        return 2;  //no samples, but not EOS either
+    }
+
+    const LONGLONG base_ns = m_base_time_ns;
+    //assert(base_ns >= 0);
+
+    if (start_ns < base_ns)
+    {
+        SetCurr(pNext);  //throw curr block away
+        return 2;  //no samples, but not EOS either
+    }
+
+    const int nFrames = pCurrBlock->GetFrameCount();
+
+    if (nFrames <= 0)   //should never happen
+    {
+        SetCurr(pNext);  //throw curr block away
+        return 2;  //no samples, but not EOS either
+    }
+
+    if (samples.size() != samples_t::size_type(nFrames))
+        return 2;   //try again
+
+    OnPopulateSample(pNext, samples);
+
+    hr = SetCurr(pNext);
+    m_bDiscontinuity = false;
+
+    return hr;
+}
+
+
+//bool Stream::SendPreroll(IMediaSample*)
+//{
+//    return false;
+//}
+
+
+ULONG Stream::GetClusterCount() const
+{
+    return m_pTrack->m_pSegment->GetCount();
+}
+
+
+HRESULT Stream::SetConnectionMediaType(const AM_MEDIA_TYPE&)
+{
+    return S_OK;
+}
+
+
+std::wstring Stream::ConvertFromUTF8(const char* str)
+{
+    const int cch = MultiByteToWideChar(
+                        CP_UTF8,
+                        0,  //TODO: MB_ERR_INVALID_CHARS
+                        str,
+                        -1,  //include NUL terminator in result
+                        0,
+                        0);  //request length
+
+    assert(cch > 0);
+
+    const size_t cb = cch * sizeof(wchar_t);
+    wchar_t* const wstr = (wchar_t*)_malloca(cb);
+
+    const int cch2 = MultiByteToWideChar(
+                        CP_UTF8,
+                        0,  //TODO: MB_ERR_INVALID_CHARS
+                        str,
+                        -1,
+                        wstr,
+                        cch);
+
+    cch2;
+    assert(cch2 > 0);
+    assert(cch2 == cch);
+
+    return wstr;
+}
+
+
+}  //end namespace mkvparser
diff --git a/libmkvparser/mkvparserstream.h b/libmkvparser/mkvparserstream.h
index a38fcce..99052b8 100644
--- a/libmkvparser/mkvparserstream.h
+++ b/libmkvparser/mkvparserstream.h
@@ -1,100 +1,100 @@
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.

-//

-// Use of this source code is governed by a BSD-style license

-// that can be found in the LICENSE file in the root of the source

-// tree. An additional intellectual property rights grant can be found

-// in the file PATENTS.  All contributing project authors may

-// be found in the AUTHORS file in the root of the source tree.

-

-#pragma once

-#include <string>

-#include <iosfwd>

-#include <vector>

-

-class CMediaTypes;

-

-namespace mkvparser

-{

-

-class Track;

-class BlockEntry;

-class Cluster;

-

-class Stream

-{

-    Stream(const Stream&);

-    Stream& operator=(const Stream&);

-

-public:

-    virtual ~Stream();

-    void Init();

-    void Stop();

-

-    std::wstring GetId() const;  //IPin::QueryId

-    std::wstring GetName() const;  //IPin::QueryPinInfo

-    virtual void GetMediaTypes(CMediaTypes&) const = 0;

-    virtual HRESULT QueryAccept(const AM_MEDIA_TYPE*) const = 0;

-

-    virtual HRESULT SetConnectionMediaType(const AM_MEDIA_TYPE&);

-    HRESULT UpdateAllocatorProperties(ALLOCATOR_PROPERTIES&) const;

-

-    //HRESULT Preload();  //exactly one cluster

-

-    HRESULT GetSampleCount(long&);

-

-    typedef std::vector<IMediaSample*> samples_t;

-

-    HRESULT PopulateSamples(const samples_t&);

-    static void Clear(samples_t&);

-

-    //__int64 GetDuration() const;

-    //__int64 GetCurrPosition() const;

-    //__int64 GetStopPosition() const;

-    __int64 GetCurrTime() const;

-    __int64 GetStopTime() const;

-

-    //HRESULT GetAvailable(LONGLONG*) const;

-

-    LONGLONG GetSeekTime(LONGLONG currTime, DWORD dwCurr) const;

-    //convert from reftime to ns

-

-    void SetCurrPosition(

-        //const Cluster*,

-        LONGLONG base_time_ns,

-        const BlockEntry*);

-

-    void SetStopPosition(LONGLONG, DWORD);

-    void SetStopPositionEOS();

-

-    ULONG GetClusterCount() const;

-

-    const Track* const m_pTrack;

-    static std::wstring ConvertFromUTF8(const char*);

-

-protected:

-    explicit Stream(const Track*);

-    bool m_bDiscontinuity;

-    const BlockEntry* m_pCurr;

-    const BlockEntry* m_pStop;

-    //const Cluster* m_pBase;

-    LONGLONG m_base_time_ns;

-

-    virtual std::wostream& GetKind(std::wostream&) const = 0;

-

-    HRESULT InitCurr();

-

-    virtual long GetBufferSize() const = 0;

-    virtual long GetBufferCount() const = 0;

-

-    virtual void OnPopulateSample(

-                const BlockEntry*,

-                const samples_t&) const = 0;

-

-private:

-

-    const BlockEntry* m_pLocked;

-    HRESULT SetCurr(const mkvparser::BlockEntry*);

-

-};

-

-}  //end namespace mkvparser

+// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#pragma once
+#include <string>
+#include <iosfwd>
+#include <vector>
+
+class CMediaTypes;
+
+namespace mkvparser
+{
+
+class Track;
+class BlockEntry;
+class Cluster;
+
+class Stream
+{
+    Stream(const Stream&);
+    Stream& operator=(const Stream&);
+
+public:
+    virtual ~Stream();
+    void Init();
+    void Stop();
+
+    std::wstring GetId() const;  //IPin::QueryId
+    std::wstring GetName() const;  //IPin::QueryPinInfo
+    virtual void GetMediaTypes(CMediaTypes&) const = 0;
+    virtual HRESULT QueryAccept(const AM_MEDIA_TYPE*) const = 0;
+
+    virtual HRESULT SetConnectionMediaType(const AM_MEDIA_TYPE&);
+    HRESULT UpdateAllocatorProperties(ALLOCATOR_PROPERTIES&) const;
+
+    //HRESULT Preload();  //exactly one cluster
+
+    HRESULT GetSampleCount(long&);
+
+    typedef std::vector<IMediaSample*> samples_t;
+
+    HRESULT PopulateSamples(const samples_t&);
+    static void Clear(samples_t&);
+
+    //__int64 GetDuration() const;
+    //__int64 GetCurrPosition() const;
+    //__int64 GetStopPosition() const;
+    __int64 GetCurrTime() const;
+    __int64 GetStopTime() const;
+
+    //HRESULT GetAvailable(LONGLONG*) const;
+
+    LONGLONG GetSeekTime(LONGLONG currTime, DWORD dwCurr) const;
+    //convert from reftime to ns
+
+    void SetCurrPosition(
+        //const Cluster*,
+        LONGLONG base_time_ns,
+        const BlockEntry*);
+
+    void SetStopPosition(LONGLONG, DWORD);
+    void SetStopPositionEOS();
+
+    ULONG GetClusterCount() const;
+
+    const Track* const m_pTrack;
+    static std::wstring ConvertFromUTF8(const char*);
+
+protected:
+    explicit Stream(const Track*);
+    bool m_bDiscontinuity;
+    const BlockEntry* m_pCurr;
+    const BlockEntry* m_pStop;
+    //const Cluster* m_pBase;
+    LONGLONG m_base_time_ns;
+
+    virtual std::wostream& GetKind(std::wostream&) const = 0;
+
+    HRESULT InitCurr();
+
+    virtual long GetBufferSize() const = 0;
+    virtual long GetBufferCount() const = 0;
+
+    virtual void OnPopulateSample(
+                const BlockEntry*,
+                const samples_t&) const = 0;
+
+private:
+
+    const BlockEntry* m_pLocked;
+    HRESULT SetCurr(const mkvparser::BlockEntry*);
+
+};
+
+}  //end namespace mkvparser
diff --git a/libmkvparser/mkvparserstreamaudio.cc b/libmkvparser/mkvparserstreamaudio.cc
index 4d47515..f00d42a 100644
--- a/libmkvparser/mkvparserstreamaudio.cc
+++ b/libmkvparser/mkvparserstreamaudio.cc
@@ -1,904 +1,904 @@
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.

-//

-// Use of this source code is governed by a BSD-style license

-// that can be found in the LICENSE file in the root of the source

-// tree. An additional intellectual property rights grant can be found

-// in the file PATENTS.  All contributing project authors may

-// be found in the AUTHORS file in the root of the source tree.

-

-#include <strmif.h>

-#include "mkvparserstreamaudio.h"

-#include "mkvparser.hpp"

-#include "vorbistypes.h"

-#include "cmediatypes.h"

-#include <cassert>

-#include <limits>

-#include <uuids.h>

-#include <mmreg.h>

-#include <malloc.h>

-#ifdef _DEBUG

-#include "odbgstream.h"

-using std::endl;

-#endif

-

-

-namespace mkvparser

-{

-

-AudioStream* AudioStream::CreateInstance(const AudioTrack* pTrack)

-{

-    assert(pTrack);

-

-    const char* const id = pTrack->GetCodecId();

-    assert(id);  //TODO

-

-    if (_stricmp(id, "A_VORBIS") == 0)

-        __noop;

-    else

-        return 0;  //can't create a stream from this track

-

-    const __int64 channels = pTrack->GetChannels();

-

-    if (channels <= 0)

-        return 0;  //bad track header

-

-    //TODO:

-    //In principle, Vorbis can have multiple audio channels.

-    //We do handle this case in the Media Foundation components,

-    //so we should handle it here in the DirectShow filters too.

-    //END TODO.

-

-    if (channels > 2)  //TODO: handle this case

-        return 0;

-

-    const double rate = pTrack->GetSamplingRate();

-

-    if (rate <= 0)

-        return 0;  //bad track header

-

-    double intrate;

-    const double fracrate = modf(rate, &intrate);

-

-    if (fracrate != 0)

-        return 0;  //bad track header

-

-    //For Vorbis audio, the CodecPrivate part of the WebM track

-    //header contains the 3 Vorbis headers: the identification header,

-    //the comments header, and the setup header.  They are all packed

-    //together as the payload of the CodecPrivate element, using

-    //Vorbis-style lacing.

-

-    size_t cp_size;

-

-    const BYTE* const cp = pTrack->GetCodecPrivate(cp_size);

-

-    if ((cp == 0) || (cp_size == 0))

-        return 0;  //bad track header

-

-    const BYTE* const begin = &cp[0];

-    const BYTE* const end = begin + cp_size;

-

-    const BYTE* p = begin;  //to walk the payload buffer

-

-    if (p >= end)

-        return 0;

-

-    //The first byte in the stream is the number of headers

-    //present.  For Vorbis there must be 3 headers.  This is

-    //Vorbis-style lacing so the count is biased (it can never

-    //have 0 as the value), so 2 is the (biased) count we must

-    //have in order for this track header to be considered valid.

-

-    const BYTE n = *p++;

-

-    if (n != 2)  //biased count value

-        return 0;

-

-    if (p >= end)

-        return 0;

-

-    //Immediately following the (biased) header count value is

-    //the lengths of the individual headers that follow.  The

-    //physical number of lengths present is exactly equal to the

-    //biased count value (here, 2). The length of the last header

-    //is inferred from the difference between the total length

-    //of the buffer and the sum of the lengths of the other headers.

-    //(So the logical number of lengths present does equal the unbiased

-    //count value; here, 3 headers total.)

-

-    //The header lengths are represented in the stream as the

-    //sum of a sequence of bytes; the sequence terminates for

-    //a particular length value when the byte has a value less

-    //then 255.  If the byte value is 255, then this implies that

-    //the header length is at least 255 bytes long and so more bytes

-    //of the sequence follow.  Note that it is valid for a byte in

-    //the sequence to have 0 as its value; this just means that

-    //the length happened to be an exact multiple of 255.

-

-    //The length of the identification header is defined to be

-    //exactly 30 bytes, so its length is represented in the stream

-    //using 1 byte only.

-

-    const ULONG id_len = *p++;

-

-    if (id_len != 30)

-        return 0;

-

-    if (p >= end)

-        return 0;

-

-    //The comment header holds the Ogg metadata for an audio track,

-    //and so in principle it can be any length. Here that means that

-    //the length can be represented in the stream using a sequence

-    //comprising multiple bytes, so to determine the length we must

-    //loop until we find a byte whose value is less than 255.

-

-    ULONG comment_len = 0;

-

-    for (;;)

-    {

-        const BYTE b = *p++;

-

-        if (p >= end)

-            return 0;

-

-        comment_len += b;

-

-        if (b < 255)

-            break;

-    }

-

-    //Each vorbis header begins with a byte having a distinguished

-    //value that specifies what kind of header this is, followed

-    //by the string "vorbis".  Therefore each well-formed header

-    //must be at least 7 bytes long.

-

-    if (comment_len < 7)

-        return 0;

-

-    //We have consumed the sequence of bytes used to represent

-    //the lengths of the individual headers.  What remains in

-    //the stream are the actual headers.  Here we don't particularly

-    //care much about the actual header payload (we defer such

-    //matters to the Vorbis decoder), but we do interrogate the

-    //first 7 bytes of each header to confirm that the headers

-    //have their correct Vorbis header-kind indicators.

-

-    //p points the first header (the ident header)

-

-    const BYTE* const id_hdr = p;

-

-    //The Vorbis ident header has 1 as its kind indicator.

-

-    if (memcmp(id_hdr, "\x01vorbis", 7) != 0)

-        return 0;

-

-    const BYTE* const comment_hdr = id_hdr + id_len;

-

-    //The Vorbis comment header has 3 as its kind indicator.

-

-    if (memcmp(comment_hdr, "\x03vorbis", 7) != 0)

-        return 0;

-

-    const BYTE* const setup_hdr = comment_hdr + comment_len;

-

-    if (setup_hdr >= end)

-        return 0;

-

-    const ptrdiff_t setup_len_ = end - setup_hdr;

-

-    if (setup_len_ <= 0)

-        return 0;

-

-    const DWORD setup_len = static_cast<DWORD>(setup_len_);

-

-    if (setup_len < 7)

-        return 0;

-

-    //The Vorbis setup header has 5 as its kind indicator.

-

-    if (memcmp(setup_hdr, "\x05vorbis", 7) != 0)

-        return 0;

-

-    //We are satisfied that the CodecPrivate value is well-formed,

-    //and so we now create the audio stream for this pin.

-

-    AudioStream* const s = new (std::nothrow) AudioStream(pTrack);

-    assert(s);  //TODO

-

-    return s;

-}

-

-

-AudioStream::AudioStream(const AudioTrack* pTrack) :

-    Stream(pTrack)

-    //m_preroll(0)

-{

-}

-

-

-std::wostream& AudioStream::GetKind(std::wostream& os) const

-{

-    return os << L"Audio";

-}

-

-

-BYTE AudioStream::GetChannels() const

-{

-    const AudioTrack* const pTrack = static_cast<const AudioTrack*>(m_pTrack);

-

-    const __int64 channels = pTrack->GetChannels();

-    assert(channels > 0);

-    assert(channels <= 255);

-

-    const BYTE result = static_cast<BYTE>(channels);

-    return result;

-}

-

-

-ULONG AudioStream::GetSamplesPerSec() const

-{

-    const AudioTrack* const pTrack = static_cast<const AudioTrack*>(m_pTrack);

-

-    const double rate = pTrack->GetSamplingRate();

-    assert(rate > 0);

-

-    double intrate_;

-    const double fracrate = modf(rate, &intrate_);

-    fracrate;

-    assert(fracrate == 0);

-

-    const ULONG result = static_cast<ULONG>(intrate_);

-    return result;

-}

-

-

-BYTE AudioStream::GetBitsPerSample() const

-{

-    const AudioTrack* const pTrack = static_cast<const AudioTrack*>(m_pTrack);

-

-    const __int64 val = pTrack->GetBitDepth();

-

-    if (val <= 0)

-        return 0;

-

-    assert(val < 256);

-    assert((val % 8) == 0);

-

-    const BYTE result = static_cast<BYTE>(val);

-    return result;

-}

-

-

-void AudioStream::GetMediaTypes(CMediaTypes& mtv) const

-{

-    mtv.Clear();

-

-    const char* const id = m_pTrack->GetCodecId();

-    assert(id);

-

-    if (_stricmp(id, "A_VORBIS") == 0)

-        GetVorbisMediaTypes(mtv);

-    else

-        assert(false);

-}

-

-

-void AudioStream::GetVorbisMediaTypes(CMediaTypes& mtv) const

-{

-    size_t cp_size;

-

-    const BYTE* const cp = m_pTrack->GetCodecPrivate(cp_size);

-    assert(cp);

-    assert(cp_size > 0);

-

-    const BYTE* const begin = &cp[0];

-    const BYTE* const end = begin + cp_size;

-

-    const BYTE* p = begin;

-    assert(p < end);

-

-    const BYTE n = *p++;

-    n;

-    assert(n == 2);

-    assert(p < end);

-

-    const ULONG id_len = *p++;

-    assert(id_len == 30);

-    assert(p < end);

-

-    ULONG comment_len = 0;

-

-    for (;;)

-    {

-        const BYTE b = *p++;

-        assert(p < end);

-

-        comment_len += b;

-

-        if (b < 255)

-            break;

-    }

-

-    assert(comment_len >= 7);

-

-    //p points to first header

-

-    const BYTE* const id_hdr = p;

-    id_hdr;

-    assert(memcmp(id_hdr, "\x01vorbis", 7) == 0);

-

-    const BYTE* const comment_hdr = id_hdr + id_len;

-    comment_hdr;

-    assert(memcmp(comment_hdr, "\x03vorbis", 7) == 0);

-

-    const BYTE* const setup_hdr = comment_hdr + comment_len;

-    setup_hdr;

-    assert(setup_hdr < end);

-

-    const ptrdiff_t setup_len_ = end - setup_hdr;

-    assert(setup_len_ > 0);

-

-    const DWORD setup_len = static_cast<DWORD>(setup_len_);

-    assert(setup_len >= 7);

-    assert(memcmp(setup_hdr, "\x05vorbis", 7) == 0);

-

-    const size_t hdr_len = id_len + comment_len + setup_len;

-

-    using VorbisTypes::VORBISFORMAT2;

-

-    const size_t cb = sizeof(VORBISFORMAT2) + hdr_len;

-    BYTE* const pb = (BYTE*)_malloca(cb);

-

-    VORBISFORMAT2& fmt = (VORBISFORMAT2&)(*pb);

-

-    fmt.channels = GetChannels();

-    fmt.samplesPerSec = GetSamplesPerSec();

-    fmt.bitsPerSample = GetBitsPerSample();

-    fmt.headerSize[0] = id_len;

-    fmt.headerSize[1] = comment_len;

-    fmt.headerSize[2] = setup_len;

-

-    assert(p < end);

-    assert(size_t(end - p) == hdr_len);

-

-    BYTE* const dst = pb + sizeof(VORBISFORMAT2);

-    memcpy(dst, p, hdr_len);

-

-    AM_MEDIA_TYPE mt;

-

-    mt.majortype = MEDIATYPE_Audio;

-    mt.subtype = VorbisTypes::MEDIASUBTYPE_Vorbis2;

-    mt.bFixedSizeSamples = FALSE;

-    mt.bTemporalCompression = FALSE;

-    mt.lSampleSize = 0;

-    mt.formattype = VorbisTypes::FORMAT_Vorbis2;

-    mt.pUnk = 0;

-    mt.cbFormat = static_cast<ULONG>(cb);

-    mt.pbFormat = pb;

-

-    mtv.Add(mt);

-

-    //TODO: if we decide source filter should attempt to also

-    //connect to Xiph Ogg Vorbis decoder filter:

-    //mt.majortype = VorbisTypes::MEDIATYPE_OggPacketStream;

-    //mt.subtype = MEDIASUBTYPE_None;

-    //mt.bFixedSizeSamples = FALSE;

-    //mt.bTemporalCompression = FALSE;

-    //mt.lSampleSize = 0;

-    //mt.formattype = VorbisTypes::FORMAT_OggIdentHeader;

-    //mt.pUnk = 0;

-    //mt.cbFormat = id_len;

-    //mt.pbFormat = const_cast<BYTE*>(id_hdr);

-    //

-    //mtv.Add(mt);

-}

-

-

-HRESULT AudioStream::QueryAccept(const AM_MEDIA_TYPE* pmt) const

-{

-    if (pmt == 0)

-        return E_INVALIDARG;

-

-    const AM_MEDIA_TYPE& mt = *pmt;

-

-    if (mt.majortype != MEDIATYPE_Audio)

-        return S_FALSE;

-

-    const char* const id = m_pTrack->GetCodecId();

-    assert(id);

-

-    if (_stricmp(id, "A_VORBIS") == 0)

-    {

-        if (mt.subtype != VorbisTypes::MEDIASUBTYPE_Vorbis2)

-            return S_FALSE;

-

-        return S_OK;

-    }

-

-    return S_FALSE;

-}

-

-

-#if 0  //if we decide to support Xiph Ogg Vorbis decoder filter:

-HRESULT AudioStream::SetConnectionMediaType(const AM_MEDIA_TYPE&)

-{

-    if (mt.majortype == VorbisTypes::MEDIATYPE_OggPacketStream)

-        m_preroll = &AudioStream::SendOggIdentPacket;

-    else

-        m_preroll = &AudioStream::DoNothing;

-

-    return S_OK;

-}

-#endif

-

-

-#if 0

-HRESULT AudioStream::UpdateAllocatorProperties(

-    ALLOCATOR_PROPERTIES& props) const

-{

-    if (props.cBuffers < 50)  //to handle laced audio

-        props.cBuffers = 50;

-

-    const long size = GetBufferSize();

-

-    if (props.cbBuffer < size)

-        props.cbBuffer = size;

-

-    if (props.cbAlign <= 0)

-        props.cbAlign = 1;

-

-    if (props.cbPrefix < 0)

-        props.cbPrefix = 0;

-

-    return S_OK;

-}

-#endif

-

-

-long AudioStream::GetBufferSize() const

-{

-    const AudioTrack* const pTrack = static_cast<const AudioTrack*>(m_pTrack);

-

-    const double rr = pTrack->GetSamplingRate();

-    const long nSamplesPerSec = static_cast<long>(rr);

-

-    const __int64 cc = pTrack->GetChannels();

-    const long nChannels = static_cast<long>(cc);

-

-    const long nBlockAlign = nChannels * 2;  //16-bit PCM

-    const long nAvgBytesPerSec = nBlockAlign * nSamplesPerSec;

-

-    const long size = nAvgBytesPerSec;  //TODO: make a better estimate

-

-    return size;

-}

-

-

-long AudioStream::GetBufferCount() const

-{

-    return 256;

-}

-

-

-void AudioStream::OnPopulateSample(

-    const BlockEntry* pNextEntry,

-    const samples_t& samples) const

-{

-    assert(!samples.empty());

-    //assert(m_pBase);

-    //assert(!m_pBase->EOS());

-    assert(m_pCurr);

-    assert(m_pCurr != m_pStop);

-    assert(!m_pCurr->EOS());

-

-    const Block* const pCurrBlock = m_pCurr->GetBlock();

-    assert(pCurrBlock);

-    assert(pCurrBlock->GetTrackNumber() == m_pTrack->GetNumber());

-

-    const int nFrames = pCurrBlock->GetFrameCount();

-    assert(nFrames > 0);  //checked by caller

-    assert(samples.size() == samples_t::size_type(nFrames));

-

-    const Cluster* const pCurrCluster = m_pCurr->GetCluster();

-    assert(pCurrCluster);

-

-    const __int64 start_ns = pCurrBlock->GetTime(pCurrCluster);

-    assert(start_ns >= 0);

-    //assert((start_ns % 100) == 0);

-

-    const LONGLONG base_ns = m_base_time_ns;

-    //assert(base_ns >= 0);

-    assert(start_ns >= base_ns);

-

-    Segment* const pSegment = m_pTrack->m_pSegment;

-    IMkvReader* const pFile = pSegment->m_pReader;

-

-    __int64 stop_ns;

-

-    if ((pNextEntry == 0) || pNextEntry->EOS())

-    {

-        const LONGLONG duration_ns = pSegment->GetDuration();

-

-        if ((duration_ns >= 0) && (duration_ns > start_ns))

-            stop_ns = duration_ns;

-        else

-        {

-            const LONGLONG ns_per_frame = 10000000;  //10ms

-            stop_ns = start_ns + LONGLONG(nFrames) * ns_per_frame;

-        }

-    }

-    else

-    {

-        const Block* const pNextBlock = pNextEntry->GetBlock();

-        assert(pNextBlock);

-

-        const Cluster* const pNextCluster = pNextEntry->GetCluster();

-

-        stop_ns = pNextBlock->GetTime(pNextCluster);

-        //assert(stop_ns > start_ns);

-

-        if (stop_ns <= start_ns)

-        {

-            const LONGLONG ns_per_frame = 10000000;  //10ms

-            stop_ns = start_ns + LONGLONG(nFrames) * ns_per_frame;

-        }

-    }

-

-    __int64 start_reftime = (start_ns - base_ns) / 100;

-    assert(start_ns >= 0);

-

-    const __int64 block_stop_reftime = (stop_ns - base_ns) / 100;

-    assert(block_stop_reftime > start_reftime);

-

-    const __int64 block_duration = block_stop_reftime - start_reftime;

-    assert(block_duration > 0);

-

-    __int64 frame_duration = block_duration / nFrames;  //reftime units

-

-    if (frame_duration <= 0)  //weird: block duration is very small

-        frame_duration = 1;

-

-    BOOL bDiscontinuity = m_bDiscontinuity ? TRUE : FALSE;

-

-    for (int idx = 0; idx < nFrames; ++idx)

-    {

-        IMediaSample* const pSample = samples[idx];

-

-        const Block::Frame& f = pCurrBlock->GetFrame(idx);

-

-        const LONG srcsize = f.len;

-        assert(srcsize >= 0);

-

-        const long tgtsize = pSample->GetSize();

-        tgtsize;

-        assert(tgtsize >= 0);

-        assert(tgtsize >= srcsize);

-

-        BYTE* ptr;

-

-        HRESULT hr = pSample->GetPointer(&ptr);

-        assert(SUCCEEDED(hr));

-        assert(ptr);

-

-        const long status = f.Read(pFile, ptr);

-        assert(status == 0);  //all bytes were read

-

-        hr = pSample->SetActualDataLength(srcsize);

-

-        hr = pSample->SetPreroll(FALSE);

-        assert(SUCCEEDED(hr));

-

-        hr = pSample->SetMediaType(0);

-        assert(SUCCEEDED(hr));

-

-        hr = pSample->SetDiscontinuity(bDiscontinuity);

-        assert(SUCCEEDED(hr));

-

-        bDiscontinuity = FALSE;

-

-        hr = pSample->SetMediaTime(0, 0);

-        assert(SUCCEEDED(hr));

-

-        hr = pSample->SetSyncPoint(TRUE);

-        assert(SUCCEEDED(hr));

-

-        LONGLONG stop_reftime = start_reftime + frame_duration;

-

-        hr = pSample->SetTime(&start_reftime, &stop_reftime);

-        assert(SUCCEEDED(hr));

-

-        start_reftime = stop_reftime;

-    }

-}

-

-

-#if 0  //if we decide to support Xiph Ogg Vorbis decoder filter

-bool AudioStream::SendPreroll(IMediaSample* pSample)

-{

-    assert(m_preroll);

-    return (this->*m_preroll)(pSample);

-}

-

-

-bool AudioStream::DoNothing(IMediaSample*)

-{

-    return false;

-}

-

-

-bool AudioStream::SendOggIdentPacket(IMediaSample* pSample)

-{

-    assert(pSample);

-

-    const char* const id = m_pTrack->GetCodecId();

-    id;

-    assert(id);

-    assert(_stricmp(id, "A_VORBIS") == 0);

-

-    const bytes_t& cp = m_pTrack->GetCodecPrivate();

-    assert(!cp.empty());

-

-    const ULONG cp_size = static_cast<ULONG>(cp.size());

-    assert(cp_size > 0);

-

-    const BYTE* const begin = &cp[0];

-    const BYTE* const end = begin + cp_size;

-    end;

-

-    const BYTE* p = begin;

-    assert(p < end);

-

-    const BYTE n = *p++;

-    n;

-    assert(n == 2);

-    assert(p < end);

-

-    const ULONG id_len = *p++;  //TODO: don't assume < 255

-    id_len;

-    assert(id_len < 255);

-    assert(id_len > 0);

-    assert(p < end);

-

-    const ULONG comment_len = *p++;  //TODO: don't assume < 255

-    comment_len;

-    assert(comment_len < 255);

-    assert(comment_len > 0);

-    assert(p < end);

-

-    //p points to first header

-

-    const BYTE* const id_hdr = p;

-

-    const long size = pSample->GetSize();

-    size;

-    assert(size >= 0);

-    assert(ULONG(size) >= id_len);

-

-    BYTE* buf;

-

-    HRESULT hr = pSample->GetPointer(&buf);

-    assert(SUCCEEDED(hr));

-    assert(buf);

-

-    memcpy(buf, id_hdr, id_len);

-

-    hr = pSample->SetActualDataLength(id_len);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetPreroll(0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetMediaType(0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetDiscontinuity(TRUE /* m_bDiscontinuity */ );  //TODO

-    assert(SUCCEEDED(hr));

-

-    //TODO

-    //set by caller:

-    //m_bDiscontinuity = false;

-

-    hr = pSample->SetMediaTime(0, 0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetSyncPoint(FALSE);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetTime(0, 0);

-    assert(SUCCEEDED(hr));

-

-    m_preroll = &AudioStream::SendOggCommentPacket;

-

-    return true;  //preroll - don't send payload

-}

-

-

-bool AudioStream::SendOggCommentPacket(IMediaSample* pSample)

-{

-    assert(pSample);

-

-    const char* const id = m_pTrack->GetCodecId();

-    id;

-    assert(id);

-    assert(_stricmp(id, "A_VORBIS") == 0);

-

-    const bytes_t& cp = m_pTrack->GetCodecPrivate();

-    assert(!cp.empty());

-

-    const ULONG cp_size = static_cast<ULONG>(cp.size());

-    assert(cp_size > 0);

-

-    const BYTE* const begin = &cp[0];

-    const BYTE* const end = begin + cp_size;

-    end;

-

-    const BYTE* p = begin;

-    assert(p < end);

-

-    const BYTE n = *p++;

-    n;

-    assert(n == 2);

-    assert(p < end);

-

-    const ULONG id_len = *p++;  //TODO: don't assume < 255

-    assert(id_len < 255);

-    assert(id_len > 0);

-    assert(p < end);

-

-    const ULONG comment_len = *p++;  //TODO: don't assume < 255

-    assert(comment_len < 255);

-    assert(comment_len > 0);

-    assert(p < end);

-

-    //p points to first header

-

-    const BYTE* const id_hdr = p;

-    id_hdr;

-

-    const BYTE* const comment_hdr = id_hdr + id_len;

-    comment_hdr;

-

-    const long size = pSample->GetSize();

-    size;

-    assert(size >= 0);

-    assert(ULONG(size) >= comment_len);

-

-    BYTE* buf;

-

-    HRESULT hr = pSample->GetPointer(&buf);

-    assert(SUCCEEDED(hr));

-    assert(buf);

-

-    memcpy(buf, comment_hdr, comment_len);

-

-    hr = pSample->SetActualDataLength(comment_len);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetPreroll(0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetMediaType(0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetDiscontinuity(TRUE /* m_bDiscontinuity */ );  //TODO

-    assert(SUCCEEDED(hr));

-

-    //TODO

-    //set by caller:

-    //m_bDiscontinuity = false;

-

-    hr = pSample->SetMediaTime(0, 0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetSyncPoint(FALSE);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetTime(0, 0);

-    assert(SUCCEEDED(hr));

-

-    m_preroll = &AudioStream::SendOggSetupPacket;

-

-    return true;  //preroll - don't send payload

-}

-

-

-bool AudioStream::SendOggSetupPacket(IMediaSample* pSample)

-{

-    assert(pSample);

-

-    const char* const id = m_pTrack->GetCodecId();

-    id;

-    assert(id);

-    assert(_stricmp(id, "A_VORBIS") == 0);

-

-    const bytes_t& cp = m_pTrack->GetCodecPrivate();

-    assert(!cp.empty());

-

-    const ULONG cp_size = static_cast<ULONG>(cp.size());

-    assert(cp_size > 0);

-

-    const BYTE* const begin = &cp[0];

-    const BYTE* const end = begin + cp_size;

-

-    const BYTE* p = begin;

-    assert(p < end);

-

-    const BYTE n = *p++;

-    n;

-    assert(n == 2);

-    assert(p < end);

-

-    const ULONG id_len = *p++;  //TODO: don't assume < 255

-    assert(id_len < 255);

-    assert(id_len > 0);

-    assert(p < end);

-

-    const ULONG comment_len = *p++;  //TODO: don't assume < 255

-    assert(comment_len < 255);

-    assert(comment_len > 0);

-    assert(p < end);

-

-    //p points to first header

-

-    const BYTE* const id_hdr = p;

-    id_hdr;

-

-    const BYTE* const comment_hdr = id_hdr + id_len;

-    comment_hdr;

-

-    const BYTE* const setup_hdr = comment_hdr + comment_len;

-    setup_hdr;

-    assert(setup_hdr < end);

-

-    const ptrdiff_t setup_len_ = end - setup_hdr;

-    assert(setup_len_ > 0);

-

-    const ULONG setup_len = static_cast<ULONG>(setup_len_);

-

-    const long size = pSample->GetSize();

-    size;

-    assert(size >= 0);

-    assert(ULONG(size) >= setup_len);

-

-    BYTE* buf;

-

-    HRESULT hr = pSample->GetPointer(&buf);

-    assert(SUCCEEDED(hr));

-    assert(buf);

-

-    memcpy(buf, setup_hdr, setup_len);

-

-    hr = pSample->SetActualDataLength(setup_len);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetPreroll(0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetMediaType(0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetDiscontinuity(TRUE /* m_bDiscontinuity */ );  //TODO

-    assert(SUCCEEDED(hr));

-

-    //TODO

-    //set by caller:

-    //m_bDiscontinuity = false;

-

-    hr = pSample->SetMediaTime(0, 0);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetSyncPoint(FALSE);

-    assert(SUCCEEDED(hr));

-

-    hr = pSample->SetTime(0, 0);

-    assert(SUCCEEDED(hr));

-

-    m_preroll = &AudioStream::DoNothing;

-

-    return true;  //don't send payload

-}

-#endif

-

-

-}  //end namespace mkvparser

+// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#include <strmif.h>
+#include "mkvparserstreamaudio.h"
+#include "mkvparser.hpp"
+#include "vorbistypes.h"
+#include "cmediatypes.h"
+#include <cassert>
+#include <limits>
+#include <uuids.h>
+#include <mmreg.h>
+#include <malloc.h>
+#ifdef _DEBUG
+#include "odbgstream.h"
+using std::endl;
+#endif
+
+
+namespace mkvparser
+{
+
+AudioStream* AudioStream::CreateInstance(const AudioTrack* pTrack)
+{
+    assert(pTrack);
+
+    const char* const id = pTrack->GetCodecId();
+    assert(id);  //TODO
+
+    if (_stricmp(id, "A_VORBIS") == 0)
+        __noop;
+    else
+        return 0;  //can't create a stream from this track
+
+    const __int64 channels = pTrack->GetChannels();
+
+    if (channels <= 0)
+        return 0;  //bad track header
+
+    //TODO:
+    //In principle, Vorbis can have multiple audio channels.
+    //We do handle this case in the Media Foundation components,
+    //so we should handle it here in the DirectShow filters too.
+    //END TODO.
+
+    if (channels > 2)  //TODO: handle this case
+        return 0;
+
+    const double rate = pTrack->GetSamplingRate();
+
+    if (rate <= 0)
+        return 0;  //bad track header
+
+    double intrate;
+    const double fracrate = modf(rate, &intrate);
+
+    if (fracrate != 0)
+        return 0;  //bad track header
+
+    //For Vorbis audio, the CodecPrivate part of the WebM track
+    //header contains the 3 Vorbis headers: the identification header,
+    //the comments header, and the setup header.  They are all packed
+    //together as the payload of the CodecPrivate element, using
+    //Vorbis-style lacing.
+
+    size_t cp_size;
+
+    const BYTE* const cp = pTrack->GetCodecPrivate(cp_size);
+
+    if ((cp == 0) || (cp_size == 0))
+        return 0;  //bad track header
+
+    const BYTE* const begin = &cp[0];
+    const BYTE* const end = begin + cp_size;
+
+    const BYTE* p = begin;  //to walk the payload buffer
+
+    if (p >= end)
+        return 0;
+
+    //The first byte in the stream is the number of headers
+    //present.  For Vorbis there must be 3 headers.  This is
+    //Vorbis-style lacing so the count is biased (it can never
+    //have 0 as the value), so 2 is the (biased) count we must
+    //have in order for this track header to be considered valid.
+
+    const BYTE n = *p++;
+
+    if (n != 2)  //biased count value
+        return 0;
+
+    if (p >= end)
+        return 0;
+
+    //Immediately following the (biased) header count value is
+    //the lengths of the individual headers that follow.  The
+    //physical number of lengths present is exactly equal to the
+    //biased count value (here, 2). The length of the last header
+    //is inferred from the difference between the total length
+    //of the buffer and the sum of the lengths of the other headers.
+    //(So the logical number of lengths present does equal the unbiased
+    //count value; here, 3 headers total.)
+
+    //The header lengths are represented in the stream as the
+    //sum of a sequence of bytes; the sequence terminates for
+    //a particular length value when the byte has a value less
+    //then 255.  If the byte value is 255, then this implies that
+    //the header length is at least 255 bytes long and so more bytes
+    //of the sequence follow.  Note that it is valid for a byte in
+    //the sequence to have 0 as its value; this just means that
+    //the length happened to be an exact multiple of 255.
+
+    //The length of the identification header is defined to be
+    //exactly 30 bytes, so its length is represented in the stream
+    //using 1 byte only.
+
+    const ULONG id_len = *p++;
+
+    if (id_len != 30)
+        return 0;
+
+    if (p >= end)
+        return 0;
+
+    //The comment header holds the Ogg metadata for an audio track,
+    //and so in principle it can be any length. Here that means that
+    //the length can be represented in the stream using a sequence
+    //comprising multiple bytes, so to determine the length we must
+    //loop until we find a byte whose value is less than 255.
+
+    ULONG comment_len = 0;
+
+    for (;;)
+    {
+        const BYTE b = *p++;
+
+        if (p >= end)
+            return 0;
+
+        comment_len += b;
+
+        if (b < 255)
+            break;
+    }
+
+    //Each vorbis header begins with a byte having a distinguished
+    //value that specifies what kind of header this is, followed
+    //by the string "vorbis".  Therefore each well-formed header
+    //must be at least 7 bytes long.
+
+    if (comment_len < 7)
+        return 0;
+
+    //We have consumed the sequence of bytes used to represent
+    //the lengths of the individual headers.  What remains in
+    //the stream are the actual headers.  Here we don't particularly
+    //care much about the actual header payload (we defer such
+    //matters to the Vorbis decoder), but we do interrogate the
+    //first 7 bytes of each header to confirm that the headers
+    //have their correct Vorbis header-kind indicators.
+
+    //p points the first header (the ident header)
+
+    const BYTE* const id_hdr = p;
+
+    //The Vorbis ident header has 1 as its kind indicator.
+
+    if (memcmp(id_hdr, "\x01vorbis", 7) != 0)
+        return 0;
+
+    const BYTE* const comment_hdr = id_hdr + id_len;
+
+    //The Vorbis comment header has 3 as its kind indicator.
+
+    if (memcmp(comment_hdr, "\x03vorbis", 7) != 0)
+        return 0;
+
+    const BYTE* const setup_hdr = comment_hdr + comment_len;
+
+    if (setup_hdr >= end)
+        return 0;
+
+    const ptrdiff_t setup_len_ = end - setup_hdr;
+
+    if (setup_len_ <= 0)
+        return 0;
+
+    const DWORD setup_len = static_cast<DWORD>(setup_len_);
+
+    if (setup_len < 7)
+        return 0;
+
+    //The Vorbis setup header has 5 as its kind indicator.
+
+    if (memcmp(setup_hdr, "\x05vorbis", 7) != 0)
+        return 0;
+
+    //We are satisfied that the CodecPrivate value is well-formed,
+    //and so we now create the audio stream for this pin.
+
+    AudioStream* const s = new (std::nothrow) AudioStream(pTrack);
+    assert(s);  //TODO
+
+    return s;
+}
+
+
+AudioStream::AudioStream(const AudioTrack* pTrack) :
+    Stream(pTrack)
+    //m_preroll(0)
+{
+}
+
+
+std::wostream& AudioStream::GetKind(std::wostream& os) const
+{
+    return os << L"Audio";
+}
+
+
+BYTE AudioStream::GetChannels() const
+{
+    const AudioTrack* const pTrack = static_cast<const AudioTrack*>(m_pTrack);
+
+    const __int64 channels = pTrack->GetChannels();
+    assert(channels > 0);
+    assert(channels <= 255);
+
+    const BYTE result = static_cast<BYTE>(channels);
+    return result;
+}
+
+
+ULONG AudioStream::GetSamplesPerSec() const
+{
+    const AudioTrack* const pTrack = static_cast<const AudioTrack*>(m_pTrack);
+
+    const double rate = pTrack->GetSamplingRate();
+    assert(rate > 0);
+
+    double intrate_;
+    const double fracrate = modf(rate, &intrate_);
+    fracrate;
+    assert(fracrate == 0);
+
+    const ULONG result = static_cast<ULONG>(intrate_);
+    return result;
+}
+
+
+BYTE AudioStream::GetBitsPerSample() const
+{
+    const AudioTrack* const pTrack = static_cast<const AudioTrack*>(m_pTrack);
+
+    const __int64 val = pTrack->GetBitDepth();
+
+    if (val <= 0)
+        return 0;
+
+    assert(val < 256);
+    assert((val % 8) == 0);
+
+    const BYTE result = static_cast<BYTE>(val);
+    return result;
+}
+
+
+void AudioStream::GetMediaTypes(CMediaTypes& mtv) const
+{
+    mtv.Clear();
+
+    const char* const id = m_pTrack->GetCodecId();
+    assert(id);
+
+    if (_stricmp(id, "A_VORBIS") == 0)
+        GetVorbisMediaTypes(mtv);
+    else
+        assert(false);
+}
+
+
+void AudioStream::GetVorbisMediaTypes(CMediaTypes& mtv) const
+{
+    size_t cp_size;
+
+    const BYTE* const cp = m_pTrack->GetCodecPrivate(cp_size);
+    assert(cp);
+    assert(cp_size > 0);
+
+    const BYTE* const begin = &cp[0];
+    const BYTE* const end = begin + cp_size;
+
+    const BYTE* p = begin;
+    assert(p < end);
+
+    const BYTE n = *p++;
+    n;
+    assert(n == 2);
+    assert(p < end);
+
+    const ULONG id_len = *p++;
+    assert(id_len == 30);
+    assert(p < end);
+
+    ULONG comment_len = 0;
+
+    for (;;)
+    {
+        const BYTE b = *p++;
+        assert(p < end);
+
+        comment_len += b;
+
+        if (b < 255)
+            break;
+    }
+
+    assert(comment_len >= 7);
+
+    //p points to first header
+
+    const BYTE* const id_hdr = p;
+    id_hdr;
+    assert(memcmp(id_hdr, "\x01vorbis", 7) == 0);
+
+    const BYTE* const comment_hdr = id_hdr + id_len;
+    comment_hdr;
+    assert(memcmp(comment_hdr, "\x03vorbis", 7) == 0);
+
+    const BYTE* const setup_hdr = comment_hdr + comment_len;
+    setup_hdr;
+    assert(setup_hdr < end);
+
+    const ptrdiff_t setup_len_ = end - setup_hdr;
+    assert(setup_len_ > 0);
+
+    const DWORD setup_len = static_cast<DWORD>(setup_len_);
+    assert(setup_len >= 7);
+    assert(memcmp(setup_hdr, "\x05vorbis", 7) == 0);
+
+    const size_t hdr_len = id_len + comment_len + setup_len;
+
+    using VorbisTypes::VORBISFORMAT2;
+
+    const size_t cb = sizeof(VORBISFORMAT2) + hdr_len;
+    BYTE* const pb = (BYTE*)_malloca(cb);
+
+    VORBISFORMAT2& fmt = (VORBISFORMAT2&)(*pb);
+
+    fmt.channels = GetChannels();
+    fmt.samplesPerSec = GetSamplesPerSec();
+    fmt.bitsPerSample = GetBitsPerSample();
+    fmt.headerSize[0] = id_len;
+    fmt.headerSize[1] = comment_len;
+    fmt.headerSize[2] = setup_len;
+
+    assert(p < end);
+    assert(size_t(end - p) == hdr_len);
+
+    BYTE* const dst = pb + sizeof(VORBISFORMAT2);
+    memcpy(dst, p, hdr_len);
+
+    AM_MEDIA_TYPE mt;
+
+    mt.majortype = MEDIATYPE_Audio;
+    mt.subtype = VorbisTypes::MEDIASUBTYPE_Vorbis2;
+    mt.bFixedSizeSamples = FALSE;
+    mt.bTemporalCompression = FALSE;
+    mt.lSampleSize = 0;
+    mt.formattype = VorbisTypes::FORMAT_Vorbis2;
+    mt.pUnk = 0;
+    mt.cbFormat = static_cast<ULONG>(cb);
+    mt.pbFormat = pb;
+
+    mtv.Add(mt);
+
+    //TODO: if we decide source filter should attempt to also
+    //connect to Xiph Ogg Vorbis decoder filter:
+    //mt.majortype = VorbisTypes::MEDIATYPE_OggPacketStream;
+    //mt.subtype = MEDIASUBTYPE_None;
+    //mt.bFixedSizeSamples = FALSE;
+    //mt.bTemporalCompression = FALSE;
+    //mt.lSampleSize = 0;
+    //mt.formattype = VorbisTypes::FORMAT_OggIdentHeader;
+    //mt.pUnk = 0;
+    //mt.cbFormat = id_len;
+    //mt.pbFormat = const_cast<BYTE*>(id_hdr);
+    //
+    //mtv.Add(mt);
+}
+
+
+HRESULT AudioStream::QueryAccept(const AM_MEDIA_TYPE* pmt) const
+{
+    if (pmt == 0)
+        return E_INVALIDARG;
+
+    const AM_MEDIA_TYPE& mt = *pmt;
+
+    if (mt.majortype != MEDIATYPE_Audio)
+        return S_FALSE;
+
+    const char* const id = m_pTrack->GetCodecId();
+    assert(id);
+
+    if (_stricmp(id, "A_VORBIS") == 0)
+    {
+        if (mt.subtype != VorbisTypes::MEDIASUBTYPE_Vorbis2)
+            return S_FALSE;
+
+        return S_OK;
+    }
+
+    return S_FALSE;
+}
+
+
+#if 0  //if we decide to support Xiph Ogg Vorbis decoder filter:
+HRESULT AudioStream::SetConnectionMediaType(const AM_MEDIA_TYPE&)
+{
+    if (mt.majortype == VorbisTypes::MEDIATYPE_OggPacketStream)
+        m_preroll = &AudioStream::SendOggIdentPacket;
+    else
+        m_preroll = &AudioStream::DoNothing;
+
+    return S_OK;
+}
+#endif
+
+
+#if 0
+HRESULT AudioStream::UpdateAllocatorProperties(
+    ALLOCATOR_PROPERTIES& props) const
+{
+    if (props.cBuffers < 50)  //to handle laced audio
+        props.cBuffers = 50;
+
+    const long size = GetBufferSize();
+
+    if (props.cbBuffer < size)
+        props.cbBuffer = size;
+
+    if (props.cbAlign <= 0)
+        props.cbAlign = 1;
+
+    if (props.cbPrefix < 0)
+        props.cbPrefix = 0;
+
+    return S_OK;
+}
+#endif
+
+
+long AudioStream::GetBufferSize() const
+{
+    const AudioTrack* const pTrack = static_cast<const AudioTrack*>(m_pTrack);
+
+    const double rr = pTrack->GetSamplingRate();
+    const long nSamplesPerSec = static_cast<long>(rr);
+
+    const __int64 cc = pTrack->GetChannels();
+    const long nChannels = static_cast<long>(cc);
+
+    const long nBlockAlign = nChannels * 2;  //16-bit PCM
+    const long nAvgBytesPerSec = nBlockAlign * nSamplesPerSec;
+
+    const long size = nAvgBytesPerSec;  //TODO: make a better estimate
+
+    return size;
+}
+
+
+long AudioStream::GetBufferCount() const
+{
+    return 256;
+}
+
+
+void AudioStream::OnPopulateSample(
+    const BlockEntry* pNextEntry,
+    const samples_t& samples) const
+{
+    assert(!samples.empty());
+    //assert(m_pBase);
+    //assert(!m_pBase->EOS());
+    assert(m_pCurr);
+    assert(m_pCurr != m_pStop);
+    assert(!m_pCurr->EOS());
+
+    const Block* const pCurrBlock = m_pCurr->GetBlock();
+    assert(pCurrBlock);
+    assert(pCurrBlock->GetTrackNumber() == m_pTrack->GetNumber());
+
+    const int nFrames = pCurrBlock->GetFrameCount();
+    assert(nFrames > 0);  //checked by caller
+    assert(samples.size() == samples_t::size_type(nFrames));
+
+    const Cluster* const pCurrCluster = m_pCurr->GetCluster();
+    assert(pCurrCluster);
+
+    const __int64 start_ns = pCurrBlock->GetTime(pCurrCluster);
+    assert(start_ns >= 0);
+    //assert((start_ns % 100) == 0);
+
+    const LONGLONG base_ns = m_base_time_ns;
+    //assert(base_ns >= 0);
+    assert(start_ns >= base_ns);
+
+    Segment* const pSegment = m_pTrack->m_pSegment;
+    IMkvReader* const pFile = pSegment->m_pReader;
+
+    __int64 stop_ns;
+
+    if ((pNextEntry == 0) || pNextEntry->EOS())
+    {
+        const LONGLONG duration_ns = pSegment->GetDuration();
+
+        if ((duration_ns >= 0) && (duration_ns > start_ns))
+            stop_ns = duration_ns;
+        else
+        {
+            const LONGLONG ns_per_frame = 10000000;  //10ms
+            stop_ns = start_ns + LONGLONG(nFrames) * ns_per_frame;
+        }
+    }
+    else
+    {
+        const Block* const pNextBlock = pNextEntry->GetBlock();
+        assert(pNextBlock);
+
+        const Cluster* const pNextCluster = pNextEntry->GetCluster();
+
+        stop_ns = pNextBlock->GetTime(pNextCluster);
+        //assert(stop_ns > start_ns);
+
+        if (stop_ns <= start_ns)
+        {
+            const LONGLONG ns_per_frame = 10000000;  //10ms
+            stop_ns = start_ns + LONGLONG(nFrames) * ns_per_frame;
+        }
+    }
+
+    __int64 start_reftime = (start_ns - base_ns) / 100;
+    assert(start_ns >= 0);
+
+    const __int64 block_stop_reftime = (stop_ns - base_ns) / 100;
+    assert(block_stop_reftime > start_reftime);
+
+    const __int64 block_duration = block_stop_reftime - start_reftime;
+    assert(block_duration > 0);
+
+    __int64 frame_duration = block_duration / nFrames;  //reftime units
+
+    if (frame_duration <= 0)  //weird: block duration is very small
+        frame_duration = 1;
+
+    BOOL bDiscontinuity = m_bDiscontinuity ? TRUE : FALSE;
+
+    for (int idx = 0; idx < nFrames; ++idx)
+    {
+        IMediaSample* const pSample = samples[idx];
+
+        const Block::Frame& f = pCurrBlock->GetFrame(idx);
+
+        const LONG srcsize = f.len;
+        assert(srcsize >= 0);
+
+        const long tgtsize = pSample->GetSize();
+        tgtsize;
+        assert(tgtsize >= 0);
+        assert(tgtsize >= srcsize);
+
+        BYTE* ptr;
+
+        HRESULT hr = pSample->GetPointer(&ptr);
+        assert(SUCCEEDED(hr));
+        assert(ptr);
+
+        const long status = f.Read(pFile, ptr);
+        assert(status == 0);  //all bytes were read
+
+        hr = pSample->SetActualDataLength(srcsize);
+
+        hr = pSample->SetPreroll(FALSE);
+        assert(SUCCEEDED(hr));
+
+        hr = pSample->SetMediaType(0);
+        assert(SUCCEEDED(hr));
+
+        hr = pSample->SetDiscontinuity(bDiscontinuity);
+        assert(SUCCEEDED(hr));
+
+        bDiscontinuity = FALSE;
+
+        hr = pSample->SetMediaTime(0, 0);
+        assert(SUCCEEDED(hr));
+
+        hr = pSample->SetSyncPoint(TRUE);
+        assert(SUCCEEDED(hr));
+
+        LONGLONG stop_reftime = start_reftime + frame_duration;
+
+        hr = pSample->SetTime(&start_reftime, &stop_reftime);
+        assert(SUCCEEDED(hr));
+
+        start_reftime = stop_reftime;
+    }
+}
+
+
+#if 0  //if we decide to support Xiph Ogg Vorbis decoder filter
+bool AudioStream::SendPreroll(IMediaSample* pSample)
+{
+    assert(m_preroll);
+    return (this->*m_preroll)(pSample);
+}
+
+
+bool AudioStream::DoNothing(IMediaSample*)
+{
+    return false;
+}
+
+
+bool AudioStream::SendOggIdentPacket(IMediaSample* pSample)
+{
+    assert(pSample);
+
+    const char* const id = m_pTrack->GetCodecId();
+    id;
+    assert(id);
+    assert(_stricmp(id, "A_VORBIS") == 0);
+
+    const bytes_t& cp = m_pTrack->GetCodecPrivate();
+    assert(!cp.empty());
+
+    const ULONG cp_size = static_cast<ULONG>(cp.size());
+    assert(cp_size > 0);
+
+    const BYTE* const begin = &cp[0];
+    const BYTE* const end = begin + cp_size;
+    end;
+
+    const BYTE* p = begin;
+    assert(p < end);
+
+    const BYTE n = *p++;
+    n;
+    assert(n == 2);
+    assert(p < end);
+
+    const ULONG id_len = *p++;  //TODO: don't assume < 255
+    id_len;
+    assert(id_len < 255);
+    assert(id_len > 0);
+    assert(p < end);
+
+    const ULONG comment_len = *p++;  //TODO: don't assume < 255
+    comment_len;
+    assert(comment_len < 255);
+    assert(comment_len > 0);
+    assert(p < end);
+
+    //p points to first header
+
+    const BYTE* const id_hdr = p;
+
+    const long size = pSample->GetSize();
+    size;
+    assert(size >= 0);
+    assert(ULONG(size) >= id_len);
+
+    BYTE* buf;
+
+    HRESULT hr = pSample->GetPointer(&buf);
+    assert(SUCCEEDED(hr));
+    assert(buf);
+
+    memcpy(buf, id_hdr, id_len);
+
+    hr = pSample->SetActualDataLength(id_len);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetPreroll(0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetMediaType(0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetDiscontinuity(TRUE /* m_bDiscontinuity */ );  //TODO
+    assert(SUCCEEDED(hr));
+
+    //TODO
+    //set by caller:
+    //m_bDiscontinuity = false;
+
+    hr = pSample->SetMediaTime(0, 0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetSyncPoint(FALSE);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetTime(0, 0);
+    assert(SUCCEEDED(hr));
+
+    m_preroll = &AudioStream::SendOggCommentPacket;
+
+    return true;  //preroll - don't send payload
+}
+
+
+bool AudioStream::SendOggCommentPacket(IMediaSample* pSample)
+{
+    assert(pSample);
+
+    const char* const id = m_pTrack->GetCodecId();
+    id;
+    assert(id);
+    assert(_stricmp(id, "A_VORBIS") == 0);
+
+    const bytes_t& cp = m_pTrack->GetCodecPrivate();
+    assert(!cp.empty());
+
+    const ULONG cp_size = static_cast<ULONG>(cp.size());
+    assert(cp_size > 0);
+
+    const BYTE* const begin = &cp[0];
+    const BYTE* const end = begin + cp_size;
+    end;
+
+    const BYTE* p = begin;
+    assert(p < end);
+
+    const BYTE n = *p++;
+    n;
+    assert(n == 2);
+    assert(p < end);
+
+    const ULONG id_len = *p++;  //TODO: don't assume < 255
+    assert(id_len < 255);
+    assert(id_len > 0);
+    assert(p < end);
+
+    const ULONG comment_len = *p++;  //TODO: don't assume < 255
+    assert(comment_len < 255);
+    assert(comment_len > 0);
+    assert(p < end);
+
+    //p points to first header
+
+    const BYTE* const id_hdr = p;
+    id_hdr;
+
+    const BYTE* const comment_hdr = id_hdr + id_len;
+    comment_hdr;
+
+    const long size = pSample->GetSize();
+    size;
+    assert(size >= 0);
+    assert(ULONG(size) >= comment_len);
+
+    BYTE* buf;
+
+    HRESULT hr = pSample->GetPointer(&buf);
+    assert(SUCCEEDED(hr));
+    assert(buf);
+
+    memcpy(buf, comment_hdr, comment_len);
+
+    hr = pSample->SetActualDataLength(comment_len);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetPreroll(0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetMediaType(0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetDiscontinuity(TRUE /* m_bDiscontinuity */ );  //TODO
+    assert(SUCCEEDED(hr));
+
+    //TODO
+    //set by caller:
+    //m_bDiscontinuity = false;
+
+    hr = pSample->SetMediaTime(0, 0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetSyncPoint(FALSE);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetTime(0, 0);
+    assert(SUCCEEDED(hr));
+
+    m_preroll = &AudioStream::SendOggSetupPacket;
+
+    return true;  //preroll - don't send payload
+}
+
+
+bool AudioStream::SendOggSetupPacket(IMediaSample* pSample)
+{
+    assert(pSample);
+
+    const char* const id = m_pTrack->GetCodecId();
+    id;
+    assert(id);
+    assert(_stricmp(id, "A_VORBIS") == 0);
+
+    const bytes_t& cp = m_pTrack->GetCodecPrivate();
+    assert(!cp.empty());
+
+    const ULONG cp_size = static_cast<ULONG>(cp.size());
+    assert(cp_size > 0);
+
+    const BYTE* const begin = &cp[0];
+    const BYTE* const end = begin + cp_size;
+
+    const BYTE* p = begin;
+    assert(p < end);
+
+    const BYTE n = *p++;
+    n;
+    assert(n == 2);
+    assert(p < end);
+
+    const ULONG id_len = *p++;  //TODO: don't assume < 255
+    assert(id_len < 255);
+    assert(id_len > 0);
+    assert(p < end);
+
+    const ULONG comment_len = *p++;  //TODO: don't assume < 255
+    assert(comment_len < 255);
+    assert(comment_len > 0);
+    assert(p < end);
+
+    //p points to first header
+
+    const BYTE* const id_hdr = p;
+    id_hdr;
+
+    const BYTE* const comment_hdr = id_hdr + id_len;
+    comment_hdr;
+
+    const BYTE* const setup_hdr = comment_hdr + comment_len;
+    setup_hdr;
+    assert(setup_hdr < end);
+
+    const ptrdiff_t setup_len_ = end - setup_hdr;
+    assert(setup_len_ > 0);
+
+    const ULONG setup_len = static_cast<ULONG>(setup_len_);
+
+    const long size = pSample->GetSize();
+    size;
+    assert(size >= 0);
+    assert(ULONG(size) >= setup_len);
+
+    BYTE* buf;
+
+    HRESULT hr = pSample->GetPointer(&buf);
+    assert(SUCCEEDED(hr));
+    assert(buf);
+
+    memcpy(buf, setup_hdr, setup_len);
+
+    hr = pSample->SetActualDataLength(setup_len);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetPreroll(0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetMediaType(0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetDiscontinuity(TRUE /* m_bDiscontinuity */ );  //TODO
+    assert(SUCCEEDED(hr));
+
+    //TODO
+    //set by caller:
+    //m_bDiscontinuity = false;
+
+    hr = pSample->SetMediaTime(0, 0);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetSyncPoint(FALSE);
+    assert(SUCCEEDED(hr));
+
+    hr = pSample->SetTime(0, 0);
+    assert(SUCCEEDED(hr));
+
+    m_preroll = &AudioStream::DoNothing;
+
+    return true;  //don't send payload
+}
+#endif
+
+
+}  //end namespace mkvparser
diff --git a/libmkvparser/mkvparserstreamaudio.h b/libmkvparser/mkvparserstreamaudio.h
index 01d04f8..8ce4724 100644
--- a/libmkvparser/mkvparserstreamaudio.h
+++ b/libmkvparser/mkvparserstreamaudio.h
@@ -1,60 +1,60 @@
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.

-//

-// Use of this source code is governed by a BSD-style license

-// that can be found in the LICENSE file in the root of the source

-// tree. An additional intellectual property rights grant can be found

-// in the file PATENTS.  All contributing project authors may

-// be found in the AUTHORS file in the root of the source tree.

-

-#pragma once

-#include "mkvparserstream.h"

-

-namespace mkvparser

-{

-

-class AudioTrack;

-class AudioStream : public Stream

-{

-    explicit AudioStream(const AudioTrack*);

-    AudioStream(const AudioStream&);

-    AudioStream& operator=(const AudioStream&);

-

-public:

-    static AudioStream* CreateInstance(const AudioTrack*);

-

-    void GetMediaTypes(CMediaTypes&) const;

-    HRESULT QueryAccept(const AM_MEDIA_TYPE*) const;

-

-#if 0  //if we decide to support Xiph Ogg Vorbis decoder filter:

-    HRESULT SetConnectionMediaType(const AM_MEDIA_TYPE&);

-#endif

-

-    //HRESULT UpdateAllocatorProperties(ALLOCATOR_PROPERTIES&) const;

-

-protected:

-    std::wostream& GetKind(std::wostream&) const;

-

-    long GetBufferSize() const;

-    long GetBufferCount() const;

-

-    void OnPopulateSample(const BlockEntry*, const samples_t&) const;

-

-    void GetVorbisMediaTypes(CMediaTypes&) const;

-

-#if 0  //if we decide to support Xiph Ogg Vorbis decoder filter:

-    bool SendPreroll(IMediaSample*);

-    bool (AudioStream::*m_preroll)(IMediaSample*);

-    bool DoNothing(IMediaSample*);

-    bool SendOggIdentPacket(IMediaSample*);

-    bool SendOggCommentPacket(IMediaSample*);

-    bool SendOggSetupPacket(IMediaSample*);

-#endif

-

-    BYTE GetChannels() const;

-    ULONG GetSamplesPerSec() const;

-    BYTE GetBitsPerSample() const;

-

-};

-

-

-}  //end namespace mkvparser

+// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#pragma once
+#include "mkvparserstream.h"
+
+namespace mkvparser
+{
+
+class AudioTrack;
+class AudioStream : public Stream
+{
+    explicit AudioStream(const AudioTrack*);
+    AudioStream(const AudioStream&);
+    AudioStream& operator=(const AudioStream&);
+
+public:
+    static AudioStream* CreateInstance(const AudioTrack*);
+
+    void GetMediaTypes(CMediaTypes&) const;
+    HRESULT QueryAccept(const AM_MEDIA_TYPE*) const;
+
+#if 0  //if we decide to support Xiph Ogg Vorbis decoder filter:
+    HRESULT SetConnectionMediaType(const AM_MEDIA_TYPE&);
+#endif
+
+    //HRESULT UpdateAllocatorProperties(ALLOCATOR_PROPERTIES&) const;
+
+protected:
+    std::wostream& GetKind(std::wostream&) const;
+
+    long GetBufferSize() const;
+    long GetBufferCount() const;
+
+    void OnPopulateSample(const BlockEntry*, const samples_t&) const;
+
+    void GetVorbisMediaTypes(CMediaTypes&) const;
+
+#if 0  //if we decide to support Xiph Ogg Vorbis decoder filter:
+    bool SendPreroll(IMediaSample*);
+    bool (AudioStream::*m_preroll)(IMediaSample*);
+    bool DoNothing(IMediaSample*);
+    bool SendOggIdentPacket(IMediaSample*);
+    bool SendOggCommentPacket(IMediaSample*);
+    bool SendOggSetupPacket(IMediaSample*);
+#endif
+
+    BYTE GetChannels() const;
+    ULONG GetSamplesPerSec() const;
+    BYTE GetBitsPerSample() const;
+
+};
+
+
+}  //end namespace mkvparser
diff --git a/libmkvparser/mkvparserstreamreader.cc b/libmkvparser/mkvparserstreamreader.cc
index 38a2f84..48bace5 100644
--- a/libmkvparser/mkvparserstreamreader.cc
+++ b/libmkvparser/mkvparserstreamreader.cc
@@ -1,24 +1,24 @@
-#include <objbase.h>

-#include "mkvparserstreamreader.h"

-

-namespace mkvparser

-{

-

-IStreamReader::IStreamReader()

-{

-}

-

-IStreamReader::~IStreamReader()

-{

-}

-

-HRESULT IStreamReader::LockPages(const BlockEntry*)

-{

-    return S_OK;

-}

-

-void IStreamReader::UnlockPages(const BlockEntry*)

-{

-}

-

-}  //end namespace mkvparser

+#include <objbase.h>
+#include "mkvparserstreamreader.h"
+
+namespace mkvparser
+{
+
+IStreamReader::IStreamReader()
+{
+}
+
+IStreamReader::~IStreamReader()
+{
+}
+
+HRESULT IStreamReader::LockPages(const BlockEntry*)
+{
+    return S_OK;
+}
+
+void IStreamReader::UnlockPages(const BlockEntry*)
+{
+}
+
+}  //end namespace mkvparser
diff --git a/libmkvparser/mkvparserstreamreader.h b/libmkvparser/mkvparserstreamreader.h
index 7eaa1d4..e1f43eb 100644
--- a/libmkvparser/mkvparserstreamreader.h
+++ b/libmkvparser/mkvparserstreamreader.h
@@ -1,22 +1,22 @@
-#pragma once

-#include "mkvparser.hpp"

-

-namespace mkvparser

-{

-    class IStreamReader : public IMkvReader

-    {

-    private:

-        IStreamReader(const IStreamReader&);

-        IStreamReader& operator=(const IStreamReader&);

-

-    protected:

-        IStreamReader();

-        virtual ~IStreamReader();

-

-    public:

-        virtual HRESULT LockPages(const BlockEntry*);

-        virtual void UnlockPages(const BlockEntry*);

-

-    };

-

-}  //end namespace mkvparser

+#pragma once
+#include "mkvparser.hpp"
+
+namespace mkvparser
+{
+    class IStreamReader : public IMkvReader
+    {
+    private:
+        IStreamReader(const IStreamReader&);
+        IStreamReader& operator=(const IStreamReader&);
+
+    protected:
+        IStreamReader();
+        virtual ~IStreamReader();
+
+    public:
+        virtual HRESULT LockPages(const BlockEntry*);
+        virtual void UnlockPages(const BlockEntry*);
+
+    };
+
+}  //end namespace mkvparser
diff --git a/libmkvparser/mkvparserstreamvideo.cc b/libmkvparser/mkvparserstreamvideo.cc
index 15cd51d..6427762 100644
--- a/libmkvparser/mkvparserstreamvideo.cc
+++ b/libmkvparser/mkvparserstreamvideo.cc
@@ -1,476 +1,476 @@
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.

-//

-// Use of this source code is governed by a BSD-style license

-// that can be found in the LICENSE file in the root of the source

-// tree. An additional intellectual property rights grant can be found

-// in the file PATENTS.  All contributing project authors may

-// be found in the AUTHORS file in the root of the source tree.

-

-#include <strmif.h>

-#include "mkvparserstreamvideo.h"

-#include "mkvparser.hpp"

-#include "webmtypes.h"

-#include "graphutil.h"

-#include "cmediatypes.h"

-#include <cassert>

-#include <amvideo.h>

-#include <dvdmedia.h>

-#include <uuids.h>

-#include <limits>

-#ifdef _DEBUG

-#include "odbgstream.h"

-using std::endl;

-#endif

-

-static const char* const s_CodecId_VP8 = "V_VP8";

-static const char* const s_CodecId_VP9 = "V_VP9";

-static const char* const s_CodecId_ON2VP8 = "V_ON2VP8";

-static const char* const s_CodecId_VFW = "V_MS/VFW/FOURCC";

-

-namespace mkvparser

-{

-

-

-VideoStream* VideoStream::CreateInstance(const VideoTrack* pTrack)

-{

-    assert(pTrack);

-

-    const char* const id = pTrack->GetCodecId();

-    assert(id);  //TODO

-

-    if (_stricmp(id, s_CodecId_VP8) == 0)

-        __noop;

-    else if (_stricmp(id, s_CodecId_VP9) == 0)

-        __noop;

-    else if (_stricmp(id, s_CodecId_ON2VP8) == 0)

-        __noop;

-    else if (_stricmp(id, s_CodecId_VFW) == 0)

-        __noop;

-    else

-        return 0;  //can't create a stream from this track

-

-    //TODO: vet settings, etc

-

-    //At least one cluster should have been loaded when we opened

-    //the file.  We search the first cluster for a frame having

-    //this track number, and use that to start from.  If no frame

-    //with this track number is present in first cluster, then

-    //we assume (correctly or incorrectly) that this file doesn't

-    //have any frames from that track at all.

-

-    VideoStream* const s = new (std::nothrow) VideoStream(pTrack);

-    assert(s);  //TODO

-

-    return s;

-}

-

-

-VideoStream::VideoStream(const VideoTrack* pTrack) : Stream(pTrack)

-{

-}

-

-

-std::wostream& VideoStream::GetKind(std::wostream& os) const

-{

-    return os << L"Video";

-}

-

-

-void VideoStream::GetMediaTypes(CMediaTypes& mtv) const

-{

-    mtv.Clear();

-

-    const char* const id = m_pTrack->GetCodecId();

-    assert(id);

-

-    if ((_stricmp(id, s_CodecId_VP8) == 0) ||

-        (_stricmp(id, s_CodecId_ON2VP8) == 0))

-    {

-        GetVpxMediaTypes(WebmTypes::MEDIASUBTYPE_VP80, mtv);

-    }

-    else if (_stricmp(id, s_CodecId_VP9) == 0)

-    {

-        GetVpxMediaTypes(WebmTypes::MEDIASUBTYPE_VP90, mtv);

-    }

-    else if (_stricmp(id, s_CodecId_VFW) == 0)

-    {

-        GetVfwMediaTypes(mtv);

-    }

-}

-

-

-void VideoStream::GetVpxMediaTypes(const GUID& subtype, CMediaTypes& mtv) const

-{

-    AM_MEDIA_TYPE mt;

-

-    VIDEOINFOHEADER vih;

-    BITMAPINFOHEADER& bmih = vih.bmiHeader;

-

-    mt.majortype = MEDIATYPE_Video;

-    mt.subtype = subtype;

-    mt.bFixedSizeSamples = FALSE;

-    mt.bTemporalCompression = TRUE;

-    mt.lSampleSize = 0;

-    mt.formattype = FORMAT_VideoInfo;

-    mt.pUnk = 0;

-    mt.cbFormat = sizeof vih;

-    mt.pbFormat = (BYTE*)&vih;

-

-    SetRectEmpty(&vih.rcSource);  //TODO

-    SetRectEmpty(&vih.rcTarget);

-    vih.dwBitRate = 0;

-    vih.dwBitErrorRate = 0;

-

-    const VideoTrack* const pTrack = static_cast<const VideoTrack*>(m_pTrack);

-

-    const double r = pTrack->GetFrameRate();

-

-    if (r <= 0)

-        vih.AvgTimePerFrame = 0;

-    else

-    {

-        const double tt = 10000000 / r;  //[ticks/sec] / [frames/sec]

-        vih.AvgTimePerFrame = static_cast<__int64>(tt);

-    }

-

-    const __int64 w = pTrack->GetWidth();

-    assert(w > 0);

-    assert(w <= LONG_MAX);

-

-    const __int64 h = pTrack->GetHeight();

-    assert(h > 0);

-    assert(h <= LONG_MAX);

-

-    bmih.biSize = sizeof bmih;

-    bmih.biWidth = static_cast<LONG>(w);

-    bmih.biHeight = static_cast<LONG>(h);

-    bmih.biPlanes = 1;

-    bmih.biBitCount = 0;

-    bmih.biCompression = mt.subtype.Data1;

-    bmih.biSizeImage = 0;

-    bmih.biXPelsPerMeter = 0;

-    bmih.biYPelsPerMeter = 0;

-    bmih.biClrUsed = 0;

-    bmih.biClrImportant = 0;

-

-    mtv.Add(mt);

-}

-

-

-void VideoStream::GetVfwMediaTypes(CMediaTypes& mtv) const

-{

-    size_t cp_size;

-

-    const BYTE* const cp = m_pTrack->GetCodecPrivate(cp_size);

-    assert(cp);

-    assert(cp_size >= sizeof(BITMAPINFOHEADER));

-

-    AM_MEDIA_TYPE mt;

-

-    VIDEOINFOHEADER vih;

-    BITMAPINFOHEADER& bmih = vih.bmiHeader;

-

-    memcpy(&bmih, &cp[0], sizeof bmih);

-    assert(bmih.biSize >= sizeof(BITMAPINFOHEADER));

-

-    mt.majortype = MEDIATYPE_Video;

-    mt.subtype = GraphUtil::FourCCGUID(bmih.biCompression);

-    mt.bFixedSizeSamples = FALSE;

-    mt.bTemporalCompression = TRUE;

-    mt.lSampleSize = 0;

-    mt.formattype = FORMAT_VideoInfo;

-    mt.pUnk = 0;

-    mt.cbFormat = sizeof vih;

-    mt.pbFormat = (BYTE*)&vih;

-

-    SetRectEmpty(&vih.rcSource);  //TODO

-    SetRectEmpty(&vih.rcTarget);

-    vih.dwBitRate = 0;

-    vih.dwBitErrorRate = 0;

-

-    const VideoTrack* const pTrack = static_cast<const VideoTrack*>(m_pTrack);

-

-    const double r = pTrack->GetFrameRate();

-

-    if (r <= 0)

-        vih.AvgTimePerFrame = 0;

-    else

-    {

-        const double tt = 10000000 / r;  //[ticks/sec] / [frames/sec]

-        vih.AvgTimePerFrame = static_cast<__int64>(tt);

-    }

-

-    const __int64 w = pTrack->GetWidth();

-    w;

-    assert(w > 0);

-    assert(w <= LONG_MAX);

-    assert(w == bmih.biWidth);

-

-    const __int64 h = pTrack->GetHeight();

-    h;

-    assert(h > 0);

-    assert(h <= LONG_MAX);

-    assert(h == bmih.biHeight);

-

-    mtv.Add(mt);

-}

-

-

-HRESULT VideoStream::QueryAccept(const AM_MEDIA_TYPE* pmt) const

-{

-    if (pmt == 0)

-        return E_INVALIDARG;

-

-    const AM_MEDIA_TYPE& mt = *pmt;

-

-    if (mt.majortype != MEDIATYPE_Video)

-        return S_FALSE;

-

-    const char* const id = m_pTrack->GetCodecId();

-    assert(id);

-

-    if ((_stricmp(id, s_CodecId_VP8) == 0) ||

-        (_stricmp(id, s_CodecId_ON2VP8) == 0))

-    {

-        if (mt.subtype != WebmTypes::MEDIASUBTYPE_VP80)

-            return S_FALSE;

-

-        //TODO: more vetting here

-

-        return S_OK;

-    }

-

-    if (_stricmp(id, s_CodecId_VP9) == 0)

-    {

-        if (mt.subtype != WebmTypes::MEDIASUBTYPE_VP90)

-            return S_FALSE;

-

-        return S_OK;

-    }

-

-    if (_stricmp(id, s_CodecId_VFW) == 0)

-    {

-        if (!GraphUtil::FourCCGUID::IsFourCC(mt.subtype))

-            return S_FALSE;

-

-        size_t cp_size;

-        const BYTE* const cp = m_pTrack->GetCodecPrivate(cp_size);

-

-        if (cp == 0)

-            return S_FALSE;

-

-        if (cp_size < sizeof(BITMAPINFOHEADER))

-            return S_FALSE;

-

-        BITMAPINFOHEADER bmih;

-

-        memcpy(&bmih, &cp[0], sizeof bmih);

-

-        if (bmih.biSize < sizeof bmih)

-            return S_FALSE;

-

-        //TODO: more vetting here

-

-        const DWORD fcc = mt.subtype.Data1;  //"VP80" or "VP90"

-

-        if (fcc != bmih.biCompression)

-            return S_FALSE;

-

-        if (mt.subtype == WebmTypes::MEDIASUBTYPE_VP80)

-            __noop;

-        else if (mt.subtype == WebmTypes::MEDIASUBTYPE_VP90)

-            __noop;

-        else

-            return S_FALSE;

-

-        return S_OK;

-    }

-

-    return S_FALSE;

-}

-

-

-#if 0

-HRESULT VideoStream::UpdateAllocatorProperties(

-    ALLOCATOR_PROPERTIES& props) const

-{

-    if (props.cBuffers <= cBuffers)  //to handle laced video

-        props.cBuffers = cBuffers;

-

-    const long size = GetBufferSize();

-

-    if (props.cbBuffer < size)

-        props.cbBuffer = size;

-

-    if (props.cbAlign <= 0)

-        props.cbAlign = 1;

-

-    if (props.cbPrefix < 0)

-        props.cbPrefix = 0;

-

-    return S_OK;

-}

-#endif

-

-

-long VideoStream::GetBufferSize() const

-{

-    const VideoTrack* const pTrack = static_cast<const VideoTrack*>(m_pTrack);

-

-    const __int64 w = pTrack->GetWidth();

-    const __int64 h = pTrack->GetHeight();

-

-    //TODO: we can do better here.  VPx is based on YV12, which would waste

-    //less memory than assuming RGB32.

-    const __int64 size_ = w * h * 4;  //RGB32 (worst case)

-    assert(size_ <= LONG_MAX);

-

-    const long size = static_cast<LONG>(size_);

-

-    return size;

-}

-

-

-long VideoStream::GetBufferCount() const

-{

-    return 10;  //?

-}

-

-

-void VideoStream::OnPopulateSample(

-    const BlockEntry* pNextEntry,

-    const samples_t& samples) const

-{

-    assert(!samples.empty());

-    //assert(m_pBase);

-    //assert(!m_pBase->EOS());

-    assert(m_pCurr);

-    assert(m_pCurr != m_pStop);

-    assert(!m_pCurr->EOS());

-

-    const Block* const pCurrBlock = m_pCurr->GetBlock();

-    assert(pCurrBlock);

-    assert(pCurrBlock->GetTrackNumber() == m_pTrack->GetNumber());

-

-    const Cluster* const pCurrCluster = m_pCurr->GetCluster();

-    assert(pCurrCluster);

-

-    assert((m_pStop == 0) ||

-           m_pStop->EOS() ||

-           (m_pStop->GetBlock()->GetTimeCode(m_pStop->GetCluster()) >

-             pCurrBlock->GetTimeCode(pCurrCluster)));

-

-    const int nFrames = pCurrBlock->GetFrameCount();

-    assert(nFrames > 0);  //checked by caller

-    assert(samples.size() == samples_t::size_type(nFrames));

-

-    const LONGLONG base_ns = m_base_time_ns;

-    //assert(base_ns >= 0);

-

-    Segment* const pSegment = m_pTrack->m_pSegment;

-    IMkvReader* const pFile = pSegment->m_pReader;

-

-    const bool bKey = pCurrBlock->IsKey();

-    assert(!m_bDiscontinuity || bKey);

-

-    const bool bInvisible = pCurrBlock->IsInvisible();

-

-    const __int64 start_ns = pCurrBlock->GetTime(pCurrCluster);

-    assert(start_ns >= base_ns);

-    //assert((start_ns % 100) == 0);

-

-    __int64 stop_ns;

-

-    if ((pNextEntry == 0) || pNextEntry->EOS())

-    {

-        //TODO: read duration from block group, if present

-

-        const LONGLONG duration_ns = pSegment->GetDuration();

-

-        if ((duration_ns >= 0) && (duration_ns > start_ns))

-            stop_ns = duration_ns;

-        else

-            stop_ns = start_ns + 1000000;  //add 1ms

-    }

-    else

-    {

-        const Block* const pNextBlock = pNextEntry->GetBlock();

-        assert(pNextBlock);

-

-        const Cluster* const pNextCluster = pNextEntry->GetCluster();

-

-        stop_ns = pNextBlock->GetTime(pNextCluster);

-        assert(stop_ns >= start_ns);

-        //assert((stop_ns % 100) == 0);

-    }

-

-    __int64 start_reftime = (start_ns - base_ns) / 100;

-

-    const __int64 block_stop_reftime = (stop_ns - base_ns) / 100;

-    assert(block_stop_reftime >= start_reftime);

-

-    const __int64 block_duration = block_stop_reftime - start_reftime;

-    assert(block_duration >= 0);

-

-    __int64 frame_duration = block_duration / nFrames;  //reftime units

-

-    if ((nFrames > 1) && (frame_duration <= 0))  //weird: small block duration

-        frame_duration = 1;

-

-    BOOL bDiscontinuity = m_bDiscontinuity ? TRUE : FALSE;

-

-    for (int idx = 0; idx < nFrames; ++idx)

-    {

-        IMediaSample* const pSample = samples[idx];

-

-        const Block::Frame& f = pCurrBlock->GetFrame(idx);

-

-        const LONG srcsize = f.len;

-        assert(srcsize >= 0);

-

-        const long tgtsize = pSample->GetSize();

-        tgtsize;

-        assert(tgtsize >= 0);

-        assert(tgtsize >= srcsize);

-

-        BYTE* ptr;

-

-        HRESULT hr = pSample->GetPointer(&ptr);  //read srcsize bytes

-        assert(SUCCEEDED(hr));

-        assert(ptr);

-

-        const long status = f.Read(pFile, ptr);

-        assert(status == 0);  //all bytes were read

-

-        hr = pSample->SetActualDataLength(srcsize);

-

-        hr = pSample->SetPreroll(bInvisible ? TRUE : FALSE);

-        assert(SUCCEEDED(hr));

-

-        hr = pSample->SetMediaType(0);

-        assert(SUCCEEDED(hr));

-

-        hr = pSample->SetDiscontinuity(bDiscontinuity);

-        assert(SUCCEEDED(hr));

-

-        bDiscontinuity = FALSE;

-

-        hr = pSample->SetMediaTime(0, 0);

-        assert(SUCCEEDED(hr));

-

-        hr = pSample->SetSyncPoint(bKey ? TRUE : FALSE);

-        assert(SUCCEEDED(hr));

-

-        LONGLONG stop_reftime = start_reftime + frame_duration;

-

-        hr = pSample->SetTime(&start_reftime, &stop_reftime);

-        assert(SUCCEEDED(hr));

-

-        start_reftime = stop_reftime;

-    }

-}

-

-

-

-

-}  //end namespace mkvparser

+// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#include <strmif.h>
+#include "mkvparserstreamvideo.h"
+#include "mkvparser.hpp"
+#include "webmtypes.h"
+#include "graphutil.h"
+#include "cmediatypes.h"
+#include <cassert>
+#include <amvideo.h>
+#include <dvdmedia.h>
+#include <uuids.h>
+#include <limits>
+#ifdef _DEBUG
+#include "odbgstream.h"
+using std::endl;
+#endif
+
+static const char* const s_CodecId_VP8 = "V_VP8";
+static const char* const s_CodecId_VP9 = "V_VP9";
+static const char* const s_CodecId_ON2VP8 = "V_ON2VP8";
+static const char* const s_CodecId_VFW = "V_MS/VFW/FOURCC";
+
+namespace mkvparser
+{
+
+
+VideoStream* VideoStream::CreateInstance(const VideoTrack* pTrack)
+{
+    assert(pTrack);
+
+    const char* const id = pTrack->GetCodecId();
+    assert(id);  //TODO
+
+    if (_stricmp(id, s_CodecId_VP8) == 0)
+        __noop;
+    else if (_stricmp(id, s_CodecId_VP9) == 0)
+        __noop;
+    else if (_stricmp(id, s_CodecId_ON2VP8) == 0)
+        __noop;
+    else if (_stricmp(id, s_CodecId_VFW) == 0)
+        __noop;
+    else
+        return 0;  //can't create a stream from this track
+
+    //TODO: vet settings, etc
+
+    //At least one cluster should have been loaded when we opened
+    //the file.  We search the first cluster for a frame having
+    //this track number, and use that to start from.  If no frame
+    //with this track number is present in first cluster, then
+    //we assume (correctly or incorrectly) that this file doesn't
+    //have any frames from that track at all.
+
+    VideoStream* const s = new (std::nothrow) VideoStream(pTrack);
+    assert(s);  //TODO
+
+    return s;
+}
+
+
+VideoStream::VideoStream(const VideoTrack* pTrack) : Stream(pTrack)
+{
+}
+
+
+std::wostream& VideoStream::GetKind(std::wostream& os) const
+{
+    return os << L"Video";
+}
+
+
+void VideoStream::GetMediaTypes(CMediaTypes& mtv) const
+{
+    mtv.Clear();
+
+    const char* const id = m_pTrack->GetCodecId();
+    assert(id);
+
+    if ((_stricmp(id, s_CodecId_VP8) == 0) ||
+        (_stricmp(id, s_CodecId_ON2VP8) == 0))
+    {
+        GetVpxMediaTypes(WebmTypes::MEDIASUBTYPE_VP80, mtv);
+    }
+    else if (_stricmp(id, s_CodecId_VP9) == 0)
+    {
+        GetVpxMediaTypes(WebmTypes::MEDIASUBTYPE_VP90, mtv);
+    }
+    else if (_stricmp(id, s_CodecId_VFW) == 0)
+    {
+        GetVfwMediaTypes(mtv);
+    }
+}
+
+
+void VideoStream::GetVpxMediaTypes(const GUID& subtype, CMediaTypes& mtv) const
+{
+    AM_MEDIA_TYPE mt;
+
+    VIDEOINFOHEADER vih;
+    BITMAPINFOHEADER& bmih = vih.bmiHeader;
+
+    mt.majortype = MEDIATYPE_Video;
+    mt.subtype = subtype;
+    mt.bFixedSizeSamples = FALSE;
+    mt.bTemporalCompression = TRUE;
+    mt.lSampleSize = 0;
+    mt.formattype = FORMAT_VideoInfo;
+    mt.pUnk = 0;
+    mt.cbFormat = sizeof vih;
+    mt.pbFormat = (BYTE*)&vih;
+
+    SetRectEmpty(&vih.rcSource);  //TODO
+    SetRectEmpty(&vih.rcTarget);
+    vih.dwBitRate = 0;
+    vih.dwBitErrorRate = 0;
+
+    const VideoTrack* const pTrack = static_cast<const VideoTrack*>(m_pTrack);
+
+    const double r = pTrack->GetFrameRate();
+
+    if (r <= 0)
+        vih.AvgTimePerFrame = 0;
+    else
+    {
+        const double tt = 10000000 / r;  //[ticks/sec] / [frames/sec]
+        vih.AvgTimePerFrame = static_cast<__int64>(tt);
+    }
+
+    const __int64 w = pTrack->GetWidth();
+    assert(w > 0);
+    assert(w <= LONG_MAX);
+
+    const __int64 h = pTrack->GetHeight();
+    assert(h > 0);
+    assert(h <= LONG_MAX);
+
+    bmih.biSize = sizeof bmih;
+    bmih.biWidth = static_cast<LONG>(w);
+    bmih.biHeight = static_cast<LONG>(h);
+    bmih.biPlanes = 1;
+    bmih.biBitCount = 0;
+    bmih.biCompression = mt.subtype.Data1;
+    bmih.biSizeImage = 0;
+    bmih.biXPelsPerMeter = 0;
+    bmih.biYPelsPerMeter = 0;
+    bmih.biClrUsed = 0;
+    bmih.biClrImportant = 0;
+
+    mtv.Add(mt);
+}
+
+
+void VideoStream::GetVfwMediaTypes(CMediaTypes& mtv) const
+{
+    size_t cp_size;
+
+    const BYTE* const cp = m_pTrack->GetCodecPrivate(cp_size);
+    assert(cp);
+    assert(cp_size >= sizeof(BITMAPINFOHEADER));
+
+    AM_MEDIA_TYPE mt;
+
+    VIDEOINFOHEADER vih;
+    BITMAPINFOHEADER& bmih = vih.bmiHeader;
+
+    memcpy(&bmih, &cp[0], sizeof bmih);
+    assert(bmih.biSize >= sizeof(BITMAPINFOHEADER));
+
+    mt.majortype = MEDIATYPE_Video;
+    mt.subtype = GraphUtil::FourCCGUID(bmih.biCompression);
+    mt.bFixedSizeSamples = FALSE;
+    mt.bTemporalCompression = TRUE;
+    mt.lSampleSize = 0;
+    mt.formattype = FORMAT_VideoInfo;
+    mt.pUnk = 0;
+    mt.cbFormat = sizeof vih;
+    mt.pbFormat = (BYTE*)&vih;
+
+    SetRectEmpty(&vih.rcSource);  //TODO
+    SetRectEmpty(&vih.rcTarget);
+    vih.dwBitRate = 0;
+    vih.dwBitErrorRate = 0;
+
+    const VideoTrack* const pTrack = static_cast<const VideoTrack*>(m_pTrack);
+
+    const double r = pTrack->GetFrameRate();
+
+    if (r <= 0)
+        vih.AvgTimePerFrame = 0;
+    else
+    {
+        const double tt = 10000000 / r;  //[ticks/sec] / [frames/sec]
+        vih.AvgTimePerFrame = static_cast<__int64>(tt);
+    }
+
+    const __int64 w = pTrack->GetWidth();
+    w;
+    assert(w > 0);
+    assert(w <= LONG_MAX);
+    assert(w == bmih.biWidth);
+
+    const __int64 h = pTrack->GetHeight();
+    h;
+    assert(h > 0);
+    assert(h <= LONG_MAX);
+    assert(h == bmih.biHeight);
+
+    mtv.Add(mt);
+}
+
+
+HRESULT VideoStream::QueryAccept(const AM_MEDIA_TYPE* pmt) const
+{
+    if (pmt == 0)
+        return E_INVALIDARG;
+
+    const AM_MEDIA_TYPE& mt = *pmt;
+
+    if (mt.majortype != MEDIATYPE_Video)
+        return S_FALSE;
+
+    const char* const id = m_pTrack->GetCodecId();
+    assert(id);
+
+    if ((_stricmp(id, s_CodecId_VP8) == 0) ||
+        (_stricmp(id, s_CodecId_ON2VP8) == 0))
+    {
+        if (mt.subtype != WebmTypes::MEDIASUBTYPE_VP80)
+            return S_FALSE;
+
+        //TODO: more vetting here
+
+        return S_OK;
+    }
+
+    if (_stricmp(id, s_CodecId_VP9) == 0)
+    {
+        if (mt.subtype != WebmTypes::MEDIASUBTYPE_VP90)
+            return S_FALSE;
+
+        return S_OK;
+    }
+
+    if (_stricmp(id, s_CodecId_VFW) == 0)
+    {
+        if (!GraphUtil::FourCCGUID::IsFourCC(mt.subtype))
+            return S_FALSE;
+
+        size_t cp_size;
+        const BYTE* const cp = m_pTrack->GetCodecPrivate(cp_size);
+
+        if (cp == 0)
+            return S_FALSE;
+
+        if (cp_size < sizeof(BITMAPINFOHEADER))
+            return S_FALSE;
+
+        BITMAPINFOHEADER bmih;
+
+        memcpy(&bmih, &cp[0], sizeof bmih);
+
+        if (bmih.biSize < sizeof bmih)
+            return S_FALSE;
+
+        //TODO: more vetting here
+
+        const DWORD fcc = mt.subtype.Data1;  //"VP80" or "VP90"
+
+        if (fcc != bmih.biCompression)
+            return S_FALSE;
+
+        if (mt.subtype == WebmTypes::MEDIASUBTYPE_VP80)
+            __noop;
+        else if (mt.subtype == WebmTypes::MEDIASUBTYPE_VP90)
+            __noop;
+        else
+            return S_FALSE;
+
+        return S_OK;
+    }
+
+    return S_FALSE;
+}
+
+
+#if 0
+HRESULT VideoStream::UpdateAllocatorProperties(
+    ALLOCATOR_PROPERTIES& props) const
+{
+    if (props.cBuffers <= cBuffers)  //to handle laced video
+        props.cBuffers = cBuffers;
+
+    const long size = GetBufferSize();
+
+    if (props.cbBuffer < size)
+        props.cbBuffer = size;
+
+    if (props.cbAlign <= 0)
+        props.cbAlign = 1;
+
+    if (props.cbPrefix < 0)
+        props.cbPrefix = 0;
+
+    return S_OK;
+}
+#endif
+
+
+long VideoStream::GetBufferSize() const
+{
+    const VideoTrack* const pTrack = static_cast<const VideoTrack*>(m_pTrack);
+
+    const __int64 w = pTrack->GetWidth();
+    const __int64 h = pTrack->GetHeight();
+
+    //TODO: we can do better here.  VPx is based on YV12, which would waste
+    //less memory than assuming RGB32.
+    const __int64 size_ = w * h * 4;  //RGB32 (worst case)
+    assert(size_ <= LONG_MAX);
+
+    const long size = static_cast<LONG>(size_);
+
+    return size;
+}
+
+
+long VideoStream::GetBufferCount() const
+{
+    return 10;  //?
+}
+
+
+void VideoStream::OnPopulateSample(
+    const BlockEntry* pNextEntry,
+    const samples_t& samples) const
+{
+    assert(!samples.empty());
+    //assert(m_pBase);
+    //assert(!m_pBase->EOS());
+    assert(m_pCurr);
+    assert(m_pCurr != m_pStop);
+    assert(!m_pCurr->EOS());
+
+    const Block* const pCurrBlock = m_pCurr->GetBlock();
+    assert(pCurrBlock);
+    assert(pCurrBlock->GetTrackNumber() == m_pTrack->GetNumber());
+
+    const Cluster* const pCurrCluster = m_pCurr->GetCluster();
+    assert(pCurrCluster);
+
+    assert((m_pStop == 0) ||
+           m_pStop->EOS() ||
+           (m_pStop->GetBlock()->GetTimeCode(m_pStop->GetCluster()) >
+             pCurrBlock->GetTimeCode(pCurrCluster)));
+
+    const int nFrames = pCurrBlock->GetFrameCount();
+    assert(nFrames > 0);  //checked by caller
+    assert(samples.size() == samples_t::size_type(nFrames));
+
+    const LONGLONG base_ns = m_base_time_ns;
+    //assert(base_ns >= 0);
+
+    Segment* const pSegment = m_pTrack->m_pSegment;
+    IMkvReader* const pFile = pSegment->m_pReader;
+
+    const bool bKey = pCurrBlock->IsKey();
+    assert(!m_bDiscontinuity || bKey);
+
+    const bool bInvisible = pCurrBlock->IsInvisible();
+
+    const __int64 start_ns = pCurrBlock->GetTime(pCurrCluster);
+    assert(start_ns >= base_ns);
+    //assert((start_ns % 100) == 0);
+
+    __int64 stop_ns;
+
+    if ((pNextEntry == 0) || pNextEntry->EOS())
+    {
+        //TODO: read duration from block group, if present
+
+        const LONGLONG duration_ns = pSegment->GetDuration();
+
+        if ((duration_ns >= 0) && (duration_ns > start_ns))
+            stop_ns = duration_ns;
+        else
+            stop_ns = start_ns + 1000000;  //add 1ms
+    }
+    else
+    {
+        const Block* const pNextBlock = pNextEntry->GetBlock();
+        assert(pNextBlock);
+
+        const Cluster* const pNextCluster = pNextEntry->GetCluster();
+
+        stop_ns = pNextBlock->GetTime(pNextCluster);
+        assert(stop_ns >= start_ns);
+        //assert((stop_ns % 100) == 0);
+    }
+
+    __int64 start_reftime = (start_ns - base_ns) / 100;
+
+    const __int64 block_stop_reftime = (stop_ns - base_ns) / 100;
+    assert(block_stop_reftime >= start_reftime);
+
+    const __int64 block_duration = block_stop_reftime - start_reftime;
+    assert(block_duration >= 0);
+
+    __int64 frame_duration = block_duration / nFrames;  //reftime units
+
+    if ((nFrames > 1) && (frame_duration <= 0))  //weird: small block duration
+        frame_duration = 1;
+
+    BOOL bDiscontinuity = m_bDiscontinuity ? TRUE : FALSE;
+
+    for (int idx = 0; idx < nFrames; ++idx)
+    {
+        IMediaSample* const pSample = samples[idx];
+
+        const Block::Frame& f = pCurrBlock->GetFrame(idx);
+
+        const LONG srcsize = f.len;
+        assert(srcsize >= 0);
+
+        const long tgtsize = pSample->GetSize();
+        tgtsize;
+        assert(tgtsize >= 0);
+        assert(tgtsize >= srcsize);
+
+        BYTE* ptr;
+
+        HRESULT hr = pSample->GetPointer(&ptr);  //read srcsize bytes
+        assert(SUCCEEDED(hr));
+        assert(ptr);
+
+        const long status = f.Read(pFile, ptr);
+        assert(status == 0);  //all bytes were read
+
+        hr = pSample->SetActualDataLength(srcsize);
+
+        hr = pSample->SetPreroll(bInvisible ? TRUE : FALSE);
+        assert(SUCCEEDED(hr));
+
+        hr = pSample->SetMediaType(0);
+        assert(SUCCEEDED(hr));
+
+        hr = pSample->SetDiscontinuity(bDiscontinuity);
+        assert(SUCCEEDED(hr));
+
+        bDiscontinuity = FALSE;
+
+        hr = pSample->SetMediaTime(0, 0);
+        assert(SUCCEEDED(hr));
+
+        hr = pSample->SetSyncPoint(bKey ? TRUE : FALSE);
+        assert(SUCCEEDED(hr));
+
+        LONGLONG stop_reftime = start_reftime + frame_duration;
+
+        hr = pSample->SetTime(&start_reftime, &stop_reftime);
+        assert(SUCCEEDED(hr));
+
+        start_reftime = stop_reftime;
+    }
+}
+
+
+
+
+}  //end namespace mkvparser
diff --git a/libmkvparser/mkvparserstreamvideo.h b/libmkvparser/mkvparserstreamvideo.h
index 2492364..3bc3702 100644
--- a/libmkvparser/mkvparserstreamvideo.h
+++ b/libmkvparser/mkvparserstreamvideo.h
@@ -1,44 +1,44 @@
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.

-//

-// Use of this source code is governed by a BSD-style license

-// that can be found in the LICENSE file in the root of the source

-// tree. An additional intellectual property rights grant can be found

-// in the file PATENTS.  All contributing project authors may

-// be found in the AUTHORS file in the root of the source tree.

-

-#pragma once

-#include "mkvparserstream.h"

-

-namespace mkvparser

-{

-

-class VideoTrack;

-

-class VideoStream : public Stream

-{

-    explicit VideoStream(const VideoTrack*);

-    VideoStream(const VideoStream&);

-    VideoStream& operator=(const VideoStream&);

-

-public:

-    static VideoStream* CreateInstance(const VideoTrack*);

-

-    void GetMediaTypes(CMediaTypes&) const;

-    HRESULT QueryAccept(const AM_MEDIA_TYPE*) const;

-    //HRESULT UpdateAllocatorProperties(ALLOCATOR_PROPERTIES&) const;

-

-protected:

-    std::wostream& GetKind(std::wostream&) const;

-

-    long GetBufferSize() const;

-    long GetBufferCount() const;

-

-    void OnPopulateSample(const BlockEntry*, const samples_t&) const;

-

-    void GetVpxMediaTypes(const GUID& subtype, CMediaTypes&) const;

-    void GetVfwMediaTypes(CMediaTypes&) const;

-

-};

-

-

-}  //end namespace mkvparser

+// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#pragma once
+#include "mkvparserstream.h"
+
+namespace mkvparser
+{
+
+class VideoTrack;
+
+class VideoStream : public Stream
+{
+    explicit VideoStream(const VideoTrack*);
+    VideoStream(const VideoStream&);
+    VideoStream& operator=(const VideoStream&);
+
+public:
+    static VideoStream* CreateInstance(const VideoTrack*);
+
+    void GetMediaTypes(CMediaTypes&) const;
+    HRESULT QueryAccept(const AM_MEDIA_TYPE*) const;
+    //HRESULT UpdateAllocatorProperties(ALLOCATOR_PROPERTIES&) const;
+
+protected:
+    std::wostream& GetKind(std::wostream&) const;
+
+    long GetBufferSize() const;
+    long GetBufferCount() const;
+
+    void OnPopulateSample(const BlockEntry*, const samples_t&) const;
+
+    void GetVpxMediaTypes(const GUID& subtype, CMediaTypes&) const;
+    void GetVfwMediaTypes(CMediaTypes&) const;
+
+};
+
+
+}  //end namespace mkvparser