summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-12-18 23:30:30 +0100
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-12-18 23:30:30 +0100
commit550758b681ce3c0b599581c823f7f30972dd1ef8 (patch)
tree3ffd1a4f5a355404be2c1837056c3e1e38a34bb4
parent66f3c9fbefdacd388e5b639fd9d4cfa4ccf81fe6 (diff)
added template for making new decoder plugins
-rw-r--r--decoder_template.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/decoder_template.c b/decoder_template.c
new file mode 100644
index 00000000..27308177
--- /dev/null
+++ b/decoder_template.c
@@ -0,0 +1,192 @@
+/*
+ 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.
+*/
+
+// this is a decoder plugin skeleton
+// use to create new decoder plugins
+
+#include "../../deadbeef.h"
+
+static DB_decoder_t plugin;
+static DB_functions_t *deadbeef;
+
+static const char * exts[] = { "example", NULL }; // e.g. mp3
+static const char *filetypes[] = { "example", NULL }; // e.g. MP3
+
+static int
+example_init (DB_playItem_t *it) {
+ // prepare to decode the track
+ // return -1 on failure
+ return 0;
+}
+
+static void
+example_free (void) {
+ // free everything allocated in _init
+}
+
+static int
+example_read_int16 (char *bytes, int size) {
+ // try decode `size' bytes
+ // return number of decoded bytes
+ // return 0 on EOF
+ return 0;
+}
+
+static int
+example_seek_sample (int sample) {
+ // seek to specified sample (frame)
+ // return 0 on success
+ // return -1 on failure
+}
+
+static int
+example_seek (float time) {
+ // seek to specified time in seconds
+ // return 0 on success
+ // return -1 on failure
+ // e.g. return example_seek_sample (time * samplerate);
+ return 0;
+}
+
+static DB_playItem_t *
+example_insert (DB_playItem_t *after, const char *fname) {
+ // read information from the track
+ // load/process cuesheet if exists
+ // insert track into playlist
+ // return track pointer on success
+ // return NULL on failure
+
+example:
+
+ // open file
+ DB_FILE *fp = deadbeef->fopen (fname);
+ if (!fp) {
+ trace ("example: failed to fopen %s\n", fname);
+ return NULL;
+ }
+ // setup decoder to use vfs
+ decoder_callbacks_t cb = {
+ open = vfs_open_wrapper,
+ .... etc ....
+ }
+ decoder_info_t *di = decoder_open_callbacks (&cb);
+ if (!di) {
+ trace ("example: failed to init decoder\n");
+ return NULL;
+ }
+ // read track info/tags
+ track_info_t ti;
+ if (decoder_read_info (&ti) < 0) {
+ trace ("example: failed to read info\n");
+ decoder_free (di);
+ return NULL;
+ }
+
+ // now we should have track duration, and can try loading cuesheet
+ // 1st try embedded cuesheet
+ if (ti.embeddedcuesheet[0]) {
+ DB_playItem_t *cue = deadbeef->pl_insert_cue_from_buffer (after, fname, ti.embeddedcuesheet, strlen (ti.embeddedcuesheet), &plugin, plugin.filetypes[0], ti.total_num_samples, ti.samplerate);
+ if (cue) {
+ // cuesheet loaded
+ decoder_free (di);
+ return cue;
+ }
+ }
+
+ // embedded cuesheet not found, try external one
+ DB_playItem_t *cue = deadbeef->pl_insert_cue (after, fname, &plugin, plugin.filetypes[0], ti.total_num_samples, ti.samplerate);
+ if (cue) {
+ // cuesheet loaded
+ decoder_free (di);
+ return cue;
+ }
+
+ // no cuesheet, prepare track for addition
+ DB_playItem_t *it = deadbeef->pl_item_alloc ();
+ it->decoder = &plugin;
+ it->fname = strdup (fname);
+ it->filetype = "OggVorbis";
+ deadbeef->pl_set_item_duration (it, (float)ti.total_num_samples/ti.samplerate);
+
+ // add metainfo
+ if (!strlen (ti.title)) {
+ // title is empty, this call will set track title to filename without extension
+ deadbeef->pl_add_meta ("title", NULL);
+ }
+ else {
+ deadbeef->pl_add_meta ("title", ti.title);
+ }
+ deadbeef->pl_add_meta ("artist", ti.artist);
+ // ... etc ...
+
+ // free decoder
+ decoder_free (di);
+
+ // now the track is ready, insert into playlist
+ after = deadbeef->pl_insert_item (after, it);
+ return after;
+}
+
+static int
+example_start (void) {
+ // do one-time plugin initialization here
+ // e.g. starting threads for background processing, subscribing to events, etc
+ // return 0 on success
+ // return -1 on failure
+ return 0;
+}
+static int
+example_stop (void) {
+ // undo everything done in _start here
+ // return 0 on success
+ // return -1 on failure
+ return 0;
+}
+
+// define plugin interface
+static DB_decoder_t plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.version_major = 0,
+ .plugin.version_minor = 1,
+ .plugin.type = DB_PLUGIN_DECODER,
+ .plugin.name = "short plugin name",
+ .plugin.descr = "plugin description",
+ .plugin.author = "author name",
+ .plugin.email = "author email",
+ .plugin.website = "author/plugin website",
+ .plugin.start = example_start,
+ .plugin.stop = example_stop,
+ .init = example_init,
+ .free = example_free,
+ .read_int16 = example_read_int16,
+// .read_float32 = example_read_float32,
+ .seek = example_seek,
+ .seek_sample = example_seek_sample,
+ .insert = example_insert,
+ .exts = exts,
+ .id = "example",
+ .filetypes = filetypes
+};
+
+DB_plugin_t *
+example_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
+