ogg.c
资源名称:tcpmp.rar [点击查看]
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:24k
源码类别:
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: ogg.c 543 2006-01-07 22:06:24Z picard $
- *
- * The Core Pocket Media Player
- * Copyright (c) 2004-2005 Gabor Kovacs
- *
- ****************************************************************************/
- #include "../common/common.h"
- #include "vorbis.h"
- #include "tremor/ogg.h"
- #include "tremor/ivorbiscodec.h"
- // OGG and OGM file format
- #define PACKET_TYPE_HEADER 0x01
- #define PACKET_TYPE_COMMENT 0x03
- #define PACKET_TYPE_CODEBOOK 0x05
- #define PACKET_TYPE_BITS 0x07
- #define PACKET_IS_SYNCPOINT 0x08
- #define PACKET_LEN_BITS01 0xc0
- #define PACKET_LEN_BITS2 0x02
- static const char MT_Video[] = "video";
- static const char MT_Audio[] = "audio";
- static const char MT_Text[] = "text";
- typedef struct oggstream
- {
- format_stream Stream;
- bool_t Invalid; // not vorbis and not ogm
- bool_t Vorbis; // sending direct oggpackets (not the merged binary data)
- bool_t Native; // speex
- int PacketNo;
- int64_t MediaTime; // in units
- int64_t MediaRateNum; // in units/tick
- int64_t MediaRateDen;
- int DefaultLen;
- bool_t NeedMorePage;
- ogg_stream_state* OggStream;
- ogg_packet OggPacket;
- vorbis_info Info;
- vorbis_comment Comment;
- } oggstream;
- typedef struct ogg
- {
- format_base Format;
- ogg_sync_state* OggSync;
- ogg_page OggPage;
- } ogg;
- typedef struct ogm_header_video
- {
- int32_t width;
- int32_t height;
- } ogm_header_video;
- typedef struct ogm_header_audio
- {
- int16_t channels;
- int16_t blockalign;
- int32_t avgbytespersec;
- } ogm_header_audio;
- typedef struct ogm_header
- {
- char streamtype[8];
- char subtype[4];
- int32_t size;
- int64_t time_unit;
- int64_t samples_per_unit;
- int32_t default_len;
- int32_t buffersize;
- int16_t bits_per_sample;
- union
- {
- ogm_header_video video;
- ogm_header_audio audio;
- } format;
- } ogm_header;
- extern int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb,int eop);
- static void FreeStream(ogg* p,oggstream* Stream)
- {
- vorbis_comment_clear(&Stream->Comment);
- vorbis_info_clear(&Stream->Info);
- ogg_packet_release(&Stream->OggPacket);
- if (Stream->OggStream)
- {
- ogg_stream_destroy(Stream->OggStream);
- Stream->OggStream = NULL;
- }
- }
- static void Done(ogg* p)
- {
- ogg_page_release(&p->OggPage);
- if (p->OggSync)
- {
- ogg_sync_destroy(p->OggSync);
- p->OggSync = NULL;
- }
- }
- static int AddBuffer(ogg* p,format_buffer* Buffer)
- {
- if (!Buffer)
- return ERR_NEED_MORE_DATA;
- if (Buffer->Length)
- {
- ogg_buffer* Ptr = ogg_sync_bufferinext(p->OggSync);
- if (!Ptr)
- {
- Format_BufferRelease(&p->Format,Buffer);
- return ERR_OUT_OF_MEMORY;
- }
- Ptr->ext = &p->Format;
- Ptr->extdata = Buffer;
- Ptr->data = Buffer->Block.Ptr;
- Ptr->size = Buffer->Length;
- ogg_sync_wrote(p->OggSync,Buffer->Length);
- }
- else
- Format_BufferRelease(&p->Format,Buffer);
- return ERR_NONE;
- }
- static int Init(ogg* p)
- {
- format_reader* Reader = p->Format.Reader;
- format_buffer* Buffer;
- int i;
- memset(&p->OggPage,0,sizeof(ogg_page));
- p->OggSync = ogg_sync_create();
- p->Format.TimeStamps = 1;
- if (!p->OggSync)
- return ERR_OUT_OF_MEMORY;
- Format_ReadBuffer(Reader,0);
- Buffer = Format_BufferRemove(Reader);
- if (!Buffer)
- return ERR_INVALID_DATA;
- // search for 'OggS' pattern
- for (i=3;i<Buffer->Length;++i)
- if (Buffer->Block.Ptr[i-3]=='O' &&
- Buffer->Block.Ptr[i-2]=='g' &&
- Buffer->Block.Ptr[i-1]=='g' &&
- Buffer->Block.Ptr[i-0]=='S')
- break;
- if (i==Buffer->Length)
- {
- Format_BufferRelease(&p->Format,Buffer);
- return ERR_INVALID_DATA;
- }
- return AddBuffer(p,Buffer);
- }
- static void AfterSeek(ogg* p)
- {
- ogg_sync_reset(p->OggSync);
- }
- static void ReleaseStream(ogg* p,oggstream* Stream)
- {
- ogg_stream_reset_serialno(Stream->OggStream,Stream->Stream.Id);
- Stream->NeedMorePage = 1;
- Stream->MediaTime = Stream->Stream.Reader->FilePos>0 && Stream->PacketNo>3 ? -1:0;
- }
- extern void oggext_release(void* ext,void* ext2)
- {
- if (ext && ext2)
- Format_BufferRelease((format_base*)ext,(format_buffer*)ext2);
- }
- static int ReadPacketTime( ogg* p, format_reader* Reader, format_packet* Packet )
- {
- // only called by CalcDuration
- format_buffer* Buffer;
- int Bytes;
- ogg_buffer* Ptr;
- ogg_sync_state* Sync = ogg_sync_create();
- ogg_page Page;
- if (!Sync)
- return ERR_OUT_OF_MEMORY;
- while ((Buffer = Format_BufferRemove(Reader))!=NULL)
- {
- Ptr = ogg_sync_bufferinext(Sync);
- if (Ptr)
- {
- Ptr->ext = &p->Format;
- Ptr->extdata = Buffer;
- Ptr->data = Buffer->Block.Ptr;
- Ptr->size = Buffer->Length;
- ogg_sync_wrote(Sync,Buffer->Length);
- }
- else
- Format_BufferRelease(&p->Format,Buffer);
- }
- memset(&Page,0,sizeof(Page));
- while ((Bytes = ogg_sync_pageseek(Sync,&Page)) != 0)
- {
- if (Bytes > 0)
- {
- int64_t MediaTime = ogg_page_granulepos(&Page);
- int Id = ogg_page_serialno(&Page);
- int i;
- if (MediaTime != -1)
- for (i=0;i<p->Format.StreamCount;++i)
- if (p->Format.Streams[i]->Id == Id)
- {
- oggstream* s = (oggstream*) p->Format.Streams[i];
- if (s->MediaRateNum)
- {
- tick_t RefTime = (tick_t)((MediaTime * s->MediaRateDen) / s->MediaRateNum);
- if (RefTime > Packet->RefTime)
- {
- Packet->Stream = &s->Stream;
- Packet->RefTime = RefTime;
- }
- }
- break;
- }
- }
- }
- ogg_page_release(&Page);
- ogg_sync_destroy(Sync);
- return ERR_NONE;
- }
- static void FrameRate( fraction* f, int64_t Num, int64_t Den )
- {
- while (Num > MAX_INT || Den > MAX_INT)
- {
- Num >>= 1;
- Den >>= 1;
- }
- f->Num = (int)Num;
- f->Den = (int)Den;
- }
- static bool_t SpeexHeader(ogg* p, oggstream* s, const char* Data, int Length )
- {
- if (Length<80 && strncmp(Data,"Speex ",8)!=0)
- return 0;
- PacketFormatClear(&s->Stream.Format);
- s->Stream.Format.Type = PACKET_AUDIO;
- s->Stream.Format.Format.Audio.Format = AUDIOFMT_SPEEX;
- s->Stream.Format.Format.Audio.Channels = INT32LE(*(int32_t*)(Data+48));
- s->Stream.Format.ByteRate = INT32LE(*(int32_t*)(Data+52))/8;
- s->Stream.Format.Format.Audio.SampleRate = INT32LE(*(int32_t*)(Data+36));
- s->MediaRateDen = TICKSPERSEC;
- s->MediaRateNum = s->Stream.Format.Format.Audio.SampleRate;
- s->Native = 1;
- if (PacketFormatExtra(&s->Stream.Format,Length))
- memcpy(s->Stream.Format.Extra,Data,s->Stream.Format.ExtraLength);
- return 1;
- }
- static bool_t OGMHeader(ogg* p, oggstream* s, const char* Data, int Length )
- {
- int i;
- if (Length<40 || (*Data & PACKET_TYPE_BITS) != PACKET_TYPE_HEADER)
- return 0;
- if (strncmp(Data+1, "Direct Show Samples embedded in Ogg", 35) == 0)
- {
- // old header
- if (INT32LE(*(int32_t*)(Data+96)) == 0x05589F80)
- {
- PacketFormatClear(&s->Stream.Format);
- s->Stream.Format.Type = PACKET_VIDEO;
- s->Stream.Format.Format.Video.Width = INT32LE(*(int32_t*)(Data+176));
- s->Stream.Format.Format.Video.Height = INT32LE(*(int32_t*)(Data+180));
- s->Stream.Format.Format.Video.Pixel.FourCC = INT32LE(*(int32_t*)(Data+68));
- s->Stream.Format.Format.Video.Pixel.BitCount = INT16LE(*(int16_t*)(Data+182));
- i = INT16LE(*(int16_t*)(Data+136)); // extrasize
- if (i && PacketFormatExtra(&s->Stream.Format,i))
- memcpy(s->Stream.Format.Extra,Data+142,s->Stream.Format.ExtraLength);
- s->MediaRateDen = INT64LE(*(int32_t*)(Data+164))*TICKSPERSEC;
- s->MediaRateNum = 10000000;
- s->DefaultLen = 1;
- FrameRate(&s->Stream.Format.PacketRate,s->MediaRateNum,s->MediaRateDen/TICKSPERSEC);
- return 1;
- }
- if (INT32LE(*(int32_t*)(Data+96)) == 0x05589F81)
- {
- PacketFormatClear(&s->Stream.Format);
- s->Stream.Format.Type = PACKET_AUDIO;
- s->Stream.Format.Format.Audio.Format = INT16LE(*(int16_t*)(Data+124));
- s->Stream.Format.Format.Audio.Channels = INT16LE(*(int16_t*)(Data+126));
- s->Stream.Format.Format.Audio.BlockAlign = INT16LE(*(int16_t*)(Data+136));
- s->Stream.Format.Format.Audio.Bits = INT16LE(*(int16_t*)(Data+138));
- s->Stream.Format.Format.Audio.SampleRate = INT32LE(*(int32_t*)(Data+128));
- s->Stream.Format.ByteRate = INT32LE(*(int32_t*)(p+132));
- i = INT16LE(*(int16_t*)(Data+136)); // extrasize
- if (i && PacketFormatExtra(&s->Stream.Format,i))
- memcpy(s->Stream.Format.Extra,Data+142,s->Stream.Format.ExtraLength);
- s->MediaRateDen = TICKSPERSEC;
- s->MediaRateNum = INT32LE(*(int32_t*)(Data+128));
- s->DefaultLen = 1;
- return 1;
- }
- }
- else
- if (Length >= sizeof(ogm_header)+1)
- {
- ogm_header Head;
- memcpy(&Head,Data+1,sizeof(Head));
- // new header
- if (strncmp(Head.streamtype, MT_Video, strlen(MT_Video)) == 0)
- {
- PacketFormatClear(&s->Stream.Format);
- s->Stream.Format.Type = PACKET_VIDEO;
- s->Stream.Format.Format.Video.Width = INT32LE(Head.format.video.width);
- s->Stream.Format.Format.Video.Height = INT32LE(Head.format.video.height);
- s->Stream.Format.Format.Video.Pixel.FourCC = INT32LE(*(int32_t*)Head.subtype);
- s->Stream.Format.Format.Video.Pixel.BitCount = INT16LE(Head.bits_per_sample);
- s->MediaRateDen = INT64LE(Head.time_unit)*TICKSPERSEC;
- s->MediaRateNum = INT64LE(Head.samples_per_unit) * 10000000;
- s->DefaultLen = INT32LE(Head.default_len);
- FrameRate(&s->Stream.Format.PacketRate,s->MediaRateNum,s->MediaRateDen/TICKSPERSEC);
- i = Length - (sizeof(ogm_header)+1);
- if (i && PacketFormatExtra(&s->Stream.Format,i))
- memcpy(s->Stream.Format.Extra,Data+1+sizeof(ogm_header),s->Stream.Format.ExtraLength);
- return 1;
- }
- if (strncmp(Head.streamtype, MT_Audio, strlen(MT_Audio)) == 0)
- {
- PacketFormatClear(&s->Stream.Format);
- s->Stream.Format.Type = PACKET_AUDIO;
- s->Stream.Format.Format.Audio.Format = 0;
- for (i=0;i<4;++i)
- if (Head.subtype[i])
- s->Stream.Format.Format.Audio.Format = s->Stream.Format.Format.Audio.Format*16+Hex(Head.subtype[i]);
- s->Stream.Format.Format.Audio.Channels = INT16LE(Head.format.audio.channels);
- s->Stream.Format.Format.Audio.Bits = INT16LE(Head.bits_per_sample);
- s->Stream.Format.Format.Audio.BlockAlign = INT16LE(Head.format.audio.blockalign);
- s->Stream.Format.ByteRate = INT32LE(Head.format.audio.avgbytespersec);
- s->Stream.Format.Format.Audio.SampleRate = (int)INT64LE(Head.samples_per_unit);
- s->MediaRateDen = INT64LE(Head.time_unit)*TICKSPERSEC;
- s->MediaRateNum = INT64LE(Head.samples_per_unit) * 10000000;
- s->DefaultLen = INT32LE(Head.default_len);
- i = Length - (sizeof(ogm_header)+1);
- if (i && PacketFormatExtra(&s->Stream.Format,i))
- memcpy(s->Stream.Format.Extra,Data+1+sizeof(ogm_header),s->Stream.Format.ExtraLength);
- return 1;
- }
- if (strncmp(Data+1, MT_Text, strlen(MT_Text)) == 0)
- {
- PacketFormatClear(&s->Stream.Format);
- s->Stream.Format.Type = PACKET_SUBTITLE;
- s->Stream.Format.Format.Subtitle.FourCC = SUBTITLE_OEM; //???
- s->MediaRateDen = INT64LE(Head.time_unit)*TICKSPERSEC;
- s->MediaRateNum = INT64LE(Head.samples_per_unit) * 10000000;
- s->DefaultLen = INT32LE(Head.default_len);
- i = Length - (sizeof(ogm_header)+1);
- if (i && PacketFormatExtra(&s->Stream.Format,i))
- memcpy(s->Stream.Format.Extra,Data+1+sizeof(ogm_header),s->Stream.Format.ExtraLength);
- return 1;
- }
- }
- return 0;
- }
- static void SendComments(oggstream* Stream)
- {
- tchar_t s[256];
- if (Stream->Stream.Comment.Node)
- {
- int No;
- for (No=0;No<Stream->Comment.comments;++No)
- {
- UTF8ToTcs(s,TSIZEOF(s),Stream->Comment.user_comments[No]);
- Stream->Stream.Comment.Node->Set(Stream->Stream.Comment.Node,Stream->Stream.Comment.No,s,sizeof(s));
- }
- }
- }
- static bool_t VorbisHeader(ogg* p,oggstream* s)
- {
- tchar_t URL[MAXPATH];
- if (vorbis_synthesis_headerin(&s->Info,&s->Comment,&s->OggPacket)<0)
- return 0;
- PacketFormatClear(&s->Stream.Format);
- s->Stream.Format.Type = PACKET_AUDIO;
- s->Stream.Format.Format.Audio.Channels = s->Info.channels;
- s->Stream.Format.Format.Audio.SampleRate = s->Info.rate;
- s->Stream.Format.ByteRate = s->Info.bitrate_nominal >> 3;
- if (p->Format.Reader->Input->Get(p->Format.Reader->Input,STREAM_URL,URL,sizeof(URL))==ERR_NONE &&
- CheckExts(URL,T("ogg:A")) != 0)
- s->Stream.Format.Format.Audio.Format = AUDIOFMT_VORBIS_INTERNAL_AUDIO;
- else
- s->Stream.Format.Format.Audio.Format = AUDIOFMT_VORBIS_INTERNAL_VIDEO;
- s->Vorbis = 1;
- s->MediaRateDen = TICKSPERSEC;
- s->MediaRateNum = s->Info.rate;
- return 1;
- }
- static int FillQueue(ogg* p,format_reader* Reader)
- {
- for (;;)
- {
- int Bytes = ogg_sync_pageseek(p->OggSync,&p->OggPage);
- if (Bytes == 0) // need more data
- {
- int Result;
- format_buffer* Buffer;
- if (!Reader->BufferAvailable && (!p->Format.SyncMode || p->Format.SyncRead<=0))
- return ERR_NEED_MORE_DATA;
- Buffer = Format_BufferRemove(Reader);
- if (!Buffer && p->Format.SyncMode && p->Format.SyncRead>0 && Format_ReadBuffer(Reader,0))
- Buffer = Format_BufferRemove(Reader);
- Result = AddBuffer(p,Buffer);
- if (Result != ERR_NONE)
- return Result;
- }
- else
- if (Bytes < 0)
- Reader->FilePos -= Bytes;
- else
- if (Bytes > 0)
- {
- int StreamNo;
- oggstream* s;
- int Id;
- Reader->FilePos += Bytes;
- Id = ogg_page_serialno(&p->OggPage);
- DEBUG_MSG4(DEBUG_FORMAT,T("OGG Page id:%d size:%d gran:%d filepos:%d"),Id,p->OggPage.body_len,(int)ogg_page_granulepos(&p->OggPage),Reader->FilePos - Bytes);
- for (StreamNo=0;StreamNo<p->Format.StreamCount;++StreamNo)
- if (p->Format.Streams[StreamNo]->Id == Id)
- break;
- if (StreamNo==p->Format.StreamCount)
- {
- // check for restarted audio http streaming (comments changed)
- if (p->Format.StreamCount==1 &&
- p->Format.Streams[0]->Format.Type == PACKET_AUDIO &&
- p->Format.Streams[0]->LastTime>0)
- {
- StreamNo = 0;
- s = (oggstream*) p->Format.Streams[0];
- if (s->Vorbis)
- {
- // vorbis decoder have to release s->Info
- s->Stream.Format.Extra = NULL;
- s->Stream.Format.ExtraLength = 0;
- ConnectionUpdate((node*)&p->Format,FORMAT_STREAM+0,s->Stream.Pin.Node,s->Stream.Pin.No);
- }
- FreeStream(p,s);
- }
- else
- {
- s = (oggstream*) Format_AddStream(&p->Format,sizeof(oggstream));
- if (!s) continue;
- }
- // init stream
- s->Stream.Id = Id;
- s->OggStream = ogg_stream_create(Id);
- s->NeedMorePage = 1;
- s->MediaTime = 0;
- s->Invalid = 0;
- s->Vorbis = 0;
- s->Native = 0;
- s->PacketNo = 0;
- vorbis_info_init(&s->Info);
- vorbis_comment_init(&s->Comment);
- }
- s = (oggstream*) p->Format.Streams[StreamNo];
- if (s->Invalid) // drop invalid streams
- continue;
- if (s->PacketNo>=3)
- {
- if (!s->Stream.Pin.Node) // drop unused streams
- continue;
- if (p->Format.InSeek)
- {
- // reftime needed for SeekByPacket
- if ((s->MediaTime = ogg_page_granulepos(&p->OggPage)) != -1)
- {
- // no need for GlobalOffset here
- s->Stream.LastTime = (tick_t)(s->MediaTime * s->MediaRateDen / s->MediaRateNum);
- if (s->Stream.Format.Type == PACKET_AUDIO)
- {
- s->Stream.LastTime += p->Format.AVOffset;
- if (s->Stream.LastTime < 0)
- s->Stream.LastTime = 0;
- }
- }
- }
- }
- // add page to stream
- if (ogg_stream_pagein(s->OggStream,&p->OggPage) >= 0)
- {
- if (s->PacketNo<3) // header packet needed?
- {
- int i = ogg_stream_packetout(s->OggStream,&s->OggPacket);
- if (i == 0) // stream needs more pages
- continue;
- if (++s->PacketNo==1) // first packet?
- {
- ogg_reference* Ref;
- const void* Data;
- int Length;
- if (i < 0)
- {
- // first header packet is a must have
- s->Invalid = 1;
- continue;
- }
- if (p->Format.UseBufferBlock)
- {
- for (Length=0,Ref=s->OggPacket.packet;Ref;Ref=Ref->next)
- Length += Ref->length;
- if (s->Stream.BufferBlockLength<Length && !Format_AllocBufferBlock(&p->Format,&s->Stream,Length))
- {
- Length = 0;
- Data = NULL;
- }
- else
- {
- for (Length=0,Ref=s->OggPacket.packet;Ref;Ref=Ref->next)
- {
- WriteBlock(&s->Stream.BufferBlock,Length,Ref->buffer->data + Ref->begin,Ref->length);
- Length += Ref->length;
- }
- Data = s->Stream.BufferBlock.Ptr;
- }
- }
- else
- {
- BufferDrop(&s->Stream.BufferMem);
- for (Ref=s->OggPacket.packet;Ref;Ref=Ref->next)
- BufferWrite(&s->Stream.BufferMem,Ref->buffer->data + Ref->begin, Ref->length, 16384);
- Data = s->Stream.BufferMem.Data;
- Length = s->Stream.BufferMem.WritePos;
- }
- if (OGMHeader(p,s,(char*)Data,Length) || SpeexHeader(p,s,(char*)Data,Length))
- {
- PacketFormatDefault(&s->Stream.Format);
- s->PacketNo = 3; // no more headers
- }
- else
- if (!VorbisHeader(p,s))
- {
- s->Invalid = 1;
- continue;
- }
- while (s->MediaRateNum > (1<<30))
- {
- s->MediaRateDen >>= 1;
- s->MediaRateNum >>= 1;
- }
- Format_PrepairStream(&p->Format,&s->Stream);
- continue;
- }
- else
- {
- assert(s->Vorbis);
- // error in second or third header packet will not cause fatal error
- vorbis_synthesis_headerin(&s->Info,&s->Comment,&s->OggPacket);
- if (s->PacketNo == 3)
- {
- // got the three header packets: reinit codec with vorbis_info
- s->Stream.Format.Extra = &s->Info;
- s->Stream.Format.ExtraLength = -1;
- ConnectionUpdate((node*)&p->Format,FORMAT_STREAM+StreamNo,s->Stream.Pin.Node,s->Stream.Pin.No);
- SendComments(s);
- }
- continue;
- }
- }
- s->NeedMorePage = 0;
- break;
- }
- }
- }
- return ERR_NONE;
- }
- static int Process(ogg* p,oggstream* Stream)
- {
- int Result;
- int No;
- int Burst = 1;
- if (Stream->Invalid)
- return ERR_NONE;
- if (Stream->Stream.Pending)
- {
- Result = Format_Send(&p->Format,&Stream->Stream);
- if (Result == ERR_BUFFER_FULL || Result == ERR_SYNCED)
- return Result;
- }
- // process a limited number of packets at once (other streams need cpu time too)
- Result = ERR_NONE;
- Burst = Stream->Stream.PacketBurst;
- for (No=0;No<Burst;++No)
- {
- while (Stream->NeedMorePage)
- {
- Result = FillQueue(p,Stream->Stream.Reader);
- if (Result == ERR_NEED_MORE_DATA && Stream->Stream.Reader->NoMoreInput)
- Result = Format_CheckEof(&p->Format,&Stream->Stream);
- if (Result != ERR_NONE || (p->Format.Bench && Stream->NeedMorePage))
- return Result;
- }
- // sync: only SyncStream is processed
- if (p->Format.SyncMode && Stream != (oggstream*)p->Format.SyncStream)
- return ERR_NEED_MORE_DATA;
- Result = ogg_stream_packetout(Stream->OggStream,&Stream->OggPacket);
- if (Result == 0)
- {
- // stream needs more pages
- Stream->NeedMorePage = 1;
- if (p->Format.Bench) break; // benchmark mode: no additional pages are added in this loop
- --No;
- continue;
- }
- if (Result < 0) // packet hole or span
- continue;
- DEBUG_MSG3(DEBUG_FORMAT,T("OGG Packet id:%d size:%d gran:%d"),Stream->Stream.Id,Stream->OggPacket.bytes,(int)Stream->OggPacket.granulepos);
- if (!Stream->Vorbis && Stream->PacketNo==3)
- {
- // non vorbis: second packet can be a comment (after first header)
- ++Stream->PacketNo;
- if (Stream->Native)
- {
- oggpack_buffer opb;
- oggpack_readinit(&opb,Stream->OggPacket.packet);
- if (_vorbis_unpack_comment(&Stream->Comment,&opb,0)>=0)
- SendComments(Stream);
- continue; // always assume comment packet
- }
- else
- {
- Stream->Info.rate=1;
- if (vorbis_synthesis_headerin(&Stream->Info,&Stream->Comment,&Stream->OggPacket) >= 0)
- {
- SendComments(Stream);
- continue;
- }
- }
- }
- // build output packet
- if (Stream->OggPacket.granulepos >= 0)
- Stream->MediaTime = Stream->OggPacket.granulepos;
- if (Stream->MediaTime >= 0)
- {
- tick_t t = (tick_t)((Stream->MediaTime * Stream->MediaRateDen) / Stream->MediaRateNum);
- t += p->Format.GlobalOffset;
- if (Stream->Stream.Format.Type == PACKET_AUDIO)
- {
- t += p->Format.AVOffset;
- if (t<0) t=0;
- }
- if (Stream->Stream.LastTime>t && t-p->Format.GlobalOffset<TICKSPERSEC)
- Format_TimeStampRestarted(&p->Format,&Stream->Stream,&t);
- Stream->Stream.LastTime = Stream->Stream.Packet.RefTime = t;
- }
- else
- {
- if (Stream->Stream.LastTime < 0)
- continue;
- Stream->Stream.Packet.RefTime = TIME_UNKNOWN;
- }
- if (!Stream->Vorbis)
- {
- ogg_reference* Ref;
- const uint8_t* Data;
- int Length;
- int Len;
- int PacketTime;
- // merge buffers
- if (p->Format.UseBufferBlock)
- {
- for (Length=0,Ref=Stream->OggPacket.packet;Ref;Ref=Ref->next)
- Length += Ref->length;
- if (Stream->Stream.BufferBlockLength<Length && !Format_AllocBufferBlock(&p->Format,&Stream->Stream,Length))
- {
- Length = 0;
- Data = NULL;
- }
- else
- {
- for (Length=0,Ref=Stream->OggPacket.packet;Ref;Ref=Ref->next)
- {
- WriteBlock(&Stream->Stream.BufferBlock,Length,Ref->buffer->data + Ref->begin,Ref->length);
- Length += Ref->length;
- }
- Data = Stream->Stream.BufferBlock.Ptr;
- }
- }
- else
- {
- BufferDrop(&Stream->Stream.BufferMem);
- for (Ref=Stream->OggPacket.packet;Ref;Ref=Ref->next)
- BufferWrite(&Stream->Stream.BufferMem,Ref->buffer->data + Ref->begin, Ref->length, 16384);
- Data = (const uint8_t*)Stream->Stream.BufferMem.Data;
- Length = Stream->Stream.BufferMem.WritePos;
- }
- if (Stream->Native)
- {
- Stream->Stream.Packet.Data[0] = Data;
- Stream->Stream.Packet.Length = Length;
- Stream->MediaTime = -1;
- }
- else
- {
- // process OGM information
- if (*Data & PACKET_TYPE_HEADER)
- continue; // not data packet
- Len = (*Data & PACKET_LEN_BITS01) >> 6;
- Len |= (*Data & PACKET_LEN_BITS2) << 1;
- Stream->Stream.Packet.Key = (*Data & PACKET_IS_SYNCPOINT) != 0;
- Stream->Stream.Packet.Data[0] = Data + 1 + Len;
- Stream->Stream.Packet.Length = Length - 1 - Len;
- if (!Len)
- PacketTime = Stream->DefaultLen;
- else
- for (PacketTime=0;Len;--Len)
- {
- PacketTime <<= 8;
- PacketTime |= Data[Len];
- }
- Stream->MediaTime += PacketTime;
- }
- }
- else
- {
- // send oggpacket directly
- if (!Stream->OggPacket.packet)
- continue;
- Stream->Stream.Packet.Data[0] = &Stream->OggPacket;
- Stream->Stream.Packet.Length = sizeof(Stream->OggPacket);
- Stream->MediaTime = -1;
- }
- Stream->Stream.Pending = 1;
- Result = Format_Send(&p->Format,&Stream->Stream);
- if (Result == ERR_BUFFER_FULL || Result == ERR_SYNCED)
- break;
- if (Stream->Stream.State.DropLevel==2)
- Burst = Stream->Stream.PacketBurst*2; // try to catch up
- }
- // buffer full: there was possibly some processing so don't allow sleeping
- // need data: burst count exceeded, but it doesn't mean there is no data left in buffers
- if (Result == ERR_BUFFER_FULL || Result == ERR_NEED_MORE_DATA)
- Result = ERR_NONE;
- return Result;
- }
- static int Create(ogg* p)
- {
- p->Format.Init = (fmtfunc)Init;
- p->Format.Done = (fmtvoid)Done;
- p->Format.Seek = (fmtseek)Format_SeekByPacket;
- p->Format.FillQueue = (fmtfill)FillQueue;
- p->Format.ReadPacket = (fmtreadpacket)ReadPacketTime;
- p->Format.ReleaseStream = (fmtstream)ReleaseStream;
- p->Format.AfterSeek = (fmtvoid)AfterSeek;
- p->Format.FreeStream = (fmtstream)FreeStream;
- p->Format.Process = (fmtstreamprocess)Process;
- p->Format.DisableReader = 1;
- p->Format.Sended = NULL;
- return ERR_NONE;
- }
- static const nodedef OGG =
- {
- sizeof(ogg),
- OGG_ID,
- FORMATBASE_CLASS,
- PRI_DEFAULT,
- (nodecreate)Create,
- };
- void OGG_Init()
- {
- NodeRegisterClass(&OGG);
- }
- void OGG_Done()
- {
- NodeUnRegisterClass(OGG_ID);
- }