/*
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 "codec.h"
#include "cvorbis.h"
#include "playlist.h"
static FILE *file;
static OggVorbis_File vorbis_file;
static vorbis_info *vi;
static int cur_bit_stream;
static float timestart;
static float timeend;
void
cvorbis_free (void);
int
cvorbis_seek (float time);
int
cvorbis_init (struct playItem_s *it) {
file = NULL;
vi = NULL;
cur_bit_stream = -1;
file = fopen (it->fname, "rb");
if (!file) {
return -1;
}
memset (&cvorbis.info, 0, sizeof (fileinfo_t));
ov_open (file, &vorbis_file, NULL, 0);
vi = ov_info (&vorbis_file, -1);
if (!vi) { // not a vorbis stream
cvorbis_free ();
return -1;
}
cvorbis.info.bitsPerSample = 16;
//cvorbis.info.dataSize = ov_pcm_total (&vorbis_file, -1) * vi->channels * 2;
cvorbis.info.channels = vi->channels;
cvorbis.info.samplesPerSecond = vi->rate;
cvorbis.info.readposition = 0;
if (it->timeend > 0) {
timestart = it->timestart;
timeend = it->timeend;
cvorbis_seek (0);
}
else {
timestart = 0;
timeend = it->duration;
}
return 0;
}
void
cvorbis_free (void) {
if (file) {
ov_clear (&vorbis_file);
//fclose (file); //-- ov_clear closes it
file = NULL;
vi = NULL;
}
}
int
cvorbis_read (char *bytes, int size) {
if (cvorbis.info.readposition >= (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;
}
}
cvorbis.info.readposition = ov_time_tell(&vorbis_file) - timestart;
if (cvorbis.info.readposition >= (timeend - timestart)) {
return 0;
}
return initsize - size;
}
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;
cvorbis.info.readposition = ov_time_tell(&vorbis_file) - timestart;
return 0;
}
playItem_t *
cvorbis_insert (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;
}
playItem_t *it = malloc (sizeof (playItem_t));
memset (it, 0, sizeof (playItem_t));
it->codec = &cvorbis;
it->fname = strdup (fname);
it->filetype = "OggVorbis";
it->duration = ov_seekable (&vorbis_file) ? ov_time_total (&vorbis_file, -1) : -1;
playItem_t *cue_after = pl_insert_cue (after, fname, &cvorbis, it->filetype);
if (cue_after) {
cue_after->timeend = it->duration;
cue_after->duration = cue_after->timeend - cue_after->timestart;
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) {
pl_add_meta (it, "vendor", vc->vendor);
for (int i = 0; i < vc->comments; i++) {
if (!strncmp (vc->user_comments[i], "artist=", 7)) {
pl_add_meta (it, "artist", vc->user_comments[i] + 7);
}
else if (!strncmp (vc->user_comments[i], "title=", 6)) {
pl_add_meta (it, "title", vc->user_comments[i] + 6);
title_added = 1;
}
else if (!strncmp (vc->user_comments[i], "date=", 5)) {
pl_add_meta (it, "date", vc->user_comments[i] + 5);
}
}
}
if (!title_added) {
pl_add_meta (it, "title", NULL);
}
ov_clear (&vorbis_file);
after = pl_insert_item (after, it);
return after;
}
static const char * exts[]=
{
"ogg",NULL
};
const char **cvorbis_getexts (void) {
return exts;
}
codec_t cvorbis = {
.init = cvorbis_init,
.free = cvorbis_free,
.read = cvorbis_read,
.seek = cvorbis_seek,
.insert = cvorbis_insert,
.getexts = cvorbis_getexts,
.id = "stdogg",
.filetypes = { "OggVorbis", NULL }
};