Factor out bounds-checking for GetAudio to a single place

It was being done in inconsistent ways in several places, which did not
include all of the places it needed to be done.

Closes #1509.

Originally committed to SVN as r6960.
This commit is contained in:
Thomas Goyne 2012-08-18 03:13:44 +00:00
parent 037d385419
commit 79684d5ad6
17 changed files with 76 additions and 179 deletions

View File

@ -88,6 +88,44 @@ void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count,
} }
} }
void AudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
if (start+count > num_samples) {
int64_t oldcount = count;
count = num_samples-start;
if (count < 0) count = 0;
// Fill beyond with zero
if (bytes_per_sample == 1) {
char *temp = (char *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
if (bytes_per_sample == 2) {
short *temp = (short *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
}
if (start + count > num_samples) {
int64_t zero_count = std::min(count, start + count - num_samples);
count -= zero_count;
char *zero_buf = static_cast<char *>(buf) + count * bytes_per_sample * channels;
if (bytes_per_sample == 1)
// 8 bit formats are usually unsigned with bias 127
memset(zero_buf, 127, zero_count * channels);
else
// While everything else is signed
memset(zero_buf, 0, zero_count * bytes_per_sample * channels);
}
if (count > 0)
FillBuffer(buf, start, count);
}
AudioProvider *AudioProviderFactory::GetProvider(wxString const& filename, int cache) { AudioProvider *AudioProviderFactory::GetProvider(wxString const& filename, int cache) {
AudioProvider *provider = 0; AudioProvider *provider = 0;
bool found_file = false; bool found_file = false;

View File

@ -151,35 +151,7 @@ void AvisynthAudioProvider::LoadFromClip(AVSValue _clip) {
clip = tempclip; clip = tempclip;
} }
/// @brief Get audio void AvisynthAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
/// @param buf clip->GetAudio(buf,start,count,avs_wrapper.GetEnv());
/// @param start
/// @param count
///
void AvisynthAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
// Requested beyond the length of audio
if (start+count > num_samples) {
int64_t oldcount = count;
count = num_samples-start;
if (count < 0) count = 0;
// Fill beyond with zero
if (bytes_per_sample == 1) {
char *temp = (char *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
if (bytes_per_sample == 2) {
short *temp = (short *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
}
if (count) {
clip->GetAudio(buf,start,count,avs_wrapper.GetEnv());
}
} }
#endif #endif

View File

@ -56,6 +56,7 @@ class AvisynthAudioProvider : public AudioProvider {
PClip clip; PClip clip;
void LoadFromClip(AVSValue clip); void LoadFromClip(AVSValue clip);
void FillBuffer(void *buf, int64_t start, int64_t count) const;
public: public:
AvisynthAudioProvider(wxString _filename); AvisynthAudioProvider(wxString _filename);
@ -64,7 +65,5 @@ public:
bool AreSamplesNativeEndian() const { return true; } bool AreSamplesNativeEndian() const { return true; }
bool NeedsCache() const { return true; } bool NeedsCache() const { return true; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
}; };
#endif #endif

View File

@ -67,7 +67,7 @@ public:
bytes_per_sample = sizeof(Target); bytes_per_sample = sizeof(Target);
} }
void GetAudio(void *buf, int64_t start, int64_t count) const { void FillBuffer(void *buf, int64_t start, int64_t count) const {
std::vector<char> src_buf(count * src_bytes_per_sample * channels); std::vector<char> src_buf(count * src_bytes_per_sample * channels);
source->GetAudio(&src_buf[0], start, count); source->GetAudio(&src_buf[0], start, count);
@ -120,7 +120,7 @@ public:
float_samples = false; float_samples = false;
} }
void GetAudio(void *buf, int64_t start, int64_t count) const { void FillBuffer(void *buf, int64_t start, int64_t count) const {
std::vector<Source> src_buf(count * channels); std::vector<Source> src_buf(count * channels);
source->GetAudio(&src_buf[0], start, count); source->GetAudio(&src_buf[0], start, count);
@ -156,7 +156,7 @@ public:
channels = 1; channels = 1;
} }
void GetAudio(void *buf, int64_t start, int64_t count) const { void FillBuffer(void *buf, int64_t start, int64_t count) const {
if (count == 0) return; if (count == 0) return;
std::vector<int16_t> src_buf(count * src_channels); std::vector<int16_t> src_buf(count * src_channels);
@ -187,7 +187,7 @@ public:
num_samples *= 2; num_samples *= 2;
} }
void GetAudio(void *buf, int64_t start, int64_t count) const { void FillBuffer(void *buf, int64_t start, int64_t count) const {
if (count == 0) return; if (count == 0) return;
int not_end = start + count < num_samples; int not_end = start + count < num_samples;

View File

@ -48,7 +48,7 @@ DummyAudioProvider::DummyAudioProvider(unsigned long dur_ms, bool _noise) {
num_samples = (int64_t)dur_ms * sample_rate / 1000; num_samples = (int64_t)dur_ms * sample_rate / 1000;
} }
void DummyAudioProvider::GetAudio(void *buf, int64_t, int64_t count) const { void DummyAudioProvider::FillBuffer(void *buf, int64_t, int64_t count) const {
short *workbuf = (short*)buf; short *workbuf = (short*)buf;
if (noise) { if (noise) {

View File

@ -44,10 +44,10 @@
class DummyAudioProvider : public AudioProvider { class DummyAudioProvider : public AudioProvider {
/// DOCME /// DOCME
bool noise; bool noise;
void FillBuffer(void *buf, int64_t start, int64_t count) const;
public: public:
DummyAudioProvider(unsigned long dur_ms, bool _noise); DummyAudioProvider(unsigned long dur_ms, bool _noise);
bool AreSamplesNativeEndian() const { return true; } bool AreSamplesNativeEndian() const { return true; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
}; };

View File

@ -175,7 +175,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
} }
} }
void FFmpegSourceAudioProvider::GetAudio(void *Buf, int64_t Start, int64_t Count) const { void FFmpegSourceAudioProvider::FillBuffer(void *Buf, int64_t Start, int64_t Count) const {
if (FFMS_GetAudio(AudioSource, Buf, Start, Count, &ErrInfo)) { if (FFMS_GetAudio(AudioSource, Buf, Start, Count, &ErrInfo)) {
throw AudioDecodeError(std::string("Failed to get audio samples: ") + ErrInfo.Buffer); throw AudioDecodeError(std::string("Failed to get audio samples: ") + ErrInfo.Buffer);
} }

View File

@ -49,6 +49,7 @@ class FFmpegSourceAudioProvider : public AudioProvider, FFmpegSourceProvider {
mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
void LoadAudio(wxString filename); void LoadAudio(wxString filename);
void FillBuffer(void *buf, int64_t start, int64_t count) const;
public: public:
FFmpegSourceAudioProvider(wxString filename); FFmpegSourceAudioProvider(wxString filename);
@ -58,7 +59,5 @@ public:
/// FFMS always delivers native endian samples. /// FFMS always delivers native endian samples.
bool AreSamplesNativeEndian() const { return true; } bool AreSamplesNativeEndian() const { return true; }
bool NeedsCache() const { return true; } bool NeedsCache() const { return true; }
virtual void GetAudio(void *buf, int64_t start, int64_t count) const;
}; };
#endif #endif

View File

@ -140,7 +140,7 @@ HDAudioProvider::~HDAudioProvider() {
wxRemoveFile(diskCacheFilename); wxRemoveFile(diskCacheFilename);
} }
void HDAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const { void HDAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
cache_provider->GetAudio(buf, start, count); cache_provider->GetAudio(buf, start, count);
} }

View File

@ -64,11 +64,11 @@ class HDAudioProvider : public AudioProvider {
/// @param ps Sink for progress reporting /// @param ps Sink for progress reporting
void FillCache(AudioProvider *src, std::ofstream *file, agi::ProgressSink *ps); void FillCache(AudioProvider *src, std::ofstream *file, agi::ProgressSink *ps);
void FillBuffer(void *buf, int64_t start, int64_t count) const;
public: public:
HDAudioProvider(AudioProvider *source, agi::BackgroundRunner *br); HDAudioProvider(AudioProvider *source, agi::BackgroundRunner *br);
~HDAudioProvider(); ~HDAudioProvider();
bool AreSamplesNativeEndian() const { return true; } bool AreSamplesNativeEndian() const { return true; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
}; };

View File

@ -30,7 +30,7 @@ LockAudioProvider::LockAudioProvider(AudioProvider *source) : source(source) {
float_samples = source->AreSamplesFloat(); float_samples = source->AreSamplesFloat();
} }
void LockAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const { void LockAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
wxMutexLocker lock(mutex); wxMutexLocker lock(mutex);
source->GetAudio(buf, start, count); source->GetAudio(buf, start, count);
} }

View File

@ -30,8 +30,8 @@ class LockAudioProvider : public AudioProvider {
agi::scoped_ptr<const AudioProvider> source; agi::scoped_ptr<const AudioProvider> source;
mutable wxMutex mutex; mutable wxMutex mutex;
void FillBuffer(void *buf, int64_t start, int64_t count) const;
public: public:
LockAudioProvider(AudioProvider *source); LockAudioProvider(AudioProvider *source);
void GetAudio(void *buf, int64_t start, int64_t count) const;
bool AreSamplesNativeEndian() const { return source->AreSamplesNativeEndian(); } bool AreSamplesNativeEndian() const { return source->AreSamplesNativeEndian(); }
}; };

View File

@ -59,10 +59,6 @@
#include "compat.h" #include "compat.h"
#include "utils.h" #include "utils.h"
/// @brief DOCME
/// @param filename
///
PCMAudioProvider::PCMAudioProvider(const wxString &filename) PCMAudioProvider::PCMAudioProvider(const wxString &filename)
#ifdef _WIN32 #ifdef _WIN32
: file_handle(0, CloseHandle) : file_handle(0, CloseHandle)
@ -117,8 +113,6 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
float_samples = false; float_samples = false;
} }
/// @brief DOCME
///
PCMAudioProvider::~PCMAudioProvider() PCMAudioProvider::~PCMAudioProvider()
{ {
#ifdef _WIN32 #ifdef _WIN32
@ -130,11 +124,6 @@ PCMAudioProvider::~PCMAudioProvider()
#endif #endif
} }
/// @brief DOCME
/// @param range_start
/// @param range_length
/// @return
///
char * PCMAudioProvider::EnsureRangeAccessible(int64_t range_start, int64_t range_length) const char * PCMAudioProvider::EnsureRangeAccessible(int64_t range_start, int64_t range_length) const
{ {
if (range_start + range_length > file_size) { if (range_start + range_length > file_size) {
@ -203,12 +192,7 @@ char * PCMAudioProvider::EnsureRangeAccessible(int64_t range_start, int64_t rang
return ((char*)current_mapping) + rel_ofs; return ((char*)current_mapping) + rel_ofs;
} }
/// @brief DOCME void PCMAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const
/// @param buf
/// @param start
/// @param count
///
void PCMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const
{ {
// Read blocks from the file // Read blocks from the file
size_t index = 0; size_t index = 0;
@ -234,16 +218,6 @@ void PCMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const
} }
index++; index++;
} }
// If we exhausted all sample sections zerofill the rest
if (count > 0) {
if (bytes_per_sample == 1)
// 8 bit formats are usually unsigned with bias 127
memset(buf, 127, count*channels);
else
// While everything else is signed
memset(buf, 0, count*bytes_per_sample*channels);
}
} }
/// DOCME /// DOCME
@ -308,11 +282,8 @@ class RiffWavPCMAudioProvider : public PCMAudioProvider {
public: public:
/// @brief DOCME
/// @param _filename
///
RiffWavPCMAudioProvider(const wxString &_filename) RiffWavPCMAudioProvider(const wxString &_filename)
: PCMAudioProvider(_filename) : PCMAudioProvider(_filename)
{ {
filename = _filename; filename = _filename;
@ -388,9 +359,6 @@ public:
} }
} }
/// @brief DOCME
/// @return
///
bool AreSamplesNativeEndian() const bool AreSamplesNativeEndian() const
{ {
// 8 bit samples don't consider endianness // 8 bit samples don't consider endianness
@ -401,34 +369,26 @@ public:
} }
}; };
/// DOCME
static const uint8_t w64GuidRIFF[16] = { static const uint8_t w64GuidRIFF[16] = {
// {66666972-912E-11CF-A5D6-28DB04C10000} // {66666972-912E-11CF-A5D6-28DB04C10000}
0x72, 0x69, 0x66, 0x66, 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 0x72, 0x69, 0x66, 0x66, 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00
}; };
/// DOCME
static const uint8_t w64GuidWAVE[16] = { static const uint8_t w64GuidWAVE[16] = {
// {65766177-ACF3-11D3-8CD1-00C04F8EDB8A} // {65766177-ACF3-11D3-8CD1-00C04F8EDB8A}
0x77, 0x61, 0x76, 0x65, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A 0x77, 0x61, 0x76, 0x65, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
}; };
/// DOCME
static const uint8_t w64Guidfmt[16] = { static const uint8_t w64Guidfmt[16] = {
// {20746D66-ACF3-11D3-8CD1-00C04F8EDB8A} // {20746D66-ACF3-11D3-8CD1-00C04F8EDB8A}
0x66, 0x6D, 0x74, 0x20, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A 0x66, 0x6D, 0x74, 0x20, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
}; };
/// DOCME
static const uint8_t w64Guiddata[16] = { static const uint8_t w64Guiddata[16] = {
// {61746164-ACF3-11D3-8CD1-00C04F8EDB8A} // {61746164-ACF3-11D3-8CD1-00C04F8EDB8A}
0x64, 0x61, 0x74, 0x61, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A 0x64, 0x61, 0x74, 0x61, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
}; };
/// DOCME /// DOCME
/// @class Wave64AudioProvider /// @class Wave64AudioProvider
/// @brief Sony Wave64 audio provider /// @brief Sony Wave64 audio provider
@ -448,49 +408,24 @@ class Wave64AudioProvider : public PCMAudioProvider {
uint16_t cbSize; uint16_t cbSize;
}; };
/// DOCME
struct RiffChunk { struct RiffChunk {
/// DOCME
uint8_t riff_guid[16]; uint8_t riff_guid[16];
/// DOCME
uint64_t file_size; uint64_t file_size;
/// DOCME
uint8_t format_guid[16]; uint8_t format_guid[16];
}; };
/// DOCME
struct FormatChunk { struct FormatChunk {
/// DOCME
uint8_t chunk_guid[16]; uint8_t chunk_guid[16];
/// DOCME
uint64_t chunk_size; uint64_t chunk_size;
/// DOCME
WaveFormatEx format; WaveFormatEx format;
/// DOCME
uint8_t padding[6]; uint8_t padding[6];
}; };
/// DOCME
struct DataChunk { struct DataChunk {
/// DOCME
uint8_t chunk_guid[16]; uint8_t chunk_guid[16];
/// DOCME
uint64_t chunk_size; uint64_t chunk_size;
}; };
/// @brief DOCME
/// @param guid1
/// @param guid2
/// @return
///
inline bool CheckGuid(const uint8_t *guid1, const uint8_t *guid2) inline bool CheckGuid(const uint8_t *guid1, const uint8_t *guid2)
{ {
return memcmp(guid1, guid2, 16) == 0; return memcmp(guid1, guid2, 16) == 0;
@ -498,9 +433,6 @@ class Wave64AudioProvider : public PCMAudioProvider {
public: public:
/// @brief DOCME
/// @param _filename
///
Wave64AudioProvider(const wxString &_filename) Wave64AudioProvider(const wxString &_filename)
: PCMAudioProvider(_filename) : PCMAudioProvider(_filename)
{ {
@ -579,9 +511,6 @@ public:
} }
} }
/// @brief DOCME
/// @return
///
bool AreSamplesNativeEndian() const bool AreSamplesNativeEndian() const
{ {
// 8 bit samples don't consider endianness // 8 bit samples don't consider endianness

View File

@ -57,19 +57,12 @@
/// DOCME /// DOCME
class PCMAudioProvider : public AudioProvider { class PCMAudioProvider : public AudioProvider {
#ifdef _WIN32 #ifdef _WIN32
/// DOCME
agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> file_handle; agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> file_handle;
/// DOCME
agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> file_mapping; agi::scoped_holder<HANDLE, BOOL (__stdcall *)(HANDLE)> file_mapping;
/// DOCME
mutable void *current_mapping; mutable void *current_mapping;
/// DOCME
mutable int64_t mapping_start; mutable int64_t mapping_start;
/// DOCME
mutable size_t mapping_length; mutable size_t mapping_length;
#else #else
agi::scoped_holder<int, int(*)(int)> file_handle; agi::scoped_holder<int, int(*)(int)> file_handle;
@ -83,32 +76,20 @@ protected:
virtual ~PCMAudioProvider(); // Closes the file mapping virtual ~PCMAudioProvider(); // Closes the file mapping
char * EnsureRangeAccessible(int64_t range_start, int64_t range_length) const; // Ensure that the given range of bytes are accessible in the file mapping and return a pointer to the first byte of the requested range char * EnsureRangeAccessible(int64_t range_start, int64_t range_length) const; // Ensure that the given range of bytes are accessible in the file mapping and return a pointer to the first byte of the requested range
/// Size of the opened file
int64_t file_size;
/// DOCME
int64_t file_size; // Size of the opened file
/// DOCME
struct IndexPoint { struct IndexPoint {
/// DOCME
int64_t start_byte; int64_t start_byte;
/// DOCME
int64_t start_sample; int64_t start_sample;
/// DOCME
int64_t num_samples; int64_t num_samples;
}; };
/// DOCME
typedef std::vector<IndexPoint> IndexVector; typedef std::vector<IndexPoint> IndexVector;
/// DOCME
IndexVector index_points; IndexVector index_points;
public: void FillBuffer(void *buf, int64_t start, int64_t count) const;
virtual void GetAudio(void *buf, int64_t start, int64_t count) const;
}; };
// Construct the right PCM audio provider (if any) for the file // Construct the right PCM audio provider (if any) for the file

View File

@ -112,45 +112,22 @@ void RAMAudioProvider::Clear() {
} }
} }
void RAMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const { void RAMAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {
// Requested beyond the length of audio // Prepare copy
if (start+count > num_samples) { char *charbuf = (char *)buf;
int64_t oldcount = count; int i = (start*bytes_per_sample) >> CacheBits;
count = num_samples-start; int start_offset = (start*bytes_per_sample) & (CacheBlockSize-1);
if (count < 0) count = 0; int64_t bytesremaining = count*bytes_per_sample;
// Fill beyond with zero // Copy
if (bytes_per_sample == 1) { while (bytesremaining) {
char *temp = (char *) buf; int readsize = std::min<int>(bytesremaining, CacheBlockSize - start_offset);
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
if (bytes_per_sample == 2) {
short *temp = (short *) buf;
for (int i=count;i<oldcount;i++) {
temp[i] = 0;
}
}
}
if (count) { memcpy(charbuf,(char *)(blockcache[i++]+start_offset),readsize);
// Prepare copy
char *charbuf = (char *)buf;
int i = (start*bytes_per_sample) >> CacheBits;
int start_offset = (start*bytes_per_sample) & (CacheBlockSize-1);
int64_t bytesremaining = count*bytes_per_sample;
// Copy charbuf+=readsize;
while (bytesremaining) {
int readsize = std::min<int>(bytesremaining, CacheBlockSize - start_offset);
memcpy(charbuf,(char *)(blockcache[i++]+start_offset),readsize); start_offset=0;
bytesremaining-=readsize;
charbuf+=readsize;
start_offset=0;
bytesremaining-=readsize;
}
} }
} }

View File

@ -58,11 +58,11 @@ class RAMAudioProvider : public AudioProvider {
void Clear(); void Clear();
void FillCache(AudioProvider *source, agi::ProgressSink *ps); void FillCache(AudioProvider *source, agi::ProgressSink *ps);
void FillBuffer(void *buf, int64_t start, int64_t count) const;
public: public:
RAMAudioProvider(AudioProvider *source, agi::BackgroundRunner *br); RAMAudioProvider(AudioProvider *source, agi::BackgroundRunner *br);
~RAMAudioProvider(); ~RAMAudioProvider();
bool AreSamplesNativeEndian() const { return samples_native_endian; } bool AreSamplesNativeEndian() const { return samples_native_endian; }
void GetAudio(void *buf, int64_t start, int64_t count) const;
}; };

View File

@ -67,11 +67,13 @@ protected:
/// DOCME /// DOCME
wxString filename; wxString filename;
virtual void FillBuffer(void *buf, int64_t start, int64_t count) const = 0;
public: public:
virtual ~AudioProvider() { } virtual ~AudioProvider() { }
virtual wxString GetFilename() const { return filename; }; virtual wxString GetFilename() const { return filename; };
virtual void GetAudio(void *buf, int64_t start, int64_t count) const = 0; void GetAudio(void *buf, int64_t start, int64_t count) const;
void GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const; void GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const;
int64_t GetNumSamples() const { return num_samples; } int64_t GetNumSamples() const { return num_samples; }