static int read_samples(struct ast_filestream *fs, float ***pcm) { int samples_in; int result; char *buffer; int bytes; struct vorbis_desc *s = (struct vorbis_desc *)fs->_private; while (1) { samples_in = vorbis_synthesis_pcmout(&s->vd, pcm); if (samples_in > 0) { return samples_in; } /* The Vorbis decoder needs more data... */ /* See ifOGG has any packets in the current page for the Vorbis decoder. */ result = ogg_stream_packetout(&s->os, &s->op); if (result > 0) { /* Yes OGG had some more packets for the Vorbis decoder. */ if (vorbis_synthesis(&s->vb, &s->op) == 0) { vorbis_synthesis_blockin(&s->vd, &s->vb); } continue; } if (result < 0) ast_log(LOG_WARNING, "Corrupt or missing data at this page position; continuing...\n"); /* No more packets left in the current page... */ if (s->eos) { /* No more pages left in the stream */ return -1; } while (!s->eos) { /* See ifOGG has any pages in it's internal buffers */ result = ogg_sync_pageout(&s->oy, &s->og); if (result > 0) { /* Yes, OGG has more pages in it's internal buffers, add the page to the stream state */ result = ogg_stream_pagein(&s->os, &s->og); if (result == 0) { /* Yes, got a new,valid page */ if (ogg_page_eos(&s->og)) { s->eos = 1; } break; } ast_log(LOG_WARNING, "Invalid page in the bitstream; continuing...\n"); } if (result < 0) ast_log(LOG_WARNING, "Corrupt or missing data in bitstream; continuing...\n"); /* No, we need to read more data from the file descrptor */ /* get a buffer from OGG to read the data into */ buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); /* read more data from the file descriptor */ bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); /* Tell OGG how many bytes we actually read into the buffer */ ogg_sync_wrote(&s->oy, bytes); if (bytes == 0) { s->eos = 1; } } } }
static int ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE* odata) { char *buffer ; int bytes, nn ; /* Call this here so it only gets called once, so no memory is leaked. */ ogg_sync_init (&odata->osync) ; odata->eos = 0 ; /* Weird stuff happens if these aren't called. */ ogg_stream_reset (&odata->ostream) ; ogg_sync_reset (&odata->osync) ; /* ** Grab some data at the head of the stream. We want the first page ** (which is guaranteed to be small and only contain the Vorbis ** stream initial header) We need the first page to get the stream ** serialno. */ /* Expose the buffer */ buffer = ogg_sync_buffer (&odata->osync, 4096L) ; /* Grab the part of the header that has already been read. */ memcpy (buffer, psf->header, psf->headindex) ; bytes = psf->headindex ; /* Submit a 4k block to libvorbis' Ogg layer */ bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ; ogg_sync_wrote (&odata->osync, bytes) ; /* Get the first page. */ if ((nn = ogg_sync_pageout (&odata->osync, &odata->opage)) != 1) { /* Have we simply run out of data? If so, we're done. */ if (bytes < 4096) return 0 ; /* Error case. Must not be Vorbis data */ psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Get the serial number and set up the rest of decode. ** Serialno first ; use it to set up a logical stream. */ ogg_stream_clear (&odata->ostream) ; ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ; if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0) { /* Error ; stream version mismatch perhaps. */ psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ; return SFE_MALFORMED_FILE ; } ; if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1) { /* No page? must not be vorbis. */ psf_log_printf (psf, "Error reading initial header packet.\n") ; return SFE_MALFORMED_FILE ; } ; odata->codec = ogg_page_classify (psf, &odata->opage) ; switch (odata->codec) { case OGG_VORBIS : psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; return 0 ; case OGG_FLAC : case OGG_FLAC0 : psf->sf.format = SF_FORMAT_OGGFLAC ; return 0 ; case OGG_SPEEX : psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ; return 0 ; case OGG_PCM : psf_log_printf (psf, "Detected Ogg/PCM data. This is not supported yet.\n") ; return SFE_UNIMPLEMENTED ; default : break ; } ; psf_log_printf (psf, "This Ogg bitstream contains some uknown data type.\n") ; return SFE_UNIMPLEMENTED ; } /* ogg_stream_classify */
static int ogg_read_header (SF_PRIVATE *psf, int log_data) { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; char *buffer ; int bytes ; int i, nn ; odata->eos = 0 ; /* Weird stuff happens if these aren't called. */ ogg_stream_reset (&odata->os) ; ogg_sync_reset (&odata->oy) ; /* ** Grab some data at the head of the stream. We want the first page ** (which is guaranteed to be small and only contain the Vorbis ** stream initial header) We need the first page to get the stream ** serialno. */ /* Expose the buffer */ buffer = ogg_sync_buffer (&odata->oy, 4096L) ; /* Grab the part of the header that has already been read. */ memcpy (buffer, psf->header, psf->headindex) ; bytes = psf->headindex ; /* Submit a 4k block to libvorbis' Ogg layer */ bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ; ogg_sync_wrote (&odata->oy, bytes) ; /* Get the first page. */ if ((nn = ogg_sync_pageout (&odata->oy, &odata->og)) != 1) { /* Have we simply run out of data? If so, we're done. */ if (bytes < 4096) return 0 ; /* Error case. Must not be Vorbis data */ psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Get the serial number and set up the rest of decode. ** Serialno first ; use it to set up a logical stream. */ ogg_stream_clear (&odata->os) ; ogg_stream_init (&odata->os, ogg_page_serialno (&odata->og)) ; /* ** This function (ogg_read_header) gets called multiple times, so the OGG ** and vorbis structs have to be cleared every time we pass through to ** prevent memory leaks. */ vorbis_block_clear (&vdata->vb) ; vorbis_dsp_clear (&vdata->vd) ; vorbis_comment_clear (&vdata->vc) ; vorbis_info_clear (&vdata->vi) ; /* ** Extract the initial header from the first page and verify that the ** Ogg bitstream is in fact Vorbis data. ** ** I handle the initial header first instead of just having the code ** read all three Vorbis headers at once because reading the initial ** header is an easy way to identify a Vorbis bitstream and it's ** useful to see that functionality seperated out. */ vorbis_info_init (&vdata->vi) ; vorbis_comment_init (&vdata->vc) ; if (ogg_stream_pagein (&odata->os, &odata->og) < 0) { /* Error ; stream version mismatch perhaps. */ psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ; return SFE_MALFORMED_FILE ; } ; if (ogg_stream_packetout (&odata->os, &odata->op) != 1) { /* No page? must not be vorbis. */ psf_log_printf (psf, "Error reading initial header packet.\n") ; return SFE_MALFORMED_FILE ; } ; if (vorbis_synthesis_headerin (&vdata->vi, &vdata->vc, &odata->op) < 0) { /* Error case ; not a vorbis header. */ psf_log_printf (psf, "This Ogg bitstream does not contain Vorbis audio data.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Common Ogg metadata fields? ** TITLE, VERSION, ALBUM, TRACKNUMBER, ARTIST, PERFORMER, COPYRIGHT, LICENSE, ** ORGANIZATION, DESCRIPTION, GENRE, DATE, LOCATION, CONTACT, ISRC, */ if (log_data) { int k ; for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) { char *dd ; dd = vorbis_comment_query (&vdata->vc, vorbis_metatypes [k].name, 0) ; if (dd == NULL) continue ; psf_store_string (psf, vorbis_metatypes [k].id, dd) ; } ; } ; /* ** At this point, we're sure we're Vorbis. We've set up the logical (Ogg) ** bitstream decoder. Get the comment and codebook headers and set up the ** Vorbis decoder. ** ** The next two packets in order are the comment and codebook headers. ** They're likely large and may span multiple pages. Thus we reead ** and submit data until we get our two pacakets, watching that no ** pages are missing. If a page is missing, error out ; losing a ** header page is the only place where missing data is fatal. */ i = 0 ; /* Count of number of packets read */ while (i < 2) { int result = ogg_sync_pageout (&odata->oy, &odata->og) ; if (result == 0) { /* Need more data */ buffer = ogg_sync_buffer (&odata->oy, 4096) ; bytes = psf_fread (buffer, 1, 4096, psf) ; if (bytes == 0 && i < 2) { psf_log_printf (psf, "End of file before finding all Vorbis headers!\n") ; return SFE_MALFORMED_FILE ; } ; nn = ogg_sync_wrote (&odata->oy, bytes) ; } else if (result == 1) { /* ** Don't complain about missing or corrupt data yet. We'll ** catch it at the packet output phase. ** ** We can ignore any errors here as they'll also become apparent ** at packetout. */ nn = ogg_stream_pagein (&odata->os, &odata->og) ; while (i < 2) { result = ogg_stream_packetout (&odata->os, &odata->op) ; if (result == 0) break ; if (result < 0) { /* Uh oh ; data at some point was corrupted or missing! ** We can't tolerate that in a header. Die. */ psf_log_printf (psf, "Corrupt secondary header. Exiting.\n") ; return SFE_MALFORMED_FILE ; } ; vorbis_synthesis_headerin (&vdata->vi, &vdata->vc, &odata->op) ; i++ ; } ; } ; } ; if (log_data) { int printed_metadata_msg = 0 ; int k ; psf_log_printf (psf, "\nBitstream is %d channel, %D Hz\n", vdata->vi.channels, vdata->vi.rate) ; psf_log_printf (psf, "Encoded by: %s\n", vdata->vc.vendor) ; /* Throw the comments plus a few lines about the bitstream we're decoding. */ for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) { char *dd ; dd = vorbis_comment_query (&vdata->vc, vorbis_metatypes [k].name, 0) ; if (dd == NULL) continue ; if (printed_metadata_msg == 0) { psf_log_printf (psf, "Metadata :\n") ; printed_metadata_msg = 1 ; } ; psf_store_string (psf, vorbis_metatypes [k].id, dd) ; psf_log_printf (psf, " %-10s : %s\n", vorbis_metatypes [k].name, dd) ; } ; psf_log_printf (psf, "End\n") ; } ; psf->sf.samplerate = vdata->vi.rate ; psf->sf.channels = vdata->vi.channels ; psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; /* OK, got and parsed all three headers. Initialize the Vorbis ** packet->PCM decoder. ** Central decode state. */ vorbis_synthesis_init (&vdata->vd, &vdata->vi) ; /* Local state for most of the decode so multiple block decodes can ** proceed in parallel. We could init multiple vorbis_block structures ** for vd here. */ vorbis_block_init (&vdata->vd, &vdata->vb) ; vdata->loc = 0 ; return 0 ; } /* ogg_read_header */
// the main page reading hook (stream friendly) ssize_t OggReader::ReadPage(bool first_page) { // TRACE("OggReader::ReadPage\n"); int read_size = (first_page ? 4096 : 4*B_PAGE_SIZE); BAutolock autolock(fSyncLock); ogg_page page; retry: int result = ogg_sync_pageout(&fSync, &page); // first read leftovers while (result == 0) { char * buffer = ogg_sync_buffer(&fSync, read_size); ssize_t bytes = Source()->Read(buffer, read_size); if (bytes == 0) { TRACE("OggReader::GetPage: Read: no data\n"); return B_LAST_BUFFER_ERROR; } if (bytes < 0) { TRACE("OggReader::GetPage: Read: error\n"); return bytes; } if (ogg_sync_wrote(&fSync, bytes) != 0) { TRACE("OggReader::GetPage: ogg_sync_wrote failed?: error\n"); return B_ERROR; } result = ogg_sync_pageout(&fSync, &page); if (first_page && (result != 1)) { TRACE("OggReader::GetPage: short first page not found: error\n"); return B_ERROR; } } if (result == -1) { TRACE("OggReader::GetPage: ogg_sync_pageout: not synced: error\n"); return B_ERROR; } if (ogg_page_version(&page) != 0) { TRACE("OggReader::GetPage: ogg_page_version: error in page encoding: error\n"); return B_ERROR; } long serialno = ogg_page_serialno(&page); bool new_serialno = fTracks.find(serialno) == fTracks.end(); if (new_serialno) { // this is an unknown serialno if (ogg_page_bos(&page) == 0) { TRACE("OggReader::GetPage: non-bos page with unknown serialno\n"); #ifdef STRICT_OGG return B_ERROR; #else // silently discard non-bos packets with unknown serialno goto retry; #endif } #ifdef STRICT_OGG if (ogg_page_continued(&page) != 0) { TRACE("oggReader::GetPage: ogg_page_continued: continued page: not ogg\n"); return B_ERROR; } #endif //STRICT_OGG // this is a beginning of stream page ogg_stream_state stream; if (ogg_stream_init(&stream, serialno) != 0) { TRACE("oggReader::GetPage: ogg_stream_init failed?: error\n"); return B_ERROR; } if (ogg_stream_pagein(&stream, &page) != 0) { TRACE("oggReader::GetPage: ogg_stream_pagein: failed: error\n"); return B_ERROR; } ogg_packet packet; if (ogg_stream_packetout(&stream, &packet) != 1) { #ifdef STRICT_OGG return B_ERROR; #endif //STRICT_OGG } if (fSeekable) { fTracks[serialno] = OggSeekable::makeOggSeekable(fSeekable, &fSeekableLock, serialno, packet); } else { class Interface : public StreamInterface { private: OggReader * reader; public: Interface(OggReader * reader) { this->reader = reader; } virtual ssize_t ReadPage() { return reader->ReadPage(); } }; fTracks[serialno] = OggStream::makeOggStream(new Interface(this), serialno, packet); } fCookies.push_back(serialno); } // this check ensures that we only push the initial pages into OggSeekables. if (!fSeekable || new_serialno) { status_t status = fTracks[serialno]->AddPage(fPosition, page); if (status != B_OK) { return status; } fPosition += page.header_len + page.body_len; } return page.header_len + page.body_len; }
int main(){ ogg_sync_state oy; /* sync and verify incoming physical bitstream */ ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the bitstream user comments */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_block vb; /* local working space for packet->PCM decode */ char *buffer; int bytes; #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */ /* Beware the evil ifdef. We avoid these where we can, but this one we cannot. Don't add any more, you'll probably go to hell if you do. */ _setmode( _fileno( stdin ), _O_BINARY ); _setmode( _fileno( stdout ), _O_BINARY ); #endif #if defined(macintosh) && defined(__MWERKS__) { int argc; char **argv; argc=ccommand(&argv); /* get a "command line" from the Mac user */ /* this also lets the user set stdin and stdout */ } #endif /********** Decode setup ************/ ogg_sync_init(&oy); /* Now we can read pages */ while(1){ /* we repeat if the bitstream is chained */ int eos=0; int i; /* grab some data at the head of the stream. We want the first page (which is guaranteed to be small and only contain the Vorbis stream initial header) We need the first page to get the stream serialno. */ FILE * pFile = NULL; pFile = fopen( "D:\\data\\tree.mine\\libvorbis-1.2.0\\win32\\Debug\\Epoq-Lepidoptera.ogg", "rb" ); /* submit a 4k block to libvorbis' Ogg layer */ buffer=ogg_sync_buffer(&oy,4096); bytes=fread(buffer,1,4096,pFile); ogg_sync_wrote(&oy,bytes); /* Get the first page. */ if(ogg_sync_pageout(&oy,&og)!=1){ /* have we simply run out of data? If so, we're done. */ if(bytes<4096)break; /* error case. Must not be Vorbis data */ fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n"); exit(1); } /* Get the serial number and set up the rest of decode. */ /* serialno first; use it to set up a logical stream */ ogg_stream_init(&os,ogg_page_serialno(&og)); /* extract the initial header from the first page and verify that the Ogg bitstream is in fact Vorbis data */ /* I handle the initial header first instead of just having the code read all three Vorbis headers at once because reading the initial header is an easy way to identify a Vorbis bitstream and it's useful to see that functionality seperated out. */ vorbis_info_init(&vi); vorbis_comment_init(&vc); if(ogg_stream_pagein(&os,&og)<0){ /* error; stream version mismatch perhaps */ fprintf(stderr,"Error reading first page of Ogg bitstream data.\n"); exit(1); } if(ogg_stream_packetout(&os,&op)!=1){ /* no page? must not be vorbis */ fprintf(stderr,"Error reading initial header packet.\n"); exit(1); } if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ /* error case; not a vorbis header */ fprintf(stderr,"This Ogg bitstream does not contain Vorbis " "audio data.\n"); exit(1); } /* At this point, we're sure we're Vorbis. We've set up the logical (Ogg) bitstream decoder. Get the comment and codebook headers and set up the Vorbis decoder */ /* The next two packets in order are the comment and codebook headers. They're likely large and may span multiple pages. Thus we reead and submit data until we get our two pacakets, watching that no pages are missing. If a page is missing, error out; losing a header page is the only place where missing data is fatal. */ i=0; while(i<2) { while(i<2) { int result=ogg_sync_pageout(&oy,&og); if(result==0) break; /* Need more data */ /* Don't complain about missing or corrupt data yet. We'll catch it at the packet output phase */ if(result==1) { ogg_stream_pagein(&os,&og); /* we can ignore any errors here as they'll also become apparent at packetout */ while(i<2) { result=ogg_stream_packetout(&os,&op); if(result==0)break; if(result<0) { /* Uh oh; data at some point was corrupted or missing! We can't tolerate that in a header. Die. */ fprintf(stderr,"Corrupt secondary header. Exiting.\n"); exit(1); } vorbis_synthesis_headerin(&vi,&vc,&op); i++; } } } /* no harm in not checking before adding more */ buffer=ogg_sync_buffer(&oy,4096); bytes=fread(buffer,1,4096,pFile); if(bytes==0 && i<2) { fprintf(stderr,"End of file before finding all Vorbis headers!\n"); exit(1); } ogg_sync_wrote(&oy,bytes); } /* Throw the comments plus a few lines about the bitstream we're decoding */ { char **ptr=vc.user_comments; while(*ptr) { fprintf(stderr,"%s\n",*ptr); ++ptr; } fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate); fprintf(stderr,"Encoded by: %s\n\n",vc.vendor); } convsize=4096/vi.channels; /* OK, got and parsed all three headers. Initialize the Vorbis packet->PCM decoder. */ vorbis_synthesis_init(&vd,&vi); /* central decode state */ vorbis_block_init(&vd,&vb); /* local state for most of the decode so multiple block decodes can proceed in parallel. We could init multiple vorbis_block structures for vd here */ /* The rest is just a straight decode loop until end of stream */ while(!eos) { while(!eos) { int result=ogg_sync_pageout(&oy,&og); if(result==0)break; /* need more data */ if(result<0) { /* missing or corrupt data at this page position */ fprintf(stderr,"Corrupt or missing data in bitstream; " "continuing...\n"); }else { ogg_stream_pagein(&os,&og); /* can safely ignore errors at this point */ while(1) { result=ogg_stream_packetout(&os,&op); if(result==0)break; /* need more data */ if(result<0){ /* missing or corrupt data at this page position */ /* no reason to complain; already complained above */ }else { /* we have a packet. Decode it */ float **pcm; int samples; if(vorbis_synthesis(&vb,&op)==0) /* test for success! */ vorbis_synthesis_blockin(&vd,&vb); /* **pcm is a multichannel float vector. In stereo, for example, pcm[0] is left, and pcm[1] is right. samples is the size of each channel. Convert the float values (-1.<=range<=1.) to whatever PCM format and write it out */ while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0) { int j; int clipflag=0; int bout=(samples<convsize?samples:convsize); /* convert floats to 16 bit signed ints (host order) and interleave */ for(i=0;i<vi.channels;i++) { ogg_int16_t *ptr=convbuffer+i; float *mono=pcm[i]; for(j=0;j<bout;j++) { #if 1 int val=mono[j]*32767.f; #else /* optional dither */ int val=mono[j]*32767.f+drand48()-0.5f; #endif /* might as well guard against clipping */ if(val>32767) { val=32767; clipflag=1; } if(val<-32768) { val=-32768; clipflag=1; } *ptr=val; ptr+=vi.channels; } } if(clipflag) fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence)); fwrite(convbuffer,2*vi.channels,bout,stdout); vorbis_synthesis_read(&vd,bout); /* tell libvorbis how many samples we actually consumed */ } } } if(ogg_page_eos(&og)) eos=1; } } if(!eos) { buffer=ogg_sync_buffer(&oy,4096); bytes=fread(buffer,1,4096,pFile); ogg_sync_wrote(&oy,bytes); if(bytes==0) eos=1; } } /* clean up this logical bitstream; before exit we see if we're followed by another [chained] */ ogg_stream_clear(&os); /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); /* must be called last */ } /* OK, clean up the framer */ ogg_sync_clear(&oy); fprintf(stderr,"Done.\n"); return(0); }
void test_pack(const int *pl, const int **headers){ unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ long inptr=0; long outptr=0; long deptr=0; long depacket=0; long granule_pos=7,pageno=0; int i,j,packets,pageout=0; int eosflag=0; int bosflag=0; ogg_stream_reset(&os_en); ogg_stream_reset(&os_de); ogg_sync_reset(&oy); for(packets=0;;packets++)if(pl[packets]==-1)break; for(i=0;i<packets;i++){ /* construct a test packet */ ogg_packet op; int len=pl[i]; op.packet=data+inptr; op.bytes=len; op.e_o_s=(pl[i+1]<0?1:0); op.granulepos=granule_pos; granule_pos+=1024; for(j=0;j<len;j++)data[inptr++]=i+j; /* submit the test packet */ ogg_stream_packetin(&os_en,&op); /* retrieve any finished pages */ { ogg_page og; while(ogg_stream_pageout(&os_en,&og)){ /* We have a page. Check it carefully */ fprintf(stderr,"%ld, ",pageno); if(headers[pageno]==NULL){ fprintf(stderr,"coded too many pages!\n"); exit(1); } check_page(data+outptr,headers[pageno],&og); outptr+=og.body_len; pageno++; /* have a complete page; submit it to sync/decode */ { ogg_page og_de; ogg_packet op_de,op_de2; char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len); memcpy(buf,og.header,og.header_len); memcpy(buf+og.header_len,og.body,og.body_len); ogg_sync_wrote(&oy,og.header_len+og.body_len); while(ogg_sync_pageout(&oy,&og_de)>0){ /* got a page. Happy happy. Verify that it's good. */ check_page(data+deptr,headers[pageout],&og_de); deptr+=og_de.body_len; pageout++; /* submit it to deconstitution */ ogg_stream_pagein(&os_de,&og_de); /* packets out? */ while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ ogg_stream_packetpeek(&os_de,NULL); ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ /* verify peek and out match */ if(memcmp(&op_de,&op_de2,sizeof(ogg_packet))){ fprintf(stderr,"packetout != packetpeek! pos=%ld\n", depacket); exit(1); } /* verify the packet! */ /* check data */ if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", depacket); exit(1); } /* check bos flag */ if(bosflag==0 && op_de.b_o_s==0){ fprintf(stderr,"b_o_s flag not set on packet!\n"); exit(1); } if(bosflag && op_de.b_o_s){ fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); exit(1); } bosflag=1; depacket+=op_de.bytes; /* check eos flag */ if(eosflag){ fprintf(stderr,"Multiple decoded packets with eos flag!\n"); exit(1); } if(op_de.e_o_s)eosflag=1; /* check granulepos flag */ if(op_de.granulepos!=-1){ fprintf(stderr," granule:%ld ",(long)op_de.granulepos); } } } } } } } _ogg_free(data); if(headers[pageno]!=NULL){ fprintf(stderr,"did not write last page!\n"); exit(1); } if(headers[pageout]!=NULL){ fprintf(stderr,"did not decode last page!\n"); exit(1); } if(inptr!=outptr){ fprintf(stderr,"encoded page data incomplete!\n"); exit(1); } if(inptr!=deptr){ fprintf(stderr,"decoded page data incomplete!\n"); exit(1); } if(inptr!=depacket){ fprintf(stderr,"decoded packet data incomplete!\n"); exit(1); } if(!eosflag){ fprintf(stderr,"Never got a packet with EOS set!\n"); exit(1); } fprintf(stderr,"ok.\n"); }
FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data) { static const size_t OGG_BYTES_CHUNK = 8192; const size_t bytes_requested = *bytes; /* * The FLAC decoding API uses pull-based reads, whereas Ogg decoding * is push-based. In libFLAC, when you ask to decode a frame, the * decoder will eventually call the read callback to supply some data, * but how much it asks for depends on how much free space it has in * its internal buffer. It does not try to grow its internal buffer * to accomodate a whole frame because then the internal buffer size * could not be limited, which is necessary in embedded applications. * * Ogg however grows its internal buffer until a whole page is present; * only then can you get decoded data out. So we can't just ask for * the same number of bytes from Ogg, then pass what's decoded down to * libFLAC. If what libFLAC is asking for will not contain a whole * page, then we will get no data from ogg_sync_pageout(), and at the * same time cannot just read more data from the client for the purpose * of getting a whole decoded page because the decoded size might be * larger than libFLAC's internal buffer. * * Instead, whenever this read callback wrapper is called, we will * continually request data from the client until we have at least one * page, and manage pages internally so that we can send pieces of * pages down to libFLAC in such a way that we obey its size * requirement. To limit the amount of callbacks, we will always try * to read in enough pages to return the full number of bytes * requested. */ *bytes = 0; while (*bytes < bytes_requested && !aspect->end_of_stream) { if (aspect->have_working_page) { if (aspect->have_working_packet) { size_t n = bytes_requested - *bytes; if ((size_t)aspect->working_packet.bytes <= n) { /* the rest of the packet will fit in the buffer */ n = aspect->working_packet.bytes; memcpy(buffer, aspect->working_packet.packet, n); *bytes += n; buffer += n; aspect->have_working_packet = false; } else { /* only n bytes of the packet will fit in the buffer */ memcpy(buffer, aspect->working_packet.packet, n); *bytes += n; buffer += n; aspect->working_packet.packet += n; aspect->working_packet.bytes -= n; } } else { /* try and get another packet */ const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet); if (ret > 0) { aspect->have_working_packet = true; /* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */ if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) { const FLAC__byte *b = aspect->working_packet.packet; const unsigned header_length = FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH + FLAC__OGG_MAPPING_MAGIC_LENGTH + FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH + FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH + FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH; if (aspect->working_packet.bytes < (long)header_length) return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC; b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH; if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH)) return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC; b += FLAC__OGG_MAPPING_MAGIC_LENGTH; aspect->version_major = (unsigned)(*b); b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH; aspect->version_minor = (unsigned)(*b); if (aspect->version_major != 1) return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION; aspect->working_packet.packet += header_length; aspect->working_packet.bytes -= header_length; } } else if (ret == 0) { aspect->have_working_page = false; } else { /* ret < 0 */ /* lost sync, we'll leave the working page for the next call */ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC; } } } else { /* try and get another page */ const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page); if (ret > 0) { /* got a page, grab the serial number if necessary */ if(aspect->need_serial_number) { aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page); aspect->need_serial_number = false; } if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) { aspect->have_working_page = true; aspect->have_working_packet = false; } /* else do nothing, could be a page from another stream */ } else if (ret == 0) { /* need more data */ const size_t ogg_bytes_to_read = max(bytes_requested - *bytes, OGG_BYTES_CHUNK); char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read); if(0 == oggbuf) { return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR; } else { size_t ogg_bytes_read = ogg_bytes_to_read; switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) { case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK: break; case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM: aspect->end_of_stream = true; break; case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT: return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; default: FLAC__ASSERT(0); } if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) { /* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */ FLAC__ASSERT(0); return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR; } } } else { /* ret < 0 */ /* lost sync, bail out */ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC; } } } if (aspect->end_of_stream && *bytes == 0) { return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM; } return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK; }
static int ReadHeader(OGG_context *ctx, SYS_FILEHANDLE file) { const size_t size = 4096; int theError; void *buffer; int i, serialNo; size_t bytes = 0; ogg_sync_init(&ctx->oy); /* Now we can read pages */ /* submit a 4k block to libvorbis' Ogg layer */ if (!ctx->eos) { buffer = ogg_sync_buffer(&ctx->oy, (int32_t)size); bytes = FIO_cur->fread(buffer, 1 , size, file); ogg_sync_wrote(&ctx->oy, (int32_t)size); } /* Get the first page. */ theError = ogg_sync_pageout(&ctx->oy, &ctx->og); SYS_ASSERT(theError == 1); if (theError!=1) { /* error case. Must not be Vorbis data */ SYS_ASSERT(bytes<size); return 0; } /* Get the serial number and set up the rest of decode. */ /* serialno first; use it to set up a logical stream */ serialNo = ogg_page_serialno(&ctx->og); theError = ogg_stream_init(&ctx->os, serialNo); SYS_ASSERT(theError==0); /* extract the initial header from the first page and verify that the Ogg bitstream is in fact Vorbis data */ /* I handle the initial header first instead of just having the code read all three Vorbis headers at once because reading the initial header is an easy way to identify a Vorbis bitstream and it's useful to see that functionality seperated out. */ theError = ogg_stream_pagein(&ctx->os, &ctx->og); SYS_ASSERT(theError>=0); if (theError < 0) { /* error; stream version mismatch perhaps */ return 0; } theError = ogg_stream_packetout(&ctx->os, &ctx->op); SYS_ASSERT(theError == 1); if (theError!=1) { /* no page? must not be vorbis */ return 0; } theError = vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &ctx->op); SYS_ASSERT(theError >=0); if (theError < 0) { return 0; } /* At this point, we're sure we're Vorbis. We've set up the logical (Ogg) bitstream decoder. Get the comment and codebook headers and set up the Vorbis decoder */ /* The next two packets in order are the comment and codebook headers. They're likely large and may span multiple pages. Thus we reead and submit data until we get our two pacakets, watching that no pages are missing. If a page is missing, error out; losing a header page is the only place where missing data is fatal. */ i=0; while(i<2) { while(i<2) { int result = ogg_sync_pageout(&ctx->oy, &ctx->og); if (result==0) break; /* Need more data */ /* Don't complain about missing or corrupt data yet. We'll catch it at the packet output phase */ if(result==1) { ogg_stream_pagein(&ctx->os, &ctx->og); /* we can ignore any errors here as they'll also become apparent at packetout */ while(i<2) { result = ogg_stream_packetout(&ctx->os, &ctx->op); if (result==0) break; if (result<0) { /* Uh oh; data at some point was corrupted or missing! We can't tolerate that in a header. Die. */ SYS_ASSERT(0); return 0; } vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &ctx->op); i++; } } } buffer = ogg_sync_buffer(&ctx->oy, (int32_t)size); bytes = FIO_cur->fread(buffer, 1 , size, file); SYS_ASSERT(!(bytes==0 && i<2)); ogg_sync_wrote(&ctx->oy,(int32_t) size); } /* OK, got and parsed all three headers. Initialize the Vorbis packet->PCM decoder. */ vorbis_synthesis_init(&ctx->vd, &ctx->vi); /* central decode state */ vorbis_block_init(&ctx->vd, &ctx->vb); /* local state for most of the decode so multiple block decodes can proceed in parallel. We could init multiple vorbis_block structures for vd here */ ctx->input_size = size; ctx->state = 0; return 1; }
static int play_vorbis(lua_State *lstate) { char buf[BLOCKSIZE]; char *pt, *oggbuf, **comm, *mark; int n, sock, sr_err, port; const char *host, *mount; VORBIS_FEED *feed; lua_pushstring(lstate, "host"); lua_gettable(lstate, -2); lua_pushstring(lstate, "port"); lua_gettable(lstate, -3); lua_pushstring(lstate, "mount"); lua_gettable(lstate, -4); mount = lua_tostring(lstate, -1); port = lua_tointeger(lstate, -2); host = lua_tostring(lstate, -3); sock = stream_connect(host, port, mount, buf, &mark); lua_pop(lstate, 3); if (sock == 0) { lua_pop(lstate, 1); return 0; } lua_pushstring(lstate, "intern"); lua_gettable(lstate, -2); feed = (VORBIS_FEED *)lua_touserdata(lstate, -1); lua_pop(lstate, 1); feed->base.sock = sock; pthread_mutex_init(&(feed->base.thread_lock), NULL); pthread_cond_init(&(feed->base.data_ready), NULL); ogg_sync_init(&(feed->oy)); oggbuf = ogg_sync_buffer(&(feed->oy), BLOCKSIZE); n = BLOCKSIZE - (mark - buf); memcpy(oggbuf, mark, n); read_sock(feed->base.sock, oggbuf + n, BLOCKSIZE - n); ogg_sync_wrote(&(feed->oy), BLOCKSIZE); if ((n = ogg_sync_pageout(&(feed->oy), &(feed->og))) != 1) { logmsg("out of data: %d\n", n); free_vorbis((FEED *)feed); lua_pop(lstate, 1); return 0; } ogg_stream_init(&(feed->os), ogg_page_serialno(&(feed->og))); vorbis_info_init(&(feed->vi)); vorbis_comment_init(&(feed->vc)); if (ogg_stream_pagein(&(feed->os), &(feed->og)) < 1) { logmsg("error reading first ogg page\n"); //free_feed(feed); //return 0; } if (ogg_stream_packetout(&(feed->os), &(feed->op)) != 1) { logmsg("error reading first header packet\n"); free_vorbis((FEED *)feed); lua_pop(lstate, 1); return 0; } if (vorbis_synthesis_headerin(&(feed->vi), &(feed->vc), &(feed->op)) < 0) { logmsg("stream is not vorbis\n"); free_vorbis((FEED *)feed); lua_pop(lstate, 1); return 0; } vorbis_headers(feed); add_table(lstate, "info"); add_table(lstate, "comments"); comm = feed->vc.user_comments; while (*comm) { if ((pt = index(*comm, '=')) != NULL) { *pt++ = '\0'; set_string(lstate, *comm, pt); } ++comm; } lua_pop(lstate, 1); // comments feed->base.channels = feed->vi.channels; set_integer(lstate, "channels", feed->base.channels); set_integer(lstate, "srate", feed->vi.rate); lua_pop(lstate, 1); // info feed->base.cbuf = new_ringbuf(feed->vi.rate, feed->base.channels, BUFSECS, 0.333, 0.667); if (jack_sr != feed->vi.rate) { feed->base.converter = src_new(SRC_SINC_MEDIUM_QUALITY, feed->base.channels, &sr_err); feed->base.src_data_in = (float *)malloc(SRC_DATA_FRAMES * feed->base.channels * sizeof(float)); feed->base.src_data.data_in = feed->base.src_data_in; feed->base.src_data_remain = 0; feed->base.src_data.src_ratio = jack_sr / (double)feed->vi.rate; feed->base.src_data_out = (float *)malloc( (int)ceil(SRC_DATA_FRAMES * feed->base.channels * sizeof(float) * feed->base.src_data.src_ratio)); } feed->base.init = 1; lua_pop(lstate, 1); pthread_create(&(feed->base.thread_id), NULL, vorbis_thread, feed); return 0; }
static gboolean xmms_speex_init (xmms_xform_t *xform) { gint pe; xmms_config_property_t *val; xmms_speex_data_t *data; xmms_error_t error; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_speex_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); ogg_sync_init (&data->sync_state); speex_bits_init (&data->speex_bits); /* Find the speex header */ while (42) { gint ret; data->ogg_data = ogg_sync_buffer (&data->sync_state, 1024); ret = xmms_xform_read (xform, data->ogg_data, 1024, &error); ogg_sync_wrote (&data->sync_state, ret); if (ret <= 0) { return FALSE; } if (ogg_sync_pageout (&data->sync_state, &data->ogg_page) == 1) { break; } } ogg_stream_init (&data->stream_state, ogg_page_serialno (&data->ogg_page)); if (ogg_stream_pagein (&data->stream_state, &data->ogg_page) < 0) { return FALSE; } if (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) != 1) { return FALSE; } data->speexheader = speex_packet_to_header ((char *)data->ogg_packet.packet, data->ogg_packet.bytes); data->speex_state = speex_decoder_init (speex_mode_list[data->speexheader->mode]); val = xmms_xform_config_lookup (xform, "perceptual_enhancer"); pe = xmms_config_property_get_int (val); speex_decoder_ctl (data->speex_state, SPEEX_SET_ENH, &pe); ogg_sync_pageout (&data->sync_state, &data->ogg_page); ogg_stream_pagein (&data->stream_state, &data->ogg_page); ogg_stream_packetout (&data->stream_state, &data->ogg_packet); data->samples_buf = g_new (gint16, data->speexheader->frames_per_packet * data->speexheader->frame_size * data->speexheader->nb_channels); data->samples_start = data->samples_buf; data->samples_count = 0; xmms_speex_read_metadata (xform, data); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->speexheader->nb_channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->speexheader->rate, XMMS_STREAM_TYPE_END); return TRUE; }
// Decode static int Decode(void *context, const void *dataRAW, size_t sizeRAW, void **ppdataPCM, size_t *sizePCM) { OGG_context *ctx = (OGG_context*)context; *sizePCM = 0; *ppdataPCM = 0; if (!dataRAW) return 0; switch(ctx->state) { // Sync buffer case 0xff: { sysMemCpy(ogg_sync_buffer(&ctx->oy, (int32_t)sizeRAW), dataRAW, sizeRAW); ctx->input_size = sizeRAW; ogg_sync_wrote(&ctx->oy, (int32_t)ctx->input_size); ctx->state = 0; } break; // Sync page out case 0: { int result = ogg_sync_pageout(&ctx->oy, &ctx->og); if (result == 0) { ctx->state = 0xff; } else if (result < 0) { ctx->state = -1; } else { ogg_stream_pagein(&ctx->os, &ctx->og); /* can safely ignore errors at this point */ ctx->state = 1; } } break; // Stream packet out case 1: { int result = ogg_stream_packetout(&ctx->os, &ctx->op); if (result == 0) { ctx->state = 0; } else if (result < 0) { ctx->state = -2; } else { /* we have a packet. Decode it */ if (vorbis_synthesis(&ctx->vb, &ctx->op)==0) /* test for success! */ vorbis_synthesis_blockin(&ctx->vd, &ctx->vb); ctx->state = 3; } } break; // synthetis pcm out case 3: { size_t samples; float **pcm; samples = vorbis_synthesis_pcmout(&ctx->vd, &pcm); if (samples<=0) { ctx->state = 1; } else { size_t convsize = ctx->input_size / ctx->vi.channels; size_t bytesCount = samples < convsize ? samples : convsize; SYS_ASSERT(bytesCount < OGG_BUFFER_SIZE); #ifdef SUPPORT_IEEE_AUDIO DeinterleaveAudio(ctx->uncompressed, pcm, ctx->vi.channels, bytesCount); *sizePCM = 4 * ctx->vi.channels * bytesCount; #else ConvertFloatToInteger(ctx->uncompressed, pcm, ctx->vi.channels, bytesCount); *sizePCM = 2 * ctx->vi.channels * bytesCount; #endif /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read(&ctx->vd, (int32_t)bytesCount); *ppdataPCM = ctx->uncompressed; } } break; // Invalid state default: SYS_ASSERT(0); return -1; break; } return ctx->state != 0xff ? 1 : 0; }
static gint xmms_speex_read (xmms_xform_t *xform, gpointer buf, gint len, xmms_error_t *err) { gint ret = 0, n; gfloat outfloat [2000]; gint16 *outbuf = (gint16 *) buf; xmms_speex_data_t *data; xmms_error_t error; SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); /* convert from bytes to samples */ len /= 2; /* first, copy already decoded samples over if we have any. */ if (data->samples_count) { n = MIN (data->samples_count, len); memcpy (outbuf, data->samples_start, n * 2); data->samples_count -= n; if (!data->samples_count) { data->samples_start = data->samples_buf; } else { data->samples_start += n; } /* convert from samples to bytes */ return n * 2; } while (42) { gint samples_per_frame; samples_per_frame = data->speexheader->frame_size * data->speexheader->nb_channels; while (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) == 1) { gint frame; speex_bits_read_from (&data->speex_bits, (char *)data->ogg_packet.packet, data->ogg_packet.bytes); for (frame = 0; frame < data->speexheader->frames_per_packet; frame++) { gint cnt; speex_decode (data->speex_state, &data->speex_bits, outfloat); if (data->speexheader->nb_channels == 2) { speex_decode_stereo (outfloat, data->speexheader->frame_size,&stereo); } n = MIN (samples_per_frame, len); /* copy as many samples to the output buffer as * possible. */ for (cnt = 0; cnt < n; cnt++) { *outbuf++ = outfloat[cnt]; len--; ret += 2; } /* store the remaining samples for later use */ for (; cnt < samples_per_frame; cnt++) { data->samples_buf[data->samples_count++] = outfloat[cnt]; } } return ret; } /* Need more data */ do { gint ret; data->ogg_data = ogg_sync_buffer (&data->sync_state, 200); ret = xmms_xform_read (xform, data->ogg_data, 200, &error); ogg_sync_wrote (&data->sync_state, ret); if (ret <= 0) { return ret; } } while (ogg_sync_pageout (&data->sync_state, &data->ogg_page) != 1); ogg_stream_pagein (&data->stream_state, &data->ogg_page); } }
/** central buffer management function * @param openmaxStandComp the component handle * @param inputbuffer contains the input ogg file content * @param outputbuffer is returned along with its output pcm file content that is produced as a result of this function execution */ void omx_vorbisdec_component_BufferMgmtCallbackVorbis(OMX_COMPONENTTYPE *openmaxStandComp, OMX_BUFFERHEADERTYPE* inputbuffer, OMX_BUFFERHEADERTYPE* outputbuffer) { omx_vorbisdec_component_PrivateType* omx_vorbisdec_component_Private = openmaxStandComp->pComponentPrivate; OMX_U8* outputCurrBuffer; OMX_U32 outputLength; OMX_S32 result; float **pcm; OMX_S32 samples; OMX_S32 i, j; OMX_S32 bout; OMX_S32 clipflag=0; int val; float *mono; int eos=0; char *vorbis_buffer; ogg_int16_t convbuffer[4096]; DEBUG(DEB_LEV_FULL_SEQ, "input buf %x filled len : %d \n", (int)inputbuffer->pBuffer, (int)inputbuffer->nFilledLen); /** Fill up the current input buffer when a new buffer has arrived */ if(omx_vorbisdec_component_Private->isNewBuffer) { omx_vorbisdec_component_Private->inputCurrBuffer = inputbuffer->pBuffer; omx_vorbisdec_component_Private->inputCurrLength = inputbuffer->nFilledLen; omx_vorbisdec_component_Private->positionInOutBuf = 0; DEBUG(DEB_LEV_SIMPLE_SEQ, "new -- input buf %x filled len : %d \n", (int)inputbuffer->pBuffer, (int)inputbuffer->nFilledLen); /** for each new input buffer --- copy buffer content into into ogg sync state structure data */ vorbis_buffer = ogg_sync_buffer(&omx_vorbisdec_component_Private->oy, inputbuffer->nAllocLen); memcpy(vorbis_buffer, inputbuffer->pBuffer, inputbuffer->nFilledLen); ogg_sync_wrote(&omx_vorbisdec_component_Private->oy, inputbuffer->nFilledLen); DEBUG(DEB_LEV_FULL_SEQ,"***** bytes read to buffer (of first header): %d \n",(int)inputbuffer->nFilledLen); } outputCurrBuffer = outputbuffer->pBuffer; outputLength = outputbuffer->nAllocLen; outputbuffer->nFilledLen = 0; outputbuffer->nOffset = 0; if(omx_vorbisdec_component_Private->packetNumber < 3) { omx_vorbisdec_component_Private->isNewBuffer = 0; if(omx_vorbisdec_component_Private->packetNumber == 0) { DEBUG(DEB_LEV_SIMPLE_SEQ, "in processing the first header buffer\n"); if(ogg_sync_pageout(&omx_vorbisdec_component_Private->oy, &omx_vorbisdec_component_Private->og) != 1) { DEBUG(DEB_LEV_ERR, "this input stream is not an Ogg stream\n"); return; } ogg_stream_init(&omx_vorbisdec_component_Private->os, ogg_page_serialno(&omx_vorbisdec_component_Private->og)); vorbis_info_init(&omx_vorbisdec_component_Private->vi); vorbis_comment_init(&omx_vorbisdec_component_Private->vc); if(ogg_stream_pagein(&omx_vorbisdec_component_Private->os, &omx_vorbisdec_component_Private->og) < 0) { DEBUG(DEB_LEV_ERR, "Error reading first page of Ogg bitstream data.\n"); return; } if(ogg_stream_packetout(&omx_vorbisdec_component_Private->os, &omx_vorbisdec_component_Private->op) != 1) { DEBUG(DEB_LEV_ERR, "Error reading initial header packet.\n"); return; } omx_vorbisdec_component_Private->packetNumber++; if(vorbis_synthesis_headerin(&omx_vorbisdec_component_Private->vi, &omx_vorbisdec_component_Private->vc, &omx_vorbisdec_component_Private->op) < 0) { DEBUG(DEB_LEV_ERR, "This Ogg bitstream does not contain Vorbis audio data\n"); return; } } while(omx_vorbisdec_component_Private->packetNumber < 3) { int result=ogg_sync_pageout(&omx_vorbisdec_component_Private->oy,&omx_vorbisdec_component_Private->og); if(result==0) { //break; /* Need more data */ omx_vorbisdec_component_Private->isNewBuffer = 1; inputbuffer->nFilledLen = 0; return; } /* Don't complain about missing or corrupt data yet. We'll catch it at the packet output phase */ if(result==1) { ogg_stream_pagein(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->og); /* we can ignore any errors here as they'll also become apparent at packetout */ while(omx_vorbisdec_component_Private->packetNumber < 3) { result=ogg_stream_packetout(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->op); if(result==0)break; if(result<0) { /* Uh oh; data at some point was corrupted or missing! We can't tolerate that in a header. Die. */ DEBUG(DEB_LEV_ERR,"Corrupt secondary header. Exiting.\n"); break; }//end if omx_vorbisdec_component_Private->packetNumber++; vorbis_synthesis_headerin(&omx_vorbisdec_component_Private->vi,&omx_vorbisdec_component_Private->vc,&omx_vorbisdec_component_Private->op); }//end while }//end if }//end while omx_vorbisdec_component_Private->isNewBuffer = 1; inputbuffer->nFilledLen = 0; return; } /* A Vorbis logical bitstream begins with 3 headers. Once the last of these has been processed, * we can report the metadata and set up the output audio port appropriately. */ if(omx_vorbisdec_component_Private->packetNumber == 3) { /* Throw the comments plus a few lines about the bitstream we're decoding */ { // ptr should be declared earlier// char **ptr=omx_vorbisdec_component_Private->vc.user_comments; while(*ptr){ DEBUG(DEB_LEV_ERR,"%s\n",*ptr); ++ptr; } DEBUG(DEB_LEV_ERR,"Bitstream is %d channel, %ldHz\n",omx_vorbisdec_component_Private->vi.channels,omx_vorbisdec_component_Private->vi.rate); DEBUG(DEB_LEV_ERR,"Encoded by: %s\n\n",omx_vorbisdec_component_Private->vc.vendor); } /* Update pAudioVorbis settings */ omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate = omx_vorbisdec_component_Private->vi.rate; omx_vorbisdec_component_Private->pAudioVorbis.nChannels = omx_vorbisdec_component_Private->vi.channels; /* Update audio port settings for this Vorbis bitstream */ if ((omx_vorbisdec_component_Private->pAudioPcmMode.nSamplingRate != omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate) || (omx_vorbisdec_component_Private->pAudioPcmMode.nChannels != omx_vorbisdec_component_Private->pAudioVorbis.nChannels)) { omx_vorbisdec_component_Private->pAudioPcmMode.nSamplingRate = omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate; omx_vorbisdec_component_Private->pAudioPcmMode.nChannels = omx_vorbisdec_component_Private->pAudioVorbis.nChannels; /*Send Port Settings changed call back*/ (*(omx_vorbisdec_component_Private->callbacks->EventHandler)) (openmaxStandComp, omx_vorbisdec_component_Private->callbackData, OMX_EventPortSettingsChanged, /* The command was completed */ 0, 1, /* This is the output port index */ NULL); } omx_vorbisdec_component_Private->convsize=inputbuffer->nFilledLen/omx_vorbisdec_component_Private->vi.channels; /* OK, got and parsed all three headers. Initialize the Vorbis packet->PCM decoder. */ vorbis_synthesis_init(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vi); /* central decode state */ vorbis_block_init(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vb);/* local state for most of the decode so multiple block decodes can proceed in parallel. We could init multiple vorbis_block structures for vd here */ } DEBUG(DEB_LEV_FULL_SEQ,"***** now the decoding will start *****\n"); if(omx_vorbisdec_component_Private->isNewBuffer) { omx_vorbisdec_component_Private->isNewBuffer=0; int result=ogg_sync_pageout(&omx_vorbisdec_component_Private->oy,&omx_vorbisdec_component_Private->og); DEBUG(DEB_LEV_FULL_SEQ," ---> page (read in decoding) - header len : %ld body len : %ld \n",omx_vorbisdec_component_Private->og.header_len,omx_vorbisdec_component_Private->og.body_len); if(result == 0) { omx_vorbisdec_component_Private->isNewBuffer = 1; inputbuffer->nFilledLen = 0; return; } if(result<0) { /* missing or corrupt data at this page position */ DEBUG(DEB_LEV_ERR,"Corrupt or missing data in bitstream; continuing...\n"); } else { ogg_stream_pagein(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->og); /* can safely ignore errors at */ } } result=ogg_stream_packetout(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->op); DEBUG(DEB_LEV_FULL_SEQ," packet length (read in decoding a particular page): %ld \n",omx_vorbisdec_component_Private->op.bytes); if(result == 0) { omx_vorbisdec_component_Private->isNewBuffer = 1; inputbuffer->nFilledLen = 0; return; } if(result<0) { /* missing or corrupt data at this page position */ /* no reason to complain; already complained above */ DEBUG(DEB_LEV_ERR,"Corrupt or missing data in bitstream; continuing...\n"); } else { /* we have a packet. Decode it */ omx_vorbisdec_component_Private->packetNumber++; if(vorbis_synthesis(&omx_vorbisdec_component_Private->vb,&omx_vorbisdec_component_Private->op)==0) /* test for success! */ vorbis_synthesis_blockin(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vb); /**pcm is a multichannel float vector. In stereo, for example, pcm[0] is left, and pcm[1] is right. samples is the size of each channel. Convert the float values (-1.<=range<=1.) to whatever PCM format and write it out */ while((samples=vorbis_synthesis_pcmout(&omx_vorbisdec_component_Private->vd,&pcm))>0) { bout=(samples<omx_vorbisdec_component_Private->convsize?samples:omx_vorbisdec_component_Private->convsize); /* convert floats to 16 bit signed ints (host order) and interleave */ for(i=0;i<omx_vorbisdec_component_Private->vi.channels;i++) { ogg_int16_t *ptr=convbuffer+i; mono=pcm[i]; for(j=0;j<bout;j++) { #if 1 val=mono[j]*32767.f; #else /* optional dither */ val=mono[j]*32767.f+drand48()-0.5f; #endif /* might as well guard against clipping */ if(val>32767) { val=32767; clipflag=1; } if(val<-32768) { val=-32768; clipflag=1; } *ptr=val; ptr+=omx_vorbisdec_component_Private->vi.channels; } } outputbuffer->nFilledLen=2*omx_vorbisdec_component_Private->vi.channels*bout; memcpy(outputCurrBuffer,(char *)convbuffer,outputbuffer->nFilledLen); if(clipflag) { DEBUG(DEB_LEV_FULL_SEQ,"Clipping in frame %ld\n",(long)(omx_vorbisdec_component_Private->vd.sequence)); } vorbis_synthesis_read(&omx_vorbisdec_component_Private->vd,bout); /* tell libvorbis how many samples we actually consumed */ } } if(ogg_page_eos(&omx_vorbisdec_component_Private->og)) { DEBUG(DEB_LEV_FULL_SEQ, "In %s EOS Detected\n",__func__); eos=1; } DEBUG(DEB_LEV_FULL_SEQ, "One output buffer %x len=%d is full returning\n", (int)outputbuffer->pBuffer, (int)outputbuffer->nFilledLen); }
/*! * \brief Create a new OGG/Vorbis filestream and set it up for reading. * \param s File that points to on disk storage of the OGG/Vorbis data. * \return The new filestream. */ static int ogg_vorbis_open(struct ast_filestream *s) { int i; int bytes; int result; char **ptr; char *buffer; struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private; tmp->writing = 0; ogg_sync_init(&tmp->oy); buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, s->f); ogg_sync_wrote(&tmp->oy, bytes); result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result != 1) { if(bytes < BLOCK_SIZE) { ast_log(LOG_ERROR, "Run out of data...\n"); } else { ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); } ogg_sync_clear(&tmp->oy); return -1; } ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og)); vorbis_info_init(&tmp->vi); vorbis_comment_init(&tmp->vc); if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); error: ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); return -1; } if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { ast_log(LOG_ERROR, "Error reading initial header packet.\n"); goto error; } if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n"); goto error; } for (i = 0; i < 2 ; ) { while (i < 2) { result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result == 0) break; if (result == 1) { ogg_stream_pagein(&tmp->os, &tmp->og); while(i < 2) { result = ogg_stream_packetout(&tmp->os,&tmp->op); if(result == 0) break; if(result < 0) { ast_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n"); goto error; } vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op); i++; } } } buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, s->f); if (bytes == 0 && i < 2) { ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n"); goto error; } ogg_sync_wrote(&tmp->oy, bytes); } for (ptr = tmp->vc.user_comments; *ptr; ptr++) ast_debug(1, "OGG/Vorbis comment: %s\n", *ptr); ast_debug(1, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate); ast_debug(1, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor); if (tmp->vi.channels != 1) { ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n"); goto error; } if (tmp->vi.rate != DEFAULT_SAMPLE_RATE) { ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n"); vorbis_block_clear(&tmp->vb); vorbis_dsp_clear(&tmp->vd); goto error; } vorbis_synthesis_init(&tmp->vd, &tmp->vi); vorbis_block_init(&tmp->vd, &tmp->vb); return 0; }
static UINT ogg_dec(GETSND snd, short *dst) { __OV *ov; int result; char *buffer; int bytes; float **pcm; int samples; int i; int j; float *mono; short *ptr; long val; ov = (__OV *)snd->snd; do { switch(ov->phase) { case OVPHASE_HEAD: result = ogg_sync_pageout(&ov->oy, &ov->og); if (result > 0) { ogg_stream_pagein(&ov->os, &ov->og); ov->phase = OVPHASE_STREAMIN; } else if (result == 0) { ov->phase = OVPHASE_NEXT; } else { TRACEOUT(("Corrupt or missing data in bitstream")); } break; case OVPHASE_STREAMIN: result = ogg_stream_packetout(&ov->os, &ov->op); if (result > 0) { if (vorbis_synthesis(&ov->vb, &ov->op) == 0) { vorbis_synthesis_blockin(&ov->vd, &ov->vb); } ov->phase = OVPHASE_GETPCM; } else if (result == 0) { if (!ogg_page_eos(&ov->og)) { ov->phase = OVPHASE_NEXT; } else { ov->phase = OVPHASE_CLOSE; } } break; case OVPHASE_GETPCM: samples = vorbis_synthesis_pcmout(&ov->vd, &pcm); if (samples > 0) { if (samples > (int)snd->blocksamples) { samples = (int)snd->blocksamples; } for (i=0; i<ov->vi.channels; i++) { ptr = dst + i; mono = pcm[i]; for (j=0; j<samples; j++) { val = (long)(mono[j] * 32767.f); if (val > 32767) { val = 32767; } if (val < -32768) { val = -32768; } *ptr = (short)val; ptr += ov->vi.channels; } } vorbis_synthesis_read(&ov->vd, samples); return((UINT)samples); } ov->phase = OVPHASE_STREAMIN; break; case OVPHASE_NEXT: buffer = ogg_sync_buffer(&ov->oy, 4096); bytes = snd_read(snd, buffer, 4096); ogg_sync_wrote(&ov->oy, bytes); #if 1 ov->phase = OVPHASE_HEAD; #else if (bytes) { ov->phase = OVPHASE_HEAD; } else { ov->phase = OVPHASE_CLOSE; } #endif break; case OVPHASE_CLOSE: return(0); } } while(1); }
int sndogg_open(SMIXTRACK trk) { __OV *ov; char *buffer; UINT r; int bytes; int i; int result; ov = (__OV *)_MALLOC(sizeof(__OV), "__OV"); if (ov == NULL) { goto ovopn_next; } ZeroMemory(ov, sizeof(__OV)); r = sndmix_dataload(trk, trk->maxdatas); if ((r == (UINT)-1) || (r == 0)) { goto ovopn_next2; } buffer = ogg_sync_buffer(&ov->oy, trk->maxdatas); CopyMemory(buffer, trk->data, r); ogg_sync_wrote(&ov->oy, (int)r); if (ogg_sync_pageout(&ov->oy, &ov->og) != 1) { TRACEOUT(("Input does not appear to be an Ogg bitstream.")); goto ovopn_next2; } ogg_stream_init(&ov->os, ogg_page_serialno(&ov->og)); sndmix_datatrash(trk, (UINT)-1); vorbis_info_init(&ov->vi); vorbis_comment_init(&ov->vc); if (ogg_stream_pagein(&ov->os, &ov->og) < 0) { TRACEOUT(("Error reading first page of Ogg bitstream data.")); goto ovopn_err1; } if (ogg_stream_packetout(&ov->os, &ov->op) != 1) { TRACEOUT(("Error reading initial header packet.")); goto ovopn_err1; } if (vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op) < 0) { TRACEOUT(("This Ogg bitstream does not contain Vorbis audio data.")); goto ovopn_err1; } i = 0; while(i < 2) { while(i < 2) { result = ogg_sync_pageout(&ov->oy, &ov->og); if (result == 0) { break; } if (result == 1) { ogg_stream_pagein(&ov->os, &ov->og); while(i < 2) { result = ogg_stream_packetout(&ov->os, &ov->op); if (result == 0) { break; } if (result < 0) { TRACEOUT(("Corrupt secondary header. Exiting.")); goto ovopn_err1; } vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op); i++; } } } buffer = ogg_sync_buffer(&ov->oy, 4096); bytes = sndmix_dataread(trk, buffer, 4096); if ((bytes == 0) && (i < 2)) { TRACEOUT(("End of file before finding all Vorbis headers!")); return(SNDMIX_FAILURE); } ogg_sync_wrote(&ov->oy, bytes); } trk->snd = ov; trk->dec = (DECFN)ogg_dec; trk->decend = ogg_decend; trk->samprate = ov->vi.rate; trk->channels = ov->vi.channels; trk->block = 4096; trk->blksamp = 4096 / ov->vi.channels; trk->bit = 16; #if defined(SOUND_MOREINFO) trk->bps = 0; trk->fmt = WAVEFMT_OGG; CopyMemory(trk->info, "Ogg vorbis", 11); #endif vorbis_synthesis_init(&ov->vd, &ov->vi); vorbis_block_init(&ov->vd, &ov->vb); return(SNDMIX_SUCCESS); ovopn_err1: ogg_sync_clear(&ov->oy); _MFREE(ov); return(SNDMIX_FAILURE); ovopn_next2: _MFREE(ov); ovopn_next: return(SNDMIX_NOTSUPPORT); }
/* Read the speex header. Return 0 on error. */ static int read_speex_header (struct spx_data *data) { int packet_count = 0; int stream_init = 0; char *buf; ssize_t nb_read; int header_packets = 2; while (packet_count < header_packets) { /* Get the ogg buffer for writing */ buf = ogg_sync_buffer (&data->oy, 200); /* Read bitstream from input file */ nb_read = io_read (data->stream, buf, 200); if (nb_read < 0) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex file: IO error: %s", io_strerror(data->stream)); return 0; } if (nb_read == 0) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex header"); return 0; } ogg_sync_wrote (&data->oy, nb_read); /* Loop for all complete pages we got (most likely only one) */ while (ogg_sync_pageout(&data->oy, &data->og) == 1) { if (stream_init == 0) { ogg_stream_init(&data->os, ogg_page_serialno(&data->og)); stream_init = 1; } /* Add page to the bitstream */ ogg_stream_pagein (&data->os, &data->og); /* Extract all available packets FIXME: EOS! */ while (ogg_stream_packetout(&data->os, &data->op) == 1) { /* If first packet, process as Speex header */ if (packet_count == 0) { data->st = process_header (data); if (!data->st) { ogg_stream_clear (&data->os); return 0; } data->rate = data->header->rate; data->nchannels = data->header->nb_channels; data->frames_per_packet = data->header->frames_per_packet; /*data->vbr = data->header->vbr; */ if (!data->frames_per_packet) data->frames_per_packet=1; data->output = xmalloc (data->frame_size * data->nchannels * data->frames_per_packet * sizeof(int16_t)); data->output_start = 0; data->output_left = 0; header_packets += data->header->extra_headers; } else if (packet_count == 1) { data->comment_packet_len = data->op.bytes; data->comment_packet = xmalloc ( sizeof(char) * data->comment_packet_len); memcpy (data->comment_packet, data->op.packet, data->comment_packet_len); } packet_count++; } } } return 1; }
static UINT ogg_dec(SMIXTRACK trk, SINT16 *dst) { __OV *ov; int result; char *buffer; UINT r; float **pcm; int samples; int i; int j; float *mono; SINT16 *ptr; SINT32 val; ov = (__OV *)trk->snd; do { switch(ov->phase) { case OVPHASE_HEAD: result = ogg_sync_pageout(&ov->oy, &ov->og); if (result > 0) { ogg_stream_pagein(&ov->os, &ov->og); ov->phase = OVPHASE_STREAMIN; } else if (result == 0) { ov->phase = OVPHASE_NEXT; } else { TRACEOUT(("Corrupt or missing data in bitstream")); } break; case OVPHASE_STREAMIN: result = ogg_stream_packetout(&ov->os, &ov->op); if (result > 0) { if (vorbis_synthesis(&ov->vb, &ov->op) == 0) { vorbis_synthesis_blockin(&ov->vd, &ov->vb); } ov->phase = OVPHASE_GETPCM; } else if (result == 0) { if (!ogg_page_eos(&ov->og)) { ov->phase = OVPHASE_NEXT; } else { ov->phase = OVPHASE_CLOSE; } } break; case OVPHASE_GETPCM: samples = vorbis_synthesis_pcmout(&ov->vd, &pcm); if (samples > 0) { if (samples > (int)trk->blksamp) { samples = (int)trk->blksamp; } for (i=0; i<ov->vi.channels; i++) { ptr = dst + i; mono = pcm[i]; for (j=0; j<samples; j++) { val = (long)(mono[j] * 32767.f); if (val > 32767) { val = 32767; } if (val < -32768) { val = -32768; } *ptr = (SINT16)val; ptr += ov->vi.channels; } } vorbis_synthesis_read(&ov->vd, samples); return((UINT)samples); } ov->phase = OVPHASE_STREAMIN; break; case OVPHASE_NEXT: buffer = ogg_sync_buffer(&ov->oy, trk->block); r = sndmix_dataread(trk, buffer, trk->block); ogg_sync_wrote(&ov->oy, (int)r); if (r) { ov->phase = OVPHASE_HEAD; } else { ov->phase = OVPHASE_CLOSE; } break; case OVPHASE_CLOSE: ov->phase = OVPHASE_HEAD; // ��[�� return(0); } } while(1); }
int main(void){ ogg_stream_init(&os_en,0x04030201); ogg_stream_init(&os_de,0x04030201); ogg_sync_init(&oy); /* Exercise each code path in the framing code. Also verify that the checksums are working. */ { /* 17 only */ const int packets[]={17, -1}; const int *headret[]={head1_0,NULL}; fprintf(stderr,"testing single page encoding... "); test_pack(packets,headret); } { /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; const int *headret[]={head1_1,head2_1,NULL}; fprintf(stderr,"testing basic page encoding... "); test_pack(packets,headret); } { /* nil packets; beginning,middle,end */ const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; const int *headret[]={head1_2,head2_2,NULL}; fprintf(stderr,"testing basic nil packets... "); test_pack(packets,headret); } { /* large initial packet */ const int packets[]={4345,259,255,-1}; const int *headret[]={head1_3,head2_3,NULL}; fprintf(stderr,"testing initial-packet lacing > 4k... "); test_pack(packets,headret); } { /* continuing packet test */ const int packets[]={0,4345,259,255,-1}; const int *headret[]={head1_4,head2_4,head3_4,NULL}; fprintf(stderr,"testing single packet page span... "); test_pack(packets,headret); } /* page with the 255 segment limit */ { const int packets[]={0,10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,50,-1}; const int *headret[]={head1_5,head2_5,head3_5,NULL}; fprintf(stderr,"testing max packet segments... "); test_pack(packets,headret); } { /* packet that overspans over an entire page */ const int packets[]={0,100,9000,259,255,-1}; const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; fprintf(stderr,"testing very large packets... "); test_pack(packets,headret); } { /* term only page. why not? */ const int packets[]={0,100,4080,-1}; const int *headret[]={head1_7,head2_7,head3_7,NULL}; fprintf(stderr,"testing zero data page (1 nil packet)... "); test_pack(packets,headret); } { /* build a bunch of pages for testing */ unsigned char *data=_ogg_malloc(1024*1024); int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1}; int inptr=0,i,j; ogg_page og[5]; ogg_stream_reset(&os_en); for(i=0;pl[i]!=-1;i++){ ogg_packet op; int len=pl[i]; op.packet=data+inptr; op.bytes=len; op.e_o_s=(pl[i+1]<0?1:0); op.granulepos=(i+1)*1000; for(j=0;j<len;j++)data[inptr++]=i+j; ogg_stream_packetin(&os_en,&op); } _ogg_free(data); /* retrieve finished pages */ for(i=0;i<5;i++){ if(ogg_stream_pageout(&os_en,&og[i])==0){ fprintf(stderr,"Too few pages output building sync tests!\n"); exit(1); } copy_page(&og[i]); } /* Test lost pages on pagein/packetout: no rollback */ { ogg_page temp; ogg_packet test; fprintf(stderr,"Testing loss of pages... "); ogg_sync_reset(&oy); ogg_stream_reset(&os_de); for(i=0;i<5;i++){ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, og[i].header_len); ogg_sync_wrote(&oy,og[i].header_len); memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); ogg_sync_wrote(&oy,og[i].body_len); } ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); /* skip */ ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); /* do we get the expected results/packets? */ if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,0,0,0); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,100,1,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,4079,2,3000); if(ogg_stream_packetout(&os_de,&test)!=-1){ fprintf(stderr,"Error: loss of page did not return error\n"); exit(1); } if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,76,5,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,34,6,-1); fprintf(stderr,"ok.\n"); } /* Test lost pages on pagein/packetout: rollback with continuation */ { ogg_page temp; ogg_packet test; fprintf(stderr,"Testing loss of pages (rollback required)... "); ogg_sync_reset(&oy); ogg_stream_reset(&os_de); for(i=0;i<5;i++){ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, og[i].header_len); ogg_sync_wrote(&oy,og[i].header_len); memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); ogg_sync_wrote(&oy,og[i].body_len); } ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); /* skip */ ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); /* do we get the expected results/packets? */ if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,0,0,0); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,100,1,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,4079,2,3000); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,2956,3,4000); if(ogg_stream_packetout(&os_de,&test)!=-1){ fprintf(stderr,"Error: loss of page did not return error\n"); exit(1); } if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,300,13,14000); fprintf(stderr,"ok.\n"); } /* the rest only test sync */ { ogg_page og_de; /* Test fractional page inputs: incomplete capture */ fprintf(stderr,"Testing sync on partial inputs... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 3); ogg_sync_wrote(&oy,3); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete fixed header */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete header */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, 5); ogg_sync_wrote(&oy,5); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete body */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, og[1].header_len-28); ogg_sync_wrote(&oy,og[1].header_len-28); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); ogg_sync_wrote(&oy,1000); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, og[1].body_len-1000); ogg_sync_wrote(&oy,og[1].body_len-1000); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test fractional page inputs: page + incomplete capture */ { ogg_page og_de; fprintf(stderr,"Testing sync on 1+partial inputs... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, og[1].header_len-20); ogg_sync_wrote(&oy,og[1].header_len-20); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test recapture: garbage + page */ { ogg_page og_de; fprintf(stderr,"Testing search for capture... "); ogg_sync_reset(&oy); /* 'garbage' */ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)>0)error(); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, og[2].header_len-20); ogg_sync_wrote(&oy,og[2].header_len-20); memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, og[2].body_len); ogg_sync_wrote(&oy,og[2].body_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test recapture: page + garbage + page */ { ogg_page og_de; fprintf(stderr,"Testing recapture... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, og[2].header_len); ogg_sync_wrote(&oy,og[2].header_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, og[2].header_len); ogg_sync_wrote(&oy,og[2].header_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, og[2].body_len-5); ogg_sync_wrote(&oy,og[2].body_len-5); memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, og[3].header_len); ogg_sync_wrote(&oy,og[3].header_len); memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, og[3].body_len); ogg_sync_wrote(&oy,og[3].body_len); if(ogg_sync_pageout(&oy,&og_de)>0)error(); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } } return(0); }
int main(int argc, char **argv) { int c; int option_index = 0; char *inFile, *outFile; FILE *fin, *fout=NULL; short out[MAX_FRAME_SIZE]; short output[MAX_FRAME_SIZE]; int frame_size=0, granule_frame_size=0; void *st=NULL; CELTMode *mode=NULL; int packet_count=0; int stream_init = 0; int quiet = 0; ogg_int64_t page_granule=0, last_granule=0; int skip_samples=0, page_nb_packets; struct option long_options[] = { {"help", no_argument, NULL, 0}, {"quiet", no_argument, NULL, 0}, {"version", no_argument, NULL, 0}, {"version-short", no_argument, NULL, 0}, {"rate", required_argument, NULL, 0}, {"mono", no_argument, NULL, 0}, {"stereo", no_argument, NULL, 0}, {"packet-loss", required_argument, NULL, 0}, {0, 0, 0, 0} }; ogg_sync_state oy; ogg_page og; ogg_packet op; ogg_stream_state os; int enh_enabled; int nframes=2; int print_bitrate=0; int close_in=0; int eos=0; int forceMode=-1; int audio_size=0; float loss_percent=-1; int channels=-1; int rate=0; int extra_headers=0; int wav_format=0; int lookahead=0; int celt_serialno = -1; int firstpacket = 1; enh_enabled = 1; /*Process options*/ while(1) { c = getopt_long (argc, argv, "hvV", long_options, &option_index); if (c==-1) break; switch(c) { case 0: if (strcmp(long_options[option_index].name,"help")==0) { usage(); exit(0); } else if (strcmp(long_options[option_index].name,"quiet")==0) { quiet = 1; } else if (strcmp(long_options[option_index].name,"version")==0) { version(); exit(0); } else if (strcmp(long_options[option_index].name,"version-short")==0) { version_short(); exit(0); } else if (strcmp(long_options[option_index].name,"mono")==0) { channels=1; } else if (strcmp(long_options[option_index].name,"stereo")==0) { channels=2; } else if (strcmp(long_options[option_index].name,"rate")==0) { rate=atoi (optarg); } else if (strcmp(long_options[option_index].name,"packet-loss")==0) { loss_percent = atof(optarg); } break; case 'h': usage(); exit(0); break; case 'v': version(); exit(0); break; case 'V': print_bitrate=1; break; case '?': usage(); exit(1); break; } } if (argc-optind!=2 && argc-optind!=1) { usage(); exit(1); } inFile=argv[optind]; if (argc-optind==2) outFile=argv[optind+1]; else outFile = ""; wav_format = strlen(outFile)>=4 && ( strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0); /*Open input file*/ if (strcmp(inFile, "-")==0) { #if defined WIN32 || defined _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif fin=stdin; } else { fin = fopen(inFile, "rb"); if (!fin) { perror(inFile); exit(1); } close_in=1; } /*Init Ogg data struct*/ ogg_sync_init(&oy); /*Main decoding loop*/ while (1) { char *data; int i, nb_read; /*Get the ogg buffer for writing*/ data = ogg_sync_buffer(&oy, 200); /*Read bitstream from input file*/ nb_read = fread(data, sizeof(char), 200, fin); ogg_sync_wrote(&oy, nb_read); /*Loop for all complete pages we got (most likely only one)*/ while (ogg_sync_pageout(&oy, &og)==1) { if (stream_init == 0) { ogg_stream_init(&os, ogg_page_serialno(&og)); stream_init = 1; } if (ogg_page_serialno(&og) != os.serialno) { /* so all streams are read. */ ogg_stream_reset_serialno(&os, ogg_page_serialno(&og)); } /*Add page to the bitstream*/ ogg_stream_pagein(&os, &og); page_granule = ogg_page_granulepos(&og); page_nb_packets = ogg_page_packets(&og); if (page_granule>0 && frame_size) { /* FIXME: shift the granule values if --force-* is specified */ skip_samples = frame_size*(page_nb_packets*granule_frame_size*nframes - (page_granule-last_granule))/granule_frame_size; if (ogg_page_eos(&og)) skip_samples = -skip_samples; /*else if (!ogg_page_bos(&og)) skip_samples = 0;*/ } else { skip_samples = 0; } /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/ last_granule = page_granule; /*Extract all available packets*/ while (!eos && ogg_stream_packetout(&os, &op) == 1) { if (op.bytes>=8 && !memcmp(op.packet, "CELT ", 8)) { celt_serialno = os.serialno; } if (celt_serialno == -1 || os.serialno != celt_serialno) break; /*If first packet, process as CELT header*/ if (packet_count==0) { st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &lookahead, &extra_headers, quiet, &mode); if (!st) exit(1); if (!nframes) nframes=1; fout = out_file_open(outFile, rate, &channels); } else if (packet_count==1) { if (!quiet) print_comments((char*)op.packet, op.bytes); } else if (packet_count<=1+extra_headers) { /* Ignore extra headers */ } else { int lost=0; if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent) lost=1; /*End of stream condition*/ if (op.e_o_s && os.serialno == celt_serialno) /* don't care for anything except celt eos */ eos=1; { int ret; /*Decode frame*/ if (!lost) ret = celt_decode(st, (unsigned char*)op.packet, op.bytes, output, frame_size); else ret = celt_decode(st, NULL, 0, output, frame_size); /*for (i=0;i<frame_size*channels;i++) printf ("%d\n", (int)output[i]);*/ if (ret<0) { fprintf (stderr, "Decoding error: %s\n", celt_strerror(ret)); break; } if (print_bitrate) { celt_int32 tmp=op.bytes; char ch=13; fputc (ch, stderr); fprintf (stderr, "Bitrate in use: %d bytes/packet ", tmp); } /*Convert to short and save to output file*/ if (strlen(outFile)!=0) { for (i=0;i<frame_size*channels;i++) out[i]=le_short(output[i]); } else { for (i=0;i<frame_size*channels;i++) out[i]=output[i]; } { int frame_offset = 0; int new_frame_size = frame_size; /*printf ("packet %d %d\n", packet_no, skip_samples);*/ /*fprintf (stderr, "packet %d %d %d\n", packet_no, skip_samples, lookahead);*/ if (firstpacket == 1) { /*printf ("chopping first packet\n");*/ new_frame_size -= lookahead; frame_offset = lookahead; firstpacket = 0; } if (new_frame_size>0) { #if defined WIN32 || defined _WIN32 if (strlen(outFile)==0) WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels); else #endif fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout); audio_size+=sizeof(short)*new_frame_size*channels; } } } } packet_count++; } } if (feof(fin)) break; } if (fout && wav_format) { if (fseek(fout,4,SEEK_SET)==0) { int tmp; tmp = le_int(audio_size+36); fwrite(&tmp,4,1,fout); if (fseek(fout,32,SEEK_CUR)==0) { tmp = le_int(audio_size); fwrite(&tmp,4,1,fout); } else { fprintf (stderr, "First seek worked, second didn't\n"); } } else { fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n"); } } if (st) { celt_decoder_destroy(st); celt_mode_destroy(mode); } else { fprintf (stderr, "This doesn't look like a CELT file\n"); } if (stream_init) ogg_stream_clear(&os); ogg_sync_clear(&oy); #if defined WIN32 || defined _WIN32 if (strlen(outFile)==0) WIN_Audio_close (); #endif if (close_in) fclose(fin); if (fout != NULL) fclose(fout); return 0; }
status_t OggReader::FindLastPages() { TRACE("OggReader::FindLastPages\n"); bigtime_t start_time = system_time(); status_t result = B_ERROR; const int read_size = 256*256; ogg_page page; ogg_sync_state sync; ogg_sync_init(&sync); off_t right = fSeekable->Seek(0, SEEK_END); off_t left = right; // we assume the common case is that the last pages are near the end uint serial_count = 0; while (serial_count < fCookies.size()) { int offset; ssize_t bytes = 0; while ((offset = ogg_sync_pageseek(&sync, &page)) <= 0) { left += -offset; if (offset == 0) { off_t pos = fSeekable->Position(); if (pos >= right || bytes == 0) { if (left == 0) { TRACE("OggReader::FindLastPages: couldn't find some stream's page!!!\n"); goto done; } left = max_c(0, left - read_size); result = fSeekable->Seek(left, SEEK_SET); if (result < 0) { goto done; } ogg_sync_reset(&sync); } char * buffer = ogg_sync_buffer(&sync, read_size); bytes = fSeekable->Read(buffer, read_size); if (bytes < 0) { TRACE("OggReader::FindLastPages: Read: error\n"); result = bytes; goto done; } if (ogg_sync_wrote(&sync, bytes) != 0) { TRACE("OggReader::FindLastPages: ogg_sync_wrote failed?: error\n"); goto done; } } } off_t current = left; do { // found a page at "current" long serialno = ogg_page_serialno(&page); OggSeekable * track = dynamic_cast<OggSeekable*>(fTracks[serialno]); if (track == 0) { TRACE("OggReader::FindLastPages: unknown serialno == TODO: chaining?\n"); } else { if (track->GetLastPagePosition() == 0) { serial_count++; } track->SetLastPagePosition(current); } current += page.header_len + page.body_len; } while ((current < right) && (ogg_sync_pageout(&sync, &page) == 1)); right = left; ogg_sync_reset(&sync); } result = B_OK; done: ogg_sync_clear(&sync); TRACE("OggReader::FindLastPages took %lld microseconds\n", system_time() - start_time); return result; }
/* main plugin handler for getting a buffer for the queue. In here we * just add an incoming page to the codecs and process it until either * more data is needed or we prodice a buffer for the queue. */ static refbuf_t *ogg_get_buffer (source_t *source) { ogg_state_t *ogg_info = source->format->_state; format_plugin_t *format = source->format; char *data = NULL; int bytes = 0, total = 0; while (total < 15000) { while (1) { ogg_page page; refbuf_t *refbuf = NULL; ogg_codec_t *codec = ogg_info->current; /* if a codec has just been given a page then process it */ if (codec && codec->process) { refbuf = codec->process (ogg_info, codec); if (refbuf) return complete_buffer (source, refbuf); ogg_info->current = NULL; } if (ogg_sync_pageout (&ogg_info->oy, &page) > 0) { if (ogg_page_bos (&page)) { process_initial_page (source->format, &page); } else { ogg_info->bos_completed = 1; refbuf = process_ogg_page (ogg_info, &page); } if (ogg_info->error) { ERROR0 ("Problem processing stream"); source->flags &= ~SOURCE_RUNNING; return NULL; } if (refbuf) return complete_buffer (source, refbuf); continue; } /* need more stream data */ break; } /* we need more data to continue getting pages */ data = ogg_sync_buffer (&ogg_info->oy, 4096); bytes = client_read_bytes (source->client, data, 4096); if (bytes <= 0) { ogg_sync_wrote (&ogg_info->oy, 0); source->client->schedule_ms += 50; break; } total += bytes; format->read_bytes += bytes; rate_add (source->in_bitrate, bytes, source->client->worker->current_time.tv_sec); ogg_sync_wrote (&ogg_info->oy, bytes); } return NULL; }
/* Helper; just grab some more compressed bitstream and sync it for page extraction */ int buffer_data(FILE *in,ogg_sync_state *oy){ char *buffer=ogg_sync_buffer(oy,4096); int bytes=fread(buffer,1,4096,in); ogg_sync_wrote(oy,bytes); return(bytes); }
UInt32 SFB::Audio::OggSpeexDecoder::_ReadAudio(AudioBufferList *bufferList, UInt32 frameCount) { if(bufferList->mNumberBuffers != mFormat.mChannelsPerFrame) { LOGGER_WARNING("org.sbooth.AudioEngine.Decoder.OggSpeex", "_ReadAudio() called with invalid parameters"); return 0; } UInt32 framesRead = 0; // Reset output buffer data size for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i) bufferList->mBuffers[i].mDataByteSize = 0; for(;;) { UInt32 framesRemaining = frameCount - framesRead; UInt32 framesToSkip = (UInt32)(bufferList->mBuffers[0].mDataByteSize / sizeof(float)); UInt32 framesInBuffer = (UInt32)(mBufferList->mBuffers[0].mDataByteSize / sizeof(float)); UInt32 framesToCopy = std::min(framesInBuffer, framesRemaining); // Copy data from the buffer to output for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) { float *floatBuffer = (float *)bufferList->mBuffers[i].mData; memcpy(floatBuffer + framesToSkip, mBufferList->mBuffers[i].mData, framesToCopy * sizeof(float)); bufferList->mBuffers[i].mDataByteSize += framesToCopy * sizeof(float); // Move remaining data in buffer to beginning if(framesToCopy != framesInBuffer) { floatBuffer = (float *)mBufferList->mBuffers[i].mData; memmove(floatBuffer, floatBuffer + framesToCopy, (framesInBuffer - framesToCopy) * sizeof(float)); } mBufferList->mBuffers[i].mDataByteSize -= framesToCopy * sizeof(float); } framesRead += framesToCopy; // All requested frames were read if(framesRead == frameCount) break; // EOS reached if(mSpeexEOSReached) break; // Attempt to process the desired number of packets unsigned packetsDesired = 1; while(0 < packetsDesired && !mSpeexEOSReached) { // Process any packets in the current page while(0 < packetsDesired && !mSpeexEOSReached) { // Grab a packet from the streaming layer ogg_packet oggPacket; int result = ogg_stream_packetout(&mOggStreamState, &oggPacket); if(-1 == result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding error: Ogg loss of streaming"); break; } // If result is 0, there is insufficient data to assemble a packet if(0 == result) break; // Otherwise, we got a valid packet for processing if(1 == result) { if(5 <= oggPacket.bytes && !memcmp(oggPacket.packet, "Speex", 5)) mSpeexSerialNumber = mOggStreamState.serialno; if(-1 == mSpeexSerialNumber || mOggStreamState.serialno != mSpeexSerialNumber) break; // Ignore the following: // - Speex comments in packet #2 // - Extra headers (optionally) in packets 3+ if(1 != mOggPacketCount && 1 + mExtraSpeexHeaderCount <= mOggPacketCount) { // Detect Speex EOS if(oggPacket.e_o_s && mOggStreamState.serialno == mSpeexSerialNumber) mSpeexEOSReached = true; // SPEEX_GET_FRAME_SIZE is in samples spx_int32_t speexFrameSize; speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize); float buffer [(2 == mFormat.mChannelsPerFrame) ? 2 * speexFrameSize : speexFrameSize]; // Copy the Ogg packet to the Speex bitstream speex_bits_read_from(&mSpeexBits, (char *)oggPacket.packet, (int)oggPacket.bytes); // Decode each frame in the Speex packet for(spx_int32_t i = 0; i < mSpeexFramesPerOggPacket; ++i) { result = speex_decode(mSpeexDecoder, &mSpeexBits, buffer); // -1 indicates EOS if(-1 == result) break; else if(-2 == result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding error: possible corrupted stream"); break; } if(0 > speex_bits_remaining(&mSpeexBits)) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding overflow: possible corrupted stream"); break; } // Normalize the values float maxSampleValue = 1u << 15; vDSP_vsdiv(buffer, 1, &maxSampleValue, buffer, 1, (vDSP_Length)speexFrameSize); // Copy the frames from the decoding buffer to the output buffer, skipping over any frames already decoded framesInBuffer = mBufferList->mBuffers[0].mDataByteSize / sizeof(float); memcpy((float *)mBufferList->mBuffers[0].mData + framesInBuffer, buffer, (size_t)speexFrameSize * sizeof(float)); mBufferList->mBuffers[0].mDataByteSize += (size_t)speexFrameSize * sizeof(float); // Process stereo channel, if present if(2 == mFormat.mChannelsPerFrame) { speex_decode_stereo(buffer, speexFrameSize, mSpeexStereoState); vDSP_vsdiv(buffer + speexFrameSize, 1, &maxSampleValue, buffer + speexFrameSize, 1, (vDSP_Length)speexFrameSize); memcpy((float *)mBufferList->mBuffers[1].mData + framesInBuffer, buffer + speexFrameSize, (size_t)speexFrameSize * sizeof(float)); mBufferList->mBuffers[1].mDataByteSize += (size_t)speexFrameSize * sizeof(float); } // Packet processing finished --packetsDesired; } } ++mOggPacketCount; } } // Grab a new Ogg page for processing, if necessary if(!mSpeexEOSReached && 0 < packetsDesired) { while(1 != ogg_sync_pageout(&mOggSyncState, &mOggPage)) { // Get the ogg buffer for writing char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES); // Read bitstream from input file ssize_t bytesRead = (ssize_t)GetInputSource().Read(data, READ_SIZE_BYTES); if(-1 == bytesRead) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Unable to read from the input file"); break; } ogg_sync_wrote(&mOggSyncState, bytesRead); // No more data available from input file if(0 == bytesRead) break; } // Ensure all Ogg streams are read if(ogg_page_serialno(&mOggPage) != mOggStreamState.serialno) ogg_stream_reset_serialno(&mOggStreamState, ogg_page_serialno(&mOggPage)); // Get the resultant Ogg page int result = ogg_stream_pagein(&mOggStreamState, &mOggPage); if(0 != result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Error reading Ogg page"); break; } } } } mCurrentFrame += framesRead; if(0 == framesRead && mSpeexEOSReached) mTotalFrames = mCurrentFrame; return framesRead; }
int parse_ogg_stream(FILE *f,const char *pre_buffer,size_t pre_bytes,ogg_parser_funcs funcs,kate_uintptr_t data) { char *ptr=NULL; ogg_sync_state oy; ogg_page og; ogg_int64_t bytes_read; static const size_t buffer_size=4096; size_t offset=0; int ret; long last_returned; long leftover_size=0; int in_hole=0; long first_hole_size=0; long hole_offset; ogg_sync_init(&oy); /* first add the buffer, if any */ if (pre_buffer && pre_bytes) { ptr=ogg_sync_buffer(&oy,pre_bytes); if (!ptr) { fprintf(stderr,"Failed to get sync buffer for %lu bytes\n",(unsigned long)pre_bytes); goto error; } memcpy(ptr,pre_buffer,pre_bytes); ogg_sync_wrote(&oy,pre_bytes); } while (1) { ptr=ogg_sync_buffer(&oy,buffer_size); if (!ptr) { fprintf(stderr,"Failed to get sync buffer for %lu bytes\n",(unsigned long)buffer_size); goto error; } bytes_read=read(fileno(f),ptr,buffer_size); if (bytes_read==0) { break; } ogg_sync_wrote(&oy,bytes_read); last_returned=0; while ((ret=ogg_sync_pageout(&oy,&og))!=0) { if (ret>0) { /* new page */ if (in_hole) { long hole_size=first_hole_size+leftover_size+oy.returned-(og.header_len+og.body_len); if (funcs.on_hole) { ret=(*funcs.on_hole)(data,hole_offset,hole_size); if (ret<0) goto error; } offset+=hole_size; } if (funcs.on_page) { ret=(*funcs.on_page)(data,offset,&og); if (ret<0) goto error; } in_hole=0; offset+=og.header_len+og.body_len; } else { /* hole in data */ first_hole_size=oy.returned-last_returned; hole_offset=offset; in_hole=1; } leftover_size=0; last_returned=oy.returned; } leftover_size+=oy.fill-last_returned; } /* detect holes at end of file */ if (leftover_size>0) { if (funcs.on_hole) { ret=(*funcs.on_hole)(data,offset,leftover_size); if (ret<0) goto error; } } ogg_sync_clear(&oy); return 0; error: ogg_sync_clear(&oy); return -1; }
bool SFB::Audio::OggSpeexDecoder::_Open(CFErrorRef *error) { // Initialize Ogg data struct ogg_sync_init(&mOggSyncState); // Get the ogg buffer for writing char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES); // Read bitstream from input file ssize_t bytesRead = (ssize_t)GetInputSource().Read(data, READ_SIZE_BYTES); if(-1 == bytesRead) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” could not be read."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Read error"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("Unable to read from the input file."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Tell the sync layer how many bytes were written to its internal buffer int result = ogg_sync_wrote(&mOggSyncState, bytesRead); if(-1 == result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Turn the data we wrote into an ogg page result = ogg_sync_pageout(&mOggSyncState, &mOggPage); if(1 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Initialize the stream and grab the serial number ogg_stream_init(&mOggStreamState, ogg_page_serialno(&mOggPage)); // Get the first Ogg page result = ogg_stream_pagein(&mOggStreamState, &mOggPage); if(0 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Get the first packet (should be the header) from the page ogg_packet op; result = ogg_stream_packetout(&mOggStreamState, &op); if(1 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } if(op.bytes >= 5 && !memcmp(op.packet, "Speex", 5)) mSpeexSerialNumber = mOggStreamState.serialno; ++mOggPacketCount; // Convert the packet to the Speex header SpeexHeader *header = speex_packet_to_header((char *)op.packet, (int)op.bytes); if(nullptr == header) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg Speex file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg Speex file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotRecognizedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } else if(SPEEX_NB_MODES <= header->mode) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The Speex mode in the file “%@” is not supported."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file mode"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("This file may have been encoded with a newer version of Speex."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header); header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } const SpeexMode *mode = speex_lib_get_mode(header->mode); if(mode->bitstream_version != header->mode_bitstream_version) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The Speex version in the file “%@” is not supported."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file version"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("This file was encoded with a different version of Speex."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header); header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } // Initialize the decoder mSpeexDecoder = speex_decoder_init(mode); if(nullptr== mSpeexDecoder) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("Unable to initialize the Speex decoder."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Error initializing Speex decoder"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("An unknown error occurred."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header); header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_SAMPLING_RATE, &header->rate); mSpeexFramesPerOggPacket = (0 == header->frames_per_packet ? 1 : header->frames_per_packet); mExtraSpeexHeaderCount = (UInt32)header->extra_headers; // Initialize the speex bit-packing data structure speex_bits_init(&mSpeexBits); // Initialize the stereo mode mSpeexStereoState = speex_stereo_state_init(); if(2 == header->nb_channels) { SpeexCallback callback; callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = mSpeexStereoState; speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_HANDLER, &callback); } // Canonical Core Audio format mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; mFormat.mBitsPerChannel = 8 * sizeof(float); mFormat.mSampleRate = header->rate; mFormat.mChannelsPerFrame = (UInt32)header->nb_channels; mFormat.mBytesPerPacket = (mFormat.mBitsPerChannel / 8); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; // Set up the source format mSourceFormat.mFormatID = 'SPEE'; mSourceFormat.mSampleRate = header->rate; mSourceFormat.mChannelsPerFrame = (UInt32)header->nb_channels; switch(header->nb_channels) { case 1: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Mono); break; case 2: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo); break; } speex_header_free(header); header = nullptr; // Allocate the buffer list spx_int32_t speexFrameSize = 0; speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize); if(!mBufferList.Allocate(mFormat, (UInt32)speexFrameSize)) { if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, nullptr); speex_stereo_state_destroy(mSpeexStereoState); mSpeexStereoState = nullptr; speex_decoder_destroy(mSpeexDecoder); mSpeexDecoder = nullptr; speex_bits_destroy(&mSpeexBits); ogg_sync_destroy(&mOggSyncState); return false; } for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) mBufferList->mBuffers[i].mDataByteSize = 0; return true; }
static void gst_tarkindec_chain (GstPad * pad, GstData * _data) { GstBuffer *buf = GST_BUFFER (_data); TarkinDec *tarkindec; g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (buf != NULL); tarkindec = GST_TARKINDEC (gst_pad_get_parent (pad)); if (!tarkindec->setup) { GST_ELEMENT_ERROR (tarkindec, CORE, NEGOTATION, (NULL), ("decoder not initialized (input is not tarkin?)")); if (GST_IS_BUFFER (buf)) gst_buffer_unref (buf); else gst_pad_event_default (pad, GST_EVENT (buf)); return; } if (GST_IS_EVENT (buf)) { switch (GST_EVENT_TYPE (buf)) { case GST_EVENT_EOS: default: gst_pad_event_default (pad, GST_EVENT (buf)); break; } } else { gchar *data; gulong size; gchar *buffer; guchar *rgb; TarkinTime date; TarkinVideoLayerDesc *layer; /* data to decode */ data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); buffer = ogg_sync_buffer (&tarkindec->oy, size); memcpy (buffer, data, size); ogg_sync_wrote (&tarkindec->oy, size); if (ogg_sync_pageout (&tarkindec->oy, &tarkindec->og)) { ogg_stream_pagein (&tarkindec->os, &tarkindec->og); while (ogg_stream_packetout (&tarkindec->os, &tarkindec->op)) { if (tarkindec->op.e_o_s) break; if (tarkindec->nheader < 3) { /* 3 first packets to headerin */ tarkin_synthesis_headerin (&tarkindec->ti, &tarkindec->tc, &tarkindec->op); if (tarkindec->nheader == 2) { tarkin_synthesis_init (tarkindec->tarkin_stream, &tarkindec->ti); } tarkindec->nheader++; } else { tarkin_synthesis_packetin (tarkindec->tarkin_stream, &tarkindec->op); while (tarkin_synthesis_frameout (tarkindec->tarkin_stream, &rgb, 0, &date) == 0) { GstBuffer *outbuf; layer = &tarkindec->tarkin_stream->layer->desc; if (!GST_PAD_CAPS (tarkindec->srcpad)) { if (gst_pad_try_set_caps (tarkindec->srcpad, GST_CAPS_NEW ("tarkin_raw", "video/x-raw-rgb", "bpp", GST_PROPS_INT (24), "depth", GST_PROPS_INT (24), "endianness", GST_PROPS_INT (G_BYTE_ORDER), "red_mask", GST_PROPS_INT (0xff0000), "green_mask", GST_PROPS_INT (0xff00), "blue_mask", GST_PROPS_INT (0xff), "width", GST_PROPS_INT (layer->width), "height", GST_PROPS_INT (layer->height), "framerate", GST_PROPS_FLOAT (0.) /* FIXME!!! */ )) <= 0) { GST_ELEMENT_ERROR (tarkindec, CORE, NEGOTATION, (NULL), ("could not output format")); gst_buffer_unref (buf); return; } } outbuf = gst_buffer_new (); GST_BUFFER_DATA (outbuf) = rgb; GST_BUFFER_SIZE (outbuf) = layer->width * layer->height * 3; GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DONTFREE); gst_pad_push (tarkindec->srcpad, GST_DATA (outbuf)); tarkin_synthesis_freeframe (tarkindec->tarkin_stream, rgb); } } } } gst_buffer_unref (buf); } }
BOOL getogg_open(GETSND snd, UINT8 *ptr, UINT size) { __OV *ov; char *buffer; int bytes; int i; int result; snd->datptr = ptr; snd->datsize = size; ov = (__OV *)_MALLOC(sizeof(__OV), "__OV"); if (ov == NULL) { goto ovopn_err0; } ZeroMemory(ov, sizeof(__OV)); buffer = ogg_sync_buffer(&ov->oy, 4096); bytes = snd_read(snd, buffer, 4096); ogg_sync_wrote(&ov->oy, bytes); if (ogg_sync_pageout(&ov->oy, &ov->og) != 1) { TRACEOUT(("Input does not appear to be an Ogg bitstream.")); goto ovopn_err1; } ogg_stream_init(&ov->os, ogg_page_serialno(&ov->og)); vorbis_info_init(&ov->vi); vorbis_comment_init(&ov->vc); if (ogg_stream_pagein(&ov->os, &ov->og) < 0) { TRACEOUT(("Error reading first page of Ogg bitstream data.")); goto ovopn_err1; } if (ogg_stream_packetout(&ov->os, &ov->op) != 1) { TRACEOUT(("Error reading initial header packet.")); goto ovopn_err1; } if (vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op) < 0) { TRACEOUT(("This Ogg bitstream does not contain Vorbis audio data.")); goto ovopn_err1; } i = 0; while(i < 2) { while(i < 2) { result = ogg_sync_pageout(&ov->oy, &ov->og); if (result == 0) { break; } if (result == 1) { ogg_stream_pagein(&ov->os, &ov->og); while(i < 2) { result = ogg_stream_packetout(&ov->os, &ov->op); if (result == 0) { break; } if (result < 0) { TRACEOUT(("Corrupt secondary header. Exiting.")); goto ovopn_err1; } vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op); i++; } } } buffer = ogg_sync_buffer(&ov->oy, 4096); bytes = snd_read(snd, buffer, 4096); if ((bytes == 0) && (i < 2)) { TRACEOUT(("End of file before finding all Vorbis headers!")); return(-1); } ogg_sync_wrote(&ov->oy, bytes); } snd->snd = ov; snd->dec = (GSDEC)ogg_dec; snd->decend = ogg_decend; snd->samplingrate = ov->vi.rate; snd->channels = ov->vi.channels; snd->blocksize = 4096 * 2; snd->blocksamples = 4096 / ov->vi.channels; snd->bit = 16; vorbis_synthesis_init(&ov->vd, &ov->vi); vorbis_block_init(&ov->vd, &ov->vb); return(SUCCESS); ovopn_err1: ogg_sync_clear(&ov->oy); _MFREE(ov); ovopn_err0: return(FAILURE); }
static sf_count_t ogg_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn) { VORBIS_PRIVATE *vdata = psf->codec_data ; OGG_PRIVATE *odata = psf->container_data ; int len, samples, i = 0 ; float **pcm ; len = lens / psf->sf.channels ; while ((samples = vorbis_synthesis_pcmout (&vdata->vd, &pcm)) > 0) { if (samples > len) samples = len ; i += transfn (samples, ptr, i, psf->sf.channels, pcm) ; len -= samples ; /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read (&vdata->vd, samples) ; vdata->loc += samples ; if (len == 0) return i ; /* Is this necessary */ } goto start0 ; /* Jump into the nasty nest */ while (len > 0 && !odata->eos) { while (len > 0 && !odata->eos) { int result = ogg_sync_pageout (&odata->oy, &odata->og) ; if (result == 0) break ; /* need more data */ if (result < 0) { /* missing or corrupt data at this page position */ psf_log_printf (psf, "Corrupt or missing data in bitstream ; continuing...\n") ; } else { /* can safely ignore errors at this point */ ogg_stream_pagein (&odata->os, &odata->og) ; start0: while (1) { result = ogg_stream_packetout (&odata->os, &odata->op) ; if (result == 0) break ; /* need more data */ if (result < 0) { /* missing or corrupt data at this page position */ /* no reason to complain ; already complained above */ } else { /* we have a packet. Decode it */ if (vorbis_synthesis (&vdata->vb, &odata->op) == 0) /* test for success! */ vorbis_synthesis_blockin (&vdata->vd, &vdata->vb) ; /* **pcm is a multichannel float vector. In stereo, for example, pcm [0] is left, and pcm [1] is right. samples is the size of each channel. Convert the float values (-1.<=range<=1.) to whatever PCM format and write it out */ while ((samples = vorbis_synthesis_pcmout (&vdata->vd, &pcm)) > 0) { if (samples>len) samples = len ; i += transfn (samples, ptr, i, psf->sf.channels, pcm) ; len -= samples ; /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read (&vdata->vd, samples) ; vdata->loc += samples ; if (len == 0) return i ; /* Is this necessary */ } ; } } if (ogg_page_eos (&odata->og)) odata->eos = 1 ; } } if (!odata->eos) { char *buffer ; int bytes ; buffer = ogg_sync_buffer (&odata->oy, 4096) ; bytes = psf_fread (buffer, 1, 4096, psf) ; ogg_sync_wrote (&odata->oy, bytes) ; if (bytes == 0) odata->eos = 1 ; } } return i ; } /* ogg_read_sample */
/*! * \brief Create a new OGG/Vorbis filestream and set it up for reading. * \param fd Descriptor that points to on disk storage of the OGG/Vorbis data. * \return The new filestream. */ static struct cw_filestream *ogg_vorbis_open(FILE *fp) { int i; int bytes; int result; char **ptr; char *buffer; struct cw_filestream *tmp; if ((tmp = malloc(sizeof(struct cw_filestream)))) { memset(tmp, 0, sizeof(struct cw_filestream)); tmp->writing = 0; tmp->fp = fp; ogg_sync_init(&tmp->oy); buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, tmp->fp); ogg_sync_wrote(&tmp->oy, bytes); result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result != 1) { if (bytes < BLOCK_SIZE) cw_log(LOG_ERROR, "Run out of data... %d %s\n", errno, strerror(errno)); else cw_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); fclose(fp); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og)); vorbis_info_init(&tmp->vi); vorbis_comment_init(&tmp->vc); if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { cw_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { cw_log(LOG_ERROR, "Error reading initial header packet.\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { cw_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } i = 0; while (i < 2) { while (i < 2) { result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result == 0) break; if (result == 1) { ogg_stream_pagein(&tmp->os, &tmp->og); while (i < 2) { result = ogg_stream_packetout(&tmp->os,&tmp->op); if (result == 0) break; if (result < 0) { cw_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op); i++; } } } buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, tmp->fp); if (bytes == 0 && i < 2) { cw_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } ogg_sync_wrote(&tmp->oy, bytes); } ptr = tmp->vc.user_comments; while (*ptr) { cw_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr); ++ptr; } cw_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate); cw_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor); if (tmp->vi.channels != 1) { cw_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n"); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } if (tmp->vi.rate != 8000) { cw_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_block_clear(&tmp->vb); vorbis_dsp_clear(&tmp->vd); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } vorbis_synthesis_init(&tmp->vd, &tmp->vi); vorbis_block_init(&tmp->vd, &tmp->vb); if (cw_mutex_lock(&ogg_vorbis_lock)) { cw_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_block_clear(&tmp->vb); vorbis_dsp_clear(&tmp->vd); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } glistcnt++; cw_mutex_unlock(&ogg_vorbis_lock); cw_update_use_count(); } return tmp; }