Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Müller <nexyon@gmail.com>2021-08-30 23:36:02 +0300
committerJörg Müller <nexyon@gmail.com>2021-09-18 22:45:33 +0300
commitbdbc7e12a02e15ad7265dfc1ac21fb6d0016308f (patch)
treee9b967deb25f77eef348786f5cd22524eef0ec20 /extern/audaspace/plugins
parent970c928f27106b26ec7cf6afa2316c60384ab4f1 (diff)
Audaspace: added audio file streams functionality.
On the blender side this commit fixes importing video files with audio and video streams that do not share the same start time and duration. Differential Revision: https://developer.blender.org/D12353
Diffstat (limited to 'extern/audaspace/plugins')
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEG.cpp18
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEG.h6
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp169
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGReader.h42
-rw-r--r--extern/audaspace/plugins/libsndfile/SndFile.cpp14
-rw-r--r--extern/audaspace/plugins/libsndfile/SndFile.h6
-rw-r--r--extern/audaspace/plugins/libsndfile/SndFileReader.cpp15
-rw-r--r--extern/audaspace/plugins/libsndfile/SndFileReader.h12
8 files changed, 191 insertions, 91 deletions
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
index 3ffe963b2b9..07c0fee691a 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
@@ -35,14 +35,24 @@ void FFMPEG::registerPlugin()
FileManager::registerOutput(plugin);
}
-std::shared_ptr<IReader> FFMPEG::createReader(std::string filename)
+std::shared_ptr<IReader> FFMPEG::createReader(std::string filename, int stream)
{
- return std::shared_ptr<IReader>(new FFMPEGReader(filename));
+ return std::shared_ptr<IReader>(new FFMPEGReader(filename, stream));
}
-std::shared_ptr<IReader> FFMPEG::createReader(std::shared_ptr<Buffer> buffer)
+std::shared_ptr<IReader> FFMPEG::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
- return std::shared_ptr<IReader>(new FFMPEGReader(buffer));
+ return std::shared_ptr<IReader>(new FFMPEGReader(buffer, stream));
+}
+
+std::vector<StreamInfo> FFMPEG::queryStreams(std::string filename)
+{
+ return FFMPEGReader(filename).queryStreams();
+}
+
+std::vector<StreamInfo> FFMPEG::queryStreams(std::shared_ptr<Buffer> buffer)
+{
+ return FFMPEGReader(buffer).queryStreams();
}
std::shared_ptr<IWriter> FFMPEG::createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEG.h b/extern/audaspace/plugins/ffmpeg/FFMPEG.h
index 108ba547e0f..fb40ba05573 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEG.h
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEG.h
@@ -52,8 +52,10 @@ public:
*/
static void registerPlugin();
- virtual std::shared_ptr<IReader> createReader(std::string filename);
- virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
+ virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
+ virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
+ virtual std::vector<StreamInfo> queryStreams(std::string filename);
+ virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
virtual std::shared_ptr<IWriter> createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate);
};
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
index afdc7fcfcc6..de3ca099696 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
@@ -31,6 +31,25 @@ AUD_NAMESPACE_BEGIN
#define FFMPEG_OLD_CODE
#endif
+SampleFormat FFMPEGReader::convertSampleFormat(AVSampleFormat format)
+{
+ switch(av_get_packed_sample_fmt(format))
+ {
+ case AV_SAMPLE_FMT_U8:
+ return FORMAT_U8;
+ case AV_SAMPLE_FMT_S16:
+ return FORMAT_S16;
+ case AV_SAMPLE_FMT_S32:
+ return FORMAT_S32;
+ case AV_SAMPLE_FMT_FLT:
+ return FORMAT_FLOAT32;
+ case AV_SAMPLE_FMT_DBL:
+ return FORMAT_FLOAT64;
+ default:
+ AUD_THROW(FileException, "FFMPEG sample format unknown.");
+ }
+}
+
int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
{
int buf_size = buffer.getSize();
@@ -68,7 +87,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
- m_frame->data[channel] + i * single_size, single_size);
+ m_frame->data[channel] + i * single_size, single_size);
}
}
}
@@ -109,7 +128,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
- m_frame->data[channel] + i * single_size, single_size);
+ m_frame->data[channel] + i * single_size, single_size);
}
}
}
@@ -123,13 +142,10 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
return buf_pos;
}
-void FFMPEGReader::init()
+void FFMPEGReader::init(int stream)
{
m_position = 0;
- m_start_offset = 0.0f;
m_pkgbuf_left = 0;
- m_st_time = 0;
- m_duration = 0;
if(avformat_find_stream_info(m_formatCtx, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be read, ffmpeg couldn't find the stream info.");
@@ -137,43 +153,22 @@ void FFMPEGReader::init()
// find audio stream and codec
m_stream = -1;
- double dur_sec = 0;
-
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
{
#ifdef FFMPEG_OLD_CODE
- if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
#else
- if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+ if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
#endif
+ && (m_stream < 0))
{
- AVStream *audio_stream = m_formatCtx->streams[i];
- double audio_timebase = av_q2d(audio_stream->time_base);
-
- if (audio_stream->start_time != AV_NOPTS_VALUE)
+ if(stream == 0)
{
- m_st_time = audio_stream->start_time;
- }
-
- int64_t ctx_start_time = 0;
- if (m_formatCtx->start_time != AV_NOPTS_VALUE) {
- ctx_start_time = m_formatCtx->start_time;
- }
-
- m_start_offset = m_st_time * audio_timebase - (double)ctx_start_time / AV_TIME_BASE;
-
- if(audio_stream->duration != AV_NOPTS_VALUE)
- {
- dur_sec = audio_stream->duration * audio_timebase;
+ m_stream=i;
+ break;
}
else
- {
- /* If the audio starts after the stream start time, subract this from the total duration. */
- dur_sec = (double)m_formatCtx->duration / AV_TIME_BASE - m_start_offset;
- }
-
- m_stream=i;
- break;
+ stream--;
}
}
@@ -242,10 +237,9 @@ void FFMPEGReader::init()
}
m_specs.rate = (SampleRate) m_codecCtx->sample_rate;
- m_duration = lround(dur_sec * m_codecCtx->sample_rate);
}
-FFMPEGReader::FFMPEGReader(std::string filename) :
+FFMPEGReader::FFMPEGReader(std::string filename, int stream) :
m_pkgbuf(),
m_formatCtx(nullptr),
m_codecCtx(nullptr),
@@ -259,7 +253,7 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
try
{
- init();
+ init(stream);
}
catch(Exception&)
{
@@ -268,7 +262,7 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
}
}
-FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
+FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer, int stream) :
m_pkgbuf(),
m_codecCtx(nullptr),
m_frame(nullptr),
@@ -295,7 +289,7 @@ FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
try
{
- init();
+ init(stream);
}
catch(Exception&)
{
@@ -318,6 +312,51 @@ FFMPEGReader::~FFMPEGReader()
avformat_close_input(&m_formatCtx);
}
+std::vector<StreamInfo> FFMPEGReader::queryStreams()
+{
+ std::vector<StreamInfo> result;
+
+ for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
+ {
+#ifdef FFMPEG_OLD_CODE
+ if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+#else
+ if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+#endif
+ {
+ StreamInfo info;
+
+ double time_base = av_q2d(m_formatCtx->streams[i]->time_base);
+
+ if(m_formatCtx->streams[i]->start_time != AV_NOPTS_VALUE)
+ info.start = m_formatCtx->streams[i]->start_time * time_base;
+ else
+ info.start = 0;
+
+ if(m_formatCtx->streams[i]->duration != AV_NOPTS_VALUE)
+ info.duration = m_formatCtx->streams[i]->duration * time_base;
+ else if(m_formatCtx->duration != AV_NOPTS_VALUE)
+ info.duration = double(m_formatCtx->duration) / AV_TIME_BASE - info.start;
+ else
+ info.duration = 0;
+
+#ifdef FFMPEG_OLD_CODE
+ info.specs.channels = Channels(m_formatCtx->streams[i]->codec->channels);
+ info.specs.rate = m_formatCtx->streams[i]->codec->sample_rate;
+ info.specs.format = convertSampleFormat(m_formatCtx->streams[i]->codec->sample_fmt);
+#else
+ info.specs.channels = Channels(m_formatCtx->streams[i]->codecpar->channels);
+ info.specs.rate = m_formatCtx->streams[i]->codecpar->sample_rate;
+ info.specs.format = convertSampleFormat(AVSampleFormat(m_formatCtx->streams[i]->codecpar->format));
+#endif
+
+ result.emplace_back(info);
+ }
+ }
+
+ return result;
+}
+
int FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size)
{
FFMPEGReader* reader = reinterpret_cast<FFMPEGReader*>(opaque);
@@ -368,18 +407,16 @@ void FFMPEGReader::seek(int position)
{
if(position >= 0)
{
- double pts_time_base =
- av_q2d(m_formatCtx->streams[m_stream]->time_base);
+ double pts_time_base = av_q2d(m_formatCtx->streams[m_stream]->time_base);
- uint64_t seek_pts = (((uint64_t)position) / ((uint64_t)m_specs.rate)) / pts_time_base;
+ uint64_t st_time = m_formatCtx->streams[m_stream]->start_time;
+ uint64_t seek_pos = (uint64_t)(position / (pts_time_base * m_specs.rate));
- if(m_st_time != AV_NOPTS_VALUE) {
- seek_pts += m_st_time;
- }
+ if(st_time != AV_NOPTS_VALUE)
+ seek_pos += st_time;
// a value < 0 tells us that seeking failed
- if(av_seek_frame(m_formatCtx, m_stream, seek_pts,
- AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
+ if(av_seek_frame(m_formatCtx, m_stream, seek_pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
{
avcodec_flush_buffers(m_codecCtx);
m_position = position;
@@ -400,7 +437,7 @@ void FFMPEGReader::seek(int position)
if(packet.pts != AV_NOPTS_VALUE)
{
// calculate real position, and read to frame!
- m_position = (packet.pts - m_st_time) * pts_time_base * m_specs.rate;
+ m_position = (packet.pts - (st_time != AV_NOPTS_VALUE ? st_time : 0)) * pts_time_base * m_specs.rate;
if(m_position < position)
{
@@ -430,8 +467,25 @@ void FFMPEGReader::seek(int position)
int FFMPEGReader::getLength() const
{
+ auto stream = m_formatCtx->streams[m_stream];
+
+ double time_base = av_q2d(stream->time_base);
+ double duration;
+
+ if(stream->duration != AV_NOPTS_VALUE)
+ duration = stream->duration * time_base;
+ else if(m_formatCtx->duration != AV_NOPTS_VALUE)
+ {
+ duration = float(m_formatCtx->duration) / AV_TIME_BASE;
+
+ if(stream->start_time != AV_NOPTS_VALUE)
+ duration -= stream->start_time * time_base;
+ }
+ else
+ duration = -1;
+
// return approximated remaning size
- return m_duration - m_position;
+ return (int)(duration * m_codecCtx->sample_rate) - m_position;
}
int FFMPEGReader::getPosition() const
@@ -439,11 +493,6 @@ int FFMPEGReader::getPosition() const
return m_position;
}
-double FFMPEGReader::getStartOffset() const
-{
- return m_start_offset;
-}
-
Specs FFMPEGReader::getSpecs() const
{
return m_specs.specs;
@@ -480,13 +529,11 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
// decode the package
pkgbuf_pos = decode(packet, m_pkgbuf);
- if (packet.pts >= m_st_time) {
- // copy to output buffer
- data_size = std::min(pkgbuf_pos, left * sample_size);
- m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
- buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
- left -= data_size / sample_size;
- }
+ // copy to output buffer
+ data_size = std::min(pkgbuf_pos, left * sample_size);
+ m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
+ buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
+ left -= data_size / sample_size;
}
av_packet_unref(&packet);
}
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
index d613457c220..70f13911eca 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
@@ -29,9 +29,11 @@
#include "respec/ConverterFunctions.h"
#include "IReader.h"
#include "util/Buffer.h"
+#include "file/FileInfo.h"
#include <string>
#include <memory>
+#include <vector>
struct AVCodecContext;
extern "C" {
@@ -55,22 +57,6 @@ private:
int m_position;
/**
- * The start offset in seconds relative to the media container start time.
- * IE how much the sound should be delayed to be kept in sync with the rest of the containter streams.
- */
- double m_start_offset;
-
- /**
- * The start time pts of the stream. All packets before this timestamp shouldn't be played back (only decoded).
- */
- int64_t m_st_time;
-
- /**
- * The duration of the audio stream in samples.
- */
- int64_t m_duration;
-
- /**
* The specification of the audio data.
*/
DeviceSpecs m_specs;
@@ -136,6 +122,13 @@ private:
bool m_tointerleave;
/**
+ * Converts an ffmpeg sample format to an audaspace one.
+ * \param format The AVSampleFormat sample format.
+ * \return The sample format as SampleFormat.
+ */
+ AUD_LOCAL static SampleFormat convertSampleFormat(AVSampleFormat format);
+
+ /**
* Decodes a packet into the given buffer.
* \param packet The AVPacket to decode.
* \param buffer The target buffer.
@@ -145,8 +138,9 @@ private:
/**
* Initializes the object.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
*/
- AUD_LOCAL void init();
+ AUD_LOCAL void init(int stream);
// delete copy constructor and operator=
FFMPEGReader(const FFMPEGReader&) = delete;
@@ -156,18 +150,20 @@ public:
/**
* Creates a new reader.
* \param filename The path to the file to be read.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the file specified does not exist or
* cannot be read with ffmpeg.
*/
- FFMPEGReader(std::string filename);
+ FFMPEGReader(std::string filename, int stream = 0);
/**
* Creates a new reader.
* \param buffer The buffer to read from.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the buffer specified cannot be read
* with ffmpeg.
*/
- FFMPEGReader(std::shared_ptr<Buffer> buffer);
+ FFMPEGReader(std::shared_ptr<Buffer> buffer, int stream = 0);
/**
* Destroys the reader and closes the file.
@@ -175,6 +171,13 @@ public:
virtual ~FFMPEGReader();
/**
+ * Queries the streams of a sound file.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
+ */
+ virtual std::vector<StreamInfo> queryStreams();
+
+ /**
* Reads data to a memory buffer.
* This function is used for avio only.
* @param opaque The FFMPEGReader.
@@ -198,7 +201,6 @@ public:
virtual void seek(int position);
virtual int getLength() const;
virtual int getPosition() const;
- virtual double getStartOffset() const;
virtual Specs getSpecs() const;
virtual void read(int& length, bool& eos, sample_t* buffer);
};
diff --git a/extern/audaspace/plugins/libsndfile/SndFile.cpp b/extern/audaspace/plugins/libsndfile/SndFile.cpp
index ba4ff24ad68..39335de9a1a 100644
--- a/extern/audaspace/plugins/libsndfile/SndFile.cpp
+++ b/extern/audaspace/plugins/libsndfile/SndFile.cpp
@@ -32,16 +32,26 @@ void SndFile::registerPlugin()
FileManager::registerOutput(plugin);
}
-std::shared_ptr<IReader> SndFile::createReader(std::string filename)
+std::shared_ptr<IReader> SndFile::createReader(std::string filename, int stream)
{
return std::shared_ptr<IReader>(new SndFileReader(filename));
}
-std::shared_ptr<IReader> SndFile::createReader(std::shared_ptr<Buffer> buffer)
+std::shared_ptr<IReader> SndFile::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
return std::shared_ptr<IReader>(new SndFileReader(buffer));
}
+std::vector<StreamInfo> SndFile::queryStreams(std::string filename)
+{
+ return SndFileReader(filename).queryStreams();
+}
+
+std::vector<StreamInfo> SndFile::queryStreams(std::shared_ptr<Buffer> buffer)
+{
+ return SndFileReader(buffer).queryStreams();
+}
+
std::shared_ptr<IWriter> SndFile::createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
{
return std::shared_ptr<IWriter>(new SndFileWriter(filename, specs, format, codec, bitrate));
diff --git a/extern/audaspace/plugins/libsndfile/SndFile.h b/extern/audaspace/plugins/libsndfile/SndFile.h
index 61afed1d564..10a7391180f 100644
--- a/extern/audaspace/plugins/libsndfile/SndFile.h
+++ b/extern/audaspace/plugins/libsndfile/SndFile.h
@@ -52,8 +52,10 @@ public:
*/
static void registerPlugin();
- virtual std::shared_ptr<IReader> createReader(std::string filename);
- virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
+ virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
+ virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
+ virtual std::vector<StreamInfo> queryStreams(std::string filename);
+ virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
virtual std::shared_ptr<IWriter> createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate);
};
diff --git a/extern/audaspace/plugins/libsndfile/SndFileReader.cpp b/extern/audaspace/plugins/libsndfile/SndFileReader.cpp
index d2d89814c07..21c733d8117 100644
--- a/extern/audaspace/plugins/libsndfile/SndFileReader.cpp
+++ b/extern/audaspace/plugins/libsndfile/SndFileReader.cpp
@@ -118,6 +118,21 @@ SndFileReader::~SndFileReader()
sf_close(m_sndfile);
}
+std::vector<StreamInfo> SndFileReader::queryStreams()
+{
+ std::vector<StreamInfo> result;
+
+ StreamInfo info;
+ info.start = 0;
+ info.duration = double(getLength()) / m_specs.rate;
+ info.specs.specs = m_specs;
+ info.specs.format = FORMAT_FLOAT32;
+
+ result.emplace_back(info);
+
+ return result;
+}
+
bool SndFileReader::isSeekable() const
{
return m_seekable;
diff --git a/extern/audaspace/plugins/libsndfile/SndFileReader.h b/extern/audaspace/plugins/libsndfile/SndFileReader.h
index 081c29c686c..b4158d9091a 100644
--- a/extern/audaspace/plugins/libsndfile/SndFileReader.h
+++ b/extern/audaspace/plugins/libsndfile/SndFileReader.h
@@ -28,9 +28,12 @@
* The SndFileReader class.
*/
+#include "file/FileInfo.h"
+
#include <string>
#include <sndfile.h>
#include <memory>
+#include <vector>
AUD_NAMESPACE_BEGIN
@@ -96,6 +99,7 @@ public:
/**
* Creates a new reader.
* \param filename The path to the file to be read.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the file specified does not exist or
* cannot be read with libsndfile.
*/
@@ -104,6 +108,7 @@ public:
/**
* Creates a new reader.
* \param buffer The buffer to read from.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the buffer specified cannot be read
* with libsndfile.
*/
@@ -114,6 +119,13 @@ public:
*/
virtual ~SndFileReader();
+ /**
+ * Queries the streams of a sound file.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
+ */
+ virtual std::vector<StreamInfo> queryStreams();
+
virtual bool isSeekable() const;
virtual void seek(int position);
virtual int getLength() const;