/* 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, see . */ #include #include #include #include #include #ifdef HAVE_CONFIG_H # include #endif #include "deadbeef.h" //#include "decoder.h" //#include "plugin.h" //#include "playlist.h" static DB_decoder_t plugin; static DB_functions_t *deadbeef; static FILE *file; static OggVorbis_File vorbis_file; static vorbis_info *vi; static int cur_bit_stream; static float timestart; static float timeend; static void cvorbis_free (void); static int cvorbis_seek (float time); static int cvorbis_init (DB_playItem_t *it) { file = NULL; vi = NULL; cur_bit_stream = -1; file = fopen (it->fname, "rb"); if (!file) { return -1; } memset (&plugin.info, 0, sizeof (plugin.info)); ov_open (file, &vorbis_file, NULL, 0); vi = ov_info (&vorbis_file, -1); if (!vi) { // not a vorbis stream cvorbis_free (); return -1; } plugin.info.bps = 16; //plugin.info.dataSize = ov_pcm_total (&vorbis_file, -1) * vi->channels * 2; plugin.info.channels = vi->channels; plugin.info.samplerate = vi->rate; plugin.info.readpos = 0; if (it->timeend > 0) { timestart = it->timestart; timeend = it->timeend; cvorbis_seek (0); } else { timestart = 0; timeend = it->duration; } return 0; } static void cvorbis_free (void) { if (file) { ov_clear (&vorbis_file); //fclose (file); //-- ov_clear closes it file = NULL; vi = NULL; } } static int cvorbis_read (char *bytes, int size) { if (plugin.info.readpos >= (timeend - timestart)) { return 0; } int initsize = size; for (;;) { // read ogg int endianess = 0; #if WORDS_BIGENDIAN endianess = 1; #endif long ret=ov_read (&vorbis_file, bytes, size, endianess, 2, 1, &cur_bit_stream); if (ret < 0) { break; } else if (ret == 0) { break; } else if (ret < size) { size -= ret; bytes += ret; } else { size = 0; break; } } plugin.info.readpos = ov_time_tell(&vorbis_file) - timestart; if (plugin.info.readpos >= (timeend - timestart)) { return 0; } return initsize - size; } static int cvorbis_seek (float time) { time += timestart; if (!file) { return -1; } int res = ov_time_seek (&vorbis_file, time); if (res != 0 && res != OV_ENOSEEK) return -1; plugin.info.readpos = ov_time_tell(&vorbis_file) - timestart; return 0; } static DB_playItem_t * cvorbis_insert (DB_playItem_t *after, const char *fname) { // check for validity FILE *fp = fopen (fname, "rb"); if (!fp) { return NULL; } OggVorbis_File vorbis_file; vorbis_info *vi; ov_open (fp, &vorbis_file, NULL, 0); vi = ov_info (&vorbis_file, -1); if (!vi) { // not a vorbis stream return NULL; } DB_playItem_t *it = deadbeef->pl_item_alloc (); it->decoder = &plugin; it->fname = strdup (fname); it->filetype = "OggVorbis"; it->duration = ov_seekable (&vorbis_file) ? ov_time_total (&vorbis_file, -1) : -1; DB_playItem_t *cue_after = deadbeef->pl_insert_cue (after, fname, &plugin, it->filetype); if (cue_after) { cue_after->timeend = it->duration; cue_after->duration = cue_after->timeend - cue_after->timestart; deadbeef->pl_item_free (it); ov_clear (&vorbis_file); return cue_after; } // metainfo int title_added = 0; vorbis_comment *vc = ov_comment (&vorbis_file, -1); if (vc) { deadbeef->pl_add_meta (it, "vendor", vc->vendor); for (int i = 0; i < vc->comments; i++) { if (!strncasecmp (vc->user_comments[i], "artist=", 7)) { deadbeef->pl_add_meta (it, "artist", vc->user_comments[i] + 7); } else if (!strncasecmp (vc->user_comments[i], "album=", 6)) { deadbeef->pl_add_meta (it, "album", vc->user_comments[i] + 6); } else if (!strncasecmp (vc->user_comments[i], "title=", 6)) { deadbeef->pl_add_meta (it, "title", vc->user_comments[i] + 6); title_added = 1; } else if (!strncasecmp (vc->user_comments[i], "date=", 5)) { deadbeef->pl_add_meta (it, "date", vc->user_comments[i] + 5); } } } if (!title_added) { deadbeef->pl_add_meta (it, "title", NULL); } ov_clear (&vorbis_file); after = deadbeef->pl_insert_item (after, it); return after; } static const char * exts[] = { "ogg", NULL }; static const char *filetypes[] = { "OggVorbis", NULL }; // define plugin interface static DB_decoder_t plugin = { .plugin.version_major = 0, .plugin.version_minor = 1, .plugin.type = DB_PLUGIN_DECODER, .plugin.name = "OggVorbis decoder", .plugin.author = "Alexey Yakovenko", .plugin.email = "waker@users.sourceforge.net", .plugin.website = "http://deadbeef.sf.net", .init = cvorbis_init, .free = cvorbis_free, .read_int16 = cvorbis_read, // vorbisfile can't output float32 // .read_float32 = cvorbis_read_float32, .seek = cvorbis_seek, .insert = cvorbis_insert, .exts = exts, .id = "stdogg", .filetypes = filetypes }; DB_plugin_t * oggvorbis_load (DB_functions_t *api) { deadbeef = api; return DB_PLUGIN (&plugin); }