diff options
author | 2010-01-30 00:34:15 +0100 | |
---|---|---|
committer | 2010-01-30 00:34:15 +0100 | |
commit | 09ed449eb2aec5ca2213e91addcf0bf80f205d44 (patch) | |
tree | fca89a5bb2133712bb74679ae39c47c477100896 /plugins | |
parent | feecc0214decb6d1b9911aafe140034449266430 (diff) |
duration calc and seeking fixes in mpgmad
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mpgmad/mpgmad.c | 110 |
1 files changed, 75 insertions, 35 deletions
diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 55bced8f..f02c9506 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -83,6 +83,10 @@ typedef struct { int endsample; int startdelay; int enddelay; + int avg_packetlength; + int avg_samplerate; + int avg_samples_per_frame; + int nframes; } buffer_t; static buffer_t buffer; @@ -158,6 +162,8 @@ extract_f32 (unsigned char *buf) { static int cmp3_scan_stream (buffer_t *buffer, int sample) { trace ("cmp3_scan_stream %d\n", sample); + int initpos = deadbeef->ftell (buffer->file); + trace ("filepos: %d\n", initpos); // if (sample == 0) { // sample = -1; // } @@ -169,13 +175,19 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { buffer->currentsample = 0; buffer->skipsamples = 0; int fsize = 0; - int avg_packetlength = 0; - int avg_samplerate = 0; - int avg_samples_per_frame = 0; + int avg_bitrate = 0; + int valid_frames = 0; if (sample <= 0) { buffer->totalsamples = 0; - fsize = deadbeef->fgetlength (buffer->file); + fsize = deadbeef->fgetlength (buffer->file) - initpos; + } + if (sample == 0 && buffer->avg_packetlength == 0) { + buffer->avg_packetlength = 0; + buffer->avg_samplerate = 0; + buffer->avg_samples_per_frame = 0; + buffer->nframes = 0; + buffer->startoffset = initpos; } for (;;) { @@ -186,7 +198,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { break; // eof } if (sync != 0xff) { - trace ("[1]frame %d didn't seek to frame end\n", nframe); +// trace ("[1]frame %d didn't seek to frame end\n", nframe); continue; // not an mpeg frame } else { @@ -195,7 +207,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { break; // eof } if ((sync >> 5) != 7) { - trace ("[2]frame %d didn't seek to frame end\n", nframe); +// trace ("[2]frame %d didn't seek to frame end\n", nframe); continue; } } @@ -282,11 +294,11 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { // check if channel/bitrate combination is valid for layer2 if (layer == 2) { if ((bitrate <= 56 || bitrate == 80) && nchannels != 1) { - trace ("[1]frame %d channel/bitrate combination is bad\n", nframe); + trace ("mpgmad: bad frame %d: layer %d, channels %d, bitrate %d\n", nframe, layer, nchannels, bitrate); continue; // bad frame } if (bitrate >= 224 && nchannels == 1) { - trace ("[2]frame %d channel/bitrate combination is bad\n", nframe); + trace ("mpgmad: bad frame %d: layer %d, channels %d, bitrate %d\n", nframe, layer, nchannels, bitrate); continue; // bad frame } } @@ -322,6 +334,10 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { continue; } + valid_frames++; + if (nframe < 1000) { + trace ("frame %d bitrate %d\n", nframe, bitrate); + } if (sample != 0 || nframe == 0) { buffer->version = ver; @@ -338,7 +354,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { if (sample <= 0 && !got_xing_header) { size_t framepos = deadbeef->ftell (buffer->file); - trace ("trying to read xing header\n"); +// trace ("trying to read xing header at pos %d\n", framepos); if (ver == 1) { deadbeef->fseek (buffer->file, 32, SEEK_CUR); } @@ -357,7 +373,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { buffer->startoffset = startoffset; } - trace ("xing magic: %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]); +// trace ("xing magic: %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]); if (!strncmp (xing, magic, 4) || !strncmp (info, magic, 4)) { trace ("xing/info frame found\n"); @@ -392,7 +408,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { if (deadbeef->fread (buf, 1, 4, buffer->file) != 4) { return -1; // EOF } - trace ("tell=%x, %c%c%c%c\n", deadbeef->ftell(buffer->file), buf[0], buf[1], buf[2], buf[3]); +// trace ("tell=%x, %c%c%c%c\n", deadbeef->ftell(buffer->file), buf[0], buf[1], buf[2], buf[3]); if (!memcmp (buf, "LAME", 4)) { trace ("lame header found\n"); deadbeef->fseek (buffer->file, 6, SEEK_CUR); @@ -425,7 +441,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { deadbeef->fread (buf, 1, 4, buffer->file); // uint32_t musiclen = extract_i32 (buf); - trace ("lpf: %d, peaksignalamp: %f, radiogain: %d, audiophile: %d, startdelay: %d, enddelay: %d, mp3gain: %d, musiclen: %d\n", lpf, rg_peaksignalamp, rg_radio, rg_audiophile, startdelay, enddelay, mp3gain, musiclen); + //trace ("lpf: %d, peaksignalamp: %f, radiogain: %d, audiophile: %d, startdelay: %d, enddelay: %d, mp3gain: %d, musiclen: %d\n", lpf, rg_peaksignalamp, rg_radio, rg_audiophile, startdelay, enddelay, mp3gain, musiclen); // skip crc //deadbeef->fseek (buffer->file, 4, SEEK_CUR); buffer->startdelay = startdelay; @@ -440,29 +456,36 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { } if (sample == 0) { // xing header failed, calculate based on file size - trace ("xing header failed\n"); +// trace ("xing header failed\n"); buffer->samplerate = samplerate; if (buffer->file->vfs->streaming) { // only suitable for cbr files, used if streaming int sz = deadbeef->fgetlength (buffer->file) - buffer->startoffset - buffer->endoffset; if (sz < 0) { + // unable to determine duration buffer->duration = -1; buffer->totalsamples = -1; if (sample == 0) { - deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET); + deadbeef->fseek (buffer->file, framepos/*+packetlength-4*/, SEEK_SET); } return 0; } - int nframes = sz / packetlength; - buffer->duration = nframes * samples_per_frame / samplerate; - buffer->totalsamples = nframes * samples_per_frame; + buffer->nframes = sz / packetlength; + buffer->avg_packetlength = packetlength; + buffer->avg_samplerate = samplerate; + buffer->avg_samples_per_frame = samples_per_frame; + buffer->duration = buffer->nframes * samples_per_frame / samplerate; + buffer->totalsamples = buffer->nframes * samples_per_frame; // trace ("bitrate=%d, layer=%d, packetlength=%d, fsize=%d, nframes=%d, samples_per_frame=%d, samplerate=%d, duration=%f, totalsamples=%d\n", bitrate, layer, packetlength, sz, nframes, samples_per_frame, samplerate, buffer->duration, buffer->totalsamples); if (sample == 0) { - deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET); + deadbeef->fseek (buffer->file, framepos/*+packetlength-4*/, SEEK_SET); return 0; } } + else { + deadbeef->fseek (buffer->file, framepos, SEEK_SET); + } } else { deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET); @@ -475,19 +498,20 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { return -1; } // calculating apx duration based on 1st 100 frames - avg_packetlength += packetlength; - avg_samplerate += samplerate; - avg_samples_per_frame += samples_per_frame; + buffer->avg_packetlength += packetlength; + buffer->avg_samplerate += samplerate; + buffer->avg_samples_per_frame += samples_per_frame; + avg_bitrate += bitrate; if (nframe >= 100) { - avg_packetlength /= nframe; - avg_samplerate /= nframe; - avg_samples_per_frame /= nframe; - - trace ("avg_packetlength=%d, avg_samplerate=%d, avg_samples_per_frame=%d\n", avg_packetlength, avg_samplerate, avg_samples_per_frame); - - int nframes = fsize / avg_packetlength; - buffer->duration = nframes * avg_samples_per_frame / avg_samplerate; - buffer->totalsamples = nframes * avg_samples_per_frame; + buffer->avg_packetlength /= valid_frames; + buffer->avg_samplerate /= valid_frames; + buffer->avg_samples_per_frame /= valid_frames; + avg_bitrate /= valid_frames; + trace ("valid_frames=%d, avg_bitrate=%d, avg_packetlength=%d, avg_samplerate=%d, avg_samples_per_frame=%d\n", valid_frames, avg_bitrate, buffer->avg_packetlength, buffer->avg_samplerate, buffer->avg_samples_per_frame); + + buffer->nframes = fsize / buffer->avg_packetlength; + buffer->duration = buffer->nframes * buffer->avg_samples_per_frame / buffer->avg_samplerate; + buffer->totalsamples = buffer->nframes * buffer->avg_samples_per_frame; return 0; } } @@ -528,6 +552,7 @@ cmp3_init (DB_playItem_t *it) { if (!buffer.file->vfs->streaming) { int skip = deadbeef->junk_get_leading_size (buffer.file); if (skip > 0) { + trace ("mpgmad: skipping %d bytes of junk\n", skip); deadbeef->fseek(buffer.file, skip, SEEK_SET); } cmp3_scan_stream (&buffer, -1); // scan entire stream, calc duration @@ -883,15 +908,28 @@ cmp3_seek_sample (int sample) { } if (buffer.file->vfs->streaming) { - if (buffer.totalsamples > 0) { - // approximation - int64_t l = deadbeef->fgetlength (buffer.file); - l = l * sample / buffer.totalsamples; - int r = deadbeef->fseek (buffer.file, l, SEEK_SET); + if (buffer.totalsamples > 0 && buffer.avg_samples_per_frame && buffer.avg_packetlength) { // that means seekable remote stream, like podcast + trace ("seeking is possible!\n"); + // get length excluding id3v2 + int64_t l = deadbeef->fgetlength (buffer.file) - buffer.startoffset; + + int r; + + // seek to beginning of the frame + int frm = sample / buffer.avg_samples_per_frame; + r = deadbeef->fseek (buffer.file, frm * buffer.avg_packetlength, SEEK_SET); + +// l = l * sample / buffer.totalsamples; +// r = deadbeef->fseek (buffer.file, l, SEEK_SET); + if (!r) { + trace ("seek successful!\n"); + buffer.skipsamples = sample - frm * buffer.avg_samples_per_frame; + buffer.currentsample = sample; plugin.info.readpos = (float)(buffer.currentsample - buffer.startsample) / buffer.samplerate; + // reset mad mad_synth_finish (&synth); mad_frame_finish (&frame); mad_stream_finish (&stream); @@ -903,8 +941,10 @@ cmp3_seek_sample (int sample) { return 0; } + trace ("seek failed!\n"); return -1; } + trace ("seek is impossible (avg_samples_per_frame=%d, avg_packetlength=%d)!\n", buffer.avg_samples_per_frame, buffer.avg_packetlength); return 0; } |