/**************************************************************************
 * 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"


CSimpleTransform::CSimpleTransform(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, REFCLSID clsid, HRESULT *phr) :
   CTransformFilter(pName, pUnk, clsid)
{  

   
   m_nOutBufferSize = 0;
   ::memset(&m_mtOut, 0, sizeof(m_mtOut));

   if(phr != NULL)
      *phr = S_OK;
}

CSimpleTransform::~CSimpleTransform()
{  

}

HRESULT CSimpleTransform::CheckInputType(const CMediaType *pmtIn)
{  

   CAutoLock lck(&m_Lock);

   return OnConnectInPin(pmtIn);
}

HRESULT CSimpleTransform::CheckTransform(const CMediaType *pmtIn, const CMediaType *pmtOut)
{  

   if( (pmtIn->majortype != m_pInput->CurrentMediaType().majortype) ||
       (pmtIn->subtype != m_pInput->CurrentMediaType().subtype) ||
       (pmtIn->formattype != m_pInput->CurrentMediaType().formattype) ||
       (pmtOut->majortype != m_mtOut.majortype) ||
       (pmtOut->subtype != m_mtOut.subtype) ||
       (pmtOut->formattype != m_mtOut.formattype) )
   {
      return S_FALSE;
   }

   return S_OK;
}

HRESULT CSimpleTransform::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties)
{  

   if(m_pInput->IsConnected()==FALSE)
      return E_FAIL;

   if(m_nOutBufferSize <= 0)
      return E_FAIL;

   pProperties->cbBuffer = m_nOutBufferSize;
   pProperties->cBuffers = 1;
   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;
}

HRESULT CSimpleTransform::GetMediaType(int iPosition, CMediaType *pOutMediaType)
{  

   CheckPointer(m_pInput, E_POINTER);

   if(iPosition < 0)
      return E_INVALIDARG;

   if(iPosition > 0)
      return VFW_S_NO_MORE_ITEMS;

   if (m_pInput->IsConnected() == FALSE)
   {
      pOutMediaType->SetType(&MEDIATYPE_NULL);
      pOutMediaType->SetSubtype(&MEDIASUBTYPE_None);
      pOutMediaType->SetFormatType(&FORMAT_None);
      return S_OK;
   }

   
   HRESULT hr;
   ALLOCATOR_PROPERTIES InProps;
   IMemAllocator * pInAlloc = NULL;

   hr = m_pInput->GetAllocator(&pInAlloc);
   if(FAILED(hr)) return hr;

   hr = pInAlloc->GetProperties(&InProps);
   SAFE_RELEASE(pInAlloc);

   if(FAILED(hr))
      return hr;

   hr = OnConnectOutPin(&m_pInput->CurrentMediaType(), (int)InProps.cbBuffer, pOutMediaType, &m_nOutBufferSize);

   m_mtOut = *pOutMediaType;

   return hr;
}

HRESULT CSimpleTransform::Receive(IMediaSample *pInSample)
{
   
   AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
   if(pProps->dwStreamId != AM_STREAM_MEDIA)
      return m_pOutput->Deliver(pInSample);

   CAutoLock lck(&m_Lock);

   return OnReceive(pInSample);
}

HRESULT CSimpleTransform::OnReceive(IMediaSample *pInSample)
{
   HRESULT hr;
   IMediaSample *pOutSample = NULL;

   hr = InitializeOutputSample(pInSample, &pOutSample);
   if (FAILED(hr))
   {
      SAFE_RELEASE(pOutSample);
      return hr;
   }

   hr = OnTransform(pInSample, pOutSample);
   if (FAILED(hr))
   {
      SAFE_RELEASE(pOutSample);
      return hr;
   }

   if (hr == S_OK)
   {
      if(pOutSample->GetActualDataLength() > 0)
      {
         hr = m_pOutput->Deliver(pOutSample);
         m_bSampleSkipped = FALSE;
      }
   }
   else
   {
      if(hr == S_FALSE)
      {
         SAFE_RELEASE(pOutSample);
         m_bSampleSkipped = TRUE;
         if (!m_bQualityChanged)
         {
            NotifyEvent(EC_QUALITY_CHANGE, 0, 0);
            m_bQualityChanged = TRUE;
         }

         return NOERROR;
      }
   }

   SAFE_RELEASE(pOutSample);

   return hr;
}

HRESULT CSimpleTransform::OnTransform(IMediaSample *pInSample, IMediaSample *pOutSample)
{
   return E_UNEXPECTED;
}

HRESULT CSimpleTransform::BeginFlush()
{  

   HRESULT hr = CTransformFilter::BeginFlush();

   CAutoLock lck(&m_Lock);

   OnSeek();

   return hr;
}

HRESULT CSimpleTransform::BreakConnect(PIN_DIRECTION dir)
{
   if(dir == PINDIR_OUTPUT)
      ::memset(&m_mtOut, 0, sizeof(m_mtOut));

   return S_OK;
}

STDMETHODIMP CSimpleTransform::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
   CAutoLock lck(&m_Lock);

   return OnQueryInterface(riid, ppv);
}

HRESULT CSimpleTransform::StartStreaming()
{
   return OnStart();
}

HRESULT CSimpleTransform::StopStreaming()
{
   CAutoLock lck(&m_Lock);
   return OnStop(false);
}

HRESULT CSimpleTransform::EndOfStream(void)
{
   HRESULT hr = NOERROR;

   CAutoLock lck(&m_Lock);

   hr = OnStop(true);
   if(FAILED(hr))
      return hr;

	return CTransformFilter::EndOfStream();
}

STDMETHODIMP CSimpleTransform::OnQueryInterface(REFIID riid, void ** ppv)
{
   return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
}

HRESULT CSimpleTransform::OnStart(void)
{  
   return NOERROR;
}

HRESULT CSimpleTransform::OnStop(bool bEos)
{  
   return NOERROR;
}

HRESULT CSimpleTransform::OnSeek(void)
{  
   return NOERROR;
}

