diff --git a/app/codec/decoder.cpp b/app/codec/decoder.cpp index 6e9527405..00b3fe8a4 100644 --- a/app/codec/decoder.cpp +++ b/app/codec/decoder.cpp @@ -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; diff --git a/app/codec/decoder.h b/app/codec/decoder.h index 31b8a7b4c..1e2bfddfa 100644 --- a/app/codec/decoder.h +++ b/app/codec/decoder.h @@ -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 * diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 2ec1a4fb8..f23c7d01e 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -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(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(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 index(index_file.size() / sizeof(int64_t)); - - index_file.read(reinterpret_cast(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(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 frame_index; - QVector< QFuture > 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 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(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 diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index a0efce468..009a9a5ae 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -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: diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index 9c8ca85c8..e5f7b74c8 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -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_); diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h index 276caf825..f481481b1 100644 --- a/app/codec/oiio/oiiodecoder.h +++ b/app/codec/oiio/oiiodecoder.h @@ -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; diff --git a/app/dialog/preferences/preferences.cpp b/app/dialog/preferences/preferences.cpp index 872cab711..6ca624c07 100644 --- a/app/dialog/preferences/preferences.cpp +++ b/app/dialog/preferences/preferences.cpp @@ -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")); diff --git a/app/dialog/preferences/tabs/CMakeLists.txt b/app/dialog/preferences/tabs/CMakeLists.txt index 65259cc3b..62c3270c1 100644 --- a/app/dialog/preferences/tabs/CMakeLists.txt +++ b/app/dialog/preferences/tabs/CMakeLists.txt @@ -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 diff --git a/app/dialog/preferences/tabs/preferencesqualitytab.cpp b/app/dialog/preferences/tabs/preferencesqualitytab.cpp deleted file mode 100644 index 32884c5f3..000000000 --- a/app/dialog/preferences/tabs/preferencesqualitytab.cpp +++ /dev/null @@ -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 . - -***/ - -#include "preferencesqualitytab.h" - -#include -#include -#include - -#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(offline_group_->ocio_method()->currentIndex())); - ColorManager::SetOCIOMethodForMode(RenderMode::kOnline, static_cast(online_group_->ocio_method()->currentIndex())); - PixelFormat::instance()->SetConfiguredFormatForMode(RenderMode::kOffline, static_cast(offline_group_->bit_depth_combobox()->currentData().toInt())); - PixelFormat::instance()->SetConfiguredFormatForMode(RenderMode::kOnline, static_cast(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(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;icount();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 diff --git a/app/dialog/preferences/tabs/preferencesqualitytab.h b/app/dialog/preferences/tabs/preferencesqualitytab.h deleted file mode 100644 index beae8ff62..000000000 --- a/app/dialog/preferences/tabs/preferencesqualitytab.h +++ /dev/null @@ -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 . - -***/ - -#ifndef PREFERENCESQUALITYTAB_H -#define PREFERENCESQUALITYTAB_H - -#include -#include -#include -#include - -#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 diff --git a/app/dialog/sequence/sequencepreset.h b/app/dialog/sequence/sequencepreset.h index 5e546a228..fb4ba9ab2 100644 --- a/app/dialog/sequence/sequencepreset.h +++ b/app/dialog/sequence/sequencepreset.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 . + +***/ + #ifndef SEQUENCEPARAM_H #define SEQUENCEPARAM_H diff --git a/app/project/item/footage/videostream.cpp b/app/project/item/footage/videostream.cpp index fe02f5c58..293a91900 100644 --- a/app/project/item/footage/videostream.cpp +++ b/app/project/item/footage/videostream.cpp @@ -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 &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() diff --git a/app/project/item/footage/videostream.h b/app/project/item/footage/videostream.h index 837fcafd9..f8a81b898 100644 --- a/app/project/item/footage/videostream.h +++ b/app/project/item/footage/videostream.h @@ -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& index); - private: rational frame_rate_; - QVector frame_index_; + //QVector frame_index_; int64_t start_time_; bool is_image_sequence_; - bool is_generating_proxy_; - - int using_proxy_; - }; using VideoStreamPtr = std::shared_ptr; diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index 09a04685b..c63a7b51a 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -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(); diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp index 267fb775d..e7ad361e4 100644 --- a/app/render/backend/opengl/openglworker.cpp +++ b/app/render/backend/opengl/openglworker.cpp @@ -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; diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index 4d49105d7..73122d889 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -127,7 +127,7 @@ QFuture > RenderBackend::Hash(const QList ×) hasher.addData(reinterpret_cast(&video_params_.format()), sizeof(PixelFormat::Format)); hasher.addData(reinterpret_cast(&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()); } diff --git a/app/render/backend/renderbackend.h b/app/render/backend/renderbackend.h index ee752ec89..a56569636 100644 --- a/app/render/backend/renderbackend.h +++ b/app/render/backend/renderbackend.h @@ -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 diff --git a/app/task/CMakeLists.txt b/app/task/CMakeLists.txt index a3b0e06ad..02eaab8e4 100644 --- a/app/task/CMakeLists.txt +++ b/app/task/CMakeLists.txt @@ -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 diff --git a/app/task/cache/CMakeLists.txt b/app/task/cache/CMakeLists.txt index 85f683a5d..5557f3f39 100644 --- a/app/task/cache/CMakeLists.txt +++ b/app/task/cache/CMakeLists.txt @@ -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 ) diff --git a/app/task/cache/cache.h b/app/task/cache/cache.h index 93e21b247..bab3cffc8 100644 --- a/app/task/cache/cache.h +++ b/app/task/cache/cache.h @@ -36,10 +36,9 @@ public: const AudioParams &aparams, bool in_out_only); -public slots: +protected: virtual bool Run() override; -protected: virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) override; virtual void FrameDownloaded(const QByteArray& hash, const std::list& times) override; diff --git a/app/task/cache/footagecache.cpp b/app/task/cache/footagecache.cpp new file mode 100644 index 000000000..9a21bc9f8 --- /dev/null +++ b/app/task/cache/footagecache.cpp @@ -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 . + +***/ + +#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 diff --git a/app/task/proxy/proxy.h b/app/task/cache/footagecache.h similarity index 64% rename from app/task/proxy/proxy.h rename to app/task/cache/footagecache.h index 977e8cdb1..f48218532 100644 --- a/app/task/proxy/proxy.h +++ b/app/task/cache/footagecache.h @@ -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 diff --git a/app/task/conform/conform.h b/app/task/conform/conform.h index 0ceb9ef5f..b65d2d689 100644 --- a/app/task/conform/conform.h +++ b/app/task/conform/conform.h @@ -32,7 +32,7 @@ class ConformTask : public Task public: ConformTask(AudioStreamPtr stream, const AudioParams& params); -public slots: +protected: virtual bool Run() override; private: diff --git a/app/task/export/export.h b/app/task/export/export.h index 8a8c7ae7f..dcbae30f0 100644 --- a/app/task/export/export.h +++ b/app/task/export/export.h @@ -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 DownloadFrame(FramePtr frame, const QByteArray &hash) override; virtual void FrameDownloaded(const QByteArray& hash, const std::list& times) override; diff --git a/app/task/project/import/import.h b/app/task/project/import/import.h index 2a439e605..d092fa192 100644 --- a/app/task/project/import/import.h +++ b/app/task/project/import/import.h @@ -42,7 +42,7 @@ public: return command_; } -public slots: +protected: virtual bool Run() override; private: diff --git a/app/task/project/load/load.h b/app/task/project/load/load.h index 0f2d88e82..fa203abfe 100644 --- a/app/task/project/load/load.h +++ b/app/task/project/load/load.h @@ -37,7 +37,7 @@ public: return projects_; } -public slots: +protected: virtual bool Run() override; private: diff --git a/app/task/project/save/save.h b/app/task/project/save/save.h index ac3933294..6d7f7dc14 100644 --- a/app/task/project/save/save.h +++ b/app/task/project/save/save.h @@ -37,7 +37,7 @@ public: return project_; } -public slots: +protected: virtual bool Run() override; private: diff --git a/app/task/proxy/CMakeLists.txt b/app/task/proxy/CMakeLists.txt deleted file mode 100644 index 6d7ca02aa..000000000 --- a/app/task/proxy/CMakeLists.txt +++ /dev/null @@ -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 . - -set(OLIVE_SOURCES - ${OLIVE_SOURCES} - task/proxy/proxy.h - task/proxy/proxy.cpp - PARENT_SCOPE -) diff --git a/app/task/proxy/proxy.cpp b/app/task/proxy/proxy.cpp deleted file mode 100644 index 5ff5f9cc5..000000000 --- a/app/task/proxy/proxy.cpp +++ /dev/null @@ -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 . - -***/ - -#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 diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index d6c109834..ba45a38b4 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -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 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(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(i)->HasStreamsOfType(Stream::kVideo)) { + all_items_have_video_streams = false; + } - VideoStreamPtr video_stream = std::static_pointer_cast(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 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(context_menu_item_)); - fpd.exec(); -} + Item* sel = context_menu_items_.first(); -void ProjectExplorer::ShowSequencePropertiesDialog() -{ - // FIXME: Support for multiple items - SequenceDialog sd(static_cast(context_menu_item_), SequenceDialog::kExisting, this); - sd.exec(); + switch (sel->type()) { + case Item::kFootage: + { + // FIXME: Support for multiple items + FootagePropertiesDialog fpd(this, static_cast(sel)); + fpd.exec(); + break; + } + case Item::kFolder: + { + // FIXME: Rename dialog probably + break; + } + case Item::kSequence: + { + // FIXME: Support for multiple items + SequenceDialog sd(static_cast(sel), SequenceDialog::kExisting, this); + sd.exec(); + break; + } + } } void ProjectExplorer::RevealSelectedFootage() { - Footage* footage = static_cast(context_menu_item_); + Footage* footage = static_cast(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 video_streams; - foreach (StreamPtr s, static_cast(context_menu_item_)->streams()) { - if (s->type() == Stream::kVideo) { - video_stream = std::static_pointer_cast(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(static_cast(i)->get_first_stream_of_type(Stream::kVideo)); + + if (s) { + video_streams.append(s); } } - if (!video_stream) { - return; - } + Sequence* sequence = Node::ValueToPtr(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()); - - } 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); } } diff --git a/app/widget/projectexplorer/projectexplorer.h b/app/widget/projectexplorer/projectexplorer.h index 69bce4b49..2fe097bbd 100644 --- a/app/widget/projectexplorer/projectexplorer.h +++ b/app/widget/projectexplorer/projectexplorer.h @@ -144,7 +144,7 @@ private: QTimer rename_timer_; - Item* context_menu_item_; + QList 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();