diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2010-01-11 22:08:31 +0100 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2010-01-11 22:19:27 +0100 |
commit | f6fdf11dcbc98fa1477bcfc5ae7317a5b2e75ede (patch) | |
tree | abee6c4200df2b4e924da4ef54f6bcae0c77a62f | |
parent | 92a8bcfc52f15022e3e7c0bdbc82f12ac327ecca (diff) |
decoder plugin reentrancy WIP (mp3 works)
-rw-r--r-- | Makefile.am | 44 | ||||
-rw-r--r-- | deadbeef.h | 25 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | moduleconf.h | 6 | ||||
-rw-r--r-- | playlist.c | 6 | ||||
-rw-r--r-- | plugins.c | 10 | ||||
-rw-r--r-- | plugins/gtkui/gtkui.c | 8 | ||||
-rw-r--r-- | plugins/mpgmad/mpgmad.c | 413 | ||||
-rw-r--r-- | streamer.c | 67 | ||||
-rw-r--r-- | streamer.h | 2 | ||||
-rw-r--r-- | vfs.c | 4 |
11 files changed, 312 insertions, 275 deletions
diff --git a/Makefile.am b/Makefile.am index 9e9ca153..8c943340 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,25 +1,34 @@ -SUBDIRS = gme/Game_Music_Emu-0.5.2\ - gme/Game_Music_Emu-0.5.2/gme\ - sid/sidplay-libs-2.1.0\ - dumb\ +SUBDIRS = ${MPGMAD_DIR}\ pixmaps\ icons\ plugins/hotkeys\ - plugins/ffap\ plugins/nullout\ - plugins/vtx\ - plugins/adplug\ ${ALSA_DIR}\ ${LFM_DIR}\ - ${MPGMAD_DIR}\ - ${VORBIS_DIR}\ - ${FLAC_DIR}\ - ${WAVPACK_DIR}\ - ${SNDFILE_DIR}\ ${VFS_CURL_DIR}\ - ${CDDA_DIR}\ - ${GTKUI_DIR}\ - ${FFMPEG_DIR} + ${GTKUI_DIR} + +#SUBDIRS = gme/Game_Music_Emu-0.5.2\ +# sid/sidplay-libs-2.1.0\ +# dumb\ +# pixmaps\ +# icons\ +# plugins/hotkeys\ +# plugins/ffap\ +# plugins/nullout\ +# plugins/vtx\ +# plugins/adplug\ +# ${ALSA_DIR}\ +# ${LFM_DIR}\ +# ${MPGMAD_DIR}\ +# ${VORBIS_DIR}\ +# ${FLAC_DIR}\ +# ${WAVPACK_DIR}\ +# ${SNDFILE_DIR}\ +# ${VFS_CURL_DIR}\ +# ${CDDA_DIR}\ +# ${GTKUI_DIR}\ +# ${FFMPEG_DIR} dumbpath=@top_srcdir@/dumb sidpath=@top_srcdir@/sid/sidplay-libs-2.1.0 @@ -35,7 +44,6 @@ deadbeef_SOURCES =\ codec.c codec.h\ messagepump.c messagepump.h\ conf.c conf.h\ - cgme.c cdumb.c csid.cpp\ playback.h\ threading_pthread.c threading.h\ md5/md5.c md5/md5.h md5/md5_loc.h\ @@ -45,11 +53,13 @@ deadbeef_SOURCES =\ optmath.h\ vfs.c vfs.h vfs_stdio.c\ timeline.c timeline.h +# cgme.c cdumb.c csid.cpp sdkdir = $(pkgincludedir) sdk_HEADERS = deadbeef.h -deadbeef_LDADD = $(LDADD) $(DEPS_LIBS) gme/Game_Music_Emu-0.5.2/gme/libgme.a sid/sidplay-libs-2.1.0/libsidplay2.a dumb/libdumb.a -lstdc++ +#deadbeef_LDADD = $(LDADD) $(DEPS_LIBS) gme/Game_Music_Emu-0.5.2/gme/libgme.a sid/sidplay-libs-2.1.0/libsidplay2.a dumb/libdumb.a -lstdc++ +deadbeef_LDADD = $(LDADD) $(DEPS_LIBS) -lstdc++ AM_CFLAGS = $(DEPS_CFLAGS) -I$(gmepath) -std=c99 AM_CPPFLAGS = $(DEPS_CFLAGS) -I$(sidpath)/libsidplay/include -I$(sidpath)/builders/resid-builder/include @@ -67,7 +67,7 @@ extern "C" { .plugin.api_vmajor = DB_API_VERSION_MAJOR,\ .plugin.api_vminor = DB_API_VERSION_MINOR, -#define MAX_OUTPUT_PLUGINS 30 +#define MAX_DECODER_PLUGINS 50 //////////////////////////// // playlist structures @@ -251,7 +251,7 @@ typedef struct { int (*streamer_read) (char *bytes, int size); void (*streamer_set_bitrate) (int bitrate); int (*streamer_get_apx_bitrate) (void); - struct DB_decoder_s *(*streamer_get_current_decoder) (void); + struct DB_fileinfo_s *(*streamer_get_current_decoder) (void); // process control const char *(*get_config_dir) (void); void (*quit) (void); @@ -421,7 +421,8 @@ typedef struct DB_plugin_s { const char *configdialog; } DB_plugin_t; -typedef struct { +typedef struct DB_fileinfo_s { + struct DB_decoder_s *plugin; int bps; int channels; int samplerate; @@ -431,36 +432,36 @@ typedef struct { // decoder plugin typedef struct DB_decoder_s { DB_plugin_t plugin; - DB_fileinfo_t info; +// DB_fileinfo_t info; // init is called to prepare song to be started - int (*init) (DB_playItem_t *it); + DB_fileinfo_t *(*init) (DB_playItem_t *it); // free is called after decoding is finished - void (*free) (void); + void (*free) (DB_fileinfo_t *info); // read is called by streamer to decode specified number of bytes // must return number of bytes that were successfully decoded (sample aligned) // read_int16 must always output 16 bit signed integer samples - int (*read_int16) (char *buffer, int size); + int (*read_int16) (DB_fileinfo_t *info, char *buffer, int size); // read_float32 must always output 32 bit floating point samples - int (*read_float32) (char *buffer, int size); + int (*read_float32) (DB_fileinfo_t *info, char *buffer, int size); - int (*seek) (float seconds); + int (*seek) (DB_fileinfo_t *info, float seconds); // perform seeking in samples (if possible) // return -1 if failed, or 0 on success // if -1 is returned, that will mean that streamer must skip that song - int (*seek_sample) (int sample); + int (*seek_sample) (DB_fileinfo_t *info, int sample); // 'insert' is called to insert new item to playlist // decoder is responsible to calculate duration, split it into subsongs, load cuesheet, etc // after==NULL means "prepend before 1st item in playlist" DB_playItem_t * (*insert) (DB_playItem_t *after, const char *fname); - int (*numvoices) (void); - void (*mutevoice) (int voice, int mute); + int (*numvoices) (DB_fileinfo_t *info); + void (*mutevoice) (DB_fileinfo_t *info, int voice, int mute); // NULL terminated array of all supported extensions const char **exts; @@ -127,7 +127,7 @@ server_exec_command_line (const char *cmdline, int len, char *sendback, int sbsi } if (sendback) { playItem_t *curr = streamer_get_playing_track (); - DB_decoder_t *dec = streamer_get_current_decoder (); + DB_fileinfo_t *dec = streamer_get_current_decoder (); if (curr && dec) { const char np[] = "nowplaying "; memcpy (sendback, np, sizeof (np)-1); diff --git a/moduleconf.h b/moduleconf.h index 4fdc123c..40aa3038 100644 --- a/moduleconf.h +++ b/moduleconf.h @@ -1,4 +1,4 @@ -PLUG(gme) -PLUG(dumb) -PLUG(sid) +//PLUG(gme) +//PLUG(dumb) +//PLUG(sid) PLUG(stdio) @@ -42,8 +42,8 @@ #define PLAYLIST_MAJOR_VER 1 #define PLAYLIST_MINOR_VER 1 -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) #define SKIP_BLANK_CUE_TRACKS 1 @@ -682,6 +682,7 @@ pl_insert_pls (playItem_t *after, const char *fname, int *pabort, int (*cb)(play playItem_t * pl_insert_file (playItem_t *after, const char *fname, int *pabort, int (*cb)(playItem_t *it, void *data), void *user_data) { + trace ("pl_insert_file %s\n", fname); if (!fname || !(*fname)) { return NULL; } @@ -738,6 +739,7 @@ pl_insert_file (playItem_t *after, const char *fname, int *pabort, int (*cb)(pla DB_decoder_t **decoders = plug_get_decoder_list (); // match by decoder for (int i = 0; decoders[i]; i++) { + trace ("matching decoder %d(%s)...\n", i, decoders[i]->id); if (decoders[i]->exts && decoders[i]->insert) { const char **exts = decoders[i]->exts; for (int e = 0; exts[e]; e++) { @@ -200,12 +200,12 @@ plug_volume_set_amp (float amp) { #define MAX_PLUGINS 100 DB_plugin_t *g_plugins[MAX_PLUGINS+1]; -#define MAX_DECODER_PLUGINS 50 DB_decoder_t *g_decoder_plugins[MAX_DECODER_PLUGINS+1]; #define MAX_VFS_PLUGINS 10 DB_vfs_t *g_vfs_plugins[MAX_VFS_PLUGINS+1]; +#define MAX_OUTPUT_PLUGINS 10 DB_output_t *g_output_plugins[MAX_OUTPUT_PLUGINS+1]; DB_output_t *output_plugin = NULL; @@ -734,13 +734,13 @@ plug_reinit_sound (void) { } // list of all unique decoder ids used in current session -static char *decoder_ids[MAX_OUTPUT_PLUGINS]; +static char *decoder_ids[MAX_DECODER_PLUGINS]; const char * plug_get_decoder_id (const char *id) { int i; char **lastnull = NULL; - for (i = 0; i < MAX_OUTPUT_PLUGINS; i++) { + for (i = 0; i < MAX_DECODER_PLUGINS; i++) { if (decoder_ids[i] && !strcmp (id, decoder_ids[i])) { return decoder_ids[i]; } @@ -759,7 +759,7 @@ plug_get_decoder_id (const char *id) { void plug_remove_decoder_id (const char *id) { int i; - for (i = 0; i < MAX_OUTPUT_PLUGINS; i++) { + for (i = 0; i < MAX_DECODER_PLUGINS; i++) { if (decoder_ids[i] && !strcmp (decoder_ids[i], id)) { free (decoder_ids[i]); decoder_ids[i] = NULL; @@ -770,7 +770,7 @@ plug_remove_decoder_id (const char *id) { void plug_free_decoder_ids (void) { int i; - for (i = 0; i < MAX_OUTPUT_PLUGINS; i++) { + for (i = 0; i < MAX_DECODER_PLUGINS; i++) { if (decoder_ids[i]) { free (decoder_ids[i]); decoder_ids[i] = NULL; diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c index 4fa1cddb..69dec742 100644 --- a/plugins/gtkui/gtkui.c +++ b/plugins/gtkui/gtkui.c @@ -83,7 +83,7 @@ update_songinfo (gpointer ctx) { } else { // codec_lock (); - DB_decoder_t *c = deadbeef->streamer_get_current_decoder (); + DB_fileinfo_t *c = deadbeef->streamer_get_current_decoder (); if (c) { float playpos = deadbeef->streamer_get_playpos (); int minpos = playpos / 60; @@ -91,9 +91,9 @@ update_songinfo (gpointer ctx) { int mindur = duration / 60; int secdur = duration - mindur * 60; - const char *mode = c->info.channels == 1 ? "Mono" : "Stereo"; - int samplerate = c->info.samplerate; - int bitspersample = c->info.bps; + const char *mode = c->channels == 1 ? "Mono" : "Stereo"; + int samplerate = c->samplerate; + int bitspersample = c->bps; songpos = playpos; // codec_unlock (); diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 49754dfa..b67fbc6a 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -82,10 +82,14 @@ typedef struct { int enddelay; } buffer_t; -static buffer_t buffer; -static struct mad_stream stream; -static struct mad_frame frame; -static struct mad_synth synth; +typedef struct { + DB_fileinfo_t info; + buffer_t buffer; + struct mad_stream stream; + struct mad_frame frame; + struct mad_synth synth; +} mpgmad_info_t; + static uint32_t extract_i32 (unsigned char *buf) @@ -422,7 +426,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; @@ -513,47 +517,51 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { } -static int +static DB_fileinfo_t * cmp3_init (DB_playItem_t *it) { - memset (&buffer, 0, sizeof (buffer)); - buffer.file = deadbeef->fopen (it->fname); - if (!buffer.file) { - return -1; + DB_fileinfo_t *_info = malloc (sizeof (mpgmad_info_t)); + mpgmad_info_t *info = (mpgmad_info_t *)_info; + memset (info, 0, sizeof (mpgmad_info_t)); + _info->plugin = &plugin; + memset (&info->buffer, 0, sizeof (info->buffer)); + info->buffer.file = deadbeef->fopen (it->fname); + if (!info->buffer.file) { + return NULL; } - buffer.it = it; - plugin.info.readpos = 0; - if (!buffer.file->vfs->streaming) { - int skip = deadbeef->junk_get_leading_size (buffer.file); + info->buffer.it = it; + info->info.readpos = 0; + if (!info->buffer.file->vfs->streaming) { + int skip = deadbeef->junk_get_leading_size (info->buffer.file); if (skip > 0) { - deadbeef->fseek(buffer.file, skip, SEEK_SET); + deadbeef->fseek (info->buffer.file, skip, SEEK_SET); } - cmp3_scan_stream (&buffer, -1); // scan entire stream, calc duration + cmp3_scan_stream (&info->buffer, -1); // scan entire stream, calc duration if (it->endsample > 0) { - buffer.startsample = it->startsample; - buffer.endsample = it->endsample; + info->buffer.startsample = it->startsample; + info->buffer.endsample = it->endsample; // that comes from cue, don't calc duration, just seek and play - plugin.seek_sample (0); + plugin.seek_sample (_info, 0); } else { - deadbeef->pl_set_item_duration (it, buffer.duration); - buffer.startsample = 0; - buffer.endsample = buffer.totalsamples-1; - buffer.skipsamples = buffer.startdelay; - buffer.currentsample = buffer.startdelay; - deadbeef->fseek (buffer.file, buffer.startoffset, SEEK_SET); + deadbeef->pl_set_item_duration (it, info->buffer.duration); + info->buffer.startsample = 0; + info->buffer.endsample = info->buffer.totalsamples-1; + info->buffer.skipsamples = info->buffer.startdelay; + info->buffer.currentsample = info->buffer.startdelay; + deadbeef->fseek (info->buffer.file, info->buffer.startoffset, SEEK_SET); } } else { - buffer.it->filetype = NULL; - int len = deadbeef->fgetlength (buffer.file); - const char *name = deadbeef->fget_content_name (buffer.file); - const char *genre = deadbeef->fget_content_genre (buffer.file); + info->buffer.it->filetype = NULL; + int len = deadbeef->fgetlength (info->buffer.file); + const char *name = deadbeef->fget_content_name (info->buffer.file); + const char *genre = deadbeef->fget_content_genre (info->buffer.file); if (len > 0) { deadbeef->pl_delete_all_meta (it); - int v2err = deadbeef->junk_read_id3v2 (it, buffer.file); + int v2err = deadbeef->junk_read_id3v2 (it, info->buffer.file); deadbeef->pl_add_meta (it, "title", NULL); if (v2err != 0) { - deadbeef->fseek (buffer.file, 0, SEEK_SET); + deadbeef->fseek (info->buffer.file, 0, SEEK_SET); } } else { @@ -568,46 +576,46 @@ cmp3_init (DB_playItem_t *it) { deadbeef->pl_add_meta (it, "genre", genre); } } - int res = cmp3_scan_stream (&buffer, 0); + int res = cmp3_scan_stream (&info->buffer, 0); if (res < 0) { trace ("mpgmad: cmp3_init: initial cmp3_scan_stream failed\n"); - plugin.free (); - return -1; + plugin.free (_info); + return NULL; } - deadbeef->pl_set_item_duration (it, buffer.duration); - if (buffer.duration >= 0) { - buffer.endsample = buffer.totalsamples - 1; + deadbeef->pl_set_item_duration (it, info->buffer.duration); + if (info->buffer.duration >= 0) { + info->buffer.endsample = info->buffer.totalsamples - 1; } else { -// buffer.duration = 200; -// buffer.totalsamples = 10000000; -// buffer.endsample = buffer.totalsamples-1; - buffer.endsample = -1; - buffer.totalsamples = -1; +// info->buffer.duration = 200; +// info->buffer.totalsamples = 10000000; +// info->buffer.endsample = info->buffer.totalsamples-1; + info->buffer.endsample = -1; + info->buffer.totalsamples = -1; } - buffer.skipsamples = 0; - buffer.currentsample = 0; - if (buffer.duration < 0) { - buffer.duration = -1; - buffer.totalsamples = -1; - buffer.endsample = -1; + info->buffer.skipsamples = 0; + info->buffer.currentsample = 0; + if (info->buffer.duration < 0) { + info->buffer.duration = -1; + info->buffer.totalsamples = -1; + info->buffer.endsample = -1; } - trace ("duration=%f, endsample=%d, totalsamples=%d\n", buffer.duration, buffer.endsample, buffer.totalsamples); + trace ("duration=%f, endsample=%d, totalsamples=%d\n", info->buffer.duration, info->buffer.endsample, info->buffer.totalsamples); } - if (buffer.samplerate == 0) { + if (info->buffer.samplerate == 0) { trace ("bad mpeg file: %f\n", it->fname); - plugin.free (); - return -1; + plugin.free (_info); + return NULL; } - plugin.info.bps = buffer.bitspersample; - plugin.info.samplerate = buffer.samplerate; - plugin.info.channels = buffer.channels; + _info->bps = info->buffer.bitspersample; + _info->samplerate = info->buffer.samplerate; + _info->channels = info->buffer.channels; - mad_stream_init(&stream); - mad_frame_init(&frame); - mad_synth_init(&synth); + mad_stream_init(&info->stream); + mad_frame_init(&info->frame); + mad_synth_init(&info->synth); - return 0; + return _info; } /**************************************************************************** @@ -657,86 +665,86 @@ MadFixedToFloat (mad_fixed_t Fixed) { // cuts readsize if it's beyond boundaries static int -cmp3_decode_cut (int framesize) { - if (buffer.duration >= 0) { - if (buffer.currentsample + buffer.readsize / (framesize * buffer.channels) > buffer.endsample) { - int sz = (buffer.endsample - buffer.currentsample + 1) * framesize * buffer.channels; - trace ("size truncated to %d bytes, cursample=%d, endsample=%d, totalsamples=%d\n", buffer.readsize, buffer.currentsample, buffer.endsample, buffer.totalsamples); +cmp3_decode_cut (mpgmad_info_t *info, int framesize) { + if (info->buffer.duration >= 0) { + if (info->buffer.currentsample + info->buffer.readsize / (framesize * info->buffer.channels) > info->buffer.endsample) { + int sz = (info->buffer.endsample - info->buffer.currentsample + 1) * framesize * info->buffer.channels; + trace ("size truncated to %d bytes, cursample=%d, endsample=%d, totalsamples=%d\n", info->buffer.readsize, info->buffer.currentsample, info->buffer.endsample, info->buffer.totalsamples); if (sz <= 0) { return 1; } - buffer.readsize = sz; + info->buffer.readsize = sz; } } return 0; } static inline void -cmp3_skip (void) { - if (buffer.skipsamples > 0) { - int skip = min (buffer.skipsamples, buffer.decode_remaining); - buffer.skipsamples -= skip; - buffer.decode_remaining -= skip; +cmp3_skip (mpgmad_info_t *info) { + if (info->buffer.skipsamples > 0) { + int skip = min (info->buffer.skipsamples, info->buffer.decode_remaining); + info->buffer.skipsamples -= skip; + info->buffer.decode_remaining -= skip; } } // decoded requested number of samples to int16 format static void -cmp3_decode_requested_int16 (void) { - cmp3_skip (); +cmp3_decode_requested_int16 (mpgmad_info_t *info) { + cmp3_skip (info); // copy synthesized samples into readbuffer - int idx = synth.pcm.length-buffer.decode_remaining; - while (buffer.decode_remaining > 0 && buffer.readsize > 0) { - *((int16_t*)buffer.out) = MadFixedToSshort (synth.pcm.samples[0][idx]); - buffer.readsize -= 2; - buffer.out += 2; - if (MAD_NCHANNELS(&frame.header) == 2) { - *((int16_t*)buffer.out) = MadFixedToSshort (synth.pcm.samples[1][idx]); - buffer.readsize -= 2; - buffer.out += 2; + int idx = info->synth.pcm.length-info->buffer.decode_remaining; + while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) { + *((int16_t*)info->buffer.out) = MadFixedToSshort (info->synth.pcm.samples[0][idx]); + info->buffer.readsize -= 2; + info->buffer.out += 2; + if (MAD_NCHANNELS(&info->frame.header) == 2) { + *((int16_t*)info->buffer.out) = MadFixedToSshort (info->synth.pcm.samples[1][idx]); + info->buffer.readsize -= 2; + info->buffer.out += 2; } - buffer.decode_remaining--; + info->buffer.decode_remaining--; idx++; } - assert (buffer.readsize >= 0); + assert (info->buffer.readsize >= 0); } // decoded requested number of samples to int16 format static void -cmp3_decode_requested_float32 (void) { - cmp3_skip (); - // copy synthesized samples into readbuffer - int idx = synth.pcm.length-buffer.decode_remaining; - while (buffer.decode_remaining > 0 && buffer.readsize > 0) { - *((float*)buffer.out) = MadFixedToFloat (synth.pcm.samples[0][idx]); - buffer.readsize -= 4; - buffer.out += 4; - if (MAD_NCHANNELS(&frame.header) == 2) { - *((float*)buffer.out) = MadFixedToFloat (synth.pcm.samples[1][idx]); - buffer.readsize -= 4; - buffer.out += 4; +cmp3_decode_requested_float32 (mpgmad_info_t *info) { + cmp3_skip (info); + // copy synthesized samples into readinfo->buffer + int idx = info->synth.pcm.length-info->buffer.decode_remaining; + while (info->buffer.decode_remaining > 0 && info->buffer.readsize > 0) { + *((float*)info->buffer.out) = MadFixedToFloat (info->synth.pcm.samples[0][idx]); + info->buffer.readsize -= 4; + info->buffer.out += 4; + if (MAD_NCHANNELS(&info->frame.header) == 2) { + *((float*)info->buffer.out) = MadFixedToFloat (info->synth.pcm.samples[1][idx]); + info->buffer.readsize -= 4; + info->buffer.out += 4; } - buffer.decode_remaining--; + info->buffer.decode_remaining--; idx++; } - assert (buffer.readsize >= 0); + assert (info->buffer.readsize >= 0); } static int -cmp3_stream_frame (void) { +cmp3_stream_frame (mpgmad_info_t *info) { int eof = 0; - while (!eof && (stream.buffer == NULL || buffer.decode_remaining <= 0)) { + while (!eof && (info->stream.buffer == NULL || info->buffer.decode_remaining <= 0)) { // read more MPEG data if needed - if(stream.buffer==NULL || stream.error==MAD_ERROR_BUFLEN) { + if(info->stream.buffer==NULL || info->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); + if (info->stream.next_frame != NULL) { + info->buffer.remaining = info->stream.bufend - info->stream.next_frame; + memmove (info->buffer.input, info->stream.next_frame, info->buffer.remaining); } - int size = READBUFFER - buffer.remaining; + int size = READBUFFER - info->buffer.remaining; int bytesread = 0; - uint8_t *bytes = buffer.input + buffer.remaining; - bytesread = deadbeef->fread (bytes, 1, size, buffer.file); + uint8_t *bytes = info->buffer.input + info->buffer.remaining; + bytesread = deadbeef->fread (bytes, 1, size, info->buffer.file); if (!bytesread) { // add guard eof = 1; @@ -748,70 +756,70 @@ cmp3_stream_frame (void) { size -= bytesread; bytes += bytesread; } - bytesread += buffer.remaining; - mad_stream_buffer(&stream,buffer.input,bytesread); - if (stream.buffer==NULL) { + bytesread += info->buffer.remaining; + mad_stream_buffer(&info->stream,info->buffer.input,bytesread); + if (info->stream.buffer==NULL) { // check sync bits if (bytes[0] != 0xff || (bytes[1]&(3<<5)) != (3<<5)) { trace ("mpgmad: read didn't start at frame boundary!\ncmp3_scan_stream is broken\n"); } } } - stream.error=0; + info->stream.error=0; // decode next frame - if(mad_frame_decode(&frame,&stream)) + if(mad_frame_decode(&info->frame,&info->stream)) { - if(MAD_RECOVERABLE(stream.error)) + if(MAD_RECOVERABLE(info->stream.error)) { #if 0 - if(stream.error!=MAD_ERROR_LOSTSYNC) { + if(info->stream.error!=MAD_ERROR_LOSTSYNC) { trace ("mpgmad: recoverable frame level error (%s)\n", MadErrorString(&stream)); } #endif continue; } else { - if(stream.error==MAD_ERROR_BUFLEN) { + if(info->stream.error==MAD_ERROR_BUFLEN) { continue; } else { - trace ("mpgmad: unrecoverable frame level error (%s).\n", MadErrorString(&stream)); + trace ("mpgmad: unrecoverable frame level error (%s).\n", MadErrorString(&info->stream)); return -1; // fatal error } } } - if (!buffer.it->filetype) { - int layer = frame.header.layer; + if (!info->buffer.it->filetype) { + int layer = info->frame.header.layer; if (layer >= 1 && layer <= 3) { - buffer.it->filetype = plugin.filetypes[layer-1]; + info->buffer.it->filetype = plugin.filetypes[layer-1]; } } - plugin.info.samplerate = frame.header.samplerate; - plugin.info.channels = MAD_NCHANNELS(&frame.header); + info->info.samplerate = info->frame.header.samplerate; + info->info.channels = MAD_NCHANNELS(&info->frame.header); // synthesize single frame - mad_synth_frame(&synth,&frame); - buffer.decode_remaining = synth.pcm.length; - deadbeef->streamer_set_bitrate (frame.header.bitrate/1000); + mad_synth_frame(&info->synth,&info->frame); + info->buffer.decode_remaining = info->synth.pcm.length; + deadbeef->streamer_set_bitrate (info->frame.header.bitrate/1000); break; } return eof; } static int -cmp3_decode_int16 (void) { - if (cmp3_decode_cut (4)) { +cmp3_decode_int16 (mpgmad_info_t *info) { + if (cmp3_decode_cut (info, 4)) { return 0; } int eof = 0; while (!eof) { - eof = cmp3_stream_frame (); - if (buffer.decode_remaining > 0) { - cmp3_decode_requested_int16 (); - if (buffer.readsize == 0) { + eof = cmp3_stream_frame (info); + if (info->buffer.decode_remaining > 0) { + cmp3_decode_requested_int16 (info); + if (info->buffer.readsize == 0) { return 0; } } @@ -820,17 +828,17 @@ cmp3_decode_int16 (void) { } static int -cmp3_decode_float32 (void) { - if (cmp3_decode_cut (8)) { +cmp3_decode_float32 (mpgmad_info_t *info) { + if (cmp3_decode_cut (info, 8)) { trace ("read request ignored (end of track passed)\n"); return 0; } int eof = 0; while (!eof) { - eof = cmp3_stream_frame (); - if (buffer.decode_remaining > 0) { - cmp3_decode_requested_float32 (); - if (buffer.readsize == 0) { + eof = cmp3_stream_frame (info); + if (info->buffer.decode_remaining > 0) { + cmp3_decode_requested_float32 (info); + if (info->buffer.readsize == 0) { return 0; } } @@ -839,60 +847,65 @@ cmp3_decode_float32 (void) { } static void -cmp3_free (void) { - if (buffer.file) { - deadbeef->fclose (buffer.file); - buffer.file = NULL; - mad_synth_finish (&synth); - mad_frame_finish (&frame); - mad_stream_finish (&stream); +cmp3_free (DB_fileinfo_t *_info) { + mpgmad_info_t *info = (mpgmad_info_t *)_info; + if (info->buffer.file) { + deadbeef->fclose (info->buffer.file); + info->buffer.file = NULL; + mad_synth_finish (&info->synth); + mad_frame_finish (&info->frame); + mad_stream_finish (&info->stream); } + free (info); } static int -cmp3_read_int16 (char *bytes, int size) { - buffer.readsize = size; - buffer.out = bytes; - cmp3_decode_int16 (); - buffer.currentsample += (size - buffer.readsize) / 4; - plugin.info.readpos = (float)(buffer.currentsample - buffer.startsample) / buffer.samplerate; - return size - buffer.readsize; +cmp3_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) { + mpgmad_info_t *info = (mpgmad_info_t *)_info; + info->buffer.readsize = size; + info->buffer.out = bytes; + cmp3_decode_int16 (info); + info->buffer.currentsample += (size - info->buffer.readsize) / 4; + _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate; + return size - info->buffer.readsize; } static int -cmp3_read_float32 (char *bytes, int size) { - buffer.readsize = size; - buffer.out = bytes; - cmp3_decode_float32 (); - buffer.currentsample += (size - buffer.readsize) / 8; - plugin.info.readpos = (float)(buffer.currentsample - buffer.startsample) / buffer.samplerate; - return size - buffer.readsize; +cmp3_read_float32 (DB_fileinfo_t *_info, char *bytes, int size) { + mpgmad_info_t *info = (mpgmad_info_t *)_info; + info->buffer.readsize = size; + info->buffer.out = bytes; + cmp3_decode_float32 (info); + info->buffer.currentsample += (size - info->buffer.readsize) / 8; + _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate; + return size - info->buffer.readsize; } static int -cmp3_seek_sample (int sample) { - if (!buffer.file) { +cmp3_seek_sample (DB_fileinfo_t *_info, int sample) { + mpgmad_info_t *info = (mpgmad_info_t *)_info; + if (!info->buffer.file) { return -1; } - if (buffer.file->vfs->streaming) { - if (buffer.totalsamples > 0) { + if (info->buffer.file->vfs->streaming) { + if (info->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); + int64_t l = deadbeef->fgetlength (info->buffer.file); + l = l * sample / info->buffer.totalsamples; + int r = deadbeef->fseek (info->buffer.file, l, SEEK_SET); if (!r) { - buffer.currentsample = sample; - plugin.info.readpos = (float)(buffer.currentsample - buffer.startsample) / buffer.samplerate; - - mad_synth_finish (&synth); - mad_frame_finish (&frame); - mad_stream_finish (&stream); - buffer.remaining = 0; - buffer.decode_remaining = 0; - mad_stream_init(&stream); - mad_frame_init(&frame); - mad_synth_init(&synth); + info->buffer.currentsample = sample; + _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate; + + mad_synth_finish (&info->synth); + mad_frame_finish (&info->frame); + mad_stream_finish (&info->stream); + info->buffer.remaining = 0; + info->buffer.decode_remaining = 0; + mad_stream_init(&info->stream); + mad_frame_init(&info->frame); + mad_synth_init(&info->synth); return 0; } @@ -901,47 +914,48 @@ cmp3_seek_sample (int sample) { return 0; } - sample += buffer.startsample + buffer.startdelay; - if (sample > buffer.endsample) { - trace ("seek sample %d is beyond end of track (%d)\n", sample, buffer.endsample); + sample += info->buffer.startsample + info->buffer.startdelay; + if (sample > info->buffer.endsample) { + trace ("seek sample %d is beyond end of track (%d)\n", sample, info->buffer.endsample); return -1; // eof } // restart file, and load until we hit required pos - deadbeef->fseek (buffer.file, 0, SEEK_SET); - int skip = deadbeef->junk_get_leading_size (buffer.file); + deadbeef->fseek (info->buffer.file, 0, SEEK_SET); + int skip = deadbeef->junk_get_leading_size (info->buffer.file); if (skip > 0) { - deadbeef->fseek(buffer.file, skip, SEEK_SET); + deadbeef->fseek (info->buffer.file, skip, SEEK_SET); } - mad_synth_finish (&synth); - mad_frame_finish (&frame); - mad_stream_finish (&stream); - buffer.remaining = 0; - buffer.readsize = 0; - buffer.decode_remaining = 0; + mad_synth_finish (&info->synth); + mad_frame_finish (&info->frame); + mad_stream_finish (&info->stream); + info->buffer.remaining = 0; + info->buffer.readsize = 0; + info->buffer.decode_remaining = 0; if (sample == 0) { - plugin.info.readpos = 0; - buffer.currentsample = 0; - buffer.skipsamples = buffer.startdelay; + _info->readpos = 0; + info->buffer.currentsample = 0; + info->buffer.skipsamples = info->buffer.startdelay; return 0; } - if (cmp3_scan_stream (&buffer, sample) == -1) { + if (cmp3_scan_stream (&info->buffer, sample) == -1) { trace ("failed to seek to sample %d\n", sample); - plugin.info.readpos = 0; + _info->readpos = 0; return -1; } - mad_stream_init(&stream); - mad_frame_init(&frame); - mad_synth_init(&synth); - plugin.info.readpos = (float)(buffer.currentsample - buffer.startsample) / buffer.samplerate; + mad_stream_init(&info->stream); + mad_frame_init(&info->frame); + mad_synth_init(&info->synth); + _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate; return 0; } static int -cmp3_seek (float time) { - int sample = time * buffer.samplerate; - return cmp3_seek_sample (sample); +cmp3_seek (DB_fileinfo_t *_info, float time) { + mpgmad_info_t *info = (mpgmad_info_t *)_info; + int sample = time * info->buffer.samplerate; + return cmp3_seek_sample (_info, sample); } static const char *filetypes[] = { @@ -950,8 +964,10 @@ static const char *filetypes[] = { static DB_playItem_t * cmp3_insert (DB_playItem_t *after, const char *fname) { + trace ("cmp3_insert %s\n", fname); DB_FILE *fp = deadbeef->fopen (fname); if (!fp) { + trace ("failed to open file %s\n", fname); return NULL; } if (fp->vfs->streaming) { @@ -975,6 +991,7 @@ cmp3_insert (DB_playItem_t *after, const char *fname) { // calc approx. mp3 duration int res = cmp3_scan_stream (&buffer, 0); if (res < 0) { + trace ("mpgmad: cmp3_scan_stream returned error\n"); deadbeef->fclose (fp); return NULL; } @@ -89,7 +89,7 @@ playItem_t str_streaming_song; static playItem_t *orig_playing_song; static playItem_t *orig_streaming_song; // current decoder -static DB_decoder_t *str_current_decoder; +static DB_fileinfo_t *str_current_decoder; static int streamer_buffering; @@ -144,7 +144,7 @@ streamer_set_current (playItem_t *it) { #endif trace ("streamer_set_current %p, buns=%d\n", it); if(str_current_decoder) { - str_current_decoder->free (); + str_current_decoder->plugin->free (str_current_decoder); str_current_decoder = NULL; pl_item_free (&str_streaming_song); } @@ -183,25 +183,23 @@ streamer_set_current (playItem_t *it) { dec = plug_get_decoder_for_id (it->decoder_id); } if (dec) { - str_current_decoder = dec; streamer_lock (); streamer_unlock (); - int ret = str_current_decoder->init (DB_PLAYITEM (it)); + str_current_decoder = dec->init (DB_PLAYITEM (it)); streamer_lock (); streamer_unlock (); pl_item_copy (&str_streaming_song, it); - if (ret < 0) { - str_current_decoder = NULL; - trace ("decoder->init returned %d\n", ret); + if (!str_current_decoder) { + trace ("decoder->init returned NULL\n"); trace ("orig_playing_song = %p\n", orig_playing_song); if (orig_playing_song == it) { orig_playing_song = NULL; messagepump_push (M_TRACKCHANGED, 0, to, 0); } - return ret; + return -1; } else { - trace ("bps=%d, channels=%d, samplerate=%d\n", dec->info.bps, dec->info.channels, dec->info.samplerate); + trace ("bps=%d, channels=%d, samplerate=%d\n", str_current_decoder->bps, str_current_decoder->channels, str_current_decoder->samplerate); } streamer_reset (0); // reset SRC } @@ -378,9 +376,9 @@ streamer_thread (void *ctx) { plug_trigger_event (DB_EV_SONGSTARTED, 0); playpos = 0; // change samplerate - if (prevtrack_samplerate != str_current_decoder->info.samplerate) { - plug_get_output ()->change_rate (str_current_decoder->info.samplerate); - prevtrack_samplerate = str_current_decoder->info.samplerate; + if (prevtrack_samplerate != str_current_decoder->samplerate) { + plug_get_output ()->change_rate (str_current_decoder->samplerate); + prevtrack_samplerate = str_current_decoder->samplerate; } } @@ -393,7 +391,8 @@ streamer_thread (void *ctx) { trace ("streamer already switched to next track\n"); // restart playing from new position if(str_current_decoder) { - str_current_decoder->free (); + str_current_decoder->plugin->free (str_current_decoder); + str_current_decoder = NULL; pl_item_free (&str_streaming_song); } orig_streaming_song = orig_playing_song; @@ -404,8 +403,11 @@ streamer_thread (void *ctx) { if (trk != -1) { messagepump_push (M_TRACKCHANGED, 0, trk, 0); } - int ret = str_current_decoder->init (DB_PLAYITEM (orig_streaming_song)); - if (ret < 0) { + DB_decoder_t *plug = plug_get_decoder_for_id (orig_streaming_song->decoder_id); + if (plug) { + str_current_decoder = plug->init (DB_PLAYITEM (orig_streaming_song)); + } + if (!plug || !str_current_decoder) { streamer_buffering = 0; if (trk != -1) { messagepump_push (M_TRACKCHANGED, 0, trk, 0); @@ -430,8 +432,8 @@ streamer_thread (void *ctx) { codec_lock (); codecleft = 0; codec_unlock (); - if (str_current_decoder->seek (pos) >= 0) { - playpos = str_current_decoder->info.readpos; + if (str_current_decoder->plugin->seek (str_current_decoder, pos) >= 0) { + playpos = str_current_decoder->readpos; } last_bitrate = -1; avg_bitrate = -1; @@ -475,7 +477,8 @@ streamer_thread (void *ctx) { // stop streaming song if(str_current_decoder) { - str_current_decoder->free (); + str_current_decoder->plugin->free (str_current_decoder); + str_current_decoder = NULL; } pl_item_free (&str_streaming_song); pl_item_free (&str_playing_song); @@ -670,24 +673,28 @@ streamer_read_async (char *bytes, int size) { for (;;) { int bytesread = 0; codec_lock (); - DB_decoder_t *decoder = str_current_decoder; + if (!str_current_decoder) { + codec_unlock (); + break; + } + DB_decoder_t *decoder = str_current_decoder->plugin; if (!decoder) { // means there's nothing left to stream, so just do nothing codec_unlock (); break; } - if (decoder->info.samplerate != -1) { - int nchannels = decoder->info.channels; - int samplerate = decoder->info.samplerate; - if (decoder->info.samplerate == p_get_rate ()) { + if (str_current_decoder->samplerate != -1) { + int nchannels = str_current_decoder->channels; + int samplerate = str_current_decoder->samplerate; + if (str_current_decoder->samplerate == p_get_rate ()) { // samplerate match - if (decoder->info.channels == 2) { - bytesread = decoder->read_int16 (bytes, size); + if (str_current_decoder->channels == 2) { + bytesread = decoder->read_int16 (str_current_decoder, bytes, size); apply_replay_gain_int16 (&str_streaming_song, bytes, size); codec_unlock (); } else { - bytesread = decoder->read_int16 (g_readbuffer, size>>1); + bytesread = decoder->read_int16 (str_current_decoder, g_readbuffer, size>>1); apply_replay_gain_int16 (&str_streaming_song, g_readbuffer, size>>1); mono_int16_to_stereo_int16 ((int16_t*)g_readbuffer, (int16_t*)bytes, size>>2); bytesread *= 2; @@ -710,7 +717,7 @@ streamer_read_async (char *bytes, int size) { trace ("input buffer overflow\n"); nbytes = INPUT_BUFFER_SIZE; } - bytesread = decoder->read_int16 (g_readbuffer, nbytes); + bytesread = decoder->read_int16 (str_current_decoder, g_readbuffer, nbytes); apply_replay_gain_int16 (&str_streaming_song, g_readbuffer, nbytes); } else { @@ -737,7 +744,7 @@ streamer_read_async (char *bytes, int size) { float *fbuffer = g_fbuffer + codecleft*2; if (nchannels == 1) { codec_lock (); - bytesread = decoder->read_float32 (g_readbuffer, nbytes*2); + bytesread = decoder->read_float32 (str_current_decoder, g_readbuffer, nbytes*2); codec_unlock (); apply_replay_gain_float32 (&str_streaming_song, g_readbuffer, nbytes*2); nsamples = bytesread / (samplesize * nchannels) + codecleft; @@ -745,7 +752,7 @@ streamer_read_async (char *bytes, int size) { } else { codec_lock (); - bytesread = decoder->read_float32 ((char *)fbuffer, nbytes*2); + bytesread = decoder->read_float32 (str_current_decoder, (char *)fbuffer, nbytes*2); codec_unlock (); apply_replay_gain_float32 (&str_streaming_song, (char *)fbuffer, nbytes*2); nsamples = bytesread / (samplesize * nchannels) + codecleft; @@ -1169,7 +1176,7 @@ streamer_get_current (void) { return orig_playing_song; } -struct DB_decoder_s * +struct DB_fileinfo_s * streamer_get_current_decoder (void) { return str_current_decoder; } @@ -98,7 +98,7 @@ streamer_move_randomsong (void); playItem_t * streamer_get_current (void); -struct DB_decoder_s * +struct DB_fileinfo_s * streamer_get_current_decoder (void); #endif // __STREAMER_H @@ -21,8 +21,8 @@ #include "vfs.h" #include "plugins.h" -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) DB_FILE * vfs_fopen (const char *fname) { |