From 08e724afb2c7f09e8f7a4b2222694a8d4faffde7 Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Sun, 4 Oct 2009 13:08:03 +0200 Subject: experimental vorbis streaming support --- plugins/vorbis/vorbis.c | 195 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 144 insertions(+), 51 deletions(-) (limited to 'plugins/vorbis/vorbis.c') diff --git a/plugins/vorbis/vorbis.c b/plugins/vorbis/vorbis.c index 32d99660..0c277f04 100644 --- a/plugins/vorbis/vorbis.c +++ b/plugins/vorbis/vorbis.c @@ -40,6 +40,8 @@ static int cur_bit_stream; static int startsample; static int endsample; static int currentsample; +static int last_comment_update; +static DB_playItem_t *ptrack; static void cvorbis_free (void); @@ -52,6 +54,9 @@ cvorbis_fread (void *ptr, size_t size, size_t nmemb, void *datasource) { static int cvorbis_fseek (void *datasource, ogg_int64_t offset, int whence) { DB_FILE *f = (DB_FILE *)datasource; + if (f->vfs->streaming) { + return -1; + } return deadbeef->fseek (datasource, offset, whence); } @@ -66,29 +71,91 @@ cvorbis_ftell (void *datasource) { return deadbeef->ftell (datasource); } +static void +update_vorbis_comments (DB_playItem_t *it, vorbis_comment *vc) { + if (vc) { + deadbeef->pl_delete_all_meta (it); + 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); + } + else if (!strncasecmp (vc->user_comments[i], "date=", 5)) { + deadbeef->pl_add_meta (it, "date", vc->user_comments[i] + 5); + } + else if (!strncasecmp (vc->user_comments[i], "replaygain_album_gain=", 22)) { + it->replaygain_album_gain = atof (vc->user_comments[i] + 22); + } + else if (!strncasecmp (vc->user_comments[i], "replaygain_album_peak=", 22)) { + it->replaygain_album_peak = atof (vc->user_comments[i] + 22); + } + else if (!strncasecmp (vc->user_comments[i], "replaygain_track_gain=", 22)) { + it->replaygain_track_gain = atof (vc->user_comments[i] + 22); + } + else if (!strncasecmp (vc->user_comments[i], "replaygain_track_peak=", 22)) { + it->replaygain_track_peak = atof (vc->user_comments[i] + 22); + } + } + } + deadbeef->pl_add_meta (it, "title", NULL); +} + static int cvorbis_init (DB_playItem_t *it) { file = NULL; vi = NULL; cur_bit_stream = -1; + ptrack = it; 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_callbacks (file, &vorbis_file, NULL, 0, ovcb); + if (file->vfs->streaming) { + ov_callbacks ovcb = { + .read_func = cvorbis_fread, + .seek_func = NULL, + .close_func = cvorbis_fclose, + .tell_func = NULL + }; + + int err; + trace ("calling ov_open_callbacks\n"); + if (err = ov_open_callbacks (file, &vorbis_file, NULL, 0, ovcb) != 0) { + trace ("ov_open_callbacks returned %d\n", err); + plugin.free (); + return -1; + } + } + else + { + ov_callbacks ovcb = { + .read_func = cvorbis_fread, + .seek_func = cvorbis_fseek, + .close_func = cvorbis_fclose, + .tell_func = cvorbis_ftell + }; + + trace ("calling ov_open_callbacks\n"); + int err; + if (err = ov_open_callbacks (file, &vorbis_file, NULL, 0, ovcb) != 0) { + trace ("ov_open_callbacks returned %d\n", err); + plugin.free (); + return -1; + } + } vi = ov_info (&vorbis_file, -1); if (!vi) { // not a vorbis stream cvorbis_free (); + trace ("not a vorbis stream\n"); return -1; } plugin.info.bps = 16; @@ -97,14 +164,26 @@ cvorbis_init (DB_playItem_t *it) { plugin.info.samplerate = vi->rate; plugin.info.readpos = 0; currentsample = 0; - if (it->endsample > 0) { - startsample = it->startsample; - endsample = it->endsample; - plugin.seek_sample (0); + if (!file->vfs->streaming) { + if (it->endsample > 0) { + startsample = it->startsample; + endsample = it->endsample; + plugin.seek_sample (0); + } + else { + startsample = 0; + endsample = ov_pcm_total (&vorbis_file, -1)-1; + } } else { startsample = 0; endsample = ov_pcm_total (&vorbis_file, -1)-1; + if (endsample <= 0) { + endsample = -1; + } + it->duration = -1; + vorbis_comment *vc = ov_comment (&vorbis_file, -1); + update_vorbis_comments (it, vc); } return 0; } @@ -112,6 +191,7 @@ cvorbis_init (DB_playItem_t *it) { static void cvorbis_free (void) { if (file) { + ptrack = NULL; ov_clear (&vorbis_file); //fclose (file); //-- ov_clear closes it file = NULL; @@ -121,13 +201,31 @@ cvorbis_free (void) { static int cvorbis_read (char *bytes, int size) { - if (currentsample + size / (2 * plugin.info.channels) > endsample) { - size = (endsample - currentsample + 1) * 2 * plugin.info.channels; - trace ("size truncated to %d bytes, cursample=%d, endsample=%d, totalsamples=%d\n", size, currentsample, endsample, ov_pcm_total (&vorbis_file, -1)); - if (size <= 0) { - return 0; +// trace ("cvorbis_read %d bytes\n", size); + if (!file->vfs->streaming) { + if (currentsample + size / (2 * plugin.info.channels) > endsample) { + size = (endsample - currentsample + 1) * 2 * plugin.info.channels; +// trace ("size truncated to %d bytes, cursample=%d, endsample=%d, totalsamples=%d\n", size, currentsample, endsample, ov_pcm_total (&vorbis_file, -1)); + if (size <= 0) { + return 0; + } } } + else { + if (ptrack && currentsample - last_comment_update > 5 * plugin.info.samplerate) { + int idx = deadbeef->pl_get_idx_of (ptrack); + if (idx >= 0) { + last_comment_update = currentsample; + vorbis_comment *vc = ov_comment (&vorbis_file, -1); + update_vorbis_comments (ptrack, vc); + deadbeef->sendmessage (M_TRACKCHANGED, 0, idx, 0); + } + else { + ptrack = NULL; + } + } + } +// trace ("cvorbis_read %d bytes[2]\n", size); int initsize = size; for (;;) { @@ -139,6 +237,23 @@ cvorbis_read (char *bytes, int size) { long ret=ov_read (&vorbis_file, bytes, size, endianess, 2, 1, &cur_bit_stream); if (ret <= 0) { + if (ret < 0) { + trace ("ov_read returned %d\n", ret); + switch (ret) { + case OV_HOLE: + trace ("OV_HOLE\n"); + break; + case OV_EBADLINK: + trace ("OV_EBADLINK\n"); + break; + case OV_EINVAL: + trace ("OV_EINVAL\n"); + break; + } + } + if (ret == OV_HOLE) { + continue; + } // error or eof break; } @@ -155,6 +270,7 @@ cvorbis_read (char *bytes, int size) { } } plugin.info.readpos = (float)(ov_pcm_tell(&vorbis_file)-startsample)/vi->rate; +// trace ("cvorbis_read got %d bytes\n", initsize-size); return initsize - size; } @@ -189,6 +305,16 @@ cvorbis_insert (DB_playItem_t *after, const char *fname) { fprintf (stderr, "vorbis: failed to fopen %s\n", fname); return NULL; } + if (fp->vfs->streaming) { + DB_playItem_t *it = deadbeef->pl_item_alloc (); + it->decoder = &plugin; + it->fname = strdup (fname); + it->filetype = "OggVorbis"; + it->duration = -1; + deadbeef->pl_add_meta (it, "title", NULL); + after = deadbeef->pl_insert_item (after, it); + return after; + } ov_callbacks ovcb = { .read_func = cvorbis_fread, .seek_func = cvorbis_fseek, @@ -218,41 +344,8 @@ cvorbis_insert (DB_playItem_t *after, const char *fname) { it->duration = duration; // 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); - } - else if (!strncasecmp (vc->user_comments[i], "replaygain_album_gain=", 22)) { - it->replaygain_album_gain = atof (vc->user_comments[i] + 22); - } - else if (!strncasecmp (vc->user_comments[i], "replaygain_album_peak=", 22)) { - it->replaygain_album_peak = atof (vc->user_comments[i] + 22); - } - else if (!strncasecmp (vc->user_comments[i], "replaygain_track_gain=", 22)) { - it->replaygain_track_gain = atof (vc->user_comments[i] + 22); - } - else if (!strncasecmp (vc->user_comments[i], "replaygain_track_peak=", 22)) { - it->replaygain_track_peak = atof (vc->user_comments[i] + 22); - } - } - } - if (!title_added) { - deadbeef->pl_add_meta (it, "title", NULL); - } + update_vorbis_comments (it, vc); ov_clear (&vorbis_file); after = deadbeef->pl_insert_item (after, it); return after; -- cgit v1.2.3