movies: support looping compressed .wav files

Any kind of skipping is supported on any kind of stream, actually, but some uses may require reopening the file and skipping some number of bytes, so a warning will be displayed in some cases.

I figure this feature is particularly interesting for .wav files since they are (1) often used for short samples, where skipping bytes is not really a big deal, and (2) aren't inherently compressed so would benefit particularly from zlib compression.
This commit is contained in:
rdb 2019-04-29 10:48:04 +02:00
parent 00b5faca2d
commit a726592244
2 changed files with 43 additions and 9 deletions

View File

@ -202,8 +202,8 @@ seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
gbump(n);
_source->seekg(0, ios::beg);
if (_source->tellg() == (streampos)0) {
if (_source->rdbuf()->pubseekpos(0, ios::in) == (streampos)0) {
_source->clear();
_z_source.next_in = Z_NULL;
_z_source.avail_in = 0;
_z_source.next_out = Z_NULL;

View File

@ -294,27 +294,61 @@ seek(double t) {
t = std::max(t, 0.0);
std::streampos pos = _data_start + (std::streampos) std::min((size_t) (t * _byte_rate), _data_size);
std::streambuf *buf = _stream->rdbuf();
if (_can_seek_fast) {
_stream->seekg(pos);
if (_stream->tellg() != pos) {
if (buf->pubseekpos(pos, std::ios::in) != pos) {
// Clearly, we can't seek fast. Fall back to the case below.
_can_seek_fast = false;
}
}
if (!_can_seek_fast) {
std::streampos current = _stream->tellg();
// Get the current position of the cursor in the file.
std::streampos current = buf->pubseekoff(0, std::ios::cur, std::ios::in);
if (!_can_seek_fast) {
if (pos > current) {
// It is ahead of our current position. Skip ahead.
_reader.skip_bytes(pos - current);
_stream->ignore(pos - current);
current = pos;
} else if (pos < current) {
// We'll have to reopen the file. TODO
// Can we seek to the beginning? Some streams, such as ZStream, let us
// rewind the stream.
if (buf->pubseekpos(0, std::ios::in) == 0) {
if (pos > _data_start && movies_cat.is_info()) {
Filename fn = get_source()->get_filename();
movies_cat.info()
<< "Unable to seek backwards in " << fn.get_basename()
<< "; seeking to beginning and skipping " << pos << " bytes.\n";
}
_stream->ignore(pos);
current = pos;
} else {
// No; close and reopen the file.
Filename fn = get_source()->get_filename();
movies_cat.warning()
<< "Unable to seek backwards in " << fn.get_basename()
<< "; reopening and skipping " << pos << " bytes.\n";
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
std::istream *stream = vfs->open_read_file(get_source()->get_filename(), true);
if (stream != nullptr) {
vfs->close_read_file(_stream);
stream->ignore(pos);
_stream = stream;
_reader = StreamReader(stream, false);
current = pos;
} else {
movies_cat.error()
<< "Unable to reopen " << fn << ".\n";
_can_seek = false;
}
}
}
}
_data_pos = _stream->tellg() - _data_start;
_data_pos = (size_t)current - _data_start;
_last_seek = _data_pos / _byte_rate;
_samples_read = 0;
}