/********************************************************************

 AviReadStream functions that are common for video and audio streams

*********************************************************************/

#include "AviReadStream.h"
#include <avifmt.h>

#include <iostream>

#define Debug if(0)

#define __MODULE__ "AviReadStream"

using namespace std;

AviReadStream::AviReadStream(streamid_t id, IMediaReadStream* stream)
    :m_pIStream(0), m_format(0), m_format_size(0), m_ch_off(0),
    m_iEof(0), rem_buffer(0), rem_size(0)
{
    if (!stream)
	throw FATAL("NULL stream passed!");

    m_id = id;
    m_pIStream = stream;
    m_pIStream->GetHeader(&m_header, sizeof(m_header));
    m_pIStream->GetFormatSize(&m_format_size);
    m_format = new char[m_format_size];
    m_pIStream->GetFormat(m_format, &m_format_size);

    fourcc_t fccType = m_pIStream->GetFourCC();
    Debug cout << "AviReadStream::GetType() " << fccType << endl;

    switch (fccType)
    {
    case streamtypeVIDEO:
	m_StreamType = Video;
        break;
    case streamtypeAUDIO:
	m_StreamType = Audio;
        break;
    default:
	m_StreamType = Other;
    }

    cout << "Successfully initialized stream " << id << endl;
    cout << "Chunk table size " << m_pIStream->GetLength()
	<< ", format size " << m_format_size << endl;
}

AviReadStream::~AviReadStream()
{
    delete[] rem_buffer;
    delete[] m_format;
}

bool AviReadStream::DropFrame() const
{
    return false;
}

bool AviReadStream::Eof() const
{
    //cout << "EOF  " << m_iEof << "   P:" << GetPos() << "  " << m_pIStream->GetLength() << endl;
    framepos_t pos = GetPos() + 1;
    unsigned int len = m_pIStream->GetLength();
    if (pos >= len || m_iEof > 15)
    {
	//Debug cout<<"End of stream ( "<<pos<<" >= "<< len <<" )"<<endl;
	return 1;
    }
    //cout<<"Not end of stream ( "<<pos<<"<"<<len<<" ) " << m_iEof <<  endl;
    return 0;
}

AviReadStream::StreamType AviReadStream::GetType() const
{
    return m_StreamType;
}

HRESULT AviReadStream::GetHeader(void* pheader, size_t n) const
{
    Debug cout << "AviReadStream::GetHeader()" << endl;
    return m_pIStream->GetHeader(pheader, n);
}

HRESULT AviReadStream::Seek(framepos_t pos)
{
    Debug cout << "AviReadStream::Seek() " << pos << endl;
    if (pos >= m_pIStream->GetLength())
	return -1;

    HRESULT hr = m_pIStream->Seek(pos);
    if (hr == 0)
	m_iEof = 0;

    rem_size = 0;
    return hr;
}

HRESULT AviReadStream::SeekTime(double timepos)
{
    Debug cout << "AviReadStream::SeekTime() " << timepos << endl;
    if (timepos >= m_pIStream->GetLengthTime())
	return -1;

    HRESULT hr = m_pIStream->SeekTime(timepos);
    if (hr == 0)
	m_iEof = 0;

    rem_size = 0;
    return hr;
}

framepos_t AviReadStream::SeekToKeyFrame(framepos_t pos)
{
    if (Seek(pos) != -1)
	return pos;
    return ERR;
}

double AviReadStream::SeekTimeToKeyFrame(double timepos)
{
    if (SeekTime(timepos) != -1)
	return timepos;//GetTime();
    return -1.0;
}

HRESULT AviReadStream::SkipFrame()
{
    Debug cout << "AviReadStream::SkipFrame()" << endl;
    return m_pIStream->SkipFrame();
}

HRESULT AviReadStream::SkipTo(double pos)
{
    Debug cout << "AviReadStream::SkipTo()" << endl;
    return m_pIStream->SkipTo(pos);
}

framepos_t AviReadStream::GetNextKeyFrame(framepos_t pos) const
{
    Debug cout << "AviReadStream::GetNextKeyFrame() " << pos << endl;
    return m_pIStream->GetNextKeyFrame(pos);
}

framepos_t AviReadStream::GetPrevKeyFrame(framepos_t pos) const
{
    Debug cout << "AviReadStream::GetPrevKeyFrame() " << pos << endl;
    if (pos == 0 || (pos == ERR && m_pIStream->GetPos() == m_pIStream->ERR))
	return ERR;
    if (pos == ERR)
        pos = GetPos();

    return m_pIStream->GetPrevKeyFrame(pos);
}

framepos_t AviReadStream::SeekToNextKeyFrame()
{
    Debug cout << "AviReadStream::SeekToNextKeyFrame() " << GetPos() << endl;
    framepos_t newpos = GetNextKeyFrame();
    if (newpos != ERR)
	Seek(newpos);

    return GetPos();
}

framepos_t AviReadStream::SeekToPrevKeyFrame()
{
    Debug cout << "AviReadStream::SeekToPrevKeyFrame() " << endl;
    framepos_t newpos = GetPrevKeyFrame();
    if (newpos != ERR)
	Seek(newpos);

    return m_pIStream->GetPos();
}

HRESULT AviReadStream::ReadDirect(void* buffer, size_t bufsize, size_t samples,
				  size_t& samples_read, size_t& bytes_read)
{
    HRESULT hr = m_pIStream->Read(samples, buffer, bufsize,
				  &bytes_read, &samples_read);
    if ((bufsize > 0) && !bytes_read)
	m_iEof++;

    return hr;
}

HRESULT AviReadStream::GetFrameFlags(int* flags) const
{
    if (!flags)
	return -1;

    // FIXME - add more flags later
    *flags = (m_pIStream->IsKeyFrame()) ? AVIIF_KEYFRAME : 0;

    return 0;
}

double AviReadStream::GetTime(framepos_t pos) const
{
    return m_pIStream->GetSampleTime(pos);
}

framepos_t AviReadStream::GetPos() const
{
    return m_pIStream->GetPos();
}

double AviReadStream::GetLengthTime() const
{
    return m_pIStream->GetLengthTime();
}

StreamInfo* AviReadStream::GetStreamInfo() const
{
    return m_pIStream->GetStreamInfo();
}

HRESULT AviReadStream::GetVideoFormatInfo(void* bi, size_t size) const
{
    cerr<<"WARNING: GetVideoFormatInfo() for non-video stream"<<endl;
    return -1;
}

HRESULT AviReadStream::GetAudioFormatInfo(void* bi, char** ext) const
{
    cerr<<"WARNING: GetAudioFormatInfo() for non-audio stream"<<endl;
    return -1;
}

IVideoDecoder* AviReadStream::GetDecoder() const
{
    cerr<<"WARNING: Getting video decoder for non-video stream"<<endl;
    return 0;
}

HRESULT AviReadStream::ReadFrame(bool render)
{
    cerr<<"WARNING: AviReadStream::ReadFrame() called for non-video stream"<<endl;
    return -1;
}

CImage* AviReadStream::GetFrame(bool readframe)
{
    cerr<<"WARNING: AviReadStream::GetFrame() called for non-video stream"<<endl;
    return 0;
}

size_t AviReadStream::GetFrameSize() const
{
    cerr<<"WARNING: AviReadStream::GetFrameSize() called for non-video stream"<<endl;
    return 0;
}

HRESULT AviReadStream::SetOutputFormat(void* bi, size_t size)
{
    cerr<<"WARNING: AviReadStream::SetOutputFormat() called"<<endl;
    return -1;
}

HRESULT AviReadStream::ReadFrames(void* buffer, size_t bufsize, size_t samples,
				  size_t& samples_read, size_t& bytes_read)
{
    cerr<<"WARNING: AviReadStream::ReadFrames() called for non-audio stream"<<endl;
    return -1;
}
