project: replaced proxy with pre-cache
Removed proxy task and replaced with a true honest-to-god pre-cache for footage. This footage is pre-cached to a sequence and therefore 100% ready for use in it once the task is done.
This commit is contained in:
@@ -57,7 +57,7 @@ void Decoder::set_stream(StreamPtr fs)
|
||||
stream_ = fs;
|
||||
}
|
||||
|
||||
FramePtr Decoder::RetrieveVideo(const rational &/*timecode*/, const int &/*divider*/, bool /*use_proxies*/)
|
||||
FramePtr Decoder::RetrieveVideo(const rational &/*timecode*/, const int &/*divider*/)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -175,11 +175,6 @@ QString Decoder::GetConformedFilename(const AudioParams ¶ms)
|
||||
return index_fn;
|
||||
}
|
||||
|
||||
bool Decoder::ProxyVideo(const QAtomicInt *, int )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Decoder::ConformAudio(const QAtomicInt *, const AudioParams& )
|
||||
{
|
||||
return false;
|
||||
|
||||
+1
-6
@@ -138,7 +138,7 @@ public:
|
||||
* A FramePtr of valid data at this timecode or nullptr if there was nothing to retrieve at the provided timecode or
|
||||
* the media could not be opened.
|
||||
*/
|
||||
virtual FramePtr RetrieveVideo(const rational& timecode, const int& divider, bool use_proxies);
|
||||
virtual FramePtr RetrieveVideo(const rational& timecode, const int& divider);
|
||||
|
||||
/**
|
||||
* @brief Retrieve video frame
|
||||
@@ -210,11 +210,6 @@ public:
|
||||
*/
|
||||
static DecoderPtr CreateFromID(const QString& id);
|
||||
|
||||
/**
|
||||
* @brief VIDEO ONLY: Produce a compressed EXR proxy with the specified divider
|
||||
*/
|
||||
virtual bool ProxyVideo(const QAtomicInt* cancelled, int divider);
|
||||
|
||||
/**
|
||||
* @brief AUDIO ONLY: Produces a complete PCM extraction of the audio stream
|
||||
*
|
||||
|
||||
@@ -135,7 +135,7 @@ bool FFmpegDecoder::Open()
|
||||
return true;
|
||||
}
|
||||
|
||||
FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int ÷r, bool use_proxies)
|
||||
FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int ÷r)
|
||||
{
|
||||
QMutexLocker locker(&mutex_);
|
||||
|
||||
@@ -152,51 +152,6 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int &divid
|
||||
|
||||
VideoStreamPtr vs = std::static_pointer_cast<VideoStream>(stream());
|
||||
|
||||
if (use_proxies && vs->using_proxy()) {
|
||||
QString proxy_fn = GetProxyFilename(vs->using_proxy());
|
||||
|
||||
int64_t index_ts = vs->get_closest_timestamp_in_frame_index(target_ts);
|
||||
|
||||
if (target_ts > -1) {
|
||||
// Use this timestamp instead - even if we fall through to decoding manually, it'll be more
|
||||
// accurate than the one we calculated earlier
|
||||
target_ts = index_ts;
|
||||
|
||||
QString frame_filename = GetProxyFrameFilename(target_ts, vs->using_proxy());
|
||||
|
||||
if (QFileInfo::exists(frame_filename)) {
|
||||
auto in = OIIO::ImageInput::open(frame_filename.toStdString());
|
||||
|
||||
if (in) {
|
||||
FramePtr copy = Frame::Create();
|
||||
copy->set_video_params(VideoParams(vs->width(),
|
||||
vs->height(),
|
||||
native_pix_fmt_,
|
||||
vs->using_proxy()));
|
||||
copy->set_timestamp(Timecode::timestamp_to_time(target_ts, time_base_));
|
||||
copy->set_sample_aspect_ratio(aspect_ratio_);
|
||||
copy->allocate();
|
||||
|
||||
// We're running one "decoder" per thread already, no need to spawn more than that
|
||||
in->threads(1);
|
||||
|
||||
in->read_image(PixelFormat::GetOIIOTypeDesc(native_pix_fmt_),
|
||||
copy->data(),
|
||||
OIIO::AutoStride,
|
||||
copy->linesize_bytes());
|
||||
|
||||
in->close();
|
||||
|
||||
#if OIIO_VERSION < 10903
|
||||
OIIO::ImageInput::destroy(in);
|
||||
#endif
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FFmpegDecoderInstance* working_instance = nullptr;
|
||||
FFmpegFramePool::ElementPtr return_frame = nullptr;
|
||||
|
||||
@@ -669,135 +624,6 @@ void SaveCacheFrame(FFmpegDecoder* decoder,
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
bool FFmpegDecoder::ProxyVideo(const QAtomicInt *cancelled, int divider)
|
||||
{
|
||||
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream());
|
||||
|
||||
QString proxy_filename = GetProxyFilename(divider);
|
||||
|
||||
if (QFileInfo::exists(proxy_filename)) {
|
||||
|
||||
// A proxy of this type already exists so we can do nothing
|
||||
QFile index_file(proxy_filename);
|
||||
if (index_file.open(QFile::ReadOnly)) {
|
||||
QVector<int64_t> index(index_file.size() / sizeof(int64_t));
|
||||
|
||||
index_file.read(reinterpret_cast<char*>(index.data()),
|
||||
index_file.size());
|
||||
|
||||
index_file.close();
|
||||
|
||||
video_stream->set_proxy(divider, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Iterate each frame and transcode it to EXR
|
||||
FFmpegDecoderInstance instance(stream()->footage()->filename().toUtf8(), stream()->index());
|
||||
|
||||
int ret;
|
||||
|
||||
AVPixelFormat src_fmt = static_cast<AVPixelFormat>(instance.stream()->codecpar->format);
|
||||
AVPixelFormat ideal_fmt = FFmpegCommon::GetCompatiblePixelFormat(src_fmt);
|
||||
PixelFormat::Format native_fmt = GetNativePixelFormat(ideal_fmt);
|
||||
|
||||
int divided_width = GetScaledDimension(instance.stream()->codecpar->width, divider);
|
||||
int divided_height = GetScaledDimension(instance.stream()->codecpar->height, divider);
|
||||
|
||||
SwsContext* scaler = sws_getContext(instance.stream()->codecpar->width,
|
||||
instance.stream()->codecpar->height,
|
||||
src_fmt,
|
||||
divided_width,
|
||||
divided_height,
|
||||
ideal_fmt,
|
||||
SWS_FAST_BILINEAR,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0);
|
||||
|
||||
AVPacket* pkt = av_packet_alloc();
|
||||
QVector<int64_t> frame_index;
|
||||
QVector< QFuture<void> > futures;
|
||||
int finished_futures = 0;
|
||||
|
||||
VideoParams converted_params(divided_width,
|
||||
divided_height,
|
||||
native_fmt);
|
||||
|
||||
bool succeeded = false;
|
||||
|
||||
while (true) {
|
||||
if (cancelled && *cancelled) {
|
||||
break;
|
||||
}
|
||||
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
|
||||
ret = instance.GetFrame(pkt, frame);
|
||||
|
||||
// Handle errors
|
||||
if (ret < 0) {
|
||||
if (ret == AVERROR_EOF) {
|
||||
succeeded = true;
|
||||
} else {
|
||||
char err_str[50];
|
||||
av_strerror(ret, err_str, 50);
|
||||
qWarning() << "Failed to proxy:" << ret << err_str;
|
||||
}
|
||||
|
||||
av_frame_free(&frame);
|
||||
break;
|
||||
}
|
||||
|
||||
frame_index.append(frame->pts);
|
||||
|
||||
QFuture<void> future = QtConcurrent::run(SaveCacheFrame,
|
||||
this,
|
||||
scaler,
|
||||
frame,
|
||||
converted_params,
|
||||
GetProxyFrameFilename(frame->pts, divider));
|
||||
futures.append(future);
|
||||
|
||||
while (finished_futures < futures.size()) {
|
||||
if (!futures.at(finished_futures).isFinished()) {
|
||||
SignalProcessingProgress(frame_index.at(finished_futures));
|
||||
break;
|
||||
}
|
||||
|
||||
finished_futures++;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for all conversions to finish
|
||||
for ( ; finished_futures<futures.size(); finished_futures++) {
|
||||
futures[finished_futures].waitForFinished();
|
||||
SignalProcessingProgress(frame_index.at(finished_futures));
|
||||
}
|
||||
|
||||
// If succeeded, update the video stream's proxy state
|
||||
if (succeeded) {
|
||||
QFile index_output(proxy_filename);
|
||||
|
||||
if (index_output.open(QFile::WriteOnly)) {
|
||||
index_output.write(reinterpret_cast<const char*>(frame_index.constData()),
|
||||
frame_index.size() * sizeof(int64_t));
|
||||
|
||||
index_output.close();
|
||||
}
|
||||
|
||||
video_stream->set_proxy(divider, frame_index);
|
||||
}
|
||||
|
||||
sws_freeContext(scaler);
|
||||
|
||||
av_packet_free(&pkt);
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams &p)
|
||||
{
|
||||
// Iterate through each audio frame and extract the PCM data
|
||||
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
virtual bool Probe(Footage *f, const QAtomicInt *cancelled) override;
|
||||
|
||||
virtual bool Open() override;
|
||||
virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider, bool use_proxies) override;
|
||||
virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override;
|
||||
virtual SampleBufferPtr RetrieveAudio(const rational &timecode, const rational &length, const AudioParams& params) override;
|
||||
virtual void Close() override;
|
||||
|
||||
@@ -143,7 +143,6 @@ public:
|
||||
virtual bool SupportsVideo() override;
|
||||
virtual bool SupportsAudio() override;
|
||||
|
||||
virtual bool ProxyVideo(const QAtomicInt* cancelled, int divider) override;
|
||||
virtual bool ConformAudio(const QAtomicInt* cancelled, const AudioParams& p) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -154,7 +154,7 @@ bool OIIODecoder::Open()
|
||||
return true;
|
||||
}
|
||||
|
||||
FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider, bool /*use_proxies*/)
|
||||
FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider)
|
||||
{
|
||||
QMutexLocker locker(&mutex_);
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
virtual bool Probe(Footage *f, const QAtomicInt* cancelled) override;
|
||||
|
||||
virtual bool Open() override;
|
||||
virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider, bool use_proxies) override;
|
||||
virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override;
|
||||
virtual void Close() override;
|
||||
|
||||
virtual bool SupportsVideo() override;
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "tabs/preferencesgeneraltab.h"
|
||||
#include "tabs/preferencesbehaviortab.h"
|
||||
#include "tabs/preferencesappearancetab.h"
|
||||
#include "tabs/preferencesqualitytab.h"
|
||||
#include "tabs/preferencesdisktab.h"
|
||||
#include "tabs/preferencesaudiotab.h"
|
||||
#include "tabs/preferenceskeyboardtab.h"
|
||||
@@ -54,7 +53,6 @@ PreferencesDialog::PreferencesDialog(QWidget *parent, QMenuBar* main_menu_bar) :
|
||||
AddTab(new PreferencesGeneralTab(), tr("General"));
|
||||
AddTab(new PreferencesAppearanceTab(), tr("Appearance"));
|
||||
AddTab(new PreferencesBehaviorTab(), tr("Behavior"));
|
||||
AddTab(new PreferencesQualityTab(), tr("Quality"));
|
||||
AddTab(new PreferencesDiskTab(), tr("Disk"));
|
||||
AddTab(new PreferencesAudioTab(), tr("Audio"));
|
||||
AddTab(new PreferencesKeyboardTab(main_menu_bar), tr("Keyboard"));
|
||||
|
||||
@@ -24,8 +24,6 @@ set(OLIVE_SOURCES
|
||||
dialog/preferences/tabs/preferencesdisktab.cpp
|
||||
dialog/preferences/tabs/preferencesappearancetab.h
|
||||
dialog/preferences/tabs/preferencesappearancetab.cpp
|
||||
dialog/preferences/tabs/preferencesqualitytab.h
|
||||
dialog/preferences/tabs/preferencesqualitytab.cpp
|
||||
dialog/preferences/tabs/preferencesaudiotab.h
|
||||
dialog/preferences/tabs/preferencesaudiotab.cpp
|
||||
dialog/preferences/tabs/preferenceskeyboardtab.h
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/***
|
||||
|
||||
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 "preferencesqualitytab.h"
|
||||
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "audio/sampleformat.h"
|
||||
#include "render/colormanager.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
PreferencesQualityTab::PreferencesQualityTab()
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
|
||||
QHBoxLayout* profile_layout = new QHBoxLayout();
|
||||
profile_layout->setMargin(0);
|
||||
|
||||
profile_layout->addWidget(new QLabel(tr("Profile:")));
|
||||
|
||||
QComboBox* profile_combobox = new QComboBox();
|
||||
profile_combobox->addItem(tr("Preview (Offline)"));
|
||||
profile_combobox->addItem(tr("Export (Online)"));
|
||||
profile_layout->addWidget(profile_combobox);
|
||||
|
||||
layout->addLayout(profile_layout);
|
||||
|
||||
quality_stack_ = new QStackedWidget();
|
||||
|
||||
offline_group_ = new PreferencesQualityGroup(tr("Offline Quality"));
|
||||
offline_group_->SetBitDepth(PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOffline));
|
||||
offline_group_->ocio_method()->setCurrentIndex(ColorManager::GetOCIOMethodForMode(RenderMode::kOffline));
|
||||
quality_stack_->addWidget(offline_group_);
|
||||
|
||||
online_group_ = new PreferencesQualityGroup(tr("Online Quality"));
|
||||
online_group_->SetBitDepth(PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOnline));
|
||||
online_group_->ocio_method()->setCurrentIndex(ColorManager::GetOCIOMethodForMode(RenderMode::kOnline));
|
||||
quality_stack_->addWidget(online_group_);
|
||||
|
||||
layout->addWidget(quality_stack_);
|
||||
|
||||
connect(profile_combobox, SIGNAL(currentIndexChanged(int)), quality_stack_, SLOT(setCurrentIndex(int)));
|
||||
}
|
||||
|
||||
void PreferencesQualityTab::Accept()
|
||||
{
|
||||
ColorManager::SetOCIOMethodForMode(RenderMode::kOffline, static_cast<ColorManager::OCIOMethod>(offline_group_->ocio_method()->currentIndex()));
|
||||
ColorManager::SetOCIOMethodForMode(RenderMode::kOnline, static_cast<ColorManager::OCIOMethod>(online_group_->ocio_method()->currentIndex()));
|
||||
PixelFormat::instance()->SetConfiguredFormatForMode(RenderMode::kOffline, static_cast<PixelFormat::Format>(offline_group_->bit_depth_combobox()->currentData().toInt()));
|
||||
PixelFormat::instance()->SetConfiguredFormatForMode(RenderMode::kOnline, static_cast<PixelFormat::Format>(online_group_->bit_depth_combobox()->currentData().toInt()));
|
||||
}
|
||||
|
||||
PreferencesQualityGroup::PreferencesQualityGroup(const QString &title, QWidget *parent) :
|
||||
QGroupBox(title, parent)
|
||||
{
|
||||
QVBoxLayout* quality_outer_layout = new QVBoxLayout(this);
|
||||
|
||||
QGroupBox* video_group = new QGroupBox(tr("Video"));
|
||||
|
||||
QGridLayout* video_layout = new QGridLayout(video_group);
|
||||
quality_outer_layout->addWidget(video_group);
|
||||
|
||||
int row = 0;
|
||||
|
||||
video_layout->addWidget(new QLabel(tr("Pixel Format:")), row, 0);
|
||||
|
||||
bit_depth_combobox_ = new QComboBox();
|
||||
|
||||
// Populate with bit depths
|
||||
for (int i=0;i<PixelFormat::PIX_FMT_COUNT;i++) {
|
||||
PixelFormat::Format pix_fmt = static_cast<PixelFormat::Format>(i);
|
||||
|
||||
// We always render with an alpha channel internally
|
||||
if (PixelFormat::FormatHasAlphaChannel(pix_fmt)
|
||||
&& PixelFormat::FormatIsFloat(pix_fmt)) {
|
||||
bit_depth_combobox_->addItem(PixelFormat::GetName(pix_fmt),
|
||||
i);
|
||||
}
|
||||
}
|
||||
|
||||
video_layout->addWidget(bit_depth_combobox_, row, 1);
|
||||
|
||||
row++;
|
||||
|
||||
video_layout->addWidget(new QLabel(tr("OpenColorIO Method:")), row, 0);
|
||||
|
||||
ocio_method_ = new QComboBox();
|
||||
ocio_method_->addItem(tr("Fast"));
|
||||
ocio_method_->addItem(tr("Accurate"));
|
||||
video_layout->addWidget(ocio_method_, row, 1);
|
||||
|
||||
quality_outer_layout->addStretch();
|
||||
}
|
||||
|
||||
void PreferencesQualityGroup::SetBitDepth(PixelFormat::Format f)
|
||||
{
|
||||
for (int i=0;i<bit_depth_combobox_->count();i++) {
|
||||
if (bit_depth_combobox_->itemData(i) == f) {
|
||||
bit_depth_combobox_->setCurrentIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QComboBox *PreferencesQualityGroup::bit_depth_combobox()
|
||||
{
|
||||
return bit_depth_combobox_;
|
||||
}
|
||||
|
||||
QComboBox *PreferencesQualityGroup::ocio_method()
|
||||
{
|
||||
return ocio_method_;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -1,72 +0,0 @@
|
||||
/***
|
||||
|
||||
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 PREFERENCESQUALITYTAB_H
|
||||
#define PREFERENCESQUALITYTAB_H
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QGroupBox>
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include "render/pixelformat.h"
|
||||
#include "preferencestab.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class PreferencesQualityGroup : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PreferencesQualityGroup(const QString& title, QWidget* parent = nullptr);
|
||||
|
||||
void SetBitDepth(PixelFormat::Format f);
|
||||
|
||||
QComboBox* bit_depth_combobox();
|
||||
|
||||
QComboBox* ocio_method();
|
||||
|
||||
private:
|
||||
QComboBox* bit_depth_combobox_;
|
||||
|
||||
QComboBox* ocio_method_;
|
||||
|
||||
};
|
||||
|
||||
class PreferencesQualityTab : public PreferencesTab
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PreferencesQualityTab();
|
||||
|
||||
virtual void Accept() override;
|
||||
|
||||
private:
|
||||
QStackedWidget* quality_stack_;
|
||||
|
||||
PreferencesQualityGroup* offline_group_;
|
||||
|
||||
PreferencesQualityGroup* online_group_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // PREFERENCESQUALITYTAB_H
|
||||
@@ -1,3 +1,23 @@
|
||||
/***
|
||||
|
||||
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 SEQUENCEPARAM_H
|
||||
#define SEQUENCEPARAM_H
|
||||
|
||||
|
||||
@@ -28,9 +28,7 @@ OLIVE_NAMESPACE_ENTER
|
||||
|
||||
VideoStream::VideoStream() :
|
||||
start_time_(0),
|
||||
is_image_sequence_(false),
|
||||
is_generating_proxy_(false),
|
||||
using_proxy_(0)
|
||||
is_image_sequence_(false)
|
||||
{
|
||||
set_type(kVideo);
|
||||
}
|
||||
@@ -73,42 +71,7 @@ void VideoStream::set_image_sequence(bool e)
|
||||
is_image_sequence_ = e;
|
||||
}
|
||||
|
||||
bool VideoStream::is_generating_proxy()
|
||||
{
|
||||
QMutexLocker locker(proxy_access_lock());
|
||||
|
||||
return is_generating_proxy_;
|
||||
}
|
||||
|
||||
bool VideoStream::try_start_proxy()
|
||||
{
|
||||
QMutexLocker locker(proxy_access_lock());
|
||||
|
||||
if (is_generating_proxy_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
is_generating_proxy_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int VideoStream::using_proxy()
|
||||
{
|
||||
QMutexLocker locker(proxy_access_lock());
|
||||
|
||||
return using_proxy_;
|
||||
}
|
||||
|
||||
void VideoStream::set_proxy(const int ÷r, const QVector<int64_t> &index)
|
||||
{
|
||||
QMutexLocker locker(proxy_access_lock());
|
||||
|
||||
using_proxy_ = divider;
|
||||
frame_index_ = index;
|
||||
is_generating_proxy_ = false;
|
||||
}
|
||||
|
||||
/*
|
||||
int64_t VideoStream::get_closest_timestamp_in_frame_index(const rational &time)
|
||||
{
|
||||
// Get rough approximation of what the timestamp would be in this timebase
|
||||
@@ -143,6 +106,7 @@ int64_t VideoStream::get_closest_timestamp_in_frame_index(int64_t timestamp)
|
||||
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
void VideoStream::clear_frame_index()
|
||||
|
||||
@@ -47,9 +47,10 @@ public:
|
||||
bool is_image_sequence() const;
|
||||
void set_image_sequence(bool e);
|
||||
|
||||
/*
|
||||
int64_t get_closest_timestamp_in_frame_index(const rational& time);
|
||||
int64_t get_closest_timestamp_in_frame_index(int64_t timestamp);
|
||||
/*
|
||||
|
||||
void clear_frame_index();
|
||||
void append_frame_index(const int64_t& ts);
|
||||
bool is_frame_index_ready();
|
||||
@@ -59,24 +60,15 @@ public:
|
||||
bool save_frame_index(const QString& s);
|
||||
*/
|
||||
|
||||
bool is_generating_proxy();
|
||||
bool try_start_proxy();
|
||||
int using_proxy();
|
||||
void set_proxy(const int& divider, const QVector<int64_t>& index);
|
||||
|
||||
private:
|
||||
rational frame_rate_;
|
||||
|
||||
QVector<int64_t> frame_index_;
|
||||
//QVector<int64_t> frame_index_;
|
||||
|
||||
int64_t start_time_;
|
||||
|
||||
bool is_image_sequence_;
|
||||
|
||||
bool is_generating_proxy_;
|
||||
|
||||
int using_proxy_;
|
||||
|
||||
};
|
||||
|
||||
using VideoStreamPtr = std::shared_ptr<VideoStream>;
|
||||
|
||||
@@ -52,7 +52,9 @@ void AudioPlaybackCache::SetParameters(const AudioParams ¶ms)
|
||||
|
||||
// Our current audio cache is unusable, so we truncate it automatically
|
||||
TimeRange invalidate_range(0, NoLockGetLength());
|
||||
NoLockInvalidate(invalidate_range);
|
||||
if (invalidate_range.in() != invalidate_range.out()) {
|
||||
NoLockInvalidate(invalidate_range);
|
||||
}
|
||||
|
||||
locker.unlock();
|
||||
|
||||
|
||||
@@ -41,8 +41,7 @@ void OpenGLWorker::TextureToFrame(const QVariant &texture, FramePtr frame, const
|
||||
NodeValue OpenGLWorker::FrameToTexture(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) const
|
||||
{
|
||||
FramePtr frame = decoder->RetrieveVideo(range.in(),
|
||||
video_params().divider(),
|
||||
render_mode() == RenderMode::kOffline);
|
||||
video_params().divider());
|
||||
|
||||
NodeValue value;
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ QFuture<QList<QByteArray> > RenderBackend::Hash(const QList<rational> ×)
|
||||
hasher.addData(reinterpret_cast<const char*>(&video_params_.format()), sizeof(PixelFormat::Format));
|
||||
hasher.addData(reinterpret_cast<const char*>(&render_mode_), sizeof(RenderMode::Mode));
|
||||
|
||||
copied_viewer_node_->Hash(hasher, t);
|
||||
copied_viewer_node_->texture_input()->get_connected_node()->Hash(hasher, t);
|
||||
|
||||
hashes.append(hasher.result());
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ public:
|
||||
|
||||
void ClearVideoQueue();
|
||||
|
||||
void ProcessUpdateQueue();
|
||||
|
||||
/**
|
||||
* @brief Asynchronously generate a hash at a given time
|
||||
*/
|
||||
@@ -98,8 +100,6 @@ private:
|
||||
|
||||
void RunNextJob();
|
||||
|
||||
void ProcessUpdateQueue();
|
||||
|
||||
ViewerOutput* viewer_node_;
|
||||
|
||||
// VIDEO MEMBERS
|
||||
|
||||
@@ -18,7 +18,6 @@ add_subdirectory(cache)
|
||||
add_subdirectory(conform)
|
||||
add_subdirectory(export)
|
||||
add_subdirectory(project)
|
||||
add_subdirectory(proxy)
|
||||
add_subdirectory(render)
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
|
||||
Vendored
+2
@@ -18,5 +18,7 @@ set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
task/cache/cache.h
|
||||
task/cache/cache.cpp
|
||||
task/cache/footagecache.h
|
||||
task/cache/footagecache.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
Vendored
+1
-2
@@ -36,10 +36,9 @@ public:
|
||||
const AudioParams &aparams,
|
||||
bool in_out_only);
|
||||
|
||||
public slots:
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
protected:
|
||||
virtual QFuture<void> DownloadFrame(FramePtr frame, const QByteArray &hash) override;
|
||||
|
||||
virtual void FrameDownloaded(const QByteArray& hash, const std::list<rational>& times) override;
|
||||
|
||||
Vendored
+53
@@ -0,0 +1,53 @@
|
||||
/***
|
||||
|
||||
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 "footagecache.h"
|
||||
|
||||
#include "common/timecodefunctions.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
FootageCacheTask::FootageCacheTask(VideoStreamPtr footage, Sequence *sequence) :
|
||||
CacheTask(new ViewerOutput(), sequence->video_params(), sequence->audio_params(), false),
|
||||
footage_(footage)
|
||||
{
|
||||
viewer()->set_video_params(sequence->video_params());
|
||||
viewer()->set_audio_params(sequence->audio_params());
|
||||
backend()->SetVideoParams(sequence->video_params());
|
||||
backend()->SetAudioParams(sequence->audio_params());
|
||||
|
||||
video_node_ = new VideoInput();
|
||||
video_node_->SetFootage(footage);
|
||||
|
||||
NodeParam::ConnectEdge(video_node_->output(), viewer()->texture_input());
|
||||
|
||||
SetTitle(tr("Pre-caching %1:%2").arg(footage->footage()->filename(),
|
||||
QString::number(footage->index())));
|
||||
|
||||
backend()->ProcessUpdateQueue();
|
||||
}
|
||||
|
||||
FootageCacheTask::~FootageCacheTask()
|
||||
{
|
||||
delete viewer();
|
||||
delete video_node_;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
+13
-11
@@ -18,29 +18,31 @@
|
||||
|
||||
***/
|
||||
|
||||
#ifndef PROXYTASK_H
|
||||
#define PROXYTASK_H
|
||||
#ifndef FOOTAGECACHETASK_H
|
||||
#define FOOTAGECACHETASK_H
|
||||
|
||||
#include "project/item/footage/videostream.h"
|
||||
#include "task/task.h"
|
||||
#include "cache.h"
|
||||
#include "node/input/media/video/video.h"
|
||||
#include "project/item/footage/footage.h"
|
||||
#include "project/item/sequence/sequence.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class ProxyTask : public Task
|
||||
class FootageCacheTask : public CacheTask
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProxyTask(VideoStreamPtr stream, int divider);
|
||||
FootageCacheTask(VideoStreamPtr footage, Sequence* sequence);
|
||||
|
||||
public slots:
|
||||
virtual bool Run() override;
|
||||
virtual ~FootageCacheTask() override;
|
||||
|
||||
private:
|
||||
VideoStreamPtr stream_;
|
||||
VideoStreamPtr footage_;
|
||||
|
||||
int divider_;
|
||||
VideoInput* video_node_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // PROXYTASK_H
|
||||
#endif // FOOTAGECACHETASK_H
|
||||
@@ -32,7 +32,7 @@ class ConformTask : public Task
|
||||
public:
|
||||
ConformTask(AudioStreamPtr stream, const AudioParams& params);
|
||||
|
||||
public slots:
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -35,10 +35,9 @@ class ExportTask : public RenderTask
|
||||
public:
|
||||
ExportTask(ViewerOutput *viewer_node, ColorManager *color_manager, const ExportParams ¶ms);
|
||||
|
||||
public slots:
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
protected:
|
||||
virtual QFuture<void> DownloadFrame(FramePtr frame, const QByteArray &hash) override;
|
||||
|
||||
virtual void FrameDownloaded(const QByteArray& hash, const std::list<rational>& times) override;
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
return command_;
|
||||
}
|
||||
|
||||
public slots:
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
return projects_;
|
||||
}
|
||||
|
||||
public slots:
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
return project_;
|
||||
}
|
||||
|
||||
public slots:
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# 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/>.
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
task/proxy/proxy.h
|
||||
task/proxy/proxy.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -1,62 +0,0 @@
|
||||
/***
|
||||
|
||||
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 "proxy.h"
|
||||
|
||||
#include "codec/decoder.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
ProxyTask::ProxyTask(VideoStreamPtr stream, int divider) :
|
||||
stream_(stream),
|
||||
divider_(divider)
|
||||
{
|
||||
if (divider_ == 1) {
|
||||
SetTitle(tr("Generating full resolution proxy %1:%2").arg(stream_->footage()->filename(),
|
||||
QString::number(stream_->index())));
|
||||
} else {
|
||||
SetTitle(tr("Generating 1/%1 resolution proxy %2:%3").arg(QString::number(divider),
|
||||
stream_->footage()->filename(),
|
||||
QString::number(stream_->index())));
|
||||
}
|
||||
}
|
||||
|
||||
bool ProxyTask::Run()
|
||||
{
|
||||
if (stream_->footage()->decoder().isEmpty()) {
|
||||
SetError(tr("Failed to find decoder to conform audio stream"));
|
||||
return false;
|
||||
} else {
|
||||
DecoderPtr decoder = Decoder::CreateFromID(stream_->footage()->decoder());
|
||||
|
||||
decoder->set_stream(stream_);
|
||||
|
||||
connect(decoder.get(), &Decoder::IndexProgress, this, &ProxyTask::ProgressChanged);
|
||||
|
||||
if (decoder->ProxyVideo(&IsCancelled(), divider_)) {
|
||||
return true;
|
||||
} else {
|
||||
SetError(tr("Failed to generate proxy"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "core.h"
|
||||
#include "dialog/footageproperties/footageproperties.h"
|
||||
#include "dialog/sequence/sequence.h"
|
||||
#include "task/proxy/proxy.h"
|
||||
#include "task/cache/footagecache.h"
|
||||
#include "task/taskmanager.h"
|
||||
#include "widget/menu/menu.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
@@ -240,121 +240,142 @@ void ProjectExplorer::ShowContextMenu()
|
||||
Menu menu;
|
||||
Menu new_menu;
|
||||
|
||||
// FIXME: Support for multiple items and items other than Footage
|
||||
QList<Item*> selected_items = SelectedItems();
|
||||
context_menu_items_ = SelectedItems();
|
||||
|
||||
if (selected_items.isEmpty()) {
|
||||
if (context_menu_items_.isEmpty()) {
|
||||
// Items to show if no items are selected
|
||||
|
||||
// "New" menu
|
||||
new_menu.setTitle(tr("&New"));
|
||||
MenuShared::instance()->AddItemsForNewMenu(&new_menu);
|
||||
menu.addMenu(&new_menu);
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
// FIXME: These are both duplicates of items from MainMenu, is there any way to re-use the code?
|
||||
// "Import" action
|
||||
QAction* import_action = menu.addAction(tr("&Import..."));
|
||||
connect(import_action, &QAction::triggered, Core::instance(), &Core::DialogImportShow);
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
// Project properties action
|
||||
QAction* project_properties = menu.addAction(tr("&Project Properties..."));
|
||||
connect(project_properties, &QAction::triggered, Core::instance(), &Core::DialogProjectPropertiesShow);
|
||||
} else {
|
||||
context_menu_item_ = selected_items.first();
|
||||
|
||||
if (context_menu_item_->type() == Item::kFolder) {
|
||||
// Actions to add when only one item is selected
|
||||
if (context_menu_items_.size() == 1) {
|
||||
Item* context_menu_item = context_menu_items_.first();
|
||||
|
||||
QAction* open_in_new_tab = menu.addAction(tr("Open in New Tab"));
|
||||
connect(open_in_new_tab, &QAction::triggered, this, &ProjectExplorer::OpenContextMenuItemInNewTab);
|
||||
switch (context_menu_item->type()) {
|
||||
case Item::kFolder:
|
||||
{
|
||||
QAction* open_in_new_tab = menu.addAction(tr("Open in New Tab"));
|
||||
connect(open_in_new_tab, &QAction::triggered, this, &ProjectExplorer::OpenContextMenuItemInNewTab);
|
||||
|
||||
QAction* open_in_new_window = menu.addAction(tr("Open in New Window"));
|
||||
connect(open_in_new_window, &QAction::triggered, this, &ProjectExplorer::OpenContextMenuItemInNewWindow);
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
} else if (context_menu_item_->type() == Item::kFootage) {
|
||||
QString reveal_text;
|
||||
QAction* open_in_new_window = menu.addAction(tr("Open in New Window"));
|
||||
connect(open_in_new_window, &QAction::triggered, this, &ProjectExplorer::OpenContextMenuItemInNewWindow);
|
||||
break;
|
||||
}
|
||||
case Item::kFootage:
|
||||
{
|
||||
QString reveal_text;
|
||||
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
reveal_text = tr("Reveal in Explorer");
|
||||
reveal_text = tr("Reveal in Explorer");
|
||||
#elif defined(Q_OS_MAC)
|
||||
reveal_text = tr("Reveal in Finder");
|
||||
reveal_text = tr("Reveal in Finder");
|
||||
#else
|
||||
reveal_text = tr("Reveal in File Manager");
|
||||
#endif
|
||||
reveal_text = tr("Reveal in File Manager");
|
||||
#endif
|
||||
|
||||
QAction* reveal_action = menu.addAction(reveal_text);
|
||||
connect(reveal_action, &QAction::triggered, this, &ProjectExplorer::RevealSelectedFootage);
|
||||
QAction* reveal_action = menu.addAction(reveal_text);
|
||||
connect(reveal_action, &QAction::triggered, this, &ProjectExplorer::RevealSelectedFootage);
|
||||
break;
|
||||
}
|
||||
case Item::kSequence:
|
||||
break;
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
}
|
||||
|
||||
Footage* f = static_cast<Footage*>(context_menu_item_);
|
||||
bool all_items_are_footage = true;
|
||||
bool all_items_have_video_streams = true;
|
||||
bool all_items_are_footage_or_sequence = true;
|
||||
|
||||
if (f->HasStreamsOfType(Stream::kVideo)) {
|
||||
Menu* proxy_menu = new Menu(tr("Proxy"), &menu);
|
||||
menu.addMenu(proxy_menu);
|
||||
foreach (Item* i, context_menu_items_) {
|
||||
if (i->type() == Item::kFootage && !static_cast<Footage*>(i)->HasStreamsOfType(Stream::kVideo)) {
|
||||
all_items_have_video_streams = false;
|
||||
}
|
||||
|
||||
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(f->get_first_stream_of_type(Stream::kVideo));
|
||||
if (i->type() != Item::kFootage) {
|
||||
all_items_are_footage = false;
|
||||
}
|
||||
|
||||
if (video_stream->is_generating_proxy()) {
|
||||
|
||||
// Prevent multiple proxy actions from occurring at once
|
||||
QAction* cant_proxy_action = proxy_menu->addAction(tr("Proxy being generated..."));
|
||||
cant_proxy_action->setEnabled(false);
|
||||
|
||||
} else {
|
||||
|
||||
proxy_menu->addAction(tr("(None)"))->setData(0);
|
||||
proxy_menu->addSeparator();
|
||||
proxy_menu->addAction(tr("Full"))->setData(1);
|
||||
proxy_menu->addAction(tr("1/2"))->setData(2);
|
||||
proxy_menu->addAction(tr("1/4"))->setData(4);
|
||||
proxy_menu->addAction(tr("1/8"))->setData(8);
|
||||
|
||||
foreach (QAction* a, proxy_menu->actions()) {
|
||||
a->setCheckable(true);
|
||||
|
||||
if (a->data() == video_stream->using_proxy()) {
|
||||
a->setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
connect(proxy_menu, &Menu::triggered, this, &ProjectExplorer::ContextMenuStartProxy);
|
||||
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
if (i->type() != Item::kFootage && i->type() != Item::kSequence) {
|
||||
all_items_are_footage_or_sequence = false;
|
||||
}
|
||||
}
|
||||
|
||||
QAction* properties_action = menu.addAction(tr("P&roperties"));
|
||||
if (all_items_are_footage && all_items_have_video_streams) {
|
||||
Menu* proxy_menu = new Menu(tr("Proxy"), &menu);
|
||||
menu.addMenu(proxy_menu);
|
||||
|
||||
if (context_menu_item_->type() == Item::kFootage) {
|
||||
connect(properties_action, &QAction::triggered, this, &ProjectExplorer::ShowFootagePropertiesDialog);
|
||||
} else if (context_menu_item_->type() == Item::kSequence) {
|
||||
connect(properties_action, &QAction::triggered, this, &ProjectExplorer::ShowSequencePropertiesDialog);
|
||||
QList<ItemPtr> sequences = project()->get_items_of_type(Item::kSequence);
|
||||
|
||||
if (sequences.isEmpty()) {
|
||||
QAction* a = proxy_menu->addAction(tr("No sequences exist in project"));
|
||||
a->setEnabled(false);
|
||||
} else {
|
||||
foreach (ItemPtr i, sequences) {
|
||||
QAction* a = proxy_menu->addAction(tr("For \"%1\"").arg(i->name()));
|
||||
a->setData(Node::PtrToValue(i.get()));
|
||||
}
|
||||
|
||||
connect(proxy_menu, &Menu::triggered, this, &ProjectExplorer::ContextMenuStartProxy);
|
||||
}
|
||||
}
|
||||
|
||||
if (context_menu_items_.size() == 1) {
|
||||
menu.addSeparator();
|
||||
|
||||
QAction* properties_action = menu.addAction(tr("P&roperties"));
|
||||
connect(properties_action, &QAction::triggered, this, &ProjectExplorer::ShowItemPropertiesDialog);
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void ProjectExplorer::ShowFootagePropertiesDialog()
|
||||
void ProjectExplorer::ShowItemPropertiesDialog()
|
||||
{
|
||||
// FIXME: Support for multiple items
|
||||
FootagePropertiesDialog fpd(this, static_cast<Footage*>(context_menu_item_));
|
||||
fpd.exec();
|
||||
}
|
||||
Item* sel = context_menu_items_.first();
|
||||
|
||||
void ProjectExplorer::ShowSequencePropertiesDialog()
|
||||
{
|
||||
// FIXME: Support for multiple items
|
||||
SequenceDialog sd(static_cast<Sequence*>(context_menu_item_), SequenceDialog::kExisting, this);
|
||||
sd.exec();
|
||||
switch (sel->type()) {
|
||||
case Item::kFootage:
|
||||
{
|
||||
// FIXME: Support for multiple items
|
||||
FootagePropertiesDialog fpd(this, static_cast<Footage*>(sel));
|
||||
fpd.exec();
|
||||
break;
|
||||
}
|
||||
case Item::kFolder:
|
||||
{
|
||||
// FIXME: Rename dialog probably
|
||||
break;
|
||||
}
|
||||
case Item::kSequence:
|
||||
{
|
||||
// FIXME: Support for multiple items
|
||||
SequenceDialog sd(static_cast<Sequence*>(sel), SequenceDialog::kExisting, this);
|
||||
sd.exec();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectExplorer::RevealSelectedFootage()
|
||||
{
|
||||
Footage* footage = static_cast<Footage*>(context_menu_item_);
|
||||
Footage* footage = static_cast<Footage*>(context_menu_items_.first());
|
||||
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
// Explorer
|
||||
@@ -379,45 +400,33 @@ void ProjectExplorer::RevealSelectedFootage()
|
||||
|
||||
void ProjectExplorer::OpenContextMenuItemInNewTab()
|
||||
{
|
||||
Core::instance()->main_window()->FolderOpen(project(), context_menu_item_, false);
|
||||
Core::instance()->main_window()->FolderOpen(project(), context_menu_items_.first(), false);
|
||||
}
|
||||
|
||||
void ProjectExplorer::OpenContextMenuItemInNewWindow()
|
||||
{
|
||||
Core::instance()->main_window()->FolderOpen(project(), context_menu_item_, true);
|
||||
Core::instance()->main_window()->FolderOpen(project(), context_menu_items_.first(), true);
|
||||
}
|
||||
|
||||
void ProjectExplorer::ContextMenuStartProxy(QAction *a)
|
||||
{
|
||||
// Find video stream
|
||||
VideoStreamPtr video_stream = nullptr;
|
||||
QList<VideoStreamPtr> video_streams;
|
||||
|
||||
foreach (StreamPtr s, static_cast<Footage*>(context_menu_item_)->streams()) {
|
||||
if (s->type() == Stream::kVideo) {
|
||||
video_stream = std::static_pointer_cast<VideoStream>(s);
|
||||
break;
|
||||
// To get here, the `context_menu_items_` must be all kFootage
|
||||
foreach (Item* i, context_menu_items_) {
|
||||
VideoStreamPtr s = std::static_pointer_cast<VideoStream>(static_cast<Footage*>(i)->get_first_stream_of_type(Stream::kVideo));
|
||||
|
||||
if (s) {
|
||||
video_streams.append(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (!video_stream) {
|
||||
return;
|
||||
}
|
||||
Sequence* sequence = Node::ValueToPtr<Sequence>(a->data());
|
||||
|
||||
int chosen_proxy_setting = a->data().toInt();
|
||||
|
||||
if (chosen_proxy_setting != video_stream->using_proxy()) {
|
||||
if (!a->data().toInt()) {
|
||||
|
||||
// 0 means disable the proxy
|
||||
video_stream->set_proxy(0, QVector<int64_t>());
|
||||
|
||||
} else if (video_stream->try_start_proxy()) {
|
||||
|
||||
// Start a background task for proxying
|
||||
ProxyTask* proxy_task = new ProxyTask(video_stream, a->data().toInt());
|
||||
TaskManager::instance()->AddTask(proxy_task);
|
||||
|
||||
}
|
||||
// Start a background task for proxying
|
||||
foreach (VideoStreamPtr video_stream, video_streams) {
|
||||
FootageCacheTask* proxy_task = new FootageCacheTask(video_stream, sequence);
|
||||
TaskManager::instance()->AddTask(proxy_task);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ private:
|
||||
|
||||
QTimer rename_timer_;
|
||||
|
||||
Item* context_menu_item_;
|
||||
QList<Item*> context_menu_items_;
|
||||
|
||||
private slots:
|
||||
void ItemClickedSlot(const QModelIndex& index);
|
||||
@@ -161,9 +161,7 @@ private slots:
|
||||
|
||||
void ShowContextMenu();
|
||||
|
||||
void ShowFootagePropertiesDialog();
|
||||
|
||||
void ShowSequencePropertiesDialog();
|
||||
void ShowItemPropertiesDialog();
|
||||
|
||||
void RevealSelectedFootage();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user