WavPack improvements
This patch does the following: -enables WVC support for streams as well, -improves MPD inputStream <=> WavPack stream connector, -fixes two compile warnings (which were caused by MPD API change). Mantis #1660 <http://musicpd.org/mantis/view.php?id=1660> git-svn-id: https://svn.musicpd.org/mpd/trunk@7210 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
@@ -52,9 +52,6 @@ static struct {
|
|||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* workaround for at least the last push_back_byte */
|
|
||||||
static int last_byte = EOF;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function has been borrowed from the tiny player found on
|
* This function has been borrowed from the tiny player found on
|
||||||
* wavpack.com. Modifications were required because mpd only handles
|
* wavpack.com. Modifications were required because mpd only handles
|
||||||
@@ -153,7 +150,12 @@ static void wavpack_decode(OutputBuffer *cb, DecoderControl *dc,
|
|||||||
format_samples = format_samples_float;
|
format_samples = format_samples_float;
|
||||||
else
|
else
|
||||||
format_samples = format_samples_int;
|
format_samples = format_samples_int;
|
||||||
|
/*
|
||||||
|
if ((WavpackGetMode(wpc) & MODE_WVC) == MODE_WVC)
|
||||||
|
ERROR("decoding WITH wvc!!!\n");
|
||||||
|
else
|
||||||
|
ERROR("decoding without wvc\n");
|
||||||
|
*/
|
||||||
allsamples = WavpackGetNumSamples(wpc);
|
allsamples = WavpackGetNumSamples(wpc);
|
||||||
Bps = WavpackGetBytesPerSample(wpc);
|
Bps = WavpackGetBytesPerSample(wpc);
|
||||||
|
|
||||||
@@ -168,6 +170,7 @@ static void wavpack_decode(OutputBuffer *cb, DecoderControl *dc,
|
|||||||
|
|
||||||
dc->totalTime = (float)allsamples / dc->audioFormat.sampleRate;
|
dc->totalTime = (float)allsamples / dc->audioFormat.sampleRate;
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
|
dc->seekable = canseek;
|
||||||
|
|
||||||
position = 0;
|
position = 0;
|
||||||
|
|
||||||
@@ -339,49 +342,57 @@ static MpdTag *wavpack_tagdup(char *fname)
|
|||||||
* mpd InputStream <=> WavpackStreamReader wrapper callbacks
|
* mpd InputStream <=> WavpackStreamReader wrapper callbacks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* This struct is needed for per-stream last_byte storage. */
|
||||||
|
typedef struct {
|
||||||
|
InputStream *is;
|
||||||
|
/* Needed for push_back_byte() */
|
||||||
|
int last_byte;
|
||||||
|
} InputStreamPlus;
|
||||||
|
|
||||||
static int32_t read_bytes(void *id, void *data, int32_t bcount)
|
static int32_t read_bytes(void *id, void *data, int32_t bcount)
|
||||||
{
|
{
|
||||||
|
InputStreamPlus *isp = (InputStreamPlus *)id;
|
||||||
uint8_t *buf = (uint8_t *)data;
|
uint8_t *buf = (uint8_t *)data;
|
||||||
int32_t i = 0;
|
int32_t i = 0;
|
||||||
|
|
||||||
if (last_byte != EOF) {
|
if (isp->last_byte != EOF) {
|
||||||
*buf++ = last_byte;
|
*buf++ = isp->last_byte;
|
||||||
last_byte = EOF;
|
isp->last_byte = EOF;
|
||||||
--bcount;
|
--bcount;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
return i + readFromInputStream((InputStream *)id, buf, 1, bcount);
|
return i + readFromInputStream(isp->is, buf, 1, bcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t get_pos(void *id)
|
static uint32_t get_pos(void *id)
|
||||||
{
|
{
|
||||||
return ((InputStream *)id)->offset;
|
return ((InputStreamPlus *)id)->is->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_pos_abs(void *id, uint32_t pos)
|
static int set_pos_abs(void *id, uint32_t pos)
|
||||||
{
|
{
|
||||||
return seekInputStream((InputStream *)id, pos, SEEK_SET);
|
return seekInputStream(((InputStreamPlus *)id)->is, pos, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_pos_rel(void *id, int32_t delta, int mode)
|
static int set_pos_rel(void *id, int32_t delta, int mode)
|
||||||
{
|
{
|
||||||
return seekInputStream((InputStream *)id, delta, mode);
|
return seekInputStream(((InputStreamPlus *)id)->is, delta, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int push_back_byte(void *id, int c)
|
static int push_back_byte(void *id, int c)
|
||||||
{
|
{
|
||||||
last_byte = c;
|
((InputStreamPlus *)id)->last_byte = c;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t get_length(void *id)
|
static uint32_t get_length(void *id)
|
||||||
{
|
{
|
||||||
return ((InputStream *)id)->size;
|
return ((InputStreamPlus *)id)->is->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int can_seek(void *id)
|
static int can_seek(void *id)
|
||||||
{
|
{
|
||||||
return (seekInputStream((InputStream *)id, 0, SEEK_SET) != -1);
|
return ((InputStreamPlus *)id)->is->seekable;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WavpackStreamReader mpd_is_reader = {
|
static WavpackStreamReader mpd_is_reader = {
|
||||||
@@ -395,6 +406,13 @@ static WavpackStreamReader mpd_is_reader = {
|
|||||||
.write_bytes = NULL /* no need to write edited tags */
|
.write_bytes = NULL /* no need to write edited tags */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
initInputStreamPlus(InputStreamPlus *isp, InputStream *is)
|
||||||
|
{
|
||||||
|
isp->is = is;
|
||||||
|
isp->last_byte = EOF;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tries to decode the specified stream, and gives true if managed to do it.
|
* Tries to decode the specified stream, and gives true if managed to do it.
|
||||||
*/
|
*/
|
||||||
@@ -402,8 +420,10 @@ static unsigned int wavpack_trydecode(InputStream *is)
|
|||||||
{
|
{
|
||||||
char error[ERRORLEN];
|
char error[ERRORLEN];
|
||||||
WavpackContext *wpc;
|
WavpackContext *wpc;
|
||||||
|
InputStreamPlus isp;
|
||||||
|
|
||||||
wpc = WavpackOpenFileInputEx(&mpd_is_reader, (void *)is, NULL, error,
|
initInputStreamPlus(&isp, is);
|
||||||
|
wpc = WavpackOpenFileInputEx(&mpd_is_reader, &isp, NULL, error,
|
||||||
OPEN_STREAMING, 0);
|
OPEN_STREAMING, 0);
|
||||||
if (wpc == NULL)
|
if (wpc == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -417,37 +437,118 @@ static unsigned int wavpack_trydecode(InputStream *is)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Decodes a stream.
|
* Decodes a stream.
|
||||||
* We cannot handle wvc files this way, use the wavpack_filedecode for that.
|
|
||||||
*/
|
*/
|
||||||
static int wavpack_streamdecode(OutputBuffer *cb, DecoderControl *dc,
|
static int wavpack_streamdecode(OutputBuffer *cb, DecoderControl *dc,
|
||||||
InputStream *is)
|
InputStream *is)
|
||||||
{
|
{
|
||||||
char error[ERRORLEN];
|
char error[ERRORLEN];
|
||||||
WavpackContext *wpc;
|
WavpackContext *wpc;
|
||||||
|
InputStream is_wvc;
|
||||||
|
int open_flags = OPEN_2CH_MAX | OPEN_NORMALIZE /*| OPEN_STREAMING*/;
|
||||||
|
char *wvc_url = NULL;
|
||||||
|
int err;
|
||||||
|
InputStreamPlus isp, isp_wvc;
|
||||||
|
int canseek;
|
||||||
|
|
||||||
/*
|
/* Try to find wvc */
|
||||||
* wavpack_streamdecode is unable to use wvc :-(
|
do {
|
||||||
* If we know the original stream url, we would find out the wvc url...
|
size_t len;
|
||||||
* This would require InputStream to store that.
|
err = 1;
|
||||||
*/
|
|
||||||
|
/*
|
||||||
|
* As we use dc->utf8url, this function will be bad for
|
||||||
|
* single files. utf8url is not absolute file path :/
|
||||||
|
*/
|
||||||
|
if (dc->utf8url == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(dc->utf8url);
|
||||||
|
if (!len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
wvc_url = (char *)malloc(len + 2); /* +2: 'c' and EOS */
|
||||||
|
if (wvc_url == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(wvc_url, dc->utf8url, len);
|
||||||
|
wvc_url[len] = 'c';
|
||||||
|
wvc_url[len + 1] = '\0';
|
||||||
|
|
||||||
|
if (openInputStream(&is_wvc, wvc_url)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And we try to buffer in order to get know
|
||||||
|
* about a possible 404 error.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
if (inputStreamAtEOF(&is_wvc)) {
|
||||||
|
/*
|
||||||
|
* EOF is reached even without
|
||||||
|
* a single byte is read...
|
||||||
|
* So, this is not good :/
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferInputStream(&is_wvc) >= 0) {
|
||||||
|
err = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dc->stop) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save some CPU */
|
||||||
|
my_usleep(1000);
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
closeInputStream(&is_wvc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
open_flags |= OPEN_WVC;
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
canseek = can_seek(&isp);
|
||||||
|
if (wvc_url != NULL) {
|
||||||
|
if (err) {
|
||||||
|
free(wvc_url);
|
||||||
|
wvc_url = NULL;
|
||||||
|
} else {
|
||||||
|
initInputStreamPlus(&isp_wvc, &is_wvc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initInputStreamPlus(&isp, is);
|
||||||
|
wpc = WavpackOpenFileInputEx(&mpd_is_reader, &isp, &isp_wvc, error,
|
||||||
|
open_flags, 15);
|
||||||
|
|
||||||
wpc = WavpackOpenFileInputEx(&mpd_is_reader, (void *)is, NULL, error,
|
|
||||||
OPEN_2CH_MAX | OPEN_NORMALIZE, 15);
|
|
||||||
if (wpc == NULL) {
|
if (wpc == NULL) {
|
||||||
ERROR("failed to open WavPack stream: %s\n", error);
|
ERROR("failed to open WavPack stream: %s\n", error);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wavpack_decode(cb, dc, wpc, can_seek(is), NULL);
|
wavpack_decode(cb, dc, wpc, canseek, NULL);
|
||||||
|
|
||||||
WavpackCloseFile(wpc);
|
WavpackCloseFile(wpc);
|
||||||
|
if (wvc_url != NULL) {
|
||||||
|
closeInputStream(&is_wvc);
|
||||||
|
free(wvc_url);
|
||||||
|
}
|
||||||
|
closeInputStream(is);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decodes a file. This has the goods on wavpack_streamdecode that this
|
* Decodes a file.
|
||||||
* can handle wvc files.
|
|
||||||
*/
|
*/
|
||||||
static int wavpack_filedecode(OutputBuffer *cb, DecoderControl *dc, char *fname)
|
static int wavpack_filedecode(OutputBuffer *cb, DecoderControl *dc, char *fname)
|
||||||
{
|
{
|
||||||
@@ -475,8 +576,8 @@ static int wavpack_filedecode(OutputBuffer *cb, DecoderControl *dc, char *fname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *wavpackSuffixes[] = { "wv", NULL };
|
static char const *wavpackSuffixes[] = { "wv", NULL };
|
||||||
static char *wavpackMimeTypes[] = { "audio/x-wavpack", NULL };
|
static char const *wavpackMimeTypes[] = { "audio/x-wavpack", NULL };
|
||||||
|
|
||||||
InputPlugin wavpackPlugin = {
|
InputPlugin wavpackPlugin = {
|
||||||
"wavpack",
|
"wavpack",
|
||||||
@@ -484,7 +585,7 @@ InputPlugin wavpackPlugin = {
|
|||||||
NULL,
|
NULL,
|
||||||
wavpack_trydecode,
|
wavpack_trydecode,
|
||||||
wavpack_streamdecode,
|
wavpack_streamdecode,
|
||||||
wavpack_filedecode, /* provides more functionality! (wvc) */
|
wavpack_filedecode,
|
||||||
wavpack_tagdup,
|
wavpack_tagdup,
|
||||||
INPUT_PLUGIN_STREAM_FILE | INPUT_PLUGIN_STREAM_URL,
|
INPUT_PLUGIN_STREAM_FILE | INPUT_PLUGIN_STREAM_URL,
|
||||||
wavpackSuffixes,
|
wavpackSuffixes,
|
||||||
|
Reference in New Issue
Block a user