/***************************************************************************** * * 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 * * The Core Pocket Media Player * Copyright (c) 2004-2005 Gabor Kovacs * ****************************************************************************/ #include "../common/common.h" #include "asf.h" //#define DUMPASF typedef struct asfstreamstate { int Offset; int Size; tick_t RefTime; format_ref* Ref; format_ref** Tail; } asfstreamstate; typedef struct asfstream { format_stream Stream; int TimeOffset; // milliseconds int DS_Span; // descrambling int DS_PacketSize; int DS_ChunkSize; asfstreamstate State; asfstreamstate Backup; } asfstream; typedef struct asfstate { bool_t Key; bool_t Multiple; bool_t Compressed; filepos_t End; int ValueLength; int Padding; asfstream* Stream; int PayloadCount; filepos_t PayloadEnd; int PayloadOffset; int PayloadTime; int CompressedTime; int CompressedDelta; } asfstate; typedef struct asfguid { guid ASFHeader; guid FileHeader; guid StreamHeader; guid AudioStream; guid VideoStream; guid CommentHeader; guid CodecCommentHeader; guid DataHeader; guid Index; guid HeadExt; guid Head2; guid NoErrorCorrection; guid AudioSpread; guid ExtendedComment; guid MarkerObject; guid StreamBitrate; guid StreamHeaderExt; } asfguid; typedef struct asf { format_base Format; filepos_t DataPos; int PacketMinSize; int PacketMaxSize; int64_t PacketCount; int64_t PlayTime; int PreRoll; int Flags; int ClientId; bool_t AdjustTime; bool_t AdjustTime0; array Bitrate; tick_t StreamingTime; format_ref* HTTPRef; format_reader HTTPReader; int HTTPChunkLeft; int HTTPChunkFilter; asfstate State; asfstate Backup; asfguid GUID; } asf; static const asfguid ASFGUID = { { 0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }}, { 0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }}, { 0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }}, { 0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }}, { 0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }}, { 0x75B22633, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }}, { 0x86D15240, 0x311D, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }}, { 0x75B22636, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }}, { 0x33000890, 0xE5B1, 0x11CF, { 0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB }}, { 0x5FBF03B5, 0xA92E, 0x11CF, { 0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }}, { 0xABD3D211, 0xA9BA, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }}, { 0x20FB5700, 0x5B55, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }}, { 0xBFC3CD50, 0x618F, 0x11CF, { 0x8B, 0xB2, 0x00, 0xAA, 0x00, 0xB4, 0xE2, 0x20 }}, { 0xD2D0A440, 0xE307, 0x11D2, { 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50 }}, { 0xF487CD01, 0xA951, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }}, { 0x7BF875CE, 0x468D, 0x11D1, { 0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2 }}, { 0x14E6A5CB, 0xC672, 0x4332, { 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A }} }; static void ReadGUID(format_reader* p,guid* g) { g->v1 = p->ReadLE32(p); g->v2 = (uint16_t) p->ReadLE16(p); g->v3 = (uint16_t) p->ReadLE16(p); p->Read(p,g->v4,8); } static void ReadStr(format_reader* p, int Len, tchar_t *Buf, size_t BufLen) { uint16_t ch[2]; ch[1] = 0; for (;Len>0;Len-=2) { ch[0] = (uint16_t) p->ReadLE16(p); #ifndef UNICODE WcsToTcs(Buf,BufLen,ch); BufLen -= tcslen(Buf); Buf += tcslen(Buf); #else if (BufLen > 1) { *Buf++ = ch[0]; --BufLen; } #endif } if (BufLen>0) *Buf = 0; } static void ReleaseStream(asf* p,asfstream* s) { Format_ReleaseRef(&p->Format,s->State.Ref); s->State.Ref = NULL; s->State.Tail = &s->State.Ref; s->State.Offset = 0; s->State.Size = 0; } static void AfterSeek(asf* p) { p->State.PayloadCount = 0; p->State.PayloadEnd = -1; p->State.End = -1; p->State.Stream = NULL; } static void BackupPacketState(asf* p, int Save) { int No; // ugly... if (Save) { p->Backup = p->State; AfterSeek(p); } else { AfterSeek(p); p->State = p->Backup; } for (No=0;NoFormat.StreamCount;++No) { asfstream* s = (asfstream*) p->Format.Streams[No]; if (Save) { s->Backup = s->State; s->State.Ref = NULL; // don't release fragref ReleaseStream(p,s); } else { ReleaseStream(p,s); s->State = s->Backup; } } } static void ReadStreamHeader(asf* p, format_reader* Reader) { int StreamId,i; int TimeOffset; int* BitRate; int FormatSize; int ErrorSize; guid Id,StreamType; asfstream* s; ReadGUID(Reader,&StreamType); // stream type ReadGUID(Reader,&Id); // error correction type TimeOffset = (int)(Reader->ReadLE64(Reader)/10000) - p->PreRoll; FormatSize = Reader->ReadLE32(Reader); // type-specific data length ErrorSize = Reader->ReadLE32(Reader); // error correction length StreamId = Reader->ReadLE16(Reader) & 0x7F; // flags Reader->Skip(Reader,4); for (i=0;iFormat.StreamCount;++i) if (p->Format.Streams[i]->Id == StreamId) return; s = (asfstream*) Format_AddStream(&p->Format,sizeof(asfstream)); if (!s) return; ReleaseStream(p,s); s->Stream.Id = StreamId; s->TimeOffset = TimeOffset; s->DS_Span = 0; if (memcmp(&StreamType, &p->GUID.AudioStream, sizeof(guid))==0) { Format_WaveFormat(Reader,&s->Stream,FormatSize); if (memcmp(&Id,&p->GUID.AudioSpread,sizeof(guid))==0) { int SilentLength; s->DS_Span = Reader->Read8(Reader); s->DS_PacketSize = Reader->ReadLE16(Reader); s->DS_ChunkSize = Reader->ReadLE16(Reader); SilentLength = Reader->ReadLE16(Reader); Reader->Skip(Reader,SilentLength); } if (s->DS_Span > 1) if (!s->DS_ChunkSize || (s->DS_PacketSize/s->DS_ChunkSize <= 1)) s->DS_Span = 0; } else if (memcmp(&StreamType, &p->GUID.VideoStream, sizeof(guid))==0) { int BitmapInfoSize; PacketFormatClear(&s->Stream.Format); s->Stream.Format.Type = PACKET_VIDEO; Reader->Skip(Reader,4+4+1); BitmapInfoSize = Reader->ReadLE16(Reader); if (BitmapInfoSize > 40 || FormatSize<=40+4+4+1+2) FormatSize = BitmapInfoSize; else FormatSize -= 4+4+1+2; Reader->Skip(Reader,4); s->Stream.Format.Format.Video.Width = Reader->ReadLE32(Reader); s->Stream.Format.Format.Video.Height = Reader->ReadLE32(Reader); Reader->ReadLE16(Reader); // planes s->Stream.Format.Format.Video.Pixel.BitCount = Reader->ReadLE16(Reader); s->Stream.Format.Format.Video.Pixel.FourCC = Reader->ReadLE32(Reader); s->Stream.Format.Format.Video.Aspect = ASPECT_ONE; //todo Reader->Skip(Reader,20); //SizeImage,XPelsPerMeter,YPelsPerMeter,ClrUsed,ClrImportant FormatSize -= 40; if (FormatSize > 0 && PacketFormatExtra(&s->Stream.Format,FormatSize)) Reader->Read(Reader,s->Stream.Format.Extra,s->Stream.Format.ExtraLength); PacketFormatDefault(&s->Stream.Format); } if (!s->Stream.Format.ByteRate) for (BitRate=ARRAYBEGIN(p->Bitrate,int);BitRate!=ARRAYEND(p->Bitrate,int);BitRate+=2) if (BitRate[0] == s->Stream.Id) { s->Stream.Format.ByteRate = BitRate[1]/8; break; } Format_PrepairStream(&p->Format,&s->Stream); } static int ReadHeaderExt(asf* p,format_reader* Reader,int Size) { guid Id; filepos_t EndPos; filepos_t End = Reader->FilePos+Size; while (Reader->FilePosEof(Reader)) return ERR_INVALID_DATA; ReadGUID(Reader,&Id); EndPos = (filepos_t)Reader->ReadLE64(Reader) - 24; if (EndPos < 0) return ERR_INVALID_DATA; EndPos += Reader->FilePos; DEBUG_MSG6(DEBUG_FORMAT,T("ASFExt %08x %08x-%04x-%04x-%08x%08x"),Reader->FilePos,Id.v1,Id.v2,Id.v3,*(int32_t*)&Id.v4[0],*(int32_t*)&Id.v4[4]); if (memcmp(&Id, &p->GUID.StreamHeaderExt, sizeof(guid))==0) { int i,n,PayloadCount,NameCount; // skip extended information // we are only interested in StreamHeader at the end... Reader->Skip(Reader,8); // start time Reader->Skip(Reader,8); // end time Reader->Skip(Reader,4+4+4); // data bitrate, buffer size, initial buffer fullness Reader->Skip(Reader,4+4+4); // alternate data bitrate, buffer size, initial buffer fullness Reader->Skip(Reader,4+4); // maximum object size, flags Reader->Skip(Reader,2); // stream id Reader->Skip(Reader,2+8); // language id, avg time per frame NameCount = Reader->ReadLE16(Reader); PayloadCount = Reader->ReadLE16(Reader); for (i=0;iSkip(Reader,2); // lang id n = Reader->ReadLE16(Reader); Reader->Skip(Reader,n*2); } for (i=0;iSkip(Reader,16+2); // guid, data size n = Reader->ReadLE32(Reader); Reader->Skip(Reader,n); } if (EndPos>Reader->FilePos+16+8) { ReadGUID(Reader,&Id); Reader->ReadLE64(Reader); if (memcmp(&Id, &p->GUID.StreamHeader, sizeof(guid))==0) ReadStreamHeader(p,Reader); } } Reader->Seek(Reader,EndPos,SEEK_SET); } return ERR_NONE; } static int ReadHeader(asf* p,format_reader* Reader) { int i,Count; tchar_t Buf[256]; guid Id; filepos_t EndPos; ReadGUID(Reader,&Id); if (memcmp(&Id, &p->GUID.ASFHeader, sizeof(guid))!=0) return ERR_INVALID_DATA; ArrayDrop(&p->Bitrate); Reader->Skip(Reader,8+4+1+1); for (;;) { if (Reader->Eof(Reader)) return ERR_INVALID_DATA; ReadGUID(Reader,&Id); EndPos = (filepos_t)Reader->ReadLE64(Reader) - 24; if (!memcmp(&Id, &p->GUID.DataHeader, sizeof(guid))) // allow invalid EndPos for this chunk { Reader->Skip(Reader,sizeof(guid)+8+2); // file id, total data packets, reserved break; } if (EndPos < 0) return ERR_INVALID_DATA; EndPos += Reader->FilePos; DEBUG_MSG6(DEBUG_FORMAT,T("ASF %08x %08x-%04x-%04x-%08x%08x"),Reader->FilePos,Id.v1,Id.v2,Id.v3,*(int32_t*)&Id.v4[0],*(int32_t*)&Id.v4[4]); if (memcmp(&Id, &p->GUID.FileHeader, sizeof(guid))==0) { int BitRate; Reader->Skip(Reader,sizeof(guid)+8+8); p->PacketCount = Reader->ReadLE64(Reader); p->PlayTime = Reader->ReadLE64(Reader); Reader->Skip(Reader,8); // send_time (sometimes not even valid) p->AdjustTime = 0; p->PreRoll = Reader->ReadLE32(Reader); Reader->Skip(Reader,4); // ignore p->Flags = Reader->ReadLE32(Reader); p->PacketMinSize = Reader->ReadLE32(Reader); // min packet size p->PacketMaxSize = Reader->ReadLE32(Reader); // max packet size BitRate = Reader->ReadLE32(Reader); // max bitrate if (BitRate > 0) p->Format.SumByteRate = BitRate/8; if (!(p->Flags & 1)) // not broadcast p->Format.Duration = (tick_t)(((p->PlayTime - (int64_t)p->PreRoll * 10000) * TICKSPERSEC) / 10000000); else { p->AdjustTime = 1; p->Format.Duration = -1; if (p->PacketMinSize <= 0) p->PacketMinSize = 0; if (p->PacketMaxSize <= 0) p->PacketMaxSize = 4*1024*1024; } p->AdjustTime0 = p->AdjustTime; } else if (memcmp(&Id, &p->GUID.StreamHeader, sizeof(guid))==0) { ReadStreamHeader(p,Reader); } else if (!memcmp(&Id, &p->GUID.MarkerObject, sizeof(guid)) && p->Format.Comment.Node) { int Len; Reader->Skip(Reader,sizeof(guid)); // reserved Count = Reader->ReadLE32(Reader); Reader->Skip(Reader,2); // reserved Len = Reader->ReadLE16(Reader); ReadStr(Reader,Len,Buf,TSIZEOF(Buf)); // marker name for (i=0;iSkip(Reader,8); // position Time = Reader->ReadLE64(Reader); EndPos = Reader->ReadLE16(Reader); EndPos += Reader->FilePos; Reader->Skip(Reader,8); // send time, flags stprintf_s(Buf,TSIZEOF(Buf),T("CHAPTER%02dNAME="),i+1); Len = Reader->ReadLE32(Reader); ReadStr(Reader,Len*sizeof(uint16_t),Buf+tcslen(Buf),TSIZEOF(Buf)-tcslen(Buf)); p->Format.Comment.Node->Set(p->Format.Comment.Node,p->Format.Comment.No,Buf,sizeof(Buf)); BuildChapter(Buf,TSIZEOF(Buf),i+1,Time,10000); p->Format.Comment.Node->Set(p->Format.Comment.Node,p->Format.Comment.No,Buf,sizeof(Buf)); Reader->Seek(Reader,EndPos,SEEK_SET); } } else if (!memcmp(&Id, &p->GUID.ExtendedComment, sizeof(guid)) && p->Format.Comment.Node) { int Type,Len; Count = Reader->ReadLE16(Reader); for (i=0;iReadLE16(Reader); ReadStr(Reader,Len,Buf,TSIZEOF(Buf)); Type = Reader->ReadLE16(Reader); Len = Reader->ReadLE16(Reader); if (Type == 0) { tcsupr(Buf); tcscat_s(Buf,TSIZEOF(Buf),T("=")); ReadStr(Reader,Len,Buf+tcslen(Buf),TSIZEOF(Buf)-tcslen(Buf)); p->Format.Comment.Node->Set(p->Format.Comment.Node,p->Format.Comment.No,Buf,sizeof(Buf)); } else Reader->Skip(Reader,Len); } } else if (!memcmp(&Id, &p->GUID.HeadExt, sizeof(guid))) { ReadGUID(Reader,&Id); if (!memcmp(&Id, &p->GUID.Head2, sizeof(guid))) { int Result; Reader->Skip(Reader,2); Result = ReadHeaderExt(p,Reader,Reader->ReadLE32(Reader)); if (Result != ERR_NONE) return Result; } } else if (!memcmp(&Id, &p->GUID.StreamBitrate, sizeof(guid))) { int Len = Reader->ReadLE16(Reader); ArrayAppend(&p->Bitrate,NULL,Len*2*sizeof(int),32); for (i=0;iBitrate,int)[i*2] = Id = Reader->ReadLE16(Reader); ARRAYBEGIN(p->Bitrate,int)[i*2+1] = BitRate = Reader->ReadLE32(Reader); for (No=0;NoFormat.StreamCount;++No) { format_stream* Stream = p->Format.Streams[No]; if (Stream->Id == Id && !Stream->Format.ByteRate) Stream->Format.ByteRate = BitRate/8; } } } else if (!memcmp(&Id, &p->GUID.CommentHeader, sizeof(guid)) && p->Format.Comment.Node) { static const tchar_t* const Comment[5] = { T("TITLE="), T("AUTHOR="), T("COPYRIGHT="), T("COMMENT="), T("RATING=") }; int Len[5]; for (i=0;i<5;++i) Len[i] = Reader->ReadLE16(Reader); for (i=0;i<5;++i) if (Len[i]) { tcscpy_s(Buf,TSIZEOF(Buf),Comment[i]); ReadStr(Reader,Len[i],Buf+tcslen(Buf),TSIZEOF(Buf)-tcslen(Buf)); if (tcslen(Buf) != tcslen(Comment[i])) p->Format.Comment.Node->Set(p->Format.Comment.Node,p->Format.Comment.No,Buf,sizeof(Buf)); } } Reader->Seek(Reader,EndPos,SEEK_SET); } return ERR_NONE; } static int Init(asf* p) { format_reader* Reader = p->Format.Reader; int Result; Result = ReadHeader(p,Reader); if (Result != ERR_NONE) return Result; AfterSeek(p); p->StreamingTime = -1; p->Format.TimeStamps = 1; p->Format.HeaderLoaded = 1; p->Format.SeekByPacket_DataStart = Reader->FilePos; if (p->PacketMaxSize == p->PacketMinSize) p->Format.SeekByPacket_BlockAlign = p->PacketMaxSize; return Result; } static void Done(asf* p) { ArrayClear(&p->Bitrate); } static int NOINLINE ReadValue(asf* p, format_reader* Reader,int Bits,int Default) { switch (Bits & 3) { default: case 0: return Default; case 1: return Reader->Read8(Reader); case 2: return Reader->ReadLE16(Reader); case 3: return Reader->ReadLE32(Reader); } } static bool_t ReadPacketHead(asf* p, format_reader* Reader,filepos_t End) { filepos_t pos; int len,time,padding; int i; pos = Reader->FilePos; if (p->PacketMinSize>0 && p->PacketMaxSize==p->PacketMinSize) { p->State.End = pos + p->PacketMinSize; p->State.Padding = 0; } i = Reader->Read8(Reader); if (i<0) return 0; if (i & 0x80) { // no real error correction supported if (i != 0x82 && i != 0x90) return 1; Reader->Skip(Reader,i & 15); i = Reader->Read8(Reader); } p->State.Multiple = i & 1; p->State.ValueLength = Reader->Read8(Reader); len = ReadValue(p,Reader,i>>5,p->PacketMaxSize); if (len<8 || len>p->PacketMaxSize) return 1; ReadValue(p,Reader,i>>1,0); // sequence padding = ReadValue(p,Reader,i>>3,0); if (padding<0 || padding>=p->PacketMaxSize) return 1; time = Reader->ReadLE32(Reader); // send time (milliseconds) if (p->StreamingTime >= 0) { if (!p->AdjustTime) { // orb server uses global time as timestamp, have to adjust it (but there is duration) p->Format.GlobalOffset = p->StreamingTime - Scale(time,TICKSPERSEC,1000); p->Format.TimeStamps = 0; } p->StreamingTime = -1; } Reader->Skip(Reader,2); // duration (milliseconds) if (p->State.Multiple) { i = Reader->Read8(Reader); p->State.PayloadCount = i&63; p->State.ValueLength |= i<<8; } else p->State.PayloadCount = 1; pos += len - padding; if (pos <= Reader->FilePos) { p->State.PayloadCount = 0; return 1; } assert(pos-Reader->FilePos<0x10000000); if (len < p->PacketMinSize) padding += p->PacketMinSize - len; p->State.End = pos; p->State.Padding = padding; if (p->HTTPRef) // adjust padding to remaining http packet length { p->State.Padding = Reader->ReadLen + p->HTTPChunkLeft - Reader->ReadPos - (pos - Reader->FilePos); if (p->State.Padding < 0) { p->State.End += p->State.Padding; p->State.Padding = 0; } } // DEBUG_MSG3(-1,T("asf %08x %d count:%d"),p->State.End,p->State.Padding,p->State.PayloadCount); return 1; } static bool_t ReadPayload(asf* p,format_reader* Reader) { int n,v = Reader->Read8(Reader); // stream number + keyframe bit if (v<0) { p->State.PayloadCount = 0; return 0; } p->State.Stream = NULL; p->State.Key = v>>7; v &= 0x7F; for (n=0;nFormat.StreamCount;++n) if (p->Format.Streams[n]->Id == v) { p->State.Stream = (asfstream*) p->Format.Streams[n]; break; } ReadValue(p,Reader,p->State.ValueLength>>4,0); // sequence v = ReadValue(p,Reader,p->State.ValueLength>>2,0); n = ReadValue(p,Reader,p->State.ValueLength,0); // replicated data length p->State.Compressed = n==1; if (p->State.Compressed) { p->State.CompressedTime = p->State.PayloadTime = v; p->State.CompressedDelta = Reader->Read8(Reader); p->State.PayloadOffset = 0; } else { p->State.PayloadOffset = v; if (n>1) { if (n<8) { p->State.PayloadCount = 0; return 1; } if (p->State.Stream) { p->State.Stream->State.Size = Reader->ReadLE32(Reader); p->State.PayloadTime = Reader->ReadLE32(Reader); n -= 8; } Reader->Skip(Reader,n); } } if (p->AdjustTime) { p->AdjustTime = 0; for (n=0;nFormat.StreamCount;++n) ((asfstream*)p->Format.Streams[n])->TimeOffset = -p->State.PayloadTime; } if (p->State.Multiple) { p->State.PayloadEnd = ReadValue(p,Reader,p->State.ValueLength>>14,0); p->State.PayloadEnd += Reader->FilePos; if (p->State.PayloadEnd > p->State.End) { p->State.PayloadCount = 0; p->State.PayloadEnd = -1; return 1; } } else p->State.PayloadEnd = p->State.End; if (!p->State.Stream) { Reader->Skip(Reader,p->State.PayloadEnd - Reader->FilePos); p->State.PayloadEnd = -1; --p->State.PayloadCount; } return 1; } static int ReadPacket(asf* p, format_reader* Reader, format_packet* Packet) { filepos_t End = Reader->FilePos+BLOCKSIZE; for (;;) { if (p->State.PayloadCount<=0) { if (Reader->FilePos >= End) break; if (p->State.End >= 0) { Reader->Skip(Reader,p->State.End+p->State.Padding-Reader->FilePos); p->State.End = -1; } if (!ReadPacketHead(p,Reader,End)) break; } else if (p->State.PayloadEnd<0) { if (!ReadPayload(p,Reader)) break; } else { int Size = p->State.PayloadEnd - Reader->FilePos; if (Size<=0) { p->State.PayloadEnd = -1; --p->State.PayloadCount; } else { asfstream* s = p->State.Stream; if (p->State.Compressed) { s->State.Size = Reader->Read8(Reader); if (s->State.Size > Size) { Reader->Skip(Reader,Size); continue; } Size = s->State.Size; p->State.PayloadTime = p->State.CompressedTime; p->State.CompressedTime += p->State.CompressedDelta; } if (s->State.Offset != p->State.PayloadOffset) // gap in offset { ReleaseStream(p,s); if (p->State.PayloadOffset) { Reader->Skip(Reader,Size); continue; } } if (s->State.Offset==0) // start of a new packet { s->State.RefTime = Scale(p->State.PayloadTime + s->TimeOffset,TICKSPERSEC,1000); if (s->State.RefTime < 0) s->State.RefTime = 0; } *s->State.Tail = Reader->ReadAsRef(Reader,Size); while (*s->State.Tail) s->State.Tail = &(*s->State.Tail)->Next; s->State.Offset += Size; if (s->State.Offset >= s->State.Size) { Packet->Key = p->State.Key; Packet->Data = s->State.Ref; Packet->RefTime = s->State.RefTime; Packet->Stream = &s->Stream; if (s->DS_Span > 1) { format_ref* New = NULL; format_ref** Ptr = &New; int Left = s->State.Size; int Row = 0; int Col = 0; while (Left>0) { int Idx = Row+Col*s->DS_Span; *Ptr = Format_DupRef(&p->Format,Packet->Data,Idx * s->DS_ChunkSize, s->DS_ChunkSize ); while (*Ptr) Ptr = &(*Ptr)->Next; Left -= s->DS_ChunkSize; Col++; if (Col == s->DS_Span) { Col = 0; Row++; } } Format_ReleaseRef(&p->Format,Packet->Data); Packet->Data = New; } s->State.Size = 0; s->State.Offset = 0; s->State.Ref = NULL; s->State.Tail = &s->State.Ref; return ERR_NONE; } } } } return ERR_DATA_NOT_FOUND; } static int Seek(asf* p,tick_t Time,filepos_t FilePos,bool_t PrevKey) { return Format_SeekByPacket(&p->Format,Time,FilePos,PrevKey); } #ifdef DUMPASF static FILE* Dump = NULL; #endif static bool_t GetHTTPBuffer(format_reader* HTTPReader) { int n,Ofs = 0; asf* p = ((asf*)((char*)(HTTPReader)-(int)&(((asf*)0)->HTTPReader))); format_reader* Reader = p->Format.Reader; for (n=0;n<16;++n) // maximum chunk tries { if (p->HTTPRef) { Format_ReleaseRef(&p->Format,p->HTTPRef); p->HTTPRef = NULL; HTTPReader->ReadBuffer = NULL; Ofs = HTTPReader->ReadPos - HTTPReader->ReadLen; HTTPReader->ReadLen = 0; } if (p->HTTPChunkLeft > 0) { p->HTTPRef = Reader->ReadAsRef(Reader,-p->HTTPChunkLeft); if (!p->HTTPRef) { HTTPReader->NoMoreInput = Reader->Eof(Reader); break; } else { HTTPReader->ReadBuffer = p->HTTPRef->Buffer; HTTPReader->ReadPos = p->HTTPRef->Begin + Ofs; HTTPReader->ReadLen = p->HTTPRef->Begin + p->HTTPRef->Length; p->HTTPChunkLeft -= p->HTTPRef->Length; #ifdef DUMPASF if (Dump) fwrite(HTTPReader->ReadBuffer->Block.Ptr+HTTPReader->ReadPos,1,HTTPReader->ReadLen-HTTPReader->ReadPos,Dump); #endif break; } } else { int Type,Len; Type = Reader->ReadLE16(Reader); Len = Reader->ReadLE16(Reader)-8; Reader->Skip(Reader,8); if ((Type & ASF_CHUNK_MASK) != p->HTTPChunkFilter) { if (Type == ASF_CHUNK_END && Len<0) Len += 8; HTTPReader->NoMoreInput = Reader->Eof(Reader); if (HTTPReader->NoMoreInput) break; if (Len >= 0) { #if 0 //def DUMPASF if (Dump) { void* i = malloc(Len); Reader->Read(Reader,i,Len); fwrite(i,1,Len,Dump); free(i); } else #endif Reader->Skip(Reader,Len); } } else p->HTTPChunkLeft = Len; } } return HTTPReader->ReadBuffer != NULL; } static void AfterSeekHTTP(asf* p) { AfterSeek(p); Format_ReleaseRef(&p->Format,p->HTTPRef); p->HTTPRef = NULL; p->HTTPChunkLeft = 0; p->HTTPReader.NoMoreInput = 0; p->HTTPReader.FilePos = 0; p->HTTPReader.ReadPos = 0; p->HTTPReader.ReadLen = 0; p->HTTPReader.ReadBuffer = NULL; } static int SetPragma(asf* p,tick_t Time) { int i; tchar_t Pragma[512]; if (p->Format.StreamCount && p->Format.Reader[0].Input->Get(p->Format.Reader[0].Input,STREAM_PRAGMA_GET,Pragma,sizeof(Pragma)) == ERR_NONE && tcslen(Pragma)>0) { bool_t First=1; int Count=0; p->StreamingTime = Time; for (i=0;iFormat.StreamCount;++i) if (p->Format.Streams[i]->Pin.Node) ++Count; stprintf_s(Pragma,TSIZEOF(Pragma), T("Pragma: no-cache,rate=1.000000,stream-time=%d,stream-offset=4294967295:4294967295,") T("request-context=2,max-duration=0,") T("xPlayStrm=1,") T("xClientGUID={3300AD50-2C39-46c0-AE0A-132C%08X},") T("stream-switch-count=%d,") T("stream-switch-entry=") ,Scale(Time,1000,TICKSPERSEC),p->ClientId,Count); for (i=0;iFormat.StreamCount;++i) if (p->Format.Streams[i]->Pin.Node) { if (!First) tcscat_s(Pragma,TSIZEOF(Pragma),T(" ")); else First=0; stcatprintf_s(Pragma,TSIZEOF(Pragma),T("ffff:%d:0"),p->Format.Streams[i]->Id); } tcscat_s(Pragma,TSIZEOF(Pragma),T("\n")); if (p->Format.Reader[0].Input->Set(p->Format.Reader[0].Input,STREAM_PRAGMA_SEND,Pragma,sizeof(Pragma)) == ERR_NONE) { int Result = Format_SeekForce(&p->Format,0,SEEK_SET); //reopen (because of seeking) if (Result == ERR_NONE) p->AdjustTime = p->AdjustTime0; return Result; } } return ERR_NOT_SUPPORTED; } static int InitHTTP(asf* p) { int Result; p->StreamingTime = 0; p->HTTPRef = NULL; memcpy(&p->HTTPReader,p->Format.Reader,sizeof(p->HTTPReader)); p->HTTPReader.BufferAvailable = 0; p->HTTPReader.BufferFirst = NULL; p->HTTPReader.BufferLast = NULL; p->HTTPReader.Input = NULL; p->HTTPReader.InputBuffer = NULL; p->HTTPReader.GetReadBuffer = GetHTTPBuffer; AfterSeekHTTP(p); p->HTTPChunkFilter = ASF_CHUNK_HEADER; Result = ReadHeader(p,&p->HTTPReader); if (Result != ERR_NONE) return Result; AfterSeekHTTP(p); p->HTTPChunkFilter = ASF_CHUNK_DATA; p->PacketMinSize = 0; // it's possible packets are not padded to MinSize p->ClientId = (rand() << 16) | rand(); p->Format.HeaderLoaded = 1; p->Format.ReadSize = 4096; if (!GetHTTPBuffer(&p->HTTPReader) && p->HTTPReader.Eof(&p->HTTPReader)) Result = SetPragma(p,0); // try reopen http stream with proper pragma #ifdef DUMPASF Dump = fopen("\\dumpasf.asf","wb+"); #endif return Result; } static void DoneHTTP(asf* p) { #ifdef DUMPASF if (Dump) { fclose(Dump); Dump = NULL; } #endif Format_ReleaseRef(&p->Format,p->HTTPRef); Done(p); } static int SetHTTP(asf* p,int No,const void* Data,int Size) { int Result = FormatBaseSet(&p->Format,No,Data,Size); if (No==FORMAT_UPDATEMASK && Size==sizeof(tick_t)) SetPragma(p,*(tick_t*)Data); return Result; } static int SeekHTTP(asf* p,tick_t Time,filepos_t FilePos,bool_t PrevKey) { if (Time < 0) return ERR_NOT_SUPPORTED; return SetPragma(p,Time); } static int ReadPacketHTTP(asf* p, format_reader* Reader, format_packet* Packet) { return ReadPacket(p,&p->HTTPReader,Packet); } static int Create(asf* p) { p->GUID = ASFGUID; p->Format.Init = (fmtfunc)Init; p->Format.Done = (fmtvoid)Done; p->Format.Seek = (fmtseek)Seek; p->Format.ReadPacket = (fmtreadpacket)ReadPacket; p->Format.ReleaseStream = (fmtstream)ReleaseStream; p->Format.AfterSeek = (fmtvoid)AfterSeek; p->Format.BackupPacketState = (fmtbackup)BackupPacketState; return ERR_NONE; } static int CreateHTTP(asf* p) { p->GUID = ASFGUID; p->Format.Init = (fmtfunc)InitHTTP; p->Format.Done = (fmtvoid)DoneHTTP; p->Format.Seek = (fmtseek)SeekHTTP; p->Format.ReadPacket = (fmtreadpacket)ReadPacketHTTP; p->Format.AfterSeek = (fmtvoid)AfterSeekHTTP; p->Format.Format.Set = (nodeset)SetHTTP; return ERR_NONE; } static const nodedef ASF = { sizeof(asf), ASF_ID, FORMATBASE_CLASS, PRI_DEFAULT-1, // prefer WMVF and WMAF (just for the reader name) (nodecreate)Create, }; static const nodedef ASFHTTP = { 0, // parent size ASF_HTTP_ID, ASF_ID, PRI_DEFAULT, (nodecreate)CreateHTTP, NULL, }; void ASF_Init() { NodeRegisterClass(&ASF); NodeRegisterClass(&ASFHTTP); } void ASF_Done() { NodeUnRegisterClass(ASF_ID); NodeUnRegisterClass(ASF_HTTP_ID); }