flac uses abstracted inputStream stuff
git-svn-id: https://svn.musicpd.org/mpd/trunk@905 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
659df58671
commit
c4a9e3790f
@ -23,11 +23,12 @@
|
||||
#include "utils.h"
|
||||
#include "log.h"
|
||||
#include "pcm_utils.h"
|
||||
#include "inputStream.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <FLAC/file_decoder.h>
|
||||
#include <FLAC/seekable_stream_decoder.h>
|
||||
#include <FLAC/metadata.h>
|
||||
|
||||
typedef struct {
|
||||
@ -39,21 +40,35 @@ typedef struct {
|
||||
Buffer * cb;
|
||||
AudioFormat * af;
|
||||
DecoderControl * dc;
|
||||
char * file;
|
||||
char * file;
|
||||
InputStream inStream;
|
||||
} FlacData;
|
||||
|
||||
/* this code is based on flac123, from flac-tools */
|
||||
|
||||
int flacSendChunk(FlacData * data);
|
||||
void flacError(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *);
|
||||
void flacPrintErroredState(FLAC__FileDecoderState state, char * file);
|
||||
void flacMetadata(const FLAC__FileDecoder *, const FLAC__StreamMetadata *, void *);
|
||||
FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__FileDecoder *, const FLAC__Frame *, const FLAC__int32 * const buf[], void *);
|
||||
void flacError(const FLAC__SeekableStreamDecoder *,
|
||||
FLAC__StreamDecoderErrorStatus, void *);
|
||||
void flacPrintErroredState(FLAC__SeekableStreamDecoderState state, char * file);
|
||||
void flacMetadata(const FLAC__SeekableStreamDecoder *,
|
||||
const FLAC__StreamMetadata *, void *);
|
||||
FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecoder *,
|
||||
const FLAC__Frame *, const FLAC__int32 * const buf[], void *);
|
||||
FLAC__SeekableStreamDecoderReadStatus flacRead(
|
||||
const FLAC__SeekableStreamDecoder *, FLAC__byte buf[],
|
||||
unsigned *, void *);
|
||||
FLAC__SeekableStreamDecoderSeekStatus flacSeek(
|
||||
const FLAC__SeekableStreamDecoder *, FLAC__uint64, void *);
|
||||
FLAC__SeekableStreamDecoderTellStatus flacTell(
|
||||
const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *);
|
||||
FLAC__SeekableStreamDecoderLengthStatus flacLength(
|
||||
const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *);
|
||||
FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder *, void *);
|
||||
|
||||
void flacPlayFile(char *file, Buffer * cb, AudioFormat * af,
|
||||
DecoderControl *dc)
|
||||
{
|
||||
FLAC__FileDecoder * flacDec;
|
||||
FLAC__SeekableStreamDecoder * flacDec;
|
||||
FlacData data;
|
||||
int status = 1;
|
||||
|
||||
@ -64,39 +79,59 @@ void flacPlayFile(char *file, Buffer * cb, AudioFormat * af,
|
||||
data.cb = cb;
|
||||
data.af = af;
|
||||
data.dc = dc;
|
||||
data.file = file;
|
||||
data.file = file;
|
||||
|
||||
if(!(flacDec = FLAC__file_decoder_new())) return;
|
||||
if(openInputStreamFromFile(&(data.inStream),file)<0) {
|
||||
ERROR("unable to open flac: %s\n",file);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(flacDec = FLAC__seekable_stream_decoder_new())) return;
|
||||
/*status&=FLAC__file_decoder_set_md5_checking(flacDec,1);*/
|
||||
status&=FLAC__file_decoder_set_filename(flacDec,file);
|
||||
status&=FLAC__file_decoder_set_write_callback(flacDec,flacWrite);
|
||||
status&=FLAC__file_decoder_set_metadata_callback(flacDec,flacMetadata);
|
||||
status&=FLAC__file_decoder_set_error_callback(flacDec,flacError);
|
||||
status&=FLAC__file_decoder_set_client_data(flacDec, (void *)&data);
|
||||
status&=FLAC__seekable_stream_decoder_set_read_callback(flacDec,
|
||||
flacRead);
|
||||
status&=FLAC__seekable_stream_decoder_set_seek_callback(flacDec,
|
||||
flacSeek);
|
||||
status&=FLAC__seekable_stream_decoder_set_tell_callback(flacDec,
|
||||
flacTell);
|
||||
status&=FLAC__seekable_stream_decoder_set_length_callback(flacDec,
|
||||
flacLength);
|
||||
status&=FLAC__seekable_stream_decoder_set_eof_callback(flacDec,flacEOF);
|
||||
status&=FLAC__seekable_stream_decoder_set_write_callback(flacDec,
|
||||
flacWrite);
|
||||
status&=FLAC__seekable_stream_decoder_set_metadata_callback(flacDec,
|
||||
flacMetadata);
|
||||
status&=FLAC__seekable_stream_decoder_set_error_callback(flacDec,
|
||||
flacError);
|
||||
status&=FLAC__seekable_stream_decoder_set_client_data(flacDec,
|
||||
(void *)&data);
|
||||
if(!status) {
|
||||
ERROR("flac problem before init(): %s\n",file);
|
||||
flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file);
|
||||
FLAC__file_decoder_delete(flacDec);
|
||||
flacPrintErroredState(
|
||||
FLAC__seekable_stream_decoder_get_state(flacDec),file);
|
||||
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||
return;
|
||||
}
|
||||
if(FLAC__file_decoder_init(flacDec)!=
|
||||
if(FLAC__seekable_stream_decoder_init(flacDec)!=
|
||||
FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
|
||||
{
|
||||
ERROR("flac problem doing init(): %s\n",file);
|
||||
flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file);
|
||||
FLAC__file_decoder_delete(flacDec);
|
||||
flacPrintErroredState(
|
||||
FLAC__seekable_stream_decoder_get_state(flacDec),file);
|
||||
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||
return;
|
||||
}
|
||||
if(!FLAC__file_decoder_process_until_end_of_metadata(flacDec)) {
|
||||
if(!FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDec)) {
|
||||
ERROR("flac problem reading metadata: %s\n",file);
|
||||
flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file);
|
||||
FLAC__file_decoder_delete(flacDec);
|
||||
flacPrintErroredState(
|
||||
FLAC__seekable_stream_decoder_get_state(flacDec),file);
|
||||
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||
return;
|
||||
}
|
||||
while(1) {
|
||||
FLAC__file_decoder_process_single(flacDec);
|
||||
if(FLAC__file_decoder_get_state(flacDec)!=
|
||||
FLAC__FILE_DECODER_OK)
|
||||
FLAC__seekable_stream_decoder_process_single(flacDec);
|
||||
if(FLAC__seekable_stream_decoder_get_state(flacDec)!=
|
||||
FLAC__SEEKABLE_STREAM_DECODER_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -105,7 +140,7 @@ void flacPlayFile(char *file, Buffer * cb, AudioFormat * af,
|
||||
af->sampleRate+0.5;
|
||||
cb->end = cb->begin;
|
||||
cb->wrap = 0;
|
||||
if(FLAC__file_decoder_seek_absolute(flacDec,
|
||||
if(FLAC__seekable_stream_decoder_seek_absolute(flacDec,
|
||||
sampleToSeek))
|
||||
{
|
||||
data.time = ((float)sampleToSeek)/
|
||||
@ -118,16 +153,76 @@ void flacPlayFile(char *file, Buffer * cb, AudioFormat * af,
|
||||
/* I don't think we need this bit here! -shank */
|
||||
/*FLAC__file_decoder_process_until_end_of_file(flacDec);*/
|
||||
if(!dc->stop) {
|
||||
flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),
|
||||
file);
|
||||
FLAC__file_decoder_finish(flacDec);
|
||||
flacPrintErroredState(
|
||||
FLAC__seekable_stream_decoder_get_state(flacDec),file);
|
||||
FLAC__seekable_stream_decoder_finish(flacDec);
|
||||
}
|
||||
FLAC__file_decoder_delete(flacDec);
|
||||
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||
/* send last little bit */
|
||||
if(data.chunk_length>0 && !dc->stop) flacSendChunk(&data);
|
||||
}
|
||||
|
||||
void flacError(const FLAC__FileDecoder *dec, FLAC__StreamDecoderErrorStatus status, void *fdata) {
|
||||
FLAC__SeekableStreamDecoderReadStatus flacRead(
|
||||
const FLAC__SeekableStreamDecoder * flacDec, FLAC__byte buf[],
|
||||
unsigned * bytes, void * fdata) {
|
||||
FlacData * data = (FlacData *) fdata;
|
||||
|
||||
*bytes = readFromInputStream(&(data->inStream),(void *)buf,1,*bytes);
|
||||
|
||||
if(*bytes==0) return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
|
||||
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__SeekableStreamDecoderSeekStatus flacSeek(
|
||||
const FLAC__SeekableStreamDecoder * flacDec,
|
||||
FLAC__uint64 offset, void * fdata)
|
||||
{
|
||||
FlacData * data = (FlacData *) fdata;
|
||||
|
||||
if(seekInputStream(&(data->inStream),offset,SEEK_SET)<0) {
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__SeekableStreamDecoderTellStatus flacTell(
|
||||
const FLAC__SeekableStreamDecoder * flacDec,
|
||||
FLAC__uint64 * offset, void * fdata)
|
||||
{
|
||||
FlacData * data = (FlacData *) fdata;
|
||||
|
||||
*offset = data->inStream.offset;
|
||||
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__SeekableStreamDecoderLengthStatus flacLength(
|
||||
const FLAC__SeekableStreamDecoder * flacDec,
|
||||
FLAC__uint64 * length, void * fdata)
|
||||
{
|
||||
FlacData * data = (FlacData *) fdata;
|
||||
|
||||
*length = data->inStream.size;
|
||||
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder * flacDec, void * fdata) {
|
||||
FlacData * data = (FlacData *) fdata;
|
||||
|
||||
switch(inputStreamAtEOF(&(data->inStream))) {
|
||||
case 1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void flacError(const FLAC__SeekableStreamDecoder *dec,
|
||||
FLAC__StreamDecoderErrorStatus status, void *fdata)
|
||||
{
|
||||
FlacData * data = (FlacData *) fdata;
|
||||
if(data->dc->stop) return;
|
||||
|
||||
@ -146,36 +241,41 @@ void flacError(const FLAC__FileDecoder *dec, FLAC__StreamDecoderErrorStatus stat
|
||||
}
|
||||
}
|
||||
|
||||
void flacPrintErroredState(FLAC__FileDecoderState state, char * file) {
|
||||
void flacPrintErroredState(FLAC__SeekableStreamDecoderState state,
|
||||
char * file)
|
||||
{
|
||||
switch(state) {
|
||||
case FLAC__FILE_DECODER_ERROR_OPENING_FILE:
|
||||
ERROR("error opening flac: %s\n",file);
|
||||
break;
|
||||
case FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
|
||||
ERROR("flac allocation error\n");
|
||||
break;
|
||||
case FLAC__FILE_DECODER_SEEK_ERROR:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR:
|
||||
ERROR("flac read error: %s\n",file);
|
||||
break;
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR:
|
||||
ERROR("flac seek error: %s\n",file);
|
||||
break;
|
||||
case FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR:
|
||||
ERROR("flac seekable stream error: %s\n",file);
|
||||
break;
|
||||
case FLAC__FILE_DECODER_ALREADY_INITIALIZED:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED:
|
||||
ERROR("flac decoder already initilaized: %s\n",file);
|
||||
break;
|
||||
case FLAC__FILE_DECODER_INVALID_CALLBACK:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK:
|
||||
ERROR("invalid flac callback\n");
|
||||
break;
|
||||
case FLAC__FILE_DECODER_UNINITIALIZED:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED:
|
||||
ERROR("flac decoder uninitialized: %s\n",file);
|
||||
break;
|
||||
case FLAC__FILE_DECODER_OK:
|
||||
case FLAC__FILE_DECODER_END_OF_FILE:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_OK:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_SEEKING:
|
||||
case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flacMetadata(const FLAC__FileDecoder *dec, const FLAC__StreamMetadata *meta, void *data) {
|
||||
void flacMetadata(const FLAC__SeekableStreamDecoder *dec,
|
||||
const FLAC__StreamMetadata *meta, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
int flacSendChunk(FlacData * data) {
|
||||
@ -203,7 +303,10 @@ int flacSendChunk(FlacData * data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__FileDecoder *dec, const FLAC__Frame *frame, const FLAC__int32 * const buf[], void * vdata) {
|
||||
FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecoder *dec,
|
||||
const FLAC__Frame *frame, const FLAC__int32 * const buf[],
|
||||
void * vdata)
|
||||
{
|
||||
FlacData * data = (FlacData *)vdata;
|
||||
FLAC__uint32 samples = frame->header.blocksize;
|
||||
FLAC__uint16 u16;
|
||||
@ -216,7 +319,7 @@ FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__FileDecoder *dec, const FLA
|
||||
timeChange = ((float)samples)/frame->header.sample_rate;
|
||||
data->time+= timeChange;
|
||||
|
||||
FLAC__file_decoder_get_decode_position(dec,&newPosition);
|
||||
FLAC__seekable_stream_decoder_get_decode_position(dec,&newPosition);
|
||||
if(data->position) {
|
||||
data->bitRate = ((newPosition-data->position)*8.0/timeChange)
|
||||
/1000+0.5;
|
||||
|
@ -71,3 +71,7 @@ int closeInputStream(InputStream * inStream) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inputStreamAtEOF(InputStream * inStream) {
|
||||
return feof(inStream->fp);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ typedef struct _InputStream {
|
||||
int openInputStreamFromFile(InputStream * inStream, char * filename);
|
||||
int seekInputStream(InputStream * inStream, long offset, int whence);
|
||||
int closeInputStream(InputStream * inStream);
|
||||
int inputStreamAtEOF(InputStream * inStream);
|
||||
|
||||
size_t readFromInputStream(InputStream * inStream, void * ptr, size_t size,
|
||||
size_t nmemb);
|
||||
|
Loading…
Reference in New Issue
Block a user