From 7577bbb5102f6fd32ed173a3daa18cb08a408b74 Mon Sep 17 00:00:00 2001 From: waker Date: Mon, 6 Jul 2009 00:18:15 +0200 Subject: very slow and bad seeking support --- callbacks.c | 10 ++- cmp3.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- codec.h | 1 + main.c | 8 +++ messages.h | 1 + 5 files changed, 210 insertions(+), 13 deletions(-) diff --git a/callbacks.c b/callbacks.c index 719274ed..4c8d99a5 100644 --- a/callbacks.c +++ b/callbacks.c @@ -17,7 +17,7 @@ #include "gtkplaylist.h" #include "messagepump.h" #include "messages.h" - +#include "codec.h" extern GtkWidget *mainwin; @@ -40,7 +40,13 @@ void on_playpos_value_changed (GtkRange *range, gpointer user_data) { - + if (playlist_current && playlist_current->codec) { + int val = gtk_range_get_value (range); + int upper = gtk_adjustment_get_upper (gtk_range_get_adjustment (range)); + float time = playlist_current->codec->info.duration / (float)upper * (float)val; + printf ("seeking to %f seconds (duration=%f)\n", time, playlist_current->codec->info.duration); + messagepump_push (M_SONGSEEK, 0, (int)time * 1000, 0); + } } diff --git a/cmp3.c b/cmp3.c index b7796031..d6a0f1b8 100644 --- a/cmp3.c +++ b/cmp3.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "codec.h" #include "cmp3.h" @@ -31,10 +32,13 @@ static struct mad_stream stream; static struct mad_frame frame; static struct mad_synth synth; static mad_timer_t timer; -static int frame_count; static int endoffile; -static int cmp3_decode (void); +static int +cmp3_decode (void); + +static int +cmp3_get_stream_info (void); int cmp3_init (const char *fname) { @@ -47,14 +51,17 @@ cmp3_init (const char *fname) { buffer.output = NULL; buffer.readsize = 0; buffer.cachefill = 0; - frame_count = 0; endoffile = 0; mad_stream_init(&stream); mad_frame_init(&frame); mad_synth_init(&synth); mad_timer_reset(&timer); - cmp3_decode (); // this 1st run will read 1st frame, but will not decode anything except header + if (cmp3_get_stream_info () == -1) { + return -1; + } + fseek (buffer.file, 0, SEEK_SET); +// cmp3_decode (); // this 1st run will read 1st frame, but will not decode anything except header return 0; } @@ -99,8 +106,12 @@ static signed short MadFixedToSshort(mad_fixed_t Fixed) #define MadErrorString(x) mad_stream_errorstr(x) static int -cmp3_decode (void) { - for (;;) { +cmp3_get_stream_info (void) { + int frame_count = 0; + mad_timer_t timer; + mad_timer_reset(&timer); + int endoffile = 0; + while (!endoffile) { // read more MPEG data if needed if(stream.buffer==NULL || stream.error==MAD_ERROR_BUFLEN) { // copy part of last frame to beginning @@ -163,15 +174,152 @@ cmp3_decode (void) { cmp3.info.dataSize = -1; cmp3.info.channels = MAD_NCHANNELS(&frame.header); cmp3.info.samplesPerSecond = frame.header.samplerate; - cmp3.info.duration = frame.header.duration.seconds; - cmp3.info.duration += (float)frame.header.duration.fraction/MAD_TIMER_RESOLUTION; - frame_count++; - break; } frame_count++; mad_timer_add(&timer,frame.header.duration); +// mad_synth_frame(&synth,&frame); + + } + cmp3.info.duration = timer.seconds; + cmp3.info.duration += (float)timer.fraction/MAD_TIMER_RESOLUTION; + printf ("song duration: %dsec %dfrac (%f)\n", timer.seconds, timer.fraction, cmp3.info.duration); + return 0; +} + +static int +cmp3_skip (float seconds) { + mad_timer_t timer; + mad_timer_reset(&timer); + int endoffile = 0; + float duration = 0; + while (!endoffile) { + // read more MPEG data if needed + if(stream.buffer==NULL || stream.error==MAD_ERROR_BUFLEN) { + // copy part of last frame to beginning + if (stream.next_frame != NULL) { + buffer.remaining = stream.bufend - stream.next_frame; + memmove (buffer.input, stream.next_frame, buffer.remaining); + } + int size = READBUFFER - buffer.remaining; + int bytesread = 0; + char *bytes = buffer.input + buffer.remaining; + if (!endoffile) { + bytesread = fread (bytes, 1, size, buffer.file); + if (bytesread < size) { + // end of file + endoffile = 1; + size -= bytesread; + bytes += bytesread; + /* + fseek (buffer.file, 0, SEEK_SET); + */ + } + } + bytesread += buffer.remaining; + if (bytesread) { + mad_stream_buffer(&stream,buffer.input,bytesread); + } + else { + return -1; + } + stream.error=0; + } + // decode next frame + if(mad_frame_decode(&frame,&stream)) + { + if(MAD_RECOVERABLE(stream.error)) + { + if(stream.error!=MAD_ERROR_LOSTSYNC) + { + fprintf(stderr,"recoverable frame level error (%s)\n", + MadErrorString(&stream)); + fflush(stderr); + } + continue; + } + else { + if(stream.error==MAD_ERROR_BUFLEN) + continue; + else + { + fprintf(stderr,"unrecoverable frame level error (%s).\n", + MadErrorString(&stream)); + break; + } + } + } + + mad_timer_add(&timer,frame.header.duration); + + duration = timer.seconds; + duration += (float)timer.fraction/MAD_TIMER_RESOLUTION; + if (duration > seconds) { + break; + } + } + return 0; +} + +static int +cmp3_decode (void) { + for (;;) { + // read more MPEG data if needed + if(stream.buffer==NULL || stream.error==MAD_ERROR_BUFLEN) { + // copy part of last frame to beginning + if (stream.next_frame != NULL) { + buffer.remaining = stream.bufend - stream.next_frame; + memmove (buffer.input, stream.next_frame, buffer.remaining); + } + int size = READBUFFER - buffer.remaining; + int bytesread = 0; + char *bytes = buffer.input + buffer.remaining; + if (!endoffile) { + bytesread = fread (bytes, 1, size, buffer.file); + if (bytesread < size) { + // end of file + endoffile = 1; + size -= bytesread; + bytes += bytesread; + } + } + bytesread += buffer.remaining; + if (bytesread) { + mad_stream_buffer(&stream,buffer.input,bytesread); + } + else { + return -1; + } + stream.error=0; + } + // decode next frame + if(mad_frame_decode(&frame,&stream)) + { + if(MAD_RECOVERABLE(stream.error)) + { + if(stream.error!=MAD_ERROR_LOSTSYNC) + { + fprintf(stderr,"recoverable frame level error (%s)\n", + MadErrorString(&stream)); + fflush(stderr); + } + continue; + } + else { + if(stream.error==MAD_ERROR_BUFLEN) + continue; + else + { + fprintf(stderr,"unrecoverable frame level error (%s).\n", + MadErrorString(&stream)); + break; + } + } + } + + mad_timer_add(&timer,frame.header.duration); + mad_synth_frame(&synth,&frame); char *cache = &buffer.cache[buffer.cachefill]; @@ -257,10 +405,43 @@ cmp3_read (char *bytes, int size) { return ret; } +int +cmp3_seek (float time) { + if (!buffer.file) { + return -1; + } + // restart file, and load until we hit required pos + mad_synth_finish (&synth); + mad_frame_finish (&frame); + mad_stream_finish (&stream); + endoffile = 0; + fseek(buffer.file, 0, SEEK_SET); + mad_stream_init(&stream); + mad_frame_init(&frame); + mad_synth_init(&synth); + mad_timer_reset(&timer); + + cmp3_skip (time); +#if 0 + int bytes_to_read = time * cmp3.info.samplesPerSecond * cmp3.info.channels * cmp3.info.bitsPerSample / 8; + printf ("reading %d bytes from stream...\n", bytes_to_read); + char buffer[8192]; + while (bytes_to_read) { + int sz = min (8192, bytes_to_read); + if (cmp3_read (buffer, sz) == -1) { + return -1; + } + bytes_to_read -= sz; + } +#endif + return 0; +} + codec_t cmp3 = { .init = cmp3_init, .free = cmp3_free, - .read = cmp3_read + .read = cmp3_read, + .seek = cmp3_seek }; diff --git a/codec.h b/codec.h index 994ca53f..5a33590a 100644 --- a/codec.h +++ b/codec.h @@ -17,6 +17,7 @@ typedef struct codec_s { void (*free) (void); // player is responsible for starting next song if -1 is returned int (*read) (char *bytes, int size); + int (*seek) (float time); } codec_t; codec_t *get_codec_for_file (const char *fname); diff --git a/main.c b/main.c index e13524c0..fd097d5c 100644 --- a/main.c +++ b/main.c @@ -10,6 +10,7 @@ #include "messagepump.h" #include "messages.h" #include "gtkplaylist.h" +#include "codec.h" GtkWidget *mainwin; @@ -61,6 +62,13 @@ psdl_thread (uintptr_t ctx) { gtkps_randomsong (); GDK_THREADS_LEAVE(); break; + case M_SONGSEEK: + if (playlist_current && playlist_current->codec) { + psdl_pause (); + playlist_current->codec->seek (p1 / 1000.f); + psdl_unpause (); + } + break; } } usleep(10); diff --git a/messages.h b/messages.h index 6a52e31d..a9d3419e 100644 --- a/messages.h +++ b/messages.h @@ -9,6 +9,7 @@ enum { M_STOPSONG, M_PAUSESONG, M_PLAYRANDOM, + M_SONGSEEK, }; #endif // __MESSAGES_H -- cgit v1.2.3