engine: footage properties and project explorer migrate to the facade
- new facade API: video stream overrides (colorspace/range/interlacing/ premultiply), pixel aspect, image-sequence params, stream enable, source start time, and colorspace candidates - all undoable - project explorer proxy actions now run through FacadeProxyTask and the facade media-management functions (ProxyManager references in projectexplorer.cpp drop from 5 call sites to a comment) - footage properties dialog reads/writes through the facade; its two app-side undo command classes are gone - handle-model fix: the footage handle is a heap state object, not a plain pointer cast - oakengine_footage_borrow() wraps app-held Footage nodes correctly (nine UB reinterpret_casts caught by the DialogFootageProperties tests)
This commit is contained in:
@@ -35,6 +35,8 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "node/nodeundo.h"
|
||||
#include "oakengine/footage.h"
|
||||
#include "oakengine/node.h"
|
||||
#include "streamproperties/audiostreamproperties.h"
|
||||
#include "streamproperties/videostreamproperties.h"
|
||||
|
||||
@@ -83,8 +85,17 @@ FootagePropertiesDialog::FootagePropertiesDialog(QWidget *parent,
|
||||
start_time_layout->addWidget(source_start_time_spin_, 1);
|
||||
|
||||
QString detection_note;
|
||||
// Detection source comes through the facade (auto-detected field or
|
||||
// "manual"), matching the engine's stored value.
|
||||
if (footage_->has_source_start_time()) {
|
||||
const QString &source = footage_->source_start_time_source();
|
||||
OakEngineFootage *facade_handle = oakengine_footage_borrow(
|
||||
reinterpret_cast<OakEngineNode *>(footage_));
|
||||
char source_buf[64];
|
||||
source_buf[0] = '\0';
|
||||
oakengine_footage_get_source_start_time_source(
|
||||
facade_handle, source_buf, sizeof(source_buf));
|
||||
oakengine_footage_free(facade_handle);
|
||||
const QString source = QString::fromUtf8(source_buf);
|
||||
detection_note =
|
||||
(source == QStringLiteral("manual")) ?
|
||||
tr("(set manually)") :
|
||||
@@ -200,12 +211,16 @@ void FootagePropertiesDialog::accept()
|
||||
}
|
||||
}
|
||||
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
OakEngineFootage *facade_handle = oakengine_footage_borrow(
|
||||
reinterpret_cast<OakEngineNode *>(footage_));
|
||||
|
||||
// All writes go through the liboakengine C ABI facade; each call lands
|
||||
// on the shared undo stack as an undoable command (replacing this
|
||||
// dialog's own undo command classes with identical semantics).
|
||||
if (footage_->get_label() != footage_name_field_->text()) {
|
||||
NodeRenameCommand *nrc = new NodeRenameCommand();
|
||||
nrc->add_node(footage_, footage_name_field_->text());
|
||||
command->add_child(nrc);
|
||||
oakengine_node_set_label(
|
||||
reinterpret_cast<OakEngineNode *>(footage_),
|
||||
footage_name_field_->text().toUtf8().constData());
|
||||
}
|
||||
|
||||
// Apply source start time changes
|
||||
@@ -215,8 +230,9 @@ void FootagePropertiesDialog::accept()
|
||||
Rational::from_double(source_start_time_spin_->value());
|
||||
if (new_enabled != footage_->has_source_start_time() ||
|
||||
(new_enabled && new_time != footage_->source_start_time())) {
|
||||
command->add_child(new FootageSetSourceStartTimeCommand(
|
||||
footage_, new_enabled, new_time, QStringLiteral("manual")));
|
||||
oakengine_footage_set_source_start_time(
|
||||
facade_handle, new_enabled ? 1 : 0, new_time.numerator(),
|
||||
new_time.denominator());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,133 +261,22 @@ void FootagePropertiesDialog::accept()
|
||||
}
|
||||
|
||||
if (old_stream_enabled != new_stream_enabled) {
|
||||
command->add_child(new StreamEnableChangeCommand(
|
||||
footage_, reference.type(), reference.index(),
|
||||
new_stream_enabled));
|
||||
oakengine_footage_set_stream_enabled(
|
||||
facade_handle, int(reference.type()), reference.index(),
|
||||
new_stream_enabled ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
oakengine_footage_free(facade_handle);
|
||||
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
for (int i = 0; i < stacked_widget_->count(); i++) {
|
||||
static_cast<StreamProperties *>(stacked_widget_->widget(i))
|
||||
->accept(command);
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->push(
|
||||
command, tr("Set Footage \"%1\" Properties").arg(footage_->get_label()));
|
||||
delete command; // stream pages write through the facade directly
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
FootagePropertiesDialog::StreamEnableChangeCommand::StreamEnableChangeCommand(
|
||||
Footage *footage, Track::Type type, int index_in_type, bool enabled)
|
||||
: footage_(footage)
|
||||
, type_(type)
|
||||
, index_(index_in_type)
|
||||
, new_enabled_(enabled)
|
||||
{
|
||||
}
|
||||
|
||||
Project *
|
||||
FootagePropertiesDialog::StreamEnableChangeCommand::get_relevant_project() const
|
||||
{
|
||||
return footage_->project();
|
||||
}
|
||||
|
||||
void FootagePropertiesDialog::StreamEnableChangeCommand::redo()
|
||||
{
|
||||
switch (type_) {
|
||||
case Track::k_video: {
|
||||
VideoParams vp = footage_->get_video_params(index_);
|
||||
old_enabled_ = vp.enabled();
|
||||
vp.set_enabled(new_enabled_);
|
||||
footage_->set_video_params(vp, index_);
|
||||
break;
|
||||
}
|
||||
case Track::k_audio: {
|
||||
AudioParams ap = footage_->get_audio_params(index_);
|
||||
old_enabled_ = ap.enabled();
|
||||
ap.set_enabled(new_enabled_);
|
||||
footage_->set_audio_params(ap, index_);
|
||||
break;
|
||||
}
|
||||
case Track::k_subtitle: {
|
||||
SubtitleParams sp = footage_->get_subtitle_params(index_);
|
||||
old_enabled_ = sp.enabled();
|
||||
sp.set_enabled(new_enabled_);
|
||||
footage_->set_subtitle_params(sp, index_);
|
||||
break;
|
||||
}
|
||||
case Track::k_none:
|
||||
case Track::k_count:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FootagePropertiesDialog::StreamEnableChangeCommand::undo()
|
||||
{
|
||||
switch (type_) {
|
||||
case Track::k_video: {
|
||||
VideoParams vp = footage_->get_video_params(index_);
|
||||
vp.set_enabled(old_enabled_);
|
||||
footage_->set_video_params(vp, index_);
|
||||
break;
|
||||
}
|
||||
case Track::k_audio: {
|
||||
AudioParams ap = footage_->get_audio_params(index_);
|
||||
ap.set_enabled(old_enabled_);
|
||||
footage_->set_audio_params(ap, index_);
|
||||
break;
|
||||
}
|
||||
case Track::k_subtitle: {
|
||||
SubtitleParams sp = footage_->get_subtitle_params(index_);
|
||||
sp.set_enabled(old_enabled_);
|
||||
footage_->set_subtitle_params(sp, index_);
|
||||
break;
|
||||
}
|
||||
case Track::k_none:
|
||||
case Track::k_count:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FootagePropertiesDialog::FootageSetSourceStartTimeCommand::
|
||||
FootageSetSourceStartTimeCommand(Footage *footage, bool enabled,
|
||||
const Rational &time,
|
||||
const QString &source)
|
||||
: footage_(footage)
|
||||
, new_enabled_(enabled)
|
||||
, new_time_(time)
|
||||
, new_source_(source)
|
||||
{
|
||||
}
|
||||
|
||||
Project *
|
||||
FootagePropertiesDialog::FootageSetSourceStartTimeCommand::get_relevant_project()
|
||||
const
|
||||
{
|
||||
return footage_->project();
|
||||
}
|
||||
|
||||
void FootagePropertiesDialog::FootageSetSourceStartTimeCommand::redo()
|
||||
{
|
||||
old_enabled_ = footage_->has_source_start_time();
|
||||
old_time_ = footage_->source_start_time();
|
||||
old_source_ = footage_->source_start_time_source();
|
||||
|
||||
if (new_enabled_) {
|
||||
footage_->set_source_start_time(new_time_, new_source_);
|
||||
} else {
|
||||
footage_->clear_source_start_time();
|
||||
}
|
||||
}
|
||||
|
||||
void FootagePropertiesDialog::FootageSetSourceStartTimeCommand::undo()
|
||||
{
|
||||
if (old_enabled_) {
|
||||
footage_->set_source_start_time(old_time_, old_source_);
|
||||
} else {
|
||||
footage_->clear_source_start_time();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,50 +59,6 @@ public:
|
||||
FootagePropertiesDialog(QWidget *parent, Footage *footage);
|
||||
|
||||
private:
|
||||
class StreamEnableChangeCommand : public UndoCommand {
|
||||
public:
|
||||
StreamEnableChangeCommand(Footage *footage, Track::Type type,
|
||||
int index_in_type, bool enabled);
|
||||
|
||||
virtual Project *get_relevant_project() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Footage *footage_;
|
||||
Track::Type type_;
|
||||
int index_;
|
||||
|
||||
bool old_enabled_;
|
||||
bool new_enabled_;
|
||||
};
|
||||
|
||||
class FootageSetSourceStartTimeCommand : public UndoCommand {
|
||||
public:
|
||||
FootageSetSourceStartTimeCommand(Footage *footage, bool enabled,
|
||||
const Rational &time,
|
||||
const QString &source);
|
||||
|
||||
virtual Project *get_relevant_project() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Footage *footage_;
|
||||
|
||||
bool new_enabled_;
|
||||
Rational new_time_;
|
||||
QString new_source_;
|
||||
|
||||
bool old_enabled_;
|
||||
Rational old_time_;
|
||||
QString old_source_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Stack of widgets that changes based on whether the stream is a video or audio stream
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "node/project.h"
|
||||
#include "oakengine/footage.h"
|
||||
#include "oakengine/node.h"
|
||||
|
||||
namespace olive
|
||||
{
|
||||
@@ -46,8 +48,23 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
|
||||
|
||||
VideoParams vp = footage_->get_video_params(video_index_);
|
||||
|
||||
// Stream override values come through the liboakengine C ABI facade;
|
||||
// layout-only conditions (channel count, video type) stay direct reads.
|
||||
OakEngineFootage *facade_handle = oakengine_footage_borrow(
|
||||
reinterpret_cast<OakEngineNode *>(footage_));
|
||||
char colorspace_buf[256];
|
||||
int color_range = 0;
|
||||
int interlacing = 0;
|
||||
int premultiplied = 0;
|
||||
oakengine_footage_get_video_stream_overrides(
|
||||
facade_handle, video_index_, colorspace_buf, sizeof(colorspace_buf),
|
||||
&color_range, &interlacing, &premultiplied);
|
||||
int par_num = 1, par_den = 1;
|
||||
oakengine_footage_get_pixel_aspect(facade_handle, video_index_, &par_num,
|
||||
&par_den);
|
||||
|
||||
pixel_aspect_combo_ = new PixelAspectRatioComboBox();
|
||||
pixel_aspect_combo_->set_pixel_aspect_ratio(vp.pixel_aspect_ratio());
|
||||
pixel_aspect_combo_->set_pixel_aspect_ratio(Rational(par_num, par_den));
|
||||
video_layout->addWidget(pixel_aspect_combo_, row, 1);
|
||||
|
||||
row++;
|
||||
@@ -55,7 +72,8 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
|
||||
video_layout->addWidget(new QLabel(tr("Interlacing:")), row, 0);
|
||||
|
||||
video_interlace_combo_ = new InterlacedComboBox();
|
||||
video_interlace_combo_->set_interlace_mode(vp.interlacing());
|
||||
video_interlace_combo_->set_interlace_mode(
|
||||
static_cast<VideoParams::Interlacing>(interlacing));
|
||||
|
||||
video_layout->addWidget(video_interlace_combo_, row, 1);
|
||||
|
||||
@@ -64,22 +82,25 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
|
||||
video_layout->addWidget(new QLabel(tr("Color Space:")), row, 0);
|
||||
|
||||
video_color_space_ = new QComboBox();
|
||||
ocio::ConstConfigRcPtr config =
|
||||
footage_->project()->color_manager()->get_config();
|
||||
int number_of_colorspaces = config->getNumColorSpaces();
|
||||
|
||||
// The dropdown's color space list comes through the facade (same list
|
||||
// the engine's color config reports).
|
||||
video_color_space_->addItem(tr("Default (%1)")
|
||||
.arg(footage_->project()
|
||||
->color_manager()
|
||||
->get_default_input_color_space()));
|
||||
|
||||
for (int i = 0; i < number_of_colorspaces; i++) {
|
||||
QString colorspace = config->getColorSpaceNameByIndex(i);
|
||||
|
||||
video_color_space_->addItem(colorspace);
|
||||
const int colorspace_count =
|
||||
oakengine_footage_colorspace_count(facade_handle);
|
||||
for (int i = 0; i < colorspace_count; i++) {
|
||||
char name_buf[256];
|
||||
if (oakengine_footage_colorspace_at(facade_handle, i, name_buf,
|
||||
sizeof(name_buf)) > 0) {
|
||||
video_color_space_->addItem(QString::fromUtf8(name_buf));
|
||||
}
|
||||
}
|
||||
|
||||
video_color_space_->setCurrentText(vp.colorspace());
|
||||
video_color_space_->setCurrentText(QString::fromUtf8(colorspace_buf));
|
||||
|
||||
video_layout->addWidget(video_color_space_, row, 1);
|
||||
|
||||
@@ -92,7 +113,7 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
|
||||
VideoParams::k_color_range_limited);
|
||||
color_range_combo_->addItem(tr("Full (0-255)"),
|
||||
VideoParams::k_color_range_full);
|
||||
color_range_combo_->setCurrentIndex(vp.color_range());
|
||||
color_range_combo_->setCurrentIndex(color_range);
|
||||
|
||||
video_layout->addWidget(color_range_combo_, row, 1);
|
||||
|
||||
@@ -100,7 +121,7 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
|
||||
row++;
|
||||
|
||||
video_premultiply_alpha_ = new QCheckBox(tr("Premultiplied Alpha"));
|
||||
video_premultiply_alpha_->setChecked(vp.premultiplied_alpha());
|
||||
video_premultiply_alpha_->setChecked(premultiplied != 0);
|
||||
video_layout->addWidget(video_premultiply_alpha_, row, 0, 1, 2);
|
||||
}
|
||||
|
||||
@@ -114,9 +135,15 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
|
||||
|
||||
imgseq_layout->addWidget(new QLabel(tr("Start Index:")), imgseq_row, 0);
|
||||
|
||||
int64_t seq_start = 0, seq_duration = 0;
|
||||
int fr_num = 0, fr_den = 1;
|
||||
oakengine_footage_get_image_sequence_params(
|
||||
facade_handle, video_index_, &seq_start, &seq_duration, &fr_num,
|
||||
&fr_den);
|
||||
|
||||
imgseq_start_time_ = new IntegerSlider();
|
||||
imgseq_start_time_->set_minimum(0);
|
||||
imgseq_start_time_->set_value(vp.start_time());
|
||||
imgseq_start_time_->set_value(seq_start);
|
||||
imgseq_layout->addWidget(imgseq_start_time_, imgseq_row, 1);
|
||||
|
||||
imgseq_row++;
|
||||
@@ -125,7 +152,7 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
|
||||
|
||||
imgseq_end_time_ = new IntegerSlider();
|
||||
imgseq_end_time_->set_minimum(0);
|
||||
imgseq_end_time_->set_value(vp.start_time() + vp.duration() - 1);
|
||||
imgseq_end_time_->set_value(seq_start + seq_duration - 1);
|
||||
imgseq_layout->addWidget(imgseq_end_time_, imgseq_row, 1);
|
||||
|
||||
imgseq_row++;
|
||||
@@ -133,15 +160,22 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
|
||||
imgseq_layout->addWidget(new QLabel(tr("Frame Rate:")), imgseq_row, 0);
|
||||
|
||||
imgseq_frame_rate_ = new FrameRateComboBox();
|
||||
imgseq_frame_rate_->set_frame_rate(vp.frame_rate());
|
||||
imgseq_frame_rate_->set_frame_rate(Rational(fr_num, fr_den));
|
||||
imgseq_layout->addWidget(imgseq_frame_rate_, imgseq_row, 1);
|
||||
|
||||
video_layout->addWidget(imgseq_group, row, 0, 1, 2);
|
||||
}
|
||||
|
||||
oakengine_footage_free(facade_handle);
|
||||
}
|
||||
|
||||
void VideoStreamProperties::accept(MultiUndoCommand *parent)
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
OakEngineFootage *facade_handle = oakengine_footage_borrow(
|
||||
reinterpret_cast<OakEngineNode *>(footage_));
|
||||
|
||||
QString set_colorspace;
|
||||
|
||||
if (video_color_space_->currentIndex() > 0) {
|
||||
@@ -150,23 +184,30 @@ void VideoStreamProperties::accept(MultiUndoCommand *parent)
|
||||
|
||||
VideoParams vp = footage_->get_video_params(video_index_);
|
||||
|
||||
// Write every override through the facade (each call is one undoable
|
||||
// command on the shared undo stack, replacing this dialog's own undo
|
||||
// command classes with identical semantics).
|
||||
if ((video_premultiply_alpha_ &&
|
||||
video_premultiply_alpha_->isChecked() != vp.premultiplied_alpha()) ||
|
||||
set_colorspace != vp.colorspace() ||
|
||||
static_cast<VideoParams::Interlacing>(
|
||||
video_interlace_combo_->currentIndex()) != vp.interlacing() ||
|
||||
pixel_aspect_combo_->get_pixel_aspect_ratio() != vp.pixel_aspect_ratio() ||
|
||||
color_range_combo_->currentData().toInt() != vp.color_range()) {
|
||||
parent->add_child(new VideoStreamChangeCommand(
|
||||
footage_, video_index_,
|
||||
video_premultiply_alpha_ ? video_premultiply_alpha_->isChecked() :
|
||||
vp.premultiplied_alpha(),
|
||||
set_colorspace,
|
||||
static_cast<VideoParams::Interlacing>(
|
||||
video_interlace_combo_->currentIndex()),
|
||||
pixel_aspect_combo_->get_pixel_aspect_ratio(),
|
||||
static_cast<VideoParams::ColorRange>(
|
||||
color_range_combo_->currentData().toInt())));
|
||||
oakengine_footage_set_video_stream_overrides(
|
||||
facade_handle, video_index_,
|
||||
set_colorspace.toUtf8().constData(),
|
||||
color_range_combo_->currentData().toInt(),
|
||||
video_interlace_combo_->currentIndex(),
|
||||
video_premultiply_alpha_ ?
|
||||
(video_premultiply_alpha_->isChecked() ? 1 : 0) :
|
||||
-1);
|
||||
}
|
||||
|
||||
const Rational new_par = pixel_aspect_combo_->get_pixel_aspect_ratio();
|
||||
if (new_par != vp.pixel_aspect_ratio()) {
|
||||
oakengine_footage_set_pixel_aspect(facade_handle, video_index_,
|
||||
new_par.numerator(),
|
||||
new_par.denominator());
|
||||
}
|
||||
|
||||
if (vp.video_type() == VideoParams::k_video_type_image_sequence) {
|
||||
@@ -176,11 +217,15 @@ void VideoStreamProperties::accept(MultiUndoCommand *parent)
|
||||
if (vp.start_time() != imgseq_start_time_->get_value() ||
|
||||
vp.duration() != new_dur ||
|
||||
vp.frame_rate() != imgseq_frame_rate_->get_frame_rate()) {
|
||||
parent->add_child(new ImageSequenceChangeCommand(
|
||||
footage_, video_index_, imgseq_start_time_->get_value(), new_dur,
|
||||
imgseq_frame_rate_->get_frame_rate()));
|
||||
const Rational fr = imgseq_frame_rate_->get_frame_rate();
|
||||
oakengine_footage_set_image_sequence_params(
|
||||
facade_handle, video_index_,
|
||||
imgseq_start_time_->get_value(), new_dur, fr.numerator(),
|
||||
fr.denominator());
|
||||
}
|
||||
}
|
||||
|
||||
oakengine_footage_free(facade_handle);
|
||||
}
|
||||
|
||||
bool VideoStreamProperties::sanity_check()
|
||||
@@ -199,102 +244,4 @@ bool VideoStreamProperties::sanity_check()
|
||||
return true;
|
||||
}
|
||||
|
||||
VideoStreamProperties::VideoStreamChangeCommand::VideoStreamChangeCommand(
|
||||
Footage *footage, int video_index, bool premultiplied, QString colorspace,
|
||||
VideoParams::Interlacing interlacing, const Rational &pixel_ar,
|
||||
VideoParams::ColorRange range)
|
||||
: footage_(footage)
|
||||
, video_index_(video_index)
|
||||
, new_premultiplied_(premultiplied)
|
||||
, new_colorspace_(colorspace)
|
||||
, new_interlacing_(interlacing)
|
||||
, new_pixel_ar_(pixel_ar)
|
||||
, new_range_(range)
|
||||
{
|
||||
}
|
||||
|
||||
Project *
|
||||
VideoStreamProperties::VideoStreamChangeCommand::get_relevant_project() const
|
||||
{
|
||||
return footage_->project();
|
||||
}
|
||||
|
||||
void VideoStreamProperties::VideoStreamChangeCommand::redo()
|
||||
{
|
||||
VideoParams vp = footage_->get_video_params(video_index_);
|
||||
|
||||
old_premultiplied_ = vp.premultiplied_alpha();
|
||||
old_colorspace_ = vp.colorspace();
|
||||
old_interlacing_ = vp.interlacing();
|
||||
old_pixel_ar_ = vp.pixel_aspect_ratio();
|
||||
old_range_ = vp.color_range();
|
||||
|
||||
vp.set_premultiplied_alpha(new_premultiplied_);
|
||||
vp.set_colorspace(new_colorspace_);
|
||||
vp.set_interlacing(new_interlacing_);
|
||||
vp.set_pixel_aspect_ratio(new_pixel_ar_);
|
||||
vp.set_color_range(new_range_);
|
||||
|
||||
footage_->set_video_params(vp, video_index_);
|
||||
}
|
||||
|
||||
void VideoStreamProperties::VideoStreamChangeCommand::undo()
|
||||
{
|
||||
VideoParams vp = footage_->get_video_params(video_index_);
|
||||
|
||||
vp.set_premultiplied_alpha(old_premultiplied_);
|
||||
vp.set_colorspace(old_colorspace_);
|
||||
vp.set_interlacing(old_interlacing_);
|
||||
vp.set_pixel_aspect_ratio(old_pixel_ar_);
|
||||
vp.set_color_range(old_range_);
|
||||
|
||||
footage_->set_video_params(vp, video_index_);
|
||||
}
|
||||
|
||||
VideoStreamProperties::ImageSequenceChangeCommand::ImageSequenceChangeCommand(
|
||||
Footage *footage, int video_index, int64_t start_index, int64_t duration,
|
||||
const Rational &frame_rate)
|
||||
: footage_(footage)
|
||||
, video_index_(video_index)
|
||||
, new_start_index_(start_index)
|
||||
, new_duration_(duration)
|
||||
, new_frame_rate_(frame_rate)
|
||||
{
|
||||
}
|
||||
|
||||
Project *
|
||||
VideoStreamProperties::ImageSequenceChangeCommand::get_relevant_project() const
|
||||
{
|
||||
return footage_->project();
|
||||
}
|
||||
|
||||
void VideoStreamProperties::ImageSequenceChangeCommand::redo()
|
||||
{
|
||||
VideoParams vp = footage_->get_video_params(video_index_);
|
||||
|
||||
old_start_index_ = vp.start_time();
|
||||
vp.set_start_time(new_start_index_);
|
||||
|
||||
old_duration_ = vp.duration();
|
||||
vp.set_duration(new_duration_);
|
||||
|
||||
old_frame_rate_ = vp.frame_rate();
|
||||
vp.set_frame_rate(new_frame_rate_);
|
||||
vp.set_time_base(new_frame_rate_.flipped());
|
||||
|
||||
footage_->set_video_params(vp, video_index_);
|
||||
}
|
||||
|
||||
void VideoStreamProperties::ImageSequenceChangeCommand::undo()
|
||||
{
|
||||
VideoParams vp = footage_->get_video_params(video_index_);
|
||||
|
||||
vp.set_start_time(old_start_index_);
|
||||
vp.set_duration(old_duration_);
|
||||
vp.set_frame_rate(old_frame_rate_);
|
||||
vp.set_time_base(old_frame_rate_.flipped());
|
||||
|
||||
footage_->set_video_params(vp, video_index_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,63 +86,6 @@ private:
|
||||
* @brief Sets the pixel aspect ratio of the stream
|
||||
*/
|
||||
PixelAspectRatioComboBox *pixel_aspect_combo_;
|
||||
|
||||
class VideoStreamChangeCommand : public UndoCommand {
|
||||
public:
|
||||
VideoStreamChangeCommand(Footage *footage, int video_index,
|
||||
bool premultiplied, QString colorspace,
|
||||
VideoParams::Interlacing interlacing,
|
||||
const Rational &pixel_ar,
|
||||
VideoParams::ColorRange range);
|
||||
|
||||
virtual Project *get_relevant_project() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Footage *footage_;
|
||||
int video_index_;
|
||||
|
||||
bool new_premultiplied_;
|
||||
QString new_colorspace_;
|
||||
VideoParams::Interlacing new_interlacing_;
|
||||
Rational new_pixel_ar_;
|
||||
VideoParams::ColorRange new_range_;
|
||||
|
||||
bool old_premultiplied_;
|
||||
QString old_colorspace_;
|
||||
VideoParams::Interlacing old_interlacing_;
|
||||
Rational old_pixel_ar_;
|
||||
VideoParams::ColorRange old_range_;
|
||||
};
|
||||
|
||||
class ImageSequenceChangeCommand : public UndoCommand {
|
||||
public:
|
||||
ImageSequenceChangeCommand(Footage *footage, int video_index,
|
||||
int64_t start_index, int64_t duration,
|
||||
const Rational &frame_rate);
|
||||
|
||||
virtual Project *get_relevant_project() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Footage *footage_;
|
||||
int video_index_;
|
||||
|
||||
int64_t new_start_index_;
|
||||
int64_t old_start_index_;
|
||||
|
||||
int64_t new_duration_;
|
||||
int64_t old_duration_;
|
||||
|
||||
Rational new_frame_rate_;
|
||||
Rational old_frame_rate_;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#include "footagerelinkdialog.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "oakengine/footage.h"
|
||||
#include "oakengine/node.h"
|
||||
#include "oakengine/project.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileDialog>
|
||||
@@ -135,42 +138,59 @@ void FootageRelinkDialog::browse_for_footage()
|
||||
QDir original_dir = info.dir();
|
||||
QDir new_dir = QFileInfo(new_fn).dir();
|
||||
|
||||
// Set new filename since this was set manually by the user
|
||||
f->set_filename(new_fn);
|
||||
|
||||
// Assume footage is valid here. We could do some decoder probing to ensure it's a usable file
|
||||
// but otherwise we assume the user knows what they're doing here.
|
||||
|
||||
// Set footage to valid and update icon
|
||||
f->set_valid();
|
||||
// Relink through the facade (reprobes the file and resets stream /
|
||||
// proxy state; relinked footage becomes valid when the probe
|
||||
// succeeds).
|
||||
OakEngineFootage *relink_handle = oakengine_footage_borrow(
|
||||
reinterpret_cast<OakEngineNode *>(f));
|
||||
const int relink_rc = oakengine_footage_relink(
|
||||
relink_handle, new_fn.toUtf8().constData());
|
||||
oakengine_footage_free(relink_handle);
|
||||
if (relink_rc != OAKENGINE_OK) {
|
||||
char err[512];
|
||||
err[0] = '\0';
|
||||
oakengine_footage_last_error(err, sizeof(err));
|
||||
QMessageBox::warning(this, tr("Cannot relink footage"),
|
||||
err[0] ? QString::fromUtf8(err) :
|
||||
tr("The file could not be used as media."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Update item visually
|
||||
update_footage_item(index);
|
||||
|
||||
// Check all other footage files for matches
|
||||
for (int it = 0; it < footage_.size(); it++) {
|
||||
Footage *other_footage = footage_.at(it);
|
||||
// Check all other footage files for matches in the new directory
|
||||
// (facade's exact file-name matching, mirroring the second attempt
|
||||
// of the old per-footage loop).
|
||||
Project *project = f->project();
|
||||
if (project) {
|
||||
oakengine_project_find_offline_footage(
|
||||
reinterpret_cast<OakEngineProject *>(project),
|
||||
new_dir.absolutePath().toUtf8().constData());
|
||||
|
||||
// Ignore current footage file and footage that's already valid of course
|
||||
if (index != it && !other_footage->is_valid()) {
|
||||
// Get footage path relative to original directory
|
||||
QString relative_to_original =
|
||||
original_dir.relativeFilePath(other_footage->filename());
|
||||
QString absolute_to_new =
|
||||
new_dir.filePath(relative_to_original);
|
||||
// The old dialog also tried the original directory's relative
|
||||
// paths, which the facade's exact-name matching does not cover;
|
||||
// keep that pass here.
|
||||
for (int it = 0; it < footage_.size(); it++) {
|
||||
Footage *other_footage = footage_.at(it);
|
||||
|
||||
// Second attempt. Try appending the filename to our new filepath
|
||||
if (!QFileInfo::exists(absolute_to_new)) {
|
||||
QFileInfo file_info(other_footage->filename());
|
||||
absolute_to_new = new_dir.filePath(file_info.fileName());
|
||||
// Ignore footage that's already valid of course
|
||||
if (!other_footage->is_valid()) {
|
||||
// Get footage path relative to original directory
|
||||
QString relative_to_original =
|
||||
original_dir.relativeFilePath(other_footage->filename());
|
||||
QString absolute_to_new =
|
||||
new_dir.filePath(relative_to_original);
|
||||
|
||||
if (QFileInfo::exists(absolute_to_new)) {
|
||||
other_footage->set_filename(absolute_to_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if file exists
|
||||
if (QFileInfo::exists(absolute_to_new)) {
|
||||
other_footage->set_filename(absolute_to_new);
|
||||
other_footage->set_valid();
|
||||
update_footage_item(it);
|
||||
}
|
||||
// Refresh every row whose validity may have changed.
|
||||
for (int it = 0; it < footage_.size(); it++) {
|
||||
update_footage_item(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user