diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2009-09-17 20:31:59 +0200 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2009-09-17 20:31:59 +0200 |
commit | 68d900b5b1a962b955098da4b2b292601163bb68 (patch) | |
tree | d4f0b12e3377d1e762ac9531991cd1fa1ba17277 /plugins | |
parent | 3c0e734fe7215692009fda08a40c99d89a5bd40f (diff) |
fixed mp3 playback/seeking
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mpgmad/mpgmad.c | 123 |
1 files changed, 62 insertions, 61 deletions
diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 661bfab2..a86ca104 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -51,9 +51,9 @@ typedef struct { float timestart; float timeend; - // input buffer, for MPEG data - // FIXME: this should go away if reading happens per-frame - mad_timer_t timer; +// // input buffer, for MPEG data +// // FIXME: this should go away if reading happens per-frame +// mad_timer_t timer; char input[READBUFFER]; int remaining; @@ -77,6 +77,9 @@ typedef struct { int bitspersample; int channels; float duration; + int currentsample; + int totalsamples; + int skipsamples; int startoffset; int endoffset; int startsample; @@ -174,39 +177,21 @@ extract_f32 (unsigned char *buf) { // sample>0: seek to the frame with the sample, update skipsamples // return value: -1 on error static int -cmp3_scan_stream (buffer_t *buffer, float position) { - int totalsamples = 0; +cmp3_scan_stream (buffer_t *buffer, int sample) { int nframe = 0; - int nskipped = 0; - float duration = 0; - int nreads = 0; - int nseeks = 0; - - int pos = ftell (buffer->file); - if (pos == 0) { - // try to skip id3v2 - int skip = deadbeef->junk_get_leading_size (buffer->file); - if (skip > 0) { - fseek (buffer->file, skip, SEEK_SET); - } - } + buffer->duration = 0; + buffer->totalsamples = 0; + buffer->currentsample = 0; + buffer->skipsamples = 0; for (;;) { - if (position >= 0 && duration > position) { - // set decoder timer - buffer->timer.seconds = (int)duration; - buffer->timer.fraction = (int)((duration - (float)buffer->timer.seconds)*MAD_TIMER_RESOLUTION); - return duration; - } uint32_t hdr; uint8_t sync; - pos = ftell (buffer->file); + size_t pos = ftell (buffer->file); if (fread (&sync, 1, 1, buffer->file) != 1) { break; // eof } - nreads++; if (sync != 0xff) { - nskipped++; continue; // not an mpeg frame } else { @@ -214,9 +199,7 @@ cmp3_scan_stream (buffer_t *buffer, float position) { if (fread (&sync, 1, 1, buffer->file) != 1) { break; // eof } - nreads++; if ((sync >> 5) != 7) { - nskipped++; continue; } } @@ -226,14 +209,11 @@ cmp3_scan_stream (buffer_t *buffer, float position) { if (fread (&sync, 1, 1, buffer->file) != 1) { break; // eof } - nreads++; hdr |= sync << 8; if (fread (&sync, 1, 1, buffer->file) != 1) { break; // eof } - nreads++; hdr |= sync; - nskipped = 0; // parse header @@ -344,7 +324,7 @@ cmp3_scan_stream (buffer_t *buffer, float position) { continue; } - if (position != 0 || nframe == 0/* || buffer->version != ver || buffer->layer != layer*/) + if (sample != 0 || nframe == 0) { buffer->version = ver; buffer->layer = layer; @@ -357,7 +337,7 @@ cmp3_scan_stream (buffer_t *buffer, float position) { //fprintf (stderr, "frame %d(@%d) mpeg v%d layer %d bitrate %d samplerate %d packetlength %d framedur %f channels %d\n", nframe, pos, ver, layer, bitrate, samplerate, packetlength, dur, nchannels); } // try to read xing/info tag - if (position == 0) { + if (sample == 0) { if (ver == 1) { fseek (buffer->file, 32, SEEK_CUR); } @@ -399,26 +379,38 @@ cmp3_scan_stream (buffer_t *buffer, float position) { int sz = ftell (buffer->file) - buffer->startoffset - buffer->endoffset; int nframes = sz / packetlength; buffer->duration = nframes * samples_per_frame / samplerate; + buffer->totalsamples = nframes * samples_per_frame; + buffer->samplerate = samplerate; + + return 0; + } + if (sample >= 0 && buffer->totalsamples + samples_per_frame >= sample) { + // set decoder timer + buffer->currentsample = sample; + buffer->skipsamples = buffer->totalsamples + samples_per_frame - sample; +// buffer->timer.seconds = (int)duration; +// buffer->timer.fraction = (int)((duration - (float)buffer->timer.seconds)*MAD_TIMER_RESOLUTION); return 0; } + buffer->totalsamples += samples_per_frame; - duration += dur; + buffer->duration += dur; nframe++; if (packetlength > 0) { fseek (buffer->file, packetlength-4, SEEK_CUR); - nseeks++; } } - if (position >= 0 && duration >= position) { - // set decoder timer - buffer->timer.seconds = (int)duration; - buffer->timer.fraction = (int)((duration - (float)buffer->timer.seconds)*MAD_TIMER_RESOLUTION); - } +// if (sample >= 0 && totalframe >= sample) { +// // set decoder timer +// buffer->timer.seconds = (int)duration; +// buffer->timer.fraction = (int)((duration - (float)buffer->timer.seconds)*MAD_TIMER_RESOLUTION); +// } if (nframe == 0) { return -1; } - return duration; + buffer->duration = buffer->totalsamples / buffer->samplerate; + return 0; } @@ -435,7 +427,7 @@ cmp3_init (DB_playItem_t *it) { buffer.cachefill = 0; buffer.cachepos = 0; plugin.info.readpos = 0; - mad_timer_reset(&buffer.timer); + //mad_timer_reset(&buffer.timer); // fseek (buffer.file, buffer.startoffset, SEEK_SET); if (it->timeend > 0) { @@ -579,15 +571,15 @@ cmp3_decode (void) { plugin.info.samplerate = frame.header.samplerate; plugin.info.channels = MAD_NCHANNELS(&frame.header); - - mad_timer_add(&buffer.timer,frame.header.duration); mad_synth_frame(&synth,&frame); // char *cache = &buffer.cache[(buffer.cachefill + buffer.cachepos) & CACHE_MASK]; int cachepos = (buffer.cachefill + buffer.cachepos) & CACHE_MASK; - int i; - for(i=0;i<synth.pcm.length;i++) + int i = min (synth.pcm.length, buffer.skipsamples); + buffer.skipsamples -= i; + buffer.currentsample += synth.pcm.length-i; + for(;i<synth.pcm.length;i++) { if (buffer.cachefill >= CACHE_SIZE) { printf ("cache overflow!\n"); @@ -643,7 +635,7 @@ cmp3_read (char *bytes, int size) { if (buffer.cachefill < size) { buffer.readsize = (size - buffer.cachefill); cmp3_decode (); - plugin.info.readpos = (float)buffer.timer.seconds + (float)buffer.timer.fraction / MAD_TIMER_RESOLUTION; + plugin.info.readpos = (float)buffer.currentsample / buffer.samplerate - buffer.timestart; } if (buffer.cachefill > 0) { int sz = min (size, buffer.cachefill); @@ -691,7 +683,7 @@ cmp3_read_float32 (char *bytes, int size) { buffer.readsize = (size - buffer.cachefill); //printf ("decoding %d bytes using read_float32\n", buffer.readsize); cmp3_decode (); - plugin.info.readpos = (float)buffer.timer.seconds + (float)buffer.timer.fraction / MAD_TIMER_RESOLUTION; + plugin.info.readpos = (float)buffer.currentsample / buffer.samplerate - buffer.timestart; } if (buffer.cachefill > 0) { int sz = min (size, buffer.cachefill); @@ -727,41 +719,49 @@ cmp3_read_float32 (char *bytes, int size) { } static int -cmp3_seek (float time) { - time += buffer.timestart; +cmp3_seek_sample (int sample) { if (!buffer.file) { return -1; } + sample += buffer.startsample; // restart file, and load until we hit required pos - mad_synth_finish (&synth); - mad_frame_finish (&frame); - mad_stream_finish (&stream); + fseek (buffer.file, 0, SEEK_SET); int skip = deadbeef->junk_get_leading_size (buffer.file); if (skip > 0) { fseek(buffer.file, skip, SEEK_SET); } + mad_synth_finish (&synth); + mad_frame_finish (&frame); + mad_stream_finish (&stream); mad_stream_init(&stream); mad_frame_init(&frame); mad_synth_init(&synth); - mad_timer_reset(&buffer.timer); + //mad_timer_reset(&buffer.timer); - if (time == 0) { + if (sample == 0) { plugin.info.readpos = 0; + buffer.currentsample = 0; + buffer.skipsamples = 0; return 0; } - if (cmp3_scan_stream (&buffer, time) == -1) { + if (cmp3_scan_stream (&buffer, sample) == -1) { plugin.info.readpos = 0; return -1; } // fixup timer - plugin.info.readpos = (float)buffer.timer.seconds + (float)buffer.timer.fraction / MAD_TIMER_RESOLUTION; - plugin.info.readpos -= buffer.timestart; - buffer.timer.seconds = (int)plugin.info.readpos; - buffer.timer.fraction = (plugin.info.readpos - buffer.timer.seconds) * MAD_TIMER_RESOLUTION; + plugin.info.readpos = (float)buffer.currentsample / buffer.samplerate - buffer.timestart; + //buffer.timer.seconds = (int)plugin.info.readpos; + //buffer.timer.fraction = (plugin.info.readpos - buffer.timer.seconds) * MAD_TIMER_RESOLUTION; return 0; } +static int +cmp3_seek (float time) { + int sample = time * buffer.samplerate; + return cmp3_seek_sample (sample); +} + // {{{ separate xing/lame header reader (unused) #if 0 // read xing/lame header @@ -1013,6 +1013,7 @@ static DB_decoder_t plugin = { .read_int16 = cmp3_read, .read_float32 = cmp3_read_float32, .seek = cmp3_seek, + .seek_sample = cmp3_seek_sample, .insert = cmp3_insert, .exts = exts, .id = "stdmpg", |