| // 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 "CVP8Sample.hpp" | |
| #include <new> | |
| #include <cassert> | |
| #include <vfwmsgs.h> | |
| HRESULT CVP8Sample::CreateAllocator(IMemAllocator** pp) | |
| { | |
| if (pp == 0) | |
| return E_POINTER; | |
| IMemAllocator*& pResult = *pp; | |
| pResult = 0; | |
| SampleFactory* pSampleFactory = new (std::nothrow) SampleFactory; | |
| if (pSampleFactory == 0) | |
| return E_OUTOFMEMORY; | |
| const HRESULT hr = CMemAllocator::CreateInstance(pSampleFactory, &pResult); | |
| if (FAILED(hr)) | |
| { | |
| pSampleFactory->Destroy(0); | |
| return VFW_E_NO_ALLOCATOR; | |
| } | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::GetFrame(CMemAllocator* pAlloc, IVP8Sample::Frame& f) | |
| { | |
| CMemAllocator::Lock lock; | |
| HRESULT hr = lock.Seize(pAlloc); | |
| if (FAILED(hr)) | |
| return hr; | |
| ALLOCATOR_PROPERTIES props; | |
| hr = pAlloc->GetProperties(&props); | |
| assert(SUCCEEDED(hr)); | |
| assert(props.cBuffers > 0); | |
| assert(props.cbBuffer > 0); | |
| assert(props.cbAlign >= 1); | |
| assert(props.cbPrefix >= 0); | |
| const long buflen = props.cbAlign - 1 + props.cbPrefix + props.cbBuffer; | |
| CMemAllocator::ISampleFactory* const pFactory_ = pAlloc->m_pSampleFactory; | |
| assert(pFactory_); | |
| SampleFactory* const pFactory = static_cast<SampleFactory*>(pFactory_); | |
| SampleFactory::frames_t& pool = pFactory->m_pool; | |
| if (!pool.empty()) | |
| { | |
| f = pool.front(); | |
| assert(f.buf); | |
| assert(f.buflen >= buflen); | |
| pool.pop_front(); | |
| } | |
| else | |
| { | |
| BYTE* const buf = new (std::nothrow) BYTE[buflen]; | |
| if (buf == 0) | |
| return E_OUTOFMEMORY; | |
| f.buf = buf; | |
| f.buflen = buflen; | |
| long off = props.cbPrefix; | |
| if (intptr_t n = intptr_t(buf) % props.cbAlign) | |
| off += props.cbAlign - n; | |
| f.off = off; | |
| } | |
| BYTE* const ptr = f.buf + f.off; | |
| ptr; | |
| assert(intptr_t(ptr - props.cbPrefix) % props.cbAlign == 0); | |
| return S_OK; | |
| } | |
| CVP8Sample::SampleFactory::SampleFactory() | |
| { | |
| } | |
| CVP8Sample::SampleFactory::~SampleFactory() | |
| { | |
| PurgePool(); | |
| } | |
| HRESULT CVP8Sample::SampleFactory::CreateSample( | |
| CMemAllocator* pAllocator, | |
| IMemSample*& pResult) | |
| { | |
| pResult = 0; | |
| CVP8Sample* pSample; | |
| const HRESULT hr = CVP8Sample::CreateInstance(pAllocator, pSample); | |
| if (FAILED(hr)) | |
| return hr; | |
| assert(pSample); | |
| assert(pSample->GetCount() == 0); | |
| pResult = pSample; | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::SampleFactory::InitializeSample(IMemSample* p) | |
| { | |
| assert(p); | |
| const HRESULT hr = p->Initialize(); | |
| assert(SUCCEEDED(hr)); | |
| assert(p->GetCount() == 0); | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::SampleFactory::FinalizeSample(IMemSample* p) | |
| { | |
| assert(p); | |
| //Note that FinalizeSample is called by the allocator while | |
| //it holds its own lock. There's no special locking we need | |
| //to here, because the allocator owns the sample factory | |
| //object it was given when it (the allocator) was created. | |
| IVP8Sample* pSample; | |
| HRESULT hr = p->QueryInterface(&pSample); | |
| assert(SUCCEEDED(hr)); | |
| assert(pSample); | |
| //NOTE: we don't bother releasing the IVP8Sample ptr, because | |
| //the sample is in the process of being destroyed. We don't want | |
| //to trigger another call to IMemAllocator::ReleaseBuffer from | |
| //IMediaSample::Release. | |
| IVP8Sample::Frame& f = pSample->GetFrame(); | |
| assert(f.buf); | |
| m_pool.push_back(f); | |
| f.buf = 0; | |
| hr = p->Finalize(); | |
| assert(SUCCEEDED(hr)); | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::SampleFactory::DestroySample(IMemSample* pSample) | |
| { | |
| assert(pSample); | |
| return pSample->Destroy(); | |
| } | |
| HRESULT CVP8Sample::SampleFactory::Destroy(CMemAllocator*) | |
| { | |
| delete this; | |
| return S_OK; | |
| } | |
| void CVP8Sample::SampleFactory::PurgePool() | |
| { | |
| while (!m_pool.empty()) | |
| { | |
| IVP8Sample::Frame& f = m_pool.front(); | |
| assert(f.buf); | |
| delete[] f.buf; | |
| m_pool.pop_front(); | |
| } | |
| } | |
| HRESULT CVP8Sample::CreateInstance( | |
| CMemAllocator* pAllocator, | |
| CVP8Sample*& pSample) | |
| { | |
| if (pAllocator == 0) | |
| return E_INVALIDARG; | |
| pSample = new (std::nothrow) CVP8Sample(pAllocator); | |
| return pSample ? S_OK : E_OUTOFMEMORY; | |
| } | |
| CVP8Sample::CVP8Sample(CMemAllocator* p) | |
| : m_pAllocator(p), | |
| m_cRef(0) //allocator will adjust | |
| { | |
| m_frame.buf = 0; | |
| } | |
| CVP8Sample::~CVP8Sample() | |
| { | |
| assert(m_frame.buf == 0); | |
| } | |
| HRESULT CVP8Sample::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<IMediaSample*>(this); | |
| else if (iid == __uuidof(IMediaSample)) | |
| pUnk = static_cast<IMediaSample*>(this); | |
| else if (iid == __uuidof(IMemSample)) | |
| pUnk = static_cast<IMemSample*>(this); | |
| else if (iid == __uuidof(IVP8Sample)) | |
| pUnk = static_cast<IVP8Sample*>(this); | |
| else | |
| { | |
| pUnk = 0; | |
| return E_NOINTERFACE; | |
| } | |
| pUnk->AddRef(); | |
| return S_OK; | |
| } | |
| ULONG CVP8Sample::AddRef() | |
| { | |
| return InterlockedIncrement((LONG*)&m_cRef); | |
| } | |
| ULONG CVP8Sample::Release() | |
| { | |
| assert(m_cRef > 0); | |
| if (LONG n = InterlockedDecrement((LONG*)&m_cRef)) | |
| return n; | |
| m_pAllocator->ReleaseBuffer(this); | |
| return 0; | |
| } | |
| CVP8Sample::Frame& CVP8Sample::GetFrame() | |
| { | |
| return m_frame; | |
| } | |
| ULONG CVP8Sample::GetCount() | |
| { | |
| return m_cRef; | |
| } | |
| HRESULT CVP8Sample::Initialize() | |
| { | |
| assert(m_frame.buf == 0); | |
| m_cRef = 0; | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::Finalize() | |
| { | |
| assert(m_frame.buf == 0); | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::Destroy() | |
| { | |
| delete this; | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::GetPointer(BYTE** pp) | |
| { | |
| if (pp == 0) | |
| return E_POINTER; | |
| BYTE*& p = *pp; | |
| const Frame& f = m_frame; | |
| assert(f.buf); | |
| assert(f.buflen >= 0); | |
| assert(f.off >= 0); | |
| assert(f.off <= f.buflen); | |
| p = f.buf + f.off; | |
| #ifdef _DEBUG | |
| ALLOCATOR_PROPERTIES props; | |
| const HRESULT hr = m_pAllocator->GetProperties(&props); | |
| assert(SUCCEEDED(hr)); | |
| assert(props.cbAlign >= 1); | |
| assert(props.cbPrefix >= 0); | |
| assert(intptr_t(p - props.cbPrefix) % props.cbAlign == 0); | |
| #endif | |
| return S_OK; | |
| } | |
| long CVP8Sample::GetSize() | |
| { | |
| const Frame& f = m_frame; | |
| assert(f.buf); | |
| assert(f.off <= f.buflen); | |
| const long size = f.buflen - f.off; | |
| assert(size >= 0); | |
| #ifdef _DEBUG | |
| ALLOCATOR_PROPERTIES props; | |
| const HRESULT hr = m_pAllocator->GetProperties(&props); | |
| assert(SUCCEEDED(hr)); | |
| assert(size >= props.cbBuffer); | |
| #endif | |
| return size; | |
| } | |
| HRESULT CVP8Sample::GetTime( | |
| REFERENCE_TIME* pstart, | |
| REFERENCE_TIME* pstop) | |
| { | |
| const Frame& f = m_frame; | |
| assert(f.buf); | |
| assert(f.start >= 0); | |
| if (pstart == 0) | |
| return E_POINTER; | |
| *pstart = f.start; | |
| if (pstop == 0) | |
| return S_OK; | |
| if (f.stop < f.start) //no stop time | |
| { | |
| *pstop = f.start + 1; | |
| return VFW_S_NO_STOP_TIME; | |
| } | |
| *pstop = f.stop; | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::SetTime( | |
| REFERENCE_TIME*, | |
| REFERENCE_TIME*) | |
| { | |
| return E_NOTIMPL; | |
| } | |
| HRESULT CVP8Sample::IsSyncPoint() | |
| { | |
| assert(m_frame.buf); | |
| return m_frame.key ? S_OK : S_FALSE; | |
| } | |
| HRESULT CVP8Sample::SetSyncPoint(BOOL) | |
| { | |
| return E_NOTIMPL; | |
| } | |
| HRESULT CVP8Sample::IsPreroll() | |
| { | |
| assert(m_frame.buf); | |
| //TODO: | |
| return m_preroll ? S_OK : S_FALSE; | |
| } | |
| HRESULT CVP8Sample::SetPreroll(BOOL b) | |
| { | |
| assert(m_frame.buf); | |
| //TODO: | |
| m_preroll = bool(b != 0); | |
| return S_OK; | |
| } | |
| long CVP8Sample::GetActualDataLength() | |
| { | |
| assert(m_frame.buf); | |
| assert(m_frame.len >= 0); | |
| return m_frame.len; | |
| } | |
| HRESULT CVP8Sample::SetActualDataLength(long) | |
| { | |
| return E_NOTIMPL; | |
| } | |
| HRESULT CVP8Sample::GetMediaType( | |
| AM_MEDIA_TYPE** pp) | |
| { | |
| if (pp == 0) | |
| return E_POINTER; | |
| AM_MEDIA_TYPE*& p = *pp; | |
| p = 0; | |
| return S_FALSE; //means "no media type" | |
| } | |
| HRESULT CVP8Sample::SetMediaType( | |
| AM_MEDIA_TYPE*) | |
| { | |
| return E_NOTIMPL; | |
| } | |
| HRESULT CVP8Sample::IsDiscontinuity() | |
| { | |
| assert(m_frame.buf); | |
| //TODO: | |
| return m_discontinuity ? S_OK : S_FALSE; | |
| } | |
| HRESULT CVP8Sample::SetDiscontinuity(BOOL b) | |
| { | |
| assert(m_frame.buf); | |
| //TODO: | |
| m_discontinuity = bool(b != 0); | |
| return S_OK; | |
| } | |
| HRESULT CVP8Sample::GetMediaTime( | |
| LONGLONG*, | |
| LONGLONG*) | |
| { | |
| return VFW_E_MEDIA_TIME_NOT_SET; | |
| } | |
| HRESULT CVP8Sample::SetMediaTime( | |
| LONGLONG*, | |
| LONGLONG*) | |
| { | |
| return E_NOTIMPL; | |
| } |