/**************************************************************************
 * 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 "DecodeTta.h"

CDecodeTta::CDecodeTta(IUnknown *pUnk, HRESULT *phr)
   : CSimpleTransform(L"Tta Decoder", pUnk, CLSID_DecodeTta, phr)
{  

   ::ZeroMemory(&m_outFormat, sizeof(m_outFormat));
   m_pTTACodec = NULL;
   m_rtCurrent = 0;
}
CDecodeTta::~CDecodeTta()  
{  

   if(m_pTTACodec != NULL)
   {
      tta_codec_free(m_pTTACodec);
      m_pTTACodec = NULL;
   }
}  
HRESULT CDecodeTta::OnStart(void)
{  
   m_rtCurrent = 0;
   return S_OK;
}
HRESULT CDecodeTta::OnSeek(void)
{  
   m_rtCurrent = 0;
   return S_OK;
}
HRESULT CDecodeTta::OnTransform(IMediaSample *pInSample, IMediaSample *pOutSample)
{  

   BYTE *pbInBuffer = NULL;
   BYTE *pbOutBuffer = NULL;

   pInSample->GetPointer(&pbInBuffer);

   pOutSample->GetPointer(&pbOutBuffer);

   unsigned long len;
   len = tta_codec_decoder_decompress(m_pTTACodec, pbInBuffer, pInSample->GetActualDataLength(), pbOutBuffer, pOutSample->GetSize());

   pOutSample->SetSyncPoint(TRUE);
   pOutSample->SetDiscontinuity(FALSE);
   pOutSample->SetPreroll(FALSE);
   pOutSample->SetActualDataLength(len);

   REFERENCE_TIME rtStop;

   rtStop = m_rtCurrent + (REFERENCE_TIME)((LONGLONG)len * ONE_SECOND / m_outFormat.nAvgBytesPerSec);
   pOutSample->SetTime(&m_rtCurrent, &rtStop);
   m_rtCurrent = rtStop;

   return S_OK;
}
HRESULT CDecodeTta::OnConnectInPin(const CMediaType *pmtIn)
{  

   if(pmtIn->majortype != MEDIATYPE_Audio)
      return S_FALSE;

   if(pmtIn->subtype != MEDIASUBTYPE_TTA1)
      return S_FALSE;

   if(pmtIn->formattype != FORMAT_WaveFormatEx)
      return S_FALSE;

   WAVEFORMATEX *pwf = (WAVEFORMATEX *)pmtIn->Format();

   if(m_pTTACodec != NULL)
   {
      tta_codec_free(m_pTTACodec);
      m_pTTACodec = NULL;
   }

   m_pTTACodec = tta_codec_decoder_new(pwf->nSamplesPerSec, pwf->nChannels, pwf->wBitsPerSample);
   if(m_pTTACodec == NULL)
      return S_FALSE;

   ::CopyMemory(&m_outFormat, pwf, sizeof(m_outFormat));
   m_outFormat.wFormatTag = WAVE_FORMAT_PCM;
   m_outFormat.cbSize = 0;

   return S_OK;
}
HRESULT CDecodeTta::OnConnectOutPin(const CMediaType *pmtIn, int nInBufferSize, CMediaType *pmtOut, int *pnOutBufferSize)
{  

   pmtOut->SetType(&MEDIATYPE_Audio);
   pmtOut->SetSubtype(&MEDIASUBTYPE_PCM);
   pmtOut->SetTemporalCompression(FALSE);
   pmtOut->SetSampleSize(0);
   pmtOut->SetFormatType(&FORMAT_WaveFormatEx);
   pmtOut->SetFormat((BYTE*)&m_outFormat, sizeof(m_outFormat));

   *pnOutBufferSize = nInBufferSize * 2;

   return S_OK;
}
CUnknown * WINAPI CDecodeTta::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
{  

   ASSERT(phr);
    
   CDecodeTta *pNewObject = new CDecodeTta(punk, phr);
   if (pNewObject == NULL)
   {
      if(phr != NULL)
         *phr = E_OUTOFMEMORY;
   }

   return dynamic_cast<CUnknown *>(pNewObject);
}
