Revamed the Ogg Vorbis & FLAC DigitalTrackInfo subclasses to work similar to the MP3 one (i.e. only open the data file when about to play)

svn-id: r25757
This commit is contained in:
Max Horn 2007-02-20 23:40:46 +00:00
parent 42745b188e
commit cb40356a7b
3 changed files with 153 additions and 168 deletions

View File

@ -874,41 +874,57 @@ void FlacInputStream::callWrapError(const ::FLAC__SeekableStreamDecoder *decoder
class FlacTrackInfo : public DigitalTrackInfo {
private:
File *_file;
FlacInputStream *_firstStream; // avoid having to open the Stream twice the first time
Common::String _filename;
bool _errorFlag;
public:
FlacTrackInfo(File *file);
~FlacTrackInfo();
bool error() { return _file == NULL; }
FlacTrackInfo(const char *filename);
bool error() { return _errorFlag; }
void play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration);
};
FlacTrackInfo::FlacTrackInfo(File *file) : _file(NULL), _firstStream(NULL) {
FlacInputStream *tempStream = new FlacInputStream(file);
/* first time the file will be tested, but not used */
if (tempStream->init()) {
_firstStream = tempStream;
_file = file;
} else
delete tempStream;
FlacTrackInfo::FlacTrackInfo(const char *filename) :
_filename(filename),
_errorFlag(false) {
// Try to open the file
Common::File file;
if (!file.open(_filename)) {
_errorFlag = true;
return;
}
// Next, try to create a FlacInputStream from it
FlacInputStream *tempStream = new FlacInputStream(&file);
// If initialising the stream fails, we set the error flag
if (!tempStream || !tempStream->init())
_errorFlag = true;
delete tempStream;
}
void FlacTrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration) {
assert(!_errorFlag);
if (error()) {
debug(1, "FlacTrackInfo::play: invalid state, method should not been called");
}
FlacInputStream *flac;
if (_firstStream != NULL) {
flac = _firstStream;
_firstStream = NULL;
} else {
flac = new FlacInputStream(_file);
flac->init();
// Open the file
Common::File *file = new Common::File();
if (!file || !file->open(_filename)) {
warning("FlacTrackInfo::play: failed to open '%s'", _filename.c_str());
delete file;
return;
}
// Create an AudioStream from the file
FlacInputStream *flac = new FlacInputStream(file);
flac->init();
file->decRef();
// Seek to the correct start position and start playback
if (flac->isStreamDecoderReady()) {
const FLAC__StreamMetadata_StreamInfo &info = flac->getStreamInfo();
if (duration)
@ -921,38 +937,30 @@ void FlacTrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int st
return;
}
// startSample is beyond the existing Samples
debug(1, "FlacTrackInfo: Audiostream %s could not seek to frame %d (ca %d secs)", _file->name(), startFrame, startFrame/75);
debug(1, "FlacTrackInfo: Audiostream %s could not seek to frame %d (ca %d secs)", _filename.c_str(), startFrame, startFrame/75);
flac->finish();
}
delete flac;
}
FlacTrackInfo::~FlacTrackInfo() {
delete _firstStream;
delete _file;
}
DigitalTrackInfo* getFlacTrack(int track) {
assert(track >= 1);
char trackName[4][32];
File *file = new File();
sprintf(trackName[0], "track%d.flac", track);
sprintf(trackName[1], "track%02d.flac", track);
sprintf(trackName[2], "track%d.fla", track);
sprintf(trackName[3], "track%02d.fla", track);
for (int i = 0; i < 4; ++i) {
if (file->open(trackName[i])) {
FlacTrackInfo *trackInfo = new FlacTrackInfo(file);
if (Common::File::exists(trackName[i])) {
FlacTrackInfo *trackInfo = new FlacTrackInfo(trackName[i]);
if (!trackInfo->error())
return trackInfo;
delete trackInfo;
}
}
delete file;
return NULL;
}

View File

@ -167,7 +167,7 @@ void MP3InputStream::decodeMP3Data() {
if (_stream.error == MAD_ERROR_BUFLEN) {
break; // Read more data
} else if (MAD_RECOVERABLE(_stream.error)) {
debug(1, "MP3InputStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
debug(6, "MP3InputStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
continue;
} else {
warning("MP3InputStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
@ -193,8 +193,10 @@ void MP3InputStream::decodeMP3Data() {
if (_stream.error == MAD_ERROR_BUFLEN) {
break; // Read more data
} else if (MAD_RECOVERABLE(_stream.error)) {
// FIXME: should we do anything here?
debug(1, "MP3InputStream: Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
// Note: we will occasionally see MAD_ERROR_BADDATAPTR errors here.
// These are normal and expected (caused by our frame skipping (i.e. "seeking")
// code above).
debug(6, "MP3InputStream: Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
continue;
} else {
warning("MP3InputStream: Unrecoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
@ -351,27 +353,27 @@ MP3TrackInfo::MP3TrackInfo(const char *filename) :
_filename(filename),
_errorFlag(false) {
Common::File file;
// Try to open the file
Common::File file;
if (!file.open(_filename)) {
_errorFlag = true;
return;
}
// Next, try to create a MP3InputStream from it
MP3InputStream *mp3Stream = new MP3InputStream(&file, false);
// Next, try to create an MP3InputStream from it
MP3InputStream *tempStream = new MP3InputStream(&file, false);
// If we see EOS here then that means that not (enough) valid input
// data was given.
_errorFlag = mp3Stream->endOfData();
_errorFlag = tempStream->endOfData();
// Clean up again
delete mp3Stream;
delete tempStream;
}
void MP3TrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration) {
assert(!_errorFlag);
mad_timer_t start;
mad_timer_t end;
@ -389,12 +391,14 @@ void MP3TrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int sta
Common::File *file = new Common::File();
if (!file || !file->open(_filename)) {
warning("MP3TrackInfo::play: failed to open '%s'", _filename.c_str());
delete file;
return;
}
// Play it
// ... create an AudioStream ...
MP3InputStream *input = new MP3InputStream(file, true, start, end);
// ... and play it
mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input);
}

View File

@ -46,8 +46,6 @@ using Common::File;
namespace Audio {
static AudioStream *makeVorbisStream(OggVorbis_File *file, int duration);
// These are wrapper functions to allow using a File object to
// provide data to the OggVorbis_File object.
@ -129,8 +127,9 @@ static int seek_wrap(void *datasource, ogg_int64_t offset, int whence) {
static int close_wrap(void *datasource) {
file_info *f = (file_info *) datasource;
f->file->decRef();
delete f->file;
delete f;
return 0;
}
@ -145,123 +144,6 @@ static ov_callbacks g_File_wrap = {
};
#pragma mark -
#pragma mark --- Ogg Vorbis Audio CD emulation ---
#pragma mark -
class VorbisTrackInfo : public DigitalTrackInfo {
private:
File *_file;
OggVorbis_File _ov_file;
bool _error_flag;
public:
VorbisTrackInfo(File *file);
~VorbisTrackInfo();
bool openTrack();
bool error() { return _error_flag; }
void play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration);
};
VorbisTrackInfo::VorbisTrackInfo(File *file) {
//debug(5, "" __FILE__ ":%i", __LINE__);
_file = file;
if (openTrack()) {
warning("Invalid file format");
_error_flag = true;
_file = 0;
} else {
_error_flag = false;
_file->incRef();
ov_clear(&_ov_file);
}
}
bool VorbisTrackInfo::openTrack() {
//debug(5, "" __FILE__ ":%i", __LINE__);
assert(_file);
file_info *f = new file_info;
#if defined(__SYMBIAN32__)
// Symbian can't share filehandles between different threads.
// So create a new file and seek that to the other filehandles position
f->file = new File;
f->file->open(_file->name());
f->file->seek(_file->pos());
#else
f->file = _file;
#endif
f->start = 0;
f->len = _file->size();
f->curr_pos = 0;
_file->seek(0);
bool err = (ov_open_callbacks((void *) f, &_ov_file, NULL, 0, g_File_wrap) < 0);
if (err) {
#ifdef __SYMBIAN32__
delete f->file;
#endif
delete f;
} else {
#ifndef __SYMBIAN32__
_file->incRef();
#endif
}
return err;
}
VorbisTrackInfo::~VorbisTrackInfo() {
//debug(5, "" __FILE__ ":%i", __LINE__);
if (! _error_flag) {
ov_clear(&_ov_file);
_file->decRef();
}
}
void VorbisTrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration) {
//debug(5, "" __FILE__ ":%i", __LINE__);
bool err = openTrack(); err=err;//satisfy unused variable
assert(!err);
#ifdef USE_TREMOR // In Tremor, the ov_time_seek() and ov_time_seek_page() calls take seeking positions in milliseconds as 64 bit integers, rather than in seconds as doubles as in Vorbisfile.
#if defined(__SYMBIAN32__) && defined(__GCC32__) // SumthinWicked says: fixing "relocation truncated to fit: ARM_26 __fixdfdi" during linking on GCC, see portdefs.h
ov_time_seek(&_ov_file, (ogg_int64_t)scumm_fixdfdi(startFrame / 75.0 * 1000));
#else
ov_time_seek(&_ov_file, (ogg_int64_t)(startFrame / 75.0 * 1000));
#endif
#else
ov_time_seek(&_ov_file, startFrame / 75.0);
#endif
AudioStream *input = makeVorbisStream(&_ov_file, duration * ov_info(&_ov_file, -1)->rate / 75);
mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input);
}
DigitalTrackInfo *getVorbisTrack(int track) {
char trackName[2][32];
File *file = new File();
sprintf(trackName[0], "track%d.ogg", track);
sprintf(trackName[1], "track%02d.ogg", track);
for (int i = 0; i < 2; ++i) {
if (file->open(trackName[i])) {
VorbisTrackInfo *trackInfo = new VorbisTrackInfo(file);
file->decRef();
if (!trackInfo->error())
return trackInfo;
delete trackInfo;
}
}
delete file;
return NULL;
}
#pragma mark -
#pragma mark --- Ogg Vorbis stream ---
#pragma mark -
@ -376,11 +258,6 @@ void VorbisInputStream::refill() {
_bufferEnd = (int16 *)read_pos;
}
static AudioStream *makeVorbisStream(OggVorbis_File *file, int duration) {
//debug(5, "" __FILE__ ":%i", __LINE__);
return new VorbisInputStream(file, duration, false);
}
AudioStream *makeVorbisStream(File *file, uint32 size) {
//debug(5, "" __FILE__ ":%i", __LINE__);
OggVorbis_File *ov_file = new OggVorbis_File;
@ -413,6 +290,102 @@ AudioStream *makeVorbisStream(File *file, uint32 size) {
}
#pragma mark -
#pragma mark --- Ogg Vorbis Audio CD emulation ---
#pragma mark -
class VorbisTrackInfo : public DigitalTrackInfo {
private:
Common::String _filename;
bool _errorFlag;
public:
VorbisTrackInfo(const char *filename);
bool openTrack(OggVorbis_File *ovFile);
bool error() { return _errorFlag; }
void play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration);
};
VorbisTrackInfo::VorbisTrackInfo(const char *filename) :
_filename(filename),
_errorFlag(false) {
OggVorbis_File ov_file;
_errorFlag = openTrack(&ov_file);
if (!_errorFlag)
ov_clear(&ov_file);
}
bool VorbisTrackInfo::openTrack(OggVorbis_File *ovFile) {
bool err;
file_info *f = new file_info;
assert(f);
f->file = new File;
assert(f->file);
err = !f->file->open(_filename);
if (!err) {
f->start = 0;
f->len = f->file->size();
f->curr_pos = 0;
err = (ov_open_callbacks((void *) f, ovFile, NULL, 0, g_File_wrap) < 0);
}
if (err) {
delete f->file;
delete f;
}
return err;
}
void VorbisTrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration) {
OggVorbis_File *ovFile = new OggVorbis_File;
bool err = openTrack(ovFile);
assert(!err);
#ifdef USE_TREMOR
// In Tremor, the ov_time_seek() and ov_time_seek_page() calls take seeking
// positions in milliseconds as 64 bit integers, rather than in seconds as
// doubles as in Vorbisfile.
#if defined(__SYMBIAN32__) && defined(__GCC32__)
// SumthinWicked says: fixing "relocation truncated to fit: ARM_26 __fixdfdi" during linking on GCC, see portdefs.h
ov_time_seek(ovFile, (ogg_int64_t)scumm_fixdfdi(startFrame / 75.0 * 1000));
#else
ov_time_seek(ovFile, (ogg_int64_t)(startFrame / 75.0 * 1000));
#endif
#else
ov_time_seek(ovFile, startFrame / 75.0);
#endif
AudioStream *input = new VorbisInputStream(ovFile, duration * ov_info(ovFile, -1)->rate / 75, true);
mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input);
}
DigitalTrackInfo *getVorbisTrack(int track) {
char trackName[2][32];
sprintf(trackName[0], "track%d.ogg", track);
sprintf(trackName[1], "track%02d.ogg", track);
for (int i = 0; i < 2; ++i) {
if (Common::File::exists(trackName[i])) {
VorbisTrackInfo *trackInfo = new VorbisTrackInfo(trackName[i]);
if (!trackInfo->error())
return trackInfo;
delete trackInfo;
}
}
return NULL;
}
} // End of namespace Audio
#endif // #ifdef USE_VORBIS