Merge pull request #4321 from TheUbuntuGuy/master
Fix inconsistent buffer sizes sent to analyzer
This commit is contained in:
commit
4d48456dec
5
src/analyzers/analyzerbase.cpp
Normal file → Executable file
5
src/analyzers/analyzerbase.cpp
Normal file → Executable file
@ -52,6 +52,7 @@ Analyzer::Base::Base(QWidget* parent, uint scopeSize)
|
|||||||
m_fht(new FHT(scopeSize)),
|
m_fht(new FHT(scopeSize)),
|
||||||
m_engine(nullptr),
|
m_engine(nullptr),
|
||||||
m_lastScope(512),
|
m_lastScope(512),
|
||||||
|
current_chunk_(0),
|
||||||
new_frame_(false),
|
new_frame_(false),
|
||||||
is_playing_(false) {}
|
is_playing_(false) {}
|
||||||
|
|
||||||
@ -85,10 +86,10 @@ void Analyzer::Base::paintEvent(QPaintEvent* e) {
|
|||||||
|
|
||||||
switch (m_engine->state()) {
|
switch (m_engine->state()) {
|
||||||
case Engine::Playing: {
|
case Engine::Playing: {
|
||||||
const Engine::Scope& thescope = m_engine->scope();
|
const Engine::Scope& thescope = m_engine->scope(m_timeout);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
// convert to mono here - our built in analyzers need mono, but we the
|
// convert to mono here - our built in analyzers need mono, but the
|
||||||
// engines provide interleaved pcm
|
// engines provide interleaved pcm
|
||||||
for (uint x = 0; (int)x < m_fht->size(); ++x) {
|
for (uint x = 0; (int)x < m_fht->size(); ++x) {
|
||||||
m_lastScope[x] =
|
m_lastScope[x] =
|
||||||
|
1
src/analyzers/analyzerbase.h
Normal file → Executable file
1
src/analyzers/analyzerbase.h
Normal file → Executable file
@ -73,6 +73,7 @@ class Base : public QWidget {
|
|||||||
FHT* m_fht;
|
FHT* m_fht;
|
||||||
EngineBase* m_engine;
|
EngineBase* m_engine;
|
||||||
Scope m_lastScope;
|
Scope m_lastScope;
|
||||||
|
int current_chunk_;
|
||||||
|
|
||||||
bool new_frame_;
|
bool new_frame_;
|
||||||
bool is_playing_;
|
bool is_playing_;
|
||||||
|
2
src/engines/enginebase.h
Normal file → Executable file
2
src/engines/enginebase.h
Normal file → Executable file
@ -85,7 +85,7 @@ class Base : public QObject {
|
|||||||
|
|
||||||
// Simple accessors
|
// Simple accessors
|
||||||
inline uint volume() const { return volume_; }
|
inline uint volume() const { return volume_; }
|
||||||
virtual const Scope& scope() { return scope_; }
|
virtual const Scope& scope(int chunk_length) { return scope_; }
|
||||||
bool is_fadeout_enabled() const { return fadeout_enabled_; }
|
bool is_fadeout_enabled() const { return fadeout_enabled_; }
|
||||||
bool is_crossfade_enabled() const { return crossfade_enabled_; }
|
bool is_crossfade_enabled() const { return crossfade_enabled_; }
|
||||||
bool is_autocrossfade_enabled() const { return autocrossfade_enabled_; }
|
bool is_autocrossfade_enabled() const { return autocrossfade_enabled_; }
|
||||||
|
63
src/engines/gstengine.cpp
Normal file → Executable file
63
src/engines/gstengine.cpp
Normal file → Executable file
@ -22,6 +22,7 @@
|
|||||||
#include "gstengine.h"
|
#include "gstengine.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <cmath>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -44,6 +45,7 @@
|
|||||||
#include "gstenginepipeline.h"
|
#include "gstenginepipeline.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/taskmanager.h"
|
#include "core/taskmanager.h"
|
||||||
|
#include "core/timeconstants.h"
|
||||||
#include "core/utilities.h"
|
#include "core/utilities.h"
|
||||||
|
|
||||||
#ifdef HAVE_MOODBAR
|
#ifdef HAVE_MOODBAR
|
||||||
@ -96,7 +98,9 @@ GstEngine::GstEngine(TaskManager* task_manager)
|
|||||||
timer_id_(-1),
|
timer_id_(-1),
|
||||||
next_element_id_(0),
|
next_element_id_(0),
|
||||||
is_fading_out_to_pause_(false),
|
is_fading_out_to_pause_(false),
|
||||||
has_faded_out_(false) {
|
has_faded_out_(false),
|
||||||
|
scope_chunk_(0),
|
||||||
|
have_new_buffer_(false) {
|
||||||
seek_timer_->setSingleShot(true);
|
seek_timer_->setSingleShot(true);
|
||||||
seek_timer_->setInterval(kSeekDelayNanosec / kNsecPerMsec);
|
seek_timer_->setInterval(kSeekDelayNanosec / kNsecPerMsec);
|
||||||
connect(seek_timer_, SIGNAL(timeout()), SLOT(SeekNow()));
|
connect(seek_timer_, SIGNAL(timeout()), SLOT(SeekNow()));
|
||||||
@ -235,20 +239,40 @@ void GstEngine::AddBufferToScope(GstBuffer* buf, int pipeline_id) {
|
|||||||
if (latest_buffer_ != nullptr) {
|
if (latest_buffer_ != nullptr) {
|
||||||
gst_buffer_unref(latest_buffer_);
|
gst_buffer_unref(latest_buffer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
latest_buffer_ = buf;
|
latest_buffer_ = buf;
|
||||||
|
have_new_buffer_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Engine::Scope& GstEngine::scope() {
|
const Engine::Scope& GstEngine::scope(int chunk_length) {
|
||||||
if (latest_buffer_ != nullptr) {
|
// the new buffer could have a different size
|
||||||
UpdateScope();
|
if (have_new_buffer_) {
|
||||||
|
if (latest_buffer_ != nullptr) {
|
||||||
|
scope_chunks_ = ceil(((double)GST_BUFFER_DURATION(latest_buffer_) /
|
||||||
|
(double)(chunk_length * kNsecPerMsec)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the buffer is shorter than the chunk length
|
||||||
|
if (scope_chunks_ <= 0) {
|
||||||
|
scope_chunks_ = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope_chunk_ = 0;
|
||||||
|
have_new_buffer_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateScope(chunk_length);
|
||||||
return scope_;
|
return scope_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEngine::UpdateScope() {
|
void GstEngine::UpdateScope(int chunk_length) {
|
||||||
typedef Engine::Scope::value_type sample_type;
|
typedef Engine::Scope::value_type sample_type;
|
||||||
|
|
||||||
|
// determine where to split the buffer
|
||||||
|
int chunk_density = GST_BUFFER_SIZE(latest_buffer_) /
|
||||||
|
(GST_BUFFER_DURATION(latest_buffer_) / kNsecPerMsec);
|
||||||
|
int chunk_size = chunk_length * chunk_density;
|
||||||
|
|
||||||
// determine the number of channels
|
// determine the number of channels
|
||||||
GstStructure* structure =
|
GstStructure* structure =
|
||||||
gst_caps_get_structure(GST_BUFFER_CAPS(latest_buffer_), 0);
|
gst_caps_get_structure(GST_BUFFER_CAPS(latest_buffer_), 0);
|
||||||
@ -258,17 +282,34 @@ void GstEngine::UpdateScope() {
|
|||||||
// scope does not support >2 channels
|
// scope does not support >2 channels
|
||||||
if (channels > 2) return;
|
if (channels > 2) return;
|
||||||
|
|
||||||
|
// in case a buffer doesn't arrive in time
|
||||||
|
if (scope_chunk_ >= scope_chunks_) {
|
||||||
|
scope_chunk_ = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the starting point in the buffer to take data from
|
||||||
const sample_type* source =
|
const sample_type* source =
|
||||||
reinterpret_cast<sample_type*>(GST_BUFFER_DATA(latest_buffer_));
|
reinterpret_cast<sample_type*>(GST_BUFFER_DATA(latest_buffer_));
|
||||||
|
source += (chunk_size / sizeof(sample_type)) * scope_chunk_;
|
||||||
sample_type* dest = scope_.data();
|
sample_type* dest = scope_.data();
|
||||||
const int bytes = qMin(
|
|
||||||
static_cast<Engine::Scope::size_type>(GST_BUFFER_SIZE(latest_buffer_)),
|
int bytes = 0;
|
||||||
scope_.size() * sizeof(sample_type));
|
|
||||||
|
// make sure we don't go beyond the end of the buffer
|
||||||
|
if (scope_chunk_ == scope_chunks_ - 1) {
|
||||||
|
bytes =
|
||||||
|
qMin(static_cast<Engine::Scope::size_type>(
|
||||||
|
GST_BUFFER_SIZE(latest_buffer_) - (chunk_size * scope_chunk_)),
|
||||||
|
scope_.size() * sizeof(sample_type));
|
||||||
|
} else {
|
||||||
|
bytes = qMin(static_cast<Engine::Scope::size_type>(chunk_size),
|
||||||
|
scope_.size() * sizeof(sample_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
scope_chunk_++;
|
||||||
|
|
||||||
memcpy(dest, source, bytes);
|
memcpy(dest, source, bytes);
|
||||||
|
|
||||||
gst_buffer_unref(latest_buffer_);
|
|
||||||
latest_buffer_ = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEngine::StartPreloading(const QUrl& url, bool force_stop_at_end,
|
void GstEngine::StartPreloading(const QUrl& url, bool force_stop_at_end,
|
||||||
|
8
src/engines/gstengine.h
Normal file → Executable file
8
src/engines/gstengine.h
Normal file → Executable file
@ -80,7 +80,7 @@ class GstEngine : public Engine::Base, public BufferConsumer {
|
|||||||
qint64 position_nanosec() const;
|
qint64 position_nanosec() const;
|
||||||
qint64 length_nanosec() const;
|
qint64 length_nanosec() const;
|
||||||
Engine::State state() const;
|
Engine::State state() const;
|
||||||
const Engine::Scope& scope();
|
const Engine::Scope& scope(int chunk_length);
|
||||||
|
|
||||||
OutputDetailsList GetOutputsList() const;
|
OutputDetailsList GetOutputsList() const;
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ class GstEngine : public Engine::Base, public BufferConsumer {
|
|||||||
std::shared_ptr<GstEnginePipeline> CreatePipeline(const QUrl& url,
|
std::shared_ptr<GstEnginePipeline> CreatePipeline(const QUrl& url,
|
||||||
qint64 end_nanosec);
|
qint64 end_nanosec);
|
||||||
|
|
||||||
void UpdateScope();
|
void UpdateScope(int chunk_length);
|
||||||
|
|
||||||
int AddBackgroundStream(std::shared_ptr<GstEnginePipeline> pipeline);
|
int AddBackgroundStream(std::shared_ptr<GstEnginePipeline> pipeline);
|
||||||
|
|
||||||
@ -224,6 +224,10 @@ class GstEngine : public Engine::Base, public BufferConsumer {
|
|||||||
bool is_fading_out_to_pause_;
|
bool is_fading_out_to_pause_;
|
||||||
bool has_faded_out_;
|
bool has_faded_out_;
|
||||||
|
|
||||||
|
int scope_chunk_;
|
||||||
|
bool have_new_buffer_;
|
||||||
|
int scope_chunks_;
|
||||||
|
|
||||||
QList<DeviceFinder*> device_finders_;
|
QList<DeviceFinder*> device_finders_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user