Merge branch 'master' into nodeviewredux
This commit is contained in:
+7
-1
@@ -6,7 +6,13 @@ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
|||||||
|
|
||||||
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||||
|
|
||||||
sudo apt-get -y -o Dpkg::Options::="--force-overwrite" install qt511base qt511multimedia qt511svg qt511tools libavformat-dev libavcodec-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev cmake libopencolorio-dev libopenimageio-dev libgl1-mesa-dev
|
sudo apt-get -y -o Dpkg::Options::="--force-overwrite" install qt511base qt511multimedia qt511svg qt511tools libavformat-dev libavcodec-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev libopencolorio-dev libopenimageio-dev libgl1-mesa-dev
|
||||||
source /opt/qt*/bin/qt*-env.sh
|
source /opt/qt*/bin/qt*-env.sh
|
||||||
|
|
||||||
|
# Acquire latest cmake (apt somehow gets the wrong version?)
|
||||||
|
wget -c https://github.com/Kitware/CMake/releases/download/v3.17.2/cmake-3.17.2-Linux-x86_64.sh -O cmake.sh
|
||||||
|
chmod +x cmake.sh
|
||||||
|
./cmake.sh --skip-license --prefix=cmake --exclude-dir
|
||||||
|
export PATH=$PWD/cmake/bin:$PATH
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
+2
-2
@@ -14,7 +14,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
|
||||||
|
|
||||||
project(olive-editor VERSION 0.2.0 LANGUAGES CXX)
|
project(olive-editor VERSION 0.2.0 LANGUAGES CXX)
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ find_package(OpenGL REQUIRED)
|
|||||||
|
|
||||||
find_package(OpenColorIO REQUIRED)
|
find_package(OpenColorIO REQUIRED)
|
||||||
|
|
||||||
find_package(OpenImageIO REQUIRED)
|
find_package(OpenImageIO 1.6 REQUIRED)
|
||||||
|
|
||||||
find_package(OpenEXR REQUIRED)
|
find_package(OpenEXR REQUIRED)
|
||||||
|
|
||||||
|
|||||||
@@ -835,7 +835,7 @@ bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioRenderi
|
|||||||
p.channel_layout(),
|
p.channel_layout(),
|
||||||
FFmpegCommon::GetFFmpegSampleFormat(p.format()),
|
FFmpegCommon::GetFFmpegSampleFormat(p.format()),
|
||||||
p.sample_rate(),
|
p.sample_rate(),
|
||||||
static_cast<int64_t>(index_instance.stream()->codecpar->channel_layout),
|
channel_layout,
|
||||||
static_cast<AVSampleFormat>(index_instance.stream()->codecpar->format),
|
static_cast<AVSampleFormat>(index_instance.stream()->codecpar->format),
|
||||||
index_instance.stream()->codecpar->sample_rate,
|
index_instance.stream()->codecpar->sample_rate,
|
||||||
0,
|
0,
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ H264CRFSection::H264CRFSection(QWidget *parent) :
|
|||||||
crf_input->SetMinimum(kMinimumCRF);
|
crf_input->SetMinimum(kMinimumCRF);
|
||||||
crf_input->SetMaximum(kMaximumCRF);
|
crf_input->SetMaximum(kMaximumCRF);
|
||||||
crf_input->SetValue(kDefaultCRF);
|
crf_input->SetValue(kDefaultCRF);
|
||||||
|
crf_input->SetDefaultValue(kDefaultCRF);
|
||||||
layout->addWidget(crf_input);
|
layout->addWidget(crf_input);
|
||||||
|
|
||||||
connect(crf_slider_, &QSlider::valueChanged, crf_input, &IntegerSlider::SetValue);
|
connect(crf_slider_, &QSlider::valueChanged, crf_input, &IntegerSlider::SetValue);
|
||||||
|
|||||||
@@ -204,7 +204,9 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) :
|
|||||||
// Set defaults
|
// Set defaults
|
||||||
format_combobox_->setCurrentIndex(kFormatMPEG4);
|
format_combobox_->setCurrentIndex(kFormatMPEG4);
|
||||||
video_tab_->width_slider()->SetValue(viewer_node_->video_params().width());
|
video_tab_->width_slider()->SetValue(viewer_node_->video_params().width());
|
||||||
|
video_tab_->width_slider()->SetDefaultValue(viewer_node_->video_params().width());
|
||||||
video_tab_->height_slider()->SetValue(viewer_node_->video_params().height());
|
video_tab_->height_slider()->SetValue(viewer_node_->video_params().height());
|
||||||
|
video_tab_->height_slider()->SetDefaultValue(viewer_node_->video_params().height());
|
||||||
video_tab_->set_frame_rate(viewer_node_->video_params().time_base().flipped());
|
video_tab_->set_frame_rate(viewer_node_->video_params().time_base().flipped());
|
||||||
audio_tab_->set_sample_rate(viewer_node_->audio_params().sample_rate());
|
audio_tab_->set_sample_rate(viewer_node_->audio_params().sample_rate());
|
||||||
audio_tab_->set_channel_layout(viewer_node_->audio_params().channel_layout());
|
audio_tab_->set_channel_layout(viewer_node_->audio_params().channel_layout());
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ ExportAdvancedVideoDialog::ExportAdvancedVideoDialog(QWidget *parent) :
|
|||||||
|
|
||||||
thread_slider_ = new IntegerSlider();
|
thread_slider_ = new IntegerSlider();
|
||||||
thread_slider_->SetMinimum(0);
|
thread_slider_->SetMinimum(0);
|
||||||
|
thread_slider_->SetDefaultValue(0);
|
||||||
layout->addWidget(thread_slider_, row, 1);
|
layout->addWidget(thread_slider_, row, 1);
|
||||||
|
|
||||||
row++;
|
row++;
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ SpeedDurationDialog::SpeedDurationDialog(const rational& timebase, const QList<C
|
|||||||
speed_slider_ = new FloatSlider();
|
speed_slider_ = new FloatSlider();
|
||||||
speed_slider_->SetMinimum(0);
|
speed_slider_->SetMinimum(0);
|
||||||
speed_slider_->SetDisplayType(FloatSlider::kPercentage);
|
speed_slider_->SetDisplayType(FloatSlider::kPercentage);
|
||||||
|
speed_slider_->SetDefaultValue(1);
|
||||||
speed_layout->addWidget(speed_slider_, row, 1);
|
speed_layout->addWidget(speed_slider_, row, 1);
|
||||||
|
|
||||||
if (same_speed) {
|
if (same_speed) {
|
||||||
@@ -113,6 +114,9 @@ SpeedDurationDialog::SpeedDurationDialog(const rational& timebase, const QList<C
|
|||||||
duration_slider_->SetMinimum(1);
|
duration_slider_->SetMinimum(1);
|
||||||
speed_layout->addWidget(duration_slider_, row, 1);
|
speed_layout->addWidget(duration_slider_, row, 1);
|
||||||
|
|
||||||
|
// Calculate duration that would occur if the speed was 100%
|
||||||
|
duration_slider_->SetDefaultValue(GetUnadjustedLengthTimestamp(clips_.first()));
|
||||||
|
|
||||||
if (same_duration) {
|
if (same_duration) {
|
||||||
duration_slider_->SetValue(Timecode::time_to_timestamp(clips_.first()->length(), timebase_));
|
duration_slider_->SetValue(Timecode::time_to_timestamp(clips_.first()->length(), timebase_));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ PanNode::PanNode()
|
|||||||
samples_input_ = new NodeInput("samples_in", NodeParam::kSamples);
|
samples_input_ = new NodeInput("samples_in", NodeParam::kSamples);
|
||||||
AddInput(samples_input_);
|
AddInput(samples_input_);
|
||||||
|
|
||||||
panning_input_ = new NodeInput("panning_in", NodeParam::kFloat);
|
panning_input_ = new NodeInput("panning_in", NodeParam::kFloat, 0.0);
|
||||||
panning_input_->set_property("min", -1.0);
|
panning_input_->set_property("min", -1.0);
|
||||||
panning_input_->set_property("max", 1.0);
|
panning_input_->set_property("max", 1.0);
|
||||||
panning_input_->set_property("view", "percent");
|
panning_input_->set_property("view", "percent");
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ VolumeNode::VolumeNode()
|
|||||||
samples_input_ = new NodeInput("samples_in", NodeParam::kSamples);
|
samples_input_ = new NodeInput("samples_in", NodeParam::kSamples);
|
||||||
AddInput(samples_input_);
|
AddInput(samples_input_);
|
||||||
|
|
||||||
volume_input_ = new NodeInput("volume_in", NodeParam::kFloat, 1);
|
volume_input_ = new NodeInput("volume_in", NodeParam::kFloat, 1.0);
|
||||||
volume_input_->set_property("min", 0.0);
|
volume_input_->set_property("min", 0.0);
|
||||||
volume_input_->set_property("view", "db");
|
volume_input_->set_property("view", "db");
|
||||||
AddInput(volume_input_);
|
AddInput(volume_input_);
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ OLIVE_NAMESPACE_ENTER
|
|||||||
|
|
||||||
MatrixGenerator::MatrixGenerator()
|
MatrixGenerator::MatrixGenerator()
|
||||||
{
|
{
|
||||||
position_input_ = new NodeInput("pos_in", NodeParam::kVec2);
|
position_input_ = new NodeInput("pos_in", NodeParam::kVec2, QVector2D());
|
||||||
AddInput(position_input_);
|
AddInput(position_input_);
|
||||||
|
|
||||||
rotation_input_ = new NodeInput("rot_in", NodeParam::kFloat);
|
rotation_input_ = new NodeInput("rot_in", NodeParam::kFloat, 0.0f);
|
||||||
AddInput(rotation_input_);
|
AddInput(rotation_input_);
|
||||||
|
|
||||||
scale_input_ = new NodeInput("scale_in", NodeParam::kVec2, QVector2D(1.0f, 1.0f));
|
scale_input_ = new NodeInput("scale_in", NodeParam::kVec2, QVector2D(1.0f, 1.0f));
|
||||||
@@ -48,7 +48,7 @@ MatrixGenerator::MatrixGenerator()
|
|||||||
connect(uniform_scale_input_, &NodeInput::ValueChanged, this, &MatrixGenerator::UniformScaleChanged);
|
connect(uniform_scale_input_, &NodeInput::ValueChanged, this, &MatrixGenerator::UniformScaleChanged);
|
||||||
AddInput(uniform_scale_input_);
|
AddInput(uniform_scale_input_);
|
||||||
|
|
||||||
anchor_input_ = new NodeInput("anchor_in", NodeParam::kVec2);
|
anchor_input_ = new NodeInput("anchor_in", NodeParam::kVec2, QVector2D());
|
||||||
AddInput(anchor_input_);
|
AddInput(anchor_input_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -386,9 +386,22 @@ void NodeInput::GetDependencies(QList<Node *> &list, bool traverse, bool exclusi
|
|||||||
|
|
||||||
QVariant NodeInput::GetDefaultValue() const
|
QVariant NodeInput::GetDefaultValue() const
|
||||||
{
|
{
|
||||||
|
if (default_value_.isEmpty()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
return combine_track_values_into_normal_value(default_value_);
|
return combine_track_values_into_normal_value(default_value_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant NodeInput::GetDefaultValueForTrack(int track) const
|
||||||
|
{
|
||||||
|
if (default_value_.isEmpty()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
return default_value_.at(track);
|
||||||
|
}
|
||||||
|
|
||||||
QList<Node *> NodeInput::GetDependencies(bool traverse, bool exclusive_only) const
|
QList<Node *> NodeInput::GetDependencies(bool traverse, bool exclusive_only) const
|
||||||
{
|
{
|
||||||
QList<Node *> list;
|
QList<Node *> list;
|
||||||
|
|||||||
@@ -279,6 +279,8 @@ public:
|
|||||||
|
|
||||||
QVariant GetDefaultValue() const;
|
QVariant GetDefaultValue() const;
|
||||||
|
|
||||||
|
QVariant GetDefaultValueForTrack(int track) const;
|
||||||
|
|
||||||
QList<Node*> GetDependencies(bool traverse = true, bool exclusive_only = false) const;
|
QList<Node*> GetDependencies(bool traverse = true, bool exclusive_only = false) const;
|
||||||
|
|
||||||
QList<Node*> GetExclusiveDependencies() const;
|
QList<Node*> GetExclusiveDependencies() const;
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ MathNode::MathNode()
|
|||||||
method_in_->set_is_keyframable(false);
|
method_in_->set_is_keyframable(false);
|
||||||
AddInput(method_in_);
|
AddInput(method_in_);
|
||||||
|
|
||||||
param_a_in_ = new NodeInput(QStringLiteral("param_a_in"), NodeParam::kFloat);
|
param_a_in_ = new NodeInput(QStringLiteral("param_a_in"), NodeParam::kFloat, 0.0);
|
||||||
param_a_in_->set_property(QStringLiteral("decimalplaces"), 8);
|
param_a_in_->set_property(QStringLiteral("decimalplaces"), 8);
|
||||||
param_a_in_->set_property(QStringLiteral("autotrim"), true);
|
param_a_in_->set_property(QStringLiteral("autotrim"), true);
|
||||||
AddInput(param_a_in_);
|
AddInput(param_a_in_);
|
||||||
|
|
||||||
param_b_in_ = new NodeInput(QStringLiteral("param_b_in"), NodeParam::kFloat);
|
param_b_in_ = new NodeInput(QStringLiteral("param_b_in"), NodeParam::kFloat, 0.0);
|
||||||
param_b_in_->set_property(QStringLiteral("decimalplaces"), 8);
|
param_b_in_->set_property(QStringLiteral("decimalplaces"), 8);
|
||||||
param_b_in_->set_property(QStringLiteral("autotrim"), true);
|
param_b_in_->set_property(QStringLiteral("autotrim"), true);
|
||||||
AddInput(param_b_in_);
|
AddInput(param_b_in_);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ TrigonometryNode::TrigonometryNode()
|
|||||||
method_in_->set_is_keyframable(false);
|
method_in_->set_is_keyframable(false);
|
||||||
AddInput(method_in_);
|
AddInput(method_in_);
|
||||||
|
|
||||||
x_in_ = new NodeInput(QStringLiteral("x_in"), NodeParam::kFloat);
|
x_in_ = new NodeInput(QStringLiteral("x_in"), NodeParam::kFloat, 0.0);
|
||||||
AddInput(x_in_);
|
AddInput(x_in_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,4 +111,11 @@ void ViewerPanelBase::CreateScopePanel(ScopePanel::Type type)
|
|||||||
vw->ForceUpdate();
|
vw->ForceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewerPanelBase::closeEvent(QCloseEvent *e)
|
||||||
|
{
|
||||||
|
static_cast<ViewerWidget*>(GetTimeBasedWidget())->Pause();
|
||||||
|
|
||||||
|
TimeBasedPanel::closeEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ public slots:
|
|||||||
protected:
|
protected:
|
||||||
void CreateScopePanel(ScopePanel::Type type);
|
void CreateScopePanel(ScopePanel::Type type);
|
||||||
|
|
||||||
|
virtual void closeEvent(QCloseEvent* e) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ const QList<QWidget *> &NodeParamViewWidgetBridge::widgets() const
|
|||||||
|
|
||||||
void NodeParamViewWidgetBridge::CreateWidgets()
|
void NodeParamViewWidgetBridge::CreateWidgets()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (input_->IsArray()) {
|
if (input_->IsArray()) {
|
||||||
|
|
||||||
NodeParamViewArrayWidget* w = new NodeParamViewArrayWidget(static_cast<NodeInputArray*>(input_));
|
NodeParamViewArrayWidget* w = new NodeParamViewArrayWidget(static_cast<NodeInputArray*>(input_));
|
||||||
@@ -91,6 +92,7 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
|||||||
case NodeParam::kInt:
|
case NodeParam::kInt:
|
||||||
{
|
{
|
||||||
IntegerSlider* slider = new IntegerSlider();
|
IntegerSlider* slider = new IntegerSlider();
|
||||||
|
slider->SetDefaultValue(input_->GetDefaultValue());
|
||||||
widgets_.append(slider);
|
widgets_.append(slider);
|
||||||
connect(slider, &IntegerSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
connect(slider, &IntegerSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||||
break;
|
break;
|
||||||
@@ -363,6 +365,7 @@ void NodeParamViewWidgetBridge::CreateSliders(int count)
|
|||||||
{
|
{
|
||||||
for (int i=0;i<count;i++) {
|
for (int i=0;i<count;i++) {
|
||||||
FloatSlider* fs = new FloatSlider();
|
FloatSlider* fs = new FloatSlider();
|
||||||
|
fs->SetDefaultValue(input_->GetDefaultValueForTrack(i));
|
||||||
widgets_.append(fs);
|
widgets_.append(fs);
|
||||||
connect(fs, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
connect(fs, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,12 +45,13 @@ SliderBase::SliderBase(Mode mode, QWidget *parent) :
|
|||||||
editor_ = new FocusableLineEdit(this);
|
editor_ = new FocusableLineEdit(this);
|
||||||
addWidget(editor_);
|
addWidget(editor_);
|
||||||
|
|
||||||
connect(label_, SIGNAL(drag_start()), this, SLOT(LabelPressed()));
|
connect(label_, &SliderLabel::drag_start, this, &SliderBase::LabelPressed);
|
||||||
connect(label_, SIGNAL(dragged(int)), this, SLOT(LabelDragged(int)));
|
connect(label_, &SliderLabel::dragged, this, &SliderBase::LabelDragged);
|
||||||
connect(label_, SIGNAL(drag_stop()), this, SLOT(LabelClicked()));
|
connect(label_, &SliderLabel::drag_stop, this, &SliderBase::LabelClicked);
|
||||||
connect(label_, SIGNAL(focused()), this, SLOT(LabelClicked()));
|
connect(label_, &SliderLabel::focused, this, &SliderBase::LabelClicked);
|
||||||
connect(editor_, SIGNAL(Confirmed()), this, SLOT(LineEditConfirmed()));
|
connect(label_, &SliderLabel::RequestReset, this, &SliderBase::ResetValue);
|
||||||
connect(editor_, SIGNAL(Cancelled()), this, SLOT(LineEditCancelled()));
|
connect(editor_, &FocusableLineEdit::Confirmed, this, &SliderBase::LineEditConfirmed);
|
||||||
|
connect(editor_, &FocusableLineEdit::Cancelled, this, &SliderBase::LineEditCancelled);
|
||||||
|
|
||||||
// Set valid cursor based on mode
|
// Set valid cursor based on mode
|
||||||
switch (mode_) {
|
switch (mode_) {
|
||||||
@@ -137,6 +138,11 @@ void SliderBase::SetValue(const QVariant &v)
|
|||||||
UpdateLabel(value_);
|
UpdateLabel(value_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SliderBase::SetDefaultValue(const QVariant &v)
|
||||||
|
{
|
||||||
|
default_value_ = v;
|
||||||
|
}
|
||||||
|
|
||||||
void SliderBase::SetMinimumInternal(const QVariant &v)
|
void SliderBase::SetMinimumInternal(const QVariant &v)
|
||||||
{
|
{
|
||||||
min_value_ = v;
|
min_value_ = v;
|
||||||
@@ -241,7 +247,6 @@ void SliderBase::LabelClicked()
|
|||||||
emit ValueChanged(value_);
|
emit ValueChanged(value_);
|
||||||
} else {
|
} else {
|
||||||
// This was a simple click
|
// This was a simple click
|
||||||
|
|
||||||
// Load label's text into editor
|
// Load label's text into editor
|
||||||
editor_->setText(ValueToString(value_));
|
editor_->setText(ValueToString(value_));
|
||||||
|
|
||||||
@@ -327,4 +332,12 @@ void SliderBase::LineEditCancelled()
|
|||||||
label_->blockSignals(false);
|
label_->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SliderBase::ResetValue()
|
||||||
|
{
|
||||||
|
if (!default_value_.isNull()) {
|
||||||
|
SetValue(default_value_);
|
||||||
|
emit ValueChanged(value_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ public:
|
|||||||
|
|
||||||
void SetAlignment(Qt::Alignment alignment);
|
void SetAlignment(Qt::Alignment alignment);
|
||||||
|
|
||||||
|
void SetDefaultValue(const QVariant& v);
|
||||||
|
|
||||||
bool IsTristate() const;
|
bool IsTristate() const;
|
||||||
void SetTristate();
|
void SetTristate();
|
||||||
|
|
||||||
@@ -89,6 +91,7 @@ private:
|
|||||||
FocusableLineEdit* editor_;
|
FocusableLineEdit* editor_;
|
||||||
|
|
||||||
QVariant value_;
|
QVariant value_;
|
||||||
|
QVariant default_value_;
|
||||||
|
|
||||||
bool has_min_;
|
bool has_min_;
|
||||||
QVariant min_value_;
|
QVariant min_value_;
|
||||||
@@ -120,6 +123,8 @@ private slots:
|
|||||||
void LineEditConfirmed();
|
void LineEditConfirmed();
|
||||||
|
|
||||||
void LineEditCancelled();
|
void LineEditCancelled();
|
||||||
|
|
||||||
|
void ResetValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -31,7 +31,8 @@
|
|||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
SliderLabel::SliderLabel(QWidget *parent) :
|
SliderLabel::SliderLabel(QWidget *parent) :
|
||||||
QLabel(parent)
|
QLabel(parent),
|
||||||
|
dragging_(false)
|
||||||
{
|
{
|
||||||
QPalette p = palette();
|
QPalette p = palette();
|
||||||
|
|
||||||
@@ -53,51 +54,70 @@ SliderLabel::SliderLabel(QWidget *parent) :
|
|||||||
setFocusPolicy(Qt::TabFocus);
|
setFocusPolicy(Qt::TabFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SliderLabel::mousePressEvent(QMouseEvent *)
|
void SliderLabel::mousePressEvent(QMouseEvent *e)
|
||||||
{
|
{
|
||||||
emit drag_start();
|
if (e->modifiers() & Qt::AltModifier) {
|
||||||
|
|
||||||
|
emit RequestReset();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
CGAssociateMouseAndMouseCursorPosition(false);
|
CGAssociateMouseAndMouseCursorPosition(false);
|
||||||
CGDisplayHideCursor(kCGDirectMainDisplay);
|
CGDisplayHideCursor(kCGDirectMainDisplay);
|
||||||
CGGetLastMouseDelta(nullptr, nullptr);
|
CGGetLastMouseDelta(nullptr, nullptr);
|
||||||
#else
|
#else
|
||||||
drag_start_ = QCursor::pos();
|
drag_start_ = QCursor::pos();
|
||||||
|
|
||||||
static_cast<QGuiApplication*>(QApplication::instance())->setOverrideCursor(Qt::BlankCursor);
|
static_cast<QGuiApplication*>(QApplication::instance())->setOverrideCursor(Qt::BlankCursor);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
emit drag_start();
|
||||||
|
|
||||||
|
dragging_ = true;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SliderLabel::mouseMoveEvent(QMouseEvent *)
|
void SliderLabel::mouseMoveEvent(QMouseEvent *)
|
||||||
{
|
{
|
||||||
int32_t x_mvmt, y_mvmt;
|
if (dragging_) {
|
||||||
|
|
||||||
// Keep cursor in the same position
|
int32_t x_mvmt, y_mvmt;
|
||||||
|
|
||||||
|
// Keep cursor in the same position
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
CGGetLastMouseDelta(&x_mvmt, &y_mvmt);
|
CGGetLastMouseDelta(&x_mvmt, &y_mvmt);
|
||||||
#else
|
#else
|
||||||
QPoint current_pos = QCursor::pos();
|
QPoint current_pos = QCursor::pos();
|
||||||
|
|
||||||
x_mvmt = current_pos.x() - drag_start_.x();
|
x_mvmt = current_pos.x() - drag_start_.x();
|
||||||
y_mvmt = drag_start_.y() - current_pos.y();
|
y_mvmt = drag_start_.y() - current_pos.y();
|
||||||
|
|
||||||
QCursor::setPos(drag_start_);
|
QCursor::setPos(drag_start_);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
emit dragged(x_mvmt + y_mvmt);
|
emit dragged(x_mvmt + y_mvmt);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SliderLabel::mouseReleaseEvent(QMouseEvent *)
|
void SliderLabel::mouseReleaseEvent(QMouseEvent *)
|
||||||
{
|
{
|
||||||
|
if (dragging_) {
|
||||||
|
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
CGAssociateMouseAndMouseCursorPosition(true);
|
CGAssociateMouseAndMouseCursorPosition(true);
|
||||||
CGDisplayShowCursor(kCGDirectMainDisplay);
|
CGDisplayShowCursor(kCGDirectMainDisplay);
|
||||||
#else
|
#else
|
||||||
static_cast<QGuiApplication*>(QApplication::instance())->restoreOverrideCursor();
|
static_cast<QGuiApplication*>(QApplication::instance())->restoreOverrideCursor();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Emit a clicked signal
|
emit drag_stop();
|
||||||
emit drag_stop();
|
|
||||||
|
dragging_ = false;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SliderLabel::focusInEvent(QFocusEvent *event)
|
void SliderLabel::focusInEvent(QFocusEvent *event)
|
||||||
|
|||||||
@@ -51,10 +51,12 @@ signals:
|
|||||||
|
|
||||||
void focused();
|
void focused();
|
||||||
|
|
||||||
|
void RequestReset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPoint drag_start_;
|
QPoint drag_start_;
|
||||||
|
|
||||||
bool cancel_mm_event_;
|
bool dragging_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ set(OLIVE_SOURCES
|
|||||||
widget/viewer/viewer.cpp
|
widget/viewer/viewer.cpp
|
||||||
widget/viewer/viewerdisplay.h
|
widget/viewer/viewerdisplay.h
|
||||||
widget/viewer/viewerdisplay.cpp
|
widget/viewer/viewerdisplay.cpp
|
||||||
|
widget/viewer/viewerplaybacktimer.h
|
||||||
|
widget/viewer/viewerplaybacktimer.cpp
|
||||||
|
widget/viewer/viewerqueue.h
|
||||||
widget/viewer/viewersafemargininfo.h
|
widget/viewer/viewersafemargininfo.h
|
||||||
widget/viewer/viewersizer.h
|
widget/viewer/viewersizer.h
|
||||||
widget/viewer/viewersizer.cpp
|
widget/viewer/viewersizer.cpp
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) :
|
|||||||
audio_node_ = new AudioInput();
|
audio_node_ = new AudioInput();
|
||||||
viewer_node_ = new ViewerOutput();
|
viewer_node_ = new ViewerOutput();
|
||||||
|
|
||||||
connect(main_gl_widget(), &ViewerDisplayWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag);
|
connect(display_widget(), &ViewerDisplayWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag);
|
||||||
|
|
||||||
controls_->SetAudioVideoDragButtonsVisible(true);
|
controls_->SetAudioVideoDragButtonsVisible(true);
|
||||||
connect(controls_, &PlaybackControls::VideoPressed, this, &FootageViewerWidget::StartVideoDrag);
|
connect(controls_, &PlaybackControls::VideoPressed, this, &FootageViewerWidget::StartVideoDrag);
|
||||||
|
|||||||
+203
-59
@@ -63,15 +63,13 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
|||||||
sizer_ = new ViewerSizer();
|
sizer_ = new ViewerSizer();
|
||||||
stack_->addWidget(sizer_);
|
stack_->addWidget(sizer_);
|
||||||
|
|
||||||
ViewerDisplayWidget* main_widget = new ViewerDisplayWidget();
|
display_widget_ = new ViewerDisplayWidget();
|
||||||
connect(main_widget, &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
|
connect(display_widget_, &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
|
||||||
connect(main_widget, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor);
|
connect(display_widget_, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor);
|
||||||
connect(main_widget, &ViewerDisplayWidget::LoadedBuffer, this, &ViewerWidget::LoadedBuffer);
|
connect(display_widget_, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged);
|
||||||
connect(main_widget, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged);
|
connect(display_widget_, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged);
|
||||||
connect(main_widget, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged);
|
connect(sizer_, &ViewerSizer::RequestMatrix, display_widget_, &ViewerDisplayWidget::SetMatrix);
|
||||||
connect(sizer_, &ViewerSizer::RequestMatrix, main_widget, &ViewerDisplayWidget::SetMatrix);
|
sizer_->SetWidget(display_widget_);
|
||||||
sizer_->SetWidget(main_widget);
|
|
||||||
gl_widgets_.append(main_widget);
|
|
||||||
|
|
||||||
// Create waveform view when audio is connected and video isn't
|
// Create waveform view when audio is connected and video isn't
|
||||||
waveform_view_ = new AudioWaveformView();
|
waveform_view_ = new AudioWaveformView();
|
||||||
@@ -117,6 +115,15 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
|||||||
SetAutoMaxScrollBar(true);
|
SetAutoMaxScrollBar(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ViewerWidget::~ViewerWidget()
|
||||||
|
{
|
||||||
|
QList<ViewerWindow*> windows = windows_;
|
||||||
|
|
||||||
|
foreach (ViewerWindow* window, windows) {
|
||||||
|
delete window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ViewerWidget::TimeChangedEvent(const int64_t &i)
|
void ViewerWidget::TimeChangedEvent(const int64_t &i)
|
||||||
{
|
{
|
||||||
if (!time_changed_from_timer_) {
|
if (!time_changed_from_timer_) {
|
||||||
@@ -133,7 +140,7 @@ void ViewerWidget::TimeChangedEvent(const int64_t &i)
|
|||||||
|
|
||||||
PushScrubbedAudio();
|
PushScrubbedAudio();
|
||||||
|
|
||||||
main_gl_widget()->SetTime(time_set);
|
display_widget_->SetTime(time_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_time_ = i;
|
last_time_ = i;
|
||||||
@@ -170,8 +177,9 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
|
|||||||
using_manager = nullptr;
|
using_manager = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
|
display_widget_->ConnectColorManager(using_manager);
|
||||||
glw->ConnectColorManager(using_manager);
|
foreach (ViewerWindow* window, windows_) {
|
||||||
|
window->display_widget()->ConnectColorManager(using_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
divider_ = CalculateDivider();
|
divider_ = CalculateDivider();
|
||||||
@@ -202,8 +210,9 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
|
|||||||
// Effectively disables the viewer and clears the state
|
// Effectively disables the viewer and clears the state
|
||||||
SizeChangedSlot(0, 0);
|
SizeChangedSlot(0, 0);
|
||||||
|
|
||||||
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
|
display_widget_->DisconnectColorManager();
|
||||||
glw->DisconnectColorManager();
|
foreach (ViewerWindow* window, windows_) {
|
||||||
|
window->display_widget()->DisconnectColorManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
waveform_view_->ConnectTimelinePoints(nullptr);
|
waveform_view_->ConnectTimelinePoints(nullptr);
|
||||||
@@ -236,14 +245,9 @@ void ViewerWidget::resizeEvent(QResizeEvent *event)
|
|||||||
UpdateMinimumScale();
|
UpdateMinimumScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QList<ViewerDisplayWidget*> &ViewerWidget::gl_widgets() const
|
ViewerDisplayWidget *ViewerWidget::display_widget() const
|
||||||
{
|
{
|
||||||
return gl_widgets_;
|
return display_widget_;
|
||||||
}
|
|
||||||
|
|
||||||
ViewerDisplayWidget *ViewerWidget::main_gl_widget() const
|
|
||||||
{
|
|
||||||
return gl_widgets_.first();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::TogglePlayPause()
|
void ViewerWidget::TogglePlayPause()
|
||||||
@@ -282,8 +286,9 @@ void ViewerWidget::SetOverrideSize(int width, int height)
|
|||||||
|
|
||||||
void ViewerWidget::SetMatrix(const QMatrix4x4 &mat)
|
void ViewerWidget::SetMatrix(const QMatrix4x4 &mat)
|
||||||
{
|
{
|
||||||
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
|
display_widget_->SetMatrix(mat);
|
||||||
glw->SetMatrix(mat);
|
foreach (ViewerWindow* vw, windows_) {
|
||||||
|
vw->display_widget()->SetMatrix(mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,19 +311,19 @@ void ViewerWidget::SetFullScreen(QScreen *screen)
|
|||||||
|
|
||||||
ViewerWindow* vw = new ViewerWindow(this);
|
ViewerWindow* vw = new ViewerWindow(this);
|
||||||
|
|
||||||
vw->showFullScreen();
|
|
||||||
vw->setGeometry(screen->geometry());
|
vw->setGeometry(screen->geometry());
|
||||||
vw->gl_widget()->ConnectColorManager(main_gl_widget()->color_manager());
|
vw->showFullScreen();
|
||||||
main_gl_widget()->ConnectSibling(vw->gl_widget());
|
vw->display_widget()->ConnectColorManager(color_manager());
|
||||||
connect(vw, &ViewerWindow::destroyed, this, &ViewerWidget::WindowAboutToClose);
|
connect(vw, &ViewerWindow::destroyed, this, &ViewerWidget::WindowAboutToClose);
|
||||||
connect(vw->gl_widget(), &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
|
connect(vw->display_widget(), &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
|
||||||
|
|
||||||
if (GetConnectedNode()) {
|
if (GetConnectedNode()) {
|
||||||
vw->SetResolution(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height());
|
vw->SetResolution(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vw->display_widget()->SetImage(display_widget_->last_loaded_buffer());
|
||||||
|
|
||||||
windows_.append(vw);
|
windows_.append(vw);
|
||||||
gl_widgets_.append(vw->gl_widget());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::ForceUpdate()
|
void ViewerWidget::ForceUpdate()
|
||||||
@@ -334,26 +339,45 @@ VideoRenderBackend *ViewerWidget::video_renderer() const
|
|||||||
|
|
||||||
ColorManager *ViewerWidget::color_manager() const
|
ColorManager *ViewerWidget::color_manager() const
|
||||||
{
|
{
|
||||||
return main_gl_widget()->color_manager();
|
return display_widget_->color_manager();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::SetGizmos(Node *node)
|
void ViewerWidget::SetGizmos(Node *node)
|
||||||
{
|
{
|
||||||
main_gl_widget()->SetTimeTarget(GetConnectedNode());
|
display_widget_->SetTimeTarget(GetConnectedNode());
|
||||||
main_gl_widget()->SetGizmos(node);
|
display_widget_->SetGizmos(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::UpdateTextureFromNode(const rational& time)
|
void ViewerWidget::UpdateTextureFromNode(const rational& time)
|
||||||
{
|
{
|
||||||
if (!GetConnectedNode() || time >= GetConnectedNode()->Length()) {
|
{
|
||||||
main_gl_widget()->SetImage(QString());
|
QMutexLocker locker(playback_queue_.lock());
|
||||||
video_renderer_->UpdateLastRequestedTime(time);
|
|
||||||
} else {
|
while (!playback_queue_.isEmpty()) {
|
||||||
QString frame_fn = video_renderer_->GetCachedFrame(time);
|
const ViewerPlaybackFrame& pf = playback_queue_.first();
|
||||||
|
|
||||||
|
if (pf.timestamp == time) {
|
||||||
|
// Frame was in queue, no need to decode anything
|
||||||
|
SetDisplayImage(pf.frame, true);
|
||||||
|
QtConcurrent::run(this, &ViewerWidget::FillPlaybackQueue);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
playback_queue_.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frame was not in queue, will require decoding
|
||||||
|
if (FrameExistsAtTime(time)) {
|
||||||
|
QString frame_fn = GetCachedFilenameFromTime(time);
|
||||||
|
|
||||||
if (!frame_fn.isEmpty()) {
|
if (!frame_fn.isEmpty()) {
|
||||||
main_gl_widget()->SetImage(frame_fn);
|
FramePtr f = DecodeCachedImage(frame_fn);
|
||||||
|
SetDisplayImage(f, false);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
SetDisplayImage(nullptr, false);
|
||||||
|
video_renderer_->UpdateLastRequestedTime(time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,11 +396,21 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
|
|||||||
QString audio_fn = audio_renderer_->CachePathName();
|
QString audio_fn = audio_renderer_->CachePathName();
|
||||||
if (!audio_fn.isEmpty()) {
|
if (!audio_fn.isEmpty()) {
|
||||||
AudioManager::instance()->SetOutputParams(audio_renderer_->params());
|
AudioManager::instance()->SetOutputParams(audio_renderer_->params());
|
||||||
AudioManager::instance()->StartOutput(audio_fn, audio_renderer_->params().time_to_bytes(GetTime()), playback_speed_);
|
AudioManager::instance()->StartOutput(audio_fn,
|
||||||
|
audio_renderer_->params().time_to_bytes(GetTime()),
|
||||||
|
playback_speed_);
|
||||||
}
|
}
|
||||||
|
|
||||||
start_msec_ = QDateTime::currentMSecsSinceEpoch();
|
int64_t start_time = ruler()->GetTime();
|
||||||
start_timestamp_ = ruler()->GetTime();
|
|
||||||
|
playback_queue_next_frame_ = start_time;
|
||||||
|
FillPlaybackQueue();
|
||||||
|
|
||||||
|
playback_timer_.Start(start_time, playback_speed_, timebase_dbl());
|
||||||
|
|
||||||
|
foreach (ViewerWindow* window, windows_) {
|
||||||
|
window->Play(start_time, playback_speed_, timebase());
|
||||||
|
}
|
||||||
|
|
||||||
controls_->ShowPauseButton();
|
controls_->ShowPauseButton();
|
||||||
|
|
||||||
@@ -385,7 +419,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
|
|||||||
if (playback_is_audio_only_) {
|
if (playback_is_audio_only_) {
|
||||||
connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
|
connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||||
} else {
|
} else {
|
||||||
connect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
|
connect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,7 +449,7 @@ int ViewerWidget::CalculateDivider()
|
|||||||
{
|
{
|
||||||
if (GetConnectedNode() && Config::Current()["AutoSelectDivider"].toBool()) {
|
if (GetConnectedNode() && Config::Current()["AutoSelectDivider"].toBool()) {
|
||||||
int long_side_of_video = qMax(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height());
|
int long_side_of_video = qMax(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height());
|
||||||
int long_side_of_widget = qMax(main_gl_widget()->width(), main_gl_widget()->height());
|
int long_side_of_widget = qMax(display_widget_->width(), display_widget_->height());
|
||||||
|
|
||||||
return qMax(1, long_side_of_video / long_side_of_widget);
|
return qMax(1, long_side_of_video / long_side_of_widget);
|
||||||
}
|
}
|
||||||
@@ -442,6 +476,113 @@ void ViewerWidget::SetColorTransform(const ColorTransform &transform, ViewerDisp
|
|||||||
sender->SetColorTransform(transform);
|
sender->SetColorTransform(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewerWidget::FillPlaybackQueue()
|
||||||
|
{
|
||||||
|
playback_queue_.lock()->lock();
|
||||||
|
foreach (ViewerWindow* window, windows_) {
|
||||||
|
window->queue()->lock()->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (playback_queue_.size() < 8) {
|
||||||
|
// Load frame from cache
|
||||||
|
FramePtr frame = nullptr;
|
||||||
|
|
||||||
|
rational rtime = Timecode::timestamp_to_time(playback_queue_next_frame_,
|
||||||
|
timebase());
|
||||||
|
|
||||||
|
QString frame_fn = GetCachedFilenameFromTime(rtime);
|
||||||
|
|
||||||
|
if (!frame_fn.isEmpty()) {
|
||||||
|
frame = DecodeCachedImage(frame_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewerPlaybackFrame f = {rtime, frame};
|
||||||
|
|
||||||
|
playback_queue_.append(f);
|
||||||
|
|
||||||
|
foreach (ViewerWindow* window, windows_) {
|
||||||
|
window->queue()->append(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!playback_speed_) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
playback_queue_next_frame_ += playback_speed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ViewerWindow* window, windows_) {
|
||||||
|
window->queue()->lock()->unlock();
|
||||||
|
}
|
||||||
|
playback_queue_.lock()->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ViewerWidget::GetCachedFilenameFromTime(const rational &time)
|
||||||
|
{
|
||||||
|
if (FrameExistsAtTime(time)) {
|
||||||
|
return video_renderer_->GetCachedFrame(time);
|
||||||
|
} else {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ViewerWidget::FrameExistsAtTime(const rational &time)
|
||||||
|
{
|
||||||
|
return GetConnectedNode() && time < GetConnectedNode()->Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
FramePtr ViewerWidget::DecodeCachedImage(const QString &fn)
|
||||||
|
{
|
||||||
|
FramePtr frame = nullptr;
|
||||||
|
|
||||||
|
if (!fn.isEmpty() && QFileInfo::exists(fn)) {
|
||||||
|
auto input = OIIO::ImageInput::open(fn.toStdString());
|
||||||
|
|
||||||
|
if (input) {
|
||||||
|
|
||||||
|
PixelFormat::Format image_format = PixelFormat::OIIOFormatToOliveFormat(input->spec().format,
|
||||||
|
input->spec().nchannels == kRGBAChannels);
|
||||||
|
|
||||||
|
frame = Frame::Create();
|
||||||
|
|
||||||
|
frame->set_video_params(VideoRenderingParams(input->spec().width,
|
||||||
|
input->spec().height,
|
||||||
|
image_format));
|
||||||
|
|
||||||
|
frame->allocate();
|
||||||
|
|
||||||
|
input->read_image(input->spec().format,
|
||||||
|
frame->data(),
|
||||||
|
OIIO::AutoStride,
|
||||||
|
frame->linesize_bytes());
|
||||||
|
|
||||||
|
input->close();
|
||||||
|
|
||||||
|
#if OIIO_VERSION < 10903
|
||||||
|
OIIO::ImageInput::destroy(input);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qWarning() << "OIIO Error:" << OIIO::geterror().c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only)
|
||||||
|
{
|
||||||
|
display_widget_->SetImage(frame);
|
||||||
|
|
||||||
|
if (!main_only) {
|
||||||
|
foreach (ViewerWindow* vw, windows_) {
|
||||||
|
vw->display_widget()->SetImage(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit LoadedBuffer(frame.get());
|
||||||
|
}
|
||||||
|
|
||||||
void ViewerWidget::UpdateStack()
|
void ViewerWidget::UpdateStack()
|
||||||
{
|
{
|
||||||
if (GetConnectedNode()
|
if (GetConnectedNode()
|
||||||
@@ -515,10 +656,7 @@ void ViewerWidget::ContextMenuSetCustomSafeMargins()
|
|||||||
|
|
||||||
void ViewerWidget::WindowAboutToClose()
|
void ViewerWidget::WindowAboutToClose()
|
||||||
{
|
{
|
||||||
ViewerWindow* vw = static_cast<ViewerWindow*>(sender());
|
windows_.removeOne(static_cast<ViewerWindow*>(sender()));
|
||||||
|
|
||||||
windows_.removeAll(vw);
|
|
||||||
gl_widgets_.removeAll(vw->gl_widget());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::ContextMenuScopeTriggered(QAction *action)
|
void ViewerWidget::ContextMenuScopeTriggered(QAction *action)
|
||||||
@@ -528,9 +666,7 @@ void ViewerWidget::ContextMenuScopeTriggered(QAction *action)
|
|||||||
|
|
||||||
void ViewerWidget::RendererGeneratedFrame(FramePtr f)
|
void ViewerWidget::RendererGeneratedFrame(FramePtr f)
|
||||||
{
|
{
|
||||||
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
|
SetDisplayImage(f, false);
|
||||||
glw->SetImageFromLoadBuffer(f.get());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::UpdateRendererParameters()
|
void ViewerWidget::UpdateRendererParameters()
|
||||||
@@ -551,7 +687,7 @@ void ViewerWidget::UpdateRendererParameters()
|
|||||||
video_renderer_->InvalidateCache(TimeRange(0, GetConnectedNode()->Length()), nullptr);
|
video_renderer_->InvalidateCache(TimeRange(0, GetConnectedNode()->Length()), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
main_gl_widget()->SetVideoParams(vparam);
|
display_widget_->SetVideoParams(vparam);
|
||||||
|
|
||||||
AudioRenderingParams aparam(GetConnectedNode()->audio_params(),
|
AudioRenderingParams aparam(GetConnectedNode()->audio_params(),
|
||||||
SampleFormat::kInternalFormat);
|
SampleFormat::kInternalFormat);
|
||||||
@@ -708,7 +844,17 @@ void ViewerWidget::Pause()
|
|||||||
if (playback_is_audio_only_) {
|
if (playback_is_audio_only_) {
|
||||||
disconnect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
|
disconnect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||||
} else {
|
} else {
|
||||||
disconnect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
|
disconnect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ViewerWindow* window, windows_) {
|
||||||
|
window->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
playback_queue_.lock()->lock();
|
||||||
|
playback_queue_.clear();
|
||||||
|
playback_queue_.lock()->unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -754,13 +900,15 @@ void ViewerWidget::ShuttleRight()
|
|||||||
|
|
||||||
void ViewerWidget::SetColorTransform(const ColorTransform &transform)
|
void ViewerWidget::SetColorTransform(const ColorTransform &transform)
|
||||||
{
|
{
|
||||||
SetColorTransform(transform, main_gl_widget());
|
SetColorTransform(transform, display_widget_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::SetSignalCursorColorEnabled(bool e)
|
void ViewerWidget::SetSignalCursorColorEnabled(bool e)
|
||||||
{
|
{
|
||||||
foreach (ViewerDisplayWidget* glw, gl_widgets_) {
|
display_widget_->SetSignalCursorColorEnabled(e);
|
||||||
glw->SetSignalCursorColorEnabled(e);
|
|
||||||
|
foreach (ViewerWindow* vw, windows_) {
|
||||||
|
vw->display_widget()->SetSignalCursorColorEnabled(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,11 +924,7 @@ void ViewerWidget::TimebaseChangedEvent(const rational &timebase)
|
|||||||
|
|
||||||
void ViewerWidget::PlaybackTimerUpdate()
|
void ViewerWidget::PlaybackTimerUpdate()
|
||||||
{
|
{
|
||||||
int64_t real_time = QDateTime::currentMSecsSinceEpoch() - start_msec_;
|
int64_t current_time = playback_timer_.GetTimestampNow();
|
||||||
|
|
||||||
int64_t frames_since_start = qRound(static_cast<double>(real_time) / (timebase_dbl() * 1000));
|
|
||||||
|
|
||||||
int64_t current_time = start_timestamp_ + frames_since_start * playback_speed_;
|
|
||||||
|
|
||||||
int64_t min_time, max_time;
|
int64_t min_time, max_time;
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
#include "render/backend/opengl/opengltexture.h"
|
#include "render/backend/opengl/opengltexture.h"
|
||||||
#include "render/backend/audio/audiobackend.h"
|
#include "render/backend/audio/audiobackend.h"
|
||||||
#include "viewerdisplay.h"
|
#include "viewerdisplay.h"
|
||||||
|
#include "viewerplaybacktimer.h"
|
||||||
|
#include "viewerqueue.h"
|
||||||
#include "viewersizer.h"
|
#include "viewersizer.h"
|
||||||
#include "viewerwindow.h"
|
#include "viewerwindow.h"
|
||||||
#include "widget/playbackcontrols/playbackcontrols.h"
|
#include "widget/playbackcontrols/playbackcontrols.h"
|
||||||
@@ -52,6 +54,8 @@ class ViewerWidget : public TimeBasedWidget
|
|||||||
public:
|
public:
|
||||||
ViewerWidget(QWidget* parent = nullptr);
|
ViewerWidget(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
virtual ~ViewerWidget() override;
|
||||||
|
|
||||||
void SetPlaybackControlsEnabled(bool enabled);
|
void SetPlaybackControlsEnabled(bool enabled);
|
||||||
|
|
||||||
void SetTimeRulerEnabled(bool enabled);
|
void SetTimeRulerEnabled(bool enabled);
|
||||||
@@ -116,7 +120,7 @@ signals:
|
|||||||
void CursorColor(const Color& reference, const Color& display);
|
void CursorColor(const Color& reference, const Color& display);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wrapper for ViewerGLWidget::LoadedBuffer()
|
* @brief Signal emitted when a new frame is loaded
|
||||||
*/
|
*/
|
||||||
void LoadedBuffer(Frame* load_buffer);
|
void LoadedBuffer(Frame* load_buffer);
|
||||||
|
|
||||||
@@ -154,8 +158,7 @@ protected:
|
|||||||
|
|
||||||
PlaybackControls* controls_;
|
PlaybackControls* controls_;
|
||||||
|
|
||||||
const QList<ViewerDisplayWidget *> &gl_widgets() const;
|
ViewerDisplayWidget* display_widget() const;
|
||||||
ViewerDisplayWidget* main_gl_widget() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateTimeInternal(int64_t i);
|
void UpdateTimeInternal(int64_t i);
|
||||||
@@ -172,14 +175,21 @@ private:
|
|||||||
|
|
||||||
void SetColorTransform(const ColorTransform& transform, ViewerDisplayWidget* sender);
|
void SetColorTransform(const ColorTransform& transform, ViewerDisplayWidget* sender);
|
||||||
|
|
||||||
|
void FillPlaybackQueue();
|
||||||
|
|
||||||
|
QString GetCachedFilenameFromTime(const rational& time);
|
||||||
|
|
||||||
|
bool FrameExistsAtTime(const rational& time);
|
||||||
|
|
||||||
|
FramePtr DecodeCachedImage(const QString& fn);
|
||||||
|
|
||||||
|
void SetDisplayImage(FramePtr frame, bool main_only);
|
||||||
|
|
||||||
QStackedWidget* stack_;
|
QStackedWidget* stack_;
|
||||||
|
|
||||||
ViewerSizer* sizer_;
|
ViewerSizer* sizer_;
|
||||||
|
|
||||||
qint64 start_msec_;
|
QAtomicInt playback_speed_;
|
||||||
int64_t start_timestamp_;
|
|
||||||
|
|
||||||
int playback_speed_;
|
|
||||||
|
|
||||||
qint64 frame_cache_job_time_;
|
qint64 frame_cache_job_time_;
|
||||||
|
|
||||||
@@ -201,10 +211,15 @@ private:
|
|||||||
|
|
||||||
QList<ViewerWindow*> windows_;
|
QList<ViewerWindow*> windows_;
|
||||||
|
|
||||||
QList<ViewerDisplayWidget*> gl_widgets_;
|
ViewerDisplayWidget* display_widget_;
|
||||||
|
|
||||||
ViewerDisplayWidget* context_menu_widget_;
|
ViewerDisplayWidget* context_menu_widget_;
|
||||||
|
|
||||||
|
ViewerPlaybackTimer playback_timer_;
|
||||||
|
|
||||||
|
ViewerQueue playback_queue_;
|
||||||
|
int64_t playback_queue_next_frame_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void PlaybackTimerUpdate();
|
void PlaybackTimerUpdate();
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
#include "common/define.h"
|
#include "common/define.h"
|
||||||
|
#include "common/functiontimer.h"
|
||||||
#include "gizmotraverser.h"
|
#include "gizmotraverser.h"
|
||||||
#include "render/backend/opengl/openglrenderfunctions.h"
|
#include "render/backend/opengl/openglrenderfunctions.h"
|
||||||
#include "render/backend/opengl/openglshader.h"
|
#include "render/backend/opengl/openglshader.h"
|
||||||
@@ -43,10 +44,10 @@ bool ViewerDisplayWidget::nouveau_check_done_ = false;
|
|||||||
|
|
||||||
ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
|
ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
|
||||||
ManagedDisplayWidget(parent),
|
ManagedDisplayWidget(parent),
|
||||||
has_image_(false),
|
|
||||||
signal_cursor_color_(false),
|
signal_cursor_color_(false),
|
||||||
gizmos_(nullptr),
|
gizmos_(nullptr),
|
||||||
gizmo_click_(false)
|
gizmo_click_(false),
|
||||||
|
last_loaded_buffer_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,81 +62,24 @@ void ViewerDisplayWidget::SetMatrix(const QMatrix4x4 &mat)
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerDisplayWidget::SetImage(const QString &fn)
|
|
||||||
{
|
|
||||||
has_image_ = false;
|
|
||||||
|
|
||||||
if (!fn.isEmpty() && QFileInfo::exists(fn)) {
|
|
||||||
auto input = OIIO::ImageInput::open(fn.toStdString());
|
|
||||||
|
|
||||||
if (input) {
|
|
||||||
|
|
||||||
PixelFormat::Format image_format = PixelFormat::OIIOFormatToOliveFormat(input->spec().format,
|
|
||||||
input->spec().nchannels == kRGBAChannels);
|
|
||||||
|
|
||||||
// Ensure the following texture operations are done in our context (in case we're in a separate window for instance)
|
|
||||||
makeCurrent();
|
|
||||||
|
|
||||||
if (!texture_.IsCreated()
|
|
||||||
|| texture_.width() != input->spec().width
|
|
||||||
|| texture_.height() != input->spec().height
|
|
||||||
|| texture_.format() != image_format) {
|
|
||||||
load_buffer_.destroy();
|
|
||||||
texture_.Destroy();
|
|
||||||
|
|
||||||
load_buffer_.set_video_params(VideoRenderingParams(input->spec().width, input->spec().height, image_format));
|
|
||||||
load_buffer_.allocate();
|
|
||||||
|
|
||||||
texture_.Create(context(), VideoRenderingParams(input->spec().width, input->spec().height, image_format));
|
|
||||||
}
|
|
||||||
|
|
||||||
input->read_image(input->spec().format, load_buffer_.data(), OIIO::AutoStride, load_buffer_.linesize_bytes());
|
|
||||||
input->close();
|
|
||||||
|
|
||||||
texture_.Upload(&load_buffer_);
|
|
||||||
|
|
||||||
doneCurrent();
|
|
||||||
|
|
||||||
emit LoadedBuffer(&load_buffer_);
|
|
||||||
|
|
||||||
has_image_ = true;
|
|
||||||
|
|
||||||
#if OIIO_VERSION < 10903
|
|
||||||
OIIO::ImageInput::destroy(input);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else {
|
|
||||||
qWarning() << "OIIO Error:" << OIIO::geterror().c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||
|
|
||||||
if (has_image_) {
|
|
||||||
emit LoadedBuffer(&load_buffer_);
|
|
||||||
} else {
|
|
||||||
emit LoadedBuffer(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e)
|
void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e)
|
||||||
{
|
{
|
||||||
signal_cursor_color_ = e;
|
signal_cursor_color_ = e;
|
||||||
setMouseTracking(e);
|
setMouseTracking(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerDisplayWidget::SetImageFromLoadBuffer(Frame *in_buffer)
|
void ViewerDisplayWidget::SetImage(FramePtr in_buffer)
|
||||||
{
|
{
|
||||||
has_image_ = in_buffer;
|
last_loaded_buffer_ = in_buffer;
|
||||||
|
|
||||||
if (has_image_) {
|
if (last_loaded_buffer_) {
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
|
|
||||||
if (!texture_.IsCreated()
|
if (!texture_.IsCreated()
|
||||||
|| texture_.width() != in_buffer->width()
|
|| texture_.width() != in_buffer->width()
|
||||||
|| texture_.height() != in_buffer->height()
|
|| texture_.height() != in_buffer->height()
|
||||||
|| texture_.format() != in_buffer->format()) {
|
|| texture_.format() != in_buffer->format()) {
|
||||||
texture_.Create(context(), in_buffer->video_params(), in_buffer->data(), load_buffer_.linesize_pixels());
|
texture_.Create(context(), in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels());
|
||||||
} else {
|
} else {
|
||||||
texture_.Upload(in_buffer);
|
texture_.Upload(in_buffer);
|
||||||
}
|
}
|
||||||
@@ -146,12 +90,6 @@ void ViewerDisplayWidget::SetImageFromLoadBuffer(Frame *in_buffer)
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerDisplayWidget::ConnectSibling(ViewerDisplayWidget *sibling)
|
|
||||||
{
|
|
||||||
connect(this, &ViewerDisplayWidget::LoadedBuffer, sibling, &ViewerDisplayWidget::SetImageFromLoadBuffer, Qt::QueuedConnection);
|
|
||||||
sibling->SetImageFromLoadBuffer(&load_buffer_);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ViewerSafeMarginInfo &ViewerDisplayWidget::GetSafeMargin() const
|
const ViewerSafeMarginInfo &ViewerDisplayWidget::GetSafeMargin() const
|
||||||
{
|
{
|
||||||
return safe_margin_;
|
return safe_margin_;
|
||||||
@@ -189,6 +127,11 @@ void ViewerDisplayWidget::SetTime(const rational &time)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FramePtr ViewerDisplayWidget::last_loaded_buffer() const
|
||||||
|
{
|
||||||
|
return last_loaded_buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
|
void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (gizmos_
|
if (gizmos_
|
||||||
@@ -215,17 +158,17 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event)
|
|||||||
if (signal_cursor_color_) {
|
if (signal_cursor_color_) {
|
||||||
Color reference, display;
|
Color reference, display;
|
||||||
|
|
||||||
if (has_image_) {
|
if (last_loaded_buffer_) {
|
||||||
QVector3D pixel_pos(static_cast<float>(event->x()) / static_cast<float>(width()) * 2.0f - 1.0f,
|
QVector3D pixel_pos(static_cast<float>(event->x()) / static_cast<float>(width()) * 2.0f - 1.0f,
|
||||||
static_cast<float>(event->y()) / static_cast<float>(height()) * 2.0f - 1.0f,
|
static_cast<float>(event->y()) / static_cast<float>(height()) * 2.0f - 1.0f,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
pixel_pos = pixel_pos * matrix_.inverted();
|
pixel_pos = pixel_pos * matrix_.inverted();
|
||||||
|
|
||||||
int frame_x = qRound((pixel_pos.x() + 1.0f) * 0.5f * load_buffer_.width());
|
int frame_x = qRound((pixel_pos.x() + 1.0f) * 0.5f * last_loaded_buffer_->width());
|
||||||
int frame_y = qRound((pixel_pos.y() + 1.0f) * 0.5f * load_buffer_.height());
|
int frame_y = qRound((pixel_pos.y() + 1.0f) * 0.5f * last_loaded_buffer_->height());
|
||||||
|
|
||||||
reference = load_buffer_.get_pixel(frame_x, frame_y);
|
reference = last_loaded_buffer_->get_pixel(frame_x, frame_y);
|
||||||
display = color_service()->ConvertColor(reference);
|
display = color_service()->ConvertColor(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +220,7 @@ void ViewerDisplayWidget::paintGL()
|
|||||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
f->glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
// We only draw if we have a pipeline
|
// We only draw if we have a pipeline
|
||||||
if (has_image_ && color_service()) {
|
if (last_loaded_buffer_ && color_service()) {
|
||||||
|
|
||||||
// Bind retrieved texture
|
// Bind retrieved texture
|
||||||
f->glBindTexture(GL_TEXTURE_2D, texture_.texture());
|
f->glBindTexture(GL_TEXTURE_2D, texture_.texture());
|
||||||
|
|||||||
@@ -66,15 +66,8 @@ public:
|
|||||||
|
|
||||||
virtual ~ViewerDisplayWidget() override;
|
virtual ~ViewerDisplayWidget() override;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set an image to load and display on screen
|
|
||||||
*/
|
|
||||||
void SetImage(const QString& fn);
|
|
||||||
|
|
||||||
const QMatrix4x4& GetMatrix();
|
const QMatrix4x4& GetMatrix();
|
||||||
|
|
||||||
void ConnectSibling(ViewerDisplayWidget* sibling);
|
|
||||||
|
|
||||||
const ViewerSafeMarginInfo& GetSafeMargin() const;
|
const ViewerSafeMarginInfo& GetSafeMargin() const;
|
||||||
void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin);
|
void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin);
|
||||||
|
|
||||||
@@ -82,6 +75,8 @@ public:
|
|||||||
void SetVideoParams(const VideoRenderingParams& params);
|
void SetVideoParams(const VideoRenderingParams& params);
|
||||||
void SetTime(const rational& time);
|
void SetTime(const rational& time);
|
||||||
|
|
||||||
|
FramePtr last_loaded_buffer() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/**
|
/**
|
||||||
* @brief Set the transformation matrix to draw with
|
* @brief Set the transformation matrix to draw with
|
||||||
@@ -105,7 +100,7 @@ public slots:
|
|||||||
* If there are multiple ViewerGLWidgets showing the same thing, this is faster than decoding the image from file
|
* If there are multiple ViewerGLWidgets showing the same thing, this is faster than decoding the image from file
|
||||||
* each time.
|
* each time.
|
||||||
*/
|
*/
|
||||||
void SetImageFromLoadBuffer(Frame* in_buffer);
|
void SetImage(FramePtr in_buffer);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
@@ -118,15 +113,6 @@ signals:
|
|||||||
*/
|
*/
|
||||||
void CursorColor(const Color& reference, const Color& display);
|
void CursorColor(const Color& reference, const Color& display);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Signal emitted when a buffer is loaded from file into memory
|
|
||||||
*
|
|
||||||
* This buffer will be the direct output of the renderer in reference space in CPU memory.
|
|
||||||
*
|
|
||||||
* Connect this to the SetImageFromLoadBuffer() slot of another ViewerGLWidget to show the same thing
|
|
||||||
*/
|
|
||||||
void LoadedBuffer(Frame* load_buffer);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Override the mouse press event for the DragStarted() signal and gizmos
|
* @brief Override the mouse press event for the DragStarted() signal and gizmos
|
||||||
@@ -174,17 +160,10 @@ private:
|
|||||||
*/
|
*/
|
||||||
QMatrix4x4 matrix_;
|
QMatrix4x4 matrix_;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Buffer to load images into RAM before sending them to the display
|
|
||||||
*/
|
|
||||||
Frame load_buffer_;
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
static bool nouveau_check_done_;
|
static bool nouveau_check_done_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool has_image_;
|
|
||||||
|
|
||||||
bool signal_cursor_color_;
|
bool signal_cursor_color_;
|
||||||
|
|
||||||
ViewerSafeMarginInfo safe_margin_;
|
ViewerSafeMarginInfo safe_margin_;
|
||||||
@@ -197,6 +176,8 @@ private:
|
|||||||
|
|
||||||
rational time_;
|
rational time_;
|
||||||
|
|
||||||
|
FramePtr last_loaded_buffer_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
/**
|
/**
|
||||||
* @brief Slot to connect just before the OpenGL context is destroyed to clean up resources
|
* @brief Slot to connect just before the OpenGL context is destroyed to clean up resources
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/***
|
||||||
|
|
||||||
|
Olive - Non-Linear Video Editor
|
||||||
|
Copyright (C) 2019 Olive Team
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include "viewerplaybacktimer.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
|
void ViewerPlaybackTimer::Start(const int64_t &start_timestamp, const int &playback_speed, const double &timebase)
|
||||||
|
{
|
||||||
|
start_msec_ = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
start_timestamp_ = start_timestamp;
|
||||||
|
playback_speed_ = playback_speed;
|
||||||
|
timebase_ = timebase;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ViewerPlaybackTimer::GetTimestampNow() const
|
||||||
|
{
|
||||||
|
int64_t real_time = QDateTime::currentMSecsSinceEpoch() - start_msec_;
|
||||||
|
|
||||||
|
int64_t frames_since_start = qRound(static_cast<double>(real_time) / (timebase_ * 1000));
|
||||||
|
|
||||||
|
return start_timestamp_ + frames_since_start * playback_speed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_EXIT
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/***
|
||||||
|
|
||||||
|
Olive - Non-Linear Video Editor
|
||||||
|
Copyright (C) 2019 Olive Team
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
***/
|
||||||
|
|
||||||
|
#ifndef VIEWERPLAYBACKTIMER_H
|
||||||
|
#define VIEWERPLAYBACKTIMER_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#include "common/define.h"
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
|
class ViewerPlaybackTimer {
|
||||||
|
public:
|
||||||
|
void Start(const int64_t& start_timestamp, const int& playback_speed, const double& timebase);
|
||||||
|
|
||||||
|
int64_t GetTimestampNow() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
qint64 start_msec_;
|
||||||
|
int64_t start_timestamp_;
|
||||||
|
|
||||||
|
int playback_speed_;
|
||||||
|
|
||||||
|
double timebase_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
#endif // VIEWERPLAYBACKTIMER_H
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/***
|
||||||
|
|
||||||
|
Olive - Non-Linear Video Editor
|
||||||
|
Copyright (C) 2019 Olive Team
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
***/
|
||||||
|
|
||||||
|
#ifndef VIEWERQUEUE_H
|
||||||
|
#define VIEWERQUEUE_H
|
||||||
|
|
||||||
|
#include <QLinkedList>
|
||||||
|
|
||||||
|
#include "codec/frame.h"
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
|
struct ViewerPlaybackFrame {
|
||||||
|
rational timestamp;
|
||||||
|
FramePtr frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ViewerQueue : public QLinkedList<ViewerPlaybackFrame> {
|
||||||
|
public:
|
||||||
|
ViewerQueue() = default;
|
||||||
|
|
||||||
|
QMutex* lock() {
|
||||||
|
return &queue_lock_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex queue_lock_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
#endif // VIEWERQUEUE_H
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "common/timecodefunctions.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
ViewerWindow::ViewerWindow(QWidget *parent) :
|
ViewerWindow::ViewerWindow(QWidget *parent) :
|
||||||
@@ -32,13 +34,13 @@ ViewerWindow::ViewerWindow(QWidget *parent) :
|
|||||||
layout->setMargin(0);
|
layout->setMargin(0);
|
||||||
layout->setSpacing(0);
|
layout->setSpacing(0);
|
||||||
|
|
||||||
gl_widget_ = new ViewerDisplayWidget();
|
display_widget_ = new ViewerDisplayWidget();
|
||||||
layout->addWidget(gl_widget_);
|
layout->addWidget(display_widget_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewerDisplayWidget *ViewerWindow::gl_widget() const
|
ViewerDisplayWidget *ViewerWindow::display_widget() const
|
||||||
{
|
{
|
||||||
return gl_widget_;
|
return display_widget_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWindow::SetResolution(int width, int height)
|
void ViewerWindow::SetResolution(int width, int height)
|
||||||
@@ -57,7 +59,26 @@ void ViewerWindow::SetResolution(int width, int height)
|
|||||||
mat.scale(1.0f, window_ar / image_ar, 1.0f);
|
mat.scale(1.0f, window_ar / image_ar, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
gl_widget_->SetMatrix(mat);
|
display_widget_->SetMatrix(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewerWindow::Play(const int64_t& start_timestamp, const int& playback_speed, const rational &timebase)
|
||||||
|
{
|
||||||
|
timer_.Start(start_timestamp, playback_speed, timebase.toDouble());
|
||||||
|
|
||||||
|
playback_timebase_ = timebase;
|
||||||
|
|
||||||
|
connect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWindow::UpdateFromQueue);
|
||||||
|
|
||||||
|
display_widget_->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewerWindow::Pause()
|
||||||
|
{
|
||||||
|
disconnect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWindow::UpdateFromQueue);
|
||||||
|
|
||||||
|
QMutexLocker locker(queue_.lock());
|
||||||
|
queue_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWindow::keyPressEvent(QKeyEvent *e)
|
void ViewerWindow::keyPressEvent(QKeyEvent *e)
|
||||||
@@ -76,4 +97,24 @@ void ViewerWindow::closeEvent(QCloseEvent *e)
|
|||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewerWindow::UpdateFromQueue()
|
||||||
|
{
|
||||||
|
int64_t t = timer_.GetTimestampNow();
|
||||||
|
|
||||||
|
rational time = Timecode::timestamp_to_time(t, playback_timebase_);
|
||||||
|
|
||||||
|
QMutexLocker locker(queue_.lock());
|
||||||
|
while (!queue_.isEmpty()) {
|
||||||
|
const ViewerPlaybackFrame& pf = queue_.first();
|
||||||
|
|
||||||
|
if (pf.timestamp == time) {
|
||||||
|
// Frame was in queue, no need to decode anything
|
||||||
|
display_widget_->SetImage(pf.frame);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
queue_.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "viewerdisplay.h"
|
#include "viewerdisplay.h"
|
||||||
|
#include "viewerplaybacktimer.h"
|
||||||
|
#include "viewerqueue.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
|
|
||||||
@@ -32,20 +34,37 @@ class ViewerWindow : public QWidget
|
|||||||
public:
|
public:
|
||||||
ViewerWindow(QWidget* parent = nullptr);
|
ViewerWindow(QWidget* parent = nullptr);
|
||||||
|
|
||||||
ViewerDisplayWidget* gl_widget() const;
|
ViewerDisplayWidget* display_widget() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Used to adjust resulting picture to be the right aspect ratio
|
* @brief Used to adjust resulting picture to be the right aspect ratio
|
||||||
*/
|
*/
|
||||||
void SetResolution(int width, int height);
|
void SetResolution(int width, int height);
|
||||||
|
|
||||||
|
ViewerQueue* queue() {
|
||||||
|
return &queue_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Play(const int64_t &start_timestamp, const int &playback_speed, const rational &timebase);
|
||||||
|
|
||||||
|
void Pause();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void keyPressEvent(QKeyEvent* e) override;
|
virtual void keyPressEvent(QKeyEvent* e) override;
|
||||||
|
|
||||||
virtual void closeEvent(QCloseEvent* e) override;
|
virtual void closeEvent(QCloseEvent* e) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void UpdateFromQueue();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ViewerDisplayWidget* gl_widget_;
|
ViewerDisplayWidget* display_widget_;
|
||||||
|
|
||||||
|
ViewerQueue queue_;
|
||||||
|
|
||||||
|
ViewerPlaybackTimer timer_;
|
||||||
|
|
||||||
|
rational playback_timebase_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -14,9 +14,9 @@ install:
|
|||||||
- cd %APPVEYOR_BUILD_FOLDER%
|
- cd %APPVEYOR_BUILD_FOLDER%
|
||||||
build_script:
|
build_script:
|
||||||
- cmd: .appveyor\build.bat
|
- cmd: .appveyor\build.bat
|
||||||
artifacts:
|
#artifacts:
|
||||||
- path: Olive*.zip
|
#- path: Olive*.zip
|
||||||
name: Olive Portable
|
# name: Olive Portable
|
||||||
- path: Olive*.exe
|
#- path: Olive*.exe
|
||||||
name: Olive Installer
|
# name: Olive Installer
|
||||||
cache: c:\tools\vcpkg\installed\
|
cache: c:\tools\vcpkg\installed\
|
||||||
|
|||||||
Reference in New Issue
Block a user