webmdshow clean up: Fix EoLs (CRLF -> LF) in MF VP8 decoder.

Change-Id: Ifaebca2db98df7b5aa75cf85542696faa892dd6e
diff --git a/mediafoundation/webmmfvp8dec/dllentry.cc b/mediafoundation/webmmfvp8dec/dllentry.cc
index d5cf8b6..d78fd58 100644
--- a/mediafoundation/webmmfvp8dec/dllentry.cc
+++ b/mediafoundation/webmmfvp8dec/dllentry.cc
@@ -1,150 +1,150 @@
-// 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 "cfactory.h"

-#include "comreg.h"

-#include "webmtypes.h"

-#include <mfapi.h>

-#include <cassert>

-#include <comdef.h>

-#include <uuids.h>

-

-HMODULE g_hModule;

-static ULONG s_cLock;

-

-namespace WebmMfVp8DecLib

-{

-

-    HRESULT CreateDecoder(

-            IClassFactory*,

-            IUnknown*,

-            const IID&,

-            void**);

-

-}  //end namespace WebmMfVp8DecLib

-

-static CFactory s_handler_factory(&s_cLock, &WebmMfVp8DecLib::CreateDecoder);

-

-

-BOOL APIENTRY DllMain(

-    HINSTANCE hModule,

-    DWORD  dwReason,

-    LPVOID)

-{

-    switch (dwReason)

-    {

-        case DLL_PROCESS_ATTACH:

-        {

-            g_hModule = hModule;

-            break;

-        }

-        case DLL_THREAD_ATTACH:

-        case DLL_THREAD_DETACH:

-        case DLL_PROCESS_DETACH:

-        default:

-            break;

-    }

-

-    return TRUE;

-}

-

-

-

-STDAPI DllCanUnloadNow()

-{

-    return s_cLock ? S_FALSE : S_OK;

-}

-

-

-STDAPI DllGetClassObject(

-    const CLSID& clsid,

-    const IID& iid,

-    void** ppv)

-{

-    if (clsid == WebmTypes::CLSID_WebmMfVp8Dec)

-        return s_handler_factory.QueryInterface(iid, ppv);

-

-    return CLASS_E_CLASSNOTAVAILABLE;

-}

-

-

-STDAPI DllUnregisterServer()

-{

-    HRESULT hr = MFTUnregister(WebmTypes::CLSID_WebmMfVp8Dec);

-    //assert(SUCCEEDED(hr));  //TODO: dump this it fails

-

-    hr = ComReg::UnRegisterCoclass(WebmTypes::CLSID_WebmMfVp8Dec);

-

-    return hr;

-}

-

-

-STDAPI DllRegisterServer()

-{

-    HRESULT hr = DllUnregisterServer();

-    assert(SUCCEEDED(hr));

-

-    std::wstring filename_;

-

-    hr = ComReg::ComRegGetModuleFileName(g_hModule, filename_);

-    assert(SUCCEEDED(hr));

-    assert(!filename_.empty());

-

-    const wchar_t* const filename = filename_.c_str();

-

-#if _DEBUG

-    const wchar_t friendly_name[] = L"WebM MF VP8 Decoder Transform (Debug)";

-#else

-    const wchar_t friendly_name[] = L"WebM MF VP8 Decoder Transform";

-#endif

-

-    hr = ComReg::RegisterCoclass(

-            WebmTypes::CLSID_WebmMfVp8Dec,

-            friendly_name,

-            filename,

-            L"Webm.MfVp8Dec",  //TODO: do we really need ProgIDs?

-            L"Webm.MfVp8Dec.1",

-            false,  //not insertable

-            false,  //not a control

-            ComReg::kBoth,  //DShow filters must support "both"

-            GUID_NULL,     //typelib

-            0,    //no version specified

-            0);   //no toolbox bitmap

-

-    if (FAILED(hr))

-        return hr;

-

-    enum { cInputTypes = 1 };

-    MFT_REGISTER_TYPE_INFO pInputTypes[cInputTypes] =

-    {

-        { MFMediaType_Video, WebmTypes::MEDIASUBTYPE_VP80 }

-    };

-

-    enum { cOutputTypes = 3 };

-    MFT_REGISTER_TYPE_INFO pOutputTypes[cOutputTypes] =

-    {

-        { MFMediaType_Video, MFVideoFormat_NV12 },

-        { MFMediaType_Video, MFVideoFormat_YV12 },

-        { MFMediaType_Video, MFVideoFormat_IYUV }

-    };

-

-    wchar_t* const friendly_name_ = const_cast<wchar_t*>(friendly_name);

-

-    hr = MFTRegister(

-            WebmTypes::CLSID_WebmMfVp8Dec,

-            MFT_CATEGORY_VIDEO_DECODER,

-            friendly_name_,

-            MFT_ENUM_FLAG_SYNCMFT,  //TODO: for now, just support sync

-            cInputTypes,

-            pInputTypes,

-            cOutputTypes,

-            pOutputTypes,

-            0);  //no attributes

-

-    return hr;

-}

+// 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 "cfactory.h"
+#include "comreg.h"
+#include "webmtypes.h"
+#include <mfapi.h>
+#include <cassert>
+#include <comdef.h>
+#include <uuids.h>
+
+HMODULE g_hModule;
+static ULONG s_cLock;
+
+namespace WebmMfVp8DecLib
+{
+
+    HRESULT CreateDecoder(
+            IClassFactory*,
+            IUnknown*,
+            const IID&,
+            void**);
+
+}  //end namespace WebmMfVp8DecLib
+
+static CFactory s_handler_factory(&s_cLock, &WebmMfVp8DecLib::CreateDecoder);
+
+
+BOOL APIENTRY DllMain(
+    HINSTANCE hModule,
+    DWORD  dwReason,
+    LPVOID)
+{
+    switch (dwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+        {
+            g_hModule = hModule;
+            break;
+        }
+        case DLL_THREAD_ATTACH:
+        case DLL_THREAD_DETACH:
+        case DLL_PROCESS_DETACH:
+        default:
+            break;
+    }
+
+    return TRUE;
+}
+
+
+
+STDAPI DllCanUnloadNow()
+{
+    return s_cLock ? S_FALSE : S_OK;
+}
+
+
+STDAPI DllGetClassObject(
+    const CLSID& clsid,
+    const IID& iid,
+    void** ppv)
+{
+    if (clsid == WebmTypes::CLSID_WebmMfVp8Dec)
+        return s_handler_factory.QueryInterface(iid, ppv);
+
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+
+STDAPI DllUnregisterServer()
+{
+    HRESULT hr = MFTUnregister(WebmTypes::CLSID_WebmMfVp8Dec);
+    //assert(SUCCEEDED(hr));  //TODO: dump this it fails
+
+    hr = ComReg::UnRegisterCoclass(WebmTypes::CLSID_WebmMfVp8Dec);
+
+    return hr;
+}
+
+
+STDAPI DllRegisterServer()
+{
+    HRESULT hr = DllUnregisterServer();
+    assert(SUCCEEDED(hr));
+
+    std::wstring filename_;
+
+    hr = ComReg::ComRegGetModuleFileName(g_hModule, filename_);
+    assert(SUCCEEDED(hr));
+    assert(!filename_.empty());
+
+    const wchar_t* const filename = filename_.c_str();
+
+#if _DEBUG
+    const wchar_t friendly_name[] = L"WebM MF VP8 Decoder Transform (Debug)";
+#else
+    const wchar_t friendly_name[] = L"WebM MF VP8 Decoder Transform";
+#endif
+
+    hr = ComReg::RegisterCoclass(
+            WebmTypes::CLSID_WebmMfVp8Dec,
+            friendly_name,
+            filename,
+            L"Webm.MfVp8Dec",  //TODO: do we really need ProgIDs?
+            L"Webm.MfVp8Dec.1",
+            false,  //not insertable
+            false,  //not a control
+            ComReg::kBoth,  //DShow filters must support "both"
+            GUID_NULL,     //typelib
+            0,    //no version specified
+            0);   //no toolbox bitmap
+
+    if (FAILED(hr))
+        return hr;
+
+    enum { cInputTypes = 1 };
+    MFT_REGISTER_TYPE_INFO pInputTypes[cInputTypes] =
+    {
+        { MFMediaType_Video, WebmTypes::MEDIASUBTYPE_VP80 }
+    };
+
+    enum { cOutputTypes = 3 };
+    MFT_REGISTER_TYPE_INFO pOutputTypes[cOutputTypes] =
+    {
+        { MFMediaType_Video, MFVideoFormat_NV12 },
+        { MFMediaType_Video, MFVideoFormat_YV12 },
+        { MFMediaType_Video, MFVideoFormat_IYUV }
+    };
+
+    wchar_t* const friendly_name_ = const_cast<wchar_t*>(friendly_name);
+
+    hr = MFTRegister(
+            WebmTypes::CLSID_WebmMfVp8Dec,
+            MFT_CATEGORY_VIDEO_DECODER,
+            friendly_name_,
+            MFT_ENUM_FLAG_SYNCMFT,  //TODO: for now, just support sync
+            cInputTypes,
+            pInputTypes,
+            cOutputTypes,
+            pOutputTypes,
+            0);  //no attributes
+
+    return hr;
+}
diff --git a/mediafoundation/webmmfvp8dec/resource.h b/mediafoundation/webmmfvp8dec/resource.h
index aeb74fa..5b870fd 100644
--- a/mediafoundation/webmmfvp8dec/resource.h
+++ b/mediafoundation/webmmfvp8dec/resource.h
@@ -1,15 +1,15 @@
-//{{NO_DEPENDENCIES}}

-// Microsoft Visual C++ generated include file.

-// Used by webmmfvp8dec.rc

-//

-

-// Next default values for new objects

-// 

-#ifdef APSTUDIO_INVOKED

-#ifndef APSTUDIO_READONLY_SYMBOLS

-#define _APS_NEXT_RESOURCE_VALUE        101

-#define _APS_NEXT_COMMAND_VALUE         40001

-#define _APS_NEXT_CONTROL_VALUE         1001

-#define _APS_NEXT_SYMED_VALUE           101

-#endif

-#endif

+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by webmmfvp8dec.rc
+//
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/mediafoundation/webmmfvp8dec/webmmfvp8dec.cc b/mediafoundation/webmmfvp8dec/webmmfvp8dec.cc
index 9db1253..a06ebb4 100644
--- a/mediafoundation/webmmfvp8dec/webmmfvp8dec.cc
+++ b/mediafoundation/webmmfvp8dec/webmmfvp8dec.cc
@@ -1,2397 +1,2397 @@
-#pragma warning(disable:4505)  //unreferenced local function removed

-#include "clockable.h"

-#include <mfidl.h>

-#include "vpx/vpx_decoder.h"

-#include "vpx/vp8dx.h"

-#include "webmmfvp8dec.h"

-#include "webmtypes.h"

-#include <mfapi.h>

-#include <mferror.h>

-#include <comdef.h>

-#include <cassert>

-#include <new>

-#ifdef _DEBUG

-#include "odbgstream.h"

-#include "iidstr.h"

-using std::endl;

-using std::boolalpha;

-#endif

-

-_COM_SMARTPTR_TYPEDEF(IMFMediaBuffer, __uuidof(IMFMediaBuffer));

-_COM_SMARTPTR_TYPEDEF(IMF2DBuffer, __uuidof(IMF2DBuffer));

-

-

-namespace WebmMfVp8DecLib

-{

-

-

-HRESULT CreateDecoder(

-    IClassFactory* pClassFactory,

-    IUnknown* pOuter,

-    const IID& iid,

-    void** ppv)

-{

-    if (ppv == 0)

-        return E_POINTER;

-

-    *ppv = 0;

-

-    if (pOuter)

-        return CLASS_E_NOAGGREGATION;

-

-    WebmMfVp8Dec* const p = new (std::nothrow) WebmMfVp8Dec(pClassFactory);

-

-    if (p == 0)

-        return E_OUTOFMEMORY;

-

-    IMFTransform* const pUnk = p;

-

-    const HRESULT hr = pUnk->QueryInterface(iid, ppv);

-

-    const ULONG cRef = pUnk->Release();

-    cRef;

-

-    return hr;

-}

-

-

-WebmMfVp8Dec::WebmMfVp8Dec(IClassFactory* pClassFactory) :

-    m_pClassFactory(pClassFactory),

-    m_cRef(1),

-    m_pInputMediaType(0),

-    m_pOutputMediaType(0),

-    m_rate(1),

-    m_bThin(FALSE),

-    m_drop_mode(MF_DROP_MODE_NONE),

-    m_drop_budget(0),

-    m_lag_sum(0),

-    m_lag_count(0),

-    m_lag_frames(0),

-    m_frame_rate(-1)

-{

-    HRESULT hr = m_pClassFactory->LockServer(TRUE);

-    assert(SUCCEEDED(hr));

-

-    hr = CLockable::Init();

-    assert(SUCCEEDED(hr));

-

-    //m_frame_rate.Init();

-}

-

-

-WebmMfVp8Dec::~WebmMfVp8Dec()

-{

-    if (m_pInputMediaType)

-    {

-        const ULONG n = m_pInputMediaType->Release();

-        n;

-        assert(n == 0);

-

-        m_pInputMediaType = 0;

-

-        const vpx_codec_err_t e = vpx_codec_destroy(&m_ctx);

-        e;

-        assert(e == VPX_CODEC_OK);

-    }

-

-    if (m_pOutputMediaType)

-    {

-        const ULONG n = m_pOutputMediaType->Release();

-        n;

-        assert(n == 0);

-

-        m_pOutputMediaType = 0;

-    }

-

-    Flush();

-

-    HRESULT hr = m_pClassFactory->LockServer(FALSE);

-    assert(SUCCEEDED(hr));

-}

-

-

-HRESULT WebmMfVp8Dec::QueryInterface(

-    const IID& iid,

-    void** ppv)

-{

-    if (ppv == 0)

-        return E_POINTER;

-

-    IUnknown*& pUnk = reinterpret_cast<IUnknown*&>(*ppv);

-

-    if (iid == __uuidof(IUnknown))

-    {

-        pUnk = static_cast<IMFTransform*>(this);  //must be nondelegating

-    }

-    else if (iid == __uuidof(IMFTransform))

-    {

-        pUnk = static_cast<IMFTransform*>(this);

-    }

-    else if (iid == __uuidof(IMFQualityAdvise2))

-    {

-        pUnk = static_cast<IMFQualityAdvise2*>(this);

-    }

-    else if (iid == __uuidof(IMFQualityAdvise))

-    {

-        pUnk = static_cast<IMFQualityAdvise*>(this);

-    }

-    else if (iid == __uuidof(IMFRateControl))

-    {

-        pUnk = static_cast<IMFRateControl*>(this);

-    }

-    else if (iid == __uuidof(IMFRateSupport))

-    {

-        pUnk = static_cast<IMFRateSupport*>(this);

-    }

-    else if (iid == __uuidof(IMFGetService))

-    {

-        pUnk = static_cast<IMFGetService*>(this);

-    }

-    else

-    {

-//#ifdef _DEBUG

-//        wodbgstream os;

-//        os << "WebmMfVp8Dec::QI: iid=" << IIDStr(iid) << std::endl;

-//#endif

-

-        pUnk = 0;

-        return E_NOINTERFACE;

-    }

-

-    pUnk->AddRef();

-    return S_OK;

-}

-

-

-ULONG WebmMfVp8Dec::AddRef()

-{

-    return InterlockedIncrement(&m_cRef);

-}

-

-

-ULONG WebmMfVp8Dec::Release()

-{

-    if (LONG n = InterlockedDecrement(&m_cRef))

-        return n;

-

-    delete this;

-    return 0;

-}

-

-

-HRESULT WebmMfVp8Dec::GetStreamLimits(

-    DWORD* pdwInputMin,

-    DWORD* pdwInputMax,

-    DWORD* pdwOutputMin,

-    DWORD* pdwOutputMax)

-{

-    if (pdwInputMin == 0)

-        return E_POINTER;

-

-    if (pdwInputMax == 0)

-        return E_POINTER;

-

-    if (pdwOutputMin == 0)

-        return E_POINTER;

-

-    if (pdwOutputMax == 0)

-        return E_POINTER;

-

-    DWORD& dwInputMin = *pdwInputMin;

-    dwInputMin = 1;

-

-    DWORD& dwInputMax = *pdwInputMax;

-    dwInputMax = 1;

-

-    DWORD& dwOutputMin = *pdwOutputMin;

-    dwOutputMin = 1;

-

-    DWORD& dwOutputMax = *pdwOutputMax;

-    dwOutputMax = 1;

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetStreamCount(

-    DWORD* pcInputStreams,

-    DWORD* pcOutputStreams)

-{

-    if (pcInputStreams == 0)

-        return E_POINTER;

-

-    if (pcOutputStreams == 0)

-        return E_POINTER;

-

-    DWORD& cInputStreams = *pcInputStreams;

-    cInputStreams = 1;

-

-    DWORD& cOutputStreams = *pcOutputStreams;

-    cOutputStreams = 1;

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetStreamIDs(

-    DWORD,

-    DWORD* pdwInputIDs,

-    DWORD,

-    DWORD* pdwOutputIDs)

-{

-    if (pdwInputIDs)

-        *pdwInputIDs = 0;

-

-    if (pdwOutputIDs)

-        *pdwOutputIDs = 0;

-

-    return E_NOTIMPL;

-}

-

-

-HRESULT WebmMfVp8Dec::GetInputStreamInfo(

-    DWORD dwInputStreamID,

-    MFT_INPUT_STREAM_INFO* pStreamInfo)

-{

-    if (pStreamInfo == 0)

-        return E_POINTER;

-

-    if (dwInputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    MFT_INPUT_STREAM_INFO& info = *pStreamInfo;

-

-    //LONGLONG hnsMaxLatency;

-    //DWORD dwFlags;

-    //DWORD cbSize;

-    //DWORD cbMaxLookahead;

-    //DWORD cbAlignment;

-

-    info.cbMaxLookahead = 0;

-    info.hnsMaxLatency = 0;  //TODO: Is 0 correct?

-    //TODO: does lag-in-frames matter here?

-    //See "_MFT_INPUT_STREAM_INFO_FLAGS Enumeration" for more info:

-    //http://msdn.microsoft.com/en-us/library/ms703975%28v=VS.85%29.aspx

-

-    //enum _MFT_INPUT_STREAM_INFO_FLAGS

-    // { MFT_INPUT_STREAM_WHOLE_SAMPLES = 0x1,

-    // MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER = 0x2,

-    // MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE = 0x4,

-    // MFT_INPUT_STREAM_HOLDS_BUFFERS    = 0x8,

-    // MFT_INPUT_STREAM_DOES_NOT_ADDREF = 0x100,

-    // MFT_INPUT_STREAM_REMOVABLE= 0x200,

-    // MFT_INPUT_STREAM_OPTIONAL = 0x400,

-    // MFT_INPUT_STREAM_PROCESSES_IN_PLACE = 0x800

-    // };

-

-    info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES;

-                   //MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;

-                   //MFT_INPUT_STREAM_DOES_NOT_ADDREF;

-

-    info.cbSize = 0;       //input size is variable

-    info.cbAlignment = 0;  //no specific alignment requirements

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetOutputStreamInfo(

-    DWORD dwOutputStreamID,

-    MFT_OUTPUT_STREAM_INFO* pStreamInfo)

-{

-    if (pStreamInfo == 0)

-        return E_POINTER;

-

-    if (dwOutputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    Lock lock;

-

-    const HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    MFT_OUTPUT_STREAM_INFO& info = *pStreamInfo;

-

-    //enum _MFT_OUTPUT_STREAM_INFO_FLAGS

-    //  {   MFT_OUTPUT_STREAM_WHOLE_SAMPLES = 0x1,

-       // MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER    = 0x2,

-       // MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE   = 0x4,

-       // MFT_OUTPUT_STREAM_DISCARDABLE = 0x8,

-       // MFT_OUTPUT_STREAM_OPTIONAL    = 0x10,

-       // MFT_OUTPUT_STREAM_PROVIDES_SAMPLES    = 0x100,

-       // MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES = 0x200,

-       // MFT_OUTPUT_STREAM_LAZY_READ   = 0x400,

-       // MFT_OUTPUT_STREAM_REMOVABLE   = 0x800

-    //  };

-

-    //see Decoder sample in the SDK

-    //decoder.cc

-

-    //The API says that the only flag that is meaningful prior to SetOutputType

-    //is the OPTIONAL flag.  We need the frame dimensions, and the stride,

-    //in order to calculte the cbSize value.

-

-    info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES |

-                   MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |

-                   MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;

-

-    FrameSize size;

-

-    info.cbSize = GetOutputBufferSize(size);

-    info.cbAlignment = 0;

-

-    return S_OK;

-}

-

-

-DWORD WebmMfVp8Dec::GetOutputBufferSize(FrameSize& s) const

-{

-    //MFT was already locked by caller

-

-    //TODO: for now, assume width and height are specified

-    //via the input media type.

-

-    if (m_pInputMediaType == 0)

-        return 0;

-

-    HRESULT hr = MFGetAttributeSize(

-                    m_pInputMediaType,

-                    MF_MT_FRAME_SIZE,

-                    &s.width,

-                    &s.height);

-

-    assert(SUCCEEDED(hr));

-

-    const DWORD w = s.width;

-    assert(w);

-

-    const DWORD h = s.height;

-    assert(h);

-

-    const DWORD cb = w*h + 2*(((w+1)/2)*((h+1)/2));

-

-    //TODO: this result does not account for stride

-

-    return cb;

-}

-

-

-HRESULT WebmMfVp8Dec::GetAttributes(IMFAttributes** pp)

-{

-    if (pp)

-        *pp = 0;

-

-    return E_NOTIMPL;

-}

-

-

-HRESULT WebmMfVp8Dec::GetInputStreamAttributes(

-    DWORD,

-    IMFAttributes** pp)

-{

-    if (pp)

-        *pp = 0;

-

-    return E_NOTIMPL;

-}

-

-

-HRESULT WebmMfVp8Dec::GetOutputStreamAttributes(

-    DWORD,

-    IMFAttributes** pp)

-{

-    if (pp)

-        *pp = 0;

-

-    return E_NOTIMPL;

-}

-

-

-HRESULT WebmMfVp8Dec::DeleteInputStream(DWORD)

-{

-    return E_NOTIMPL;

-}

-

-

-HRESULT WebmMfVp8Dec::AddInputStreams(

-    DWORD,

-    DWORD*)

-{

-    return E_NOTIMPL;

-}

-

-

-HRESULT WebmMfVp8Dec::GetInputAvailableType(

-    DWORD dwInputStreamID,

-    DWORD dwTypeIndex,

-    IMFMediaType** pp)

-{

-     if (pp)

-        *pp = 0;

-

-    if (dwInputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    if (dwTypeIndex > 0)

-        return MF_E_NO_MORE_TYPES;

-

-    if (pp == 0)

-        return E_POINTER;

-

-    IMFMediaType*& pmt = *pp;

-

-    HRESULT hr = MFCreateMediaType(&pmt);

-    assert(SUCCEEDED(hr));

-    assert(pmt);

-

-    hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);

-    assert(SUCCEEDED(hr));

-

-    hr = pmt->SetGUID(MF_MT_SUBTYPE, WebmTypes::MEDIASUBTYPE_VP80);

-    assert(SUCCEEDED(hr));

-

-    hr = pmt->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, FALSE);

-    assert(SUCCEEDED(hr));

-

-    hr = pmt->SetUINT32(MF_MT_COMPRESSED, TRUE);

-    assert(SUCCEEDED(hr));

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetOutputAvailableType(

-    DWORD dwOutputStreamID,

-    DWORD dwTypeIndex,

-    IMFMediaType** pp)

-{

-     if (pp)

-        *pp = 0;

-

-    if (dwOutputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    enum { subtype_count = 3 };

-

-    if (dwTypeIndex >= subtype_count)

-        return MF_E_NO_MORE_TYPES;

-

-    if (pp == 0)

-        return E_POINTER;

-

-    IMFMediaType*& pmt = *pp;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    hr = MFCreateMediaType(&pmt);

-    assert(SUCCEEDED(hr));

-    assert(pmt);

-

-    hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);

-    assert(SUCCEEDED(hr));

-

-    const GUID subtypes[subtype_count] =

-    {

-        MFVideoFormat_NV12,

-        MFVideoFormat_YV12,

-        MFVideoFormat_IYUV

-    };

-

-    const GUID& subtype = subtypes[dwTypeIndex];

-

-    hr = pmt->SetGUID(MF_MT_SUBTYPE, subtype);

-    assert(SUCCEEDED(hr));

-

-    hr = pmt->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);

-    assert(SUCCEEDED(hr));

-

-    hr = pmt->SetUINT32(MF_MT_COMPRESSED, FALSE);

-    assert(SUCCEEDED(hr));

-

-    if (m_pInputMediaType == 0)  //nothing else we can say

-        return S_OK;

-

-    FrameRate r;

-

-    hr = r.AssignFrom(m_pInputMediaType);

-

-    if (hr == S_OK)  //means attribute was set, and its value is valid

-    {

-        //odbgstream os;

-        //os << "\nvp8dec: num=" << r.m_numerator

-        //   << " den=" << r.m_denominator;

-        //

-        //const float rate = float(r.m_numerator) / float(r.m_denominator);

-        //os << rate << '\n' << endl;

-

-        //TODO: a simpler way to handle this is to copy

-        //an item directly from media type to media type (assuming

-        //the MF API provides such a function), instead of going

-        //through this intermediate FrameRate value.

-

-        hr = r.CopyTo(pmt);

-        assert(SUCCEEDED(hr));

-    }

-

-    FrameSize s;

-

-    hr = MFGetAttributeSize(

-            m_pInputMediaType,

-            MF_MT_FRAME_SIZE,

-            &s.width,

-            &s.height);

-

-    assert(SUCCEEDED(hr));

-    assert(s.width);

-    assert(s.height);

-

-    hr = MFSetAttributeSize(

-            pmt,

-            MF_MT_FRAME_SIZE,

-            s.width,

-            s.height);

-

-    assert(SUCCEEDED(hr));

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::SetInputType(

-    DWORD dwInputStreamID,

-    IMFMediaType* pmt,

-    DWORD dwFlags)

-{

-    if (dwInputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (pmt == 0)

-    {

-        //TODO: disallow this case while we're playing?

-

-        if (m_pInputMediaType)

-        {

-            const ULONG n = m_pInputMediaType->Release();

-            n;

-            assert(n == 0);

-

-            m_pInputMediaType = 0;

-

-            const vpx_codec_err_t e = vpx_codec_destroy(&m_ctx);

-            e;

-            assert(e == VPX_CODEC_OK);

-        }

-

-        if (m_pOutputMediaType)

-        {

-            const ULONG n = m_pOutputMediaType->Release();

-            n;

-            assert(n == 0);

-

-            m_pOutputMediaType = 0;

-        }

-

-        return S_OK;

-    }

-

-    //TODO: handle the case when already have an input media type

-    //or output media type, or are already playing.  I don't

-    //think we can change media types while we're playing.

-

-    GUID g;

-

-    hr = pmt->GetMajorType(&g);

-

-    if (FAILED(hr))

-        return MF_E_INVALIDMEDIATYPE;

-

-    if (g != MFMediaType_Video)

-        return MF_E_INVALIDMEDIATYPE;

-

-    hr = pmt->GetGUID(MF_MT_SUBTYPE, &g);

-

-    if (FAILED(hr))

-        return MF_E_INVALIDMEDIATYPE;

-

-    if (g != WebmTypes::MEDIASUBTYPE_VP80)

-        return MF_E_INVALIDMEDIATYPE;

-

-    //hr = pmt->SetUINT32(MF_MT_COMPRESSED, FALSE);

-    //assert(SUCCEEDED(hr));

-

-    FrameRate r;

-

-    hr = r.AssignFrom(pmt);

-

-    if (FAILED(hr))  //input mt has framerate, but it's bad

-        return hr;

-

-    r.CopyTo(m_frame_rate);

-

-    //odbgstream os;

-    //os << "\nvp8dec: framerate=" << m_frame_rate << '\n' << endl;

-

-    FrameSize s;

-

-    hr = MFGetAttributeSize(

-            pmt,

-            MF_MT_FRAME_SIZE,

-            &s.width,

-            &s.height);

-

-    if (FAILED(hr))

-        return MF_E_INVALIDMEDIATYPE;

-

-    if (s.width == 0)

-        return MF_E_INVALIDMEDIATYPE;

-

-    if (s.width % 2)  //TODO

-        return MF_E_INVALIDMEDIATYPE;

-

-    if (s.height == 0)

-        return MF_E_INVALIDMEDIATYPE;

-

-    //TODO: do we need to check for odd height too?

-

-    if (dwFlags & MFT_SET_TYPE_TEST_ONLY)

-        return S_OK;

-

-    if (m_pInputMediaType)

-    {

-        hr = m_pInputMediaType->DeleteAllItems();

-        assert(SUCCEEDED(hr));

-

-        const vpx_codec_err_t e = vpx_codec_destroy(&m_ctx);

-        e;

-        assert(e == VPX_CODEC_OK);

-    }

-    else

-    {

-        hr = MFCreateMediaType(&m_pInputMediaType);

-

-        if (FAILED(hr))

-            return hr;

-    }

-

-    hr = pmt->CopyAllItems(m_pInputMediaType);

-

-    if (FAILED(hr))

-        return hr;

-

-    //m_frame_rate = r;

-

-    //TODO: should this really be done here?

-

-    vpx_codec_iface_t& vp8 = vpx_codec_vp8_dx_algo;

-

-    const int flags = 0;  //TODO: VPX_CODEC_USE_POSTPROC;

-

-    const vpx_codec_err_t err = vpx_codec_dec_init(

-                                    &m_ctx,

-                                    &vp8,

-                                    0,

-                                    flags);

-

-    if (err == VPX_CODEC_MEM_ERROR)

-        return E_OUTOFMEMORY;

-

-    if (err != VPX_CODEC_OK)

-        return E_FAIL;

-

-    //const HRESULT hr = OnApplyPostProcessing();

-

-    if (m_pOutputMediaType)

-    {

-        //TODO: Is this the correct behavior?

-

-        const ULONG n = m_pOutputMediaType->Release();

-        n;

-        assert(n == 0);

-

-        m_pOutputMediaType = 0;

-    }

-

-#if 0

-    //TODO:

-    //We could update the preferred ("available") output media types,

-    //now that we know the frame rate and frame size, etc.

-

-    hr = MFCreateMediaType(&m_pOutputMediaType);

-    assert(SUCCEEDED(hr));  //TODO

-

-    hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);

-    assert(SUCCEEDED(hr));  //TODO

-

-    hr = pmt->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12);

-    assert(SUCCEEDED(hr));  //TODO

-

-    hr = pmt->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);

-    assert(SUCCEEDED(hr));  //TODO

-

-    hr = pmt->SetUINT32(MF_MT_COMPRESSED, FALSE);

-    assert(SUCCEEDED(hr));  //TODO

-

-    if (r.numerator)  //means "has been set"

-    {

-        hr = MFSetAttributeRatio(

-                m_pOutputMediaType,

-                MF_MT_FRAME_RATE,

-                r.numerator,

-                r.denominator);

-

-        assert(SUCCEEDED(hr));  //TODO

-    }

-

-    hr = MFSetAttributeSize(

-            m_pOutputMediaType,

-            MF_MT_FRAME_SIZE,

-            s.width,

-            s.height);

-

-    assert(SUCCEEDED(hr));  //TODO

-#endif

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::SetOutputType(

-    DWORD dwOutputStreamID,

-    IMFMediaType* pmt,

-    DWORD dwFlags)

-{

-    if (dwOutputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (pmt == 0)

-    {

-        //TODO: disallow this case while we're playing?

-

-        if (m_pOutputMediaType)

-        {

-            const ULONG n = m_pOutputMediaType->Release();

-            n;

-            assert(n == 0);

-

-            m_pOutputMediaType = 0;

-        }

-

-        return S_OK;

-    }

-

-    if (m_pInputMediaType == 0)

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    GUID g;

-

-    hr = pmt->GetMajorType(&g);

-

-    if (FAILED(hr))

-        return MF_E_INVALIDMEDIATYPE;

-

-    if (g != MFMediaType_Video)

-        return MF_E_INVALIDMEDIATYPE;

-

-    hr = pmt->GetGUID(MF_MT_SUBTYPE, &g);

-

-    if (FAILED(hr))

-        return MF_E_INVALIDMEDIATYPE;

-

-    if (g == MFVideoFormat_NV12)

-        __noop;

-    else if (g == MFVideoFormat_YV12)

-        __noop;

-    else if (g == MFVideoFormat_IYUV)

-        __noop;

-    else  //TODO: add I420 support

-        return MF_E_INVALIDMEDIATYPE;

-

-    //hr = pmt->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);

-    //assert(SUCCEEDED(hr));

-

-    //hr = pmt->SetUINT32(MF_MT_COMPRESSED, FALSE);

-    //assert(SUCCEEDED(hr));

-

-    FrameRate r_out;

-

-    hr = r_out.AssignFrom(pmt);

-

-    if (FAILED(hr))  //output type has value, but it's not valid

-        return hr;

-

-    if (hr == S_OK)  //output type has value, and it's valid

-    {

-        FrameRate r_in;

-

-        hr = r_in.AssignFrom(m_pInputMediaType);

-

-        if ((hr == S_OK) && !r_in.Match(r_out))

-            return MF_E_INVALIDMEDIATYPE;

-    }

-

-    FrameSize s_out;

-

-    hr = MFGetAttributeSize(

-            pmt,

-            MF_MT_FRAME_SIZE,

-            &s_out.width,

-            &s_out.height);

-

-    if (SUCCEEDED(hr))

-    {

-        if (s_out.width == 0)

-            return MF_E_INVALIDMEDIATYPE;

-

-        //TODO: check whether width is odd

-

-        if (s_out.height == 0)

-            return MF_E_INVALIDMEDIATYPE;

-

-        FrameSize s_in;

-

-        hr = MFGetAttributeSize(

-                m_pInputMediaType,

-                MF_MT_FRAME_SIZE,

-                &s_in.width,

-                &s_in.height);

-

-        assert(SUCCEEDED(hr));

-

-        if (s_out.width != s_in.width)

-            return MF_E_INVALIDMEDIATYPE;

-

-        if (s_out.height != s_in.height)

-            return MF_E_INVALIDMEDIATYPE;

-    }

-

-    if (dwFlags & MFT_SET_TYPE_TEST_ONLY)

-        return S_OK;

-

-    if (m_pOutputMediaType)

-    {

-        hr = m_pOutputMediaType->DeleteAllItems();

-        assert(SUCCEEDED(hr));

-    }

-    else

-    {

-        hr = MFCreateMediaType(&m_pOutputMediaType);

-

-        if (FAILED(hr))

-            return hr;

-    }

-

-    hr = pmt->CopyAllItems(m_pOutputMediaType);

-

-    if (FAILED(hr))

-        return hr;

-

-    //TODO: do something

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetInputCurrentType(

-    DWORD dwInputStreamID,

-    IMFMediaType** pp)

-{

-    if (dwInputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    if (pp)

-        *pp = 0;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (m_pInputMediaType == 0)

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    IMFMediaType*& p = *pp;

-

-    hr = MFCreateMediaType(&p);

-

-    if (FAILED(hr))

-        return hr;

-

-    return m_pInputMediaType->CopyAllItems(p);

-}

-

-

-HRESULT WebmMfVp8Dec::GetOutputCurrentType(

-    DWORD dwOutputStreamID,

-    IMFMediaType** pp)

-{

-    if (dwOutputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    if (pp)

-        *pp = 0;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    //TODO: synthesize from input media type?

-

-    if (m_pOutputMediaType == 0)  //TODO: liberalize?

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    IMFMediaType*& p = *pp;

-

-    hr = MFCreateMediaType(&p);

-

-    if (FAILED(hr))

-        return hr;

-

-    return m_pOutputMediaType->CopyAllItems(p);

-}

-

-

-HRESULT WebmMfVp8Dec::GetInputStatus(

-    DWORD dwInputStreamID,

-    DWORD* pdwFlags)

-{

-    if (dwInputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (m_pInputMediaType == 0)

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    //TODO: check output media type too?

-

-    if (pdwFlags == 0)

-        return E_POINTER;

-

-    DWORD& dwFlags = *pdwFlags;

-

-    dwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;  //because we always queue

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetOutputStatus(DWORD*)

-{

-#if 1

-    return E_NOTIMPL;

-#else

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (m_pInputMediaType == 0)

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    //TODO: check output media type too?

-

-    if (pdwFlags == 0)

-        return E_POINTER;

-

-    DWORD& dwFlags = *pdwFlags;

-

-    const vpx_image_t* const f = vpx_codec_get_frame(&m_ctx, &m_iter);

-

-    dwFlags = f ? MFT_OUTPUT_STATUS_SAMPLE_READY : 0;

-

-    //TODO: alternatively, we could return E_NOTIMPL, which

-    //forces client to call ProcessOutput to determine whether

-    //a sample is ready.

-

-    return S_OK;

-#endif

-}

-

-

-HRESULT WebmMfVp8Dec::SetOutputBounds(

-    LONGLONG /* hnsLowerBound */ ,

-    LONGLONG /* hnsUpperBound */ )

-{

-    return E_NOTIMPL;  //TODO

-}

-

-

-HRESULT WebmMfVp8Dec::ProcessEvent(

-    DWORD dwInputStreamID,

-    IMFMediaEvent* /* pEvent */ )

-{

-    if (dwInputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-#if 0 //def _DEBUG

-    if (pEvent)

-    {

-        MediaEventType t;

-

-        HRESULT hr = pEvent->GetType(&t);

-        assert(SUCCEEDED(hr));

-

-        odbgstream os;

-        os << "WebmMfVp8Dec::ProcessEvent: type=" << t << endl;

-    }

-#endif

-

-    return E_NOTIMPL;  //TODO

-}

-

-

-HRESULT WebmMfVp8Dec::ProcessMessage(

-    MFT_MESSAGE_TYPE m,

-    ULONG_PTR)

-{

-#if 0 //def _DEBUG

-    odbgstream os;

-    os << "WebmMfVp8Dec::ProcessMessage(samples.size="

-       << m_samples.size() << "): ";

-#endif

-

-    switch (m)

-    {

-        case MFT_MESSAGE_COMMAND_FLUSH:

-#if 0 //def _DEBUG

-            os << "COMMAND_FLUSH" << endl;

-#endif

-

-        //http://msdn.microsoft.com/en-us/library/dd940419%28v=VS.85%29.aspx

-

-            Flush();

-            return S_OK;

-

-        case MFT_MESSAGE_COMMAND_DRAIN:

-#if 0 //def _DEBUG

-            os << "COMMAND_DRAIN" << endl;

-#endif

-

-        //http://msdn.microsoft.com/en-us/library/dd940418%28v=VS.85%29.aspx

-

-        //TODO: input stream does not accept input in the MFT processes all

-        //data from previous calls to ProcessInput.

-

-            return S_OK;

-

-        case MFT_MESSAGE_SET_D3D_MANAGER:

-#if 0 //def _DEBUG

-            os << "SET_D3D" << endl;

-#endif

-

-            return S_OK;

-

-        case MFT_MESSAGE_DROP_SAMPLES:

-#if 0 //def _DEBUG

-            os << "DROP_SAMPLES" << endl;

-#endif

-

-            return S_OK;

-

-        case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:

-#if 0 //def _DEBUG

-            os << "NOTIFY_BEGIN_STREAMING" << endl;

-#endif

-

-        //http://msdn.microsoft.com/en-us/library/dd940421%28v=VS.85%29.aspx

-

-        //TODO: init decoder library here, instead of during SetInputType

-

-            return S_OK;

-

-        case MFT_MESSAGE_NOTIFY_END_STREAMING:

-#if 0 //def _DEBUG

-            os << "NOTIFY_END_STREAMING" << endl;

-#endif

-

-        //http://msdn.microsoft.com/en-us/library/dd940423%28v=VS.85%29.aspx

-

-        //NOTE: flush is not performed here

-

-            return S_OK;

-

-        case MFT_MESSAGE_NOTIFY_END_OF_STREAM:

-#if 0 //def _DEBUG

-            os << "NOTIFY_EOS" << endl;

-#endif

-

-        //http://msdn.microsoft.com/en-us/library/dd940422%28v=VS.85%29.aspx

-

-        //TODO: set discontinuity flag on first sample after this

-

-            return S_OK;

-

-        case MFT_MESSAGE_NOTIFY_START_OF_STREAM:

-#if 0 //def _DEBUG

-            os << "NOTIFY_START_OF_STREAM" << endl;

-#endif

-

-            return S_OK;

-

-        case MFT_MESSAGE_COMMAND_MARKER:

-#if 0 //def _DEBUG

-            os << "COMMAND_MARKER" << endl;

-#endif

-

-            return S_OK;

-

-        default:

-            return S_OK;

-    }

-}

-

-

-HRESULT WebmMfVp8Dec::ProcessInput(

-    DWORD dwInputStreamID,

-    IMFSample* pSample,

-    DWORD)

-{

-    if (dwInputStreamID != 0)

-        return MF_E_INVALIDSTREAMNUMBER;

-

-    if (pSample == 0)

-        return E_INVALIDARG;

-

-    DWORD count;

-

-    HRESULT hr = pSample->GetBufferCount(&count);

-    assert(SUCCEEDED(hr));

-

-    if (count == 0)  //weird

-        return S_OK;

-

-    //if (count > 1)

-    //    return E_INVALIDARG;

-

-    //TODO: check duration

-    //TODO: check timestamp

-

-    Lock lock;

-

-    hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (m_pInputMediaType == 0)

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    if (m_pOutputMediaType == 0)  //TODO: need this check here?

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    pSample->AddRef();

-

-    m_samples.push_back(SampleInfo());

-

-    SampleInfo& i = m_samples.back();

-

-    i.pSample = pSample;

-    i.dwBuffer = 0;

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::ProcessOutput(

-    DWORD dwFlags,

-    DWORD cOutputBufferCount,

-    MFT_OUTPUT_DATA_BUFFER* pOutputSamples,

-    DWORD* pdwStatus)

-{

-    if (pdwStatus)

-        *pdwStatus = 0;

-

-    if (dwFlags)

-        return E_INVALIDARG;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (m_pInputMediaType == 0)

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    if (m_pOutputMediaType == 0)

-        return MF_E_TRANSFORM_TYPE_NOT_SET;

-

-    if (cOutputBufferCount == 0)

-        return E_INVALIDARG;

-

-    if (pOutputSamples == 0)

-        return E_INVALIDARG;

-

-    const MFT_OUTPUT_DATA_BUFFER& data = pOutputSamples[0];

-    //data.dwStreamID should equal 0, but we ignore it

-

-    for (;;)

-    {

-        hr = Decode(data.pSample);

-

-        if (FAILED(hr) || (hr == S_OK))

-            return hr;

-    }

-}

-

-

-HRESULT WebmMfVp8Dec::Decode(IMFSample* pSample_out)

-{

-    if (pSample_out == 0)

-        return E_INVALIDARG;

-

-    if (m_samples.empty())

-        return MF_E_TRANSFORM_NEED_MORE_INPUT;

-

-    HRESULT hr;

-    LONGLONG time, duration;

-

-    {

-        SampleInfo& i = m_samples.front();

-        assert(i.pSample);

-

-        UINT32 iKey;

-

-        hr = i.pSample->GetUINT32(MFSampleExtension_CleanPoint, &iKey);

-

-        const bool bKey = SUCCEEDED(hr) && (iKey != FALSE);

-

-        //TODO: this is an optimization oppurtunity, since it would

-        //optimize-away the expense of decoding too (not the expense

-        //of mere rendering, which is what other modes optimize away).

-        //It's tricky to implement since if we

-        //transition OUT of DROP_5 mode, then it's possible that we

-        //we're in the middle of a GOP and so we cannot decode

-        //again until we see the next keyframe.  In other modes, we

-        //decode every frame (we are suppressing the rendering, not

-        //decode), so a state transition between modes is not an issue.

-        //For now, just decompress every frame.

-        //

-        //if (!bKey && (m_drop_mode == MF_DROP_MODE_5))

-        //{

-        //    i.pSample->Release();

-        //    i.pSample = 0;

-        //

-        //    m_samples.pop_front();

-        //

-        //    return S_FALSE;

-        //}

-        //END TODO.

-

-        UINT32 bPreroll;

-

-        hr = i.pSample->GetUINT32(WebmTypes::WebMSample_Preroll, &bPreroll);

-

-        if (SUCCEEDED(hr) && (bPreroll != FALSE))  //preroll frame

-        {

-            hr = i.DecodeAll(m_ctx);

-

-            i.pSample->Release();

-            i.pSample = 0;

-

-            m_samples.pop_front();

-

-            if (FAILED(hr))  //bad decode

-                return hr;

-

-            ReplenishDropBudget();

-            return S_FALSE;  //throw away this sample

-        }

-

-        hr = i.DecodeOne(m_ctx, time, duration);

-

-        if (FAILED(hr) || (hr != S_OK))

-        {

-            i.pSample->Release();

-            i.pSample = 0;

-

-            m_samples.pop_front();

-

-            if (FAILED(hr))  //bad decode

-                return hr;

-        }

-

-        if (m_drop_mode == MF_DROP_MODE_NONE)

-            __noop;  //we're not throwing away frames

-

-        else if (m_drop_mode >= MF_DROP_MODE_5)

-        {

-            if (!bKey)

-                return S_FALSE;  //throw away this sample

-        }

-        else if (bKey || (m_drop_budget > 1))

-            --m_drop_budget;  //spend out budget to render this frame

-

-        else

-        {

-            ReplenishDropBudget();

-            return S_FALSE;  //throw away this sample

-        }

-    }

-

-    DWORD count_out;

-

-    hr = pSample_out->GetBufferCount(&count_out);

-

-    if (SUCCEEDED(hr) && (count_out != 1))  //TODO: handle this?

-        return E_INVALIDARG;

-

-    IMFMediaBufferPtr buf_out;

-

-    hr = pSample_out->GetBufferByIndex(0, &buf_out);

-

-    if (FAILED(hr) || !bool(buf_out))

-        return E_INVALIDARG;

-

-    GUID subtype;

-

-    hr = m_pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &subtype);

-    assert(SUCCEEDED(hr));

-

-    //TODO:

-    //MFVideoFormat_I420

-

-    FrameSize frame_size;

-

-    const DWORD cbFrameLen = GetOutputBufferSize(frame_size);

-    assert(cbFrameLen > 0);

-

-    //The sequence of querying for the output buffer is described on

-    //the page "Uncompressed Video Buffers".

-    //http://msdn.microsoft.com/en-us/library/aa473821%28v=VS.85%29.aspx

-

-    IMF2DBuffer* buf2d_out;

-

-    hr = buf_out->QueryInterface(&buf2d_out);

-

-    if (SUCCEEDED(hr))

-    {

-        assert(buf2d_out);

-

-        BYTE* ptr_out;

-        LONG stride_out;

-

-        hr = buf2d_out->Lock2D(&ptr_out, &stride_out);

-        assert(SUCCEEDED(hr));

-        assert(ptr_out);

-        assert(stride_out > 0);  //top-down DIBs are positive, right?

-

-        const HRESULT hrGetFrame = GetFrame(ptr_out, stride_out, subtype);

-

-        //TODO: set output buffer length?

-

-        hr = buf2d_out->Unlock2D();

-        assert(SUCCEEDED(hr));

-

-        buf2d_out->Release();

-        buf2d_out = 0;

-

-        if (FAILED(hrGetFrame) || (hrGetFrame != S_OK))

-            return hrGetFrame;

-    }

-    else

-    {

-        BYTE* ptr_out;

-        DWORD cbMaxLen;

-

-        hr = buf_out->Lock(&ptr_out, &cbMaxLen, 0);

-        assert(SUCCEEDED(hr));

-        assert(ptr_out);

-        assert(cbMaxLen >= cbFrameLen);

-

-        //TODO: verify stride of output buffer

-        //The page "Uncompressed Video Buffers" here:

-        //http://msdn.microsoft.com/en-us/library/aa473821%28v=VS.85%29.aspx

-        //explains how to calculate the "minimum stride":

-        //  MF_MT_DEFAULT_STRIDE

-        //  or, MFGetStrideForBitmapInfoHeader

-        //  or, calculate it yourself

-

-        INT32 stride_out;

-

-        hr = pSample_out->GetUINT32(

-                MF_MT_DEFAULT_STRIDE,

-                (UINT32*)&stride_out);

-

-        if (SUCCEEDED(hr) && (stride_out != 0))

-            assert(stride_out > 0);

-        else

-        {

-            const DWORD fcc = subtype.Data1;

-

-            const DWORD w = frame_size.width;

-            LONG stride_out_;

-

-            hr = MFGetStrideForBitmapInfoHeader(fcc, w, &stride_out_);

-

-            if (SUCCEEDED(hr) && (stride_out_ != 0))

-            {

-                assert(stride_out_ > 0);

-                stride_out = stride_out_;

-            }

-            else

-            {

-                assert((w % 2) == 0);  //TODO

-                stride_out = w;  //TODO: is this correct???

-            }

-        }

-

-        const HRESULT hrGetFrame = GetFrame(ptr_out, stride_out, subtype);

-

-        hr = buf_out->Unlock();

-        assert(SUCCEEDED(hr));

-

-        if (FAILED(hrGetFrame) || (hrGetFrame != S_OK))

-            return hrGetFrame;

-

-        hr = buf_out->SetCurrentLength(cbFrameLen);

-        assert(SUCCEEDED(hr));

-    }

-

-    if (time >= 0)

-    {

-        hr = pSample_out->SetSampleTime(time);

-        assert(SUCCEEDED(hr));

-    }

-

-    if (duration >= 0)

-    {

-        hr = pSample_out->SetSampleDuration(duration);

-        assert(SUCCEEDED(hr));

-    }

-

-    return S_OK;  //done

-}

-

-

-HRESULT WebmMfVp8Dec::GetFrame(

-    BYTE* pOutBuf,

-    ULONG strideOut,

-    const GUID& subtype)

-{

-    assert(pOutBuf);

-    assert(strideOut);

-    assert((strideOut % 2) == 0);  //TODO: resolve this issue

-

-    vpx_codec_iter_t iter = 0;

-

-    const vpx_image_t* const f = vpx_codec_get_frame(&m_ctx, &iter);

-

-    if (f == 0)  //alt-ref

-        return S_FALSE;  //tell caller to pop this buffer and call me back

-

-    //Y

-

-    const BYTE* pInY = f->planes[VPX_PLANE_Y];

-    assert(pInY);

-

-    unsigned int wIn = f->d_w;

-    unsigned int hIn = f->d_h;

-

-    BYTE* pOut = pOutBuf;

-

-    const int strideInY = f->stride[VPX_PLANE_Y];

-

-    for (unsigned int y = 0; y < hIn; ++y)

-    {

-        memcpy(pOut, pInY, wIn);

-        pInY += strideInY;

-        pOut += strideOut;

-    }

-

-    const BYTE* pInV = f->planes[VPX_PLANE_V];

-    assert(pInV);

-

-    const int strideInV = f->stride[VPX_PLANE_V];

-

-    const BYTE* pInU = f->planes[VPX_PLANE_U];

-    assert(pInU);

-

-    const int strideInU = f->stride[VPX_PLANE_U];

-

-    wIn = (wIn + 1) / 2;

-    hIn = (hIn + 1) / 2;

-

-    if (subtype == MFVideoFormat_NV12)

-    {

-        for (unsigned int y = 0; y < hIn; ++y)

-        {

-            const BYTE* u = pInU;   //src

-            const BYTE* v = pInV;   //src

-            BYTE* uv = pOut;        //dst

-

-            for (unsigned int idx = 0; idx < wIn; ++idx)  //uv

-            {

-                *uv++ = *u++;  //Cb

-                *uv++ = *v++;  //Cr

-            }

-

-            pInU += strideInU;

-            pInV += strideInV;

-            pOut += strideOut;

-        }

-    }

-    else if (subtype == MFVideoFormat_YV12)

-    {

-        strideOut /= 2;

-

-        //V

-

-        for (unsigned int y = 0; y < hIn; ++y)

-        {

-            memcpy(pOut, pInV, wIn);

-            pInV += strideInV;

-            pOut += strideOut;

-        }

-

-        //U

-

-        for (unsigned int y = 0; y < hIn; ++y)

-        {

-            memcpy(pOut, pInU, wIn);

-            pInU += strideInU;

-            pOut += strideOut;

-        }

-    }

-    else

-    {

-        assert(subtype == MFVideoFormat_IYUV);

-

-        strideOut /= 2;

-

-        //U

-

-        for (unsigned int y = 0; y < hIn; ++y)

-        {

-            memcpy(pOut, pInU, wIn);

-            pInU += strideInU;

-            pOut += strideOut;

-        }

-

-        //V

-

-        for (unsigned int y = 0; y < hIn; ++y)

-        {

-            memcpy(pOut, pInV, wIn);

-            pInV += strideInV;

-            pOut += strideOut;

-        }

-    }

-

-    const vpx_image_t* const f2 = vpx_codec_get_frame(&m_ctx, &iter);

-    f2;

-    assert(f2 == 0);

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::SetRate(BOOL bThin, float rate)

-{

-    //odbgstream os;

-    //os << "WebmMfVp8Dec::SetRate: bThin="

-    //   << boolalpha << (bThin ? true : false)

-    //   << " rate="

-    //   << rate

-    //   << endl;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    //if (m_pEvents == 0)

-    //    return MF_E_SHUTDOWN;

-

-    //if (bThin)

-    //    return MF_E_THINNING_UNSUPPORTED;  //TODO

-

-    if (rate < 0)

-        return MF_E_REVERSE_UNSUPPORTED;  //TODO

-

-    m_rate = rate;

-    m_bThin = bThin;

-

-    //reset drop mode when rate change

-

-    m_lag_sum = 0;

-    m_lag_count = 0;

-    m_lag_frames = 0;

-

-    hr = WebmMfVp8Dec::SetDropMode(MF_DROP_MODE_NONE);

-    assert(SUCCEEDED(hr));

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetRate(BOOL* pbThin, float* pRate)

-{

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    //if (m_pEvents == 0)

-    //    return MF_E_SHUTDOWN;

-

-    if (pbThin)

-        *pbThin = m_bThin;

-

-    if (pRate)  //return error when pRate ptr is NULL?

-        *pRate = m_rate;

-

-    //odbgstream os;

-    //os << "WebmMfVp8Dec::GetRate: bThin="

-    //   << boolalpha << m_bThin

-    //   << " rate="

-    //   << m_rate

-    //   << endl;

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetSlowestRate(

-    MFRATE_DIRECTION d,

-    BOOL /* bThin */ ,

-    float* pRate)

-{

-    //odbgstream os;

-    //os << "WebmMfVp8Dec::GetSlowestRate" << endl;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    //if (m_pEvents == 0)

-    //    return MF_E_SHUTDOWN;

-

-    if (d == MFRATE_REVERSE)

-        return MF_E_REVERSE_UNSUPPORTED;  //TODO

-

-    //if (bThin)

-    //    return MF_E_THINNING_UNSUPPORTED;  //TODO

-

-    if (pRate == 0)

-        return E_POINTER;

-

-    float& r = *pRate;

-    r = 0;  //?

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetFastestRate(

-    MFRATE_DIRECTION d,

-    BOOL /* bThin */ ,

-    float* pRate)

-{

-    //odbgstream os;

-    //os << "WebmMfSource::GetFastestRate" << endl;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    //if (m_pEvents == 0)

-    //    return MF_E_SHUTDOWN;

-

-    if (d == MFRATE_REVERSE)

-        return MF_E_REVERSE_UNSUPPORTED;  //TODO

-

-    //if (bThin)

-    //    return MF_E_THINNING_UNSUPPORTED;  //TODO

-

-    if (pRate == 0)

-        return E_POINTER;

-

-    float& r = *pRate;

-    r = 64;  //?

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::IsRateSupported(

-    BOOL /* bThin */ ,

-    float rate,

-    float* pNearestRate)

-{

-    //odbgstream os;

-    //os << "WebmMfVp8Dec::IsRateSupported: rate=" << rate << endl;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    //if (m_pEvents == 0)

-    //    return MF_E_SHUTDOWN;

-

-    //if (bThin)

-    //    return MF_E_THINNING_UNSUPPORTED;  //TODO

-

-    if (rate < 0)

-        return MF_E_REVERSE_UNSUPPORTED;  //TODO

-

-    //float int_part;

-    //const float frac_part = modf(rate, &int_part);

-

-    if (pNearestRate)

-        *pNearestRate = rate;

-

-    return S_OK;  //TODO

-}

-

-

-HRESULT WebmMfVp8Dec::GetService(

-    REFGUID sid,

-    REFIID iid,

-    LPVOID* ppv)

-{

-    if (sid == MF_RATE_CONTROL_SERVICE)

-        return WebmMfVp8Dec::QueryInterface(iid, ppv);

-

-    if (ppv)

-        *ppv = 0;

-

-    return MF_E_UNSUPPORTED_SERVICE;

-}

-

-

-void WebmMfVp8Dec::Flush()

-{

-    while (!m_samples.empty())

-    {

-        SampleInfo& i = m_samples.front();

-        assert(i.pSample);

-

-        i.pSample->Release();

-        i.pSample = 0;

-

-        m_samples.pop_front();

-    }

-}

-

-

-HRESULT WebmMfVp8Dec::SampleInfo::DecodeAll(vpx_codec_ctx_t& ctx)

-{

-    assert(pSample);

-

-    DWORD count;

-

-    HRESULT hr = pSample->GetBufferCount(&count);

-    assert(SUCCEEDED(hr));

-    assert(count > 0);

-

-    while (dwBuffer < count)

-    {

-        IMFMediaBufferPtr buf;

-

-        hr = pSample->GetBufferByIndex(dwBuffer, &buf);

-        assert(SUCCEEDED(hr));

-        assert(buf);

-

-        BYTE* ptr;

-        DWORD len;

-

-        hr = buf->Lock(&ptr, 0, &len);

-        assert(SUCCEEDED(hr));

-        assert(ptr);

-        assert(len);

-

-        const vpx_codec_err_t e = vpx_codec_decode(&ctx, ptr, len, 0, 0);

-

-        hr = buf->Unlock();

-        assert(SUCCEEDED(hr));

-

-        if (e != VPX_CODEC_OK)

-            return MF_E_INVALID_STREAM_DATA;

-

-        ++dwBuffer;  //consume this buffer

-    }

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::SampleInfo::DecodeOne(

-    vpx_codec_ctx_t& ctx,

-    LONGLONG& time,

-    LONGLONG& duration)

-{

-    assert(pSample);

-

-    DWORD count;

-

-    HRESULT hr = pSample->GetBufferCount(&count);

-    assert(SUCCEEDED(hr));

-    assert(count > 0);

-    assert(count > dwBuffer);

-

-    IMFMediaBufferPtr buf;

-

-    hr = pSample->GetBufferByIndex(dwBuffer, &buf);

-    assert(SUCCEEDED(hr));

-    assert(buf);

-

-    BYTE* ptr;

-    DWORD len;

-

-    hr = buf->Lock(&ptr, 0, &len);

-    assert(SUCCEEDED(hr));

-    assert(ptr);

-    assert(len);

-

-    const vpx_codec_err_t e = vpx_codec_decode(&ctx, ptr, len, 0, 0);

-

-    hr = buf->Unlock();

-    assert(SUCCEEDED(hr));

-

-    if (e != VPX_CODEC_OK)

-        return MF_E_INVALID_STREAM_DATA;

-

-    LONGLONG t;

-

-    hr = pSample->GetSampleTime(&t);

-

-    if (FAILED(hr) || (t < 0))

-    {

-        time = -1;

-        duration = -1;

-    }

-    else

-    {

-        LONGLONG d;

-

-        hr = pSample->GetSampleDuration(&d);

-

-        if (FAILED(hr) || (d <= 0))

-        {

-            if (dwBuffer == 0)  //first buffer

-                time = t;

-            else

-                time = -1;

-

-            duration = -1;

-        }

-        else

-        {

-            duration = d / count;

-            time = t + dwBuffer * duration;

-        }

-    }

-

-    ++dwBuffer;  //consume this buffer

-    return (dwBuffer >= count) ? S_FALSE : S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::SetDropMode(MF_QUALITY_DROP_MODE d)

-{

-    if (d > MF_DROP_MODE_5)

-        return MF_E_NO_MORE_DROP_MODES;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    m_drop_mode = d;

-    m_drop_budget = 0;

-

-    //odbgstream os;

-    //os << "SetDropMode=" << m_drop_mode << endl;

-

-    return S_OK;

-

-    //we always keep keyframes ("cleanpoint")

-    //1: drop 1 out of every 2 frames

-    //2: drop 2 out of every 3 frames

-    //3: drop 3 out of every 4 frames

-    //4: drop 4 out of every 5 frames

-    //5: drop all delta frames

-    //

-    //alternatively:

-    //1: drop 1 out of every 16 = 2^4 = 2^(5-1)

-    //2: drop 1 out of every 8  = 2^3 = 2^(5-2) = 2 out of every 16

-    //3: drop 1 out of every 4  = 2^2 = 2^(5-3) = 4 out of every 16

-    //4: drop 1 out of every 2  = 2^1 = 2^(5-4) = 8 out of every 16

-    //5: drop all delta frames

-

-    //when we detect a keyframe, this resets the counter

-    //

-    //level 1:

-    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0

-    //                              x

-    //

-    //level 2:

-    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0

-    //              x               x

-    //

-    //level 3:

-    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0

-    //      x       x       x       x       x

-    //

-    //level 4:

-    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0

-    //  x   x   x   x   x   x   x   x   x   x

-    //

-    //we could also tie this to framerate, e.g.

-    //1: drop 1 frame per second

-    //2: drop 1 frame per 1/2 sec

-    //3: drop 1 frame per 1/4 sec

-    //4: drop 1 frame per 1/8 sec

-    //5: drop all delta frames

-    //

-    //Give outselves a budget: the smaller the drop mode,

-    //the larger the budget.  Drop the first eligrable

-    //frame when our budget drops to 0.

-}

-

-

-void WebmMfVp8Dec::ReplenishDropBudget()

-{

-    if (m_drop_mode == MF_DROP_MODE_NONE)

-    {

-        m_drop_budget = 0;  //doesn't really matter

-        return;

-    }

-

-    if (m_drop_mode >= MF_DROP_MODE_5)

-    {

-        m_drop_budget = 0;  //doesn't really matter

-        return;

-    }

-

-    const int d = m_drop_mode;

-    assert(d >= 1);

-    assert(d <= 4);

-

-    m_drop_budget = (1 << (5 - d));

-}

-

-

-HRESULT WebmMfVp8Dec::SetQualityLevel(MF_QUALITY_LEVEL q)

-{

-    if (q == MF_QUALITY_NORMAL)

-        return S_OK;

-

-    return MF_E_NO_MORE_QUALITY_LEVELS;

-}

-

-

-HRESULT WebmMfVp8Dec::GetDropMode(MF_QUALITY_DROP_MODE* p)

-{

-    if (p == 0)

-        return E_POINTER;

-

-    Lock lock;

-

-    HRESULT hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    MF_QUALITY_DROP_MODE& d = *p;

-    d = m_drop_mode;

-

-    //odbgstream os;

-    //os << "GetDropMode=" << m_drop_mode << endl;

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::GetQualityLevel(MF_QUALITY_LEVEL* p)

-{

-    if (p == 0)

-        return E_POINTER;

-

-    MF_QUALITY_LEVEL& q = *p;

-    q = MF_QUALITY_NORMAL;  //no post-processing for us to shut off

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::DropTime(LONGLONG t)

-{

-    t;

-    return MF_E_DROPTIME_NOT_SUPPORTED;

-}

-

-

-HRESULT WebmMfVp8Dec::NotifyQualityEvent(IMFMediaEvent* pe, DWORD* pdw)

-{

-    if (pe == 0)

-        return E_INVALIDARG;

-

-    if (pdw == 0)

-        return E_POINTER;

-

-    DWORD& dw = *pdw;

-    dw = 0;  //TODO: possibly set this to MF_QUALITY_CANNOT_KEEP_UP

-

-    MediaEventType type;

-

-    HRESULT hr = pe->GetType(&type);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (type != MEQualityNotify)

-        return E_INVALIDARG;

-

-    GUID ext;

-

-    hr = pe->GetExtendedType(&ext);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (ext != MF_QUALITY_NOTIFY_SAMPLE_LAG)

-        return S_OK;

-

-    PROPVARIANT v;

-

-    hr = pe->GetValue(&v);

-

-    if (FAILED(hr))

-        return E_INVALIDARG;

-

-    if (v.vt != VT_I8)

-        return E_INVALIDARG;

-

-    const LONGLONG reftime = v.hVal.QuadPart;

-

-    //MEQualityNotify Event

-    //http://msdn.microsoft.com/en-us/library/ms694893(VS.85).aspx

-

-    //negative is good - frames are early

-    //positive is bad - frames are late

-    //value is a lateness - time in 100ns units

-    //we're seeing extreme lateness: 2 or 3s

-

-    //if (ext == MF_QUALITY_NOTIFY_PROCESSING_LATENCY)

-    //    return S_OK;

-

-    Lock lock;

-

-    hr = lock.Seize(this);

-

-    if (FAILED(hr))

-        return hr;

-

-    if (m_frame_rate <= 0)   //no framerate available

-        return S_OK;         //TODO: for now, don't bother trying to drop

-

-    if (m_bThin || (m_rate != 1))  //bThin = true implies drop level 5 already

-        return S_OK;

-

-    if (reftime <= 0)  //assume we're all caught up, even if value is spurious

-    {

-        m_lag_sum = 0;

-        m_lag_count = 0;

-        m_lag_frames = 0;

-

-        hr = WebmMfVp8Dec::SetDropMode(MF_DROP_MODE_NONE);

-        assert(SUCCEEDED(hr));

-

-        return S_OK;

-    }

-

-    m_lag_sum += reftime;

-    ++m_lag_count;

-

-    if (m_lag_count < 16)

-        return S_OK;

-

-    const float lag_reftime = float(m_lag_sum) / float(m_lag_count);

-

-    const float frames_ = lag_reftime * m_frame_rate / 10000000.0F;

-    const int frames = static_cast<int>(frames_);

-

-    if (frames <= 1)  //treat small values as noise

-    {

-        m_lag_sum = 0;

-        m_lag_count = 0;

-        m_lag_frames = 0;

-

-        hr = WebmMfVp8Dec::SetDropMode(MF_DROP_MODE_NONE);

-        assert(SUCCEEDED(hr));

-    }

-

-    MF_QUALITY_DROP_MODE m;

-

-    hr = WebmMfVp8Dec::GetDropMode(&m);

-    assert(SUCCEEDED(hr));

-

-    if ((m_lag_frames > 0) &&          //have previous value

-        (frames >= m_lag_frames) &&    //we're not getting better

-        (m < MF_DROP_MODE_5))          //TODO: use MF_QUALITY_CANNOT_KEEP_UP?

-    {

-#ifdef _DEBUG

-        odbgstream os;

-        os << "WebmMfVp8Dec::NotifyQualityEvent: old drop mode=" << m;

-#endif

-

-        m = static_cast<MF_QUALITY_DROP_MODE>(int(m) + 1);

-

-#ifdef _DEBUG

-        os << " new drop mode=" << m << endl;

-#endif

-

-        hr = WebmMfVp8Dec::SetDropMode(m);

-        assert(SUCCEEDED(hr));

-    }

-

-    m_lag_sum = 0;

-    m_lag_count = 0;

-    m_lag_frames = frames;

-

-    return S_OK;

-

-    //Here's a case when there's been a long sequence of frames

-    //having positive lag.  That means we're slightly behind, so

-    //we should compare how much we're behind now to how much

-    //we were behind in the recent past.  The reason we do that

-    //is to discover whether we have a trend.

-    //

-    //How many data points to we use to compute the trend?  We used

-    //the most recent 16 points to compute our latest lag value, so

-    //we must compare the most recent lag value to previous lag values.

-    //

-    //If we have a previous lag value, then we can compute a trend, even

-    //if we only have two points.

-    //

-    //If the avg lag computed here is same or (slightly?) larger, then it

-    //means we really are behind.  We would choose a drop level.  Our

-    //current algorithm even for dropping doesn't work that fast: at

-    //drop level 1, we drop only 1 frame for every 16 frames, so once

-    //we set a non-zero drop level we do have to wait at least 16 frames

-    //before reacting (which is what we do here).

-    //

-    //We don't necessarily have to compare lag times: we convert this to

-    //a frame, so we could compare frames instead.

-    //

-    //The issue remain: how often do we adjust the drop level?

-    //

-    //I suppose that when the reported lag time is less than 0, then this

-    //will reset everything anyway, so we can set the drop level back to

-    //0 when that happens.

-    //

-    //We probalby only have to increase the drop level, until we're caught

-    //up, and it gets reset back to 0.  The question is how often we adjust

-    //the drop level up.

-    //

-    //1st time: 1 out of 16

-    //2nd time: 2 out of 16

-    //3rd time: 4 out of 16

-    //4th time: 8 out of 16

-    //5th time: keyframes only

-    //

-    //if lag has increased since last time, go ahead and increase the drop

-    //level.

-    //

-    //if lag has decreased since last time, the we can probably either decrease

-    //the drop level, or leave it as is.

-

-    //These dampened out by themselves, so there's nothing special we needed

-    //to do.  We don't want to react right away.  The problem we need to

-    //handle

-    //is when the lag is positive and large, and stays constant or is

-    //increasing.

-    //It the number is trending down then the problem solves itself.  The hard

-    //cases are when the lag is growing, or staying constant and large.

-    //

-    //How to define "growing"?  If the slope is positive, that's growing.  If

-    //we remain at any positive slope, the lag will definitely grow.

-    //

-    //We could use a one-shot flag: if the flag is true, throw away the next

-    //non-key frame, then clear the flag.

-    //

-    //Our goal is to pull the slope down to 0 (or negative).  This should drive

-    //the lag down, which should drive the slope towards 0.

-    //

-    //A running average isn't necessarily what we want, although this

-    //will give us an estimate of the avg lag.  If the avg is large and

-    //constant then we must correct.

-

-    //How to compute avg lag:

-    //  (sum of lag times) / (number of lag times)

-    //or could weigh curr avg and curr lag

-    //e.g.  new avg lag = (15/16) * (old avg lag) + (1/16) * (new lag)

-    //if lag <= 0 then reset avg lag

-

-    //10000000 = 1 sec

-    // 5000000 = 1/2 sec

-    // 2500000 = 1/4 sec

-    // 1250000 = 1/8 sec

-    //  625000 = 1/16 sec

-    //  312500 = 1/32 sec

-    //  156250 = 1/64 sec

-    //   78125 = 1/128 sec

-

-    // 1 sec late

-    //  if we see 2 frames the set drop mode #5 (keyframe only)

-    //

-    // 1/2 sec late

-    //  if we see 4 frames then set drop mode #4

-    //

-    // 1/4 sec late

-    //  if we see

-

-    //drop mode 1 = 1/16 frames are dropped

-    //          2 = 1/8 frames

-    //          3 = 1/4 frames

-    //          4 = 1/2 frames

-    //

-    //If we do set the drop mode, then the decoder doesn't

-    //react that fast.

-    //

-    //for drop mode 1, we gain 1/16th sec every 16 frames

-    //if we were behind by 1/16th sec, then we'd catch up after 1 cycle

-    //if we were behind by 1/8th sec, we'd catch up after 2 cycles, etc

-    //

-    //for drop mode 2, we gain 1/8th sec every 8 frames

-    //if we were behind by 1/8th sec, we'd catch up after 1 cycle

-    //if we were behind by 1/4 sec, then we'd catch up after 2 cycles, etc

-    //

-    //for drop mode 3, we gain 1/4 sec every 4 frames

-    //if we were behind by 1/4 sec, we'd catch up after 1 cycle

-    //if we were behind by 1/2 sec, then we'd catch up after 2 cycles, etc

-    //

-    //for drop mode 4, we gain 1/2 sec every 2 frames

-    //

-    //THAT'S ALL WRONG

-    //the drop modes work in terms of frames, not times

-    //IQualityAdvise2 works in terms of time, not frames

-    //

-    //To convert between the two advise interfaces we need the frame rate

-}

-

-

-void WebmMfVp8Dec::FrameRate::Init()

-{

-    m_numerator = 0;

-    m_denominator = 0;

-}

-

-

-HRESULT WebmMfVp8Dec::FrameRate::AssignFrom(IMFMediaType* pmt)

-{

-    UINT32& num = m_numerator;

-    UINT32& den = m_denominator;

-

-    const HRESULT hr = MFGetAttributeRatio(pmt, MF_MT_FRAME_RATE, &num, &den);

-

-    //TODO: check explicitly for the result that means "attribute not set".

-    //MF_E_ATTRIBUTENOTFOUND

-    //MF_E_INVALIDTYPE

-

-    if (FAILED(hr))  //we assume here this means value wasn't found

-    {

-        Init();

-        return S_FALSE;

-    }

-

-    if (den == 0)

-        return MF_E_INVALIDMEDIATYPE;

-

-    if (num == 0)

-        return MF_E_INVALIDMEDIATYPE;

-

-    return S_OK;

-}

-

-

-HRESULT WebmMfVp8Dec::FrameRate::CopyTo(IMFMediaType* pmt) const

-{

-    const UINT32 num = m_numerator;

-    const UINT32 den = m_denominator;

-

-    return MFSetAttributeRatio(pmt, MF_MT_FRAME_RATE, num, den);

-}

-

-

-HRESULT WebmMfVp8Dec::FrameRate::CopyTo(float& value) const

-{

-    const UINT32 num = m_numerator;

-    const UINT32 den = m_denominator;

-

-    if (den == 0)

-        value = -1;  //serves as our "undefined framerate" nonce value

-    else

-        value = float(num) / float(den);

-

-    return S_OK;

-}

-

-

-bool WebmMfVp8Dec::FrameRate::Match(const FrameRate& rhs) const

-{

-    const UINT64 n_in = m_numerator;

-    const UINT64 d_in = m_denominator;

-

-    const UINT64 n_out = rhs.m_numerator;

-    const UINT64 d_out = rhs.m_denominator;

-

-    // n_in / d_in = n_out / d_out

-    // n_in * d_out = n_out * d_in

-

-    return ((n_in * d_out) == (n_out * d_in));

-}

-

-

-}  //end namespace WebmMfVp8DecLib

+#pragma warning(disable:4505)  //unreferenced local function removed
+#include "clockable.h"
+#include <mfidl.h>
+#include "vpx/vpx_decoder.h"
+#include "vpx/vp8dx.h"
+#include "webmmfvp8dec.h"
+#include "webmtypes.h"
+#include <mfapi.h>
+#include <mferror.h>
+#include <comdef.h>
+#include <cassert>
+#include <new>
+#ifdef _DEBUG
+#include "odbgstream.h"
+#include "iidstr.h"
+using std::endl;
+using std::boolalpha;
+#endif
+
+_COM_SMARTPTR_TYPEDEF(IMFMediaBuffer, __uuidof(IMFMediaBuffer));
+_COM_SMARTPTR_TYPEDEF(IMF2DBuffer, __uuidof(IMF2DBuffer));
+
+
+namespace WebmMfVp8DecLib
+{
+
+
+HRESULT CreateDecoder(
+    IClassFactory* pClassFactory,
+    IUnknown* pOuter,
+    const IID& iid,
+    void** ppv)
+{
+    if (ppv == 0)
+        return E_POINTER;
+
+    *ppv = 0;
+
+    if (pOuter)
+        return CLASS_E_NOAGGREGATION;
+
+    WebmMfVp8Dec* const p = new (std::nothrow) WebmMfVp8Dec(pClassFactory);
+
+    if (p == 0)
+        return E_OUTOFMEMORY;
+
+    IMFTransform* const pUnk = p;
+
+    const HRESULT hr = pUnk->QueryInterface(iid, ppv);
+
+    const ULONG cRef = pUnk->Release();
+    cRef;
+
+    return hr;
+}
+
+
+WebmMfVp8Dec::WebmMfVp8Dec(IClassFactory* pClassFactory) :
+    m_pClassFactory(pClassFactory),
+    m_cRef(1),
+    m_pInputMediaType(0),
+    m_pOutputMediaType(0),
+    m_rate(1),
+    m_bThin(FALSE),
+    m_drop_mode(MF_DROP_MODE_NONE),
+    m_drop_budget(0),
+    m_lag_sum(0),
+    m_lag_count(0),
+    m_lag_frames(0),
+    m_frame_rate(-1)
+{
+    HRESULT hr = m_pClassFactory->LockServer(TRUE);
+    assert(SUCCEEDED(hr));
+
+    hr = CLockable::Init();
+    assert(SUCCEEDED(hr));
+
+    //m_frame_rate.Init();
+}
+
+
+WebmMfVp8Dec::~WebmMfVp8Dec()
+{
+    if (m_pInputMediaType)
+    {
+        const ULONG n = m_pInputMediaType->Release();
+        n;
+        assert(n == 0);
+
+        m_pInputMediaType = 0;
+
+        const vpx_codec_err_t e = vpx_codec_destroy(&m_ctx);
+        e;
+        assert(e == VPX_CODEC_OK);
+    }
+
+    if (m_pOutputMediaType)
+    {
+        const ULONG n = m_pOutputMediaType->Release();
+        n;
+        assert(n == 0);
+
+        m_pOutputMediaType = 0;
+    }
+
+    Flush();
+
+    HRESULT hr = m_pClassFactory->LockServer(FALSE);
+    assert(SUCCEEDED(hr));
+}
+
+
+HRESULT WebmMfVp8Dec::QueryInterface(
+    const IID& iid,
+    void** ppv)
+{
+    if (ppv == 0)
+        return E_POINTER;
+
+    IUnknown*& pUnk = reinterpret_cast<IUnknown*&>(*ppv);
+
+    if (iid == __uuidof(IUnknown))
+    {
+        pUnk = static_cast<IMFTransform*>(this);  //must be nondelegating
+    }
+    else if (iid == __uuidof(IMFTransform))
+    {
+        pUnk = static_cast<IMFTransform*>(this);
+    }
+    else if (iid == __uuidof(IMFQualityAdvise2))
+    {
+        pUnk = static_cast<IMFQualityAdvise2*>(this);
+    }
+    else if (iid == __uuidof(IMFQualityAdvise))
+    {
+        pUnk = static_cast<IMFQualityAdvise*>(this);
+    }
+    else if (iid == __uuidof(IMFRateControl))
+    {
+        pUnk = static_cast<IMFRateControl*>(this);
+    }
+    else if (iid == __uuidof(IMFRateSupport))
+    {
+        pUnk = static_cast<IMFRateSupport*>(this);
+    }
+    else if (iid == __uuidof(IMFGetService))
+    {
+        pUnk = static_cast<IMFGetService*>(this);
+    }
+    else
+    {
+//#ifdef _DEBUG
+//        wodbgstream os;
+//        os << "WebmMfVp8Dec::QI: iid=" << IIDStr(iid) << std::endl;
+//#endif
+
+        pUnk = 0;
+        return E_NOINTERFACE;
+    }
+
+    pUnk->AddRef();
+    return S_OK;
+}
+
+
+ULONG WebmMfVp8Dec::AddRef()
+{
+    return InterlockedIncrement(&m_cRef);
+}
+
+
+ULONG WebmMfVp8Dec::Release()
+{
+    if (LONG n = InterlockedDecrement(&m_cRef))
+        return n;
+
+    delete this;
+    return 0;
+}
+
+
+HRESULT WebmMfVp8Dec::GetStreamLimits(
+    DWORD* pdwInputMin,
+    DWORD* pdwInputMax,
+    DWORD* pdwOutputMin,
+    DWORD* pdwOutputMax)
+{
+    if (pdwInputMin == 0)
+        return E_POINTER;
+
+    if (pdwInputMax == 0)
+        return E_POINTER;
+
+    if (pdwOutputMin == 0)
+        return E_POINTER;
+
+    if (pdwOutputMax == 0)
+        return E_POINTER;
+
+    DWORD& dwInputMin = *pdwInputMin;
+    dwInputMin = 1;
+
+    DWORD& dwInputMax = *pdwInputMax;
+    dwInputMax = 1;
+
+    DWORD& dwOutputMin = *pdwOutputMin;
+    dwOutputMin = 1;
+
+    DWORD& dwOutputMax = *pdwOutputMax;
+    dwOutputMax = 1;
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetStreamCount(
+    DWORD* pcInputStreams,
+    DWORD* pcOutputStreams)
+{
+    if (pcInputStreams == 0)
+        return E_POINTER;
+
+    if (pcOutputStreams == 0)
+        return E_POINTER;
+
+    DWORD& cInputStreams = *pcInputStreams;
+    cInputStreams = 1;
+
+    DWORD& cOutputStreams = *pcOutputStreams;
+    cOutputStreams = 1;
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetStreamIDs(
+    DWORD,
+    DWORD* pdwInputIDs,
+    DWORD,
+    DWORD* pdwOutputIDs)
+{
+    if (pdwInputIDs)
+        *pdwInputIDs = 0;
+
+    if (pdwOutputIDs)
+        *pdwOutputIDs = 0;
+
+    return E_NOTIMPL;
+}
+
+
+HRESULT WebmMfVp8Dec::GetInputStreamInfo(
+    DWORD dwInputStreamID,
+    MFT_INPUT_STREAM_INFO* pStreamInfo)
+{
+    if (pStreamInfo == 0)
+        return E_POINTER;
+
+    if (dwInputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    MFT_INPUT_STREAM_INFO& info = *pStreamInfo;
+
+    //LONGLONG hnsMaxLatency;
+    //DWORD dwFlags;
+    //DWORD cbSize;
+    //DWORD cbMaxLookahead;
+    //DWORD cbAlignment;
+
+    info.cbMaxLookahead = 0;
+    info.hnsMaxLatency = 0;  //TODO: Is 0 correct?
+    //TODO: does lag-in-frames matter here?
+    //See "_MFT_INPUT_STREAM_INFO_FLAGS Enumeration" for more info:
+    //http://msdn.microsoft.com/en-us/library/ms703975%28v=VS.85%29.aspx
+
+    //enum _MFT_INPUT_STREAM_INFO_FLAGS
+    // { MFT_INPUT_STREAM_WHOLE_SAMPLES = 0x1,
+    // MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER = 0x2,
+    // MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE = 0x4,
+    // MFT_INPUT_STREAM_HOLDS_BUFFERS    = 0x8,
+    // MFT_INPUT_STREAM_DOES_NOT_ADDREF = 0x100,
+    // MFT_INPUT_STREAM_REMOVABLE= 0x200,
+    // MFT_INPUT_STREAM_OPTIONAL = 0x400,
+    // MFT_INPUT_STREAM_PROCESSES_IN_PLACE = 0x800
+    // };
+
+    info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES;
+                   //MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;
+                   //MFT_INPUT_STREAM_DOES_NOT_ADDREF;
+
+    info.cbSize = 0;       //input size is variable
+    info.cbAlignment = 0;  //no specific alignment requirements
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetOutputStreamInfo(
+    DWORD dwOutputStreamID,
+    MFT_OUTPUT_STREAM_INFO* pStreamInfo)
+{
+    if (pStreamInfo == 0)
+        return E_POINTER;
+
+    if (dwOutputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    Lock lock;
+
+    const HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    MFT_OUTPUT_STREAM_INFO& info = *pStreamInfo;
+
+    //enum _MFT_OUTPUT_STREAM_INFO_FLAGS
+    //  {   MFT_OUTPUT_STREAM_WHOLE_SAMPLES = 0x1,
+       // MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER    = 0x2,
+       // MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE   = 0x4,
+       // MFT_OUTPUT_STREAM_DISCARDABLE = 0x8,
+       // MFT_OUTPUT_STREAM_OPTIONAL    = 0x10,
+       // MFT_OUTPUT_STREAM_PROVIDES_SAMPLES    = 0x100,
+       // MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES = 0x200,
+       // MFT_OUTPUT_STREAM_LAZY_READ   = 0x400,
+       // MFT_OUTPUT_STREAM_REMOVABLE   = 0x800
+    //  };
+
+    //see Decoder sample in the SDK
+    //decoder.cc
+
+    //The API says that the only flag that is meaningful prior to SetOutputType
+    //is the OPTIONAL flag.  We need the frame dimensions, and the stride,
+    //in order to calculte the cbSize value.
+
+    info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES |
+                   MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
+                   MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
+
+    FrameSize size;
+
+    info.cbSize = GetOutputBufferSize(size);
+    info.cbAlignment = 0;
+
+    return S_OK;
+}
+
+
+DWORD WebmMfVp8Dec::GetOutputBufferSize(FrameSize& s) const
+{
+    //MFT was already locked by caller
+
+    //TODO: for now, assume width and height are specified
+    //via the input media type.
+
+    if (m_pInputMediaType == 0)
+        return 0;
+
+    HRESULT hr = MFGetAttributeSize(
+                    m_pInputMediaType,
+                    MF_MT_FRAME_SIZE,
+                    &s.width,
+                    &s.height);
+
+    assert(SUCCEEDED(hr));
+
+    const DWORD w = s.width;
+    assert(w);
+
+    const DWORD h = s.height;
+    assert(h);
+
+    const DWORD cb = w*h + 2*(((w+1)/2)*((h+1)/2));
+
+    //TODO: this result does not account for stride
+
+    return cb;
+}
+
+
+HRESULT WebmMfVp8Dec::GetAttributes(IMFAttributes** pp)
+{
+    if (pp)
+        *pp = 0;
+
+    return E_NOTIMPL;
+}
+
+
+HRESULT WebmMfVp8Dec::GetInputStreamAttributes(
+    DWORD,
+    IMFAttributes** pp)
+{
+    if (pp)
+        *pp = 0;
+
+    return E_NOTIMPL;
+}
+
+
+HRESULT WebmMfVp8Dec::GetOutputStreamAttributes(
+    DWORD,
+    IMFAttributes** pp)
+{
+    if (pp)
+        *pp = 0;
+
+    return E_NOTIMPL;
+}
+
+
+HRESULT WebmMfVp8Dec::DeleteInputStream(DWORD)
+{
+    return E_NOTIMPL;
+}
+
+
+HRESULT WebmMfVp8Dec::AddInputStreams(
+    DWORD,
+    DWORD*)
+{
+    return E_NOTIMPL;
+}
+
+
+HRESULT WebmMfVp8Dec::GetInputAvailableType(
+    DWORD dwInputStreamID,
+    DWORD dwTypeIndex,
+    IMFMediaType** pp)
+{
+     if (pp)
+        *pp = 0;
+
+    if (dwInputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    if (dwTypeIndex > 0)
+        return MF_E_NO_MORE_TYPES;
+
+    if (pp == 0)
+        return E_POINTER;
+
+    IMFMediaType*& pmt = *pp;
+
+    HRESULT hr = MFCreateMediaType(&pmt);
+    assert(SUCCEEDED(hr));
+    assert(pmt);
+
+    hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
+    assert(SUCCEEDED(hr));
+
+    hr = pmt->SetGUID(MF_MT_SUBTYPE, WebmTypes::MEDIASUBTYPE_VP80);
+    assert(SUCCEEDED(hr));
+
+    hr = pmt->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, FALSE);
+    assert(SUCCEEDED(hr));
+
+    hr = pmt->SetUINT32(MF_MT_COMPRESSED, TRUE);
+    assert(SUCCEEDED(hr));
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetOutputAvailableType(
+    DWORD dwOutputStreamID,
+    DWORD dwTypeIndex,
+    IMFMediaType** pp)
+{
+     if (pp)
+        *pp = 0;
+
+    if (dwOutputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    enum { subtype_count = 3 };
+
+    if (dwTypeIndex >= subtype_count)
+        return MF_E_NO_MORE_TYPES;
+
+    if (pp == 0)
+        return E_POINTER;
+
+    IMFMediaType*& pmt = *pp;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    hr = MFCreateMediaType(&pmt);
+    assert(SUCCEEDED(hr));
+    assert(pmt);
+
+    hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
+    assert(SUCCEEDED(hr));
+
+    const GUID subtypes[subtype_count] =
+    {
+        MFVideoFormat_NV12,
+        MFVideoFormat_YV12,
+        MFVideoFormat_IYUV
+    };
+
+    const GUID& subtype = subtypes[dwTypeIndex];
+
+    hr = pmt->SetGUID(MF_MT_SUBTYPE, subtype);
+    assert(SUCCEEDED(hr));
+
+    hr = pmt->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+    assert(SUCCEEDED(hr));
+
+    hr = pmt->SetUINT32(MF_MT_COMPRESSED, FALSE);
+    assert(SUCCEEDED(hr));
+
+    if (m_pInputMediaType == 0)  //nothing else we can say
+        return S_OK;
+
+    FrameRate r;
+
+    hr = r.AssignFrom(m_pInputMediaType);
+
+    if (hr == S_OK)  //means attribute was set, and its value is valid
+    {
+        //odbgstream os;
+        //os << "\nvp8dec: num=" << r.m_numerator
+        //   << " den=" << r.m_denominator;
+        //
+        //const float rate = float(r.m_numerator) / float(r.m_denominator);
+        //os << rate << '\n' << endl;
+
+        //TODO: a simpler way to handle this is to copy
+        //an item directly from media type to media type (assuming
+        //the MF API provides such a function), instead of going
+        //through this intermediate FrameRate value.
+
+        hr = r.CopyTo(pmt);
+        assert(SUCCEEDED(hr));
+    }
+
+    FrameSize s;
+
+    hr = MFGetAttributeSize(
+            m_pInputMediaType,
+            MF_MT_FRAME_SIZE,
+            &s.width,
+            &s.height);
+
+    assert(SUCCEEDED(hr));
+    assert(s.width);
+    assert(s.height);
+
+    hr = MFSetAttributeSize(
+            pmt,
+            MF_MT_FRAME_SIZE,
+            s.width,
+            s.height);
+
+    assert(SUCCEEDED(hr));
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::SetInputType(
+    DWORD dwInputStreamID,
+    IMFMediaType* pmt,
+    DWORD dwFlags)
+{
+    if (dwInputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (pmt == 0)
+    {
+        //TODO: disallow this case while we're playing?
+
+        if (m_pInputMediaType)
+        {
+            const ULONG n = m_pInputMediaType->Release();
+            n;
+            assert(n == 0);
+
+            m_pInputMediaType = 0;
+
+            const vpx_codec_err_t e = vpx_codec_destroy(&m_ctx);
+            e;
+            assert(e == VPX_CODEC_OK);
+        }
+
+        if (m_pOutputMediaType)
+        {
+            const ULONG n = m_pOutputMediaType->Release();
+            n;
+            assert(n == 0);
+
+            m_pOutputMediaType = 0;
+        }
+
+        return S_OK;
+    }
+
+    //TODO: handle the case when already have an input media type
+    //or output media type, or are already playing.  I don't
+    //think we can change media types while we're playing.
+
+    GUID g;
+
+    hr = pmt->GetMajorType(&g);
+
+    if (FAILED(hr))
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (g != MFMediaType_Video)
+        return MF_E_INVALIDMEDIATYPE;
+
+    hr = pmt->GetGUID(MF_MT_SUBTYPE, &g);
+
+    if (FAILED(hr))
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (g != WebmTypes::MEDIASUBTYPE_VP80)
+        return MF_E_INVALIDMEDIATYPE;
+
+    //hr = pmt->SetUINT32(MF_MT_COMPRESSED, FALSE);
+    //assert(SUCCEEDED(hr));
+
+    FrameRate r;
+
+    hr = r.AssignFrom(pmt);
+
+    if (FAILED(hr))  //input mt has framerate, but it's bad
+        return hr;
+
+    r.CopyTo(m_frame_rate);
+
+    //odbgstream os;
+    //os << "\nvp8dec: framerate=" << m_frame_rate << '\n' << endl;
+
+    FrameSize s;
+
+    hr = MFGetAttributeSize(
+            pmt,
+            MF_MT_FRAME_SIZE,
+            &s.width,
+            &s.height);
+
+    if (FAILED(hr))
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (s.width == 0)
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (s.width % 2)  //TODO
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (s.height == 0)
+        return MF_E_INVALIDMEDIATYPE;
+
+    //TODO: do we need to check for odd height too?
+
+    if (dwFlags & MFT_SET_TYPE_TEST_ONLY)
+        return S_OK;
+
+    if (m_pInputMediaType)
+    {
+        hr = m_pInputMediaType->DeleteAllItems();
+        assert(SUCCEEDED(hr));
+
+        const vpx_codec_err_t e = vpx_codec_destroy(&m_ctx);
+        e;
+        assert(e == VPX_CODEC_OK);
+    }
+    else
+    {
+        hr = MFCreateMediaType(&m_pInputMediaType);
+
+        if (FAILED(hr))
+            return hr;
+    }
+
+    hr = pmt->CopyAllItems(m_pInputMediaType);
+
+    if (FAILED(hr))
+        return hr;
+
+    //m_frame_rate = r;
+
+    //TODO: should this really be done here?
+
+    vpx_codec_iface_t& vp8 = vpx_codec_vp8_dx_algo;
+
+    const int flags = 0;  //TODO: VPX_CODEC_USE_POSTPROC;
+
+    const vpx_codec_err_t err = vpx_codec_dec_init(
+                                    &m_ctx,
+                                    &vp8,
+                                    0,
+                                    flags);
+
+    if (err == VPX_CODEC_MEM_ERROR)
+        return E_OUTOFMEMORY;
+
+    if (err != VPX_CODEC_OK)
+        return E_FAIL;
+
+    //const HRESULT hr = OnApplyPostProcessing();
+
+    if (m_pOutputMediaType)
+    {
+        //TODO: Is this the correct behavior?
+
+        const ULONG n = m_pOutputMediaType->Release();
+        n;
+        assert(n == 0);
+
+        m_pOutputMediaType = 0;
+    }
+
+#if 0
+    //TODO:
+    //We could update the preferred ("available") output media types,
+    //now that we know the frame rate and frame size, etc.
+
+    hr = MFCreateMediaType(&m_pOutputMediaType);
+    assert(SUCCEEDED(hr));  //TODO
+
+    hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
+    assert(SUCCEEDED(hr));  //TODO
+
+    hr = pmt->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12);
+    assert(SUCCEEDED(hr));  //TODO
+
+    hr = pmt->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+    assert(SUCCEEDED(hr));  //TODO
+
+    hr = pmt->SetUINT32(MF_MT_COMPRESSED, FALSE);
+    assert(SUCCEEDED(hr));  //TODO
+
+    if (r.numerator)  //means "has been set"
+    {
+        hr = MFSetAttributeRatio(
+                m_pOutputMediaType,
+                MF_MT_FRAME_RATE,
+                r.numerator,
+                r.denominator);
+
+        assert(SUCCEEDED(hr));  //TODO
+    }
+
+    hr = MFSetAttributeSize(
+            m_pOutputMediaType,
+            MF_MT_FRAME_SIZE,
+            s.width,
+            s.height);
+
+    assert(SUCCEEDED(hr));  //TODO
+#endif
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::SetOutputType(
+    DWORD dwOutputStreamID,
+    IMFMediaType* pmt,
+    DWORD dwFlags)
+{
+    if (dwOutputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (pmt == 0)
+    {
+        //TODO: disallow this case while we're playing?
+
+        if (m_pOutputMediaType)
+        {
+            const ULONG n = m_pOutputMediaType->Release();
+            n;
+            assert(n == 0);
+
+            m_pOutputMediaType = 0;
+        }
+
+        return S_OK;
+    }
+
+    if (m_pInputMediaType == 0)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    GUID g;
+
+    hr = pmt->GetMajorType(&g);
+
+    if (FAILED(hr))
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (g != MFMediaType_Video)
+        return MF_E_INVALIDMEDIATYPE;
+
+    hr = pmt->GetGUID(MF_MT_SUBTYPE, &g);
+
+    if (FAILED(hr))
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (g == MFVideoFormat_NV12)
+        __noop;
+    else if (g == MFVideoFormat_YV12)
+        __noop;
+    else if (g == MFVideoFormat_IYUV)
+        __noop;
+    else  //TODO: add I420 support
+        return MF_E_INVALIDMEDIATYPE;
+
+    //hr = pmt->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+    //assert(SUCCEEDED(hr));
+
+    //hr = pmt->SetUINT32(MF_MT_COMPRESSED, FALSE);
+    //assert(SUCCEEDED(hr));
+
+    FrameRate r_out;
+
+    hr = r_out.AssignFrom(pmt);
+
+    if (FAILED(hr))  //output type has value, but it's not valid
+        return hr;
+
+    if (hr == S_OK)  //output type has value, and it's valid
+    {
+        FrameRate r_in;
+
+        hr = r_in.AssignFrom(m_pInputMediaType);
+
+        if ((hr == S_OK) && !r_in.Match(r_out))
+            return MF_E_INVALIDMEDIATYPE;
+    }
+
+    FrameSize s_out;
+
+    hr = MFGetAttributeSize(
+            pmt,
+            MF_MT_FRAME_SIZE,
+            &s_out.width,
+            &s_out.height);
+
+    if (SUCCEEDED(hr))
+    {
+        if (s_out.width == 0)
+            return MF_E_INVALIDMEDIATYPE;
+
+        //TODO: check whether width is odd
+
+        if (s_out.height == 0)
+            return MF_E_INVALIDMEDIATYPE;
+
+        FrameSize s_in;
+
+        hr = MFGetAttributeSize(
+                m_pInputMediaType,
+                MF_MT_FRAME_SIZE,
+                &s_in.width,
+                &s_in.height);
+
+        assert(SUCCEEDED(hr));
+
+        if (s_out.width != s_in.width)
+            return MF_E_INVALIDMEDIATYPE;
+
+        if (s_out.height != s_in.height)
+            return MF_E_INVALIDMEDIATYPE;
+    }
+
+    if (dwFlags & MFT_SET_TYPE_TEST_ONLY)
+        return S_OK;
+
+    if (m_pOutputMediaType)
+    {
+        hr = m_pOutputMediaType->DeleteAllItems();
+        assert(SUCCEEDED(hr));
+    }
+    else
+    {
+        hr = MFCreateMediaType(&m_pOutputMediaType);
+
+        if (FAILED(hr))
+            return hr;
+    }
+
+    hr = pmt->CopyAllItems(m_pOutputMediaType);
+
+    if (FAILED(hr))
+        return hr;
+
+    //TODO: do something
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetInputCurrentType(
+    DWORD dwInputStreamID,
+    IMFMediaType** pp)
+{
+    if (dwInputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    if (pp)
+        *pp = 0;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (m_pInputMediaType == 0)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    IMFMediaType*& p = *pp;
+
+    hr = MFCreateMediaType(&p);
+
+    if (FAILED(hr))
+        return hr;
+
+    return m_pInputMediaType->CopyAllItems(p);
+}
+
+
+HRESULT WebmMfVp8Dec::GetOutputCurrentType(
+    DWORD dwOutputStreamID,
+    IMFMediaType** pp)
+{
+    if (dwOutputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    if (pp)
+        *pp = 0;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    //TODO: synthesize from input media type?
+
+    if (m_pOutputMediaType == 0)  //TODO: liberalize?
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    IMFMediaType*& p = *pp;
+
+    hr = MFCreateMediaType(&p);
+
+    if (FAILED(hr))
+        return hr;
+
+    return m_pOutputMediaType->CopyAllItems(p);
+}
+
+
+HRESULT WebmMfVp8Dec::GetInputStatus(
+    DWORD dwInputStreamID,
+    DWORD* pdwFlags)
+{
+    if (dwInputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (m_pInputMediaType == 0)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    //TODO: check output media type too?
+
+    if (pdwFlags == 0)
+        return E_POINTER;
+
+    DWORD& dwFlags = *pdwFlags;
+
+    dwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;  //because we always queue
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetOutputStatus(DWORD*)
+{
+#if 1
+    return E_NOTIMPL;
+#else
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (m_pInputMediaType == 0)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    //TODO: check output media type too?
+
+    if (pdwFlags == 0)
+        return E_POINTER;
+
+    DWORD& dwFlags = *pdwFlags;
+
+    const vpx_image_t* const f = vpx_codec_get_frame(&m_ctx, &m_iter);
+
+    dwFlags = f ? MFT_OUTPUT_STATUS_SAMPLE_READY : 0;
+
+    //TODO: alternatively, we could return E_NOTIMPL, which
+    //forces client to call ProcessOutput to determine whether
+    //a sample is ready.
+
+    return S_OK;
+#endif
+}
+
+
+HRESULT WebmMfVp8Dec::SetOutputBounds(
+    LONGLONG /* hnsLowerBound */ ,
+    LONGLONG /* hnsUpperBound */ )
+{
+    return E_NOTIMPL;  //TODO
+}
+
+
+HRESULT WebmMfVp8Dec::ProcessEvent(
+    DWORD dwInputStreamID,
+    IMFMediaEvent* /* pEvent */ )
+{
+    if (dwInputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+#if 0 //def _DEBUG
+    if (pEvent)
+    {
+        MediaEventType t;
+
+        HRESULT hr = pEvent->GetType(&t);
+        assert(SUCCEEDED(hr));
+
+        odbgstream os;
+        os << "WebmMfVp8Dec::ProcessEvent: type=" << t << endl;
+    }
+#endif
+
+    return E_NOTIMPL;  //TODO
+}
+
+
+HRESULT WebmMfVp8Dec::ProcessMessage(
+    MFT_MESSAGE_TYPE m,
+    ULONG_PTR)
+{
+#if 0 //def _DEBUG
+    odbgstream os;
+    os << "WebmMfVp8Dec::ProcessMessage(samples.size="
+       << m_samples.size() << "): ";
+#endif
+
+    switch (m)
+    {
+        case MFT_MESSAGE_COMMAND_FLUSH:
+#if 0 //def _DEBUG
+            os << "COMMAND_FLUSH" << endl;
+#endif
+
+        //http://msdn.microsoft.com/en-us/library/dd940419%28v=VS.85%29.aspx
+
+            Flush();
+            return S_OK;
+
+        case MFT_MESSAGE_COMMAND_DRAIN:
+#if 0 //def _DEBUG
+            os << "COMMAND_DRAIN" << endl;
+#endif
+
+        //http://msdn.microsoft.com/en-us/library/dd940418%28v=VS.85%29.aspx
+
+        //TODO: input stream does not accept input in the MFT processes all
+        //data from previous calls to ProcessInput.
+
+            return S_OK;
+
+        case MFT_MESSAGE_SET_D3D_MANAGER:
+#if 0 //def _DEBUG
+            os << "SET_D3D" << endl;
+#endif
+
+            return S_OK;
+
+        case MFT_MESSAGE_DROP_SAMPLES:
+#if 0 //def _DEBUG
+            os << "DROP_SAMPLES" << endl;
+#endif
+
+            return S_OK;
+
+        case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+#if 0 //def _DEBUG
+            os << "NOTIFY_BEGIN_STREAMING" << endl;
+#endif
+
+        //http://msdn.microsoft.com/en-us/library/dd940421%28v=VS.85%29.aspx
+
+        //TODO: init decoder library here, instead of during SetInputType
+
+            return S_OK;
+
+        case MFT_MESSAGE_NOTIFY_END_STREAMING:
+#if 0 //def _DEBUG
+            os << "NOTIFY_END_STREAMING" << endl;
+#endif
+
+        //http://msdn.microsoft.com/en-us/library/dd940423%28v=VS.85%29.aspx
+
+        //NOTE: flush is not performed here
+
+            return S_OK;
+
+        case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+#if 0 //def _DEBUG
+            os << "NOTIFY_EOS" << endl;
+#endif
+
+        //http://msdn.microsoft.com/en-us/library/dd940422%28v=VS.85%29.aspx
+
+        //TODO: set discontinuity flag on first sample after this
+
+            return S_OK;
+
+        case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
+#if 0 //def _DEBUG
+            os << "NOTIFY_START_OF_STREAM" << endl;
+#endif
+
+            return S_OK;
+
+        case MFT_MESSAGE_COMMAND_MARKER:
+#if 0 //def _DEBUG
+            os << "COMMAND_MARKER" << endl;
+#endif
+
+            return S_OK;
+
+        default:
+            return S_OK;
+    }
+}
+
+
+HRESULT WebmMfVp8Dec::ProcessInput(
+    DWORD dwInputStreamID,
+    IMFSample* pSample,
+    DWORD)
+{
+    if (dwInputStreamID != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+
+    if (pSample == 0)
+        return E_INVALIDARG;
+
+    DWORD count;
+
+    HRESULT hr = pSample->GetBufferCount(&count);
+    assert(SUCCEEDED(hr));
+
+    if (count == 0)  //weird
+        return S_OK;
+
+    //if (count > 1)
+    //    return E_INVALIDARG;
+
+    //TODO: check duration
+    //TODO: check timestamp
+
+    Lock lock;
+
+    hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (m_pInputMediaType == 0)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    if (m_pOutputMediaType == 0)  //TODO: need this check here?
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    pSample->AddRef();
+
+    m_samples.push_back(SampleInfo());
+
+    SampleInfo& i = m_samples.back();
+
+    i.pSample = pSample;
+    i.dwBuffer = 0;
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::ProcessOutput(
+    DWORD dwFlags,
+    DWORD cOutputBufferCount,
+    MFT_OUTPUT_DATA_BUFFER* pOutputSamples,
+    DWORD* pdwStatus)
+{
+    if (pdwStatus)
+        *pdwStatus = 0;
+
+    if (dwFlags)
+        return E_INVALIDARG;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (m_pInputMediaType == 0)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    if (m_pOutputMediaType == 0)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+    if (cOutputBufferCount == 0)
+        return E_INVALIDARG;
+
+    if (pOutputSamples == 0)
+        return E_INVALIDARG;
+
+    const MFT_OUTPUT_DATA_BUFFER& data = pOutputSamples[0];
+    //data.dwStreamID should equal 0, but we ignore it
+
+    for (;;)
+    {
+        hr = Decode(data.pSample);
+
+        if (FAILED(hr) || (hr == S_OK))
+            return hr;
+    }
+}
+
+
+HRESULT WebmMfVp8Dec::Decode(IMFSample* pSample_out)
+{
+    if (pSample_out == 0)
+        return E_INVALIDARG;
+
+    if (m_samples.empty())
+        return MF_E_TRANSFORM_NEED_MORE_INPUT;
+
+    HRESULT hr;
+    LONGLONG time, duration;
+
+    {
+        SampleInfo& i = m_samples.front();
+        assert(i.pSample);
+
+        UINT32 iKey;
+
+        hr = i.pSample->GetUINT32(MFSampleExtension_CleanPoint, &iKey);
+
+        const bool bKey = SUCCEEDED(hr) && (iKey != FALSE);
+
+        //TODO: this is an optimization oppurtunity, since it would
+        //optimize-away the expense of decoding too (not the expense
+        //of mere rendering, which is what other modes optimize away).
+        //It's tricky to implement since if we
+        //transition OUT of DROP_5 mode, then it's possible that we
+        //we're in the middle of a GOP and so we cannot decode
+        //again until we see the next keyframe.  In other modes, we
+        //decode every frame (we are suppressing the rendering, not
+        //decode), so a state transition between modes is not an issue.
+        //For now, just decompress every frame.
+        //
+        //if (!bKey && (m_drop_mode == MF_DROP_MODE_5))
+        //{
+        //    i.pSample->Release();
+        //    i.pSample = 0;
+        //
+        //    m_samples.pop_front();
+        //
+        //    return S_FALSE;
+        //}
+        //END TODO.
+
+        UINT32 bPreroll;
+
+        hr = i.pSample->GetUINT32(WebmTypes::WebMSample_Preroll, &bPreroll);
+
+        if (SUCCEEDED(hr) && (bPreroll != FALSE))  //preroll frame
+        {
+            hr = i.DecodeAll(m_ctx);
+
+            i.pSample->Release();
+            i.pSample = 0;
+
+            m_samples.pop_front();
+
+            if (FAILED(hr))  //bad decode
+                return hr;
+
+            ReplenishDropBudget();
+            return S_FALSE;  //throw away this sample
+        }
+
+        hr = i.DecodeOne(m_ctx, time, duration);
+
+        if (FAILED(hr) || (hr != S_OK))
+        {
+            i.pSample->Release();
+            i.pSample = 0;
+
+            m_samples.pop_front();
+
+            if (FAILED(hr))  //bad decode
+                return hr;
+        }
+
+        if (m_drop_mode == MF_DROP_MODE_NONE)
+            __noop;  //we're not throwing away frames
+
+        else if (m_drop_mode >= MF_DROP_MODE_5)
+        {
+            if (!bKey)
+                return S_FALSE;  //throw away this sample
+        }
+        else if (bKey || (m_drop_budget > 1))
+            --m_drop_budget;  //spend out budget to render this frame
+
+        else
+        {
+            ReplenishDropBudget();
+            return S_FALSE;  //throw away this sample
+        }
+    }
+
+    DWORD count_out;
+
+    hr = pSample_out->GetBufferCount(&count_out);
+
+    if (SUCCEEDED(hr) && (count_out != 1))  //TODO: handle this?
+        return E_INVALIDARG;
+
+    IMFMediaBufferPtr buf_out;
+
+    hr = pSample_out->GetBufferByIndex(0, &buf_out);
+
+    if (FAILED(hr) || !bool(buf_out))
+        return E_INVALIDARG;
+
+    GUID subtype;
+
+    hr = m_pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &subtype);
+    assert(SUCCEEDED(hr));
+
+    //TODO:
+    //MFVideoFormat_I420
+
+    FrameSize frame_size;
+
+    const DWORD cbFrameLen = GetOutputBufferSize(frame_size);
+    assert(cbFrameLen > 0);
+
+    //The sequence of querying for the output buffer is described on
+    //the page "Uncompressed Video Buffers".
+    //http://msdn.microsoft.com/en-us/library/aa473821%28v=VS.85%29.aspx
+
+    IMF2DBuffer* buf2d_out;
+
+    hr = buf_out->QueryInterface(&buf2d_out);
+
+    if (SUCCEEDED(hr))
+    {
+        assert(buf2d_out);
+
+        BYTE* ptr_out;
+        LONG stride_out;
+
+        hr = buf2d_out->Lock2D(&ptr_out, &stride_out);
+        assert(SUCCEEDED(hr));
+        assert(ptr_out);
+        assert(stride_out > 0);  //top-down DIBs are positive, right?
+
+        const HRESULT hrGetFrame = GetFrame(ptr_out, stride_out, subtype);
+
+        //TODO: set output buffer length?
+
+        hr = buf2d_out->Unlock2D();
+        assert(SUCCEEDED(hr));
+
+        buf2d_out->Release();
+        buf2d_out = 0;
+
+        if (FAILED(hrGetFrame) || (hrGetFrame != S_OK))
+            return hrGetFrame;
+    }
+    else
+    {
+        BYTE* ptr_out;
+        DWORD cbMaxLen;
+
+        hr = buf_out->Lock(&ptr_out, &cbMaxLen, 0);
+        assert(SUCCEEDED(hr));
+        assert(ptr_out);
+        assert(cbMaxLen >= cbFrameLen);
+
+        //TODO: verify stride of output buffer
+        //The page "Uncompressed Video Buffers" here:
+        //http://msdn.microsoft.com/en-us/library/aa473821%28v=VS.85%29.aspx
+        //explains how to calculate the "minimum stride":
+        //  MF_MT_DEFAULT_STRIDE
+        //  or, MFGetStrideForBitmapInfoHeader
+        //  or, calculate it yourself
+
+        INT32 stride_out;
+
+        hr = pSample_out->GetUINT32(
+                MF_MT_DEFAULT_STRIDE,
+                (UINT32*)&stride_out);
+
+        if (SUCCEEDED(hr) && (stride_out != 0))
+            assert(stride_out > 0);
+        else
+        {
+            const DWORD fcc = subtype.Data1;
+
+            const DWORD w = frame_size.width;
+            LONG stride_out_;
+
+            hr = MFGetStrideForBitmapInfoHeader(fcc, w, &stride_out_);
+
+            if (SUCCEEDED(hr) && (stride_out_ != 0))
+            {
+                assert(stride_out_ > 0);
+                stride_out = stride_out_;
+            }
+            else
+            {
+                assert((w % 2) == 0);  //TODO
+                stride_out = w;  //TODO: is this correct???
+            }
+        }
+
+        const HRESULT hrGetFrame = GetFrame(ptr_out, stride_out, subtype);
+
+        hr = buf_out->Unlock();
+        assert(SUCCEEDED(hr));
+
+        if (FAILED(hrGetFrame) || (hrGetFrame != S_OK))
+            return hrGetFrame;
+
+        hr = buf_out->SetCurrentLength(cbFrameLen);
+        assert(SUCCEEDED(hr));
+    }
+
+    if (time >= 0)
+    {
+        hr = pSample_out->SetSampleTime(time);
+        assert(SUCCEEDED(hr));
+    }
+
+    if (duration >= 0)
+    {
+        hr = pSample_out->SetSampleDuration(duration);
+        assert(SUCCEEDED(hr));
+    }
+
+    return S_OK;  //done
+}
+
+
+HRESULT WebmMfVp8Dec::GetFrame(
+    BYTE* pOutBuf,
+    ULONG strideOut,
+    const GUID& subtype)
+{
+    assert(pOutBuf);
+    assert(strideOut);
+    assert((strideOut % 2) == 0);  //TODO: resolve this issue
+
+    vpx_codec_iter_t iter = 0;
+
+    const vpx_image_t* const f = vpx_codec_get_frame(&m_ctx, &iter);
+
+    if (f == 0)  //alt-ref
+        return S_FALSE;  //tell caller to pop this buffer and call me back
+
+    //Y
+
+    const BYTE* pInY = f->planes[VPX_PLANE_Y];
+    assert(pInY);
+
+    unsigned int wIn = f->d_w;
+    unsigned int hIn = f->d_h;
+
+    BYTE* pOut = pOutBuf;
+
+    const int strideInY = f->stride[VPX_PLANE_Y];
+
+    for (unsigned int y = 0; y < hIn; ++y)
+    {
+        memcpy(pOut, pInY, wIn);
+        pInY += strideInY;
+        pOut += strideOut;
+    }
+
+    const BYTE* pInV = f->planes[VPX_PLANE_V];
+    assert(pInV);
+
+    const int strideInV = f->stride[VPX_PLANE_V];
+
+    const BYTE* pInU = f->planes[VPX_PLANE_U];
+    assert(pInU);
+
+    const int strideInU = f->stride[VPX_PLANE_U];
+
+    wIn = (wIn + 1) / 2;
+    hIn = (hIn + 1) / 2;
+
+    if (subtype == MFVideoFormat_NV12)
+    {
+        for (unsigned int y = 0; y < hIn; ++y)
+        {
+            const BYTE* u = pInU;   //src
+            const BYTE* v = pInV;   //src
+            BYTE* uv = pOut;        //dst
+
+            for (unsigned int idx = 0; idx < wIn; ++idx)  //uv
+            {
+                *uv++ = *u++;  //Cb
+                *uv++ = *v++;  //Cr
+            }
+
+            pInU += strideInU;
+            pInV += strideInV;
+            pOut += strideOut;
+        }
+    }
+    else if (subtype == MFVideoFormat_YV12)
+    {
+        strideOut /= 2;
+
+        //V
+
+        for (unsigned int y = 0; y < hIn; ++y)
+        {
+            memcpy(pOut, pInV, wIn);
+            pInV += strideInV;
+            pOut += strideOut;
+        }
+
+        //U
+
+        for (unsigned int y = 0; y < hIn; ++y)
+        {
+            memcpy(pOut, pInU, wIn);
+            pInU += strideInU;
+            pOut += strideOut;
+        }
+    }
+    else
+    {
+        assert(subtype == MFVideoFormat_IYUV);
+
+        strideOut /= 2;
+
+        //U
+
+        for (unsigned int y = 0; y < hIn; ++y)
+        {
+            memcpy(pOut, pInU, wIn);
+            pInU += strideInU;
+            pOut += strideOut;
+        }
+
+        //V
+
+        for (unsigned int y = 0; y < hIn; ++y)
+        {
+            memcpy(pOut, pInV, wIn);
+            pInV += strideInV;
+            pOut += strideOut;
+        }
+    }
+
+    const vpx_image_t* const f2 = vpx_codec_get_frame(&m_ctx, &iter);
+    f2;
+    assert(f2 == 0);
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::SetRate(BOOL bThin, float rate)
+{
+    //odbgstream os;
+    //os << "WebmMfVp8Dec::SetRate: bThin="
+    //   << boolalpha << (bThin ? true : false)
+    //   << " rate="
+    //   << rate
+    //   << endl;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    //if (m_pEvents == 0)
+    //    return MF_E_SHUTDOWN;
+
+    //if (bThin)
+    //    return MF_E_THINNING_UNSUPPORTED;  //TODO
+
+    if (rate < 0)
+        return MF_E_REVERSE_UNSUPPORTED;  //TODO
+
+    m_rate = rate;
+    m_bThin = bThin;
+
+    //reset drop mode when rate change
+
+    m_lag_sum = 0;
+    m_lag_count = 0;
+    m_lag_frames = 0;
+
+    hr = WebmMfVp8Dec::SetDropMode(MF_DROP_MODE_NONE);
+    assert(SUCCEEDED(hr));
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetRate(BOOL* pbThin, float* pRate)
+{
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    //if (m_pEvents == 0)
+    //    return MF_E_SHUTDOWN;
+
+    if (pbThin)
+        *pbThin = m_bThin;
+
+    if (pRate)  //return error when pRate ptr is NULL?
+        *pRate = m_rate;
+
+    //odbgstream os;
+    //os << "WebmMfVp8Dec::GetRate: bThin="
+    //   << boolalpha << m_bThin
+    //   << " rate="
+    //   << m_rate
+    //   << endl;
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetSlowestRate(
+    MFRATE_DIRECTION d,
+    BOOL /* bThin */ ,
+    float* pRate)
+{
+    //odbgstream os;
+    //os << "WebmMfVp8Dec::GetSlowestRate" << endl;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    //if (m_pEvents == 0)
+    //    return MF_E_SHUTDOWN;
+
+    if (d == MFRATE_REVERSE)
+        return MF_E_REVERSE_UNSUPPORTED;  //TODO
+
+    //if (bThin)
+    //    return MF_E_THINNING_UNSUPPORTED;  //TODO
+
+    if (pRate == 0)
+        return E_POINTER;
+
+    float& r = *pRate;
+    r = 0;  //?
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetFastestRate(
+    MFRATE_DIRECTION d,
+    BOOL /* bThin */ ,
+    float* pRate)
+{
+    //odbgstream os;
+    //os << "WebmMfSource::GetFastestRate" << endl;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    //if (m_pEvents == 0)
+    //    return MF_E_SHUTDOWN;
+
+    if (d == MFRATE_REVERSE)
+        return MF_E_REVERSE_UNSUPPORTED;  //TODO
+
+    //if (bThin)
+    //    return MF_E_THINNING_UNSUPPORTED;  //TODO
+
+    if (pRate == 0)
+        return E_POINTER;
+
+    float& r = *pRate;
+    r = 64;  //?
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::IsRateSupported(
+    BOOL /* bThin */ ,
+    float rate,
+    float* pNearestRate)
+{
+    //odbgstream os;
+    //os << "WebmMfVp8Dec::IsRateSupported: rate=" << rate << endl;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    //if (m_pEvents == 0)
+    //    return MF_E_SHUTDOWN;
+
+    //if (bThin)
+    //    return MF_E_THINNING_UNSUPPORTED;  //TODO
+
+    if (rate < 0)
+        return MF_E_REVERSE_UNSUPPORTED;  //TODO
+
+    //float int_part;
+    //const float frac_part = modf(rate, &int_part);
+
+    if (pNearestRate)
+        *pNearestRate = rate;
+
+    return S_OK;  //TODO
+}
+
+
+HRESULT WebmMfVp8Dec::GetService(
+    REFGUID sid,
+    REFIID iid,
+    LPVOID* ppv)
+{
+    if (sid == MF_RATE_CONTROL_SERVICE)
+        return WebmMfVp8Dec::QueryInterface(iid, ppv);
+
+    if (ppv)
+        *ppv = 0;
+
+    return MF_E_UNSUPPORTED_SERVICE;
+}
+
+
+void WebmMfVp8Dec::Flush()
+{
+    while (!m_samples.empty())
+    {
+        SampleInfo& i = m_samples.front();
+        assert(i.pSample);
+
+        i.pSample->Release();
+        i.pSample = 0;
+
+        m_samples.pop_front();
+    }
+}
+
+
+HRESULT WebmMfVp8Dec::SampleInfo::DecodeAll(vpx_codec_ctx_t& ctx)
+{
+    assert(pSample);
+
+    DWORD count;
+
+    HRESULT hr = pSample->GetBufferCount(&count);
+    assert(SUCCEEDED(hr));
+    assert(count > 0);
+
+    while (dwBuffer < count)
+    {
+        IMFMediaBufferPtr buf;
+
+        hr = pSample->GetBufferByIndex(dwBuffer, &buf);
+        assert(SUCCEEDED(hr));
+        assert(buf);
+
+        BYTE* ptr;
+        DWORD len;
+
+        hr = buf->Lock(&ptr, 0, &len);
+        assert(SUCCEEDED(hr));
+        assert(ptr);
+        assert(len);
+
+        const vpx_codec_err_t e = vpx_codec_decode(&ctx, ptr, len, 0, 0);
+
+        hr = buf->Unlock();
+        assert(SUCCEEDED(hr));
+
+        if (e != VPX_CODEC_OK)
+            return MF_E_INVALID_STREAM_DATA;
+
+        ++dwBuffer;  //consume this buffer
+    }
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::SampleInfo::DecodeOne(
+    vpx_codec_ctx_t& ctx,
+    LONGLONG& time,
+    LONGLONG& duration)
+{
+    assert(pSample);
+
+    DWORD count;
+
+    HRESULT hr = pSample->GetBufferCount(&count);
+    assert(SUCCEEDED(hr));
+    assert(count > 0);
+    assert(count > dwBuffer);
+
+    IMFMediaBufferPtr buf;
+
+    hr = pSample->GetBufferByIndex(dwBuffer, &buf);
+    assert(SUCCEEDED(hr));
+    assert(buf);
+
+    BYTE* ptr;
+    DWORD len;
+
+    hr = buf->Lock(&ptr, 0, &len);
+    assert(SUCCEEDED(hr));
+    assert(ptr);
+    assert(len);
+
+    const vpx_codec_err_t e = vpx_codec_decode(&ctx, ptr, len, 0, 0);
+
+    hr = buf->Unlock();
+    assert(SUCCEEDED(hr));
+
+    if (e != VPX_CODEC_OK)
+        return MF_E_INVALID_STREAM_DATA;
+
+    LONGLONG t;
+
+    hr = pSample->GetSampleTime(&t);
+
+    if (FAILED(hr) || (t < 0))
+    {
+        time = -1;
+        duration = -1;
+    }
+    else
+    {
+        LONGLONG d;
+
+        hr = pSample->GetSampleDuration(&d);
+
+        if (FAILED(hr) || (d <= 0))
+        {
+            if (dwBuffer == 0)  //first buffer
+                time = t;
+            else
+                time = -1;
+
+            duration = -1;
+        }
+        else
+        {
+            duration = d / count;
+            time = t + dwBuffer * duration;
+        }
+    }
+
+    ++dwBuffer;  //consume this buffer
+    return (dwBuffer >= count) ? S_FALSE : S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::SetDropMode(MF_QUALITY_DROP_MODE d)
+{
+    if (d > MF_DROP_MODE_5)
+        return MF_E_NO_MORE_DROP_MODES;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    m_drop_mode = d;
+    m_drop_budget = 0;
+
+    //odbgstream os;
+    //os << "SetDropMode=" << m_drop_mode << endl;
+
+    return S_OK;
+
+    //we always keep keyframes ("cleanpoint")
+    //1: drop 1 out of every 2 frames
+    //2: drop 2 out of every 3 frames
+    //3: drop 3 out of every 4 frames
+    //4: drop 4 out of every 5 frames
+    //5: drop all delta frames
+    //
+    //alternatively:
+    //1: drop 1 out of every 16 = 2^4 = 2^(5-1)
+    //2: drop 1 out of every 8  = 2^3 = 2^(5-2) = 2 out of every 16
+    //3: drop 1 out of every 4  = 2^2 = 2^(5-3) = 4 out of every 16
+    //4: drop 1 out of every 2  = 2^1 = 2^(5-4) = 8 out of every 16
+    //5: drop all delta frames
+
+    //when we detect a keyframe, this resets the counter
+    //
+    //level 1:
+    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+    //                              x
+    //
+    //level 2:
+    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+    //              x               x
+    //
+    //level 3:
+    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+    //      x       x       x       x       x
+    //
+    //level 4:
+    //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+    //  x   x   x   x   x   x   x   x   x   x
+    //
+    //we could also tie this to framerate, e.g.
+    //1: drop 1 frame per second
+    //2: drop 1 frame per 1/2 sec
+    //3: drop 1 frame per 1/4 sec
+    //4: drop 1 frame per 1/8 sec
+    //5: drop all delta frames
+    //
+    //Give outselves a budget: the smaller the drop mode,
+    //the larger the budget.  Drop the first eligrable
+    //frame when our budget drops to 0.
+}
+
+
+void WebmMfVp8Dec::ReplenishDropBudget()
+{
+    if (m_drop_mode == MF_DROP_MODE_NONE)
+    {
+        m_drop_budget = 0;  //doesn't really matter
+        return;
+    }
+
+    if (m_drop_mode >= MF_DROP_MODE_5)
+    {
+        m_drop_budget = 0;  //doesn't really matter
+        return;
+    }
+
+    const int d = m_drop_mode;
+    assert(d >= 1);
+    assert(d <= 4);
+
+    m_drop_budget = (1 << (5 - d));
+}
+
+
+HRESULT WebmMfVp8Dec::SetQualityLevel(MF_QUALITY_LEVEL q)
+{
+    if (q == MF_QUALITY_NORMAL)
+        return S_OK;
+
+    return MF_E_NO_MORE_QUALITY_LEVELS;
+}
+
+
+HRESULT WebmMfVp8Dec::GetDropMode(MF_QUALITY_DROP_MODE* p)
+{
+    if (p == 0)
+        return E_POINTER;
+
+    Lock lock;
+
+    HRESULT hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    MF_QUALITY_DROP_MODE& d = *p;
+    d = m_drop_mode;
+
+    //odbgstream os;
+    //os << "GetDropMode=" << m_drop_mode << endl;
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::GetQualityLevel(MF_QUALITY_LEVEL* p)
+{
+    if (p == 0)
+        return E_POINTER;
+
+    MF_QUALITY_LEVEL& q = *p;
+    q = MF_QUALITY_NORMAL;  //no post-processing for us to shut off
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::DropTime(LONGLONG t)
+{
+    t;
+    return MF_E_DROPTIME_NOT_SUPPORTED;
+}
+
+
+HRESULT WebmMfVp8Dec::NotifyQualityEvent(IMFMediaEvent* pe, DWORD* pdw)
+{
+    if (pe == 0)
+        return E_INVALIDARG;
+
+    if (pdw == 0)
+        return E_POINTER;
+
+    DWORD& dw = *pdw;
+    dw = 0;  //TODO: possibly set this to MF_QUALITY_CANNOT_KEEP_UP
+
+    MediaEventType type;
+
+    HRESULT hr = pe->GetType(&type);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (type != MEQualityNotify)
+        return E_INVALIDARG;
+
+    GUID ext;
+
+    hr = pe->GetExtendedType(&ext);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (ext != MF_QUALITY_NOTIFY_SAMPLE_LAG)
+        return S_OK;
+
+    PROPVARIANT v;
+
+    hr = pe->GetValue(&v);
+
+    if (FAILED(hr))
+        return E_INVALIDARG;
+
+    if (v.vt != VT_I8)
+        return E_INVALIDARG;
+
+    const LONGLONG reftime = v.hVal.QuadPart;
+
+    //MEQualityNotify Event
+    //http://msdn.microsoft.com/en-us/library/ms694893(VS.85).aspx
+
+    //negative is good - frames are early
+    //positive is bad - frames are late
+    //value is a lateness - time in 100ns units
+    //we're seeing extreme lateness: 2 or 3s
+
+    //if (ext == MF_QUALITY_NOTIFY_PROCESSING_LATENCY)
+    //    return S_OK;
+
+    Lock lock;
+
+    hr = lock.Seize(this);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (m_frame_rate <= 0)   //no framerate available
+        return S_OK;         //TODO: for now, don't bother trying to drop
+
+    if (m_bThin || (m_rate != 1))  //bThin = true implies drop level 5 already
+        return S_OK;
+
+    if (reftime <= 0)  //assume we're all caught up, even if value is spurious
+    {
+        m_lag_sum = 0;
+        m_lag_count = 0;
+        m_lag_frames = 0;
+
+        hr = WebmMfVp8Dec::SetDropMode(MF_DROP_MODE_NONE);
+        assert(SUCCEEDED(hr));
+
+        return S_OK;
+    }
+
+    m_lag_sum += reftime;
+    ++m_lag_count;
+
+    if (m_lag_count < 16)
+        return S_OK;
+
+    const float lag_reftime = float(m_lag_sum) / float(m_lag_count);
+
+    const float frames_ = lag_reftime * m_frame_rate / 10000000.0F;
+    const int frames = static_cast<int>(frames_);
+
+    if (frames <= 1)  //treat small values as noise
+    {
+        m_lag_sum = 0;
+        m_lag_count = 0;
+        m_lag_frames = 0;
+
+        hr = WebmMfVp8Dec::SetDropMode(MF_DROP_MODE_NONE);
+        assert(SUCCEEDED(hr));
+    }
+
+    MF_QUALITY_DROP_MODE m;
+
+    hr = WebmMfVp8Dec::GetDropMode(&m);
+    assert(SUCCEEDED(hr));
+
+    if ((m_lag_frames > 0) &&          //have previous value
+        (frames >= m_lag_frames) &&    //we're not getting better
+        (m < MF_DROP_MODE_5))          //TODO: use MF_QUALITY_CANNOT_KEEP_UP?
+    {
+#ifdef _DEBUG
+        odbgstream os;
+        os << "WebmMfVp8Dec::NotifyQualityEvent: old drop mode=" << m;
+#endif
+
+        m = static_cast<MF_QUALITY_DROP_MODE>(int(m) + 1);
+
+#ifdef _DEBUG
+        os << " new drop mode=" << m << endl;
+#endif
+
+        hr = WebmMfVp8Dec::SetDropMode(m);
+        assert(SUCCEEDED(hr));
+    }
+
+    m_lag_sum = 0;
+    m_lag_count = 0;
+    m_lag_frames = frames;
+
+    return S_OK;
+
+    //Here's a case when there's been a long sequence of frames
+    //having positive lag.  That means we're slightly behind, so
+    //we should compare how much we're behind now to how much
+    //we were behind in the recent past.  The reason we do that
+    //is to discover whether we have a trend.
+    //
+    //How many data points to we use to compute the trend?  We used
+    //the most recent 16 points to compute our latest lag value, so
+    //we must compare the most recent lag value to previous lag values.
+    //
+    //If we have a previous lag value, then we can compute a trend, even
+    //if we only have two points.
+    //
+    //If the avg lag computed here is same or (slightly?) larger, then it
+    //means we really are behind.  We would choose a drop level.  Our
+    //current algorithm even for dropping doesn't work that fast: at
+    //drop level 1, we drop only 1 frame for every 16 frames, so once
+    //we set a non-zero drop level we do have to wait at least 16 frames
+    //before reacting (which is what we do here).
+    //
+    //We don't necessarily have to compare lag times: we convert this to
+    //a frame, so we could compare frames instead.
+    //
+    //The issue remain: how often do we adjust the drop level?
+    //
+    //I suppose that when the reported lag time is less than 0, then this
+    //will reset everything anyway, so we can set the drop level back to
+    //0 when that happens.
+    //
+    //We probalby only have to increase the drop level, until we're caught
+    //up, and it gets reset back to 0.  The question is how often we adjust
+    //the drop level up.
+    //
+    //1st time: 1 out of 16
+    //2nd time: 2 out of 16
+    //3rd time: 4 out of 16
+    //4th time: 8 out of 16
+    //5th time: keyframes only
+    //
+    //if lag has increased since last time, go ahead and increase the drop
+    //level.
+    //
+    //if lag has decreased since last time, the we can probably either decrease
+    //the drop level, or leave it as is.
+
+    //These dampened out by themselves, so there's nothing special we needed
+    //to do.  We don't want to react right away.  The problem we need to
+    //handle
+    //is when the lag is positive and large, and stays constant or is
+    //increasing.
+    //It the number is trending down then the problem solves itself.  The hard
+    //cases are when the lag is growing, or staying constant and large.
+    //
+    //How to define "growing"?  If the slope is positive, that's growing.  If
+    //we remain at any positive slope, the lag will definitely grow.
+    //
+    //We could use a one-shot flag: if the flag is true, throw away the next
+    //non-key frame, then clear the flag.
+    //
+    //Our goal is to pull the slope down to 0 (or negative).  This should drive
+    //the lag down, which should drive the slope towards 0.
+    //
+    //A running average isn't necessarily what we want, although this
+    //will give us an estimate of the avg lag.  If the avg is large and
+    //constant then we must correct.
+
+    //How to compute avg lag:
+    //  (sum of lag times) / (number of lag times)
+    //or could weigh curr avg and curr lag
+    //e.g.  new avg lag = (15/16) * (old avg lag) + (1/16) * (new lag)
+    //if lag <= 0 then reset avg lag
+
+    //10000000 = 1 sec
+    // 5000000 = 1/2 sec
+    // 2500000 = 1/4 sec
+    // 1250000 = 1/8 sec
+    //  625000 = 1/16 sec
+    //  312500 = 1/32 sec
+    //  156250 = 1/64 sec
+    //   78125 = 1/128 sec
+
+    // 1 sec late
+    //  if we see 2 frames the set drop mode #5 (keyframe only)
+    //
+    // 1/2 sec late
+    //  if we see 4 frames then set drop mode #4
+    //
+    // 1/4 sec late
+    //  if we see
+
+    //drop mode 1 = 1/16 frames are dropped
+    //          2 = 1/8 frames
+    //          3 = 1/4 frames
+    //          4 = 1/2 frames
+    //
+    //If we do set the drop mode, then the decoder doesn't
+    //react that fast.
+    //
+    //for drop mode 1, we gain 1/16th sec every 16 frames
+    //if we were behind by 1/16th sec, then we'd catch up after 1 cycle
+    //if we were behind by 1/8th sec, we'd catch up after 2 cycles, etc
+    //
+    //for drop mode 2, we gain 1/8th sec every 8 frames
+    //if we were behind by 1/8th sec, we'd catch up after 1 cycle
+    //if we were behind by 1/4 sec, then we'd catch up after 2 cycles, etc
+    //
+    //for drop mode 3, we gain 1/4 sec every 4 frames
+    //if we were behind by 1/4 sec, we'd catch up after 1 cycle
+    //if we were behind by 1/2 sec, then we'd catch up after 2 cycles, etc
+    //
+    //for drop mode 4, we gain 1/2 sec every 2 frames
+    //
+    //THAT'S ALL WRONG
+    //the drop modes work in terms of frames, not times
+    //IQualityAdvise2 works in terms of time, not frames
+    //
+    //To convert between the two advise interfaces we need the frame rate
+}
+
+
+void WebmMfVp8Dec::FrameRate::Init()
+{
+    m_numerator = 0;
+    m_denominator = 0;
+}
+
+
+HRESULT WebmMfVp8Dec::FrameRate::AssignFrom(IMFMediaType* pmt)
+{
+    UINT32& num = m_numerator;
+    UINT32& den = m_denominator;
+
+    const HRESULT hr = MFGetAttributeRatio(pmt, MF_MT_FRAME_RATE, &num, &den);
+
+    //TODO: check explicitly for the result that means "attribute not set".
+    //MF_E_ATTRIBUTENOTFOUND
+    //MF_E_INVALIDTYPE
+
+    if (FAILED(hr))  //we assume here this means value wasn't found
+    {
+        Init();
+        return S_FALSE;
+    }
+
+    if (den == 0)
+        return MF_E_INVALIDMEDIATYPE;
+
+    if (num == 0)
+        return MF_E_INVALIDMEDIATYPE;
+
+    return S_OK;
+}
+
+
+HRESULT WebmMfVp8Dec::FrameRate::CopyTo(IMFMediaType* pmt) const
+{
+    const UINT32 num = m_numerator;
+    const UINT32 den = m_denominator;
+
+    return MFSetAttributeRatio(pmt, MF_MT_FRAME_RATE, num, den);
+}
+
+
+HRESULT WebmMfVp8Dec::FrameRate::CopyTo(float& value) const
+{
+    const UINT32 num = m_numerator;
+    const UINT32 den = m_denominator;
+
+    if (den == 0)
+        value = -1;  //serves as our "undefined framerate" nonce value
+    else
+        value = float(num) / float(den);
+
+    return S_OK;
+}
+
+
+bool WebmMfVp8Dec::FrameRate::Match(const FrameRate& rhs) const
+{
+    const UINT64 n_in = m_numerator;
+    const UINT64 d_in = m_denominator;
+
+    const UINT64 n_out = rhs.m_numerator;
+    const UINT64 d_out = rhs.m_denominator;
+
+    // n_in / d_in = n_out / d_out
+    // n_in * d_out = n_out * d_in
+
+    return ((n_in * d_out) == (n_out * d_in));
+}
+
+
+}  //end namespace WebmMfVp8DecLib
diff --git a/mediafoundation/webmmfvp8dec/webmmfvp8dec.h b/mediafoundation/webmmfvp8dec/webmmfvp8dec.h
index 19348db..18ee506 100644
--- a/mediafoundation/webmmfvp8dec/webmmfvp8dec.h
+++ b/mediafoundation/webmmfvp8dec/webmmfvp8dec.h
@@ -1,239 +1,239 @@
-#pragma once

-#include <list>

-

-namespace WebmMfVp8DecLib

-{

-

-class WebmMfVp8Dec : public IMFTransform,

-                     //public IVP8PostProcessing,  //TODO

-                     //public IMFQualityAdvise,

-                     public IMFQualityAdvise2,

-                     public IMFRateControl,

-                     public IMFRateSupport,

-                     public IMFGetService,

-                     public CLockable

-{

-    friend HRESULT CreateDecoder(

-            IClassFactory*,

-            IUnknown*,

-            const IID&,

-            void**);

-

-    WebmMfVp8Dec(const WebmMfVp8Dec&);

-    WebmMfVp8Dec& operator=(const WebmMfVp8Dec&);

-

-public:

-

-    //IUnknown

-

-    HRESULT STDMETHODCALLTYPE QueryInterface(const IID&, void**);

-    ULONG STDMETHODCALLTYPE AddRef();

-    ULONG STDMETHODCALLTYPE Release();

-

-    //IMFTransform

-

-    HRESULT STDMETHODCALLTYPE GetStreamLimits(

-        DWORD* pdwInputMinimum,

-        DWORD* pdwInputMaximum,

-        DWORD* pdwOutputMinimum,

-        DWORD* pdwOutputMaximum);

-

-    HRESULT STDMETHODCALLTYPE GetStreamCount(

-        DWORD* pcInputStreams,

-        DWORD* pcOutputStreams);

-

-    HRESULT STDMETHODCALLTYPE GetStreamIDs(

-        DWORD dwInputIDArraySize,

-        DWORD* pdwInputIDs,

-        DWORD dwOutputIDArraySize,

-        DWORD* pdwOutputIDs);

-

-    HRESULT STDMETHODCALLTYPE GetInputStreamInfo(

-        DWORD dwInputStreamID,

-        MFT_INPUT_STREAM_INFO* pStreamInfo);

-

-    HRESULT STDMETHODCALLTYPE GetOutputStreamInfo(

-        DWORD dwOutputStreamID,

-        MFT_OUTPUT_STREAM_INFO* pStreamInfo);

-

-    HRESULT STDMETHODCALLTYPE GetAttributes(IMFAttributes**);

-

-    HRESULT STDMETHODCALLTYPE GetInputStreamAttributes(

-        DWORD dwInputStreamID,

-        IMFAttributes**);

-

-    HRESULT STDMETHODCALLTYPE GetOutputStreamAttributes(

-        DWORD dwOutputStreamID,

-        IMFAttributes**);

-

-    HRESULT STDMETHODCALLTYPE DeleteInputStream(DWORD dwStreamID);

-

-    HRESULT STDMETHODCALLTYPE AddInputStreams(

-        DWORD cStreams,

-        DWORD* adwStreamIDs);

-

-    HRESULT STDMETHODCALLTYPE GetInputAvailableType(

-        DWORD dwInputStreamID,

-        DWORD dwTypeIndex,

-        IMFMediaType**);

-

-    HRESULT STDMETHODCALLTYPE GetOutputAvailableType(

-        DWORD dwOutputStreamID,

-        DWORD dwTypeIndex,

-        IMFMediaType**);

-

-    HRESULT STDMETHODCALLTYPE SetInputType(

-        DWORD dwInputStreamID,

-        IMFMediaType*,

-        DWORD dwFlags);

-

-    HRESULT STDMETHODCALLTYPE SetOutputType(

-        DWORD dwOutputStreamID,

-        IMFMediaType*,

-        DWORD dwFlags);

-

-    HRESULT STDMETHODCALLTYPE GetInputCurrentType(

-        DWORD dwInputStreamID,

-        IMFMediaType**);

-

-    HRESULT STDMETHODCALLTYPE GetOutputCurrentType(

-        DWORD dwOutputStreamID,

-        IMFMediaType**);

-

-    HRESULT STDMETHODCALLTYPE GetInputStatus(

-        DWORD dwInputStreamID,

-        DWORD* pdwFlags);

-

-    HRESULT STDMETHODCALLTYPE GetOutputStatus(

-        DWORD* pdwFlags);

-

-    HRESULT STDMETHODCALLTYPE SetOutputBounds(

-        LONGLONG hnsLowerBound,

-        LONGLONG hnsUpperBound);

-

-    HRESULT STDMETHODCALLTYPE ProcessEvent(

-        DWORD dwInputStreamID,

-        IMFMediaEvent*);

-

-    HRESULT STDMETHODCALLTYPE ProcessMessage(

-        MFT_MESSAGE_TYPE,

-        ULONG_PTR);

-

-    HRESULT STDMETHODCALLTYPE ProcessInput(

-        DWORD dwInputStreamID,

-        IMFSample*,

-        DWORD dwFlags);

-

-    HRESULT STDMETHODCALLTYPE ProcessOutput(

-        DWORD dwFlags,

-        DWORD cOutputBufferCount,

-        MFT_OUTPUT_DATA_BUFFER* pOutputSamples,

-        DWORD* pdwStatus);

-

-    //IMFQualityAdvise

-

-    HRESULT STDMETHODCALLTYPE SetDropMode(MF_QUALITY_DROP_MODE);

-

-    HRESULT STDMETHODCALLTYPE SetQualityLevel(MF_QUALITY_LEVEL);

-

-    HRESULT STDMETHODCALLTYPE GetDropMode(MF_QUALITY_DROP_MODE*);

-

-    HRESULT STDMETHODCALLTYPE GetQualityLevel(MF_QUALITY_LEVEL*);

-

-    HRESULT STDMETHODCALLTYPE DropTime(LONGLONG);

-

-    //IMFQualityAdvise2

-

-    HRESULT STDMETHODCALLTYPE NotifyQualityEvent(IMFMediaEvent*, DWORD*);

-

-    //IMFRateControl

-

-    HRESULT STDMETHODCALLTYPE SetRate(BOOL, float);

-

-    HRESULT STDMETHODCALLTYPE GetRate(BOOL*, float*);

-

-    //IMFRateSupport

-

-    HRESULT STDMETHODCALLTYPE GetSlowestRate(MFRATE_DIRECTION, BOOL, float*);

-

-    HRESULT STDMETHODCALLTYPE GetFastestRate(MFRATE_DIRECTION, BOOL, float*);

-

-    HRESULT STDMETHODCALLTYPE IsRateSupported(BOOL, float, float*);

-

-    //IMFGetService

-

-    HRESULT STDMETHODCALLTYPE GetService(REFGUID, REFIID, LPVOID*);

-

-private:

-

-    explicit WebmMfVp8Dec(IClassFactory*);

-    virtual ~WebmMfVp8Dec();

-

-    IClassFactory* const m_pClassFactory;

-    LONG m_cRef;

-

-    struct FrameSize { UINT32 width; UINT32 height; };

-

-    struct FrameRate

-    {

-        UINT32 m_numerator;

-        UINT32 m_denominator;

-

-        void Init();

-        bool Match(const FrameRate& rhs) const;

-

-        HRESULT AssignFrom(IMFMediaType*);

-        HRESULT CopyTo(IMFMediaType*) const;

-        HRESULT CopyTo(float&) const;

-    };

-

-    //FrameRate m_frame_rate;

-    float m_frame_rate;

-    IMFMediaType* m_pInputMediaType;

-    IMFMediaType* m_pOutputMediaType;

-

-    struct SampleInfo

-    {

-        IMFSample* pSample;

-        DWORD dwBuffer;

-

-        HRESULT DecodeAll(vpx_codec_ctx_t&);

-        HRESULT DecodeOne(vpx_codec_ctx_t&, LONGLONG&, LONGLONG&);

-    };

-

-    typedef std::list<SampleInfo> samples_t;

-    samples_t m_samples;

-

-    vpx_codec_ctx_t m_ctx;

-

-    float m_rate;  //trick-play mode

-    BOOL m_bThin;

-

-    MF_QUALITY_DROP_MODE m_drop_mode;

-    int m_drop_budget;

-    int m_drop_late;

-    void ReplenishDropBudget();

-

-    //struct LagInfo

-    //{

-    //    LONGLONG lag;

-    //};

-

-    LONGLONG m_lag_sum;  //sum of lag values in list

-    int m_lag_count;

-

-    //typedef std::list<LagInfo> lag_info_list_t;

-    //lag_info_list_t m_lag_info_list;

-

-    //float m_lag_reftime;

-    int m_lag_frames;

-

-    DWORD GetOutputBufferSize(FrameSize&) const;

-    HRESULT Decode(IMFSample*);

-    HRESULT GetFrame(BYTE*, ULONG, const GUID&);

-

-    void Flush();

-

-};

-

-}  //end namespace WebmMfVp8DecLib

+#pragma once
+#include <list>
+
+namespace WebmMfVp8DecLib
+{
+
+class WebmMfVp8Dec : public IMFTransform,
+                     //public IVP8PostProcessing,  //TODO
+                     //public IMFQualityAdvise,
+                     public IMFQualityAdvise2,
+                     public IMFRateControl,
+                     public IMFRateSupport,
+                     public IMFGetService,
+                     public CLockable
+{
+    friend HRESULT CreateDecoder(
+            IClassFactory*,
+            IUnknown*,
+            const IID&,
+            void**);
+
+    WebmMfVp8Dec(const WebmMfVp8Dec&);
+    WebmMfVp8Dec& operator=(const WebmMfVp8Dec&);
+
+public:
+
+    //IUnknown
+
+    HRESULT STDMETHODCALLTYPE QueryInterface(const IID&, void**);
+    ULONG STDMETHODCALLTYPE AddRef();
+    ULONG STDMETHODCALLTYPE Release();
+
+    //IMFTransform
+
+    HRESULT STDMETHODCALLTYPE GetStreamLimits(
+        DWORD* pdwInputMinimum,
+        DWORD* pdwInputMaximum,
+        DWORD* pdwOutputMinimum,
+        DWORD* pdwOutputMaximum);
+
+    HRESULT STDMETHODCALLTYPE GetStreamCount(
+        DWORD* pcInputStreams,
+        DWORD* pcOutputStreams);
+
+    HRESULT STDMETHODCALLTYPE GetStreamIDs(
+        DWORD dwInputIDArraySize,
+        DWORD* pdwInputIDs,
+        DWORD dwOutputIDArraySize,
+        DWORD* pdwOutputIDs);
+
+    HRESULT STDMETHODCALLTYPE GetInputStreamInfo(
+        DWORD dwInputStreamID,
+        MFT_INPUT_STREAM_INFO* pStreamInfo);
+
+    HRESULT STDMETHODCALLTYPE GetOutputStreamInfo(
+        DWORD dwOutputStreamID,
+        MFT_OUTPUT_STREAM_INFO* pStreamInfo);
+
+    HRESULT STDMETHODCALLTYPE GetAttributes(IMFAttributes**);
+
+    HRESULT STDMETHODCALLTYPE GetInputStreamAttributes(
+        DWORD dwInputStreamID,
+        IMFAttributes**);
+
+    HRESULT STDMETHODCALLTYPE GetOutputStreamAttributes(
+        DWORD dwOutputStreamID,
+        IMFAttributes**);
+
+    HRESULT STDMETHODCALLTYPE DeleteInputStream(DWORD dwStreamID);
+
+    HRESULT STDMETHODCALLTYPE AddInputStreams(
+        DWORD cStreams,
+        DWORD* adwStreamIDs);
+
+    HRESULT STDMETHODCALLTYPE GetInputAvailableType(
+        DWORD dwInputStreamID,
+        DWORD dwTypeIndex,
+        IMFMediaType**);
+
+    HRESULT STDMETHODCALLTYPE GetOutputAvailableType(
+        DWORD dwOutputStreamID,
+        DWORD dwTypeIndex,
+        IMFMediaType**);
+
+    HRESULT STDMETHODCALLTYPE SetInputType(
+        DWORD dwInputStreamID,
+        IMFMediaType*,
+        DWORD dwFlags);
+
+    HRESULT STDMETHODCALLTYPE SetOutputType(
+        DWORD dwOutputStreamID,
+        IMFMediaType*,
+        DWORD dwFlags);
+
+    HRESULT STDMETHODCALLTYPE GetInputCurrentType(
+        DWORD dwInputStreamID,
+        IMFMediaType**);
+
+    HRESULT STDMETHODCALLTYPE GetOutputCurrentType(
+        DWORD dwOutputStreamID,
+        IMFMediaType**);
+
+    HRESULT STDMETHODCALLTYPE GetInputStatus(
+        DWORD dwInputStreamID,
+        DWORD* pdwFlags);
+
+    HRESULT STDMETHODCALLTYPE GetOutputStatus(
+        DWORD* pdwFlags);
+
+    HRESULT STDMETHODCALLTYPE SetOutputBounds(
+        LONGLONG hnsLowerBound,
+        LONGLONG hnsUpperBound);
+
+    HRESULT STDMETHODCALLTYPE ProcessEvent(
+        DWORD dwInputStreamID,
+        IMFMediaEvent*);
+
+    HRESULT STDMETHODCALLTYPE ProcessMessage(
+        MFT_MESSAGE_TYPE,
+        ULONG_PTR);
+
+    HRESULT STDMETHODCALLTYPE ProcessInput(
+        DWORD dwInputStreamID,
+        IMFSample*,
+        DWORD dwFlags);
+
+    HRESULT STDMETHODCALLTYPE ProcessOutput(
+        DWORD dwFlags,
+        DWORD cOutputBufferCount,
+        MFT_OUTPUT_DATA_BUFFER* pOutputSamples,
+        DWORD* pdwStatus);
+
+    //IMFQualityAdvise
+
+    HRESULT STDMETHODCALLTYPE SetDropMode(MF_QUALITY_DROP_MODE);
+
+    HRESULT STDMETHODCALLTYPE SetQualityLevel(MF_QUALITY_LEVEL);
+
+    HRESULT STDMETHODCALLTYPE GetDropMode(MF_QUALITY_DROP_MODE*);
+
+    HRESULT STDMETHODCALLTYPE GetQualityLevel(MF_QUALITY_LEVEL*);
+
+    HRESULT STDMETHODCALLTYPE DropTime(LONGLONG);
+
+    //IMFQualityAdvise2
+
+    HRESULT STDMETHODCALLTYPE NotifyQualityEvent(IMFMediaEvent*, DWORD*);
+
+    //IMFRateControl
+
+    HRESULT STDMETHODCALLTYPE SetRate(BOOL, float);
+
+    HRESULT STDMETHODCALLTYPE GetRate(BOOL*, float*);
+
+    //IMFRateSupport
+
+    HRESULT STDMETHODCALLTYPE GetSlowestRate(MFRATE_DIRECTION, BOOL, float*);
+
+    HRESULT STDMETHODCALLTYPE GetFastestRate(MFRATE_DIRECTION, BOOL, float*);
+
+    HRESULT STDMETHODCALLTYPE IsRateSupported(BOOL, float, float*);
+
+    //IMFGetService
+
+    HRESULT STDMETHODCALLTYPE GetService(REFGUID, REFIID, LPVOID*);
+
+private:
+
+    explicit WebmMfVp8Dec(IClassFactory*);
+    virtual ~WebmMfVp8Dec();
+
+    IClassFactory* const m_pClassFactory;
+    LONG m_cRef;
+
+    struct FrameSize { UINT32 width; UINT32 height; };
+
+    struct FrameRate
+    {
+        UINT32 m_numerator;
+        UINT32 m_denominator;
+
+        void Init();
+        bool Match(const FrameRate& rhs) const;
+
+        HRESULT AssignFrom(IMFMediaType*);
+        HRESULT CopyTo(IMFMediaType*) const;
+        HRESULT CopyTo(float&) const;
+    };
+
+    //FrameRate m_frame_rate;
+    float m_frame_rate;
+    IMFMediaType* m_pInputMediaType;
+    IMFMediaType* m_pOutputMediaType;
+
+    struct SampleInfo
+    {
+        IMFSample* pSample;
+        DWORD dwBuffer;
+
+        HRESULT DecodeAll(vpx_codec_ctx_t&);
+        HRESULT DecodeOne(vpx_codec_ctx_t&, LONGLONG&, LONGLONG&);
+    };
+
+    typedef std::list<SampleInfo> samples_t;
+    samples_t m_samples;
+
+    vpx_codec_ctx_t m_ctx;
+
+    float m_rate;  //trick-play mode
+    BOOL m_bThin;
+
+    MF_QUALITY_DROP_MODE m_drop_mode;
+    int m_drop_budget;
+    int m_drop_late;
+    void ReplenishDropBudget();
+
+    //struct LagInfo
+    //{
+    //    LONGLONG lag;
+    //};
+
+    LONGLONG m_lag_sum;  //sum of lag values in list
+    int m_lag_count;
+
+    //typedef std::list<LagInfo> lag_info_list_t;
+    //lag_info_list_t m_lag_info_list;
+
+    //float m_lag_reftime;
+    int m_lag_frames;
+
+    DWORD GetOutputBufferSize(FrameSize&) const;
+    HRESULT Decode(IMFSample*);
+    HRESULT GetFrame(BYTE*, ULONG, const GUID&);
+
+    void Flush();
+
+};
+
+}  //end namespace WebmMfVp8DecLib