From b5bedb49dad2da3aab4a997ac6daad1c4f30d67a Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Mon, 28 Sep 2009 22:56:57 +0200 Subject: added VFS plugins implemented stdio VFS plugin ported flac, mpgmad, ffap, vorbis, wavpack, junklib to VFS --- Makefile.am | 3 +- deadbeef.h | 40 ++++++++++-- junklib.c | 43 +++++++------ junklib.h | 10 +-- moduleconf.h | 1 + plugins.c | 44 ++++++++++--- plugins.h | 5 ++ plugins/ffap/ffap.c | 53 +++++++-------- plugins/flac/flac.c | 160 +++++++++++++++++++++++++++++++++------------- plugins/mpgmad/mpgmad.c | 102 ++++++++++++++--------------- plugins/vorbis/vorbis.c | 48 ++++++++++++-- plugins/wavpack/wavpack.c | 94 +++++++++++++++++++++++---- vfs.c | 72 +++++++++++++++++++++ vfs.h | 32 ++++++++++ vfs_stdio.c | 98 ++++++++++++++++++++++++++++ 15 files changed, 622 insertions(+), 183 deletions(-) create mode 100644 vfs.c create mode 100644 vfs.h create mode 100644 vfs_stdio.c diff --git a/Makefile.am b/Makefile.am index b79c89d7..1e0a07d2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,7 +41,8 @@ deadbeef_SOURCES =\ drawing.h gdkdrawing.c\ session.h session.c gtksession.c\ junklib.h junklib.c utf8.c utf8.h\ - optmath.h + optmath.h\ + vfs.c vfs.h vfs_stdio.c sdkdir = $(pkgincludedir) sdk_HEADERS = deadbeef.h diff --git a/deadbeef.h b/deadbeef.h index ddff5aed..9c8fdb86 100644 --- a/deadbeef.h +++ b/deadbeef.h @@ -29,7 +29,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -54,7 +53,7 @@ extern "C" { // DON'T release plugins without DB_PLUGIN_SET_API_VERSION #define DB_API_VERSION_MAJOR 0 -#define DB_API_VERSION_MINOR 2 +#define DB_API_VERSION_MINOR 3 #define DB_PLUGIN_SET_API_VERSION\ .plugin.api_vmajor = DB_API_VERSION_MAJOR,\ @@ -87,7 +86,8 @@ enum { DB_PLUGIN_DECODER = 1, DB_PLUGIN_OUTPUT = 2, DB_PLUGIN_DSP = 3, - DB_PLUGIN_MISC = 4 + DB_PLUGIN_MISC = 4, + DB_PLUGIN_VFS = 5, }; typedef struct { @@ -118,6 +118,11 @@ enum { #define DB_EVENT(x) ((DB_event_t *)(x)) #define DB_PLAYITEM(x) ((DB_playItem_t *)(x)) +// FILE object wrapper for vfs access +typedef struct { + struct DB_vfs_s *vfs; +} DB_FILE; + // forward decl for plugin struct struct DB_plugin_s; @@ -174,10 +179,17 @@ typedef struct { void (*volume_set_amp) (float amp); float (*volume_get_amp) (void); // junk reading - int (*junk_read_id3v1) (DB_playItem_t *it, FILE *fp); - int (*junk_read_id3v2) (DB_playItem_t *it, FILE *fp); - int (*junk_read_ape) (DB_playItem_t *it, FILE *fp); - int (*junk_get_leading_size) (FILE *fp); + int (*junk_read_id3v1) (DB_playItem_t *it, DB_FILE *fp); + int (*junk_read_id3v2) (DB_playItem_t *it, DB_FILE *fp); + int (*junk_read_ape) (DB_playItem_t *it, DB_FILE *fp); + int (*junk_get_leading_size) (DB_FILE *fp); + // vfs + DB_FILE* (*fopen) (const char *fname); + void (*fclose) (DB_FILE *f); + size_t (*fread) (void *ptr, size_t size, size_t nmemb, DB_FILE *stream); + int (*fseek) (DB_FILE *stream, long offset, int whence); + long (*ftell) (DB_FILE *stream); + void (*rewind) (DB_FILE *stream); } DB_functions_t; // base plugin interface @@ -302,6 +314,20 @@ typedef struct { DB_plugin_t plugin; } DB_misc_t; +// vfs plugin +// provides means for reading, seeking, etc +// api is based on stdio +typedef struct DB_vfs_s { + DB_plugin_t plugin; + DB_FILE* (*open) (const char *fname); + void (*close) (DB_FILE *f); + size_t (*read) (void *ptr, size_t size, size_t nmemb, DB_FILE *stream); + int (*seek) (DB_FILE *stream, long offset, int whence); + long (*tell) (DB_FILE *stream); + void (*rewind) (DB_FILE *stream); + const char **scheme_names; // NULL-terminated list of supported schemes, e.g. {"http", "ftp", NULL} +} DB_vfs_t; + #ifdef __cplusplus } #endif diff --git a/junklib.c b/junklib.c index 0169e1a8..b35a658a 100644 --- a/junklib.c +++ b/junklib.c @@ -22,6 +22,7 @@ #include #include "playlist.h" #include "utf8.h" +#include "plugins.h" #define trace(...) { fprintf(stderr, __VA_ARGS__); } //#define trace(fmt,...) @@ -420,15 +421,15 @@ str_trim_right (uint8_t *str, int len) { // should read both id3v1 and id3v1.1 int -junk_read_id3v1 (playItem_t *it, FILE *fp) { +junk_read_id3v1 (playItem_t *it, DB_FILE *fp) { if (!it || !fp) { trace ("bad call to junk_read_id3v1!\n"); return -1; } uint8_t buffer[128]; // try reading from end - fseek (fp, -128, SEEK_END); - if (fread (buffer, 1, 128, fp) != 128) { + deadbeef->fseek (fp, -128, SEEK_END); + if (deadbeef->fread (buffer, 1, 128, fp) != 128) { return -1; } if (strncmp (buffer, "TAG", 3)) { @@ -496,24 +497,24 @@ junk_read_id3v1 (playItem_t *it, FILE *fp) { } int -junk_read_ape (playItem_t *it, FILE *fp) { +junk_read_ape (playItem_t *it, DB_FILE *fp) { // trace ("trying to read ape tag\n"); // try to read footer, position must be already at the EOF right before // id3v1 (if present) uint8_t header[32]; - if (fseek (fp, -32, SEEK_END) == -1) { + if (deadbeef->fseek (fp, -32, SEEK_END) == -1) { return -1; // something bad happened } - if (fread (header, 1, 32, fp) != 32) { + if (deadbeef->fread (header, 1, 32, fp) != 32) { return -1; // something bad happened } if (strncmp (header, "APETAGEX", 8)) { // try to skip 128 bytes backwards (id3v1) - if (fseek (fp, -128-32, SEEK_END) == -1) { + if (deadbeef->fseek (fp, -128-32, SEEK_END) == -1) { return -1; // something bad happened } - if (fread (header, 1, 32, fp) != 32) { + if (deadbeef->fread (header, 1, 32, fp) != 32) { return -1; // something bad happened } if (strncmp (header, "APETAGEX", 8)) { @@ -534,14 +535,14 @@ junk_read_ape (playItem_t *it, FILE *fp) { //trace ("APEv%d, size=%d, items=%d, flags=%x\n", version, size, numitems, flags); // now seek to beginning of the tag (exluding header) - if (fseek (fp, -size, SEEK_CUR) == -1) { + if (deadbeef->fseek (fp, -size, SEEK_CUR) == -1) { trace ("failed to seek to tag start (-%d)\n", size); return -1; } int i; for (i = 0; i < numitems; i++) { uint8_t buffer[8]; - if (fread (buffer, 1, 8, fp) != 8) { + if (deadbeef->fread (buffer, 1, 8, fp) != 8) { return -1; } uint32_t itemsize = extract_i32_le (&buffer[0]); @@ -550,7 +551,7 @@ junk_read_ape (playItem_t *it, FILE *fp) { char key[256]; int keysize = 0; while (keysize <= 255) { - if (fread (&key[keysize], 1, 1, fp) != 1) { + if (deadbeef->fread (&key[keysize], 1, 1, fp) != 1) { return -1; } if (key[keysize] == 0) { @@ -564,7 +565,7 @@ junk_read_ape (playItem_t *it, FILE *fp) { key[255] = 0; // read value char value[itemsize+1]; - if (fread (value, 1, itemsize, fp) != itemsize) { + if (deadbeef->fread (value, 1, itemsize, fp) != itemsize) { return -1; } value[itemsize] = 0; @@ -644,14 +645,14 @@ id3v2_string_read (int version, uint8_t *out, int sz, int unsync, const uint8_t } int -junk_get_leading_size (FILE *fp) { +junk_get_leading_size (DB_FILE *fp) { uint8_t header[10]; - int pos = ftell (fp); - if (fread (header, 1, 10, fp) != 10) { - fseek (fp, pos, SEEK_SET); + int pos = deadbeef->ftell (fp); + if (deadbeef->fread (header, 1, 10, fp) != 10) { + deadbeef->fseek (fp, pos, SEEK_SET); return -1; // too short } - fseek (fp, pos, SEEK_SET); + deadbeef->fseek (fp, pos, SEEK_SET); if (strncmp (header, "ID3", 3)) { return -1; // no tag } @@ -678,15 +679,15 @@ junk_get_leading_size (FILE *fp) { } int -junk_read_id3v2 (playItem_t *it, FILE *fp) { +junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { int title_added = 0; if (!it || !fp) { trace ("bad call to junk_read_id3v2!\n"); return -1; } - rewind (fp); + deadbeef->rewind (fp); uint8_t header[10]; - if (fread (header, 1, 10, fp) != 10) { + if (deadbeef->fread (header, 1, 10, fp) != 10) { return -1; // too short } if (strncmp (header, "ID3", 3)) { @@ -725,7 +726,7 @@ junk_read_id3v2 (playItem_t *it, FILE *fp) { return -1; } uint8_t tag[size]; - if (fread (tag, 1, size, fp) != size) { + if (deadbeef->fread (tag, 1, size, fp) != size) { return -1; // bad size } uint8_t *readptr = tag; diff --git a/junklib.h b/junklib.h index 76399bd6..807c300d 100644 --- a/junklib.h +++ b/junklib.h @@ -18,21 +18,21 @@ #ifndef __JUNKLIB_H #define __JUNKLIB_H -#include +#include "deadbeef.h" struct playItem_s; int -junk_read_id3v1 (struct playItem_s *it, FILE *fp); +junk_read_id3v1 (struct playItem_s *it, DB_FILE *fp); int -junk_read_id3v2 (struct playItem_s *it, FILE *fp); +junk_read_id3v2 (struct playItem_s *it, DB_FILE *fp); int -junk_read_ape (struct playItem_s *it, FILE *fp); +junk_read_ape (struct playItem_s *it, DB_FILE *fp); int -junk_get_leading_size (FILE *fp); +junk_get_leading_size (DB_FILE *fp); const char * junk_detect_charset (const char *s); diff --git a/moduleconf.h b/moduleconf.h index fbb48a9a..4fdc123c 100644 --- a/moduleconf.h +++ b/moduleconf.h @@ -1,3 +1,4 @@ PLUG(gme) PLUG(dumb) PLUG(sid) +PLUG(stdio) diff --git a/plugins.c b/plugins.c index 85067630..33938c33 100644 --- a/plugins.c +++ b/plugins.c @@ -39,6 +39,7 @@ #include "common.h" #include "conf.h" #include "junklib.h" +#include "vfs.h" //#define DISABLE_VERSIONCHECK 1 @@ -97,8 +98,17 @@ static DB_functions_t deadbeef_api = { .junk_read_id3v2 = (int (*)(DB_playItem_t *it, FILE *fp))junk_read_id3v2, .junk_read_ape = (int (*)(DB_playItem_t *it, FILE *fp))junk_read_ape, .junk_get_leading_size = junk_get_leading_size, + // vfs + .fopen = vfs_fopen, + .fclose = vfs_fclose, + .fread = vfs_fread, + .fseek = vfs_fseek, + .ftell = vfs_ftell, + .rewind = vfs_rewind, }; +DB_functions_t *deadbeef = &deadbeef_api; + const char * plug_get_config_dir (void) { return dbconfdir; @@ -119,8 +129,11 @@ plug_volume_set_amp (float amp) { volumebar_notify_changed (); } -#define MAX_DECODERS 50 -DB_decoder_t *g_decoders[MAX_DECODERS+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]; void plug_md5 (uint8_t sig[16], const char *in, int len) { @@ -390,19 +403,29 @@ plug_load_all (void) { #include "moduleconf.h" #undef PLUG - // find all decoders, and put in g_decoders list + // categorize plugins int numdecoders = 0; + int numvfs = 0; for (plugin_t *plug = plugins; plug; plug = plug->next) { if (plug->plugin->type == DB_PLUGIN_DECODER) { - printf ("found decoder plugin %s\n", plug->plugin->name); - if (numdecoders >= MAX_DECODERS) { + fprintf (stderr, "found decoder plugin %s\n", plug->plugin->name); + if (numdecoders >= MAX_DECODER_PLUGINS) { break; } - g_decoders[numdecoders] = (DB_decoder_t *)plug->plugin; + g_decoder_plugins[numdecoders] = (DB_decoder_t *)plug->plugin; numdecoders++; } + else if (plug->plugin->type == DB_PLUGIN_VFS) { + fprintf (stderr, "found vfs plugin %s\n", plug->plugin->name); + if (numvfs >= MAX_VFS_PLUGINS) { + break; + } + g_vfs_plugins[numvfs] = (DB_vfs_t *)plug->plugin; + numvfs++; + } } - g_decoders[numdecoders] = NULL; + g_decoder_plugins[numdecoders] = NULL; + g_vfs_plugins[numvfs] = NULL; } void @@ -422,6 +445,11 @@ plug_unload_all (void) { struct DB_decoder_s ** plug_get_decoder_list (void) { - return g_decoders; + return g_decoder_plugins; +} + +struct DB_vfs_s ** +plug_get_vfs_list (void) { + return g_vfs_plugins; } diff --git a/plugins.h b/plugins.h index ca0c5668..f1d542a5 100644 --- a/plugins.h +++ b/plugins.h @@ -20,6 +20,8 @@ #define __PLUGINS_H #include "deadbeef.h" +extern DB_functions_t *deadbeef; + void plug_load_all (void); @@ -71,6 +73,9 @@ plug_playback_set_pos (float pos); struct DB_decoder_s ** plug_get_decoder_list (void); +struct DB_vfs_s ** +plug_get_vfs_list (void); + void plug_volume_set_db (float db); diff --git a/plugins/ffap/ffap.c b/plugins/ffap/ffap.c index 68899578..735630bf 100644 --- a/plugins/ffap/ffap.c +++ b/plugins/ffap/ffap.c @@ -268,15 +268,14 @@ typedef struct APEContext { } APEContext; APEContext ape_ctx; -FILE *fp; inline static int -read_uint16(FILE *fp, uint16_t* x) +read_uint16(DB_FILE *fp, uint16_t* x) { unsigned char tmp[2]; int n; - n = fread(tmp, 1, 2, fp); + n = deadbeef->fread(tmp, 1, 2, fp); if (n != 2) return -1; @@ -288,18 +287,18 @@ read_uint16(FILE *fp, uint16_t* x) inline static int -read_int16(FILE *fp, int16_t* x) +read_int16(DB_FILE *fp, int16_t* x) { return read_uint16(fp, (uint16_t*)x); } inline static int -read_uint32(FILE *fp, uint32_t* x) +read_uint32(DB_FILE *fp, uint32_t* x) { unsigned char tmp[4]; int n; - n = fread(tmp, 1, 4, fp); + n = deadbeef->fread(tmp, 1, 4, fp); if (n != 4) return -1; @@ -365,7 +364,7 @@ static void ape_dumpinfo(APEContext * ape_ctx) } static int -ape_read_header(FILE *fp, APEContext *ape) +ape_read_header(DB_FILE *fp, APEContext *ape) { int i; int total_blocks; @@ -373,7 +372,7 @@ ape_read_header(FILE *fp, APEContext *ape) /* TODO: Skip any leading junk such as id3v2 tags */ ape->junklength = 0; - if (fread (ape->magic, 1, 4, fp) != 4) { + if (deadbeef->fread (ape->magic, 1, 4, fp) != 4) { return -1; } if (memcmp (ape->magic, "MAC ", 4)) @@ -413,14 +412,14 @@ ape_read_header(FILE *fp, APEContext *ape) if (read_uint32 (fp, &ape->wavtaillength) < 0) { return -1; } - if (fread (ape->md5, 1, 16, fp) != 16) { + if (deadbeef->fread (ape->md5, 1, 16, fp) != 16) { return -1; } /* Skip any unknown bytes at the end of the descriptor. This is for future compatibility */ if (ape->descriptorlength > 52) { - fseek (fp, ape->descriptorlength - 52, SEEK_CUR); + deadbeef->fseek (fp, ape->descriptorlength - 52, SEEK_CUR); } /* Read header data */ @@ -478,7 +477,7 @@ ape_read_header(FILE *fp, APEContext *ape) } if (ape->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL) { - fseek(fp, 4, SEEK_CUR); /* Skip the peak level */ + deadbeef->fseek(fp, 4, SEEK_CUR); /* Skip the peak level */ ape->headerlength += 4; } @@ -507,7 +506,7 @@ ape_read_header(FILE *fp, APEContext *ape) /* Skip any stored wav header */ if (!(ape->formatflags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)) { - fseek (fp, ape->wavheaderlength, SEEK_CUR); + deadbeef->fseek (fp, ape->wavheaderlength, SEEK_CUR); } } @@ -583,19 +582,19 @@ static inline const uint32_t bswap_32(uint32_t x) return x; } -static int ape_read_packet(FILE *fp, APEContext *ape_ctx) +static int ape_read_packet(DB_FILE *fp, APEContext *ape_ctx) { int ret; int nblocks; APEContext *ape = ape_ctx; uint32_t extra_size = 8; - if (feof(fp)) - return -1; if (ape->currentframe > ape->totalframes) return -1; // fprintf (stderr, "seeking to %d\n", ape->frames[ape->currentframe].pos); - fseek (fp, ape->frames[ape->currentframe].pos, SEEK_SET); + if (deadbeef->fseek (fp, ape->frames[ape->currentframe].pos, SEEK_SET) != 0) { + return -1; + } /* Calculate how many blocks there are in this frame */ if (ape->currentframe == (ape->totalframes - 1)) @@ -615,7 +614,7 @@ static int ape_read_packet(FILE *fp, APEContext *ape_ctx) int sz = PACKET_BUFFER_SIZE-8; sz = min (sz, ape->frames[ape->currentframe].size); // fprintf (stderr, "readsize: %d, packetsize: %d\n", sz, ape->frames[ape->currentframe].size); - ret = fread (ape->packet_data + extra_size, 1, sz, fp); + ret = deadbeef->fread (ape->packet_data + extra_size, 1, sz, fp); ape->packet_sizeleft = ape->frames[ape->currentframe].size - sz + 8; ape->packet_remaining = sz+8; @@ -664,10 +663,12 @@ static int ape_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp } #endif +static DB_FILE *fp; + static int ffap_init(DB_playItem_t *it) { - fp = fopen (it->fname, "rb"); + fp = deadbeef->fopen (it->fname); if (!fp) { return -1; } @@ -1548,7 +1549,7 @@ ape_decode_frame(APEContext *s, void *data, int *data_size) sz = min (sz, s->packet_sizeleft); sz = sz&~3; uint8_t *p = s->packet_data + s->packet_remaining; - int r = fread (p, 1, sz, fp); + int r = deadbeef->fread (p, 1, sz, fp); //if (r != s) { // fprintf (stderr, "unexpected eof while reading ape frame\n"); // return -1; @@ -1626,19 +1627,19 @@ static DB_playItem_t * ffap_insert (DB_playItem_t *after, const char *fname) { APEContext ape_ctx; memset (&ape_ctx, 0, sizeof (ape_ctx)); - FILE *fp = fopen (fname, "rb"); + DB_FILE *fp = deadbeef->fopen (fname); if (!fp) { return NULL; } if (ape_read_header (fp, &ape_ctx) < 0) { fprintf (stderr, "failed to read ape header\n"); - fclose (fp); + deadbeef->fclose (fp); ape_free_ctx (&ape_ctx); return NULL; } if ((ape_ctx.fileversion < APE_MIN_VERSION) || (ape_ctx.fileversion > APE_MAX_VERSION)) { fprintf(stderr, "unsupported file version - %.2f\n", ape_ctx.fileversion/1000.0); - fclose (fp); + deadbeef->fclose (fp); ape_free_ctx (&ape_ctx); return NULL; } @@ -1647,7 +1648,7 @@ ffap_insert (DB_playItem_t *after, const char *fname) { DB_playItem_t *it; it = deadbeef->pl_insert_cue (after, fname, &plugin, "APE", ape_ctx.totalsamples, ape_ctx.samplerate); if (it) { - fclose (fp); + deadbeef->fclose (fp); ape_free_ctx (&ape_ctx); return it; } @@ -1661,16 +1662,16 @@ ffap_insert (DB_playItem_t *after, const char *fname) { int v2err = deadbeef->junk_read_id3v2 (it, fp); int v1err = deadbeef->junk_read_id3v1 (it, fp); if (v1err >= 0) { - fseek (fp, -128, SEEK_END); + deadbeef->fseek (fp, -128, SEEK_END); } else { - fseek (fp, 0, SEEK_END); + deadbeef->fseek (fp, 0, SEEK_END); } int apeerr = deadbeef->junk_read_ape (it, fp); deadbeef->pl_add_meta (it, "title", NULL); after = deadbeef->pl_insert_item (after, it); - fclose (fp); + deadbeef->fclose (fp); ape_free_ctx (&ape_ctx); return after; } diff --git a/plugins/flac/flac.c b/plugins/flac/flac.c index aebe061e..a2e8506a 100644 --- a/plugins/flac/flac.c +++ b/plugins/flac/flac.c @@ -24,8 +24,8 @@ static DB_decoder_t plugin; static DB_functions_t *deadbeef; -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) @@ -39,8 +39,10 @@ static int endsample; static int currentsample; typedef struct { + DB_FILE *file; DB_playItem_t *after; DB_playItem_t *last; + DB_playItem_t *it; const char *fname; int samplerate; int channels; @@ -48,6 +50,45 @@ typedef struct { int bps; } cue_cb_data_t; +static cue_cb_data_t flac_callbacks; + +// callbacks +FLAC__StreamDecoderReadStatus flac_read_cb (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) { + cue_cb_data_t *cb = (cue_cb_data_t *)client_data; + size_t r = deadbeef->fread (buffer, 1, *bytes, cb->file); + *bytes = r; + if (r == 0) { + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +FLAC__StreamDecoderSeekStatus flac_seek_cb (const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) { + cue_cb_data_t *cb = (cue_cb_data_t *)client_data; + int r = deadbeef->fseek (cb->file, absolute_byte_offset, SEEK_SET); + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +FLAC__StreamDecoderTellStatus flac_tell_cb (const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) { + cue_cb_data_t *cb = (cue_cb_data_t *)client_data; + size_t r = deadbeef->ftell (cb->file); + *absolute_byte_offset = r; + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +FLAC__StreamDecoderLengthStatus flac_lenght_cb (const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) { + cue_cb_data_t *cb = (cue_cb_data_t *)client_data; + size_t pos = deadbeef->ftell (cb->file); + deadbeef->fseek (cb->file, 0, SEEK_END); + *stream_length = deadbeef->ftell (cb->file); + deadbeef->fseek (cb->file, pos, SEEK_SET); + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +FLAC__bool flac_eof_cb (const FLAC__StreamDecoder *decoder, void *client_data) { + return 0; +} + static FLAC__StreamDecoderWriteStatus cflac_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const inputbuffer[], void *client_data) { if (frame->header.blocksize == 0) { @@ -73,7 +114,7 @@ cflac_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *fra } } if (readbytes > bufsize) { - fprintf (stderr, "flac: buffer overflow, distortion will occur\n"); + trace ("flac: buffer overflow, distortion will occur\n"); // return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; @@ -101,70 +142,66 @@ cflac_init_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecode cflac_init_stop_decoding = 1; } -static void -cflac_free (void); - static int cflac_init (DB_playItem_t *it) { - FILE *fp = fopen (it->fname, "rb"); - if (!fp) { + memset (&flac_callbacks, 0, sizeof (flac_callbacks)); + flac_callbacks.file = deadbeef->fopen (it->fname); + if (!flac_callbacks.file) { return -1; } - int skip = deadbeef->junk_get_leading_size (fp); + int skip = deadbeef->junk_get_leading_size (flac_callbacks.file); if (skip > 0) { - fseek (fp, skip, SEEK_SET); + deadbeef->fseek (flac_callbacks.file, skip, SEEK_SET); } char sign[4]; - if (fread (sign, 1, 4, fp) != 4) { - fclose (fp); + if (deadbeef->fread (sign, 1, 4, flac_callbacks.file) != 4) { + plugin.free (); return -1; } if (strncmp (sign, "fLaC", 4)) { - fclose (fp); + plugin.free (); return -1; } - fclose (fp); - fp = NULL; + deadbeef->fseek (flac_callbacks.file, -4, SEEK_CUR); FLAC__StreamDecoderInitStatus status; decoder = FLAC__stream_decoder_new(); if (!decoder) { -// printf ("FLAC__stream_decoder_new failed\n"); + trace ("FLAC__stream_decoder_new failed\n"); return -1; } FLAC__stream_decoder_set_md5_checking(decoder, 0); - cue_cb_data_t cb; - status = FLAC__stream_decoder_init_file(decoder, it->fname, cflac_write_callback, cflac_metadata_callback, cflac_error_callback, &cb); + status = FLAC__stream_decoder_init_stream (decoder, flac_read_cb, flac_seek_cb, flac_tell_cb, flac_lenght_cb, flac_eof_cb, cflac_write_callback, cflac_metadata_callback, cflac_error_callback, &flac_callbacks); if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { - cflac_free (); + plugin.free (); return -1; } //plugin.info.samplerate = -1; if (!FLAC__stream_decoder_process_until_end_of_metadata (decoder)) { - cflac_free (); + plugin.free (); return -1; } - plugin.info.samplerate = cb.samplerate; - plugin.info.channels = cb.channels; - plugin.info.bps = cb.bps; + plugin.info.samplerate = flac_callbacks.samplerate; + plugin.info.channels = flac_callbacks.channels; + plugin.info.bps = flac_callbacks.bps; plugin.info.readpos = 0; if (plugin.info.samplerate == -1) { // not a FLAC stream - cflac_free (); + plugin.free (); return -1; } if (it->endsample > 0) { startsample = it->startsample; endsample = it->endsample; if (plugin.seek_sample (0) < 0) { - cflac_free (); + plugin.free (); return -1; } } else { startsample = 0; - endsample = cb.totalsamples-1; + endsample = flac_callbacks.totalsamples-1; currentsample = 0; - trace ("startsample=%d, endsample=%d, totalsamples=%d\n", startsample, endsample, cb.totalsamples); + trace ("startsample=%d, endsample=%d, totalsamples=%d\n", startsample, endsample, flac_callbacks.totalsamples); } remaining = 0; @@ -287,16 +324,19 @@ cflac_init_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame static void cflac_init_cue_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { if (cflac_init_stop_decoding) { + trace ("flac: cflac_init_cue_metadata_callback: cflac_init_stop_decoding=1\n"); return; } cue_cb_data_t *cb = (cue_cb_data_t *)client_data; if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + trace ("flac: cflac_init_cue_metadata_callback: got FLAC__METADATA_TYPE_STREAMINFO\n"); cb->samplerate = metadata->data.stream_info.sample_rate; cb->channels = metadata->data.stream_info.channels; //cb->duration = metadata->data.stream_info.total_samples / (float)metadata->data.stream_info.sample_rate; cb->totalsamples = metadata->data.stream_info.total_samples; } else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + trace ("flac: cflac_init_cue_metadata_callback: got FLAC__METADATA_TYPE_VORBIS_COMMENT\n"); const FLAC__StreamMetadata_VorbisComment *vc = &metadata->data.vorbis_comment; for (int i = 0; i < vc->num_comments; i++) { const FLAC__StreamMetadata_VorbisComment_Entry *c = &vc->comments[i]; @@ -315,10 +355,11 @@ cflac_init_cue_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC_ static void cflac_init_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { if (cflac_init_stop_decoding) { - fprintf (stderr, "error flag is set, ignoring init_metadata callback..\n"); + trace ("error flag is set, ignoring init_metadata callback..\n"); return; } - DB_playItem_t *it = (DB_playItem_t *)client_data; + cue_cb_data_t *cb = (cue_cb_data_t *)client_data; + DB_playItem_t *it = cb->it; //it->tracknum = 0; if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { it->duration = metadata->data.stream_info.total_samples / (float)metadata->data.stream_info.sample_rate; @@ -380,64 +421,80 @@ cflac_init_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__Str static DB_playItem_t * cflac_insert (DB_playItem_t *after, const char *fname) { + trace ("flac: inserting %s\n", fname); DB_playItem_t *it = NULL; FLAC__StreamDecoder *decoder = NULL; - FILE *fp = fopen (fname, "rb"); - if (!fp) { + cue_cb_data_t cb = { + .fname = fname, + .after = after, + .last = after + }; + cb.file = deadbeef->fopen (fname); + if (!cb.file) { goto cflac_insert_fail; } // skip id3 junk - int skip = deadbeef->junk_get_leading_size (fp); + int skip = deadbeef->junk_get_leading_size (cb.file); if (skip > 0) { - fseek (fp, skip, SEEK_SET); + deadbeef->fseek (cb.file, skip, SEEK_SET); } char sign[4]; - if (fread (sign, 1, 4, fp) != 4) { + if (deadbeef->fread (sign, 1, 4, cb.file) != 4) { + trace ("flac: failed to read signature\n"); goto cflac_insert_fail; } if (strncmp (sign, "fLaC", 4)) { + trace ("flac: file signature is not fLaC\n"); goto cflac_insert_fail; } - fclose (fp); - fp = NULL; + deadbeef->fseek (cb.file, -4, SEEK_CUR); cflac_init_stop_decoding = 0; //try embedded cue, and calculate duration FLAC__StreamDecoderInitStatus status; decoder = FLAC__stream_decoder_new(); if (!decoder) { + trace ("flac: failed to create decoder\n"); goto cflac_insert_fail; } FLAC__stream_decoder_set_md5_checking(decoder, 0); // try embedded cue - cue_cb_data_t cb = { - .fname = fname, - .after = after, - .last = after - }; FLAC__stream_decoder_set_metadata_respond_all (decoder); - status = FLAC__stream_decoder_init_file (decoder, fname, cflac_init_write_callback, cflac_init_cue_metadata_callback, cflac_init_error_callback, &cb); + status = FLAC__stream_decoder_init_stream (decoder, flac_read_cb, flac_seek_cb, flac_tell_cb, flac_lenght_cb, flac_eof_cb, cflac_init_write_callback, cflac_init_cue_metadata_callback, cflac_init_error_callback, &cb); if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK || cflac_init_stop_decoding) { + trace ("flac: FLAC__stream_decoder_init_stream failed\n"); goto cflac_insert_fail; } if (!FLAC__stream_decoder_process_until_end_of_metadata (decoder) || cflac_init_stop_decoding) { + trace ("flac: FLAC__stream_decoder_process_until_end_of_metadata failed\n"); goto cflac_insert_fail; } FLAC__stream_decoder_delete(decoder); decoder = NULL; if (cb.last != after) { + trace ("flac: loaded embedded cuesheet\n"); // that means embedded cue is loaded + if (cb.file) { + deadbeef->fclose (cb.file); + } return cb.last; } // try external cue DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, "flac", cb.totalsamples, cb.samplerate); if (cue_after) { + if (cb.file) { + deadbeef->fclose (cb.file); + } + trace ("flac: loaded external cuesheet\n"); return cue_after; } decoder = FLAC__stream_decoder_new(); if (!decoder) { + if (cb.file) { + deadbeef->fclose (cb.file); + } goto cflac_insert_fail; } FLAC__stream_decoder_set_md5_checking(decoder, 0); @@ -447,17 +504,30 @@ cflac_insert (DB_playItem_t *after, const char *fname) { it = deadbeef->pl_item_alloc (); it->decoder = &plugin; it->fname = strdup (fname); - status = FLAC__stream_decoder_init_file (decoder, fname, cflac_init_write_callback, cflac_init_metadata_callback, cflac_init_error_callback, it); + cb.it = it; + if (skip > 0) { + deadbeef->fseek (cb.file, skip, SEEK_SET); + } + else { + deadbeef->rewind (cb.file); + } + deadbeef->fseek (cb.file, -4, SEEK_CUR); + status = FLAC__stream_decoder_init_stream (decoder, flac_read_cb, flac_seek_cb, flac_tell_cb, flac_lenght_cb, flac_eof_cb, cflac_init_write_callback, cflac_init_metadata_callback, cflac_init_error_callback, &cb); if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK || cflac_init_stop_decoding) { + trace ("flac: FLAC__stream_decoder_init_stream [2] failed\n"); goto cflac_insert_fail; } if (!FLAC__stream_decoder_process_until_end_of_metadata (decoder) || cflac_init_stop_decoding) { + trace ("flac: FLAC__stream_decoder_process_until_end_of_metadata [2] failed\n"); goto cflac_insert_fail; } FLAC__stream_decoder_delete(decoder); decoder = NULL; it->filetype = "FLAC"; after = deadbeef->pl_insert_item (after, it); + if (cb.file) { + deadbeef->fclose (cb.file); + } return after; cflac_insert_fail: if (it) { @@ -466,8 +536,8 @@ cflac_insert_fail: if (decoder) { FLAC__stream_decoder_delete(decoder); } - if (fp) { - fclose (fp); + if (cb.file) { + deadbeef->fclose (cb.file); } return NULL; } diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 99279faf..14a277f0 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -54,7 +54,7 @@ static DB_functions_t *deadbeef; #define VBR_SCALE_FLAG 0x0008 typedef struct { - FILE *file; + DB_FILE *file; // // input buffer, for MPEG data // // FIXME: this should go away if reading happens per-frame @@ -181,8 +181,8 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { for (;;) { uint32_t hdr; uint8_t sync; - size_t pos = ftell (buffer->file); - if (fread (&sync, 1, 1, buffer->file) != 1) { + size_t pos = deadbeef->ftell (buffer->file); + if (deadbeef->fread (&sync, 1, 1, buffer->file) != 1) { break; // eof } if (sync != 0xff) { @@ -190,7 +190,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { } else { // 2nd sync byte - if (fread (&sync, 1, 1, buffer->file) != 1) { + if (deadbeef->fread (&sync, 1, 1, buffer->file) != 1) { break; // eof } if ((sync >> 5) != 7) { @@ -200,11 +200,11 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { // found frame hdr = (0xff<<24) | (sync << 16); // read 2 bytes more - if (fread (&sync, 1, 1, buffer->file) != 1) { + if (deadbeef->fread (&sync, 1, 1, buffer->file) != 1) { break; // eof } hdr |= sync << 8; - if (fread (&sync, 1, 1, buffer->file) != 1) { + if (deadbeef->fread (&sync, 1, 1, buffer->file) != 1) { break; // eof } hdr |= sync; @@ -333,22 +333,22 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { // try to read xing/info tag (only on initial scans) if (sample <= 0 && !got_xing_header) { - size_t framepos = ftell (buffer->file); + size_t framepos = deadbeef->ftell (buffer->file); trace ("trying to read xing header\n"); if (ver == 1) { - fseek (buffer->file, 32, SEEK_CUR); + deadbeef->fseek (buffer->file, 32, SEEK_CUR); } else { - fseek (buffer->file, 17, SEEK_CUR); + deadbeef->fseek (buffer->file, 17, SEEK_CUR); } const char xing[] = "Xing"; const char info[] = "Info"; char magic[4]; - if (fread (magic, 1, 4, buffer->file) != 4) { + if (deadbeef->fread (magic, 1, 4, buffer->file) != 4) { return -1; // EOF } // add information to skip this frame - int startoffset = ftell (buffer->file) + packetlength; + int startoffset = deadbeef->ftell (buffer->file) + packetlength; if (startoffset > buffer->startoffset) { buffer->startoffset = startoffset; } @@ -358,13 +358,13 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { // read flags uint32_t flags; uint8_t buf[4]; - if (fread (buf, 1, 4, buffer->file) != 4) { + if (deadbeef->fread (buf, 1, 4, buffer->file) != 4) { return -1; // EOF } flags = extract_i32 (buf); if (flags & FRAMES_FLAG) { // read number of frames - if (fread (buf, 1, 4, buffer->file) != 4) { + if (deadbeef->fread (buf, 1, 4, buffer->file) != 4) { return -1; // EOF } uint32_t nframes = extract_i32 (buf); @@ -374,65 +374,65 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { buffer->samplerate = samplerate; } if (flags & BYTES_FLAG) { - fseek (buffer->file, 4, SEEK_CUR); + deadbeef->fseek (buffer->file, 4, SEEK_CUR); } if (flags & TOC_FLAG) { - fseek (buffer->file, 100, SEEK_CUR); + deadbeef->fseek (buffer->file, 100, SEEK_CUR); } if (flags & VBR_SCALE_FLAG) { - fseek (buffer->file, 4, SEEK_CUR); + deadbeef->fseek (buffer->file, 4, SEEK_CUR); } // lame header - if (fread (buf, 1, 4, buffer->file) != 4) { + if (deadbeef->fread (buf, 1, 4, buffer->file) != 4) { return -1; // EOF } - trace ("tell=%x, %c%c%c%c\n", 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"); - fseek (buffer->file, 6, SEEK_CUR); + deadbeef->fseek (buffer->file, 6, SEEK_CUR); // FIXME: that can be optimized by single read uint8_t lpf; - fread (&lpf, 1, 1, buffer->file); + deadbeef->fread (&lpf, 1, 1, buffer->file); //3 floats: replay gain - fread (buf, 1, 4, buffer->file); + deadbeef->fread (buf, 1, 4, buffer->file); float rg_peaksignalamp = extract_f32 (buf); - fread (buf, 1, 2, buffer->file); + deadbeef->fread (buf, 1, 2, buffer->file); uint16_t rg_radio = extract_i16 (buf); - fread (buf, 1, 2, buffer->file); + deadbeef->fread (buf, 1, 2, buffer->file); uint16_t rg_audiophile = extract_i16 (buf); // skip - fseek (buffer->file, 2, SEEK_CUR); - fread (buf, 1, 3, buffer->file); + deadbeef->fseek (buffer->file, 2, SEEK_CUR); + deadbeef->fread (buf, 1, 3, buffer->file); uint32_t startdelay = (((uint32_t)buf[0]) << 4) | ((((uint32_t)buf[1]) & 0xf0)>>4); uint32_t enddelay = ((((uint32_t)buf[1])&0x0f)<<8) | ((uint32_t)buf[2]); // skip - fseek (buffer->file, 1, SEEK_CUR); + deadbeef->fseek (buffer->file, 1, SEEK_CUR); // mp3gain uint8_t mp3gain; - fread (&mp3gain, 1, 1, buffer->file); + deadbeef->fread (&mp3gain, 1, 1, buffer->file); // skip - fseek (buffer->file, 2, SEEK_CUR); + deadbeef->fseek (buffer->file, 2, SEEK_CUR); // musiclen - fread (buf, 1, 4, buffer->file); + 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); // skip crc - //fseek (buffer->file, 4, SEEK_CUR); + //deadbeef->fseek (buffer->file, 4, SEEK_CUR); buffer->startdelay = startdelay; buffer->enddelay = enddelay; } if (sample <= 0 && (flags&FRAMES_FLAG)) { buffer->totalsamples -= buffer->enddelay; trace ("lame totalsamples: %d\n", buffer->totalsamples); - fseek (buffer->file, framepos+packetlength-4, SEEK_SET); + deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET); return 0; } } if (sample == 0) { // xing header failed, calculate based on file size - fseek (buffer->file, 0, SEEK_END); - int sz = ftell (buffer->file) - buffer->startoffset - buffer->endoffset; + deadbeef->fseek (buffer->file, 0, SEEK_END); + int sz = deadbeef->ftell (buffer->file) - buffer->startoffset - buffer->endoffset; int nframes = sz / packetlength; buffer->duration = nframes * samples_per_frame / samplerate; buffer->totalsamples = nframes * samples_per_frame; @@ -440,16 +440,16 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { // trace ("packetlength=%d, fsize=%d, nframes=%d, samples_per_frame=%d, samplerate=%d, duration=%f, totalsamples=%d\n", packetlength, sz, nframes, samples_per_frame, samplerate, buffer->duration, buffer->totalsamples); if (sample == 0) { - fseek (buffer->file, framepos+packetlength-4, SEEK_SET); + deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET); return 0; } } - fseek (buffer->file, framepos+packetlength-4, SEEK_SET); + deadbeef->fseek (buffer->file, framepos+packetlength-4, SEEK_SET); got_xing_header = 1; } if (sample >= 0 && scansamples + samples_per_frame >= sample) { - fseek (buffer->file, -4, SEEK_CUR); + deadbeef->fseek (buffer->file, -4, SEEK_CUR); buffer->currentsample = sample; buffer->skipsamples = sample - scansamples; return 0; @@ -459,7 +459,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { buffer->duration += dur; nframe++; if (packetlength > 0) { - fseek (buffer->file, packetlength-4, SEEK_CUR); + deadbeef->fseek (buffer->file, packetlength-4, SEEK_CUR); } } if (nframe == 0) { @@ -474,13 +474,13 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { static int cmp3_init (DB_playItem_t *it) { memset (&buffer, 0, sizeof (buffer)); - buffer.file = fopen (it->fname, "rb"); + buffer.file = deadbeef->fopen (it->fname); if (!buffer.file) { return -1; } int skip = deadbeef->junk_get_leading_size (buffer.file); if (skip > 0) { - fseek(buffer.file, skip, SEEK_SET); + deadbeef->fseek(buffer.file, skip, SEEK_SET); } plugin.info.readpos = 0; cmp3_scan_stream (&buffer, -1); // scan entire stream, calc duration @@ -496,11 +496,11 @@ cmp3_init (DB_playItem_t *it) { buffer.endsample = buffer.totalsamples-1; buffer.skipsamples = buffer.startdelay; buffer.currentsample = buffer.startdelay; - fseek (buffer.file, buffer.startoffset, SEEK_SET); + deadbeef->fseek (buffer.file, buffer.startoffset, SEEK_SET); } if (buffer.samplerate == 0) { trace ("bad mpeg file: %f\n", it->fname); - fclose (buffer.file); + deadbeef->fclose (buffer.file); return -1; } plugin.info.bps = buffer.bitspersample; @@ -584,7 +584,7 @@ cmp3_decode (void) { int size = READBUFFER - buffer.remaining; int bytesread = 0; char *bytes = buffer.input + buffer.remaining; - bytesread = fread (bytes, 1, size, buffer.file); + bytesread = deadbeef->fread (bytes, 1, size, buffer.file); if (!bytesread) { // add guard eof = 1; @@ -686,7 +686,7 @@ cmp3_decode (void) { static void cmp3_free (void) { if (buffer.file) { - fclose (buffer.file); + deadbeef->fclose (buffer.file); buffer.file = NULL; mad_synth_finish (&synth); mad_frame_finish (&frame); @@ -788,10 +788,10 @@ cmp3_seek_sample (int sample) { return -1; // eof } // restart file, and load until we hit required pos - fseek (buffer.file, 0, SEEK_SET); + deadbeef->fseek (buffer.file, 0, SEEK_SET); int skip = deadbeef->junk_get_leading_size (buffer.file); if (skip > 0) { - fseek(buffer.file, skip, SEEK_SET); + deadbeef->fseek(buffer.file, skip, SEEK_SET); } mad_synth_finish (&synth); mad_frame_finish (&frame); @@ -832,7 +832,7 @@ static const char *filetypes[] = { static DB_playItem_t * cmp3_insert (DB_playItem_t *after, const char *fname) { - FILE *fp = fopen (fname, "rb"); + DB_FILE *fp = deadbeef->fopen (fname); if (!fp) { return NULL; } @@ -841,12 +841,12 @@ cmp3_insert (DB_playItem_t *after, const char *fname) { buffer.file = fp; int skip = deadbeef->junk_get_leading_size (buffer.file); if (skip > 0) { - fseek(buffer.file, skip, SEEK_SET); + deadbeef->fseek(buffer.file, skip, SEEK_SET); } // calc approx. mp3 duration int res = cmp3_scan_stream (&buffer, 0); if (res < 0) { - fclose (fp); + deadbeef->fclose (fp); return NULL; } @@ -893,11 +893,11 @@ cmp3_insert (DB_playItem_t *after, const char *fname) { // FIXME! bad numsamples passed to cue DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, ftype, buffer.duration*buffer.samplerate, buffer.samplerate); if (cue_after) { - fclose (fp); + deadbeef->fclose (fp); return cue_after; } - rewind (fp); + deadbeef->rewind (fp); DB_playItem_t *it = deadbeef->pl_item_alloc (); it->decoder = &plugin; @@ -906,7 +906,7 @@ cmp3_insert (DB_playItem_t *after, const char *fname) { int apeerr = deadbeef->junk_read_ape (it, fp); int v2err = deadbeef->junk_read_id3v2 (it, fp); int v1err = deadbeef->junk_read_id3v1 (it, fp); - fclose (fp); + deadbeef->fclose (fp); deadbeef->pl_add_meta (it, "title", NULL); it->duration = buffer.duration; it->filetype = ftype; diff --git a/plugins/vorbis/vorbis.c b/plugins/vorbis/vorbis.c index 26cd3051..32d99660 100644 --- a/plugins/vorbis/vorbis.c +++ b/plugins/vorbis/vorbis.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #ifdef HAVE_CONFIG_H # include @@ -34,7 +33,7 @@ static DB_decoder_t plugin; static DB_functions_t *deadbeef; -static FILE *file; +static DB_FILE *file; static OggVorbis_File vorbis_file; static vorbis_info *vi; static int cur_bit_stream; @@ -45,19 +44,48 @@ static int currentsample; static void cvorbis_free (void); +static size_t +cvorbis_fread (void *ptr, size_t size, size_t nmemb, void *datasource) { + return deadbeef->fread (ptr, size, nmemb, datasource); +} + +static int +cvorbis_fseek (void *datasource, ogg_int64_t offset, int whence) { + DB_FILE *f = (DB_FILE *)datasource; + return deadbeef->fseek (datasource, offset, whence); +} + +static int +cvorbis_fclose (void *datasource) { + deadbeef->fclose (datasource); + return 0; +} + +static long +cvorbis_ftell (void *datasource) { + return deadbeef->ftell (datasource); +} + static int cvorbis_init (DB_playItem_t *it) { file = NULL; vi = NULL; cur_bit_stream = -1; - file = fopen (it->fname, "rb"); + file = deadbeef->fopen (it->fname); if (!file) { return -1; } + ov_callbacks ovcb = { + .read_func = cvorbis_fread, + .seek_func = cvorbis_fseek, + .close_func = cvorbis_fclose, + .tell_func = cvorbis_ftell + }; memset (&plugin.info, 0, sizeof (plugin.info)); - ov_open (file, &vorbis_file, NULL, 0); + + ov_open_callbacks (file, &vorbis_file, NULL, 0, ovcb); vi = ov_info (&vorbis_file, -1); if (!vi) { // not a vorbis stream cvorbis_free (); @@ -156,15 +184,23 @@ cvorbis_seek (float time) { static DB_playItem_t * cvorbis_insert (DB_playItem_t *after, const char *fname) { // check for validity - FILE *fp = fopen (fname, "rb"); + DB_FILE *fp = deadbeef->fopen (fname); if (!fp) { + fprintf (stderr, "vorbis: failed to fopen %s\n", fname); return NULL; } + ov_callbacks ovcb = { + .read_func = cvorbis_fread, + .seek_func = cvorbis_fseek, + .close_func = cvorbis_fclose, + .tell_func = cvorbis_ftell + }; OggVorbis_File vorbis_file; vorbis_info *vi; - ov_open (fp, &vorbis_file, NULL, 0); + ov_open_callbacks (fp, &vorbis_file, NULL, 0, ovcb); vi = ov_info (&vorbis_file, -1); if (!vi) { // not a vorbis stream + fprintf (stderr, "vorbis: failed to ov_open %s\n", fname); return NULL; } float duration = ov_time_total (&vorbis_file, -1); diff --git a/plugins/wavpack/wavpack.c b/plugins/wavpack/wavpack.c index 5a9b9501..876fc0d3 100644 --- a/plugins/wavpack/wavpack.c +++ b/plugins/wavpack/wavpack.c @@ -19,6 +19,7 @@ #include #include +#include #include "../../deadbeef.h" #define min(x,y) ((x)<(y)?(x):(y)) @@ -31,6 +32,7 @@ static DB_decoder_t plugin; static DB_functions_t *deadbeef; typedef struct { + DB_FILE *file; WavpackContext *ctx; int startsample; int endsample; @@ -38,11 +40,68 @@ typedef struct { static wvctx_t wvctx; +int32_t wv_read_bytes(void *id, void *data, int32_t bcount) { + trace ("wv_read_bytes\n"); + return deadbeef->fread (data, 1, bcount, id); +} + +uint32_t wv_get_pos(void *id) { + trace ("wv_get_pos\n"); + return deadbeef->ftell (id); +} + +int wv_set_pos_abs(void *id, uint32_t pos) { + trace ("wv_set_pos_abs\n"); + return deadbeef->fseek (id, pos, SEEK_SET); +} +int wv_set_pos_rel(void *id, int32_t delta, int mode) { + trace ("wv_set_pos_rel\n"); + return deadbeef->fseek (id, delta, SEEK_CUR); +} +int wv_push_back_byte(void *id, int c) { + trace ("wv_push_back_byte\n"); + deadbeef->fseek (id, -1, SEEK_CUR); + return deadbeef->ftell (id); +} +uint32_t wv_get_length(void *id) { + trace ("wv_get_length\n"); + size_t pos = deadbeef->ftell (id); + deadbeef->fseek (id, 0, SEEK_END); + size_t sz = deadbeef->ftell (id); + deadbeef->fseek (id, pos, SEEK_SET); + return sz; +} +int wv_can_seek(void *id) { + trace ("wv_can_seek\n"); + return 1; +} + +int32_t wv_write_bytes (void *id, void *data, int32_t bcount) { + return 0; +} + +static WavpackStreamReader wsr = { + .read_bytes = wv_read_bytes, + .get_pos = wv_get_pos, + .set_pos_abs = wv_set_pos_abs, + .set_pos_rel = wv_set_pos_rel, + .push_back_byte = wv_push_back_byte, + .get_length = wv_get_length, + .can_seek = wv_can_seek, + .write_bytes = wv_write_bytes +}; + static int wv_init (DB_playItem_t *it) { memset (&wvctx, 0, sizeof (wvctx)); - wvctx.ctx = WavpackOpenFileInput (it->fname, NULL, OPEN_2CH_MAX|OPEN_WVC, 0); + + wvctx.file = deadbeef->fopen (it->fname); + if (!wvctx.file) { + return -1; + } + wvctx.ctx = WavpackOpenFileInputEx (&wsr, wvctx.file, NULL, NULL, OPEN_2CH_MAX/*|OPEN_WVC*/, 0); if (!wvctx.ctx) { + plugin.free (); return -1; } plugin.info.bps = WavpackGetBitsPerSample (wvctx.ctx); @@ -66,8 +125,13 @@ wv_init (DB_playItem_t *it) { static void wv_free (void) { + if (wvctx.file) { + deadbeef->fclose (wvctx.file); + wvctx.file = NULL; + } if (wvctx.ctx) { WavpackCloseFile (wvctx.ctx); + wvctx.ctx = NULL; } memset (&wvctx, 0, sizeof (wvctx)); } @@ -141,9 +205,15 @@ wv_seek (float sec) { static DB_playItem_t * wv_insert (DB_playItem_t *after, const char *fname) { - WavpackContext *ctx = WavpackOpenFileInput (fname, NULL, 0, 0); + + DB_FILE *fp = deadbeef->fopen (fname); + if (!fp) { + return NULL; + } + WavpackContext *ctx = WavpackOpenFileInputEx (&wsr, fp, NULL, NULL, 0, 0); if (!ctx) { trace ("WavpackOpenFileInput failed"); + deadbeef->fclose (fp); return NULL; } int totalsamples = WavpackGetNumSamples (ctx); @@ -152,6 +222,7 @@ wv_insert (DB_playItem_t *after, const char *fname) { float duration = (float)totalsamples / samplerate; DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, "wv", totalsamples, samplerate); if (cue_after) { + deadbeef->fclose (fp); return cue_after; } @@ -163,18 +234,15 @@ wv_insert (DB_playItem_t *after, const char *fname) { trace ("wv: totalsamples=%d, samplerate=%d, duration=%f\n", totalsamples, samplerate, duration); - FILE *fp = fopen (fname, "rb"); - if (fp) { - int apeerr = deadbeef->junk_read_ape (it, fp); - if (!apeerr) { - trace ("wv: ape tag found\n"); - } - int v1err = deadbeef->junk_read_id3v1 (it, fp); - if (!v1err) { - trace ("wv: id3v1 tag found\n"); - } - fclose (fp); + int apeerr = deadbeef->junk_read_ape (it, fp); + if (!apeerr) { + trace ("wv: ape tag found\n"); + } + int v1err = deadbeef->junk_read_id3v1 (it, fp); + if (!v1err) { + trace ("wv: id3v1 tag found\n"); } + deadbeef->fclose (fp); deadbeef->pl_add_meta (it, "title", NULL); after = deadbeef->pl_insert_item (after, it); diff --git a/vfs.c b/vfs.c new file mode 100644 index 00000000..a4b456d2 --- /dev/null +++ b/vfs.c @@ -0,0 +1,72 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009 Alexey Yakovenko + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include +#include "vfs.h" +#include "plugins.h" + +DB_FILE * +vfs_fopen (const char *fname) { + DB_vfs_t **plugs = plug_get_vfs_list (); + DB_vfs_t *fallback = NULL; + int i; + for (i = 0; plugs[i]; i++) { + DB_vfs_t *p = plugs[i]; + if (!p->scheme_names) { + fallback = p; + continue; + } + int n; + for (n = 0; p->scheme_names[n]; n++) { + size_t l = strlen (p->scheme_names[n]); + if (!strncasecmp (p->scheme_names[n], fname, l)) { + return p->open (fname); + } + } + } + if (fallback) { + return fallback->open (fname); + } + return NULL; +} + +void +vfs_fclose (DB_FILE *stream) { + return stream->vfs->close (stream); +} + +size_t +vfs_fread (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) { + return stream->vfs->read (ptr, size, nmemb, stream); +} + +int +vfs_fseek (DB_FILE *stream, long offset, int whence) { + return stream->vfs->seek (stream, offset, whence); +} + +long +vfs_ftell (DB_FILE *stream) { + return stream->vfs->tell (stream); +} + +void +vfs_rewind (DB_FILE *stream) { + stream->vfs->rewind (stream); +} + diff --git a/vfs.h b/vfs.h new file mode 100644 index 00000000..22ca1c25 --- /dev/null +++ b/vfs.h @@ -0,0 +1,32 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009 Alexey Yakovenko + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __VFS_H +#define __VFS_H + +#include "deadbeef.h" + +DB_FILE* vfs_fopen (const char *fname); +void vfs_fclose (DB_FILE *f); +size_t vfs_fread (void *ptr, size_t size, size_t nmemb, DB_FILE *stream); +int vfs_fseek (DB_FILE *stream, long offset, int whence); +long vfs_ftell (DB_FILE *stream); +void vfs_rewind (DB_FILE *stream); + +#endif // __VFS_H diff --git a/vfs_stdio.c b/vfs_stdio.c new file mode 100644 index 00000000..bc0f1183 --- /dev/null +++ b/vfs_stdio.c @@ -0,0 +1,98 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009 Alexey Yakovenko + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "deadbeef.h" +#include +#include +#include + +static DB_functions_t *deadbeef; +typedef struct { + DB_vfs_t *vfs; + FILE *stream; +} STDIO_FILE; + +static DB_vfs_t plugin; + +DB_FILE * +stdio_open (const char *fname) { + FILE *file = fopen (fname, "rb"); + if (!file) { + return NULL; + } + STDIO_FILE *fp = malloc (sizeof (STDIO_FILE)); + fp->vfs = &plugin; + fp->stream = file; + return (DB_FILE*)fp; +} + +void +stdio_close (DB_FILE *stream) { + assert (stream); + fclose (((STDIO_FILE *)stream)->stream); + free (stream); +} + +size_t stdio_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) { + assert (stream); + assert (ptr); + return fread (ptr, size, nmemb, ((STDIO_FILE *)stream)->stream); +} + +int +stdio_seek (DB_FILE *stream, long offset, int whence) { + assert (stream); + return fseek (((STDIO_FILE *)stream)->stream, offset, whence); +} + +long +stdio_tell (DB_FILE *stream) { + assert (stream); + return ftell (((STDIO_FILE *)stream)->stream); +} + +void +stdio_rewind (DB_FILE *stream) { + assert (stream); + rewind (((STDIO_FILE *)stream)->stream); +} + +// standard stdio vfs +static DB_vfs_t plugin = { + DB_PLUGIN_SET_API_VERSION + .plugin.version_major = 0, + .plugin.version_minor = 1, + .plugin.type = DB_PLUGIN_VFS, + .plugin.name = "STDIO VFS", + .plugin.author = "Alexey Yakovenko", + .plugin.email = "waker@users.sourceforge.net", + .plugin.website = "http://deadbeef.sf.net", + .open = stdio_open, + .close = stdio_close, + .read = stdio_read, + .seek = stdio_seek, + .tell = stdio_tell, + .rewind = stdio_rewind, + .scheme_names = NULL // this is NULL because that's a fallback vfs, used when no other matching vfs plugin found +}; + +DB_plugin_t * +stdio_load (DB_functions_t *api) { + deadbeef = api; + return DB_PLUGIN (&plugin); +} -- cgit v1.2.3