summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-28 22:56:57 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-28 22:56:57 +0200
commitb5bedb49dad2da3aab4a997ac6daad1c4f30d67a (patch)
tree82390feb2bc4925b707f11f65e08f7523e9dad90
parent75d630d07d325ca8ac895dc23186819c00003926 (diff)
added VFS plugins
implemented stdio VFS plugin ported flac, mpgmad, ffap, vorbis, wavpack, junklib to VFS
-rw-r--r--Makefile.am3
-rw-r--r--deadbeef.h40
-rw-r--r--junklib.c43
-rw-r--r--junklib.h10
-rw-r--r--moduleconf.h1
-rw-r--r--plugins.c44
-rw-r--r--plugins.h5
-rw-r--r--plugins/ffap/ffap.c53
-rw-r--r--plugins/flac/flac.c160
-rw-r--r--plugins/mpgmad/mpgmad.c102
-rw-r--r--plugins/vorbis/vorbis.c48
-rw-r--r--plugins/wavpack/wavpack.c94
-rw-r--r--vfs.c72
-rw-r--r--vfs.h32
-rw-r--r--vfs_stdio.c98
15 files changed, 622 insertions, 183 deletions
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 <stdint.h>
#include <time.h>
-#include <stdio.h>
#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 <string.h>
#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 <stdio.h>
+#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 <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#include <string.h>
-#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -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 <string.h>
#include <wavpack/wavpack.h>
+#include <stdio.h>
#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 <string.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+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);
+}