node: split off traversing functions from renderer for usage elsewhere
Fixes issue where Viewer node wouldn't pick up correct length if a tracks weren't in use.
This commit is contained in:
@@ -194,6 +194,7 @@ AudioManager::AudioManager() :
|
||||
RefreshDevices();
|
||||
|
||||
connect(&output_manager_, &AudioOutputManager::SentSamples, this, &AudioManager::SentSamples);
|
||||
connect(&output_manager_, &AudioOutputManager::OutputNotified, this, &AudioManager::OutputNotified);
|
||||
|
||||
output_manager_.SetEnableSendingSamples(true);
|
||||
}
|
||||
|
||||
@@ -102,6 +102,8 @@ signals:
|
||||
|
||||
void SentSamples(QVector<double> averages);
|
||||
|
||||
void OutputNotified();
|
||||
|
||||
private:
|
||||
AudioManager();
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ void AudioOutputManager::Push(const QByteArray& samples)
|
||||
ResetToPushMode();
|
||||
|
||||
// Start pushing samples to the output
|
||||
OutputNotified();
|
||||
PushMoreSamples();
|
||||
}
|
||||
|
||||
void AudioOutputManager::ResetToPushMode()
|
||||
@@ -92,7 +92,7 @@ void AudioOutputManager::PullFromDevice(QIODevice *device, int playback_speed)
|
||||
output_->start(&device_proxy_);
|
||||
}
|
||||
|
||||
void AudioOutputManager::OutputNotified()
|
||||
void AudioOutputManager::PushMoreSamples()
|
||||
{
|
||||
// Check if we're currently in push mode and if we have samples to push
|
||||
if (!push_device_ || pushed_samples_.isEmpty()) {
|
||||
@@ -139,6 +139,7 @@ void AudioOutputManager::SetOutputDevice(QAudioDeviceInfo info, QAudioFormat for
|
||||
output_ = std::unique_ptr<QAudioOutput>(new QAudioOutput(info, format, this));
|
||||
output_->setNotifyInterval(1);
|
||||
push_device_ = output_->start();
|
||||
connect(output_.get(), &QAudioOutput::notify, this, &AudioOutputManager::PushMoreSamples);
|
||||
connect(output_.get(), &QAudioOutput::notify, this, &AudioOutputManager::OutputNotified);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ signals:
|
||||
*/
|
||||
void SentSamples(QVector<double> averages);
|
||||
|
||||
void OutputNotified();
|
||||
|
||||
private:
|
||||
void ProcessAverages(const char* data, int length);
|
||||
|
||||
@@ -83,7 +85,7 @@ private:
|
||||
AudioOutputDeviceProxy device_proxy_;
|
||||
|
||||
private slots:
|
||||
void OutputNotified();
|
||||
void PushMoreSamples();
|
||||
};
|
||||
|
||||
#endif // AUDIOHYBRIDDEVICE_H
|
||||
|
||||
@@ -46,6 +46,8 @@ set(OLIVE_SOURCES
|
||||
node/output.cpp
|
||||
node/param.h
|
||||
node/param.cpp
|
||||
node/traverser.h
|
||||
node/traverser.cpp
|
||||
node/value.h
|
||||
node/value.cpp
|
||||
PARENT_SCOPE
|
||||
|
||||
@@ -28,8 +28,3 @@ QString AudioInput::Description() const
|
||||
{
|
||||
return tr("Import an audio footage stream.");
|
||||
}
|
||||
|
||||
NodeValueTable AudioInput::Value(const NodeValueDatabase &value) const
|
||||
{
|
||||
return value[footage_input_];
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@ public:
|
||||
virtual QString Category() const override;
|
||||
virtual QString Description() const override;
|
||||
|
||||
protected:
|
||||
virtual NodeValueTable Value(const NodeValueDatabase& value) const override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "viewer.h"
|
||||
|
||||
#include "node/traverser.h"
|
||||
|
||||
ViewerOutput::ViewerOutput()
|
||||
{
|
||||
texture_input_ = new NodeInput("tex_in", NodeInput::kTexture);
|
||||
@@ -28,9 +30,6 @@ ViewerOutput::ViewerOutput()
|
||||
samples_input_ = new NodeInput("samples_in", NodeInput::kSamples);
|
||||
AddInput(samples_input_);
|
||||
|
||||
length_input_ = new NodeInput("length_in", NodeInput::kRational);
|
||||
AddInput(length_input_);
|
||||
|
||||
// Create TrackList instances
|
||||
track_inputs_.resize(Timeline::kTrackTypeCount);
|
||||
track_lists_.resize(Timeline::kTrackTypeCount);
|
||||
@@ -91,11 +90,6 @@ NodeInput *ViewerOutput::samples_input() const
|
||||
return samples_input_;
|
||||
}
|
||||
|
||||
NodeInput *ViewerOutput::length_input() const
|
||||
{
|
||||
return length_input_;
|
||||
}
|
||||
|
||||
void ViewerOutput::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
|
||||
{
|
||||
Node::InvalidateCache(start_range, end_range, from);
|
||||
@@ -104,8 +98,6 @@ void ViewerOutput::InvalidateCache(const rational &start_range, const rational &
|
||||
emit VideoChangedBetween(TimeRange(start_range, end_range));
|
||||
} else if (from == samples_input()) {
|
||||
emit AudioChangedBetween(TimeRange(start_range, end_range));
|
||||
} else if (from == length_input()) {
|
||||
emit LengthChanged(Length());
|
||||
}
|
||||
|
||||
SendInvalidateCache(start_range, end_range);
|
||||
@@ -146,18 +138,23 @@ void ViewerOutput::set_audio_params(const AudioParams &audio)
|
||||
|
||||
rational ViewerOutput::Length()
|
||||
{
|
||||
if (!length_input_->IsConnected()) {
|
||||
return timeline_length_;
|
||||
NodeTraverser traverser;
|
||||
|
||||
rational video_length;
|
||||
|
||||
if (texture_input_->IsConnected()) {
|
||||
NodeValueTable t = traverser.ProcessNode(NodeDependency(texture_input_->get_connected_node(), 0, 0));
|
||||
video_length = t.Get(NodeParam::kNumber, "length").value<rational>();
|
||||
}
|
||||
|
||||
Node* connected_node = length_input_->get_connected_node();
|
||||
rational audio_length;
|
||||
|
||||
if (connected_node) {
|
||||
// This is kind of messy?
|
||||
return connected_node->Value(NodeValueDatabase()).Get(NodeParam::kNumber, "length").value<rational>();
|
||||
if (samples_input_->IsConnected()) {
|
||||
NodeValueTable t = traverser.ProcessNode(NodeDependency(samples_input_->get_connected_node(), 0, 0));
|
||||
audio_length = t.Get(NodeParam::kNumber, "length").value<rational>();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return qMax(video_length, qMax(audio_length, timeline_length_));
|
||||
}
|
||||
|
||||
const QUuid &ViewerOutput::uuid() const
|
||||
|
||||
@@ -52,7 +52,6 @@ public:
|
||||
|
||||
NodeInput* texture_input() const;
|
||||
NodeInput* samples_input() const;
|
||||
NodeInput* length_input() const;
|
||||
|
||||
virtual void InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from = nullptr) override;
|
||||
virtual void InvalidateVisible(NodeInput *from) override;
|
||||
@@ -117,8 +116,6 @@ private:
|
||||
|
||||
NodeInput* samples_input_;
|
||||
|
||||
NodeInput* length_input_;
|
||||
|
||||
VideoParams video_params_;
|
||||
|
||||
AudioParams audio_params_;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#include "traverser.h"
|
||||
|
||||
#include "node.h"
|
||||
|
||||
NodeTraverser::NodeTraverser()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRange &range)
|
||||
{
|
||||
NodeValueDatabase database;
|
||||
|
||||
// We need to insert tables into the database for each input
|
||||
foreach (NodeParam* param, node->parameters()) {
|
||||
if (IsCancelled()) {
|
||||
return NodeValueDatabase();
|
||||
}
|
||||
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
NodeInput* input = static_cast<NodeInput*>(param);
|
||||
TimeRange input_time = node->InputTimeAdjustment(input, range);
|
||||
|
||||
NodeValueTable table = ProcessInput(input, input_time);
|
||||
|
||||
InputProcessingEvent(input, input_time, &table);
|
||||
|
||||
database.Insert(input, table);
|
||||
}
|
||||
}
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
NodeValueTable NodeTraverser::ProcessNode(const NodeDependency& dep)
|
||||
{
|
||||
const Node* node = dep.node();
|
||||
|
||||
if (node->IsTrack()) {
|
||||
// If the range is not wholly contained in this Block, we'll need to do some extra processing
|
||||
return RenderBlock(static_cast<const TrackOutput*>(node), dep.range());
|
||||
}
|
||||
|
||||
// FIXME: Cache certain values here if we've already processed them before
|
||||
|
||||
// Generate database of input values of node
|
||||
NodeValueDatabase database = GenerateDatabase(node, dep.range());
|
||||
|
||||
// By this point, the node should have all the inputs it needs to render correctly
|
||||
NodeValueTable table = node->Value(database);
|
||||
|
||||
ProcessNodeEvent(node, dep.range(), database, &table);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
NodeValueTable NodeTraverser::RenderBlock(const TrackOutput *track, const TimeRange &range)
|
||||
{
|
||||
// By default, don't bother traversing blocks
|
||||
return NodeValueTable();
|
||||
}
|
||||
|
||||
NodeValueTable NodeTraverser::ProcessInput(const NodeInput *input, const TimeRange& range)
|
||||
{
|
||||
if (input->IsConnected()) {
|
||||
// Value will equal something from the connected node, follow it
|
||||
return ProcessNode(NodeDependency(input->get_connected_node(), range));
|
||||
} else {
|
||||
// Push onto the table the value at this time from the input
|
||||
QVariant input_value = input->get_value_at_time(range.in());
|
||||
|
||||
NodeValueTable table;
|
||||
table.Push(input->data_type(), input_value);
|
||||
return table;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef NODETRAVERSER_H
|
||||
#define NODETRAVERSER_H
|
||||
|
||||
#include "codec/decoder.h"
|
||||
#include "common/cancelableobject.h"
|
||||
#include "dependency.h"
|
||||
#include "node/output/track/track.h"
|
||||
#include "project/item/footage/stream.h"
|
||||
#include "value.h"
|
||||
|
||||
class NodeTraverser : public CancelableObject
|
||||
{
|
||||
public:
|
||||
NodeTraverser();
|
||||
|
||||
NodeValueTable ProcessNode(const NodeDependency &dep);
|
||||
|
||||
protected:
|
||||
NodeValueDatabase GenerateDatabase(const Node *node, const TimeRange &range);
|
||||
|
||||
virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range);
|
||||
|
||||
NodeValueTable ProcessInput(const NodeInput* input, const TimeRange &range);
|
||||
|
||||
virtual void InputProcessingEvent(NodeInput*, const TimeRange&, NodeValueTable*){}
|
||||
|
||||
virtual void ProcessNodeEvent(const Node*, const TimeRange&, const NodeValueDatabase&, NodeValueTable*){}
|
||||
|
||||
};
|
||||
|
||||
#endif // NODETRAVERSER_H
|
||||
+2
-6
@@ -58,13 +58,9 @@ NodeValueTable::NodeValueTable()
|
||||
|
||||
QVariant NodeValueTable::Get(const NodeParam::DataType &type, const QString &tag) const
|
||||
{
|
||||
int value_index = GetInternal(type, tag);
|
||||
NodeValue v = GetWithMeta(type, tag);
|
||||
|
||||
if (value_index >= 0) {
|
||||
return values_.at(value_index).data();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
return v.data();
|
||||
}
|
||||
|
||||
NodeValue NodeValueTable::GetWithMeta(const NodeParam::DataType &type, const QString &tag) const
|
||||
|
||||
@@ -87,95 +87,41 @@ bool RenderWorker::IsStarted()
|
||||
return started_;
|
||||
}
|
||||
|
||||
NodeValueTable RenderWorker::ProcessNode(const NodeDependency& dep)
|
||||
{
|
||||
const Node* node = dep.node();
|
||||
|
||||
if (node->IsTrack()) {
|
||||
// If the range is not wholly contained in this Block, we'll need to do some extra processing
|
||||
return RenderBlock(static_cast<const TrackOutput*>(node), dep.range());
|
||||
}
|
||||
|
||||
// FIXME: Cache certain values here if we've already processed them before
|
||||
|
||||
// Generate database of input values of node
|
||||
NodeValueDatabase database = GenerateDatabase(node, dep.range());
|
||||
|
||||
// By this point, the node should have all the inputs it needs to render correctly
|
||||
NodeValueTable table = node->Value(database);
|
||||
|
||||
// Check if we have a shader for this output
|
||||
RunNodeAccelerated(node, dep.range(), database, &table);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
NodeValueTable RenderWorker::ProcessInput(const NodeInput *input, const TimeRange& range)
|
||||
{
|
||||
if (input->IsConnected()) {
|
||||
// Value will equal something from the connected node, follow it
|
||||
return ProcessNode(NodeDependency(input->get_connected_node(), range));
|
||||
} else {
|
||||
// Push onto the table the value at this time from the input
|
||||
QVariant input_value = input->get_value_at_time(range.in());
|
||||
|
||||
NodeValueTable table;
|
||||
table.Push(input->data_type(), input_value);
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWorker::ReportUnavailableFootage(StreamPtr stream, Decoder::RetrieveState state, const rational& stream_time)
|
||||
{
|
||||
emit FootageUnavailable(stream, state, path_.range(), stream_time);
|
||||
}
|
||||
|
||||
void RenderWorker::InputProcessingEvent(NodeInput* input, const TimeRange& input_time, NodeValueTable *table)
|
||||
{
|
||||
// Exception for Footage types where we actually retrieve some Footage data from a decoder
|
||||
if (input->data_type() == NodeParam::kFootage) {
|
||||
StreamPtr stream = ResolveStreamFromInput(input);
|
||||
|
||||
if (stream) {
|
||||
DecoderPtr decoder = ResolveDecoderFromInput(stream);
|
||||
|
||||
if (decoder) {
|
||||
|
||||
Decoder::RetrieveState state = decoder->GetRetrieveState(input_time.out());
|
||||
|
||||
if (state == Decoder::kReady) {
|
||||
FrameToValue(decoder, stream, input_time, table);
|
||||
} else {
|
||||
ReportUnavailableFootage(stream, state, input_time.out());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderWorker::ProcessNodeEvent(const Node *node, const TimeRange &range, const NodeValueDatabase &input_params, NodeValueTable* output_params)
|
||||
{
|
||||
// Check if we have a shader for this output
|
||||
RunNodeAccelerated(node, range, input_params, output_params);
|
||||
}
|
||||
|
||||
const NodeDependency &RenderWorker::CurrentPath() const
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
|
||||
#include "common/functiontimer.h"
|
||||
NodeValueDatabase RenderWorker::GenerateDatabase(const Node* node, const TimeRange &range)
|
||||
{
|
||||
NodeValueDatabase database;
|
||||
|
||||
// We need to insert tables into the database for each input
|
||||
foreach (NodeParam* param, node->parameters()) {
|
||||
if (IsCancelled()) {
|
||||
return NodeValueDatabase();
|
||||
}
|
||||
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
NodeInput* input = static_cast<NodeInput*>(param);
|
||||
TimeRange input_time = node->InputTimeAdjustment(input, range);
|
||||
|
||||
NodeValueTable table = ProcessInput(input, input_time);
|
||||
|
||||
// Exception for Footage types where we actually retrieve some Footage data from a decoder
|
||||
if (input->data_type() == NodeParam::kFootage) {
|
||||
StreamPtr stream = ResolveStreamFromInput(input);
|
||||
|
||||
if (stream) {
|
||||
DecoderPtr decoder = ResolveDecoderFromInput(stream);
|
||||
|
||||
if (decoder) {
|
||||
|
||||
Decoder::RetrieveState state = decoder->GetRetrieveState(input_time.out());
|
||||
|
||||
if (state == Decoder::kReady) {
|
||||
FrameToValue(decoder, stream, input_time, &table);
|
||||
} else {
|
||||
ReportUnavailableFootage(stream, state, input_time.out());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.Insert(input, table);
|
||||
}
|
||||
}
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "common/cancelableobject.h"
|
||||
#include "common/constructors.h"
|
||||
#include "node/output/track/track.h"
|
||||
#include "node/node.h"
|
||||
#include "decodercache.h"
|
||||
#include "node/node.h"
|
||||
#include "node/output/track/track.h"
|
||||
#include "node/traverser.h"
|
||||
|
||||
class RenderWorker : public QObject, public CancelableObject
|
||||
class RenderWorker : public QObject, public NodeTraverser
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -38,24 +38,21 @@ protected:
|
||||
|
||||
virtual void RunNodeAccelerated(const Node *node, const TimeRange& range, const NodeValueDatabase &input_params, NodeValueTable* output_params);
|
||||
|
||||
StreamPtr ResolveStreamFromInput(NodeInput* input);
|
||||
DecoderPtr ResolveDecoderFromInput(StreamPtr stream);
|
||||
|
||||
virtual void FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) = 0;
|
||||
|
||||
NodeValueTable ProcessNode(const NodeDependency &dep);
|
||||
|
||||
virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range) = 0;
|
||||
|
||||
NodeValueTable ProcessInput(const NodeInput* input, const TimeRange &range);
|
||||
|
||||
virtual void ReportUnavailableFootage(StreamPtr stream, Decoder::RetrieveState state, const rational& stream_time);
|
||||
|
||||
virtual void InputProcessingEvent(NodeInput *input, const TimeRange &input_time, NodeValueTable* table) override;
|
||||
|
||||
virtual void ProcessNodeEvent(const Node *node, const TimeRange &range, const NodeValueDatabase &input_params, NodeValueTable* output_params) override;
|
||||
|
||||
StreamPtr ResolveStreamFromInput(NodeInput* input);
|
||||
|
||||
DecoderPtr ResolveDecoderFromInput(StreamPtr stream);
|
||||
|
||||
const NodeDependency& CurrentPath() const;
|
||||
|
||||
private:
|
||||
NodeValueDatabase GenerateDatabase(const Node *node, const TimeRange &range);
|
||||
|
||||
bool started_;
|
||||
|
||||
DecoderCache* decoder_cache_;
|
||||
|
||||
@@ -13,9 +13,13 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) :
|
||||
audio_node_ = new AudioInput();
|
||||
viewer_node_ = new ViewerOutput();
|
||||
|
||||
waveform_view_ = new QWidget();
|
||||
waveform_view_->setAutoFillBackground(true);
|
||||
waveform_view_->setStyleSheet("background: black;");
|
||||
stack()->addWidget(waveform_view_);
|
||||
|
||||
NodeParam::ConnectEdge(video_node_->output(), viewer_node_->texture_input());
|
||||
NodeParam::ConnectEdge(audio_node_->output(), viewer_node_->samples_input());
|
||||
NodeParam::ConnectEdge(video_node_->output(), viewer_node_->length_input());
|
||||
|
||||
connect(gl_widget_, &ViewerGLWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag);
|
||||
}
|
||||
@@ -55,6 +59,10 @@ void FootageViewerWidget::SetFootage(Footage *footage)
|
||||
if (video_stream) {
|
||||
video_node_->SetFootage(video_stream);
|
||||
viewer_node_->set_video_params(VideoParams(video_stream->width(), video_stream->height(), video_stream->frame_rate().flipped()));
|
||||
|
||||
stack()->setCurrentWidget(gl_widget_);
|
||||
} else {
|
||||
stack()->setCurrentWidget(waveform_view_);
|
||||
}
|
||||
|
||||
if (audio_stream) {
|
||||
@@ -79,7 +87,6 @@ void FootageViewerWidget::StartFootageDrag()
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Drag start!";
|
||||
QDrag* drag = new QDrag(this);
|
||||
QMimeData* mimedata = new QMimeData();
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ private:
|
||||
|
||||
ViewerOutput* viewer_node_;
|
||||
|
||||
QWidget* waveform_view_;
|
||||
|
||||
private slots:
|
||||
void StartFootageDrag();
|
||||
|
||||
|
||||
@@ -47,9 +47,13 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setMargin(0);
|
||||
|
||||
// Set up stacked widget to allow switching away from the viewer widget
|
||||
stack_ = new QStackedWidget();
|
||||
layout->addWidget(stack_);
|
||||
|
||||
// Create main OpenGL-based view
|
||||
sizer_ = new ViewerSizer();
|
||||
layout->addWidget(sizer_);
|
||||
stack_->addWidget(sizer_);
|
||||
|
||||
gl_widget_ = new ViewerGLWidget();
|
||||
connect(gl_widget_, &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
|
||||
@@ -111,7 +115,13 @@ void ViewerWidget::TimeChangedEvent(const int64_t &i)
|
||||
|
||||
void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
|
||||
{
|
||||
SetTimebase(n->video_params().time_base());
|
||||
if (!n->video_params().time_base().isNull()) {
|
||||
SetTimebase(n->video_params().time_base());
|
||||
} else if (n->audio_params().sample_rate() > 0) {
|
||||
SetTimebase(rational(1, n->audio_params().sample_rate()));
|
||||
} else {
|
||||
SetTimebase(rational());
|
||||
}
|
||||
|
||||
connect(n, &ViewerOutput::TimebaseChanged, this, &ViewerWidget::SetTimebase);
|
||||
connect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot);
|
||||
@@ -139,7 +149,7 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
|
||||
{
|
||||
Pause();
|
||||
|
||||
SetTimebase(0);
|
||||
SetTimebase(rational());
|
||||
|
||||
disconnect(n, &ViewerOutput::TimebaseChanged, this, &ViewerWidget::SetTimebase);
|
||||
disconnect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot);
|
||||
@@ -171,6 +181,11 @@ void ViewerWidget::resizeEvent(QResizeEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
QStackedWidget *ViewerWidget::stack() const
|
||||
{
|
||||
return stack_;
|
||||
}
|
||||
|
||||
void ViewerWidget::TogglePlayPause()
|
||||
{
|
||||
if (IsPlaying()) {
|
||||
@@ -251,7 +266,11 @@ void ViewerWidget::PlayInternal(int speed)
|
||||
|
||||
controls_->ShowPauseButton();
|
||||
|
||||
connect(gl_widget_, &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||
if (stack_->currentWidget() == gl_widget_) {
|
||||
connect(gl_widget_, &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||
} else {
|
||||
connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerWidget::PushScrubbedAudio()
|
||||
@@ -387,7 +406,11 @@ void ViewerWidget::Pause()
|
||||
playback_speed_ = 0;
|
||||
controls_->ShowPlayButton();
|
||||
|
||||
disconnect(gl_widget_, &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||
if (stack_->currentWidget() == gl_widget_) {
|
||||
disconnect(gl_widget_, &ViewerGLWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||
} else {
|
||||
disconnect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,8 @@ protected:
|
||||
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
QStackedWidget* stack() const;
|
||||
|
||||
OpenGLBackend* video_renderer_;
|
||||
AudioBackend* audio_renderer_;
|
||||
|
||||
@@ -131,6 +133,8 @@ private:
|
||||
|
||||
int CalculateDivider();
|
||||
|
||||
QStackedWidget* stack_;
|
||||
|
||||
ViewerSizer* sizer_;
|
||||
|
||||
PlaybackControls* controls_;
|
||||
|
||||
Reference in New Issue
Block a user