Merge pull request #4321 from TheUbuntuGuy/master

Fix inconsistent buffer sizes sent to analyzer
This commit is contained in:
David Sansome 2014-05-03 23:30:53 +10:00
commit 4d48456dec
5 changed files with 63 additions and 16 deletions

5
src/analyzers/analyzerbase.cpp Normal file → Executable file
View 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
View 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
View 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
View 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
View 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_;
}; };