simplified and optimized samplebuffer

This commit is contained in:
itsmattkc
2022-05-09 14:55:51 -07:00
parent 58c4600d04
commit bb0fedabba
47 changed files with 214 additions and 252 deletions
+6 -6
View File
@@ -109,7 +109,7 @@ FramePtr Decoder::RetrieveVideo(const rational &timecode, const RetrieveVideoPar
return RetrieveVideoInternal(timecode, divider, cancelled);
}
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBufferPtr dest, const TimeRange &range, const AudioParams &params, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode)
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams &params, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode)
{
QMutexLocker locker(&mutex_);
@@ -272,14 +272,14 @@ bool Decoder::ConformAudioInternal(const QVector<QString> &filenames, const Audi
return false;
}
bool Decoder::RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVector<QString> &conform_filenames, const TimeRange& range, Footage::LoopMode loop_mode, const AudioParams &input_params)
bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange& range, Footage::LoopMode loop_mode, const AudioParams &input_params)
{
PlanarFileDevice input;
if (input.open(conform_filenames, QFile::ReadOnly)) {
qint64 read_index = input_params.time_to_bytes(range.in()) / input_params.channel_count();
qint64 write_index = 0;
const qint64 buffer_length_in_bytes = sample_buffer->sample_count() * input_params.bytes_per_sample_per_channel();
const qint64 buffer_length_in_bytes = sample_buffer.sample_count() * input_params.bytes_per_sample_per_channel();
while (write_index < buffer_length_in_bytes) {
if (loop_mode == Footage::kLoopModeLoop) {
@@ -297,15 +297,15 @@ bool Decoder::RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVec
if (read_index < 0) {
// Reading before 0, write silence here until audio data would actually start
write_count = qMin(-read_index, buffer_length_in_bytes);
sample_buffer->silence_bytes(write_index, write_index + write_count);
sample_buffer.silence_bytes(write_index, write_index + write_count);
} else if (read_index >= input.size()) {
// Reading after data length, write silence until the end of the buffer
write_count = buffer_length_in_bytes - write_index;
sample_buffer->silence_bytes(write_index, write_index + write_count);
sample_buffer.silence_bytes(write_index, write_index + write_count);
} else {
write_count = qMin(input.size() - read_index, buffer_length_in_bytes - write_index);
input.seek(read_index);
input.read(reinterpret_cast<char**>(sample_buffer->to_raw_ptrs()), write_count, write_index);
input.read(reinterpret_cast<char**>(sample_buffer.to_raw_ptrs().data()), write_count, write_index);
}
read_index += write_count;
+2 -2
View File
@@ -201,7 +201,7 @@ public:
*
* This function is thread safe and can only run while the decoder is open. \see Open()
*/
RetrieveAudioStatus RetrieveAudio(SampleBufferPtr dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode);
RetrieveAudioStatus RetrieveAudio(SampleBuffer &dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode);
/**
* @brief Determine the last time this decoder instance was used in any way
@@ -307,7 +307,7 @@ signals:
private:
void UpdateLastAccessed();
bool RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVector<QString> &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams &params);
bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams &params);
CodecStream stream_;
+1 -1
View File
@@ -183,7 +183,7 @@ public slots:
virtual bool Open() = 0;
virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) = 0;
virtual bool WriteAudio(olive::SampleBufferPtr audio) = 0;
virtual bool WriteAudio(const olive::SampleBuffer &audio) = 0;
virtual bool WriteSubtitle(const SubtitleBlock *sub_block) = 0;
virtual void Close() = 0;
+2 -2
View File
@@ -515,7 +515,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
// Resample audio to our destination parameters
nb_samples = swr_convert(resampler,
reinterpret_cast<uint8_t**>(data.to_raw_ptrs()),
reinterpret_cast<uint8_t**>(data.to_raw_ptrs().data()),
nb_samples,
const_cast<const uint8_t**>(frame->data),
frame->nb_samples);
@@ -526,7 +526,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
nb_bytes_per_channel = params.samples_to_bytes(nb_samples) / nb_channels;
// Write to files
wave_out.write(const_cast<const char**>(reinterpret_cast<char**>(data.to_raw_ptrs())), nb_bytes_per_channel);
wave_out.write(const_cast<const char**>(reinterpret_cast<char**>(data.to_raw_ptrs().data())), nb_bytes_per_channel);
}
// Free buffer
+9 -9
View File
@@ -266,26 +266,26 @@ fail:
return success;
}
bool FFmpegEncoder::WriteAudio(SampleBufferPtr audio)
bool FFmpegEncoder::WriteAudio(const SampleBuffer &audio)
{
bool result = true;
// Create input buffer
int input_sample_count = 0;
uint8_t** input_data = nullptr;
if (audio) {
input_sample_count = audio->sample_count();
if (audio.is_allocated()) {
input_sample_count = audio.sample_count();
int input_linesize;
av_samples_alloc_array_and_samples(&input_data, &input_linesize, audio->audio_params().channel_count(),
input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio->audio_params().format()), 0);
av_samples_alloc_array_and_samples(&input_data, &input_linesize, audio.audio_params().channel_count(),
input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio.audio_params().format()), 0);
for (int i=0; i<audio->audio_params().channel_count(); i++) {
memcpy(input_data[i], audio->data(i), input_sample_count * audio->audio_params().bytes_per_sample_per_channel());
for (int i=0; i<audio.audio_params().channel_count(); i++) {
memcpy(input_data[i], audio.data(i), input_sample_count * audio.audio_params().bytes_per_sample_per_channel());
}
}
result = WriteAudioData(audio ? audio->audio_params() : params().audio_params(), const_cast<const uint8_t**>(input_data), input_sample_count);
result = WriteAudioData(audio.audio_params().is_valid() ? audio.audio_params() : params().audio_params(), const_cast<const uint8_t**>(input_data), input_sample_count);
if (input_data) {
av_freep(&input_data[0]);
@@ -774,7 +774,7 @@ void FFmpegEncoder::FlushEncoders()
}
if (audio_codec_ctx_) {
WriteAudio(nullptr);
WriteAudio(SampleBuffer());
FlushCodecCtx(audio_codec_ctx_, audio_stream_);
}
+1 -1
View File
@@ -47,7 +47,7 @@ public:
virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) override;
virtual bool WriteAudio(olive::SampleBufferPtr audio) override;
virtual bool WriteAudio(const olive::SampleBuffer &audio) override;
bool WriteAudioData(const AudioParams &audio_params, const uint8_t **data, int input_sample_count);
+1 -1
View File
@@ -62,7 +62,7 @@ bool OIIOEncoder::WriteFrame(FramePtr frame, rational time)
return true;
}
bool OIIOEncoder::WriteAudio(SampleBufferPtr audio)
bool OIIOEncoder::WriteAudio(const SampleBuffer &audio)
{
// Do nothing
return false;
+1 -1
View File
@@ -35,7 +35,7 @@ public slots:
virtual bool Open() override;
virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) override;
virtual bool WriteAudio(SampleBufferPtr audio) override;
virtual bool WriteAudio(const SampleBuffer &audio) override;
virtual bool WriteSubtitle(const SubtitleBlock *sub_block) override;
virtual void Close() override;
+28 -33
View File
@@ -20,6 +20,8 @@
#include "samplebuffer.h"
#include "common/cpuoptimize.h"
namespace olive {
SampleBuffer::SampleBuffer() :
@@ -27,25 +29,18 @@ SampleBuffer::SampleBuffer() :
{
}
SampleBufferPtr SampleBuffer::Create()
SampleBuffer::SampleBuffer(const AudioParams &audio_params, const rational &length) :
audio_params_(audio_params)
{
return std::make_shared<SampleBuffer>();
sample_count_per_channel_ = audio_params_.time_to_samples(length);
allocate();
}
SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, const rational &length)
SampleBuffer::SampleBuffer(const AudioParams &audio_params, int samples_per_channel) :
audio_params_(audio_params),
sample_count_per_channel_(samples_per_channel)
{
return CreateAllocated(audio_params, audio_params.time_to_samples(length));
}
SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, int samples_per_channel)
{
SampleBufferPtr buffer = Create();
buffer->set_audio_params(audio_params);
buffer->set_sample_count(samples_per_channel);
buffer->allocate();
return buffer;
allocate();
}
const AudioParams &SampleBuffer::audio_params() const
@@ -104,14 +99,11 @@ void SampleBuffer::allocate()
for (int i=0; i<audio_params_.channel_count(); i++) {
data_[i].resize(sample_count_per_channel_);
}
update_raw();
}
void SampleBuffer::destroy()
{
data_.clear();
raw_ptrs_.clear();
}
void SampleBuffer::reverse()
@@ -157,29 +149,40 @@ void SampleBuffer::speed(double speed)
}
data_ = output_data;
update_raw();
}
void SampleBuffer::transform_volume(float f)
{
for (int i=0;i<audio_params().channel_count();i++) {
for (int j=0;j<sample_count_per_channel_;j++) {
data_[i][j] *= f;
}
transform_volume_for_channel(i, f);
}
}
void SampleBuffer::transform_volume_for_channel(int channel, float volume)
{
for (int i=0;i<sample_count_per_channel_;i++) {
data_[channel][i] *= volume;
float *cdat = data_[channel].data();
int unopt_start = 0;
#if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM)
__m128 mult = _mm_load1_ps(&volume);
unopt_start = (sample_count_per_channel_ / 4) * 4;
for (int j=0; j<unopt_start; j+=4) {
float *here = cdat + j;
__m128 samples = _mm_loadu_ps(here);
__m128 multiplied = _mm_mul_ps(samples, mult);
_mm_storeu_ps(here, multiplied);
}
#endif
for (int j=unopt_start; j<sample_count_per_channel_; j++) {
cdat[j] *= volume;
}
}
void SampleBuffer::transform_volume_for_sample(int sample_index, float volume)
{
for (int i=0;i<audio_params().channel_count();i++) {
data_[i][sample_index] *= volume;
transform_volume_for_sample_on_channel(sample_index, i, volume);
}
}
@@ -220,12 +223,4 @@ void SampleBuffer::set(int channel, const float *data, int sample_offset, int sa
memcpy(&data_[channel].data()[sample_offset], data, sizeof(float) * sample_length);
}
void SampleBuffer::update_raw()
{
raw_ptrs_.resize(data_.size());
for (int i=0; i<raw_ptrs_.size(); i++) {
raw_ptrs_[i] = data_[i].data();
}
}
}
+9 -15
View File
@@ -27,9 +27,6 @@
namespace olive {
class SampleBuffer;
using SampleBufferPtr = std::shared_ptr<SampleBuffer>;
/**
* @brief A buffer of audio samples
*
@@ -42,12 +39,8 @@ class SampleBuffer
{
public:
SampleBuffer();
static SampleBufferPtr Create();
static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, const rational& length);
static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, int samples_per_channel);
DISABLE_COPY_MOVE(SampleBuffer)
SampleBuffer(const AudioParams& audio_params, const rational& length);
SampleBuffer(const AudioParams& audio_params, int samples_per_channel);
const AudioParams& audio_params() const;
void set_audio_params(const AudioParams& params);
@@ -69,9 +62,13 @@ public:
return data_.at(channel).constData();
}
float **to_raw_ptrs()
QVector<float *> to_raw_ptrs()
{
return raw_ptrs_.data();
QVector<float *> r(data_.size());
for (int i=0; i<r.size(); i++) {
r[i] = data_[i].data();
}
return r;
}
bool is_allocated() const;
@@ -96,19 +93,16 @@ public:
}
private:
void update_raw();
AudioParams audio_params_;
int sample_count_per_channel_;
QVector< QVector<float> > data_;
QVector<float*> raw_ptrs_;
};
}
Q_DECLARE_METATYPE(olive::SampleBufferPtr)
Q_DECLARE_METATYPE(olive::SampleBuffer)
#endif // SAMPLEBUFFER_H