/**************************************************************************
 * Copyright (C) 2008 Cocha                                               *
 * http://sourceforge.jp/projects/ecodecotool/                            *
 *                                                                        *
 *  This Program 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 2, or (at your option)   *
 *  any later version.                                                    *
 *                                                                        *
 *  This Program 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 GNU Make; see the file COPYING.  If not, write to          *
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *
 *                                                                        *
 **************************************************************************/

#include "CSimpleFilter.h"

CSimplePushSourceOutputPin::CSimplePushSourceOutputPin(CSimplePushSource *pFilter, CCritSec *pLock, HRESULT *phr)
   : CSourceStream(TEXT("Output"), phr, pFilter, TEXT("Output"))
{  

   m_nOutBufferSize = 0;
   m_pFilter = pFilter;
   m_pMyLock = pLock;
}
CSimplePushSourceOutputPin::~CSimplePushSourceOutputPin()
{  

}
HRESULT CSimplePushSourceOutputPin::FillBuffer(IMediaSample *pOutSample)
{
   CheckPointer(pOutSample, E_POINTER);

   CAutoLock lck(m_pMyLock);

   HRESULT hr;
   hr = ((CSimplePushSource *)m_pFilter)->FillBuffer(pOutSample);

   if(hr == S_OK)
      pOutSample->GetTime(&((CSimplePushSource *)m_pFilter)->m_rtStart, &((CSimplePushSource *)m_pFilter)->m_rtEnd);

   return hr;
}  
HRESULT CSimplePushSourceOutputPin::OnThreadCreate(void)
{  
   CAutoLock lck(m_pMyLock);
   return ((CSimplePushSource *)m_pFilter)->OnStart();
}
HRESULT CSimplePushSourceOutputPin::OnThreadDestroy(void)
{  
   CAutoLock lck(m_pMyLock);
   return ((CSimplePushSource *)m_pFilter)->OnStop();
}
HRESULT CSimplePushSourceOutputPin::GetMediaType(CMediaType *pOutMediaType)
{  
   return ((CSimplePushSource *)m_pFilter)->OnConnectOutPin(pOutMediaType, &m_nOutBufferSize, &((CSimplePushSource *)m_pFilter)->m_rtTotalTime);
}
HRESULT CSimplePushSourceOutputPin::CheckMediaType(const CMediaType *pMediaType)
{
   CheckPointer(pMediaType, E_POINTER);  

   CMediaType mt;
   GetMediaType(&mt);

   if(mt == *pMediaType)
      return S_OK;  

   return VFW_E_TYPE_NOT_ACCEPTED;
}  
HRESULT CSimplePushSourceOutputPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties)
{
   CheckPointer(pAlloc, E_POINTER);
   CheckPointer(pProperties, E_POINTER);

   if(m_nOutBufferSize <= 0)
      return E_FAIL;

   pProperties->cBuffers = 1;
   pProperties->cbBuffer = m_nOutBufferSize;
   pProperties->cbAlign = 1;
   pProperties->cbPrefix = 0;

   HRESULT hr;
   ALLOCATOR_PROPERTIES Actual;
   hr = pAlloc->SetProperties(pProperties, &Actual);
   if(FAILED(hr)) return hr;

   if( (pProperties->cBuffers > Actual.cBuffers) || (pProperties->cbBuffer > Actual.cbBuffer) )
       return E_FAIL;

   return S_OK;
}
CSimplePushSource::CSimplePushSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, REFCLSID clsid, HRESULT *phr)
   : CSource(pName, pUnk, clsid)
{  

   m_pOutPin = new CSimplePushSourceOutputPin(this, &m_MyLock, phr);
   if(m_pOutPin == NULL)
   {
      if(phr != NULL)
         *phr = E_OUTOFMEMORY;
   }

   m_rtStart = 0;
   m_rtEnd = 0;
   m_rtStopTime = 0;
   m_rtTotalTime = 0;
   ::ZeroMemory(m_awInputFileName, sizeof(m_awInputFileName));
}  
CSimplePushSource::~CSimplePushSource()  
{  

   SAFE_DELETE(m_pOutPin);
}  
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetDuration(LONGLONG *pDuration)
{
   CheckPointer(pDuration, E_POINTER);
   *pDuration = (LONGLONG)m_rtTotalTime;
   return S_OK;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetCurrentPosition(LONGLONG *pCurrent)
{
   CheckPointer(pCurrent, E_POINTER);
   *pCurrent = m_rtStopTime;
   return S_OK;
}
STDMETHODIMP CSimplePushSource::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
{  

   CheckPointer(ppv, E_POINTER);
   CAutoLock lck(&m_MyLock);

   if(riid == IID_IMediaSeeking)
      return GetInterface((IMediaSeeking *)this, ppv);

   return OnQueryInterface(riid, ppv);
}
STDMETHODIMP CSimplePushSource::OnQueryInterface(REFIID riid, void ** ppv)
{  
   return CSource::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CSimplePushSource::OnStart(void)
{  
   return S_OK;
}
HRESULT CSimplePushSource::OnStop(void)
{  
   return S_OK;
}
HRESULT CSimplePushSource::OnSeek(LONGLONG llNewPosition, LONGLONG llStopPosition)
{  
   return S_OK;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetCapabilities(DWORD *pCapabilities)
{  
   CheckPointer(pCapabilities, E_POINTER);
   *pCapabilities = AM_SEEKING_CanSeekAbsolute;
   return S_OK;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::CheckCapabilities(DWORD *pCapabilities)
{  

   CheckPointer(pCapabilities, E_POINTER);

   if(*pCapabilities & AM_SEEKING_CanSeekAbsolute)
   {
      if(*pCapabilities == AM_SEEKING_CanSeekAbsolute)
         return S_OK;

      return S_FALSE;
   }

   return E_FAIL;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::IsFormatSupported(const GUID *pFormat)
{  
   CheckPointer(pFormat , E_POINTER);
   if(*pFormat == TIME_FORMAT_MEDIA_TIME)
      return S_OK;

   return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::QueryPreferredFormat(GUID *pFormat)
{  
   CheckPointer(pFormat , E_POINTER);
   *pFormat = TIME_FORMAT_MEDIA_TIME;
   return S_OK;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetTimeFormat(GUID *pFormat)
{  
   CheckPointer(pFormat , E_POINTER);
   *pFormat = TIME_FORMAT_MEDIA_TIME;
   return S_OK;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::IsUsingTimeFormat(const GUID *pFormat)
{  
   CheckPointer(pFormat , E_POINTER);
   if(*pFormat == TIME_FORMAT_MEDIA_TIME)
      return S_OK;

   return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::SetTimeFormat(const GUID *pFormat)
{  
   CheckPointer(pFormat , E_POINTER);
   if(*pFormat == TIME_FORMAT_MEDIA_TIME)
      return S_OK;

   return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetStopPosition(LONGLONG *pStop)
{  
   CheckPointer(pStop, E_POINTER);
   *pStop = (REFERENCE_TIME)m_rtStopTime;
   return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
{  
   return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::SetPositions(LONGLONG *pNewPosition, DWORD dwCurrentFlags, LONGLONG *pStopPosition, DWORD dwStopFlags)
{  

   CAutoLock lck(&m_MyLock);

   if(pNewPosition == NULL && pStopPosition == NULL)
      return E_POINTER;

   m_pOutPin->BeginFlush();

   LONGLONG llNewPosition = -1;
   LONGLONG llStopPosition = -1;

   if(pNewPosition != NULL)
      llNewPosition = *pNewPosition;

   if(llStopPosition != NULL)
      llStopPosition = *pStopPosition;

   HRESULT hr;
   hr = OnSeek(llNewPosition, llStopPosition);

   if(llStopPosition != NULL && hr == S_OK)
      m_rtStopTime = (REFERENCE_TIME)*pStopPosition;

   m_pOutPin->EndFlush();

   return hr;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetPositions(LONGLONG *pCurrent, LONGLONG *pStop)
{  

   CAutoLock lck(&m_MyLock);

   if(pCurrent == NULL && pStop == NULL)
      return E_POINTER;

   if(pCurrent != NULL)
      *pCurrent = (LONGLONG)m_rtStart;

   if(pStop != NULL)
      *pStop = (LONGLONG)m_rtEnd;

   return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest)
{  
   return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::SetRate(double dRate)
{  
   return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetRate(double *pdRate)
{  
   return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CSimplePushSource::GetPreroll(LONGLONG *pPreroll)
{  

   CheckPointer(pPreroll, E_POINTER);
    *pPreroll = 0;
    return S_OK;
}
