simplified and optimized samplebuffer
This commit is contained in:
@@ -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 ¶ms, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode)
|
||||
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams ¶ms, 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
@@ -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 ¶ms);
|
||||
bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams ¶ms);
|
||||
|
||||
CodecStream stream_;
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user