blob: fd74a8bbb2a896e6e057ef89fbdfe56cbeb10706 [file]
// 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 "webmmuxfilter.h"
//#include "cmemallocator.h"
#include "cmediasample.h"
#include "webmtypes.h"
#include <vfwmsgs.h>
#include <uuids.h>
#include <dvdmedia.h>
#include <cassert>
namespace WebmMuxLib
{
Outpin::Outpin(Filter* p) :
Pin(p, L"outpin", PINDIR_OUTPUT)
{
AM_MEDIA_TYPE mt;
mt.majortype = MEDIATYPE_Stream;
mt.subtype = WebmTypes::MEDIASUBTYPE_WEBM;
mt.bFixedSizeSamples = FALSE;
mt.bTemporalCompression = FALSE;
mt.lSampleSize = 0;
mt.formattype = GUID_NULL;
mt.pUnk = 0;
mt.cbFormat = 0;
mt.pbFormat = 0;
m_preferred_mtv.Add(mt);
}
Outpin::~Outpin()
{
assert(!bool(m_pStream));
assert(!bool(m_pAllocator));
}
void Outpin::Init()
{
if (bool(m_pAllocator))
{
const HRESULT hr = m_pAllocator->Commit();
assert(SUCCEEDED(hr)); //TODO
hr;
}
m_pFilter->m_ctx.Open(m_pStream);
}
void Outpin::Final()
{
m_pFilter->m_ctx.Close();
if (bool(m_pAllocator))
{
const HRESULT hr = m_pAllocator->Decommit();
assert(SUCCEEDED(hr)); //TODO
hr;
}
}
HRESULT Outpin::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<IPin*>(this);
else if (iid == __uuidof(IPin))
pUnk = static_cast<IPin*>(this);
else
{
pUnk = 0;
return E_NOINTERFACE;
}
pUnk->AddRef();
return S_OK;
}
ULONG Outpin::AddRef()
{
return m_pFilter->AddRef();
}
ULONG Outpin::Release()
{
return m_pFilter->Release();
}
HRESULT Outpin::Connect(
IPin* pin,
const AM_MEDIA_TYPE* pmt)
{
if (pin == 0)
return E_POINTER;
IStreamPtr pStream;
HRESULT hr = pin->QueryInterface(&pStream);
if (hr != S_OK)
return hr;
Filter::Lock lock;
hr = lock.Seize(m_pFilter);
if (FAILED(hr))
return hr;
if (m_pFilter->m_state != State_Stopped)
return VFW_E_NOT_STOPPED;
if (bool(m_pPinConnection))
return VFW_E_ALREADY_CONNECTED;
assert(!bool(m_pAllocator));
assert(!bool(m_pStream));
m_connection_mtv.Clear();
if (pmt)
{
hr = QueryAccept(pmt);
if (hr != S_OK)
return VFW_E_TYPE_NOT_ACCEPTED;
hr = pin->ReceiveConnection(this, pmt);
if (FAILED(hr))
return hr;
hr = m_connection_mtv.Add(*pmt);
if (FAILED(hr))
return hr;
}
else
{
assert(m_preferred_mtv.Size() == 1);
const AM_MEDIA_TYPE& mt = m_preferred_mtv[0];
hr = pin->ReceiveConnection(this, &mt);
if (FAILED(hr))
return hr;
hr = m_connection_mtv.Add(mt);
if (FAILED(hr))
return hr;
}
const GraphUtil::IMemInputPinPtr pMemInput(pin);
if (bool(pMemInput))
{
hr = pMemInput->GetAllocator(&m_pAllocator);
if (FAILED(hr))
{
//hr = CMemAllocator::CreateInstance(&m_pAllocator);
hr = CMediaSample::CreateAllocator(&m_pAllocator);
if (FAILED(hr))
return VFW_E_NO_ALLOCATOR;
}
assert(bool(m_pAllocator));
ALLOCATOR_PROPERTIES props;
props.cBuffers = -1; //number of buffers
props.cbBuffer = -1; //size of each buffer, excluding prefix
props.cbAlign = -1; //applies to prefix, too
props.cbPrefix = -1; //imediasample::getbuffer does NOT include prefix
hr = pMemInput->GetAllocatorRequirements(&props);
if (props.cBuffers < 0)
props.cBuffers = 0;
if (props.cbBuffer < 0)
props.cbBuffer = 0;
if (props.cbAlign <= 0)
props.cbAlign = 1;
if (props.cbPrefix < 0)
props.cbPrefix = 0;
hr = m_pAllocator->SetProperties(&props, &m_props);
if (FAILED(hr))
return hr;
hr = pMemInput->NotifyAllocator(m_pAllocator, 0); //allow writes
if (FAILED(hr) && (hr != E_NOTIMPL))
return hr;
}
m_pStream = pStream;
m_pPinConnection = pin;
return S_OK;
}
HRESULT Outpin::ReceiveConnection(
IPin*,
const AM_MEDIA_TYPE*)
{
return E_UNEXPECTED; //for input pins only
}
HRESULT Outpin::QueryAccept(const AM_MEDIA_TYPE* pmt)
{
if (pmt == 0)
return E_POINTER;
const AM_MEDIA_TYPE& mt = *pmt;
if (mt.majortype == MEDIATYPE_Stream)
return S_OK;
return S_FALSE;
}
HRESULT Outpin::QueryInternalConnections(IPin** pa, ULONG* pn)
{
if (pn == 0)
return E_POINTER;
if (*pn == 0)
{
if (pa == 0) //query for required number
{
*pn = 2;
return S_OK;
}
return S_FALSE; //means "insufficient number of array elements"
}
*pn = 0;
if (pa == 0)
return E_POINTER;
if (*pn < 2)
return S_FALSE; //means "insufficient number of array elements"
IPin*& vpin = pa[0];
vpin = &m_pFilter->m_inpin_video;
vpin->AddRef();
IPin*& apin = pa[1];
apin = &m_pFilter->m_inpin_audio;
apin->AddRef();
*pn = 2;
return S_OK;
}
HRESULT Outpin::EndOfStream()
{
return E_UNEXPECTED; //for inpins only
}
HRESULT Outpin::NewSegment(
REFERENCE_TIME,
REFERENCE_TIME,
double)
{
return E_UNEXPECTED;
}
HRESULT Outpin::BeginFlush()
{
return E_UNEXPECTED;
}
HRESULT Outpin::EndFlush()
{
return E_UNEXPECTED;
}
HRESULT Outpin::OnDisconnect()
{
m_pStream = 0;
m_pAllocator = 0;
return S_OK;
}
HRESULT Outpin::GetCurrentPosition(LONGLONG& reftime) const
{
if (!bool(m_pStream))
return VFW_E_NOT_CONNECTED;
const Context& ctx = m_pFilter->m_ctx;
const ULONG tc = ctx.GetTimecode();
const ULONG sc = ctx.GetTimecodeScale();
const LONGLONG ns = LONGLONG(tc) * ULONG(sc); //nanoseconds
reftime = ns / 100; //reftime units (100ns ticks)
return S_OK;
}
} //end namespace WebmMuxLib