Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 1 | /************************************************************************** |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * |
| 9 | * Copyright (C) 2006 Frederik M.J. Vestre |
| 10 | * Based on vorbis.c codec interface: |
| 11 | * Copyright (C) 2002 Bjrn Stenberg |
| 12 | * |
| 13 | * All files in this archive are subject to the GNU General Public License. |
| 14 | * See the file COPYING in the source tree root for full license agreement. |
| 15 | * |
| 16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 17 | * KIND, either express or implied. |
| 18 | * |
| 19 | ***************************************************************************/ |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 20 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 21 | #include "libspeex/speex/ogg.h" |
| 22 | #include "libspeex/speex/speex.h" |
Dan Everton | 7bf62e8 | 2007-02-10 11:44:26 +0000 | [diff] [blame] | 23 | #include "libspeex/speex/speex_callbacks.h" |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 24 | #include "libspeex/speex/speex_header.h" |
| 25 | #include "libspeex/speex/speex_stereo.h" |
Magnus Holmgren | 2c7030b | 2007-02-10 13:33:29 +0000 | [diff] [blame] | 26 | #include "libspeex/speex/speex_config_types.h" |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 27 | #include "codeclib.h" |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 28 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 29 | #define MAX_FRAME_SIZE 2000 |
| 30 | #define CHUNKSIZE 10000 /*2kb*/ |
| 31 | #define SEEK_CHUNKSIZE 7*CHUNKSIZE |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 32 | |
| 33 | //#define LOGF(...) |
| 34 | |
| 35 | CODEC_HEADER |
| 36 | |
| 37 | struct codec_api *rb; |
| 38 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 39 | int get_more_data(spx_ogg_sync_state *oy,struct codec_api *rb) |
| 40 | { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 41 | int bytes; |
| 42 | char *buffer; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 43 | |
| 44 | buffer = (char *)spx_ogg_sync_buffer(oy,CHUNKSIZE); |
| 45 | |
| 46 | bytes = rb->read_filebuf(buffer, sizeof(char)*CHUNKSIZE); |
| 47 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 48 | spx_ogg_sync_wrote(oy,bytes); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 49 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 50 | return bytes; |
| 51 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 52 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 53 | /* The read/seek functions track absolute position within the stream */ |
| 54 | |
| 55 | static spx_int64_t get_next_page(spx_ogg_sync_state *oy,spx_ogg_page *og, |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 56 | spx_int64_t boundary,struct codec_api *rb) |
| 57 | { |
| 58 | spx_int64_t localoffset = rb->curpos; |
| 59 | long more; |
| 60 | long ret; |
| 61 | |
| 62 | if (boundary > 0) |
| 63 | boundary += rb->curpos; |
| 64 | |
| 65 | while (1) { |
| 66 | more = spx_ogg_sync_pageseek(oy,og); |
| 67 | |
| 68 | if (more < 0) { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 69 | /* skipped n bytes */ |
| 70 | localoffset-=more; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 71 | } else { |
| 72 | if (more == 0) { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 73 | /* send more paramedics */ |
| 74 | if(!boundary)return(-1); |
| 75 | { |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 76 | ret = get_more_data(oy,rb); |
| 77 | if (ret == 0) |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 78 | return(-2); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 79 | |
| 80 | if (ret < 0) |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 81 | return(-3); |
| 82 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 83 | } else { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 84 | /* got a page. Return the offset at the page beginning, |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 85 | advance the internal offset past the page end */ |
| 86 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 87 | spx_int64_t ret=localoffset; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 88 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 89 | return(ret); |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 95 | static spx_int64_t seek_backwards(spx_ogg_sync_state *oy, spx_ogg_page *og, |
| 96 | spx_int64_t wantedpos, |
| 97 | struct codec_api *rb) |
| 98 | { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 99 | spx_int64_t crofs; |
| 100 | spx_int64_t *curoffset=&crofs; |
| 101 | *curoffset=rb->curpos; |
| 102 | spx_int64_t begin=*curoffset; |
| 103 | spx_int64_t end=begin; |
| 104 | spx_int64_t ret; |
| 105 | spx_int64_t offset=-1; |
| 106 | spx_int64_t avgpagelen=-1; |
| 107 | spx_int64_t lastgranule=-1; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 108 | |
| 109 | short time = -1; |
| 110 | |
| 111 | while (offset == -1) { |
| 112 | |
| 113 | begin -= SEEK_CHUNKSIZE; |
| 114 | |
| 115 | if (begin < 0) { |
| 116 | if (time < 0) { |
| 117 | begin = 0; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 118 | time++; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 119 | } else { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 120 | LOGF("Can't seek that early:%d\n",begin); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 121 | return -3; /* too early */ |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 122 | } |
| 123 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 124 | |
| 125 | *curoffset = begin; |
| 126 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 127 | rb->seek_buffer(*curoffset); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 128 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 129 | spx_ogg_sync_reset(oy); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 130 | |
| 131 | lastgranule = -1; |
| 132 | |
| 133 | while (*curoffset < end) { |
| 134 | ret = get_next_page(oy,og,end-*curoffset,rb); |
| 135 | |
| 136 | if (ret > 0) { |
| 137 | if (lastgranule != -1) { |
| 138 | if (avgpagelen < 0) |
| 139 | avgpagelen = (spx_ogg_page_granulepos(og)-lastgranule); |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 140 | else |
| 141 | avgpagelen=((spx_ogg_page_granulepos(og)-lastgranule) |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 142 | + avgpagelen) / 2; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 143 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 144 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 145 | lastgranule=spx_ogg_page_granulepos(og); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 146 | |
| 147 | if ((lastgranule - (avgpagelen/4)) < wantedpos && |
| 148 | (lastgranule + avgpagelen + (avgpagelen/4)) > wantedpos) { |
| 149 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 150 | /*wanted offset found Yeay!*/ |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 151 | |
| 152 | /*LOGF("GnPagefound:%d,%d,%d,%d\n",ret, |
| 153 | lastgranule,wantedpos,avgpagelen);*/ |
| 154 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 155 | return ret; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 156 | |
| 157 | } else if (lastgranule > wantedpos) { /*too late, seek more*/ |
| 158 | if (offset != -1) { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 159 | LOGF("Toolate, returnanyway:%d,%d,%d,%d\n", |
| 160 | ret,lastgranule,wantedpos,avgpagelen); |
| 161 | return ret; |
| 162 | } |
| 163 | break; |
| 164 | } else{ /*if (spx_ogg_page_granulepos(&og)<wantedpos)*/ |
| 165 | /*too early*/ |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 166 | offset = ret; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 167 | continue; |
| 168 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 169 | } else if (ret == -3) |
| 170 | return(-3); |
| 171 | else if (ret<=0) |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 172 | break; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 173 | else if (*curoffset < end) { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 174 | /*this should not be possible*/ |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 175 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 176 | //LOGF("Seek:get_earlier_page:Offset:not_cached by granule:"\"%d,%d,%d,%d,%d\n",*curoffset,end,begin,wantedpos,curpos); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 177 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 178 | offset=ret; |
| 179 | } |
| 180 | } |
| 181 | } |
| 182 | return -1; |
| 183 | } |
| 184 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 185 | int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos, |
| 186 | spx_ogg_sync_state *oy, |
| 187 | spx_int64_t headerssize, |
| 188 | struct codec_api *rb) |
| 189 | { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 190 | /* TODO: Someone may want to try to implement seek to packet, |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 191 | instead of just to page (should be more accurate, not be any |
| 192 | faster) */ |
| 193 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 194 | spx_int64_t crofs; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 195 | spx_int64_t *curbyteoffset = &crofs; |
| 196 | *curbyteoffset = rb->curpos; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 197 | spx_int64_t curoffset; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 198 | curoffset = *curbyteoffset; |
| 199 | spx_int64_t offset = 0; |
| 200 | spx_ogg_page og = {0,0,0,0}; |
| 201 | spx_int64_t avgpagelen = -1; |
| 202 | spx_int64_t lastgranule = -1; |
| 203 | |
| 204 | if(abs(pos-curpos)>10000 && headerssize>0 && curoffset-headerssize>10000) { |
| 205 | /* if seeking for more that 10sec, |
| 206 | headersize is known & more than 10kb is played, |
| 207 | try to guess a place to seek from the number of |
| 208 | bytes playe for this position, this works best when |
| 209 | the bitrate is relativly constant. |
| 210 | */ |
| 211 | |
| 212 | curoffset = (int)((((float)(*curbyteoffset-(headerssize)) * |
| 213 | (float)pos)/(float)curpos)*0.98); |
| 214 | |
| 215 | if (curoffset < 0) |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 216 | curoffset=0; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 217 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 218 | //spx_int64_t toffset=curoffset; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 219 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 220 | rb->seek_buffer(curoffset); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 221 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 222 | spx_ogg_sync_reset(oy); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 223 | |
| 224 | offset = get_next_page(oy,&og,-1,rb); |
| 225 | |
| 226 | if (offset < 0) { /* could not find new page,use old offset */ |
| 227 | LOGF("Seek/guess/fault:%d->-<-%d,%d:%d,%d,%d\n", |
| 228 | curpos,0,pos,offset,0, |
| 229 | rb->curpos,/*stream_length*/0); |
| 230 | |
| 231 | curoffset = *curbyteoffset; |
| 232 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 233 | rb->seek_buffer(curoffset); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 234 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 235 | spx_ogg_sync_reset(oy); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 236 | } else { |
| 237 | if (spx_ogg_page_granulepos(&og) == 0 && pos > 5000) { |
| 238 | LOGF("SEEK/guess/fault:%d->-<-%d,%d:%d,%d,%d\n", |
| 239 | curpos,spx_ogg_page_granulepos(&og),pos, |
| 240 | offset,0,rb->curpos,/*stream_length*/0); |
| 241 | |
| 242 | curoffset = *curbyteoffset; |
| 243 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 244 | rb->seek_buffer(curoffset); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 245 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 246 | spx_ogg_sync_reset(oy); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 247 | } else { |
| 248 | curoffset = offset; |
| 249 | curpos = spx_ogg_page_granulepos(&og); |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 250 | } |
| 251 | } |
| 252 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 253 | |
| 254 | /* which way do we want to seek? */ |
| 255 | |
| 256 | if (curpos > pos) { /* backwards */ |
| 257 | offset = seek_backwards(oy,&og,pos,rb); |
| 258 | |
| 259 | if (offset > 0) { |
| 260 | *curbyteoffset = curoffset; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 261 | return 1; |
| 262 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 263 | } else { /* forwards */ |
| 264 | |
| 265 | while ( (offset = get_next_page(oy,&og,-1,rb)) > 0) { |
| 266 | if (lastgranule != -1) { |
| 267 | if (avgpagelen < 0) |
| 268 | avgpagelen = (spx_ogg_page_granulepos(&og) - lastgranule); |
| 269 | else |
| 270 | avgpagelen = ((spx_ogg_page_granulepos(&og) - lastgranule) |
| 271 | + avgpagelen) / 2; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 272 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 273 | |
| 274 | lastgranule = spx_ogg_page_granulepos(&og); |
| 275 | |
| 276 | if ( ((lastgranule - (avgpagelen/4)) < pos && ( lastgranule + |
| 277 | avgpagelen + (avgpagelen / 4)) > pos) || |
| 278 | lastgranule > pos) { |
| 279 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 280 | /*wanted offset found Yeay!*/ |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 281 | |
| 282 | *curbyteoffset = offset; |
| 283 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 284 | return offset; |
| 285 | } |
| 286 | } |
| 287 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 288 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 289 | rb->seek_buffer(*curbyteoffset); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 290 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 291 | spx_ogg_sync_reset(oy); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 292 | |
| 293 | LOGF("Seek failed:%d\n", offset); |
| 294 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 295 | rb->splash(HZ*2, true, "Seek failed"); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 296 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 297 | return -1; |
| 298 | } |
| 299 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 300 | static void *process_header(spx_ogg_packet *op, |
| 301 | int enh_enabled, |
| 302 | int *frame_size, |
| 303 | int *rate, |
| 304 | int *nframes, |
| 305 | int *channels, |
| 306 | SpeexStereoState *stereo, |
| 307 | int *extra_headers |
| 308 | ) |
| 309 | { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 310 | void *st; |
| 311 | const SpeexMode *mode; |
| 312 | SpeexHeader *header; |
| 313 | int modeID; |
| 314 | SpeexCallback callback; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 315 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 316 | header = speex_packet_to_header((char*)op->packet, op->bytes); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 317 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 318 | if (!header){ |
| 319 | DEBUGF ("Cannot read header\n"); |
| 320 | return NULL; |
| 321 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 322 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 323 | if (header->mode >= SPEEX_NB_MODES){ |
| 324 | DEBUGF ("Mode does not exist\n"); |
| 325 | return NULL; |
| 326 | } |
| 327 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 328 | modeID = header->mode; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 329 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 330 | mode = speex_lib_get_mode (modeID); |
| 331 | |
| 332 | if (header->speex_version_id > 1) { |
| 333 | DEBUGF("Undecodeable bitstream"); |
| 334 | return NULL; |
| 335 | } |
| 336 | |
| 337 | if (mode->bitstream_version < header->mode_bitstream_version){ |
| 338 | DEBUGF("Undecodeable bitstream, newer bitstream"); |
| 339 | return NULL; |
| 340 | } |
| 341 | |
| 342 | if (mode->bitstream_version > header->mode_bitstream_version){ |
| 343 | DEBUGF("Too old bitstream"); |
| 344 | return NULL; |
| 345 | } |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 346 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 347 | st = speex_decoder_init(mode); |
| 348 | if (!st){ |
| 349 | DEBUGF("Decoder init failed"); |
| 350 | return NULL; |
| 351 | } |
| 352 | speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled); |
| 353 | speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size); |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 354 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 355 | if (*channels==-1) |
| 356 | *channels = header->nb_channels; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 357 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 358 | if (!(*channels==1)){ |
| 359 | callback.callback_id = SPEEX_INBAND_STEREO; |
| 360 | callback.func = speex_std_stereo_request_handler; |
| 361 | callback.data = stereo; |
| 362 | speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback); |
| 363 | } |
| 364 | if (!*rate) |
| 365 | *rate = header->rate; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 366 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 367 | speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate); |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 368 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 369 | *nframes = header->frames_per_packet; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 370 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 371 | if (*channels == 2) { |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 372 | rb->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 373 | } else if (*channels == 1) { |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 374 | rb->configure(DSP_SET_STEREO_MODE, STEREO_MONO); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 375 | } |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 376 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 377 | *extra_headers = header->extra_headers; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 378 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 379 | codec_free(header); |
| 380 | return st; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 381 | } |
| 382 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 383 | /* this is the codec entry point */ |
Dan Everton | c22e29f | 2007-02-09 10:20:27 +0000 | [diff] [blame] | 384 | enum codec_status codec_main(void) |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 385 | { |
| 386 | SpeexBits vf; |
| 387 | int error; |
| 388 | int eof; |
| 389 | spx_ogg_sync_state oy; |
| 390 | spx_ogg_page og; |
| 391 | spx_ogg_packet op; |
| 392 | spx_ogg_stream_state os; |
| 393 | spx_int64_t page_granule=0, cur_granule=0; |
| 394 | int enh_enabled; |
| 395 | int nframes=2; |
| 396 | int eos=0; |
| 397 | SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; |
| 398 | int channels=-1; |
| 399 | int rate=0,samplerate=0; |
| 400 | int extra_headers; |
| 401 | int stream_init=0; |
| 402 | int page_nb_packets,frame_size,packet_count=0; |
| 403 | int lookahead; |
| 404 | int headerssize=-1; |
| 405 | unsigned long strtoffset; |
| 406 | short output[MAX_FRAME_SIZE]; |
| 407 | enh_enabled = 1; |
| 408 | void *st=0; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 409 | int j; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 410 | rb = ci; |
| 411 | |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 412 | //rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, CHUNKSIZE*128); |
| 413 | //rb->configure(DSP_DITHER, false); |
| 414 | rb->configure(DSP_SET_SAMPLE_DEPTH, 16); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 415 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 416 | /* We need to flush reserver memory every track load. */ |
| 417 | next_track: |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 418 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 419 | if (codec_init()) { |
| 420 | error = CODEC_ERROR; |
| 421 | goto exit; |
| 422 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 423 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 424 | strtoffset=rb->id3->offset; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 425 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 426 | while (!*rb->taginfo_ready && !rb->stop_codec) |
| 427 | rb->sleep(1); |
| 428 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 429 | spx_ogg_sync_init(&oy); |
| 430 | spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 431 | |
| 432 | samplerate = rb->id3->frequency; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 433 | codec_set_replaygain(rb->id3); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 434 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 435 | speex_bits_init(&vf); |
| 436 | |
| 437 | eof = 0; |
| 438 | while (!eof) { |
| 439 | rb->yield(); |
| 440 | if (rb->stop_codec || rb->new_track) |
| 441 | break; |
| 442 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 443 | /*seek (seeks to the page before the position) */ |
| 444 | if (rb->seek_time) { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 445 | if(samplerate!=0&&packet_count>1){ |
| 446 | LOGF("Speex seek page:%d,%d,%d,%d\n", |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 447 | ((spx_int64_t)rb->seek_time/1000) * |
| 448 | (spx_int64_t)samplerate, |
| 449 | page_granule, rb->seek_time, |
| 450 | (page_granule/samplerate)*1000, samplerate); |
| 451 | |
| 452 | speex_seek_page_granule(((spx_int64_t)rb->seek_time/1000) * |
| 453 | (spx_int64_t)samplerate, |
| 454 | page_granule, &oy, headerssize, rb); |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 455 | rb->seek_complete(); |
| 456 | } |
| 457 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 458 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 459 | next_page: |
| 460 | /*Get the ogg buffer for writing*/ |
| 461 | if(get_more_data(&oy,rb)<1){/*read error*/ |
| 462 | error=CODEC_ERROR; |
| 463 | goto done; |
| 464 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 465 | |
| 466 | /* Loop for all complete pages we got (most likely only one) */ |
| 467 | while (spx_ogg_sync_pageout(&oy, &og) == 1) { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 468 | int packet_no; |
| 469 | if (stream_init == 0) { |
| 470 | spx_ogg_stream_init(&os,spx_ogg_page_serialno(&og)); |
| 471 | stream_init = 1; |
| 472 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 473 | |
| 474 | /* Add page to the bitstream */ |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 475 | spx_ogg_stream_pagein(&os, &og); |
| 476 | |
| 477 | page_granule = spx_ogg_page_granulepos(&og); |
| 478 | page_nb_packets = spx_ogg_page_packets(&og); |
| 479 | |
| 480 | cur_granule = page_granule; |
| 481 | |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 482 | /* Extract all available packets */ |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 483 | packet_no=0; |
| 484 | |
| 485 | while (!eos && spx_ogg_stream_packetout(&os, &op)==1){ |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 486 | /* If first packet, process as Speex header */ |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 487 | if (packet_count==0){ |
| 488 | st = process_header(&op, enh_enabled, &frame_size, |
| 489 | &samplerate,&nframes, &channels, |
| 490 | &stereo, &extra_headers); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 491 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 492 | speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 493 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 494 | if (!nframes) |
| 495 | nframes=1; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 496 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 497 | if (!st){ |
| 498 | error=CODEC_ERROR; |
| 499 | goto exit; |
| 500 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 501 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 502 | rb->id3->vbr = true; |
| 503 | rb->id3->frequency = samplerate; |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 504 | rb->configure(DSP_SET_FREQUENCY, rb->id3->frequency); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 505 | |
| 506 | /* Speex header in its own page, add the whole page |
| 507 | headersize */ |
| 508 | headerssize+=og.header_len+og.body_len; |
| 509 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 510 | } else if (packet_count<=1+extra_headers){ |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 511 | /* add packet to headersize */ |
| 512 | headerssize += op.bytes; |
| 513 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 514 | /* Ignore extra headers */ |
| 515 | } else { |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 516 | if (packet_count <= 2+extra_headers) { |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 517 | if (strtoffset) { |
| 518 | rb->seek_buffer(strtoffset); |
| 519 | spx_ogg_sync_reset(&oy); |
| 520 | packet_count++; |
| 521 | goto next_page; |
| 522 | } |
| 523 | } |
| 524 | packet_no++; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 525 | |
| 526 | if (op.e_o_s) /* End of stream condition */ |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 527 | eos=1; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 528 | |
| 529 | /* Copy Ogg packet to Speex bitstream */ |
| 530 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 531 | speex_bits_read_from(&vf, (char*)op.packet, op.bytes); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 532 | |
| 533 | for (j = 0; j != nframes; j++){ |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 534 | int ret; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 535 | |
| 536 | /* Decode frame */ |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 537 | ret = speex_decode_int(st, &vf, output); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 538 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 539 | if (ret==-1) |
| 540 | break; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 541 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 542 | if (ret==-2) |
| 543 | break; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 544 | |
| 545 | if (speex_bits_remaining(&vf) < 0) |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 546 | break; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 547 | |
Dan Everton | 69c40d7 | 2007-02-10 06:11:30 +0000 | [diff] [blame] | 548 | if (channels == 2) |
| 549 | speex_decode_stereo_int(output, frame_size, &stereo); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 550 | |
Dan Everton | 69c40d7 | 2007-02-10 06:11:30 +0000 | [diff] [blame] | 551 | int new_frame_size = frame_size; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 552 | |
Dan Everton | 69c40d7 | 2007-02-10 06:11:30 +0000 | [diff] [blame] | 553 | if (new_frame_size>0){ |
| 554 | rb->pcmbuf_insert((const char*)output, NULL, |
| 555 | new_frame_size); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 556 | |
Dan Everton | 69c40d7 | 2007-02-10 06:11:30 +0000 | [diff] [blame] | 557 | /* 2 bytes/sample */ |
| 558 | cur_granule += new_frame_size / 2; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 559 | |
Dan Everton | 69c40d7 | 2007-02-10 06:11:30 +0000 | [diff] [blame] | 560 | rb->set_offset((long)rb->curpos); |
| 561 | |
| 562 | rb->set_elapsed( (samplerate==0) ? 0 : |
| 563 | cur_granule*1000/samplerate); |
| 564 | } |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 565 | } |
| 566 | } |
| 567 | packet_count++; |
| 568 | } |
| 569 | } |
| 570 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 571 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 572 | done: |
| 573 | if (rb->request_next_track()) { |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 574 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 575 | /* Clean things up for the next track */ |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 576 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 577 | speex_decoder_destroy(st); |
| 578 | speex_bits_reset(&vf); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 579 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 580 | if (stream_init==1) |
| 581 | spx_ogg_stream_reset(&os); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 582 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 583 | spx_ogg_sync_reset(&oy); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 584 | |
| 585 | cur_granule = stream_init = rate = samplerate = headerssize |
| 586 | = packet_count = eos = 0; |
| 587 | |
| 588 | stereo.balance =stereo.smooth_left = stereo.smooth_right = 1; |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 589 | stereo.e_ratio = .5; |
| 590 | stereo.reserved1=stereo.reserved2= 0; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 591 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 592 | goto next_track; |
| 593 | } |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 594 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 595 | error = CODEC_OK; |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 596 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 597 | exit: |
| 598 | speex_bits_destroy(&vf); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 599 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 600 | if (stream_init) |
| 601 | spx_ogg_stream_destroy(&os); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 602 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 603 | spx_ogg_sync_destroy(&oy); |
Dave Chapman | 0abfe9f | 2007-02-09 18:10:24 +0000 | [diff] [blame] | 604 | |
Dan Everton | ebc58c9 | 2007-02-09 10:06:53 +0000 | [diff] [blame] | 605 | return error; |
| 606 | } |