avi.c
资源名称:tcpmp.rar [点击查看]
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:40k
源码类别:
Windows CE
开发平台:
C/C++
- /*****************************************************************************
- *
- * This program is free software ; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * $Id: avi.c 607 2006-01-22 20:58:29Z picard $
- *
- * The Core Pocket Media Player
- * Copyright (c) 2004-2005 Gabor Kovacs
- *
- ****************************************************************************/
- #include "../common/common.h"
- #include "avi.h"
- #define INDEXSTEP 512
- #define AVI_INDEX_OF_INDEXES 0x00
- #define AVI_INDEX_OF_CHUNKS 0x01
- #define AVI_INDEX_KEY 0x80000000
- typedef struct aviindex
- {
- int32_t Id;
- int8_t Flags[4];
- int32_t Pos;
- int32_t Length;
- } aviindex;
- typedef struct avisuperindex
- {
- int Offset;
- int Size;
- int StartTime;
- int EndTime;
- int LastData;
- } avisuperindex;
- typedef struct avistdindex
- {
- uint32_t FourCC;
- int Size;
- int16_t LongsPerEntry;
- int8_t IndexSubType;
- int8_t IndexType;
- int Count;
- int ChunkId;
- int OffsetLow;
- int OffsetHigh;
- int Reserved;
- } avistdindex;
- typedef struct avistream
- {
- format_stream Stream;
- int* Index; // mediatime
- bool_t ByteRate;
- int RefStart;
- int MediaTime;
- int NewMediaTime; // after seek (if seek successed)
- fraction64 MediaRate; // byterate or packetrate
- int SampleSize;
- int MaxPacket;
- int Length;
- int SuperIndexCount;
- avisuperindex* SuperIndex; //opendml index
- int PrevKey;
- int PrevMediaTime;
- int PrevKeyBuffer;
- filepos_t OffsetMin;
- filepos_t OffsetMax;
- int* ZeroChunkPos;
- array ZeroChunk;
- int LastPos;
- } avistream;
- typedef struct avi
- {
- format_base Format;
- int FramePeriod;
- int ByteRate;
- bool_t ErrorIndex;
- bool_t UnLimited;
- bool_t CheckForZero;
- bool_t FoundStdIndex;
- int DataPos;
- int DataEnd;
- // stream header and format loading
- int HeadType;
- avistream* LastStream;
- int VideoHandler;
- int VideoFrames;
- fraction VideoFPS;
- int VideoStart;
- fraction AudioRate;
- int AudioLength;
- int AudioStart;
- int AudioSampleSize;
- int IndexAdjustPos;
- int IndexCount;
- int IndexPos;
- int IndexReaded;
- int IndexBufferNo;
- block IndexBuffer;
- char NameChar[256];
- int FoundTotal;
- int FoundAtEnd[8];
- int FoundLastPos[8];
- } avi;
- #define ALIGN2(x) (((x)+1)&~1)
- #define ISDIGIT(x) ((x)>='0' && (x)<='9')
- #define STREAMNO(x) ((((x) & 255)-'0')*10 + ((((x) >> 8) & 255)-'0'))
- #define ISDATA(x) (ISDIGIT((x) & 255) && ISDIGIT(((x) >> 8) & 255))
- #define ISIDX(x) (ISDIGIT(((x) >> 16) & 255) && ISDIGIT(((x) >> 24) & 255) && ((x) & 255)=='i' && (((x) >> 8) & 255)=='x')
- #define IDXNO(x) (((((x) >> 16) & 255)-'0')*10 + ((((x) >> 24) & 255)-'0'))
- static void Done(avi* p)
- {
- FreeBlock(&p->IndexBuffer);
- }
- #define CHECKINDEX 16384
- static NOINLINE int Load32LE(const uint8_t* i) { return LOAD32LE(i); }
- static void PreCheckIndexODML(avi* p,avistream* Stream)
- {
- int k;
- array Array = {NULL};
- avistdindex StdIndex;
- stream* Input = p->Format.Reader->Input;
- filepos_t Save = Input->Seek(Input,0,SEEK_CUR);
- if (Save>=0 && Input->Seek(Input,Stream->SuperIndex[0].Offset,SEEK_SET)>=0)
- {
- if (Input->Read(Input,&StdIndex,sizeof(StdIndex)) == sizeof(StdIndex) &&
- StdIndex.IndexType == AVI_INDEX_OF_CHUNKS &&
- StdIndex.LongsPerEntry == 2)
- {
- if (StdIndex.Count > 1024)
- StdIndex.Count = 1024;
- if (ArrayAppend(&Array,NULL,8*StdIndex.Count,1024))
- {
- if (Input->Read(Input,ARRAYBEGIN(Array,int32_t),8*StdIndex.Count) == 8*StdIndex.Count)
- {
- for (k=0;k<StdIndex.Count;++k)
- if ((ARRAYBEGIN(Array,int32_t)[k*2+1] & ~AVI_INDEX_KEY)==0)
- {
- p->CheckForZero = 1;
- break;
- }
- }
- ArrayClear(&Array);
- }
- }
- Input->Seek(Input,Save,SEEK_SET);
- }
- }
- static void PreCheckIndex(avi* p)
- {
- block Buffer;
- if (AllocBlock(CHECKINDEX,&Buffer,0,HEAP_ANY))
- {
- format_reader* Reader = p->Format.Reader;
- filepos_t Save = Reader->Input->Seek(Reader->Input,0,SEEK_CUR);
- if (Save>=0 && Reader->Input->Seek(Reader->Input,-CHECKINDEX,SEEK_END)>=0)
- {
- if (Reader->Input->ReadBlock(Reader->Input,&Buffer,0,CHECKINDEX)==CHECKINDEX)
- {
- int Type = 0;
- int LastNo;
- int No = 24;
- const uint8_t* i = Buffer.Ptr+CHECKINDEX-12;
- while (--i>=Buffer.Ptr+16)
- {
- if (p->NameChar[*i])
- {
- Type |= *i << No;
- No -= 8;
- if (No<0)
- {
- if (Type == FOURCCLE('J','U','N','K') && ISDATA(Load32LE(i-16)))
- {
- i -= 16;
- p->FoundStdIndex = 1;
- break;
- }
- if (ISDATA(Type) && (Load32LE(i+4) & ~0x10)==0)
- {
- p->FoundStdIndex = 1;
- break;
- }
- Type <<= 8;
- No += 8;
- }
- }
- else
- {
- Type = 0;
- No = 24;
- }
- }
- LastNo = -1;
- for (;i>=Buffer.Ptr+16;i-=16)
- {
- if (Load32LE(i-8) == FOURCCLE('i','d','x','1'))
- break;
- Type = Load32LE(i);
- if (ISDATA(Type))
- {
- int Pos = Load32LE(i+8);
- int No = STREAMNO(Type);
- if (No >= 0 && No < 8)
- {
- if (No != LastNo)
- {
- if (LastNo>=0)
- ++p->FoundAtEnd[LastNo];
- LastNo = No;
- }
- if (p->FoundLastPos[No] == Pos)
- p->CheckForZero = 1;
- p->FoundLastPos[No] = Pos;
- ++p->FoundTotal;
- }
- if (Load32LE(i+12)==0 && Pos==Load32LE(i-16+8))
- {
- p->CheckForZero = 1;
- break;
- }
- }
- }
- if (LastNo>=0)
- ++p->FoundAtEnd[LastNo];
- }
- Reader->Input->Seek(Reader->Input,Save,SEEK_SET);
- }
- FreeBlock(&Buffer);
- }
- }
- static int Init(avi* p)
- {
- int DataLength;
- int Type;
- format_reader* Reader = p->Format.Reader;
- if (!AllocBlock(sizeof(aviindex)*INDEXSTEP,&p->IndexBuffer,0,HEAP_ANY))
- return ERR_OUT_OF_MEMORY;
- memset(p->FoundAtEnd,0,sizeof(p->FoundAtEnd));
- memset(p->FoundLastPos,0,sizeof(p->FoundLastPos));
- p->LastStream = NULL;
- p->FoundTotal = 0;
- p->FoundStdIndex = 0;
- p->CheckForZero = 0;
- p->UnLimited = 1;
- p->IndexAdjustPos = 4;
- p->IndexPos = -1;
- p->IndexCount = 0;
- p->IndexReaded = 0;
- p->IndexBufferNo = -1;
- p->DataPos = -1;
- p->DataEnd = -1;
- p->ErrorIndex = 0;
- p->AudioLength = 0;
- memset(p->NameChar,0,sizeof(p->NameChar));
- memset(p->NameChar+'a',1,'z'-'a');
- memset(p->NameChar+'A',1,'Z'-'A');
- memset(p->NameChar+'0',1,'9'-'0');
- p->NameChar['_']=1;
- p->NameChar[' ']=1;
- Type = Reader->ReadLE32(Reader);
- DataLength = Reader->ReadLE32(Reader);
- if (Type != FOURCCLE('R','I','F','F'))
- return ERR_INVALID_DATA;
- if (DataLength > 256 && (p->Format.FileSize < 0 || p->Format.FileSize > DataLength + 8))
- p->Format.FileSize = DataLength + 8;
- Reader->ReadLE32(Reader); // 'AVI ' or 'AVIX'
- PreCheckIndex(p);
- return ERR_NONE;
- }
- static INLINE int ChunkTime(avistream* Stream, int DataLength)
- {
- if (Stream->ByteRate)
- return DataLength; //byterate
- // packetrate
- if (DataLength > Stream->MaxPacket)
- return (DataLength + Stream->MaxPacket - 1) / Stream->MaxPacket;
- return 1;
- }
- static void UpdateAviFrameRate(avi* p)
- {
- if (QueryAdvanced(ADVANCED_AVIFRAMERATE) && p->AudioLength && p->VideoFrames)
- {
- int i;
- for (i=0;i<p->Format.StreamCount;++i)
- {
- avistream* Stream = (avistream*) p->Format.Streams[i];
- if (Stream->Stream.Format.Type == PACKET_VIDEO && Stream->Length)
- {
- Stream->MediaRate.Num = Scale64(p->AudioLength,(int64_t)p->AudioRate.Den*TICKSPERSEC,p->AudioRate.Num);
- Stream->MediaRate.Den = p->VideoFrames;
- }
- }
- }
- }
- static bool_t SubtitleTiming(format_packet* Packet,format_reader* Reader,int Length)
- {
- int Hour0,Hour1,Min0,Min1,Sec0,Sec1,MSec0,MSec1;
- int i;
- tchar_t s[64];
- for (i=0;i<63 && Length>0;++i)
- {
- int ch = Reader->Read8(Reader);
- --Length;
- if (ch<0 || ch==']') break;
- s[i] = (tchar_t)ch;
- }
- s[i] = 0;
- if (stscanf(s,T("[%d:%d:%d.%d-%d:%d:%d.%d"),&Hour0,&Min0,&Sec0,&MSec0,&Hour1,&Min1,&Sec1,&MSec1)!=8)
- {
- Reader->Skip(Reader,Length);
- return 0;
- }
- Packet->RefTime = Scale(((Hour0*60+Min0)*60+Sec0)*1000+MSec0,TICKSPERSEC,1000);
- Packet->EndRefTime = Scale(((Hour1*60+Min1)*60+Sec1)*1000+MSec1,TICKSPERSEC,1000);
- Packet->Data = Reader->ReadAsRef(Reader,Length);
- return 1;
- }
- static void SetMediaTime(avistream* p,int Time)
- {
- p->MediaTime = Time;
- p->ZeroChunkPos = ARRAYBEGIN(p->ZeroChunk,int);
- if (p->ZeroChunkPos)
- while (*p->ZeroChunkPos < Time)
- ++p->ZeroChunkPos;
- }
- static void ReadMeta(avi* p, format_reader* Reader, int* DataLength)
- {
- pin* Comment = &p->LastStream->Stream.Comment;
- tchar_t Meta[512];
- char UTF8[512];
- int Len = *DataLength;
- if (Len>=512) Len=511;
- Len = Reader->Read(Reader,UTF8,Len);
- if (Len>0)
- {
- *DataLength -= Len;
- UTF8[Len] = 0;
- tcscpy_s(Meta,TSIZEOF(Meta),T("LANGUAGE="));
- UTF8ToTcs(Meta+tcslen(Meta),TSIZEOF(Meta)-tcslen(Meta),UTF8);
- if (Comment->Node)
- Comment->Node->Set(Comment->Node,Comment->No,Meta,sizeof(Meta));
- }
- }
- static void CheckIndex(avi* p, format_reader* Reader);
- static int ReadPacket(avi* p, format_reader* Reader, format_packet* Packet)
- {
- avistream* Stream;
- int No,Ch,StartPos;
- int SubType,Type,DataLength;
- tick_t Duration;
- int LongsPerEntry;
- int IndexType;
- int Count;
- int BaseOffset;
- // find a valid chunk header first
- //DEBUG_MSG1(DEBUG_FORMAT,T("AVI Packet %08x"),Reader->FilePos);
- StartPos = Reader->FilePos;
- if (!p->UnLimited && p->DataEnd >= 0 && Reader->FilePos >= p->DataEnd)
- return ERR_END_OF_FILE;
- do
- {
- bool_t PossibleAlign = Reader->FilePos & 1;
- Type = 0;
- No = 0;
- while (No<32)
- {
- Ch = Reader->Read8(Reader);
- if (Ch>=0 && p->NameChar[Ch])
- {
- Type |= Ch << No;
- No += 8;
- if (No==32 && PossibleAlign)
- {
- int Stream = STREAMNO(Type);
- if (!ISDATA(Type) || ISDIGIT((Type>>16) & 255) || ISDIGIT((Type>>24) & 255) ||
- Stream <0 || Stream>=p->Format.StreamCount)
- {
- No -= 8;
- Type >>= 8;
- }
- }
- }
- else
- {
- if (!PossibleAlign)
- {
- Reader->OutOfSync = 1;
- if ((Reader->FilePos-StartPos)>=16384)
- return ERR_DATA_NOT_FOUND; // this will force the process loop to stop, so input thread can be woken up
- if (Reader->Eof(Reader))
- return ERR_END_OF_FILE;
- }
- No = 0;
- Type = 0;
- PossibleAlign = 0;
- }
- }
- if (!p->UnLimited && p->DataEnd >= 0 && Reader->FilePos >= p->DataEnd)
- return ERR_END_OF_FILE;
- DataLength = Reader->ReadLE32(Reader);
- if (DataLength<0 || (Reader->FilePos+DataLength<0) || (p->DataPos>=0 && p->Format.FileSize>=0 && Reader->FilePos+DataLength>p->Format.FileSize))
- {
- DataLength = -1;
- Reader->OutOfSync = 1;
- continue;
- }
- if (ISDATA(Type))
- {
- No = STREAMNO(Type);
- if (No >= 0 && No < p->Format.StreamCount)
- {
- //DEBUG_MSG3(-1,"AVI Packet stream:%d pos:%08x length:%d",No,Reader->FilePos,DataLength);
- Stream = (avistream*) p->Format.Streams[No];
- if (Stream->Stream.Reader != Reader)
- break;
- if (Reader->OutOfSync)
- {
- if (p->Format.ProcessTime >= 0)
- {
- int i;
- tick_t RefTime;
- // this won't solve the out of sync problem
- // but at least the streams won't be dropped
- for (i=0;i<p->Format.StreamCount;++i)
- {
- avistream* s = (avistream*) p->Format.Streams[i];
- if (s->Stream.Reader == Reader)
- {
- RefTime = s->RefStart+Scale64(s->MediaTime,s->MediaRate.Num,s->MediaRate.Den);
- if (RefTime < p->Format.ProcessTime - TICKSPERSEC)
- SetMediaTime(s,Scale64(p->Format.ProcessTime-s->RefStart,s->MediaRate.Den,s->MediaRate.Num));
- }
- }
- }
- Reader->OutOfSync = 0;
- }
- Packet->Stream = &Stream->Stream;
- if (Stream->ZeroChunkPos)
- while (*Stream->ZeroChunkPos == Stream->MediaTime)
- {
- Stream->MediaTime += ChunkTime(Stream,0);
- ++Stream->ZeroChunkPos;
- }
- if (Stream->Stream.Format.Type == PACKET_SUBTITLE)
- {
- if (!SubtitleTiming(Packet,Reader,DataLength))
- continue;
- }
- else
- {
- Packet->Data = Reader->ReadAsRef(Reader,DataLength);
- Packet->RefTime = Stream->RefStart+Scale64(Stream->MediaTime,Stream->MediaRate.Num,Stream->MediaRate.Den);
- }
- DEBUG_MSG5(DEBUG_FORMAT,T("AVI stream:%d time:%d mediatime:%d pos:%08x length:%08x"),No,Packet->RefTime,Stream->MediaTime,Reader->FilePos,DataLength);
- Stream->MediaTime += ChunkTime(Stream,DataLength);
- return ERR_NONE;
- }
- }
- if (ISIDX(Type))
- {
- No = IDXNO(Type);
- if (No >= 0 && No < p->Format.StreamCount)
- break; // opendml index
- }
- switch (Type)
- {
- case FOURCCLE('R','I','F','F'):
- Reader->ReadLE32(Reader); // 'AVI ' or 'AVIX'
- return ERR_NONE;
- case FOURCCLE('a','v','i','h'):
- if (p->Format.HeaderLoaded) break;
- p->FramePeriod = Reader->ReadLE32(Reader);
- p->ByteRate = Reader->ReadLE32(Reader);
- DataLength -= 8;
- break;
- case FOURCCLE('i','n','d','x'):
- if (p->Format.HeaderLoaded) break;
- // opendml index
- LongsPerEntry = Reader->ReadLE16(Reader);
- Reader->Read8(Reader); //subtype
- IndexType = Reader->Read8(Reader);
- Count = Reader->ReadLE32(Reader);
- Type = Reader->ReadLE32(Reader);
- BaseOffset = (int)Reader->ReadLE64(Reader);
- Reader->Skip(Reader,4);
- DataLength -= 6*4;
- if (ISDATA(Type))
- {
- No = STREAMNO(Type);
- if (No >= 0 && No < p->Format.StreamCount && Count)
- {
- avisuperindex* s;
- Stream = (avistream*) p->Format.Streams[No];
- if (IndexType == AVI_INDEX_OF_CHUNKS && LongsPerEntry==2)
- {
- p->UnLimited = 1;
- p->Format.FileSize = -1;
- // create fake index of indexes
- Stream->SuperIndexCount = 1;
- Stream->SuperIndex = s = (avisuperindex*) malloc(sizeof(avisuperindex));
- s->Offset = Reader->FilePos - 6*4 - 8;
- s->Size = DataLength + 6*4 + 8;
- s->StartTime = 0;
- s->EndTime = 0;
- s->LastData = 0;
- for (No=0;No<Count;++No)
- {
- int Data = BaseOffset + Reader->ReadLE32(Reader) - 8;
- int Size = Reader->ReadLE32(Reader) & ~AVI_INDEX_KEY;
- if (s->LastData < Data)
- s->LastData = Data;
- s->EndTime += ChunkTime(Stream,Size);
- }
- }
- if (IndexType == AVI_INDEX_OF_INDEXES && LongsPerEntry==4)
- {
- int Time;
- p->UnLimited = 1;
- p->Format.FileSize = -1;
- // load index of indexes
- Stream->SuperIndexCount = Count;
- Stream->SuperIndex = s = (avisuperindex*) malloc(sizeof(avisuperindex)*Count);
- Time = 0;
- for (No=0;No<Count;++No,++s)
- {
- s->Offset = (int)Reader->ReadLE64(Reader);
- s->Size = Reader->ReadLE32(Reader);
- s->StartTime = Time;
- Time += Reader->ReadLE32(Reader) * Stream->SampleSize;
- s->EndTime = Time;
- s->LastData = -1;
- DataLength -= 16;
- }
- if (Count && !p->FoundStdIndex && !p->CheckForZero && Stream->Stream.Format.Type == PACKET_VIDEO)
- {
- LockEnter(p->Format.InputLock);
- PreCheckIndexODML(p,Stream);
- LockLeave(p->Format.InputLock);
- }
- }
- }
- }
- break;
- case FOURCCLE('s','t','r','h'):
- if (p->Format.HeaderLoaded) break;
- p->HeadType = Reader->ReadLE32(Reader);
- DataLength -= 4;
- if (p->HeadType == FOURCCLE('v','i','d','s'))
- {
- p->VideoHandler = Reader->ReadLE32(Reader);
- Reader->ReadLE32(Reader); // flags
- Reader->ReadLE16(Reader); // priority
- Reader->ReadLE16(Reader); // language
- Reader->ReadLE32(Reader);
- p->VideoFPS.Den = Reader->ReadLE32(Reader);
- p->VideoFPS.Num = Reader->ReadLE32(Reader);
- if (!p->VideoFPS.Den || !p->VideoFPS.Num)
- {
- p->VideoFPS.Den = 1;
- p->VideoFPS.Num = 25;
- }
- if (p->VideoFPS.Den==1 && p->VideoFPS.Num >= 12000) //not important
- p->VideoFPS.Den = 1000;
- p->VideoStart = Reader->ReadLE32(Reader);
- p->VideoFrames = Reader->ReadLE32(Reader);
- DataLength -= 32;
- }
- else
- if (p->HeadType == FOURCCLE('a','u','d','s'))
- {
- Reader->ReadLE32(Reader); // format
- Reader->ReadLE32(Reader); // flags
- Reader->ReadLE16(Reader); // priority
- Reader->ReadLE16(Reader); // language
- Reader->ReadLE32(Reader);
- p->AudioRate.Den = Reader->ReadLE32(Reader);
- p->AudioRate.Num = Reader->ReadLE32(Reader);
- p->AudioStart = Reader->ReadLE32(Reader);
- p->AudioLength = Reader->ReadLE32(Reader);
- Reader->ReadLE32(Reader); // initialframes
- Reader->ReadLE32(Reader); // suggested buffersize
- p->AudioSampleSize = Reader->ReadLE32(Reader);
- DataLength -= 44;
- }
- break;
- case FOURCCLE('s','t','r','n'):
- if (p->Format.HeaderLoaded) break;
- if (p->LastStream && DataLength)
- ReadMeta(p,Reader,&DataLength);
- break;
- case FOURCCLE('s','t','r','f'):
- if (p->Format.HeaderLoaded) break;
- if (p->HeadType == FOURCCLE('v','i','d','s'))
- {
- p->LastStream = Stream = (avistream*) Format_AddStream(&p->Format,sizeof(avistream));
- if (Stream)
- {
- Stream->Index = NULL;
- Stream->SuperIndex = NULL;
- Stream->ByteRate = 0;
- Stream->Stream.Fragmented = 0;
- Stream->SampleSize = 1;
- Stream->MaxPacket = MAX_INT;
- Format_BitmapInfo(Reader,&Stream->Stream,DataLength);
- if (Stream->Stream.Format.Format.Video.Pixel.FourCC == FOURCC('D','X','S','B'))
- {
- PacketFormatClear(&Stream->Stream.Format);
- Stream->Stream.Format.Type = PACKET_SUBTITLE;
- Stream->Stream.Format.Format.Subtitle.FourCC = FOURCC('D','X','S','B');
- }
- else
- {
- if (Stream->Stream.Format.Format.Video.Pixel.FourCC == 4)
- Stream->Stream.Format.Format.Video.Pixel.FourCC = UpperFourCC(p->VideoHandler);
- Stream->MediaRate.Den = p->VideoFPS.Num;
- Stream->MediaRate.Num = (int64_t)p->VideoFPS.Den * TICKSPERSEC;
- Stream->RefStart = Scale64(p->VideoStart,Stream->MediaRate.Num,Stream->MediaRate.Den);
- Stream->Length = p->VideoFrames;
- Stream->Stream.Format.PacketRate = p->VideoFPS;
- if (p->VideoFrames)
- {
- Duration = Scale64(p->VideoFrames,Stream->MediaRate.Num,Stream->MediaRate.Den);
- if (p->Format.Duration < Duration)
- p->Format.Duration = Duration;
- }
- UpdateAviFrameRate(p);
- }
- Format_PrepairStream(&p->Format,&Stream->Stream);
- }
- else
- Reader->Skip(Reader,DataLength);
- return ERR_NONE;
- }
- else
- if (p->HeadType == FOURCCLE('a','u','d','s'))
- {
- p->LastStream = Stream = (avistream*) Format_AddStream(&p->Format,sizeof(avistream));
- if (Stream)
- {
- Format_WaveFormat(Reader,&Stream->Stream,DataLength);
- // some encoders doesn't set AudioSampleSize, but still using CBR mode
- // detect it by insane packet rate
- if (!p->AudioSampleSize && p->AudioRate.Den*1000<=p->AudioRate.Num)
- p->AudioSampleSize = Stream->Stream.Format.Format.Audio.BlockAlign;
- Stream->Index = NULL;
- Stream->SuperIndex = NULL;
- Stream->ByteRate = p->AudioSampleSize != 0;
- Stream->Stream.Fragmented = Stream->ByteRate && p->AudioSampleSize <= 4;
- if (!Stream->ByteRate)
- {
- // VBR (packetrate)
- Stream->MediaRate.Den = p->AudioRate.Num;
- Stream->MediaRate.Num = (int64_t)p->AudioRate.Den * TICKSPERSEC;
- if (p->AudioRate.Num == Stream->Stream.Format.Format.Audio.SampleRate)
- Stream->MaxPacket = p->AudioRate.Den;
- else
- Stream->MaxPacket = MAX_INT;
- Stream->SampleSize = 1;
- }
- else
- {
- // CBR (byterate)
- // some digital cameras don't fill AudioSampleSize correctly only BlockAlign (with ADPCM)
- if (p->AudioSampleSize < Stream->Stream.Format.Format.Audio.BlockAlign)
- p->AudioSampleSize = Stream->Stream.Format.Format.Audio.BlockAlign;
- if (Stream->Stream.Format.Format.Audio.Format == 0x55 /*MP3*/ &&
- p->AudioRate.Num == 4977)
- {
- Stream->MediaRate.Den = (p->AudioRate.Num*16-7)*p->AudioSampleSize;
- Stream->MediaRate.Num = (int64_t)p->AudioRate.Den*TICKSPERSEC*16;
- }
- else
- {
- Stream->MediaRate.Den = p->AudioRate.Num*p->AudioSampleSize;
- Stream->MediaRate.Num = (int64_t)p->AudioRate.Den*TICKSPERSEC;
- }
- Stream->SampleSize = p->AudioSampleSize;
- }
- Stream->RefStart = Scale64(p->AudioStart,(int64_t)p->AudioRate.Den*TICKSPERSEC,p->AudioRate.Num);
- Stream->Length = p->AudioLength;
- if (p->AudioLength)
- {
- Duration = Scale64(p->AudioLength,(int64_t)p->AudioRate.Den*TICKSPERSEC,p->AudioRate.Num);
- if (Duration>0 && p->Format.Duration < Duration)
- p->Format.Duration = Duration;
- }
- UpdateAviFrameRate(p);
- Format_PrepairStream(&p->Format,&Stream->Stream);
- }
- else
- Reader->Skip(Reader,DataLength);
- return ERR_NONE;
- }
- else
- p->LastStream = NULL;
- break;
- case FOURCCLE('L','I','S','T'):
- SubType = Reader->ReadLE32(Reader);
- DataLength -= 4;
- switch (SubType)
- {
- case FOURCCLE('s','t','r','l'):
- return ERR_NONE;
- case FOURCCLE('h','d','r','l'):
- return ERR_NONE;
- case FOURCCLE('m','o','v','i'):
- if (p->Format.HeaderLoaded) return ERR_NONE;
- p->DataPos = Reader->FilePos;
- p->DataEnd = DataLength + Reader->FilePos;
- p->Format.HeaderLoaded = 1;
- if (p->FoundTotal >= 256 && p->Format.StreamCount>1)
- {
- for (No=0;No<p->Format.StreamCount && No<8;++No)
- if (p->FoundAtEnd[No] < 2)
- p->CheckForZero = 1; // possibly non interleaved streams
- }
- if (p->CheckForZero)
- {
- LockEnter(p->Format.InputLock);
- CheckIndex(p,Reader);
- LockLeave(p->Format.InputLock);
- }
- for (No=0;No<p->Format.StreamCount;++No)
- SetMediaTime((avistream*)p->Format.Streams[No],0);
- return ERR_NONE;
- case FOURCCLE('o','d','m','l'):
- break;
- default:
- return ERR_NONE;
- }
- break;
- case FOURCCLE('J','U','N','K'):
- case FOURCCLE('i','d','x','1'):
- break;
- default:
- if (Reader->OutOfSync || DataLength > 256*1024) // unknown
- DataLength = -1;
- }
- }
- while (DataLength<0);
- Reader->Skip(Reader,DataLength);
- return ERR_NONE;
- }
- static int ErrorIndex(avi* p,stream* Input,filepos_t OldFilePos)
- {
- if (OldFilePos>=0)
- {
- if (Input)
- Input->Seek(Input,OldFilePos,SEEK_SET);
- if (!p->ErrorIndex)
- {
- p->ErrorIndex = 1;
- ShowError(p->Format.Format.Class,AVI_ID,AVI_NO_INDEX);
- }
- }
- return ERR_NOT_SUPPORTED;
- }
- static INLINE const aviindex* IndexBuffer(avi* p,int n)
- {
- return ((const aviindex*)p->IndexBuffer.Ptr)+n;
- }
- static int LoadIndexBuffer(avi* p,stream* Input,int No,filepos_t OldFilePos)
- {
- if (p->IndexBufferNo != No)
- {
- int Bytes = (p->IndexCount - No*INDEXSTEP)*sizeof(aviindex);
- if (Bytes > INDEXSTEP*sizeof(aviindex))
- Bytes = INDEXSTEP*sizeof(aviindex);
- if (Input->Seek(Input,p->IndexPos+No*INDEXSTEP*sizeof(aviindex),SEEK_SET)<0)
- return ErrorIndex(p,Input,OldFilePos);
- if (Input->ReadBlock(Input,&p->IndexBuffer,0,Bytes) != Bytes)
- return ErrorIndex(p,Input,OldFilePos);
- p->IndexBufferNo = No;
- if (No == 0)
- {
- if (INT32LE(IndexBuffer(p,0)->Pos) == p->DataPos)
- p->IndexAdjustPos = p->DataPos;
- else
- p->IndexAdjustPos = 4;
- }
- }
- return ERR_NONE;
- }
- static int ReadIndex(stream* Input,avistream* Stream,avisuperindex* Index,int MediaTime,int DstPos,bool_t PrevKey)
- {
- bool_t NeedKey = Stream->Stream.Format.Type == PACKET_VIDEO;
- avistdindex StdIndex;
- int No;
- int FoundPos = -1;
- int32_t* i;
- int LookBack = 0;
- if (!NeedKey)
- PrevKey = 0;
- if (PrevKey)
- LookBack = 300;
- if (DstPos>=0 && Index->LastData>=0 && DstPos > Index->LastData)
- return -1;
- if (MediaTime>=0 && Index->EndTime + LookBack <= MediaTime)
- return -1;
- if (Input->Seek(Input,Index->Offset,SEEK_SET) < 0)
- return -2;
- if (Input->Read(Input,&StdIndex,sizeof(StdIndex)) != sizeof(StdIndex))
- return -1;
- if (StdIndex.IndexType != AVI_INDEX_OF_CHUNKS ||
- StdIndex.LongsPerEntry != 2)
- return -1;
- i = (int32_t*) malloc(8*StdIndex.Count);
- if (!i)
- return -1;
- if (Input->Read(Input,i,8*StdIndex.Count) != 8*StdIndex.Count)
- {
- free(i);
- return -1;
- }
- if (Index->LastData<0)
- {
- Index->LastData = 0;
- for (No=0;No<StdIndex.Count;++No)
- {
- int Data = StdIndex.OffsetLow + i[No*2] - 8;
- int Size = i[No*2+1] & ~AVI_INDEX_KEY;
- if (Size && Index->LastData < Data)
- Index->LastData = Data;
- }
- }
- Stream->NewMediaTime = Index->StartTime;
- for (No=0;No<StdIndex.Count;++No)
- {
- int Data = StdIndex.OffsetLow + i[No*2] - 8;
- int Size = i[No*2+1];
- if (MediaTime>=0)
- {
- if (Stream->NewMediaTime >= MediaTime && (!NeedKey || !(Size & AVI_INDEX_KEY)))
- {
- if (PrevKey && Stream->NewMediaTime != MediaTime && Stream->PrevKey>=0)
- {
- Stream->NewMediaTime = Stream->PrevMediaTime;
- FoundPos = Stream->PrevKey; // use previous key
- }
- else
- FoundPos = Data; // found sample after mediatime
- break;
- }
- if (PrevKey && !(Size & AVI_INDEX_KEY))
- {
- Stream->PrevMediaTime = Stream->NewMediaTime;
- Stream->PrevKey = Data;
- }
- }
- if (DstPos>=0 && Data >= DstPos)
- {
- FoundPos = Data; // found a sample after the destination position
- break;
- }
- Stream->NewMediaTime = Stream->NewMediaTime + ChunkTime(Stream,Size & ~AVI_INDEX_KEY);
- }
- free(i);
- return FoundPos;
- }
- static int RestorePrevKey(avi* p,avistream* Stream,int No,int OldFilePos,int* Pos)
- {
- int i,j;
- avistream* s;
- if (Stream->PrevKeyBuffer != No)
- {
- int Result = LoadIndexBuffer(p,Stream->Stream.Reader->Input,Stream->PrevKeyBuffer,OldFilePos);
- if (Result != ERR_NONE)
- return Result;
- No = Stream->PrevKeyBuffer;
- }
- // restart this block and recalc NewMediaTime
- for (j=0;j<p->Format.StreamCount;++j)
- {
- s = (avistream*) p->Format.Streams[j];
- s->NewMediaTime = s->Index[No];
- }
- for (i=0;i<Stream->PrevKey;++i)
- {
- j = STREAMNO(IndexBuffer(p,i)->Id);
- if (j>=0 && j<p->Format.StreamCount)
- {
- s = (avistream*) p->Format.Streams[j];
- s->NewMediaTime += ChunkTime(s,IndexBuffer(p,i)->Length);
- }
- }
- *Pos = INT32LE(IndexBuffer(p,i)->Pos) - p->IndexAdjustPos;
- return ERR_NONE;
- }
- static int FindIndexPos(avi* p,stream* Input)
- {
- int OldFilePos = Input->Seek(Input,0,SEEK_CUR);
- int Pos = p->DataEnd;
- // try to find index block
- if (Input->Seek(Input,Pos,SEEK_SET) < 0)
- return ERR_NOT_SUPPORTED;
- for (;;)
- {
- int32_t Head[2];
- if (Pos & 1)
- {
- if (Input->Read(Input,Head,sizeof(Head)) != sizeof(Head))
- return ErrorIndex(p,Input,OldFilePos);
- Pos += sizeof(Head);
- if (Head[0] != FOURCC('i','d','x','1'))
- {
- memmove((char*)Head,(char*)Head+1,sizeof(Head)-1);
- if (Input->Read(Input,(char*)Head+sizeof(Head)-1,1) != 1)
- return ErrorIndex(p,Input,OldFilePos);
- ++Pos;
- }
- }
- else
- {
- if (Input->Read(Input,Head,sizeof(Head)) != sizeof(Head))
- return ErrorIndex(p,Input,OldFilePos);
- Pos += sizeof(Head);
- }
- if (Head[0] == FOURCC('i','d','x','1'))
- {
- int i,No;
- p->IndexCount = Head[1] / sizeof(aviindex);
- i = ((p->IndexCount + INDEXSTEP - 1) / INDEXSTEP) + 1;
- for (No=0;No<p->Format.StreamCount;++No)
- {
- avistream* s = (avistream*) p->Format.Streams[No];
- s->Index = (int*) malloc(sizeof(int)*i);
- if (!s->Index)
- return ERR_OUT_OF_MEMORY;
- s->Index[0] = 0;
- }
- p->IndexPos = Pos;
- p->IndexReaded = 0;
- break;
- }
- if (Head[1]<0 || (Pos+Head[1]<0))
- return ErrorIndex(p,Input,OldFilePos);
- Pos += Head[1];
- if (Input->Seek(Input,Pos,SEEK_SET) != Pos)
- return ErrorIndex(p,Input,OldFilePos);
- }
- return ERR_NONE;
- }
- static NOINLINE int CheckIndexBuffer(avi* p,stream* Input,int No,filepos_t OldFilePos,int IndexCount)
- {
- // load page and calc sum mediatime
- if (p->IndexReaded <= No)
- {
- int i,j;
- int Result = LoadIndexBuffer(p,Input,No,OldFilePos);
- if (Result != ERR_NONE)
- return Result;
- for (j=0;j<p->Format.StreamCount;++j)
- {
- avistream* s = (avistream*) p->Format.Streams[j];
- s->Index[No+1] = s->Index[No];
- }
- for (i=0;i<IndexCount;++i)
- {
- j = STREAMNO(IndexBuffer(p,i)->Id);
- if (j>=0 && j<p->Format.StreamCount)
- {
- avistream* s = (avistream*) p->Format.Streams[j];
- s->Index[No+1] += ChunkTime(s,INT32LE(IndexBuffer(p,i)->Length));
- }
- }
- p->IndexReaded = No+1;
- }
- return ERR_NONE;
- }
- static int Seek(avi* p, tick_t Time, filepos_t FilePos, bool_t PrevKey)
- {
- int Result = ERR_NONE;
- int RNo;
- if (p->DataPos < 0)
- {
- // no avi header yet, only seek to the beginning supported
- if (Time>0 || FilePos>0)
- return ERR_NOT_SUPPORTED;
- p->Format.Reader[0].OutOfSync = 0;
- return Format_Seek(&p->Format,0,SEEK_SET);
- }
- for (RNo=0;RNo<MAXREADER;++RNo)
- {
- filepos_t Pos = -1;
- avistream* Stream;
- avistream* s;
- int i,j,No;
- format_reader* Reader = &p->Format.Reader[RNo];
- stream* Input = Reader->Input;
- filepos_t OldReaderPos = Reader->FilePos;
- filepos_t OldFilePos;
- if (!Input)
- break;
- OldFilePos = Input->Seek(Input,0,SEEK_CUR);
- if (Time <= 0 && FilePos <= 0)
- {
- // seek to the beginning (no index needed for that)
- Pos = Reader->OffsetMin<MAX_INT?Reader->OffsetMin:p->DataPos;
- for (j=0;j<p->Format.StreamCount;++j)
- if (p->Format.Streams[j]->Reader == Reader)
- ((avistream*)p->Format.Streams[j])->NewMediaTime = 0;
- }
- else
- {
- Stream = (avistream*) Format_DefSyncStream(&p->Format,Reader);
- if (Stream)
- {
- bool_t NeedKey = Stream->Stream.Format.Type == PACKET_VIDEO;
- int MediaTime = Scale64(Time,Stream->MediaRate.Den,Stream->MediaRate.Num);
- Stream->PrevKey = -1;
- if (PrevKey)
- ++MediaTime; // seek to same position even if there is rounding error
- if (Stream->SuperIndex)
- {
- // using OpenDML index
- if (MediaTime >= Stream->SuperIndex[Stream->SuperIndexCount-1].EndTime)
- MediaTime = Stream->SuperIndex[Stream->SuperIndexCount-1].EndTime-1;
- // find position by MediaTime
- for (No=0;No<Stream->SuperIndexCount;++No)
- {
- Pos = ReadIndex(Input,Stream,Stream->SuperIndex+No,MediaTime,-1,PrevKey);
- if (Pos == -2)
- return ERR_NOT_SUPPORTED;
- if (Pos >= 0)
- break;
- }
- if (Pos<0)
- {
- if (PrevKey && Stream->PrevKey>=0)
- {
- Stream->NewMediaTime = Stream->PrevMediaTime;
- Pos = Stream->PrevKey;
- }
- else
- {
- Stream->NewMediaTime = Stream->SuperIndex[Stream->SuperIndexCount-1].EndTime;
- Pos = Stream->SuperIndex[Stream->SuperIndexCount-1].LastData;
- if (Pos<0)
- return ErrorIndex(p,Input,OldFilePos);
- }
- }
- // calculate NewMediaTime for all other streams
- for (j=0;j<p->Format.StreamCount;++j)
- {
- s = (avistream*) p->Format.Streams[j];
- if (s->Stream.Reader==Reader && s != Stream)
- {
- // find position by Pos
- for (No=0;No<s->SuperIndexCount;++No)
- if (ReadIndex(Input,s,s->SuperIndex+No,-1,Pos,0) >= 0)
- break;
- if (No==s->SuperIndexCount)
- s->NewMediaTime = s->SuperIndex[s->SuperIndexCount-1].EndTime;
- }
- }
- }
- else
- {
- int Next;
- int IndexCount,IndexLeft;
- tick_t LookBack = 0;
- // do we have the index block?
- if (p->IndexPos < 0)
- {
- Result = FindIndexPos(p,Input);
- if (Result!=ERR_NONE)
- return Result;
- }
- IndexLeft = p->IndexCount;
- if (!NeedKey)
- PrevKey = 0;
- if (PrevKey)
- LookBack = 300;
- // find the index page
- for (No=0;IndexLeft>0;++No,IndexLeft-=INDEXSTEP)
- {
- IndexCount = IndexLeft;
- if (IndexCount > INDEXSTEP)
- IndexCount = INDEXSTEP;
- Result = CheckIndexBuffer(p,Input,No,OldFilePos,IndexCount);
- if (Result != ERR_NONE)
- return Result;
- //DEBUG_MSG4(DEBUG_FORMAT,"AVI IndexBlock no:%d start:%d end:%d (target:%d)",No,Stream->Index[No],Stream->Index[No+1],MediaTime);
- if (Stream->Index[No]!=Stream->Index[No+1] &&
- (Stream->Index[No+1]+LookBack > MediaTime || IndexLeft<2*INDEXSTEP))
- {
- Result = LoadIndexBuffer(p,Input,No,OldFilePos);
- if (Result != ERR_NONE)
- return Result;
- for (j=0;j<p->Format.StreamCount;++j)
- {
- s = (avistream*) p->Format.Streams[j];
- if (s->Stream.Reader == Reader)
- s->NewMediaTime = s->Index[No];
- }
- // find sub page position
- for (i=0;i<IndexCount;++i)
- {
- j = STREAMNO(IndexBuffer(p,i)->Id);
- if (j>=0 && j<p->Format.StreamCount && p->Format.Streams[j]->Reader==Reader)
- {
- s = (avistream*) p->Format.Streams[j];
- Next = s->NewMediaTime + ChunkTime(s,IndexBuffer(p,i)->Length);
- //DEBUG_MSG3(DEBUG_FORMAT,"AVI Index stream:%d pos:%d flag:%d",j,INT32LE(IndexBuffer(p,i)->Pos),IndexBuffer(p,i)->Flags[0]);
- if (s==Stream)
- {
- Pos = INT32LE(IndexBuffer(p,i)->Pos) - p->IndexAdjustPos;
- if (s->NewMediaTime >= MediaTime)
- {
- // only accept keyframes with valid position
- if (Pos >= 0 && Pos < p->DataEnd - p->DataPos &&
- (!NeedKey || (IndexBuffer(p,i)->Flags[0] & 0x10)))
- {
- if (PrevKey && s->NewMediaTime != MediaTime && Stream->PrevKey>=0)
- {
- Result = RestorePrevKey(p,Stream,No,OldFilePos,&Pos);
- if (Result != ERR_NONE)
- return Result;
- }
- break;
- }
- }
- if (Pos >= 0 && Pos < p->DataEnd - p->DataPos &&
- (IndexBuffer(p,i)->Flags[0] & 0x10))
- {
- Stream->PrevKey = i;
- Stream->PrevKeyBuffer = No;
- }
- }
- s->NewMediaTime = Next;
- }
- }
- // found?
- if (i<IndexCount)
- break;
- }
- }
- if (IndexLeft <= 0)
- {
- if (Stream->PrevKey>=0)
- {
- Result = RestorePrevKey(p,Stream,No,OldFilePos,&Pos);
- if (Result != ERR_NONE)
- return Result;
- }
- else
- {
- // go to end
- for (j=0;j<p->Format.StreamCount;++j)
- {
- s = (avistream*) p->Format.Streams[j];
- s->NewMediaTime = s->Index[p->IndexReaded];
- }
- Pos = p->DataEnd - p->DataPos;
- }
- }
- Pos += p->DataPos;
- }
- if (NeedKey && Stream->NewMediaTime >= 0) // use updated time with other Readers
- Time = Scale64(Stream->NewMediaTime,Stream->MediaRate.Num,Stream->MediaRate.Den);
- }
- }
- if (Pos>=0)
- {
- Reader->FilePos = -1; // force seek, because Input changed
- if (Reader->Seek(Reader,Pos,SEEK_SET) != ERR_NONE)
- {
- Reader->FilePos = OldReaderPos;
- // restore old input position
- Input->Seek(Input,OldFilePos,SEEK_SET);
- return ERR_NOT_SUPPORTED;
- }
- // set new positions
- for (j=0;j<p->Format.StreamCount;++j)
- if (p->Format.Streams[j]->Reader == Reader)
- {
- s = (avistream*) p->Format.Streams[j];
- SetMediaTime(s,s->NewMediaTime);
- }
- Reader->OutOfSync = 0;
- }
- }
- Format_AfterSeek(&p->Format);
- return ERR_NONE;
- }
- static NOINLINE void AddZeroChunk(avistream* Stream)
- {
- ArrayAppend(&Stream->ZeroChunk,&Stream->NewMediaTime,sizeof(Stream->NewMediaTime),512);
- }
- static void CheckIndex(avi* p, format_reader* Reader)
- {
- bool_t FlushBuffers = 0;
- avistream* Stream;
- int i,j,k;
- bool_t OpenDML = 0;
- array Array = {NULL};
- stream* Input = Reader->Input;
- filepos_t OldFilePos = Input->Seek(Input,0,SEEK_CUR);
- filepos_t OldReaderPos = Reader->FilePos;
- if (OldFilePos<0)
- return;
- for (i=0;i<p->Format.StreamCount;++i)
- {
- Stream = (avistream*)p->Format.Streams[i];
- Stream->NewMediaTime = 0;
- Stream->OffsetMin = MAX_INT;
- Stream->OffsetMax = 0;
- Stream->LastPos = 0;
- if (Stream->SuperIndex) // we need non video streams as well for offsetmin/max
- {
- OpenDML = 1;
- for (j=0;j<Stream->SuperIndexCount;++j)
- {
- avistdindex StdIndex;
- if (Input->Seek(Input,Stream->SuperIndex[j].Offset,SEEK_SET) < 0)
- break;
- if (Input->Read(Input,&StdIndex,sizeof(StdIndex)) != sizeof(StdIndex))
- break;
- if (StdIndex.IndexType != AVI_INDEX_OF_CHUNKS ||
- StdIndex.LongsPerEntry != 2)
- break;
- ArrayDrop(&Array);
- if (!ArrayAppend(&Array,NULL,8*StdIndex.Count,1024))
- break;
- if (Input->Read(Input,ARRAYBEGIN(Array,int32_t),8*StdIndex.Count) != 8*StdIndex.Count)
- break;
- for (k=0;k<StdIndex.Count;++k)
- {
- int Pos = StdIndex.OffsetLow + ARRAYBEGIN(Array,int32_t)[k*2] - 8;
- int Size = ARRAYBEGIN(Array,int32_t)[k*2+1] & ~AVI_INDEX_KEY;
- if (!Size)
- AddZeroChunk(Stream);
- else
- {
- if (Stream->OffsetMin>Pos)
- Stream->OffsetMin=Pos;
- if (Stream->OffsetMax<Pos)
- Stream->OffsetMax=Pos;
- }
- Stream->NewMediaTime = Stream->NewMediaTime + ChunkTime(Stream,Size);
- }
- }
- }
- }
- if (!OpenDML && (p->IndexPos>=0 || FindIndexPos(p,Input)==ERR_NONE))
- {
- int IndexLeft = p->IndexCount;
- int IndexCount;
- int LastPos = 0;
- for (i=0;IndexLeft>0;++i,IndexLeft-=INDEXSTEP)
- {
- IndexCount = IndexLeft;
- if (IndexCount > INDEXSTEP)
- IndexCount = INDEXSTEP;
- if (CheckIndexBuffer(p,Input,i,-1,IndexCount)==ERR_NONE &&
- LoadIndexBuffer(p,Input,i,-1)==ERR_NONE)
- {
- for (k=0;k<IndexCount;++k)
- {
- j = STREAMNO(IndexBuffer(p,k)->Id);
- if (j>=0 && j<p->Format.StreamCount)
- {
- int Pos = IndexBuffer(p,k)->Pos - p->IndexAdjustPos + p->DataPos;
- int Size = IndexBuffer(p,k)->Length;
- Stream = (avistream*) p->Format.Streams[j];
- if ((Size==0 && Pos==LastPos) || (Pos==Stream->LastPos))
- AddZeroChunk(Stream);
- if (Size)
- {
- if (Stream->OffsetMin>Pos)
- Stream->OffsetMin=Pos;
- if (Stream->OffsetMax<Pos)
- Stream->OffsetMax=Pos;
- }
- LastPos = Pos;
- Stream->LastPos=Pos;
- Stream->NewMediaTime = Stream->NewMediaTime + ChunkTime(Stream,Size);
- }
- }
- }
- }
- }
- for (i=0;i<p->Format.StreamCount;++i)
- {
- Stream = (avistream*)p->Format.Streams[i];
- if (!ARRAYEMPTY(Stream->ZeroChunk))
- {
- Stream->NewMediaTime = MAX_INT;
- AddZeroChunk(Stream);
- }
- if (Stream->OffsetMax)
- {
- format_reader* Reader = Format_FindReader(&p->Format,Stream->OffsetMin,Stream->OffsetMax);
- if (Reader)
- Stream->Stream.Reader = Reader;
- }
- }
- ArrayClear(&Array);
- for (i=0;i<MAXREADER;++i)
- {
- format_reader* v = &p->Format.Reader[i];
- if (v->Input && v->OffsetMax>0)
- {
- v->Seek(v,v->OffsetMin,SEEK_SET);
- FlushBuffers = 1;
- if (Reader == v)
- OldReaderPos = v->OffsetMin;
- }
- }
- if (!FlushBuffers)
- Input->Seek(Input,OldFilePos,SEEK_SET);
- else
- {
- // probably first reader already allocated all the buffers
- Reader->FilePos = -1;
- Reader->Seek(Reader,OldReaderPos,SEEK_SET);
- }
- }
- static int Set(avi* p,int No,const void* Data,int Size)
- {
- if (No == NODE_SETTINGSCHANGED)
- UpdateAviFrameRate(p);
- return FormatBaseSet(&p->Format,No,Data,Size);
- }
- static void FreeStream(avi* p, avistream* Stream)
- {
- free(Stream->Index);
- free(Stream->SuperIndex);
- ArrayClear(&Stream->ZeroChunk);
- }
- static int Create(avi* p)
- {
- p->Format.Format.Set = (nodeset)Set;
- p->Format.Init = (fmtfunc)Init;
- p->Format.Done = (fmtvoid)Done;
- p->Format.Seek = (fmtseek)Seek;
- p->Format.ReadPacket = (fmtreadpacket)ReadPacket;
- p->Format.FreeStream = (fmtstream)FreeStream;
- p->Format.MinHeaderLoad = MAX_INT; //manualy setting HeaderLoaded
- return ERR_NONE;
- }
- static const nodedef AVI =
- {
- sizeof(avi),
- AVI_ID,
- FORMATBASE_CLASS,
- PRI_DEFAULT,
- (nodecreate)Create,
- };
- void AVI_Init()
- {
- NodeRegisterClass(&AVI);
- }
- void AVI_Done()
- {
- NodeUnRegisterClass(AVI_ID);
- }