void alogg_seek_rel_secs_ogg(ALOGG_OGG *ogg, int sec) { double s = sec; s += ov_time_tell(&(ogg->vf)); ov_time_seek(&(ogg->vf), s); }
const int oggDecoder::getTime( ) { return int(ov_time_tell( decoder )); }
/* process the Ogg from start_time to end_time, passing the decoded data to the supplied callback if the start and end time are the same value, the entire OGG is processed from the specified start time until the end of the file buffer_samples is the internally allocated buffer size to use */ int alogg_process_ogg(ALOGG_OGG * ogg, void(*callback)(void * buf, int nsamples, int stereo), int buffer_samples, double start_time, double end_time) { int size_done, i, all_done = 0; int ret = 0; int bits; char * buffer; char * buffer_p; double current_pos; int buffer_bytes = buffer_samples * 2; unsigned long num_samples_left = 0, num_samples_decoded; char all = 0; //Is set to nonzero if the OGG is to be processed until the end of the file buffer = malloc(buffer_bytes); if(!buffer) { return 0; } current_pos = ov_time_tell(&(ogg->vf)); ov_time_seek(&(ogg->vf), start_time); if(start_time == end_time) { //If the calling function intends to process the OGG until the end of the file all = 1; } else { num_samples_left = ((end_time - start_time) * alogg_get_wave_freq_ogg(ogg)) * (ogg->stereo ? 2 : 1); //The number of samples to pass to the callback function } bits = alogg_get_wave_bits_ogg(ogg); //The number of bits per sample (expected to be 16) if(bits != 16) { //Unexpected sample size free(buffer); return 0; } while(!all_done) { buffer_p = buffer; for(i = 0; i < buffer_samples; i++) { //Fill buffer with silent audio ((unsigned short *)(buffer_p))[i] = 0x8000; } size_done = num_samples_decoded = 0; /* read samples from Ogg Vorbis file */ for(i = buffer_bytes; i > 0; i -= size_done) { /* decode */ size_done = ov_read(&(ogg->vf), buffer_p, i, alogg_endianess, 2, 0, &(ogg->current_section)); /* check if the decoding was not successful */ if(size_done < 0) { if(size_done == OV_HOLE) { size_done = 0; } else { all_done = 2; } } else if(size_done == 0) { //No more samples all_done = 1; ret = 1; break; // playback finished so get out of loop } num_samples_decoded += size_done / 2; //Keep track of how many samples have been decoded since the last callback buffer_p += size_done; } if(all || (num_samples_decoded < num_samples_left)) { //If all of the newly decoded samples are to be passed to the callback callback(buffer, buffer_samples, ogg->stereo); num_samples_left -= num_samples_decoded; } else { //If the samples passed to the callback will be limited to the given time range callback(buffer, num_samples_left, ogg->stereo); all_done = 3; ret = 1; } } free(buffer); ov_time_seek(&(ogg->vf), current_pos); return ret; }
CBaseDec::RetCode COggDec::Decoder(FILE *in, const int OutputFd, State* const state, CAudioMetaData* meta_data, time_t* const time_played, unsigned int* const secondsToSkip) { OggVorbis_File vf; int bitstream, rval; ogg_int64_t jumptime=0; Status=OK; mOutputFd = OutputFd; mState = state; mTimePlayed=time_played; if (!Open(in, &vf)) { Status=DATA_ERR; return Status; } SetMetaData(&vf, meta_data); audioDecoder->PrepareClipPlay(ov_info(&vf,0)->channels, ov_info(&vf,0)->rate, 16, 1); /* up and away ... */ mSlotSize = MAX_OUTPUT_SAMPLES * 2 * ov_info(&vf,0)->channels; for(int i = 0 ; i < DECODE_SLOTS ; i++) { if ((mPcmSlots[i] = (char*) malloc(mSlotSize)) == NULL) { for (int j = i - 1; j >= 0; j--) { free(mPcmSlots[j]); } Status=INTERNAL_ERR; return Status; } mSlotTime[i]=0; } mReadSlot=mWriteSlot=0; pthread_t OutputThread; if (pthread_create (&OutputThread, 0, OutputDsp, (void *) this) != 0 ) { for(int i = 0 ; i < DECODE_SLOTS ; i++) free(mPcmSlots[i]); Status=INTERNAL_ERR; return Status; } int bytes; State oldstate=*state; do { // clear buffer on state change if(oldstate!=*state) { if(*state!=PAUSE && (*state!=PLAY || oldstate!=PAUSE)) { mWriteSlot=mReadSlot=0; oldstate=*state; } } while((mWriteSlot+1)%DECODE_SLOTS == mReadSlot) { usleep(10000); } bytes=0; if(mSeekable) #ifdef DBOX mSlotTime[mWriteSlot] = ov_time_tell(&vf); #else mSlotTime[mWriteSlot] = (ogg_int64_t)(1000 * ov_time_tell(&vf)); #endif do { #ifdef DBOX rval = ov_read(&vf, mPcmSlots[mWriteSlot]+bytes, mSlotSize-bytes, &bitstream); #else rval = ov_read(&vf, mPcmSlots[mWriteSlot]+bytes, mSlotSize-bytes, 0, 2, 1, &bitstream); #endif bytes+=rval; //printf("Ogg: read buf 0x%x size %d / %d done %d\n", mPcmSlots[mWriteSlot]+bytes, rval, mSlotSize, bytes); } while (rval > 0 && bytes !=mSlotSize); //printf("\n"); int actMSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip * 1000 : MSECS_TO_SKIP; if((*state==FF || *state==REV) && mSeekable ) { if((std::abs((long int)( mSlotTime[mWriteSlot]-jumptime))) > MSECS_TO_PLAY) { if(*state==FF) { ov_time_seek_page(&vf, mSlotTime[mWriteSlot] + actMSecsToSkip); jumptime=mSlotTime[mWriteSlot]+actMSecsToSkip; } else { if(mSlotTime[mWriteSlot] < actMSecsToSkip) { ov_time_seek(&vf, 0); *state=PLAY; } else { ov_time_seek_page(&vf, mSlotTime[mWriteSlot] - actMSecsToSkip); jumptime=mSlotTime[mWriteSlot]-actMSecsToSkip; } } } if (*secondsToSkip != 0) { *state=PLAY; } } if(bytes == mSlotSize) mWriteSlot=(mWriteSlot+1) % DECODE_SLOTS; } while (rval != 0 && *state!=STOP_REQ && Status==OK); //printf("COggDec::Decoder: read loop stop, rval %d state %d status %d\n", rval, *state, Status); // let buffer run dry while(rval==0 && *state!=STOP_REQ && Status==OK && mReadSlot != mWriteSlot) usleep(100000); //pthread_cancel(OutputThread); //printf("COggDec::Decoder: OutputThread join\n"); Status = WRITE_ERR; pthread_join(OutputThread, NULL); //printf("COggDec::Decoder: OutputThread join done\n"); audioDecoder->StopClip(); for(int i = 0 ; i < DECODE_SLOTS ; i++) free(mPcmSlots[i]); /* clean up the junk from the party */ ov_clear(&vf); /* and drive home ;) */ return Status; }
int vorbis_get_current_pos() { return ov_time_tell(&track); }
int alogg_get_pos_secs_ogg(ALOGG_OGG *ogg) { return (int)ov_time_tell(&(ogg->vf)); }
bool ImportOGG(wxWindow * parent, wxString Filename, WaveTrack ** channels[], int *numChannels, DirManager * dirManager) { wxFFile file(Filename, "rb"); if (!file.IsOpened()) { // No need for a message box, it's done automatically (but how?) return false; } OggVorbis_File vf; int err = ov_open(file.fp(), &vf, NULL, 0); if (err < 0) { wxString message; switch (err) { case OV_EREAD: message = _("Media read error"); break; case OV_ENOTVORBIS: message = _("Not an Ogg Vorbis file"); break; case OV_EVERSION: message = _("Vorbis version mismatch"); break; case OV_EBADHEADER: message = _("Invalid Vorbis bitstream header"); break; case OV_EFAULT: message = _("Internal logic fault"); break; } wxMessageBox(message); file.Close(); return false; } /* -1 is for the current logical bitstream */ vorbis_info *vi = ov_info(&vf, -1); *numChannels = vi->channels; *channels = new WaveTrack *[*numChannels]; int c; for (c = 0; c < *numChannels; c++) { (*channels)[c] = new WaveTrack(dirManager); (*channels)[c]->SetRate(vi->rate); (*channels)[c]->SetSampleFormat(int16Sample); switch (c) { case 0: (*channels)[c]->SetChannel(VTrack::LeftChannel); break; case 1: (*channels)[c]->SetChannel(VTrack::RightChannel); break; default: (*channels)[c]->SetChannel(VTrack::MonoChannel); } } if (*numChannels == 2) (*channels)[0]->SetLinked(true); wxProgressDialog *progress = NULL; wxYield(); wxStartTimer(); /* The number of bytes to get from the codec in each run */ #define CODEC_TRANSFER_SIZE 4096 const int bufferSize = 1048576; short *mainBuffer = new short[CODEC_TRANSFER_SIZE]; short **buffers = new short *[*numChannels]; for (int i = 0; i < *numChannels; i++) { buffers[i] = new short[bufferSize]; } /* determine endianness (clever trick courtesy of Nicholas Devillard, * (http://www.eso.org/~ndevilla/endian/) */ int testvar = 1, endian; if(*(char *)&testvar) endian = 0; // little endian else endian = 1; // big endian /* number of samples currently in each channel's buffer */ int bufferCount = 0; bool cancelled = false; long bytesRead = 0; long samplesRead = 0; int bitstream = 0; do { bytesRead = ov_read(&vf, (char *) mainBuffer, CODEC_TRANSFER_SIZE, endian, 2, // word length (2 for 16 bit samples) 1, // signed &bitstream); samplesRead = bytesRead / *numChannels / sizeof(short); if (samplesRead + bufferCount > bufferSize) { for (c = 0; c < *numChannels; c++) (*channels)[c]->Append((samplePtr)buffers[c], int16Sample, bufferCount); bufferCount = 0; } /* Un-interleave */ for (int s = 0; s < samplesRead; s++) for (c = 0; c < *numChannels; c++) buffers[c][s + bufferCount] = mainBuffer[s * (*numChannels) + c]; bufferCount += samplesRead; if (!progress && wxGetElapsedTime(false) > 500) progress = new wxProgressDialog(_("Import"), _("Importing Ogg Vorbis File..."), 1000, parent, wxPD_CAN_ABORT | wxPD_REMAINING_TIME | wxPD_AUTO_HIDE); if (progress) cancelled = !progress->Update(ov_time_tell(&vf) * 1000 / ov_time_total(&vf, bitstream)); } while (!cancelled && bytesRead != 0 && bitstream == 0); /* ...the rest is de-allocation */ ov_clear(&vf); file.Detach(); // so that it doesn't try to close the file (ov_clear() // did that already) delete[]mainBuffer; for (c = 0; c < *numChannels; c++) delete[]buffers[c]; delete[]buffers; if (progress) delete progress; if (cancelled) { for (c = 0; c < *numChannels; c++) delete(*channels)[c]; delete[] * channels; return false; } return true; }
static void ogg_play_task(mp_callback_func cb) { long ret = 0; int current_section = 0; double time_seek_to = 0; vorbis_info *vi; struct snd_device *sound_dev; int *processed_pcm; double song_time; PE_DBG_PRINTF("MusicEngine: ==> ogg_play_task()! \n"); sound_dev = (struct snd_device*)dev_get_by_type(NULL, HLD_DEV_TYPE_SND); processed_pcm = (int*)ogg_file->processed_pcm_buff; if (ov_open(ogg_file->file, &ogg_file->vf, NULL, 0) < 0) { PE_DBG_PRINTF("MusicEngine: ogg_play_task() ov_open failed! \n"); #ifdef ENABLE_PE_CACHE pe_cache_close(ogg_cache_id); // 这个ogg_cache_id是在play_file时打开 ogg_cache_id = -1; #else fclose(ogg_file->file); #endif //FREE(processed_pcm); osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_UNSUCCESSFUL); return; } else { PE_DBG_PRINTF("MusicEngine: ov_opened \n"); { vorbis_info *vi = ov_info(&ogg_file->vf, -1); if (!vi) { PE_DBG_PRINTF("MusicEngine: ov_info failed!\n"); ov_clear(&ogg_file->vf); osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_UNSUCCESSFUL); return; } ogg_file->samplerate = vi->rate; ogg_file->channel = vi->channels; PE_DBG_PRINTF("\nBitstream is %d channel, %ldHz\n", vi->channels, vi->rate); song_time = ov_time_total(&ogg_file->vf, -1); if (song_time <= 0) { PE_DBG_PRINTF("MusicEngine: ov_info failed!\n"); ov_clear(&ogg_file->vf); osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_UNSUCCESSFUL); } } osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_SUCCESS); } //all work success, we can start to play while (ogg_file->command != OGG_CMD_STOP) { if (ogg_file->seek_to != 0) { time_seek_to = ov_time_tell(&ogg_file->vf); time_seek_to = time_seek_to + (ogg_file->seek_to * 1000); if (time_seek_to < 0) { time_seek_to = 0; } else if (time_seek_to > song_time) { time_seek_to = song_time; } ret = ov_time_seek(&ogg_file->vf, time_seek_to); if (ret < 0) { //seek failed } osal_task_dispatch_off(); ogg_file->seek_to = 0; osal_task_dispatch_on(); } if (ogg_file->command == OGG_CMD_NONE) { ret = ov_read(&ogg_file->vf, (void *)ogg_file->pcm_out_buff, 2304, ¤t_section); if (ret == 0) { PE_DBG_PRINTF("file end!\n"); //EOF we need call back osal_task_dispatch_off(); if (ogg_file->command != OGG_CMD_STOP) { ogg_file->command = OGG_CMD_WAIT_FOR_STOP; } osal_task_dispatch_on(); cb(MP_MUSIC_PLAYBACK_END, 0); osal_task_sleep(10); } else if (ret < 0) { PE_DBG_PRINTF("error!!!\n"); /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ osal_task_dispatch_off(); if (ogg_file->command != OGG_CMD_STOP) { ogg_file->command = OGG_CMD_WAIT_FOR_STOP; } osal_task_dispatch_on(); cb(MP_MUSIC_PLAYBACK_END, 0); osal_task_sleep(10); } else { /* we don't bother dealing with sample rate changes, etc, but you'll have to*/ process_ogg_pcm(sound_dev, ret, processed_pcm); } } else { osal_task_sleep(10); } } ov_clear(&ogg_file->vf); ogg_avoid_under_run = 0; snd_io_control(sound_dev, SND_CC_MUTE, 0); snd_stop(sound_dev); //FREE(processed_pcm); osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_TASK_EXIT); // task结束,发出EXIT消息 PE_DBG_PRINTF("MusicEngine: <== ogg_play_task()! \n"); }
/* * Change position in the file. */ void OGG_Seek ( ogg_seek_t type, double offset ) { double pos; /* Position in file (in seconds). */ double total; /* Length of file (in seconds). */ /* Check if the file is seekable. */ if ( ov_seekable( &ovFile ) == 0 ) { Com_Printf( "OGG_Seek: file is not seekable.\n" ); return; } /* Get file information. */ pos = ov_time_tell( &ovFile ); total = ov_time_total( &ovFile, -1 ); switch ( type ) { case ABS: if ( ( offset >= 0 ) && ( offset <= total ) ) { if ( ov_time_seek( &ovFile, offset ) != 0 ) { Com_Printf( "OGG_Seek: could not seek.\n" ); } else { Com_Printf( "%0.2f -> %0.2f of %0.2f.\n", pos, offset, total ); } } else { Com_Printf( "OGG_Seek: invalid offset.\n" ); } break; case REL: if ( ( pos + offset >= 0 ) && ( pos + offset <= total ) ) { if ( ov_time_seek( &ovFile, pos + offset ) != 0 ) { Com_Printf( "OGG_Seek: could not seek.\n" ); } else { Com_Printf( "%0.2f -> %0.2f of %0.2f.\n", pos, pos + offset, total ); } } else { Com_Printf( "OGG_Seek: invalid offset.\n" ); } break; } }
float cOggDecoder::getCurrentTime() { return ov_time_tell(&oggStream); }
/* this is the codec entry point */ enum codec_status codec_main(void) { ov_callbacks callbacks; OggVorbis_File vf; ogg_int32_t **pcm; int error; long n; int current_section; int previous_section; int eof; ogg_int64_t vf_offsets[2]; ogg_int64_t vf_dataoffsets; ogg_uint32_t vf_serialnos; ogg_int64_t vf_pcmlengths[2]; ci->configure(DSP_SET_SAMPLE_DEPTH, 24); if (codec_init()) { error = CODEC_ERROR; goto exit; } ogg_malloc_init(); #if defined(CPU_ARM) || defined(CPU_COLDFIRE) || defined(CPU_MIPS) if (setjmp(rb_jump_buf) != 0) { /* malloc failed; skip to next track */ error = CODEC_ERROR; goto done; } #endif next_track: while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); /* Create a decoder instance */ callbacks.read_func = read_handler; callbacks.seek_func = initial_seek_handler; callbacks.tell_func = tell_handler; callbacks.close_func = close_handler; /* Open a non-seekable stream */ error = ov_open_callbacks(ci, &vf, NULL, 0, callbacks); /* If the non-seekable open was successful, we need to supply the missing * data to make it seekable. This is a hack, but it's reasonable since we * don't want to run the whole file through the buffer before we start * playing. Using Tremor's seekable open routine would cause us to do * this, so we pretend not to be seekable at first. Then we fill in the * missing fields of vf with 1) information in ci->id3, and 2) info * obtained by Tremor in the above ov_open call. * * Note that this assumes there is only ONE logical Vorbis bitstream in our * physical Ogg bitstream. This is verified in metadata.c, well before we * get here. */ if (!error) { ogg_free(vf.offsets); ogg_free(vf.dataoffsets); ogg_free(vf.serialnos); vf.offsets = vf_offsets; vf.dataoffsets = &vf_dataoffsets; vf.serialnos = &vf_serialnos; vf.pcmlengths = vf_pcmlengths; vf.offsets[0] = 0; vf.offsets[1] = ci->id3->filesize; vf.dataoffsets[0] = vf.offset; vf.pcmlengths[0] = 0; vf.pcmlengths[1] = ci->id3->samples; vf.serialnos[0] = vf.current_serialno; vf.callbacks.seek_func = seek_handler; vf.seekable = 1; vf.end = ci->id3->filesize; vf.ready_state = OPENED; vf.links = 1; } else { DEBUGF("Vorbis: ov_open failed: %d", error); error = CODEC_ERROR; goto done; } if (ci->id3->offset) { ci->advance_buffer(ci->id3->offset); ov_raw_seek(&vf, ci->id3->offset); ci->set_elapsed(ov_time_tell(&vf)); ci->set_offset(ov_raw_tell(&vf)); } previous_section = -1; eof = 0; while (!eof) { ci->yield(); if (ci->stop_codec || ci->new_track) break; if (ci->seek_time) { if (ov_time_seek(&vf, ci->seek_time - 1)) { //ci->logf("ov_time_seek failed"); } ci->seek_complete(); } /* Read host-endian signed 24-bit PCM samples */ n = ov_read_fixed(&vf, &pcm, 1024, ¤t_section); /* Change DSP and buffer settings for this bitstream */ if (current_section != previous_section) { if (!vorbis_set_codec_parameters(&vf)) { error = CODEC_ERROR; goto done; } else { previous_section = current_section; } } if (n == 0) { eof = 1; } else if (n < 0) { DEBUGF("Vorbis: Error decoding frame\n"); } else { ci->pcmbuf_insert(pcm[0], pcm[1], n); ci->set_offset(ov_raw_tell(&vf)); ci->set_elapsed(ov_time_tell(&vf)); } } error = CODEC_OK; done: #if 0 /* defined(SIMULATOR) */ { size_t bufsize; void* buf = ci->codec_get_buffer(&bufsize); DEBUGF("Vorbis: Memory max: %u\n", get_max_size(buf)); } #endif if (ci->request_next_track()) { /* Clean things up for the next track */ vf.dataoffsets = NULL; vf.offsets = NULL; vf.serialnos = NULL; vf.pcmlengths = NULL; ov_clear(&vf); goto next_track; } exit: ogg_malloc_destroy(); return error; }
long VorbisDecoder::position() { if (!m_data->initialized) return -1; double oggpos = ov_time_tell(m_data->vf); return (long)(oggpos*1000.0); }
double getPosition() { double pos = ov_time_tell(oggStream); return pos * 1000.0; }
float OggWrapper::getTime() const { return static_cast<float>(ov_time_tell(ovFile_)); }
int alogg_get_pos_msecs_ogg(ALOGG_OGG *ogg) { return (int)(ov_time_tell(&(ogg->vf)) * 1000); }
int main(){ OggVorbis_File ov; int i,ret; ogg_int64_t pcmlength; double timelength; char *bigassbuffer; int dummy; #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */ _setmode( _fileno( stdin ), _O_BINARY ); #endif /* open the file/pipe on stdin */ if(ov_open_callbacks(stdin,&ov,NULL,-1,OV_CALLBACKS_NOCLOSE)<0){ fprintf(stderr,"Could not open input as an OggVorbis file.\n\n"); exit(1); } if(ov_seekable(&ov)){ /* to simplify our own lives, we want to assume the whole file is stereo. Verify this to avoid potentially mystifying users (pissing them off is OK, just don't confuse them) */ for(i=0;i<ov.links;i++){ vorbis_info *vi=ov_info(&ov,i); if(vi->channels!=2){ fprintf(stderr,"Sorry; right now seeking_test can only use Vorbis files\n" "that are entirely stereo.\n\n"); exit(1); } } /* because we want to do sample-level verification that the seek does what it claimed, decode the entire file into memory */ pcmlength=ov_pcm_total(&ov,-1); timelength=ov_time_total(&ov,-1); bigassbuffer=malloc(pcmlength*2); /* w00t */ i=0; while(i<pcmlength*2){ int ret=ov_read(&ov,bigassbuffer+i,pcmlength*2-i,1,1,1,&dummy); if(ret<0)continue; if(ret){ i+=ret; }else{ pcmlength=i/2; } fprintf(stderr,"\rloading.... [%ld left] ", (long)(pcmlength*2-i)); } { ogg_int64_t length=ov.end; fprintf(stderr,"\rtesting raw seeking to random places in %ld bytes....\n", (long)length); for(i=0;i<1000;i++){ ogg_int64_t val=(double)rand()/RAND_MAX*length; fprintf(stderr,"\r\t%d [raw position %ld]... ",i,(long)val); ret=ov_raw_seek(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } _verify(&ov,val,-1,-1.,pcmlength,bigassbuffer); } } fprintf(stderr,"\r"); { fprintf(stderr,"testing pcm page seeking to random places in %ld samples....\n", (long)pcmlength); for(i=0;i<1000;i++){ ogg_int64_t val=(double)rand()/RAND_MAX*pcmlength; fprintf(stderr,"\r\t%d [pcm position %ld]... ",i,(long)val); ret=ov_pcm_seek_page(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } _verify(&ov,-1,val,-1.,pcmlength,bigassbuffer); } } fprintf(stderr,"\r"); { fprintf(stderr,"testing pcm exact seeking to random places in %ld samples....\n", (long)pcmlength); for(i=0;i<1000;i++){ ogg_int64_t val=(double)rand()/RAND_MAX*pcmlength; fprintf(stderr,"\r\t%d [pcm position %ld]... ",i,(long)val); ret=ov_pcm_seek(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } if(ov_pcm_tell(&ov)!=val){ fprintf(stderr,"Declared position didn't perfectly match request: %ld != %ld\n", (long)val,(long)ov_pcm_tell(&ov)); exit(1); } _verify(&ov,-1,val,-1.,pcmlength,bigassbuffer); } } fprintf(stderr,"\r"); { fprintf(stderr,"testing time page seeking to random places in %f seconds....\n", timelength); for(i=0;i<1000;i++){ double val=(double)rand()/RAND_MAX*timelength; fprintf(stderr,"\r\t%d [time position %f]... ",i,val); ret=ov_time_seek_page(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } _verify(&ov,-1,-1,val,pcmlength,bigassbuffer); } } fprintf(stderr,"\r"); { fprintf(stderr,"testing time exact seeking to random places in %f seconds....\n", timelength); for(i=0;i<1000;i++){ double val=(double)rand()/RAND_MAX*timelength; fprintf(stderr,"\r\t%d [time position %f]... ",i,val); ret=ov_time_seek(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } if(ov_time_tell(&ov)<val-1 || ov_time_tell(&ov)>val+1){ fprintf(stderr,"Declared position didn't perfectly match request: %f != %f\n", val,ov_time_tell(&ov)); exit(1); } _verify(&ov,-1,-1,val,pcmlength,bigassbuffer); } } fprintf(stderr,"\r \nOK.\n\n"); }else{ fprintf(stderr,"Standard input was not seekable.\n"); } ov_clear(&ov); return 0; }
unsigned long alogg_get_pos_msecs_ogg_ul(ALOGG_OGG *ogg) { return (unsigned long)(ov_time_tell(&(ogg->vf)) * 1000); }
int OggImportFileHandle::Import(TrackFactory *trackFactory, Track ***outTracks, int *outNumTracks, Tags *tags) { wxASSERT(mFile->IsOpened()); CreateProgress(); //Number of streams used may be less than mVorbisFile->links, //but this way bitstream matches array index. mChannels = new WaveTrack **[mVorbisFile->links]; int i,c; for (i = 0; i < mVorbisFile->links; i++) { //Stream is not used if (mStreamUsage[i] == 0) { //This is just a padding to keep bitstream number and //array indices matched. mChannels[i] = NULL; continue; } vorbis_info *vi = ov_info(mVorbisFile, i); mChannels[i] = new WaveTrack *[vi->channels]; for (c = 0; c < vi->channels; c++) { mChannels[i][c] = trackFactory->NewWaveTrack(int16Sample, vi->rate); if (vi->channels == 2) { switch (c) { case 0: mChannels[i][c]->SetChannel(Track::LeftChannel); mChannels[i][c]->SetLinked(true); break; case 1: mChannels[i][c]->SetChannel(Track::RightChannel); break; } } else { mChannels[i][c]->SetChannel(Track::MonoChannel); } } } /* The number of bytes to get from the codec in each run */ #define CODEC_TRANSFER_SIZE 4096 /* The number of samples to read between calls to the callback. * Balance between responsiveness of the GUI and throughput of import. */ #define SAMPLES_PER_CALLBACK 100000 short *mainBuffer = new short[CODEC_TRANSFER_SIZE]; /* determine endianness (clever trick courtesy of Nicholas Devillard, * (http://www.eso.org/~ndevilla/endian/) */ int testvar = 1, endian; if(*(char *)&testvar) endian = 0; // little endian else endian = 1; // big endian /* number of samples currently in each channel's buffer */ int updateResult = eProgressSuccess; long bytesRead = 0; long samplesRead = 0; int bitstream = 0; int samplesSinceLastCallback = 0; // You would think that the stream would already be seeked to 0, and // indeed it is if the file is legit. But I had several ogg files on // my hard drive that have malformed headers, and this added call // causes them to be read correctly. Otherwise they have lots of // zeros inserted at the beginning ov_pcm_seek(mVorbisFile, 0); do { /* get data from the decoder */ bytesRead = ov_read(mVorbisFile, (char *) mainBuffer, CODEC_TRANSFER_SIZE, endian, 2, // word length (2 for 16 bit samples) 1, // signed &bitstream); if (bytesRead == OV_HOLE) { wxFileName f(mFilename); wxLogError(wxT("Ogg Vorbis importer: file %s is malformed, ov_read() reported a hole"), f.GetFullName().c_str()); /* http://lists.xiph.org/pipermail/vorbis-dev/2001-February/003223.html * is the justification for doing this - best effort for malformed file, * hence the message. */ continue; } else if (bytesRead < 0) { /* Malformed Ogg Vorbis file. */ /* TODO: Return some sort of meaningful error. */ wxLogError(wxT("Ogg Vorbis importer: ov_read() returned error %i"), bytesRead); break; } samplesRead = bytesRead / mVorbisFile->vi[bitstream].channels / sizeof(short); /* give the data to the wavetracks */ if (mStreamUsage[bitstream] != 0) { for (c = 0; c < mVorbisFile->vi[bitstream].channels; c++) mChannels[bitstream][c]->Append((char *)(mainBuffer + c), int16Sample, samplesRead, mVorbisFile->vi[bitstream].channels); } samplesSinceLastCallback += samplesRead; if (samplesSinceLastCallback > SAMPLES_PER_CALLBACK) { updateResult = mProgress->Update(ov_time_tell(mVorbisFile), ov_time_total(mVorbisFile, bitstream)); samplesSinceLastCallback -= SAMPLES_PER_CALLBACK; } } while (updateResult == eProgressSuccess && bytesRead != 0); delete[]mainBuffer; int res = updateResult; if (bytesRead < 0) res = eProgressFailed; if (res == eProgressFailed || res == eProgressCancelled) { for (i = 0; i < mVorbisFile->links; i++) { if (mChannels[i]) { for(c = 0; c < mVorbisFile->vi[bitstream].channels; c++) { if (mChannels[i][c]) delete mChannels[i][c]; } delete[] mChannels[i]; } } delete[] mChannels; return res; } *outNumTracks = 0; for (int s = 0; s < mVorbisFile->links; s++) { if (mStreamUsage[s] != 0) *outNumTracks += mVorbisFile->vi[s].channels; } *outTracks = new Track *[*outNumTracks]; int trackindex = 0; for (i = 0; i < mVorbisFile->links; i++) { if (mChannels[i]) { for (c = 0; c < mVorbisFile->vi[i].channels; c++) { mChannels[i][c]->Flush(); (*outTracks)[trackindex++] = mChannels[i][c]; } delete[] mChannels[i]; } } delete[] mChannels; //\todo { Extract comments from each stream? } if (mVorbisFile->vc[0].comments > 0) { tags->Clear(); for (c = 0; c < mVorbisFile->vc[0].comments; c++) { wxString comment = UTF8CTOWX(mVorbisFile->vc[0].user_comments[c]); wxString name = comment.BeforeFirst(wxT('=')); wxString value = comment.AfterFirst(wxT('=')); if (name.Upper() == wxT("DATE") && !tags->HasTag(TAG_YEAR)) { long val; if (value.Length() == 4 && value.ToLong(&val)) { name = TAG_YEAR; } } tags->SetTag(name, value); } } return res; }
int OggStream::getCurrentMS() const { int r = (int)ov_time_tell(const_cast<OggVorbis_File*>(&_vorbisFile)); return r; }
static gboolean vorbis_play (InputPlayback * playback, const gchar * filename, VFSFile * file, gint start_time, gint stop_time, gboolean pause) { if (file == NULL) return FALSE; vorbis_info *vi; OggVorbis_File vf; gint last_section = -1; ReplayGainInfo rg_info; gfloat pcmout[PCM_BUFSIZE*sizeof(float)], **pcm; gint bytes, channels, samplerate, br; gchar * title = NULL; seek_value = (start_time > 0) ? start_time : -1; stop_flag = FALSE; memset(&vf, 0, sizeof(vf)); gboolean error = FALSE; if (ov_open_callbacks (file, & vf, NULL, 0, vfs_is_streaming (file) ? vorbis_callbacks_stream : vorbis_callbacks) < 0) { error = TRUE; goto play_cleanup; } vi = ov_info(&vf, -1); if (vi->channels > 2) goto play_cleanup; br = vi->bitrate_nominal; channels = vi->channels; samplerate = vi->rate; playback->set_params (playback, br, samplerate, channels); if (!playback->output->open_audio(FMT_FLOAT, samplerate, channels)) { error = TRUE; goto play_cleanup; } if (pause) playback->output->pause (TRUE); vorbis_update_replaygain(&vf, &rg_info); playback->output->set_replaygain_info (& rg_info); playback->set_pb_ready(playback); /* * Note that chaining changes things here; A vorbis file may * be a mix of different channels, bitrates and sample rates. * You can fetch the information for any section of the file * using the ov_ interface. */ while (1) { if (stop_time >= 0 && playback->output->written_time () >= stop_time) goto DRAIN; g_mutex_lock (seek_mutex); if (stop_flag) { g_mutex_unlock (seek_mutex); break; } if (seek_value >= 0) { ov_time_seek (& vf, (double) seek_value / 1000); playback->output->flush (seek_value); seek_value = -1; g_cond_signal (seek_cond); } g_mutex_unlock (seek_mutex); gint current_section = last_section; bytes = ov_read_float(&vf, &pcm, PCM_FRAMES, ¤t_section); if (bytes == OV_HOLE) continue; if (bytes <= 0) { DRAIN: while (playback->output->buffer_playing ()) g_usleep (10000); break; } bytes = vorbis_interleave_buffer (pcm, bytes, channels, pcmout); { /* try to detect when metadata has changed */ vorbis_comment * comment = ov_comment (& vf, -1); const gchar * new_title = (comment == NULL) ? NULL : vorbis_comment_query (comment, "title", 0); if (new_title != NULL && (title == NULL || strcmp (title, new_title))) { g_free (title); title = g_strdup (new_title); playback->set_tuple (playback, get_tuple_for_vorbisfile (& vf, filename)); } } if (current_section <= last_section) { /* * The info struct is different in each section. vf * holds them all for the given bitstream. This * requests the current one */ vi = ov_info(&vf, -1); if (vi->channels > 2) goto stop_processing; if (vi->rate != samplerate || vi->channels != channels) { samplerate = vi->rate; channels = vi->channels; while (playback->output->buffer_playing()) g_usleep(1000); playback->output->close_audio(); if (!playback->output->open_audio(FMT_FLOAT, vi->rate, vi->channels)) { error = TRUE; goto stop_processing; } playback->output->flush(ov_time_tell(&vf) * 1000); vorbis_update_replaygain(&vf, &rg_info); playback->output->set_replaygain_info (& rg_info); /* audio reopened */ } } playback->output->write_audio (pcmout, bytes); stop_processing: if (current_section <= last_section) { playback->set_params (playback, br, samplerate, channels); last_section = current_section; } } /* main loop */ g_mutex_lock (seek_mutex); stop_flag = TRUE; g_cond_signal (seek_cond); /* wake up any waiting request */ g_mutex_unlock (seek_mutex); playback->output->close_audio (); play_cleanup: ov_clear(&vf); g_free (title); return ! error; }
double OggVorbisMusic::getPosition() const { if (!file.isOpen()) return 0; return ov_time_tell(&const_cast<OggVorbis_File&>(vorbisFile)); }
static void* player_thread(void* _minfo) { ogg_t* minfo = (ogg_t*) _minfo; log_debug("ogg player started"); long current_position_in_ms = 0; long previous_position_in_ms = -1; long guard_position_in_ms = -1; el_bool playing = el_false; post_event(minfo->client_notification, AUDIO_READY, current_position_in_ms); audio_event_t *event; event = audio_event_fifo_dequeue(minfo->player_control); while (event->state != INTERNAL_CMD_DESTROY) { audio_state_t event_state = event->state; long event_position = event->position_in_ms; audio_event_destroy(event); switch (event_state) { case INTERNAL_CMD_LOAD_FILE: { playing = el_false; if (minfo->is_open) { ov_clear(&minfo->vf); fclose(minfo->fh); aodev_close(minfo->ao_handle); } minfo->fh = fopen(minfo->file_or_url, "rb"); if (minfo->fh != NULL) { if (ov_open_callbacks(minfo->fh , &minfo->vf, NULL, 0, OV_CALLBACKS_NOCLOSE) < 0) { fclose(minfo->fh); post_event(minfo->client_notification, AUDIO_NOT_SUPPORTED, -1); minfo->is_open = el_false; } else { minfo->is_open = el_true; minfo->can_seek = ov_seekable(&minfo->vf); minfo->length = (long) (ov_time_total(&minfo->vf, -1) * 1000.0); psem_post(minfo->length_set); minfo->current_section = 0; vorbis_info* vi = ov_info(&minfo->vf, -1); aodev_set_format(minfo->ao_handle, 16, vi->rate, vi->channels); aodev_set_endian(minfo->ao_handle, AO_FMT_LITTLE); aodev_open(minfo->ao_handle); } } else { post_event(minfo->client_notification, AUDIO_IO_ERROR, -1); minfo->is_open = el_false; } current_position_in_ms = 0; guard_position_in_ms = -1; log_debug("Stream initialized"); } break; case INTERNAL_CMD_LOAD_URL: { } break; case INTERNAL_CMD_SEEK: { ov_time_seek_lap(&minfo->vf, ((double) event_position / 1000.0)); } break; case INTERNAL_CMD_PLAY: { playing = el_true; } break; case INTERNAL_CMD_PAUSE: { playing = el_false; } break; case INTERNAL_CMD_GUARD: { guard_position_in_ms = event_position; } break; case INTERNAL_CMD_SET_VOLUME: { double scale = ((double) event_position) / 1000.0; minfo->volume_scale = scale; log_debug2("setting volume to %lf", scale); } break; case INTERNAL_CMD_NONE: break; default: break; } if (guard_position_in_ms >= 0 && current_position_in_ms >= guard_position_in_ms) { guard_position_in_ms = -1; post_event(minfo->client_notification, AUDIO_GUARD_REACHED, current_position_in_ms); } else if (playing) { if (minfo->is_file) { int n = ov_read_filter(&minfo->vf, minfo->buffer, BUFFER_SIZE(minfo), 0, 2, 1, &minfo->current_section, adjust_volume, minfo ); if (n > 0) { aodev_play_buffer(minfo->ao_handle, minfo->buffer, n); //log_debug("buffer played"); double tm = ov_time_tell(&minfo->vf); current_position_in_ms = (long) (tm * 1000.0); if ((current_position_in_ms - previous_position_in_ms) >= STATE_REPORT_THRESHOLD) { post_event(minfo->client_notification, AUDIO_PLAYING, current_position_in_ms); } previous_position_in_ms = current_position_in_ms; } else { post_event(minfo->client_notification, AUDIO_EOS, current_position_in_ms); playing = el_false; } } else { // Stream playing post_event(minfo->client_notification, AUDIO_STATE_ERROR, -1); playing = el_false; } } if (playing) { if (audio_event_fifo_peek(minfo->player_control) != NULL) { event = audio_event_fifo_dequeue(minfo->player_control); } else { event = (audio_event_t*) mc_malloc(sizeof(audio_event_t)); event->state = INTERNAL_CMD_NONE; event->position_in_ms = -1; } } else { event = audio_event_fifo_dequeue(minfo->player_control); } } // destroy event received audio_event_destroy(event); // exit thread return NULL; }
int VorbisDecoder::GetTimePosition() { if (!m_opened) { return 0; } return int(ov_time_tell(&m_file)); }
int alogg_get_pos_secs_oggstream(ALOGG_OGGSTREAM *ogg) { return (int)ov_time_tell(&(ogg->vf)); }
///////////////////////////////////////////////////////////////////////////////////////// //Audio callback ///////////////////////////////////////////////////////////////////////////////////////// static void oggDecodeThread(void *_buf2, unsigned int numSamples, void *pdata){ short *_buf = (short *)_buf2; //static short OGG_mixBuffer[PSP_NUM_AUDIO_SAMPLES * 2 * 2]__attribute__ ((aligned(64))); //static unsigned long OGG_tempmixleft = 0; int current_section; if (OGG_isPlaying) { // Playing , so mix up a buffer outputInProgress = 1; while (OGG_tempmixleft < numSamples) { // Not enough in buffer, so we must mix more unsigned long bytesRequired = (numSamples - OGG_tempmixleft) * 4; // 2channels, 16bit = 4 bytes per sample unsigned long ret = ov_read(&OGG_VorbisFile, (char *) &OGG_mixBuffer[OGG_tempmixleft * 2], bytesRequired, ¤t_section); //libtremor //unsigned long ret = ov_read(&OGG_VorbisFile, (char *) &OGG_mixBuffer[OGG_tempmixleft * 2], bytesRequired, 0, 2, 1, ¤t_section); //ogg-vorbis if (!ret) { //EOF OGG_isPlaying = 0; OGG_eos = 1; outputInProgress = 0; return; } else if (ret < 0) { if (ret == OV_HOLE) continue; OGG_isPlaying = 0; OGG_eos = 1; outputInProgress = 0; return; } OGG_tempmixleft += ret / 4; // back down to sample num } OGG_info.instantBitrate = ov_bitrate_instant(&OGG_VorbisFile); OGG_milliSeconds = ov_time_tell(&OGG_VorbisFile); //Check for playing speed: if (OGG_playingSpeed){ if (ov_raw_seek(&OGG_VorbisFile, ov_raw_tell(&OGG_VorbisFile) + OGG_playingDelta) != 0) OGG_setPlayingSpeed(0); } if (OGG_tempmixleft >= numSamples) { // Buffer has enough, so copy across int count, count2; short *_buf2; for (count = 0; count < numSamples; count++) { count2 = count + count; _buf2 = _buf + count2; //Volume boost: if (OGG_volume_boost){ *(_buf2) = volume_boost(&OGG_mixBuffer[count2], &OGG_volume_boost); *(_buf2 + 1) = volume_boost(&OGG_mixBuffer[count2 + 1], &OGG_volume_boost); }else{ // Double up for stereo *(_buf2) = OGG_mixBuffer[count2]; *(_buf2 + 1) = OGG_mixBuffer[count2 + 1]; } } // Move the pointers OGG_tempmixleft -= numSamples; // Now shuffle the buffer along for (count = 0; count < OGG_tempmixleft * 2; count++) OGG_mixBuffer[count] = OGG_mixBuffer[numSamples * 2 + count]; } outputInProgress = 0; } else { // Not Playing , so clear buffer int count; for (count = 0; count < numSamples * 2; count++) *(_buf + count) = 0; } }
const int oggDecoder::getRTime( ) { return int( ov_time_total( decoder, -1 )-ov_time_tell( decoder )); }