Advertising
- Untitled
- Saturday, June 24th, 2006 at 10:36:41am MDT
- /***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id: speex.c,v 1.00 2006/02/18 20:22:03 lostlogic Exp $
- *
- * Copyright (C) 2006 Frederik M.J. Vestre
- * Based on vorbis.c codec interface:
- * Copyright (C) 2002 Bjørn Stenberg
- *
- * All files in this archive are subject to the GNU General Public License.
- * See the file COPYING in the source tree root for full license agreement.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
- #include "codeclib.h"
- // #include "Tremor/ivorbisfile.h"
- //#include "libspeex/speex/speex_bits.h"
- /*#include "libspeex/speex/speex_config_types.h"*/
- //#include "libspeex/speex/speex_types.h"
- #include "libogg/ogg/ogg.h"
- #include "libspeex/speex/speex.h"
- #include "libspeex/speex/speex_header.h"
- #include "libspeex/speex/speex_stereo.h"
- #include "libspeex/speex/speex_callbacks.h"
- #include "codeclib.h"
- #define MAX_FRAME_SIZE 2000
- #define CHUNKSIZE 1000
- #define SEEK_CHUNKSIZE 5000
- #include <stdio.h>
- CODEC_HEADER
- static struct codec_api *rb;
- /* Some standard functions and variables needed by Tremor */
- //int errno;
- size_t read_handler(void *ptr, size_t size, size_t nmemb, void *datasource)
- {
- (void)datasource;
- return rb->read_filebuf(ptr, nmemb*size);
- }
- int initial_seek_handler(void *datasource, ogg_int64_t offset, int whence)
- {
- (void)datasource;
- (void)offset;
- (void)whence;
- return -1;
- }
- int seek_handler(void *datasource, ogg_int64_t offset, int whence)
- {
- (void)datasource;
- if (whence == SEEK_CUR) {
- offset += rb->curpos;
- } else if (whence == SEEK_END) {
- offset += rb->filesize;
- }
- if (rb->seek_buffer(offset)) {
- return 0;
- }
- return -1;
- }
- //void get_more_data(ogg_sync_state *oy,struct codec_api *rb,char* buffer){
- void get_more_data(ogg_sync_state *oy,ogg_int64_t *curoffset,struct codec_api *rb){
- int bytes;
- char *buffer;
- buffer=(char *)ogg_sync_buffer(oy,1000);//CHUNKSIZE);
- bytes=rb->read_filebuf(buffer, sizeof(char)*1000);
- ogg_sync_wrote(oy,bytes);
- *curoffset+=bytes;
- }
- void get_more_data_2(ogg_sync_state *oy,ogg_int64_t *curoffset,struct codec_api *rb,ogg_int16_t datalen){
- int bytes;
- char *buffer;
- buffer=(char *)ogg_sync_buffer(oy,datalen);//CHUNKSIZE);
- bytes=rb->read_filebuf(buffer, sizeof(char)*datalen);
- ogg_sync_wrote(oy,bytes);
- *curoffset+=bytes;
- }
- /* The read/seek functions track absolute position within the stream */
- /* from the head of the stream, get the next page. boundary specifies
- if the function is allowed to fetch more data from the stream (and
- how much) or only use internally buffered data.
- boundary: -1) unbounded search
- 0) read no additional data; use cached only
- n) search for a new page beginning for n bytes
- return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
- n) found a page at absolute offset n
- */
- static ogg_int64_t get_next_page(ogg_sync_state *oy,ogg_page *og,ogg_int64_t *curoffset,
- ogg_int64_t boundary,struct codec_api *rb){
- ogg_int64_t localoffset=*curoffset;
- if(boundary>0)boundary+=*curoffset;
- while(1){
- long more;
- //if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
- more=ogg_sync_pageseek(oy,og);
- if(more<0){
- /* skipped n bytes */
- localoffset-=more;
- }else{
- if(more==0){
- /* send more paramedics */
- if(!boundary)return(-1);
- {
- long ret=1;
- ret=*curoffset;
- get_more_data(oy,curoffset,rb);
- LOGF("Gmbgnp:%d,%d,%d\n",ret,*curoffset,(*curoffset-ret));
- ret=*curoffset-ret;
- LOGF("Gmbgnpp:%d\n",ret);
- if(ret==0)return(-2);
- if(ret<0){
- LOGF("GmbgnRN:%d\n",ret);
- return(-3);
- }
- }
- }else{
- /* got a page. Return the offset at the page beginning,
- advance the internal offset past the page end */
- ogg_int64_t ret=localoffset;
- *curoffset=localoffset+more;
- return(ret);
- }
- }
- }
- }
- /* find the latest page beginning before the current stream cursor
- position. Much dirtier than the above as Ogg doesn't have any
- backward search linkage. no 'readp' as it will certainly have to
- read. */
- /* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */
- static ogg_int64_t get_prev_page(ogg_sync_state *oy,ogg_page *og,ogg_int64_t *curoffset,struct codec_api *rb){
- ogg_int64_t begin=*curoffset-1;
- ogg_int64_t end=begin;
- ogg_int64_t ret;
- ogg_int64_t offset=-1;
- while(offset==-1){
- begin-=2*CHUNKSIZE;
- if(begin<0){
- return -3;//to early
- }
- rb->seek_buffer(begin);
- ogg_sync_reset(oy);
- get_more_data_2(oy,curoffset,rb,CHUNKSIZE);//read data into the ogg stream
- ret=begin-*curoffset;
- LOGF("Sbb:%d,%d,%d,%d\n",begin,end,begin-*curoffset,*curoffset);
- *curoffset=begin;
- while(*curoffset<end){
- ret=get_next_page(oy,og,curoffset,end-*curoffset,rb);
- if(ret==-3) return(-3);
- if(ret<=0){
- break;
- }else if(*curoffset<end) {
- offset=ret;
- }
- }
- }
- if(end-offset<0){
- /* this shouldn't be possible */
- return(-4);
- }
- /* we have the offset. Actually snork and hold the page now */
- *curoffset=offset;
- rb->seek_buffer(*curoffset);
- ogg_sync_reset(oy);
- get_more_data_2(oy,curoffset,rb,end-*curoffset);//read data into the ogg stream
- ret=get_next_page(oy,og,curoffset,end-*curoffset,rb);
- if(ret<0){
- /* this shouldn't be possible */
- return(-4);
- }
- return(offset);
- }
- int speex_seek_page_granule(
- ogg_int64_t pos,
- ogg_int64_t curpos,
- ogg_sync_state *oy,
- ogg_int64_t *curbyteoffset,
- ogg_int64_t headerssize,
- ogg_int64_t stream_length,
- struct codec_api *rb
- ){
- ogg_int64_t curoffset;
- curoffset=*curbyteoffset;
- ogg_int64_t offset=0;
- ogg_page og={0,0,0,0};
- ogg_packet op={0,0,0,0,0,0};
- //#if 0
- if(abs(pos-curpos)>10000 && headerssize>0 && curoffset-headerssize>10000){
- //if seeking for more that 10sec,
- //headersize is known & more than 10kb is played,
- //try to guess a place to seek from the number of
- //bytes playe for this position, this works best when
- //the bitrate is relativly constant.
- curoffset=(int)(((float)(*curbyteoffset-headerssize)*(float)pos)/(float)curpos);
- ogg_int64_t toffset=toffset;
- rb->seek_buffer(curoffset);
- ogg_sync_reset(oy);
- offset=get_next_page(oy,&og,&curoffset,-1,rb);
- if(offset<0){//could not find new page,use old offset
- LOGF("Seek/guess/fault:%d->-<-%d,%d:%d,%d\n",curpos,pos,0,offset,toffset,stream_length);
- curoffset=*curbyteoffset;
- rb->seek_buffer(curoffset);
- ogg_sync_reset(oy);
- }else{
- if(ogg_page_granulepos(&og)==0&&pos>5000){
- LOGF("SEEK/guess/fault:%d->-<-%d,%d:%d,%d\n",curpos,ogg_page_granulepos(&og),pos,offset,toffset,stream_length);
- curoffset=*curbyteoffset;
- rb->seek_buffer(curoffset);
- ogg_sync_reset(oy);
- }else{
- LOGF("Seek/guess:%d->%d<-%d,%d:%d,%d\n",curpos,ogg_page_granulepos(&og),pos,offset,toffset,stream_length);
- curoffset=offset;
- curpos=ogg_page_granulepos(&og);
- }
- }
- }
- //#endif
- //which way do we want to seek?
- if(curpos>pos){//backwards
- LOGF("Sbw\n");
- while((offset=get_prev_page(oy,&og,&curoffset,rb))>0){
- LOGF("Gp:%d,%d,%d,%d,%d,%d\n",ogg_page_granulepos(&og),curoffset,offset,pos,pos-ogg_page_granulepos(&og),2);
- if(ogg_page_granulepos(&og)<pos){
- *curbyteoffset=curoffset;
- LOGF("GP:%d,%d,%d:%d=%d\n",ogg_page_granulepos(&og),curoffset,curpos-ogg_page_granulepos(&og),curpos-pos);
- return 1;
- }
- curoffset=offset;
- }
- LOGF("Srr:%d\n",offset);
- }else{//forwards
- LOGF("Sfw\n");
- while((offset=get_next_page(oy,&og,&curoffset,-1,rb))>0){
- LOGF("gp:%d,%d,%d,%d,%d,%d\n",ogg_page_granulepos(&og),curoffset,offset,pos,pos-ogg_page_granulepos(&og),2);
- if(ogg_page_granulepos(&og)>pos){
- LOGF("gP:%d,%d,%d:%d=%d\n",ogg_page_granulepos(&og),curoffset,curpos-ogg_page_granulepos(&og),curpos-pos);
- offset=get_prev_page(oy,&og,&curoffset,rb);
- *curbyteoffset=offset;
- return 1;
- }
- }
- }
- rb->seek_buffer(*curbyteoffset);
- ogg_sync_reset(oy);
- LOGF("Seek failed:%d\n",offset);
- rb->splash(HZ*2, true, "Seek failed");
- return -1;
- }
- int close_handler(void *datasource)
- {
- (void)datasource;
- return 0;
- }
- long tell_handler(void *datasource)
- {
- (void)datasource;
- return rb->curpos;
- }
- static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, int *rate, int *nframes, int *channels, SpeexStereoState *stereo, int *extra_headers)
- {
- void *st;
- const SpeexMode *mode;
- SpeexHeader *header;
- int modeID;
- SpeexCallback callback;
- header = speex_packet_to_header((char*)op->packet, op->bytes);
- if (!header)
- {
- rb->splash(HZ*5, true, "Can't read header");
- DEBUGF ("Cannot read header\n");
- return NULL;
- }
- if (header->mode >= SPEEX_NB_MODES)
- {
- rb->splash(HZ*5, true, "Mode does not (yet/any longer) exist in this version");
- DEBUGF ("Mode does not (yet/any longer) exist in this version\n");
- return NULL;
- }
- modeID = header->mode;
- mode = speex_lib_get_mode (modeID);
- if (header->speex_version_id > 1)
- {
- rb->splash(HZ*5, true, "Undecodeable bitstream");
- DEBUGF("Undecodeable bitstream");
- //fprintf (stderr, "This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", header->speex_version_id);
- return NULL;
- }
- if (mode->bitstream_version < header->mode_bitstream_version)
- {
- rb->splash(HZ*5, true,"Undecodeable bitstream2");
- DEBUGF("Undecodeable bitstream2");
- //fprintf (stderr, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n");
- return NULL;
- }
- if (mode->bitstream_version > header->mode_bitstream_version)
- {
- rb->splash(HZ*5, true,"Too old bitstream");
- DEBUGF("Too old bitstream");
- //fprintf (stderr, "The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n");
- return NULL;
- }
- st = speex_decoder_init(mode);
- if (!st)
- {
- rb->splash(HZ*5, true,"Decoder init failed");
- DEBUGF("Decoder init failed");
- return NULL;
- }
- speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
- speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
- if (*channels==-1)
- *channels = header->nb_channels;
- if (!(*channels==1))
- {
- callback.callback_id = SPEEX_INBAND_STEREO;
- callback.func = speex_std_stereo_request_handler;
- callback.data = stereo;
- speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
- }
- if (!*rate)
- *rate = header->rate;
- speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
- *nframes = header->frames_per_packet;
- if (*channels == 2) {
- rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
- } else if (*channels == 1) {
- rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_MONO);
- }
- *extra_headers = header->extra_headers;
- codec_free(header);
- return st;
- }
- #ifdef USE_IRAM
- extern char iramcopy[];
- extern char iramstart[];
- extern char iramend[];
- extern char iedata[];
- extern char iend[];
- #endif
- /* this is the codec entry point */
- enum codec_status codec_start(struct codec_api *api)
- {
- //printf("Codec start\n");
- //ov_callbacks callbacks;
- //OggVorbis_File vf;
- SpeexBits vf;
- //ogg_int32_t **pcm;
- int error;
- /*long n,bytes*/;
- //int current_section;
- int previous_section = -1;
- int eof;
- ogg_sync_state oy;
- //ogg_page *og;
- ogg_page og;//={0,0,0,0};
- ogg_packet op;
- ogg_stream_state os;
- ogg_int64_t page_granule=0, cur_granule=0;
- int enh_enabled;
- int nframes=2;
- //int print_bitrate=0;
- //int close_in=0;
- int eos=0;
- SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
- int channels=-1;
- int rate=0,samplerate=0;
- int extra_headers;
- int stream_init=0;
- int /*skip_samples=0,*/ page_nb_packets,frame_size,packet_count=0;
- int lookahead;
- int headerssize=-1;
- //float output[MAX_FRAME_SIZE];
- short output[MAX_FRAME_SIZE];
- enh_enabled = 1;
- void *st;
- ogg_int64_t cur_offset=0;
- //char msgbuf[80];
- // ogg_int64_t vf_offsets[2];
- // ogg_int64_t vf_dataoffsets;
- // ogg_uint32_t vf_serialnos;
- // ogg_int64_t vf_pcmlengths[2];
- rb = api;
- #ifdef USE_IRAM
- rb->memcpy(iramstart, iramcopy, iramend - iramstart);
- rb->memset(iedata, 0, iend - iedata);
- #endif
- //rb->configure(CODEC_DSP_ENABLE, (bool *)true);
- rb->configure(DSP_DITHER, (bool *)false);
- /* rb->configure(DSP_SET_SAMPLE_DEPTH, (short *)16);*/
- rb->configure(DSP_SET_SAMPLE_DEPTH, (long *)16);
- //rb->configure(DSP_SET_CLIP_MAX, (long *)((1 << 64)));
- // rb->configure(DSP_SET_CLIP_MIN, (long *)-((1 << 16)));
- /* rb->configure(DSP_SET_CLIP_MAX, (long *)());
- rb->configure(DSP_SET_CLIP_MIN, (long *)-(-32768));*/
- /* Note: These are sane defaults for these values. Perhaps
- * they should be set differently based on quality setting
- */
- /* The chunk size below is magic. If set any lower, resume
- * doesn't work properly (ov_raw_seek() does the wrong thing).
- */
- rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (char *)(1000));
- //printf("c1\n");
- /* We need to flush reserver memory every track load. */
- next_track:
- if (codec_init(rb)) {
- error = CODEC_ERROR;
- //printf("Initr\n");
- goto exit;
- }
- ogg_sync_init(&oy);
- samplerate=rb->id3->frequency; //get samplerate from metadata
- //parsing to support start offset
- speex_bits_init(&vf);
- eof = 0;
- while (!eof) {
- rb->yield();
- if (rb->stop_codec || rb->new_track)
- break;
- if (rb->seek_time) {//seek (seeks to the page before the position
- if(samplerate!=0){
- // int speex_seek_page_granule(ogg_int64_t /*granule_*/pos,ogg_sync_state *oy,ogg_int64_t *curoffset,ogg_int64_t stream_length,struct codec_api *rb){
- LOGF("Seek page:%d,%d,%d,%d\n",
- (rb->seek_time*samplerate)/1000,
- page_granule,
- (rb->id3->length*samplerate)/1000,
- rb->seek_time,
- (page_granule/samplerate)*1000,
- samplerate);
- speex_seek_page_granule(
- (rb->seek_time*samplerate)/1000,
- page_granule,
- &oy,
- &cur_offset,
- headerssize,
- (rb->id3->length*samplerate)/1000,
- rb
- );
- }
- /* if (ov_time_seek(&vf, rb->seek_time - 1)) {
- //rb->logf("ov_time_seek failed");
- }*/
- rb->seek_complete();
- }
- //char *data1,*data;
- int /*i,*/ j;
- next_page:
- //long nb_read;
- /*Get the ogg buffer for writing*/
- //char * buffer;
- get_more_data(&oy,&cur_offset,rb);
- // if(bytes<0){
- // DEBUGF("Decoding, read error\n");
- // error=CODEC_ERROR;
- // goto exit;
- // }
- //cur_offset+=bytes;
- //printf("Getbuf\n");
- /*Loop for all complete pages we got (most likely only one)*/
- while (ogg_sync_pageout(&oy, &og)==1)
- {
- int packet_no;
- if (stream_init == 0) {
- ogg_stream_init(&os, ogg_page_serialno(&og));
- stream_init = 1;
- }
- /*Add page to the bitstream*/
- ogg_stream_pagein(&os, &og);
- page_granule = ogg_page_granulepos(&og);
- page_nb_packets = ogg_page_packets(&og);
- cur_granule = page_granule;
- /*Extract all available packets*/
- packet_no=0;
- while (!eos && ogg_stream_packetout(&os, &op)==1)
- {
- /*If first packet, process as Speex header*/
- if (packet_count==0)
- {
- st = process_header(&op, enh_enabled, &frame_size, &samplerate, &nframes, &channels, &stereo, &extra_headers);
- speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
- if (!nframes)
- nframes=1;
- if (!st){
- error=CODEC_ERROR;
- goto exit;
- }
- rb->id3->vbr = true;
- //int tmp;
- rb->id3->frequency = samplerate;
- rb->configure(DSP_SET_FREQUENCY, (int *)samplerate);//short
- headerssize+=og.header_len+og.body_len;//Speex header in it's own page, add the whole page headersize
- //printf("Freq:%d,%d\n",rate,channels);
- //rb->configure(DSP_SWITCH_FREQUENCY, (bool *)true);//short
- } else if (packet_count<=1+extra_headers)
- {
- headerssize+=op.bytes;//add packet to headersize
- /* Ignore extra headers */
- } else {
- if(packet_count==2+extra_headers){
- if (rb->id3->offset) {
- rb->advance_buffer(rb->id3->offset);
- rb->seek_buffer(rb->id3->offset);
- cur_offset=rb->id3->offset;
- ogg_sync_reset(&oy);
- get_more_data(&oy,&cur_offset,rb);
- goto next_page;
- }
- }
- //int lost=0;
- packet_no++;
- /*End of stream condition*/
- if (op.e_o_s)
- eos=1;
- /*Copy Ogg packet to Speex bitstream*/
- speex_bits_read_from(&vf, (char*)op.packet, op.bytes);
- //for (i=0;i<op.bytes;i++)
- // printf ("%d,", (int)op.packet[i]);
- for (j=0;j!=nframes;j++)
- {
- int ret;
- /*Decode frame*/
- ret = speex_decode_int(st, &vf, output);
- /* printf("\nDecoded:");
- for (i=frame_size;i<frame_size*channels;i++)
- printf ("%d,", (short)output[i]);*/
- // printf("\n");
- if (ret==-1)
- break;
- if (ret==-2)
- {
- //printf ("Decoding error: corrupted stream?\n");
- break;
- }
- if (speex_bits_remaining(&vf)<0)
- {
- //printf ("Decoding overflow: corrupted stream?\n");
- break;
- }
- if (channels==2)
- speex_decode_stereo_int(output, frame_size, &stereo);//vector rand hack
- speex_decoder_ctl(st, SPEEX_GET_BITRATE, &rate);
- rb->id3->bitrate=(rate/1000);//k(bps)
- {
- //int frame_offset = 0;
- int new_frame_size = frame_size;
- if (new_frame_size>0)
- {
- /*fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);*/
- //fwrite(output+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
- //audio_size+=sizeof(short)*new_frame_size*channels;
- // printf("Inspbuf%d,%d>",sizeof(spx_int16_t) * new_frame_size*channels,new_frame_size,channels/*,frame_offset*/);
- // int i;
- // for (i=0;i<frame_size*channels;i++)
- // printf ("%d,", (short)output[i]);
- // for (i=0;i<frame_size*channels;i++)
- // printf ("%d,", (short)output[i]);
- //write((const char*)output,sizeof(short),new_frame_size*channels);
- //printf("<\n");
- while (!rb->pcmbuf_insert_split((const char*)output,(const char*)output+new_frame_size,sizeof(short) * new_frame_size*channels)) {
- rb->sleep(1);
- }
- cur_granule+=new_frame_size/2;/*2 bytes/sample*/
- rb->set_offset((long)cur_offset);
- rb->set_elapsed((samplerate==0)?0:cur_granule*1000/samplerate);
- }
- //return CODEC_OK;
- }
- }
- }
- packet_count++;
- }
- }
- }
- if (rb->request_next_track()) {
- /* Clean things up for the next track */
- /* vf.dataoffsets = NULL;
- vf.offsets = NULL;
- vf.serialnos = NULL;
- vf.pcmlengths = NULL;*/
- speex_bits_reset(&vf);//ov_clear(&vf);
- if (stream_init)
- ogg_stream_clear(&os);
- ogg_sync_clear(&oy);
- ogg_sync_init(&oy);
- previous_section = -1;
- // stereo = SPEEX_STEREO_STATE_INIT;
- goto next_track;
- }
- error = CODEC_OK;
- exit:
- speex_bits_destroy(&vf);
- if (stream_init)
- ogg_stream_clear(&os);
- ogg_sync_clear(&oy);
- return error;
- }
advertising
Update the Post
Either update this post and resubmit it with changes, or make a new post.
You may also comment on this post.
Please note that information posted here will expire by default in one month. If you do not want it to expire, please set the expiry time above. If it is set to expire, web search engines will not be allowed to index it prior to it expiring. Items that are not marked to expire will be indexable by search engines. Be careful with your passwords. All illegal activities will be reported and any information will be handed over to the authorities, so be good.