/******************************************************** Classes for reading AVIs Copyright 2000 Eugene Kuznetsov (divx@euro.ru) *********************************************************/ #include "AviRead.h" #include using namespace std; #define __MODULE__ "AviRead" #ifndef TIMING #define Debug if(0) #else #define Debug #endif IAviReadStream::~IAviReadStream() { } IAviReadFile::~IAviReadFile() { } /******************************************************************** AviReadStream functions that are common for video and audio streams *********************************************************************/ AviReadStream::~AviReadStream() { delete rem_buffer; } HRESULT AviReadStream::Eof() const { // cerr<Length()<=m_pIStream->Length(); //#ifdef __FreeBSD__ // if (m_header.fccType == streamtypeAUDIO) // return (GetPos() >= m_header.dwLength); //#endif // return (GetPos() >= m_table_size); } HRESULT AviReadStream::Init(Unsigned id, IvAVIReadStream* stream) { if(stream==0) return -1; m_pIStream=stream; m_id=id; m_pIStream->Header(&m_header); m_pIStream->FormatSize(0, &m_format_size); m_format=new char[m_format_size]; m_pIStream->ReadFormat(0, m_format, &m_format_size); m_table_size=stream->Length(); cout<<"Successfully initialized stream "<=GetEndPos())return -1; m_pIStream->ClearCache(); return 0; } double AviReadStreamV::SeekToTime(double time) { // cout<<"AviReadStreamV::SeekToTime"<=m_table_size) { Seek(pos); return time; } pos=m_pIStream->NearestKeyFrame(pos); Seek(pos); double qq=pos*(double)m_header.dwScale/m_header.dwRate; return qq; } Unsigned AviReadStreamV::SeekToKeyframe(Unsigned pos) { if(pos>=m_table_size) return (Unsigned)0; pos=m_pIStream->NearestKeyFrame(pos); Seek(pos); return pos; } Unsigned AviReadStream::GetNextKeyFrame(int frame) const { if(m_pIStream==0)return 0; return m_pIStream->NextKeyFrame((frame<0)?(int)m_sample:frame); } Unsigned AviReadStream::GetPrevKeyFrame(int frame) const { if(m_pIStream==0)return 0; if(frame==0)return 0; if(frame<0 && m_sample<2)return 0; return m_pIStream->PrevKeyFrame((frame<0)?int(m_sample-(Unsigned)2):frame); } int AviReadStream::ToNextKeyFrame() { if(m_pIStream==0)return -1; Unsigned newpos=m_pIStream->NextKeyFrame(m_sample); if(newpos==-1)return -1; m_sample=newpos; return 0; } int AviReadStream::ToPrevKeyFrame() { if(m_pIStream==0)return -1; Unsigned newpos=m_pIStream->PrevKeyFrame(m_sample-(Unsigned)2); if(newpos==-1)return -1; m_sample=newpos; return 0; } HRESULT AviReadStream::ReadDirect(char* buffer, Unsigned bufsize, Unsigned samples, Unsigned& samples_read, Unsigned& bytes_read) { if(m_pIStream==0)return -1; HRESULT hr=m_pIStream->Read(m_sample, samples, buffer, bufsize, (long*)&bytes_read, (long*)&samples_read); m_sample+=samples_read; return hr; } HRESULT AviReadStream::GetFrameFlags(int* flags) const { if(flags==0)return -1; if(!m_pIStream)return 0; #warning FIXME *flags=(m_pIStream->IsKeyFrame(m_sample)?AVIIF_KEYFRAME:0); return 0; } double AviReadStream::GetTime() const { return GetPos()*(double)m_header.dwScale/m_header.dwRate; } Unsigned AviReadStream::GetPos() const { return m_sample; } double AviReadStream::GetEndTime() const { return m_header.dwLength*(double)m_header.dwScale/m_header.dwRate; } bool AviReadStream::IsStreaming() const { return m_streaming; } /****************************************************************** These functions are meaningless for 'unknown type' stream ******************************************************************/ HRESULT AviReadStream::GetVideoFormatInfo(void* bi) const { cerr<<"WARNING: GetVideoFormatInfo() for non-video stream"<Start(); m_streaming=1; } catch(FatalError& error) { error.Print(); delete videodecoder; videodecoder=0; return -1; } return 0; } HRESULT AviReadStreamV::StopStreaming() { int result; if(m_streaming==0) return 0; if(videodecoder) { delete videodecoder; videodecoder=0; } m_streaming=0; } /* HRESULT AviReadStreamV::SetBitDepth(Unsigned depth) { if(videodecoder==0)return -1; videodecoder->Stop(); HRESULT hr=videodecoder->SetBitDepth(depth); videodecoder->Start(); return hr; } */ HRESULT AviReadStreamV::GetOutputFormat(void* format, Unsigned size) { if(sizeDestFmt(); return 0; } HRESULT AviReadStreamV::SetOutputFormat() { if(videodecoder==0)return -1; #warning FIXME return -1; //not implemented } HRESULT AviReadStreamV::ReadFrame() { if(m_pIStream==0)return -1; if(!m_streaming)return -1; long lBytes, lSamples; long size; // cout<<"Current pos: "<Read(m_sample, 1, 0, 0, &size, 0); if(hr!=0) { // cout<<"WARNING: Read() failed"<DecodeFrame(temp_buffer, lBytes, m_pIStream->IsKeyFrame(m_sample)?AVIIF_KEYFRAME:0); else hr=-1; delete temp_buffer; m_sample++; return hr; } CImage* AviReadStreamV::GetFrame() { if(videodecoder==0)return 0; return videodecoder->GetFrame(); } int AviReadStreamV::GetFrameSize() { if(videodecoder==0)return 0; return videodecoder->DestFmt().biSizeImage; } /* HRESULT AviReadStreamV::ReadFrames(char* buffer, Unsigned bufsize, Unsigned samples, Unsigned& samples_read, Unsigned& bytes_read) { long _samp=samples; long lBytes, lSamples; long size; long bufsize_avail=bufsize; char* temp_buffer=0; HRESULT hr=0; if(m_pIStream==0)return -1; if(samples==0)return -1; samples_read=0; bytes_read=0; while(_samp>0) { if(hr!=0)return -1; hr=m_pIStream->Read(m_sample, 1, 0, 0, &size, 0); if(size<0)return -1; temp_buffer=new char[size]; if(temp_buffer==NULL)return -1; hr=m_pIStream->Read(m_sample, 1, temp_buffer, size, &lBytes, &lSamples); _samp-=lSamples; Unsigned in_size=0; Unsigned ocnt=0; Unsigned local_read; if(GetFrameSize()>bufsize) { hr=-2; goto fail; } hr=videodecoder->DecodeFrame(temp_buffer, lBytes, m_pIStream->IsKeyFrame(m_sample)?AVIIF_KEYFRAME:0); if(hr!=0) { if(temp_buffer)delete temp_buffer; return hr; } memcpy(buffer, videodecoder->GetFrame(), GetFrameSize()); buffer+=GetFrameSize(); bufsize-=GetFrameSize(); bytes_read+=GetFrameSize(); m_sample+=lSamples; samples_read+=lSamples; } fail: if(temp_buffer)delete temp_buffer; return hr; } */ /************************************************************* AviReadStreamA ( audio AVI stream ) Functions **************************************************************/ double AviReadStreamA::SeekToTime(double time) { cout<<"AviReadStreamA::SeekToTime"<cbSize>0) { if(m_format_sizecbSize)) { ((LPWAVEFORMATEX)bi)->cbSize=wfmtx_size-m_format_size; // cout<<"WARNING: GetAudioFormatInfo: bad audio structure"<cbSize+18]; memcpy(*ext, m_format, ((LPWAVEFORMATEX)bi)->cbSize+18); return 0; } else *ext=0; return 0; } Unsigned AviReadStreamA::GetPos() const { Debug cout<<"Sample "<m_sample) return 0; else return m_sample-int(rem_size/m_header.dwSampleSize); } int AviReadStreamA::GetFrameSize() { return audiodecoder->GetMinSize(); } HRESULT AviReadStreamA::StartStreaming() { int result; if(m_streaming)return 0; try { audiodecoder=IAudioDecoder::Create((WAVEFORMATEX*)m_format, (m_format_size>wfmtx_size)?m_format+wfmtx_size:0); } catch(FatalError& e) { e.Print(); cout<<"Failed to initialize audio decoder for format "<<((WAVEFORMATEX*)m_format)->wFormatTag<Close(); delete audiodecoder; audiodecoder=0; } if(m_header.dwSampleSize) if(rem_size/m_header.dwSampleSizeGetOutputFormat((WAVEFORMATEX*)format); } HRESULT AviReadStreamA::ReadFrames(void* buffer, Unsigned bufsize, Unsigned samples, Unsigned& samples_read, Unsigned& bytes_read) { long lBytes, lSamples; long size; Unsigned in_size=0; Unsigned ocnt=0; Unsigned local_read; char* temp_buffer=0; HRESULT hr=0; if(m_pIStream==0)return -1; if(samples==0)return -1; if(!m_streaming)return -1; samples_read=0; bytes_read=0; int rem_diff=0; temp_buffer=new char[bufsize]; if(rem_buffer) { rem_diff=min((long)rem_size, (long)bufsize); memcpy(temp_buffer, rem_buffer, rem_diff); if(rem_diffRead(m_sample, samples, temp_buffer+rem_diff, bufsize-rem_diff, &lBytes, &lSamples); Debug printf("AviReadStreamA: Read %d samples ( %d bytes ) from pos %d\n", (int)lSamples, (int)lBytes, (int)m_sample); // if(lSamples==0 && rem_diff==0 && (bufsize-rem_diff>=m_header.dwSampleSize)) // // We've run out of data // // { // m_sample=m_header.dwLength; // rem_diff=0; // } m_sample+=lSamples; samples_read+=lSamples; // printf("AviReadStreamA::ReadFrames: Read %d samples ( %d bytes ), %d from last call\n", lSamples, lBytes, rem_diff); // if(lBytes==0) // { // delete temp_buffer; // return -1; // } } lBytes+=rem_diff; hr=audiodecoder->Convert((unsigned char*)temp_buffer, lBytes, (unsigned char*)buffer, bufsize, &local_read, &ocnt); if(local_read>lBytes)local_read=lBytes; if((lBytes-local_read) && !rem_buffer) { rem_limit=max(2*audiodecoder->GetMinSize(), 50000); rem_buffer=new char[rem_limit]; } rem_size=min(lBytes-local_read, (unsigned long)rem_limit); Debug printf("AviReadStreamA::ReadFrames: converted %d bytes of %d to %d, bufsize %d\n", (int)local_read, (int)lBytes, (int)ocnt, (int)bufsize); if((local_read==0) && (ocnt==0))//shouldn't happen. Just skip some data, hoping that things will be OK later. { #ifndef QUIET // cerr<<"WARNING: audio decompressor rejected data, not good. Input buffer size "<Length() // <<", header length "<GetStream(mmioFOURCC('v', 'i', 'd', 's'), m_vcount++)); m_vcount--; while(stream=m_pIFile->GetStream(mmioFOURCC('a', 'u', 'd', 's'), m_acount++)); m_acount--; m_streams.clear(); // m_streams=new AviReadStream[m_vcount+m_acount]; for(i=0; iInit(i, m_pIFile->GetStream(mmioFOURCC('v', 'i', 'd', 's'), i)); m_streams.push_back(str); } for(i=0; iInit(m_vcount+i, m_pIFile->GetStream(mmioFOURCC('a', 'u', 'd', 's'), i)); m_streams.push_back(str); } m_pIFile->Header(&m_header); cout<<"Successfully opened "<