/* * (C) 2003-2006 Gabest * (C) 2006-2013 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * MPC-HC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "stdafx.h" #include #include "BaseMuxer.h" #include "../../../DSUtil/DSUtil.h" #include #include "moreuuids.h" #define MAXQUEUESIZE 100 // // CBaseMuxerInputPin // CBaseMuxerInputPin::CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) : CBaseInputPin(NAME("CBaseMuxerInputPin"), pFilter, pLock, phr, pName) , m_rtDuration(0) , m_evAcceptPacket(TRUE) , m_iPacketIndex(0) , m_fEOS(false) { static int s_iID = 0; m_iID = s_iID++; } CBaseMuxerInputPin::~CBaseMuxerInputPin() { } STDMETHODIMP CBaseMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) { CheckPointer(ppv, E_POINTER); return QI(IBaseMuxerRelatedPin) QI(IPropertyBag) QI(IPropertyBag2) QI(IDSMPropertyBag) __super::NonDelegatingQueryInterface(riid, ppv); } bool CBaseMuxerInputPin::IsSubtitleStream() { return m_mt.majortype == MEDIATYPE_Subtitle || m_mt.majortype == MEDIATYPE_Text; } void CBaseMuxerInputPin::PushPacket(CAutoPtr pPacket) { for (int i = 0; m_pFilter->IsActive() && !m_bFlushing && !m_evAcceptPacket.Wait(1) && i < 1000; i++) { ; } if (!m_pFilter->IsActive() || m_bFlushing) { return; } CAutoLock cAutoLock(&m_csQueue); m_queue.AddTail(pPacket); if (m_queue.GetCount() >= MAXQUEUESIZE) { m_evAcceptPacket.Reset(); } } CAutoPtr CBaseMuxerInputPin::PopPacket() { CAutoPtr pPacket; CAutoLock cAutoLock(&m_csQueue); if (m_queue.GetCount()) { pPacket = m_queue.RemoveHead(); } if (m_queue.GetCount() < MAXQUEUESIZE) { m_evAcceptPacket.Set(); } return pPacket; } HRESULT CBaseMuxerInputPin::CheckMediaType(const CMediaType* pmt) { if (pmt->formattype == FORMAT_WaveFormatEx) { WORD wFormatTag = ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag; if ((wFormatTag == WAVE_FORMAT_PCM || wFormatTag == WAVE_FORMAT_EXTENSIBLE || wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && pmt->subtype != FOURCCMap(wFormatTag) && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_EXTENSIBLE) && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && pmt->subtype != MEDIASUBTYPE_DVD_LPCM_AUDIO && pmt->subtype != MEDIASUBTYPE_DOLBY_AC3 && pmt->subtype != MEDIASUBTYPE_DTS) { return E_INVALIDARG; } } return pmt->majortype == MEDIATYPE_Video || pmt->majortype == MEDIATYPE_Audio && pmt->formattype != FORMAT_VorbisFormat || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None || pmt->majortype == MEDIATYPE_Subtitle ? S_OK : E_INVALIDARG; } HRESULT CBaseMuxerInputPin::BreakConnect() { HRESULT hr = __super::BreakConnect(); if (FAILED(hr)) { return hr; } RemoveAll(); // TODO: remove extra disconnected pins, leave one return hr; } HRESULT CBaseMuxerInputPin::CompleteConnect(IPin* pReceivePin) { HRESULT hr = __super::CompleteConnect(pReceivePin); if (FAILED(hr)) { return hr; } // duration m_rtDuration = 0; CComQIPtr pMS; if ((pMS = GetFilterFromPin(pReceivePin)) || (pMS = pReceivePin)) { pMS->GetDuration(&m_rtDuration); } // properties for (CComPtr pPin = pReceivePin; pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { if (CComQIPtr pPB = pPin) { ULONG cProperties = 0; if (SUCCEEDED(pPB->CountProperties(&cProperties)) && cProperties > 0) { for (ULONG iProperty = 0; iProperty < cProperties; iProperty++) { PROPBAG2 PropBag; ZeroMemory(&PropBag, sizeof(PropBag)); ULONG cPropertiesReturned = 0; if (FAILED(pPB->GetPropertyInfo(iProperty, 1, &PropBag, &cPropertiesReturned))) { continue; } HRESULT hr2; CComVariant var; if (SUCCEEDED(pPB->Read(1, &PropBag, nullptr, &var, &hr2)) && SUCCEEDED(hr2)) { SetProperty(PropBag.pstrName, &var); } CoTaskMemFree(PropBag.pstrName); } } } } (static_cast(m_pFilter))->AddInput(); return S_OK; } HRESULT CBaseMuxerInputPin::Active() { m_rtMaxStart = _I64_MIN; m_fEOS = false; m_iPacketIndex = 0; m_evAcceptPacket.Set(); return __super::Active(); } HRESULT CBaseMuxerInputPin::Inactive() { CAutoLock cAutoLock(&m_csQueue); m_queue.RemoveAll(); return __super::Inactive(); } STDMETHODIMP CBaseMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) { CAutoLock cAutoLock(&m_csReceive); return __super::NewSegment(tStart, tStop, dRate); } STDMETHODIMP CBaseMuxerInputPin::Receive(IMediaSample* pSample) { CAutoLock cAutoLock(&m_csReceive); HRESULT hr = __super::Receive(pSample); if (FAILED(hr)) { return hr; } CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); long len = pSample->GetActualDataLength(); BYTE* pData = nullptr; if (FAILED(pSample->GetPointer(&pData)) || !pData) { return S_OK; } pPacket->pData.SetCount(len); memcpy(pPacket->pData.GetData(), pData, len); if (S_OK == pSample->IsSyncPoint() || m_mt.majortype == MEDIATYPE_Audio && !m_mt.bTemporalCompression) { pPacket->flags |= MuxerPacket::syncpoint; } if (S_OK == pSample->GetTime(&pPacket->rtStart, &pPacket->rtStop)) { pPacket->flags |= MuxerPacket::timevalid; pPacket->rtStart += m_tStart; pPacket->rtStop += m_tStart; if ((pPacket->flags & MuxerPacket::syncpoint) && pPacket->rtStart < m_rtMaxStart) { pPacket->flags &= ~MuxerPacket::syncpoint; pPacket->flags |= MuxerPacket::bogus; } m_rtMaxStart = max(m_rtMaxStart, pPacket->rtStart); } else if (pPacket->flags & MuxerPacket::syncpoint) { pPacket->flags &= ~MuxerPacket::syncpoint; pPacket->flags |= MuxerPacket::bogus; } if (S_OK == pSample->IsDiscontinuity()) { pPacket->flags |= MuxerPacket::discontinuity; } pPacket->index = m_iPacketIndex++; PushPacket(pPacket); return S_OK; } STDMETHODIMP CBaseMuxerInputPin::EndOfStream() { CAutoLock cAutoLock(&m_csReceive); HRESULT hr = __super::EndOfStream(); if (FAILED(hr)) { return hr; } ASSERT(!m_fEOS); CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); pPacket->flags |= MuxerPacket::eos; PushPacket(pPacket); m_fEOS = true; return hr; }