/*
* (C) 2003-2006 Gabest
* (C) 2006-2012 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 .
*
*/
#pragma once
#include
#include
#include
#include "IKeyFrameInfo.h"
#include "IBufferInfo.h"
#include "IBitRateInfo.h"
#include "BaseSplitterFileEx.h"
#include "AsyncReader.h"
#include "../../../DSUtil/DSMPropertyBag.h"
#include "../../../DSUtil/FontInstaller.h"
#define MINPACKETS 100 // Beliyaal: Changed the min number of packets to allow Bluray playback over network
#define MINPACKETSIZE 256*1024 // Beliyaal: Changed the min packet size to allow Bluray playback over network
#define MAXPACKETS 2000
#define MAXPACKETSIZE 128*1024*1024
enum {
/* various PCM "codecs" */
FF_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
FF_CODEC_ID_PCM_S16LE = 0x10000,
FF_CODEC_ID_PCM_S16BE,
FF_CODEC_ID_PCM_U16LE,
FF_CODEC_ID_PCM_U16BE,
FF_CODEC_ID_PCM_S8,
FF_CODEC_ID_PCM_U8,
FF_CODEC_ID_PCM_MULAW,
FF_CODEC_ID_PCM_ALAW,
FF_CODEC_ID_PCM_S32LE,
FF_CODEC_ID_PCM_S32BE,
FF_CODEC_ID_PCM_U32LE,
FF_CODEC_ID_PCM_U32BE,
FF_CODEC_ID_PCM_S24LE,
FF_CODEC_ID_PCM_S24BE,
FF_CODEC_ID_PCM_U24LE,
FF_CODEC_ID_PCM_U24BE,
FF_CODEC_ID_PCM_S24DAUD,
FF_CODEC_ID_PCM_ZORK,
FF_CODEC_ID_PCM_S16LE_PLANAR,
FF_CODEC_ID_PCM_DVD,
FF_CODEC_ID_PCM_F32BE,
FF_CODEC_ID_PCM_F32LE,
FF_CODEC_ID_PCM_F64BE,
FF_CODEC_ID_PCM_F64LE,
FF_CODEC_ID_PCM_BLURAY,
FF_CODEC_ID_PCM_LXF,
FF_CODEC_ID_S302M,
/* various ADPCM codecs */
FF_CODEC_ID_ADPCM_IMA_QT = 0x11000,
FF_CODEC_ID_ADPCM_IMA_WAV,
FF_CODEC_ID_ADPCM_IMA_DK3,
FF_CODEC_ID_ADPCM_IMA_DK4,
FF_CODEC_ID_ADPCM_IMA_WS,
FF_CODEC_ID_ADPCM_IMA_SMJPEG,
FF_CODEC_ID_ADPCM_MS,
FF_CODEC_ID_ADPCM_4XM,
FF_CODEC_ID_ADPCM_XA,
FF_CODEC_ID_ADPCM_ADX,
FF_CODEC_ID_ADPCM_EA,
FF_CODEC_ID_ADPCM_G726,
FF_CODEC_ID_ADPCM_CT,
FF_CODEC_ID_ADPCM_SWF,
FF_CODEC_ID_ADPCM_YAMAHA,
FF_CODEC_ID_ADPCM_SBPRO_4,
FF_CODEC_ID_ADPCM_SBPRO_3,
FF_CODEC_ID_ADPCM_SBPRO_2,
FF_CODEC_ID_ADPCM_THP,
FF_CODEC_ID_ADPCM_IMA_AMV,
FF_CODEC_ID_ADPCM_EA_R1,
FF_CODEC_ID_ADPCM_EA_R3,
FF_CODEC_ID_ADPCM_EA_R2,
FF_CODEC_ID_ADPCM_IMA_EA_SEAD,
FF_CODEC_ID_ADPCM_IMA_EA_EACS,
FF_CODEC_ID_ADPCM_EA_XAS,
FF_CODEC_ID_ADPCM_EA_MAXIS_XA,
FF_CODEC_ID_ADPCM_IMA_ISS,
FF_CODEC_ID_ADPCM_G722
};
class Packet : public CAtlArray
{
public:
DWORD TrackNumber;
BOOL bDiscontinuity, bSyncPoint, bAppendable;
static const REFERENCE_TIME INVALID_TIME = _I64_MIN;
REFERENCE_TIME rtStart, rtStop;
AM_MEDIA_TYPE* pmt;
Packet() {
pmt = NULL;
bDiscontinuity = bAppendable = FALSE;
}
virtual ~Packet() {
if (pmt) {
DeleteMediaType(pmt);
}
}
virtual int GetDataSize() { return (int)GetCount(); }
void SetData(const void* ptr, DWORD len) {
SetCount(len);
memcpy(GetData(), ptr, len);
}
};
class CPacketQueue
: public CCritSec
, protected CAutoPtrList
{
int m_size;
public:
CPacketQueue();
void Add(CAutoPtr p);
CAutoPtr Remove();
void RemoveAll();
int GetCount(), GetSize();
};
class CBaseSplitterFilter;
class CBaseSplitterInputPin
: public CBasePin
{
protected:
CComQIPtr m_pAsyncReader;
public:
CBaseSplitterInputPin(TCHAR* pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr);
virtual ~CBaseSplitterInputPin();
HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader);
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
HRESULT CheckMediaType(const CMediaType* pmt);
HRESULT CheckConnect(IPin* pPin);
HRESULT BreakConnect();
HRESULT CompleteConnect(IPin* pPin);
STDMETHODIMP BeginFlush();
STDMETHODIMP EndFlush();
};
class CBaseSplitterOutputPin
: public CBaseOutputPin
, public IDSMPropertyBagImpl
, protected CAMThread
, public IMediaSeeking
, public IBitRateInfo
{
protected:
CAtlArray m_mts;
int m_nBuffers;
private:
CPacketQueue m_queue;
HRESULT m_hrDeliver;
bool m_fFlushing, m_fFlushed;
CAMEvent m_eEndFlush;
enum { CMD_EXIT };
DWORD ThreadProc();
void MakeISCRHappy();
// please only use DeliverPacket from the derived class
HRESULT GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags);
HRESULT Deliver(IMediaSample* pSample);
// bitrate stats
struct {
UINT64 nTotalBytesDelivered;
REFERENCE_TIME rtTotalTimeDelivered;
UINT64 nBytesSinceLastDeliverTime;
REFERENCE_TIME rtLastDeliverTime;
DWORD nCurrentBitRate;
DWORD nAverageBitRate;
} m_brs;
int m_QueueMaxPackets;
protected:
REFERENCE_TIME m_rtStart;
// override this if you need some second level stream specific demuxing (optional)
// the default implementation will send the sample as is
virtual HRESULT DeliverPacket(CAutoPtr p);
// IMediaSeeking
STDMETHODIMP GetCapabilities(DWORD* pCapabilities);
STDMETHODIMP CheckCapabilities(DWORD* pCapabilities);
STDMETHODIMP IsFormatSupported(const GUID* pFormat);
STDMETHODIMP QueryPreferredFormat(GUID* pFormat);
STDMETHODIMP GetTimeFormat(GUID* pFormat);
STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat);
STDMETHODIMP SetTimeFormat(const GUID* pFormat);
STDMETHODIMP GetDuration(LONGLONG* pDuration);
STDMETHODIMP GetStopPosition(LONGLONG* pStop);
STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent);
STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat,
LONGLONG Source, const GUID* pSourceFormat);
STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags,
LONGLONG* pStop, DWORD dwStopFlags);
STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop);
STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest);
STDMETHODIMP SetRate(double dRate);
STDMETHODIMP GetRate(double* pdRate);
STDMETHODIMP GetPreroll(LONGLONG* pllPreroll);
public:
CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName,
CBaseFilter* pFilter, CCritSec* pLock,
HRESULT* phr, int nBuffers = 0,
int QueueMaxPackets = MAXPACKETS);
CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter,
CCritSec* pLock, HRESULT* phr,
int nBuffers = 0,
int QueueMaxPackets = MAXPACKETS);
virtual ~CBaseSplitterOutputPin();
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
HRESULT SetName(LPCWSTR pName);
HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties);
HRESULT CheckMediaType(const CMediaType* pmt);
HRESULT GetMediaType(int iPosition, CMediaType* pmt);
CMediaType& CurrentMediaType() { return m_mt; }
STDMETHODIMP Notify(IBaseFilter* pSender, Quality q);
// Queueing
HANDLE GetThreadHandle() {
ASSERT(m_hThread != NULL);
return m_hThread;
}
void SetThreadPriority(int nPriority) {
if (m_hThread) {
::SetThreadPriority(m_hThread, nPriority);
}
}
HRESULT Active();
HRESULT Inactive();
HRESULT DeliverBeginFlush();
HRESULT DeliverEndFlush();
HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
int QueueCount();
int QueueSize();
HRESULT QueueEndOfStream();
HRESULT QueuePacket(CAutoPtr p);
// returns true for everything which (the lack of) would not block other streams (subtitle streams, basically)
virtual bool IsDiscontinuous();
// returns IStreamsSwitcherInputPin::IsActive(), when it can find one downstream
bool IsActive();
// IBitRateInfo
STDMETHODIMP_(DWORD) GetCurrentBitRate() { return m_brs.nCurrentBitRate; }
STDMETHODIMP_(DWORD) GetAverageBitRate() { return m_brs.nAverageBitRate; }
};
class CBaseSplitterFilter
: public CBaseFilter
, public CCritSec
, public IDSMPropertyBagImpl
, public IDSMResourceBagImpl
, public IDSMChapterBagImpl
, protected CAMThread
, public IFileSourceFilter
, public IMediaSeeking
, public IAMOpenProgress
, public IAMMediaContent
, public IAMExtendedSeeking
, public IKeyFrameInfo
, public IBufferInfo
{
CCritSec m_csPinMap;
CAtlMap m_pPinMap;
CCritSec m_csmtnew;
CAtlMap m_mtnew;
CAutoPtrList m_pRetiredOutputs;
CComQIPtr m_pSyncReader;
protected:
CStringW m_fn;
CAutoPtr m_pInput;
CAutoPtrList m_pOutputs;
CBaseSplitterOutputPin* GetOutputPin(DWORD TrackNum);
DWORD GetOutputTrackNum(CBaseSplitterOutputPin* pPin);
HRESULT AddOutputPin(DWORD TrackNum, CAutoPtr pPin);
HRESULT RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt);
virtual HRESULT DeleteOutputs();
virtual HRESULT CreateOutputs(IAsyncReader* pAsyncReader) = 0; // override this ...
virtual LPCTSTR GetPartFilename(IAsyncReader* pAsyncReader);
LONGLONG m_nOpenProgress;
bool m_fAbort;
REFERENCE_TIME m_rtDuration; // derived filter should set this at the end of CreateOutputs
REFERENCE_TIME m_rtStart, m_rtStop, m_rtCurrent, m_rtNewStart, m_rtNewStop;
double m_dRate;
CAtlList m_bDiscontinuitySent;
CAtlList m_pActivePins;
CAMEvent m_eEndFlush;
bool m_fFlushing;
void DeliverBeginFlush();
void DeliverEndFlush();
HRESULT DeliverPacket(CAutoPtr p);
int m_priority;
CFontInstaller m_fontinst;
int m_QueueMaxPackets;
protected:
enum { CMD_EXIT, CMD_SEEK };
DWORD ThreadProc();
// ... and also override all these too
virtual bool DemuxInit() = 0;
virtual void DemuxSeek(REFERENCE_TIME rt) = 0;
virtual bool DemuxLoop() = 0;
virtual bool BuildPlaylist(LPCTSTR pszFileName, CAtlList& Items) { return false; };
virtual bool BuildChapters(LPCTSTR pszFileName, CAtlList& PlaylistItems, CAtlList& Items) { return false; };
public:
CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr,
const CLSID& clsid, int QueueMaxPackets = MAXPACKETS);
virtual ~CBaseSplitterFilter();
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
bool IsAnyPinDrying();
HRESULT BreakConnect(PIN_DIRECTION dir, CBasePin* pPin);
HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin);
int GetPinCount();
CBasePin* GetPin(int n);
STDMETHODIMP Stop();
STDMETHODIMP Pause();
STDMETHODIMP Run(REFERENCE_TIME tStart);
// IFileSourceFilter
STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt);
STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt);
// IMediaSeeking
STDMETHODIMP GetCapabilities(DWORD* pCapabilities);
STDMETHODIMP CheckCapabilities(DWORD* pCapabilities);
STDMETHODIMP IsFormatSupported(const GUID* pFormat);
STDMETHODIMP QueryPreferredFormat(GUID* pFormat);
STDMETHODIMP GetTimeFormat(GUID* pFormat);
STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat);
STDMETHODIMP SetTimeFormat(const GUID* pFormat);
STDMETHODIMP GetDuration(LONGLONG* pDuration);
STDMETHODIMP GetStopPosition(LONGLONG* pStop);
STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent);
STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat,
LONGLONG Source, const GUID* pSourceFormat);
STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags,
LONGLONG* pStop, DWORD dwStopFlags);
STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop);
STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest);
STDMETHODIMP SetRate(double dRate);
STDMETHODIMP GetRate(double* pdRate);
STDMETHODIMP GetPreroll(LONGLONG* pllPreroll);
protected:
friend class CBaseSplitterOutputPin;
virtual HRESULT SetPositionsInternal(void* id, LONGLONG* pCurrent,
DWORD dwCurrentFlags, LONGLONG* pStop,
DWORD dwStopFlags);
private:
REFERENCE_TIME m_rtLastStart, m_rtLastStop;
CAtlList m_LastSeekers;
public:
// IAMOpenProgress
STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent);
STDMETHODIMP AbortOperation();
// IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; }
STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { return E_NOTIMPL; }
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { return E_NOTIMPL; }
STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) { return E_NOTIMPL; }
// IAMMediaContent
STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName);
STDMETHODIMP get_Title(BSTR* pbstrTitle);
STDMETHODIMP get_Rating(BSTR* pbstrRating);
STDMETHODIMP get_Description(BSTR* pbstrDescription);
STDMETHODIMP get_Copyright(BSTR* pbstrCopyright);
STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL) { return E_NOTIMPL; }
STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; }
STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; }
STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL) { return E_NOTIMPL; }
STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL) { return E_NOTIMPL; }
STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) { return E_NOTIMPL; }
STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) { return E_NOTIMPL; }
STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText) { return E_NOTIMPL; }
// IAMExtendedSeeking
STDMETHODIMP get_ExSeekCapabilities(long* pExCapabilities);
STDMETHODIMP get_MarkerCount(long* pMarkerCount);
STDMETHODIMP get_CurrentMarker(long* pCurrentMarker);
STDMETHODIMP GetMarkerTime(long MarkerNum, double* pMarkerTime);
STDMETHODIMP GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName);
STDMETHODIMP put_PlaybackSpeed(double Speed) { return E_NOTIMPL; }
STDMETHODIMP get_PlaybackSpeed(double* pSpeed) { return E_NOTIMPL; }
// IKeyFrameInfo
STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs);
STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs);
// IBufferInfo
STDMETHODIMP_(int) GetCount();
STDMETHODIMP GetStatus(int i, int& samples, int& size);
STDMETHODIMP_(DWORD) GetPriority();
};