#include "AsfInputStream.h"
#include "AsfReadStream.h"
#include "AsfReadHandler.h"
#include "asf_guids.h"

//#include <stdio.h>

using namespace std;

ASFReadStream::ASFReadStream(ASFReadHandler* parent)
    :m_pParent(parent), m_pSeekInfo(0), m_uiPosition(0),
    m_pIterator(0), m_iPointer(0), m_uiSubpointer(0), m_uiLastTimestamp(0),
    m_bValidBuf(false)
{
}

ASFReadStream::ASFReadStream(const ASFReadStream& c)
{
    m_Header=c.m_Header;
    m_pParent=c.m_pParent;
    m_iId=c.m_iId;
    m_uiPosition=c.m_uiPosition;
    m_pIterator=c.m_pIterator;
    if (m_pIterator)
	m_pIterator->addRef();
    m_iPointer=c.m_iPointer;
    m_uiLastTimestamp=c.m_uiLastTimestamp;
    m_pSeekInfo=c.m_pSeekInfo;
    m_bIsAudio=c.m_bIsAudio;
    m_bIsScrambled=c.m_bIsScrambled;
    m_pcScrambleBuf=c.m_pcScrambleBuf;
    m_bValidBuf=c.m_bValidBuf;
    if (m_bIsScrambled)
    {
    	char* tmp=(char*)(&m_Header.hdr.aud.wfex);
    	tmp+=18+m_Header.hdr.aud.wfex.cbSize;
	m_pScrambleDef=(const ASFAudioScrambleDef*)tmp;
	m_iScrOffset=c.m_iScrOffset;
    }
//    if(c.m_pcScrambleBuf)
//	m_pcScrambleBuf=new char[c.m_pScrambleDef->chunk_size*c.m_pScrambleDef->block_size];//correct?
}

ASFReadStream& ASFReadStream::operator=(const ASFReadStream& c)
{
    m_Header=c.m_Header;
    m_pParent=c.m_pParent;
    m_iId=c.m_iId;
    m_uiPosition=c.m_uiPosition;
    m_pIterator=c.m_pIterator;
    if (m_pIterator)
	m_pIterator->addRef();
    m_iPointer=c.m_iPointer;
    m_uiLastTimestamp=c.m_uiLastTimestamp;
    m_pSeekInfo=c.m_pSeekInfo;
    m_bIsAudio=c.m_bIsAudio;
    m_bValidBuf=c.m_bValidBuf;
    if(m_bIsScrambled)
    {
    	char* tmp=(char*)(&m_Header.hdr.aud.wfex);
    	tmp+=18+m_Header.hdr.aud.wfex.cbSize;
	m_pScrambleDef=(const ASFAudioScrambleDef*)tmp;
	m_iScrOffset=c.m_iScrOffset;
    }
//    if(c.m_pcScrambleBuf)
//	m_pcScrambleBuf=new char[c.m_pScrambleDef->chunk_size*c.m_pScrambleDef->block_size];//correct?
    return *this;
}

ASFReadStream::~ASFReadStream()
{
    if (m_pIterator)
	m_pIterator->release();
//    delete m_pcScrambleBuf;
//    if(m_pcScrambleBuf)
//	free(m_pcScrambleBuf);
}

HRESULT ASFReadStream::GetHeader(void* pheader, size_t size) const
{
    if (!pheader || (size < sizeof(AVIStreamHeader)))
	return -1;
    memset(pheader, 0, size);

    AVIStreamHeader* p = (AVIStreamHeader*) pheader;

    if (!m_pSeekInfo)
    {
	p->dwRate=15;
	p->dwScale=1;
	p->dwLength=0x7FFFFFFF;
    }
    else
    {
	double stream_length = m_pParent->m_Header.play_time/10000000.;
	p->dwRate=1000000;
	if (m_pSeekInfo->size())
	    p->dwScale=1000000/15;
	else
	    p->dwScale=int(1000000*stream_length/m_pSeekInfo->size());
	p->dwLength=m_pSeekInfo->size();
    }

    if (m_bIsAudio)
    {
	p->fccType=mmioFOURCC('a', 'u', 'd', 's');
	p->fccHandler=m_Header.hdr.aud.wfex.wFormatTag;
	p->dwSampleSize=m_Header.hdr.aud.wfex.nBlockAlign;
    }
    else if (m_Header.hdr.uid_type == guid_video_stream)
    {
	p->fccType=mmioFOURCC('v', 'i', 'd', 's');
	p->fccHandler=m_Header.hdr.vid.biCompression;
	p->rcFrame.right=m_Header.hdr.vid.biWidth;
	p->rcFrame.top=m_Header.hdr.vid.biHeight;
    }
    return 0;
}

bool ASFReadStream::IsKeyFrame(framepos_t lFrame) const
{
    if (!m_pSeekInfo || m_bIsAudio)
	return true;

    framepos_t info_pos;

    if (lFrame != ERR)
    {
	if (lFrame >= m_pSeekInfo->size())
	    return true;
	info_pos = lFrame;
    }
    else
	info_pos = GetPos();

    return (info_pos != ERR) ? (*m_pSeekInfo)[info_pos].keyframe : true;
}

framepos_t ASFReadStream::GetPos() const
{
    return (m_pSeekInfo) ? m_pSeekInfo->find(m_uiLastTimestamp) : 0;
}

framepos_t ASFReadStream::GetPrevKeyFrame(framepos_t lFrame) const
{
    if (!m_pSeekInfo)
	return 0;

    framepos_t info_pos;
    if (lFrame != ERR)
    {
	if (lFrame >= m_pSeekInfo->size())
	    return 0;
	info_pos = lFrame;
    }
    else
	info_pos = GetPos();

    return m_pSeekInfo->prevKeyFrame(info_pos);
}

framepos_t ASFReadStream::GetNextKeyFrame(framepos_t lFrame) const
{
    if (!m_pSeekInfo)
	return 0;

    framepos_t info_pos;

    if (lFrame != ERR)
    {
	if (lFrame >= m_pSeekInfo->size())
	    return 0;
	info_pos = lFrame;
    }
    else
	info_pos = GetPos();

    return m_pSeekInfo->nextKeyFrame(info_pos + 1);
}

framepos_t ASFReadStream::GetNearestKeyFrame(framepos_t lFrame) const
{
    if (!m_pSeekInfo)
	return 0;

    framepos_t info_pos;

    if (lFrame != ERR)
    {
	if (lFrame >= m_pSeekInfo->size())
	    return 0;
	info_pos = lFrame;
    }
    else
	info_pos = GetPos();

    return m_pSeekInfo->nearestKeyFrame(info_pos);
}

unsigned int ASFReadStream::GetLength() const
{
    return (m_pSeekInfo) ? m_pSeekInfo->size() : 0x7FFFFFFF;
}

double ASFReadStream::GetLengthTime() const
{
    if (m_pSeekInfo && m_pSeekInfo->size() > 0)
	return (*m_pSeekInfo)[m_pSeekInfo->size() - 1].object_start_time / 1000.0;

    return m_pParent->m_Header.play_time / 10000000.0;
}

StreamInfo* ASFReadStream::GetStreamInfo() const
{
    if (!m_pSeekInfo)
    {
	cout << "ASFReadStream::GetStreamInfo() no seek info" << endl;
        return 0;
    }
    if (m_StreamInfo.m_dLengthTime == 0.0)
    {
	unsigned int kfmax = 0;
	unsigned int kfmin = ~0U;
	unsigned int kfchunks = 0;
	int64_t kfsize = 0;
	unsigned int max = 0;
	unsigned int min = ~0U;
	unsigned int chunks = 0;
	int64_t size = 0;

	for (unsigned i = 0; i < m_pSeekInfo->size(); i++)
	{
	    unsigned int l = (*m_pSeekInfo)[i].object_length;
	    if ((*m_pSeekInfo)[i].keyframe)
	    {
		kfmax = (kfmax > l) ? kfmax : l;
		kfmin = (kfmin < l) ? kfmin : l;
		kfsize += l;
                kfchunks++;
	    }
	    else
	    {
		max = (max > l) ? max : l;
		min = (min < l) ? min : l;
		size += l;
		chunks++;
	    }
	}

	m_StreamInfo.m_uiMaxKfFrameSize = kfmax;
        m_StreamInfo.m_uiMinKfFrameSize = kfmin;
        m_StreamInfo.m_uiKfFramesSize = kfsize;
        m_StreamInfo.m_uiKfFrames = kfchunks;

	m_StreamInfo.m_uiMaxFrameSize = max;
        m_StreamInfo.m_uiMinFrameSize = min;
        m_StreamInfo.m_uiFramesSize = size;
        m_StreamInfo.m_uiFrames = chunks;

	m_StreamInfo.m_dLengthTime = GetLengthTime();
    }

    return new StreamInfo(m_StreamInfo);
}

/**
    We assume that audio data is aligned by samples.
    We can restart reading audio from the middle of object,
    but only from fragment boundaries. It is necessary because
    objects may be quite large.
**/
HRESULT ASFReadStream::Read(size_t lSamples, void* lpBuffer, size_t cbBuffer,
			    size_t* plBytes, size_t* plSamples)
{
    if (!m_bIsScrambled || !lpBuffer)
	return ReadInternal(lSamples, lpBuffer, cbBuffer, plBytes, plSamples);

    size_t sampCount = 0, bCount = 0;
    const unsigned short& samp_size = m_Header.hdr.aud.wfex.nBlockAlign;
    size_t lSamples_actual = cbBuffer / samp_size;
    if (lSamples_actual < lSamples)
        lSamples = lSamples_actual;
    while (sampCount < lSamples)
    {
	size_t sampRead, bRead;

	if (!m_bValidBuf)
	{
	    HRESULT res = ReadInternal((m_pcScrambleBuf.size() - m_iScrOffset)
				       / m_pScrambleDef->block_align_1,
				       &m_pcScrambleBuf[m_iScrOffset],
				       m_pcScrambleBuf.size() - m_iScrOffset,
				       &bRead, &sampRead);
	}
	if (bRead == 0)
	    break;

	m_bValidBuf = true;
	unsigned int i = m_iScrOffset / m_pScrambleDef->block_align_1;
	for (; i<m_pcScrambleBuf.size()/m_pScrambleDef->block_align_1; i++)
	{
	    if (lSamples <= sampCount)
		break;
	    int cnt = m_pScrambleDef->block_size;
	    int row=i / cnt;
	    int col=i % cnt;
	    int idx=row + col * m_pScrambleDef->chunk_size / m_pScrambleDef->block_align_1;
	    //printf("%f ms, %d bytes in buffer:\n", m_dLastTimestamp, m_pcScrambleBuf.size()-m_iScrOffset);
	    //printf("%d bytes in buffer:\n", m_pcScrambleBuf.size()-m_iScrOffset);
	    //printf("%d: writing block %dx%d as %d\n", i, row, col, index);
	    memcpy(lpBuffer,
		   &m_pcScrambleBuf[idx * m_pScrambleDef->block_align_1],
		   m_pScrambleDef->block_align_1);
	    lpBuffer = (char*)lpBuffer + m_pScrambleDef->block_align_1;
	    sampCount++;
	    m_iScrOffset += m_pScrambleDef->block_align_1;
	    if ((unsigned)m_iScrOffset >= m_pcScrambleBuf.size())
	    {
		m_iScrOffset = 0;
		m_bValidBuf = false;
	    }
	}
    }
    if (plBytes)
	*plBytes = lSamples * samp_size;
    if (plSamples)
	*plSamples = lSamples;
    //cout << " READSAMPLE " << lSamples << "  isaudio " << m_bIsAudio << endl;
    return 0;
}

HRESULT ASFReadStream::ReadInternal(size_t lSamples, void *lpBuffer,
				    size_t cbBuffer,
				    size_t* plBytes, size_t* plSamples)
{
    size_t read_bytes = 0, read_samples = 0;
    size_t buffer_required = 0;
    bool abort_process = false;
    const unsigned short& samp_size=m_Header.hdr.aud.wfex.nBlockAlign;

    if (m_bIsAudio)
    {
	//cout << "***********   READING PACKET " << lSamples << "  " << m_uiSubpointer << "  " << m_iPointer << "  cbBuf " << cbBuffer << endl;

	//if(samp_size)
	//	{
	size_t lSamples_actual = cbBuffer/samp_size;
	if (lSamples_actual < lSamples)
	    lSamples = lSamples_actual;
	//cout << "cbUf " << cbBuffer << " sampsize " << samp_size << "  lact " << lSamples_actual << endl;

        cbBuffer = lSamples * samp_size;
//	}
//	else
//	    cout<<"WARNING: audio_stream with sample size = 0?"<<endl;
        memset(lpBuffer, 0, cbBuffer);
    }
    unsigned int _position2 = 0;
    if (!lpBuffer)
    {
	// if we are only queried for buffer size,
	// we shouldn't change our global pointer
	_position2 = m_uiPosition;
	m_pIterator->undoPosition();
    }
    bool in_fragment = false;
    //unsigned int fragment_start_packet=0;
    unsigned int fragment_start_pos=0;
    unsigned int fragment_read_bytes=0;
    size_t object_read_size=0;
    if (m_iPointer + m_uiSubpointer)
    {
	if (m_iPointer)
	    in_fragment = true;
	object_read_size = m_iPointer;
	//read_bytes = m_uiSubpointer;
        //if (m_bIsAudio)
	//    cout << "SETTING OBJEC " << object_read_size << endl;
    }
    /**
	This code should be tolerant to most possible errors.
	It only returns less data than requested if it gets
	to the end of stream. In all errorneous situations which
	are possible during reassembly of packets, it simply skips
	suspicious data.
    **/

    int result = 0;

    while (((read_bytes <= cbBuffer) || !lpBuffer)
	  && (read_samples < lSamples) && !abort_process)
    {
	bool success;
	packet p = m_pIterator->getPacket(success);
	if (!success)
	{
	    //cout << "s: success " << success << "  pos: " << m_uiPosition << " rb: " << read_bytes << "  " << lSamples << endl;
	    result = -1;
	    break;
	}

	while (m_uiPosition < p.fragments.size())
	{
            //cout << "Pos " << (int) p.fragments[m_uiPosition].stream_id << endl;
	    //if (m_bIsAudio)
	    //    cout << "XXXXXXXXX " << object_read_size << endl;
	    if (p.fragments[m_uiPosition].stream_id != m_iId)
	    {
		m_uiPosition++;
		continue;
	    }

//	    if(reached<m_uiPosition){reached++; continue;}
	    const fragment& f = p.fragments[m_uiPosition];
	    m_uiPosition++;

	    //cout << " inf: " << in_fragment << "   pos: " << m_uiPosition << endl;
	    //if (m_bIsAudio)
	    //    cout << "datalen " << f.data_length << " objlen " << f.object_length << "  offset " << f.fragment_offset << endl;
	    if (f.data_length < f.object_length)//incomplete object
	    {
		if (lpBuffer && (f.data_length + read_bytes) > cbBuffer)
		{
		    // this fragment won't fit into the buffer
		    //  cout<<"WARNING: this fragment won't fit into the buffer"<<
		    //   "( buffer size "<<cbBuffer<<", read bytes "<<read_bytes<<
		    //   ", fragment data length "<<f.data_length
		    //   <<", position "<<m_uiPosition<<", packet timestamp "<<p.hdr.send_time/1000.0
		    //   <<endl;
		    abort_process = true;
		    //m_pIterator->forgetUndo();
		    m_uiPosition--;
		    break;
		}

		if (!in_fragment && f.fragment_offset)
		{
		    cout << "WARNING: incomplete fragment found"
			<< " ( offset " << f.fragment_offset
			<< ", length " << f.object_length
			<< " ), packet timestamp " << p.hdr.send_time / 1000.0
			<< endl;
	    	    read_bytes = fragment_read_bytes;
 		    in_fragment = false;
		    m_pIterator->forgetUndo();
                    result = -1;
		    continue;
		}

		if (in_fragment && f.fragment_offset != object_read_size)
		{
		    cout << "WARNING: fragment with unexpected offset while"
			<< " reassembling ( expected " << object_read_size
			<< ", found " << f.fragment_offset
			<< " ), packet timestamp " << p.hdr.send_time/1000.0
			<< endl;
		    //m_uiPosition=fragment_start_pos;
		    //_chunk=fragment_start_packet;
		    read_bytes = fragment_read_bytes;
		    m_pIterator->forgetUndo();
		    in_fragment = false;
                    result = -1;
		    continue;
		}

		size_t to_read = f.data_length - m_uiSubpointer;
		//cout << "to_read " << to_read << "   " << m_uiSubpointer
		//   << " data: " << f.data_length << endl;
		if (lpBuffer)
		    if (to_read > (cbBuffer - read_bytes))
			to_read = cbBuffer - read_bytes;

		if (in_fragment && (object_read_size + to_read > f.object_length))
		{
		    cout << "WARNING: overflow while reassembling object"
			<< " ( reassembled " << object_read_size
                        << " + to_read " << to_read
			<< " bytes, size " << f.object_length
			<< " bytes ), packet timestamp " << p.hdr.send_time / 1000.0
			<< endl;
		    //m_uiPosition=fragment_start_pos;
		    //chunk=fragment_start_packet;
	    	    read_bytes = fragment_read_bytes;
 		    in_fragment = false;
		    m_pIterator->forgetUndo();
		    m_iPointer=0;
		    result = -1;
		    continue;
		}

		if (lpBuffer)
		{
		    //if (m_bIsAudio)
		    //    cout << "copy " << read_bytes << " len " << to_read << "  " << f.pointer << endl;
		    memcpy((char*)lpBuffer + read_bytes,
			   &p[f.pointer + m_uiSubpointer], to_read);
		}
		read_bytes += to_read;
		m_uiSubpointer += to_read;

		//cout << "sub " << m_uiSubpointer << "  " << f.data_length
		//    << "  " << read_bytes << "  to_read " << to_read << endl;

		if (m_uiSubpointer >= f.data_length)
		    m_uiSubpointer = 0;
		else
		    m_uiPosition--;

		if (read_bytes > buffer_required)
		    buffer_required = read_bytes;
	        object_read_size += to_read;

		if (m_bIsAudio)
		{
		    read_samples = read_bytes / samp_size;
		    //cout << "READSAMPLER " << read_samples << "   " << read_bytes << "   " << samp_size << endl;
		}
		if (in_fragment)
		{
		    if (object_read_size == f.object_length) // completed
		    {
			//cout << "packet completed!!! " << f.object_length << endl;
			in_fragment = false;
			m_pIterator->forgetUndo();
			if (!m_bIsAudio)
			    read_samples++;
		    }
		}
		else // just entered fragmented object
		{
                    in_fragment = true;
		    m_pIterator->undoPosition();
		    fragment_start_pos = m_uiPosition - 1;
		    fragment_read_bytes = read_bytes - to_read;
		    object_read_size = to_read;
		}
		m_uiLastTimestamp = f.object_start_time - m_pParent->m_Header.play_start_time;

		if (read_samples >= lSamples)
		{
		    //cout << "ABORTING  " << read_samples << "  " << lSamples << endl;
		    abort_process = true;
		    break;
		}
	    }
	    else //complete object
	    {
		if (in_fragment)
		{
		    cout<<"WARNING: found complete object while reassembling, packet timestamp "<<p.hdr.send_time/1000.0<<endl;
	    	    read_bytes = fragment_read_bytes;
		    in_fragment = false;
		    m_pIterator->forgetUndo();
		    result = -1;
		}
		if (!m_bIsAudio && lpBuffer && (f.data_length>(cbBuffer-read_bytes)))
		// this fragment won't fit into the buffer
	        {
//		    cout<<"WARNING: this fragment won't fit into the buffer"<<
//		    "( buffer size "<<cbBuffer<<", read bytes "<<read_bytes<<
//		    ", fragment data length "<<f.data_length
//		    <<", position "<<m_uiPosition<<", packet timestamp "<<p.hdr.send_time/1000.
//		    <<endl;
	    	    abort_process=true;
		    m_uiPosition--;
		    break;
	        }
		int to_read = f.data_length - m_uiSubpointer;
		if (to_read < 0)
                    to_read = 0;
		if (lpBuffer)
		{
		    if ((unsigned)to_read > (cbBuffer - read_bytes))
			to_read = cbBuffer - read_bytes;

		    memcpy((char*)lpBuffer + read_bytes,
			   &p[f.pointer + m_uiSubpointer], to_read);
		}
		read_bytes += to_read;
		m_uiSubpointer += to_read;

		if (m_uiSubpointer >= f.data_length)
		    m_uiSubpointer = 0;
		else
		    m_uiPosition--;

		if (read_bytes > buffer_required)
		    buffer_required = read_bytes;

		if (m_bIsAudio)
		    read_samples = read_bytes/m_Header.hdr.aud.wfex.nBlockAlign;
		else
		    read_samples++;

		m_uiLastTimestamp = f.object_start_time-m_pParent->m_Header.play_start_time;

		if (read_samples>=lSamples)
		{
		    abort_process=true;
		    break;
		}
	    }
	}//while
	if (abort_process)
	    break;
	m_uiPosition=0;
	m_iPointer=0;
	m_pIterator->next();

    }//while

    if (in_fragment)
    {
	// we ran out of space in output buffer
	// while reassembling fragmented object
	if (!m_bIsAudio)
	{
	    m_uiPosition = fragment_start_pos;
	    m_pIterator->undo();
	    read_bytes = fragment_read_bytes;
	}
	else
	{
	    m_pIterator->undo();
	    m_iPointer = object_read_size;
	    //cout << "SETAUDIOPOINTER " << m_iPointer << endl;
	}
    }
    else if (m_bIsAudio)
        m_iPointer = 0;

    //if (m_bIsAudio)
    //    read_samples=read_bytes/m_Header.hdr.aud.wfex.nBlockAlign;

    if (plBytes)
	*plBytes = read_bytes;
    if (plSamples)
	*plSamples = read_samples;
    if (!lpBuffer)
    {
	// if we are only queried for buffer size,
	// we shouldn't change our global pointer
	m_uiPosition = _position2;
	if (plBytes)
	    *plBytes = buffer_required;
	m_pIterator->undo();
    }
    //Debug cout<<"Read(): read "<<read_bytes<<" bytes ( "<<read_samples<<" samples )   result: " << result << endl;
    //cout<<"Read(): read "<<read_bytes<<" bytes ( "<<read_samples<<" samples )   result: " << result << "      " << m_uiLastTimestamp << endl;
    //if (m_bIsAudio)
    //    cout<<"Read(): read "<<read_bytes<<" bytes ( "<<read_samples<<" samples )"<<endl;
    return result;
}

HRESULT ASFReadStream::SeekToPrevKeyFrame()
{
    return (m_pSeekInfo) ? Seek(GetPrevKeyFrame()) : -1;
}

HRESULT ASFReadStream::Seek(framepos_t pos)
{
    chunk_info ch;
    if (m_pIterator->seek((int64_t)pos, &ch))
	return -1;
    m_uiPosition = ch.fragment_id;
    m_iPointer = m_uiSubpointer = 0;
    m_uiLastTimestamp = ch.object_start_time;

    // reset descrambling
    m_iScrOffset = 0;
    m_bValidBuf = false;

    return 0;
}


HRESULT ASFReadStream::SeekTime(double timepos)
{
    Debug cout << "ASFReadStream::SeekTime() " << timepos << endl;
    chunk_info ch;
    if (m_pIterator->seek(timepos, &ch))
	return -1;
    m_uiPosition = ch.fragment_id;
    m_iPointer = m_uiSubpointer = 0;
    m_uiLastTimestamp = ch.object_start_time;

    // reset descrambling
    m_iScrOffset = 0;
    m_bValidBuf = false;

    return 0;
}

double ASFReadStream::GetSampleTime(framepos_t lSample) const
{
    if (lSample == ERR)
	return m_uiLastTimestamp / 1000.0;

    if (m_pSeekInfo && lSample < m_pSeekInfo->size())
    {
	cout << "SCROFFSET " << m_iScrOffset << "    " << lSample << endl;
	return (*m_pSeekInfo)[lSample].object_start_time / 1000.0;
    }

    return 0.;
}

HRESULT ASFReadStream::GetFormatSize(size_t *plSize) const
{
    size_t size =
	(m_bIsAudio) ? m_Header.hdr.data_len : m_Header.hdr.data_len-11;

    if (plSize)
	*plSize = size;
    return 0;
}

HRESULT ASFReadStream::GetFormat(void *pFormat, size_t* plSize) const
{
    size_t size;
    const void* fmt;
    if (m_bIsAudio)
    {
	size = m_Header.hdr.data_len;
	fmt = &m_Header.hdr.aud.wfex;
    }
    else
    {
	size = m_Header.hdr.data_len - 11;
	fmt = &m_Header.hdr.vid.biSize2;
    }

    if (pFormat)
	memcpy(pFormat, fmt, size);
    if (plSize)
	*plSize = size;
    return 0;
}

fourcc_t ASFReadStream::GetFourCC() const
{
    if (m_Header.hdr.uid_type == guid_audio_stream)
	return streamtypeAUDIO;
    else if (m_Header.hdr.uid_type == guid_video_stream)
	return streamtypeVIDEO;

    return 0;
}

unsigned int ASFReadStream::GetSampleSize() const
{
    if (m_bIsAudio)
	return m_Header.hdr.aud.wfex.nBlockAlign;
    return 0;
}

void ASFReadStream::ClearCache()
{
//    return m_pParent->m_pInput->clear();
}

HRESULT ASFReadStream::SkipFrame()
{
    Debug cout << "Skip frame " << endl;

    m_pIterator->next();

    return 0;
}

HRESULT ASFReadStream::SkipTo(double pos)
{
    if (pos < (m_uiLastTimestamp / 1000.0))
	return -1;

    for (;;)
    {
	bool success;
	packet p=m_pIterator->getPacket(success);

	if (!success)
	    return -1;
	if ((p.hdr.send_time-m_pParent->m_Header.play_start_time)/1000.0 > pos)
	    return 0;
	m_pIterator->next();
    }
}
