#include <windows.h>

#include "kbmio_decoder.h"

//リンカエラー回避
GLSEXPORT void eslFillMemory(void * ptrMem, BYTE bytData, DWORD dwLength)
{
    FillMemory(ptrMem, bytData, dwLength);
}
GLSEXPORT void eslMoveMemory(void * ptrDst, const void * ptrSrc, DWORD dwLength)
{
    MoveMemory(ptrDst, ptrSrc, dwLength);
}
void eriImageFilterLoop421(const EGL_IMAGE_INFO & eiiDst, const EGL_IMAGE_INFO * eiiSrc,
    SBYTE * pFlags, int nBlockSize)
{
}
/*
void * eslHeapReallocate
(HESLHEAP hHeap, void * ptrObj, DWORD dwSize, DWORD dwFlags)
{
    return realloc(ptrObj, dwSize);
}
*/
//ここまで

//////////////////////////////////////////////////////////////////////////////
//EKpiFile
//////////////////////////////////////////////////////////////////////////////
IMPLEMENT_CLASS_INFO(EKpiFile, ESLObject)
//////////////////////////////////////////////////////////////////////////////
unsigned long int EKpiFile::Read(void * ptrBuffer, unsigned long int nBytes)
{
    return m_pFile->Read(ptrBuffer, nBytes);
}
//////////////////////////////////////////////////////////////////////////////
unsigned long int EKpiFile::GetLength(void)const
{
    return m_pFile->GetSize();
}
//////////////////////////////////////////////////////////////////////////////
unsigned long int EKpiFile::Seek( long int nOffsetPos, SeekOrigin fSeekFrom )
{
    return m_pFile->Seek(nOffsetPos, fSeekFrom);
}
//////////////////////////////////////////////////////////////////////////////
unsigned long int EKpiFile::GetPosition( void ) const
{
    return m_pFile->Seek(0, FILE_CURRENT);
}
//////////////////////////////////////////////////////////////////////////////
//KbMioDecoder
//////////////////////////////////////////////////////////////////////////////
KbMioDecoder::KbMioDecoder(void)
{
    m_buffer = NULL;
    m_dwBufSize = 0;
    m_dwBufIndex = 0;
    kpi_InitMediaInfo(&m_MediaInfo);
}
//////////////////////////////////////////////////////////////////////////////
KbMioDecoder::~KbMioDecoder(void)
{
    if(m_buffer)m_player.DeleteWaveBuffer(m_buffer);
    m_player.Close();
}
//////////////////////////////////////////////////////////////////////////////
DWORD __fastcall KbMioDecoder::Open(const KPI_MEDIAINFO *cpRequest,
                                    IKpiFile *pFile,
                                    IKpiFolder *pFolder)
{
    m_file.SetKpiFile(pFile);
    if(m_player.Open(&m_file, -1) != eslErrSuccess){//-1=先読みなし
        return 0;
    }
    kpi_InitMediaInfo(&m_MediaInfo);
    m_MediaInfo.dwSampleRate = m_player.GetFrequency();
    m_MediaInfo.dwChannels = m_player.GetChannelCount();
    m_MediaInfo.nBitsPerSample = m_player.GetBitsPerSample();
    m_MediaInfo.qwLength = kpi_SampleTo100ns(m_player.GetTotalSampleCount(), m_MediaInfo.dwSampleRate);
    m_MediaInfo.dwSeekableFlags = KPI_MEDIAINFO::SEEK_FLAGS_SAMPLE;
    m_MediaInfo.dwUnitSample = 0;
    m_MediaInfo.dwCount = 1;
    m_MediaInfo.dwNumber = 1;
    return 1;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbMioDecoder::Select(DWORD dwNumber,
                                  const KPI_MEDIAINFO **ppMediaInfo,
                                  IKpiTagInfo *pTagInfo,
                                  DWORD dwTagGetFlags)
{
    if(ppMediaInfo){
        *ppMediaInfo = NULL;
    }
    if(dwNumber > m_MediaInfo.dwCount){//番号がおかしい
        return 0;
    }
    *ppMediaInfo = &m_MediaInfo;
    return dwNumber;
}
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbMioDecoder::Render(BYTE *pBuffer, DWORD dwSizeSample)
{
    if(!m_buffer){
        return 0;
    }
    const DWORD cdwBlockAlign = (m_MediaInfo.nBitsPerSample / 8) * m_MediaInfo.dwChannels;
    DWORD dwRetSample = 0;
    DWORD dwCopySample;
    while(dwRetSample < dwSizeSample){
        if(m_dwBufIndex >= m_dwBufSize){
            m_dwBufIndex = 0;
            m_player.DeleteWaveBuffer(m_buffer);
            if(m_player.IsNextDataRewound()){//終了
                m_buffer = NULL;
                return dwRetSample;
            }
            m_buffer = (BYTE*)m_player.GetNextWaveBuffer(m_dwBufSize);
            if(!m_buffer)break;
        }
        dwCopySample = (m_dwBufSize - m_dwBufIndex) / cdwBlockAlign;
        if(dwCopySample > dwSizeSample - dwRetSample){
            dwCopySample = dwSizeSample - dwRetSample;
        }
        memcpy(pBuffer + dwRetSample * cdwBlockAlign, 
               m_buffer + m_dwBufIndex, 
               dwCopySample * cdwBlockAlign);
        dwRetSample += dwCopySample;
        m_dwBufIndex += dwCopySample * cdwBlockAlign;
    }
    return dwRetSample;
}
//////////////////////////////////////////////////////////////////////////////
UINT64 WINAPI KbMioDecoder::Seek(UINT64 qwPosSample, DWORD dwFlag)
{
    if(m_buffer)m_player.DeleteWaveBuffer(m_buffer);
    DWORD dwSample = qwPosSample;
    DWORD dwOffsetBytes = 0;
    m_buffer = (BYTE*)m_player.GetWaveBufferFrom(dwSample, m_dwBufSize, dwOffsetBytes);
    m_dwBufIndex = 0;
    return dwSample;
}
//////////////////////////////////////////////////////////////////////////////
