summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-01-30 00:34:15 +0100
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-01-30 00:34:15 +0100
commit09ed449eb2aec5ca2213e91addcf0bf80f205d44 (patch)
treefca89a5bb2133712bb74679ae39c47c477100896 /plugins
parentfeecc0214decb6d1b9911aafe140034449266430 (diff)
duration calc and seeking fixes in mpgmad
Diffstat (limited to 'plugins')
-rw-r--r--plugins/mpgmad/mpgmad.c110
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;
}