/********************************************************************
 *                                                                  *
 * THIS FILE IS PART OF THE aoTuvWriter SOURCE CODE.                *
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
 *                                                                  *
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
 *                                                                  *
 * THE aoTuv SOURCE CODE IS (C) COPYRIGHT 2003-2008 Aoyumi          *
 * http://www.geocities.jp/aoyoume/aotuv/                           *
 *                                                                  *
 * THE aoTuvWriter SOURCE CODE IS (C) COPYRIGHT 2008 Cocha          *
 * http://sourceforge.jp/projects/directshow/                       *
 *                                                                  *
 ********************************************************************/

#include "aoTuvWriter.h"

// -----------------------------------------------------------------------------------------------------------------------------------
int CaoTuvWriter::GetPinCount()
{  // ピンの数を返す(当フィルターは入力ピンが1つ)

   if(m_pInputPin == NULL)
      return 0;

   return 1;
}
// -----------------------------------------------------------------------------------------------------------------------------------
CBasePin *CaoTuvWriter::GetPin(int n)
{  // n番目のピンのポインタを返す(当フィルターは入力ピンが1つ)

   if(n == 0)
      return m_pInputPin;

   return NULL;
}
// -----------------------------------------------------------------------------------------------------------------------------------
STDMETHODIMP CaoTuvWriter::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
{  // インターフェイスを取得し、参照カウントをインクリメントする

   CheckPointer(ppv, E_POINTER);
   CAutoLock lock(&m_Lock);

   if (riid == IID_IFileSinkFilter)
   {
      return GetInterface((IFileSinkFilter *)this, ppv);
   }
   else if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking)
   {
      if (m_pPosition == NULL) 
      {
         HRESULT hr = S_OK;
         m_pPosition = new CPosPassThru(NAME("aoTuvWriter Pass Through"), (IUnknown *) GetOwner(), (HRESULT *) &hr, m_pInputPin);

         if (m_pPosition == NULL) 
            return E_OUTOFMEMORY;

         if (FAILED(hr)) 
         {
            delete m_pPosition;
            m_pPosition = NULL;
            return hr;
         }
      }

      return m_pPosition->NonDelegatingQueryInterface(riid, ppv);
   } 

   return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
}
// -----------------------------------------------------------------------------------------------------------------------------------
HRESULT CaoTuvWriter::SetVorbisFormat(void *pVorbisFormat)
{  // エンコード設定

   CheckPointer(pVorbisFormat, E_POINTER);

   if(m_pInputPin->IsConnected() == FALSE)
   {  // 入力ピンが接続されていない場合
      return VFW_E_NOT_CONNECTED;
   }

   return m_pInputPin->SetVorbisFormat((VORBISFORMAT *)pVorbisFormat);
}
// -----------------------------------------------------------------------------------------------------------------------------------
HRESULT CaoTuvWriter::SetVorbisTag(void *pVorbisTag)
{  // TAG設定

   CheckPointer(pVorbisTag, E_POINTER);

   if(m_pInputPin->IsConnected() == FALSE)
   {  // 入力ピンが接続されていない場合
      return VFW_E_NOT_CONNECTED;
   }

   return m_pInputPin->SetVorbisTag((VORBISTAG *)pVorbisTag);
}
// -----------------------------------------------------------------------------------------------------------------------------------
CaoTuvWriter::CaoTuvWriter(LPUNKNOWN pUnk, HRESULT *phr)
   : CBaseFilter(NAME("aoTuvWriter"), pUnk, &m_Lock, CLSID_aoTuvWriter) , m_pPosition(NULL)
{  // CaoTuvWriterのコンストラクタ
   ASSERT(phr);

   // 入力ピンの作成
   m_pInputPin = new CInputPin(this, GetOwner(), &m_Lock, &m_ReceiveLock, phr);
   if (m_pInputPin == NULL)
   {
      if(phr)
         *phr = E_OUTOFMEMORY;

      return;
   }

   if(phr)
      *phr = S_OK;
}
// -----------------------------------------------------------------------------------------------------------------------------------
CaoTuvWriter::~CaoTuvWriter()
{  // CaoTuvWriterのデコンストラクタ

   // 入力ピンの解放
   if(m_pInputPin != NULL)
   {
      delete m_pInputPin;
      m_pInputPin = NULL;
   }

   if(m_pPosition != NULL)
   {
      delete m_pPosition;
      m_pPosition = NULL;
   }
}
// -----------------------------------------------------------------------------------------------------------------------------------
STDMETHODIMP CaoTuvWriter::SetFileName(LPCOLESTR pszFileName,const AM_MEDIA_TYPE *pmt)
{  // 出力ファイル名を設定する

   CheckPointer(pszFileName,E_POINTER);
   if(wcslen(pszFileName) > MAX_PATH)
      return ERROR_FILENAME_EXCED_RANGE;

   // すでにファイルが存在するなら、ファイルを削除する
   if(::PathFileExists(pszFileName) != FALSE)
   {
      if(::DeleteFile(pszFileName) == FALSE)
         return E_FAIL; // ファイル削除に失敗
   }

   // ファイルを作成できるかチェック
   HANDLE hFile = NULL;
   hFile = ::CreateFile(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, (DWORD)0, NULL);
   if(hFile == INVALID_HANDLE_VALUE)
      return E_FAIL; // ファイル作成に失敗

   ::CloseHandle(hFile);

   // ファイル名を格納しておく
   lstrcpyW(m_awFileName, pszFileName);
   m_pInputPin->SetFileName(pszFileName);

   return S_OK;
}
// -----------------------------------------------------------------------------------------------------------------------------------
STDMETHODIMP CaoTuvWriter::GetCurFile(LPOLESTR * ppszFileName,AM_MEDIA_TYPE *pmt)
{  // 出力ファイル名を取得する

   CheckPointer(ppszFileName, E_POINTER);
   *ppszFileName = NULL;

   if (m_awFileName != NULL) 
   {
      *ppszFileName = (LPOLESTR)
      QzTaskMemAlloc(sizeof(WCHAR) * (1+lstrlenW(m_awFileName)));

        if (*ppszFileName != NULL) 
            lstrcpyW(*ppszFileName, m_awFileName);
   }

   if(pmt != NULL)
   {
      ZeroMemory(pmt, sizeof(*pmt));
      pmt->majortype = MEDIATYPE_NULL;
      pmt->subtype = MEDIASUBTYPE_NULL;
   }

   return S_OK;
}
// -----------------------------------------------------------------------------------------------------------------------------------
