footage: merge video and image streams and improve image sequence import process

Image streams were initially separated from video streams, but they're now
joined with a parameter defining if they're a still image, image sequence,
or regular video. The image sequence import process has also improved so
that if images from the same sequence are imported too, they'll either be
ignored or the user won't be asked again for those if they should be an
image sequence (fixes #1193). Also shifts decoder "probe" process to return
an item, useful if the decoder returns a non-footage item.
This commit is contained in:
itsmattkc
2020-09-26 19:45:07 +10:00
parent 85abd6c6b4
commit 6db591e89f
37 changed files with 613 additions and 779 deletions
-2
View File
@@ -21,8 +21,6 @@ set(OLIVE_SOURCES
project/item/footage/audiostream.cpp
project/item/footage/footage.h
project/item/footage/footage.cpp
project/item/footage/imagestream.h
project/item/footage/imagestream.cpp
project/item/footage/stream.h
project/item/footage/stream.cpp
project/item/footage/videostream.h
+5
View File
@@ -96,4 +96,9 @@ void AudioStream::append_conformed_version(const AudioParams &params)
emit ConformAppended(params);
}
QIcon AudioStream::icon() const
{
return icon::Audio;
}
OLIVE_NAMESPACE_EXIT
+2
View File
@@ -53,6 +53,8 @@ public:
bool has_conformed_version(const AudioParams& params);
void append_conformed_version(const AudioParams& params);
virtual QIcon icon() const override;
signals:
void ConformAppended(OLIVE_NAMESPACE::AudioParams params);
+30 -92
View File
@@ -43,6 +43,7 @@ Footage::~Footage()
void Footage::Load(QXmlStreamReader *reader, XMLNodeData &xml_node_data, const QAtomicInt* cancelled)
{
/*
QXmlStreamAttributes attributes = reader->attributes();
foreach (const QXmlStreamAttribute& attr, attributes) {
@@ -110,6 +111,7 @@ void Footage::Load(QXmlStreamReader *reader, XMLNodeData &xml_node_data, const Q
reader->skipCurrentElement();
}
}
*/
}
void Footage::Save(QXmlStreamWriter *writer) const
@@ -128,25 +130,18 @@ void Footage::Save(QXmlStreamWriter *writer) const
writer->writeEndElement(); // footage
}
const Footage::Status& Footage::status() const
{
return status_;
}
void Footage::set_status(const Footage::Status &status)
{
status_ = status;
UpdateTooltip();
}
void Footage::Clear()
{
// Clear all streams
ClearStreams();
// Reset ready state
set_status(kUnprobed);
valid_ = false;
}
void Footage::SetValid()
{
valid_ = true;
}
const QString &Footage::filename() const
@@ -210,34 +205,21 @@ void Footage::set_decoder(const QString &id)
QIcon Footage::icon()
{
switch (status_) {
case kUnprobed:
case kUnindexed:
// FIXME Set a waiting icon
return QIcon();
case kReady:
if (HasStreamsOfType(Stream::kVideo)) {
if (valid_ && !streams_.isEmpty()) {
StreamPtr first_stream = streams_.first();
// Prioritize the video icon
return icon::Video;
} else if (HasStreamsOfType(Stream::kAudio)) {
// Otherwise assume it's audio only
if (first_stream->type() == Stream::kVideo) {
if (std::static_pointer_cast<VideoStream>(first_stream)->video_type() == VideoStream::kVideoTypeStill) {
return icon::Image;
} else {
return icon::Video;
}
} else if (first_stream->type() == Stream::kAudio) {
return icon::Audio;
} else if (HasStreamsOfType(Stream::kImage)) {
// Otherwise assume it's an image
return icon::Image;
}
/* fall-through */
case kInvalid:
return icon::Error;
}
return QIcon();
return icon::Error;
}
QString Footage::duration()
@@ -248,7 +230,7 @@ QString Footage::duration()
rational longest;
foreach (StreamPtr stream, streams_) {
if (stream->type() == Stream::kVideo || stream->type() == Stream::kAudio) {
if (stream->enabled() && (stream->type() == Stream::kVideo || stream->type() == Stream::kAudio)) {
rational this_stream_dur = Timecode::timestamp_to_time(stream->duration(),
stream->timebase());
@@ -300,7 +282,8 @@ QString Footage::rate()
return QString();
}
if (HasStreamsOfType(Stream::kVideo)) {
if (HasStreamsOfType(Stream::kVideo)
&& std::static_pointer_cast<VideoStream>(get_first_stream_of_type(Stream::kVideo))->video_type() != VideoStream::kVideoTypeStill) {
// This is a video editor, prioritize video streams
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(get_first_stream_of_type(Stream::kVideo));
return QCoreApplication::translate("Footage", "%1 FPS").arg(video_stream->frame_rate().toDouble());
@@ -331,10 +314,6 @@ quint64 Footage::get_enabled_stream_flags() const
void Footage::ClearStreams()
{
if (streams_.empty()) {
return;
}
// Delete all streams
streams_.clear();
}
@@ -343,7 +322,7 @@ bool Footage::HasStreamsOfType(const Stream::Type &type) const
{
// Return true if any streams are video streams
foreach (StreamPtr stream, streams_) {
if (stream->type() == type) {
if (stream->enabled() && stream->type() == type) {
return true;
}
}
@@ -354,7 +333,7 @@ bool Footage::HasStreamsOfType(const Stream::Type &type) const
StreamPtr Footage::get_first_stream_of_type(const Stream::Type &type) const
{
foreach (StreamPtr stream, streams_) {
if (stream->type() == type) {
if (stream->enabled() && stream->type() == type) {
return stream;
}
}
@@ -364,62 +343,21 @@ StreamPtr Footage::get_first_stream_of_type(const Stream::Type &type) const
void Footage::UpdateTooltip()
{
switch (status_) {
case kUnprobed:
set_tooltip(QCoreApplication::translate("Footage", "Waiting for probe"));
break;
case kUnindexed:
set_tooltip(QCoreApplication::translate("Footage", "Waiting for index"));
break;
case kReady:
{
if (valid_) {
QString tip = QCoreApplication::translate("Footage", "Filename: %1").arg(filename());
if (!streams_.isEmpty()) {
tip.append("\n");
for (int i=0;i<streams_.size();i++) {
StreamPtr s = streams_.at(i);
switch (s->type()) {
case Stream::kVideo:
case Stream::kImage:
{
ImageStreamPtr vs = std::static_pointer_cast<ImageStream>(s);
tip.append(
QCoreApplication::translate("Footage",
"\nVideo %1: %2x%3").arg(QString::number(i),
QString::number(vs->width()),
QString::number(vs->height()))
);
break;
}
case Stream::kAudio:
{
AudioStreamPtr as = std::static_pointer_cast<AudioStream>(s);
tip.append(
QCoreApplication::translate("Footage",
"\nAudio %1: %2 channels %3 Hz").arg(QString::number(i),
QString::number(as->channels()),
QString::number(as->sample_rate()))
);
break;
}
default:
break;
foreach (StreamPtr s, streams_) {
if (s->enabled()) {
tip.append("\n");
tip.append(s->description());
}
}
}
set_tooltip(tip);
}
break;
case kInvalid:
set_tooltip(QCoreApplication::translate("Footage", "An error occurred probing this footage"));
break;
} else {
set_tooltip(QCoreApplication::translate("Footage", "This footage is not valid for use"));
}
}
+12 -33
View File
@@ -27,7 +27,6 @@
#include "common/rational.h"
#include "project/item/item.h"
#include "project/item/footage/audiostream.h"
#include "project/item/footage/imagestream.h"
#include "project/item/footage/videostream.h"
#include "timeline/timelinepoints.h"
@@ -43,13 +42,6 @@ OLIVE_NAMESPACE_ENTER
class Footage : public Item, public TimelinePoints
{
public:
enum Status {
kUnprobed,
kUnindexed,
kReady,
kInvalid
};
/**
* @brief Footage Constructor
*/
@@ -72,26 +64,6 @@ public:
*/
virtual void Save(QXmlStreamWriter *writer) const override;
/**
* @brief Check the ready state of this Footage object
*
* @return
*
* If the Footage has been successfully probed, this will return TRUE.
*/
const Status& status() const;
/**
* @brief Set ready state
*
* This should only be set by olive::ProbeMedia. Sets the Footage's current status to a member of enum
* Footage::Status.
*
* This function also runs UpdateIcon() and UpdateTooltip(). If you need to override the tooltip (e.g. for an error
* message), you must run set_tooltip() *after* running set_status();
*/
void set_status(const Status& status);
/**
* @brief Reset Footage state ready for running through Probe() again
*
@@ -104,6 +76,16 @@ public:
*/
void Clear();
bool IsValid() const
{
return valid_;
}
/**
* @brief Sets this footage to valid and ready to use
*/
void SetValid();
/**
* @brief Return the current filename of this Footage object
*/
@@ -254,16 +236,13 @@ private:
*/
QList<StreamPtr> streams_;
/**
* @brief Internal ready setting
*/
Status status_;
/**
* @brief Internal attached decoder ID
*/
QString decoder_;
bool valid_;
};
using FootagePtr = std::shared_ptr<Footage>;
-136
View File
@@ -1,136 +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 "imagestream.h"
#include "common/xmlutils.h"
#include "footage.h"
#include "project/project.h"
#include "render/colormanager.h"
OLIVE_NAMESPACE_ENTER
ImageStream::ImageStream() :
premultiplied_alpha_(false),
interlacing_(VideoParams::kInterlaceNone),
pixel_aspect_ratio_(1)
{
set_type(kImage);
}
void ImageStream::FootageSetEvent(Footage *f)
{
// For some reason this connection fails if we don't explicitly specify DirectConnection
connect(f->project()->color_manager(),
&ColorManager::ConfigChanged,
this,
&ImageStream::ColorConfigChanged,
Qt::DirectConnection);
connect(f->project()->color_manager(),
&ColorManager::DefaultInputColorSpaceChanged,
this,
&ImageStream::DefaultColorSpaceChanged,
Qt::DirectConnection);
}
void ImageStream::LoadCustomParameters(QXmlStreamReader *reader)
{
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("colorspace")) {
set_colorspace(reader->readElementText());
} else {
reader->skipCurrentElement();
}
}
}
void ImageStream::SaveCustomParameters(QXmlStreamWriter *writer) const
{
writer->writeTextElement("colorspace", colorspace_);
}
QString ImageStream::description() const
{
return QCoreApplication::translate("Stream", "%1: Image - %2x%3").arg(QString::number(index()),
QString::number(width()),
QString::number(height()));
}
bool ImageStream::premultiplied_alpha() const
{
return premultiplied_alpha_;
}
void ImageStream::set_premultiplied_alpha(bool e)
{
premultiplied_alpha_ = e;
emit ParametersChanged();
}
const QString &ImageStream::colorspace(bool default_if_empty) const
{
if (colorspace_.isEmpty() && default_if_empty) {
return footage()->project()->color_manager()->GetDefaultInputColorSpace();
} else {
return colorspace_;
}
}
void ImageStream::set_colorspace(const QString &color)
{
colorspace_ = color;
emit ParametersChanged();
}
QString ImageStream::get_colorspace_match_string() const
{
return QStringLiteral("%1:%2").arg(footage()->project()->color_manager()->GetConfigFilename(),
colorspace());
}
void ImageStream::ColorConfigChanged()
{
ColorManager* color_manager = footage()->project()->color_manager();
// Check if this colorspace is in the new config
if (!colorspace_.isEmpty()) {
QStringList colorspaces = color_manager->ListAvailableColorspaces();
if (!colorspaces.contains(colorspace_)) {
// Set to empty if not
colorspace_.clear();
}
}
// Either way, the color calculation has likely changed so we signal here
emit ParametersChanged();
}
void ImageStream::DefaultColorSpaceChanged()
{
// If no colorspace is set, this stream uses the default color space and it's just changed
if (colorspace_.isEmpty()) {
emit ParametersChanged();
}
}
OLIVE_NAMESPACE_EXIT
-137
View File
@@ -1,137 +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 IMAGESTREAM_H
#define IMAGESTREAM_H
#include "render/pixelformat.h"
#include "render/videoparams.h"
#include "stream.h"
OLIVE_NAMESPACE_ENTER
/**
* @brief A Stream derivative containing video-specific information
*/
class ImageStream : public Stream
{
Q_OBJECT
public:
ImageStream();
virtual QString description() const override;
const int& width() const
{
return width_;
}
void set_width(const int& width)
{
width_ = width;
}
const int& height() const
{
return height_;
}
void set_height(const int& height)
{
height_ = height;
}
const PixelFormat::Format& format() const
{
return format_;
}
void set_format(const PixelFormat::Format& format)
{
format_ = format;
}
bool premultiplied_alpha() const;
void set_premultiplied_alpha(bool e);
const QString& colorspace(bool default_if_empty = true) const;
void set_colorspace(const QString& color);
QString get_colorspace_match_string() const;
VideoParams::Interlacing interlacing() const
{
return interlacing_;
}
void set_interlacing(VideoParams::Interlacing i)
{
interlacing_ = i;
emit ParametersChanged();
}
const rational& pixel_aspect_ratio() const
{
return pixel_aspect_ratio_;
}
void set_pixel_aspect_ratio(const rational& r)
{
// Auto-correct null aspect ratio to 1:1
if (r.isNull()) {
pixel_aspect_ratio_ = 1;
} else {
pixel_aspect_ratio_ = r;
}
emit ParametersChanged();
}
protected:
virtual void FootageSetEvent(Footage*) override;
virtual void LoadCustomParameters(QXmlStreamReader *reader) override;
virtual void SaveCustomParameters(QXmlStreamWriter* writer) const override;
private:
int width_;
int height_;
bool premultiplied_alpha_;
QString colorspace_;
VideoParams::Interlacing interlacing_;
PixelFormat::Format format_;
rational pixel_aspect_ratio_;
private slots:
void ColorConfigChanged();
void DefaultColorSpaceChanged();
};
using ImageStreamPtr = std::shared_ptr<ImageStream>;
OLIVE_NAMESPACE_EXIT
#endif // IMAGESTREAM_H
+1 -17
View File
@@ -78,7 +78,6 @@ Footage *Stream::footage() const
void Stream::set_footage(Footage *f)
{
footage_ = f;
FootageSetEvent(footage_);
}
const rational &Stream::timebase() const
@@ -123,19 +122,8 @@ void Stream::set_enabled(bool e)
enabled_ = e;
}
QIcon Stream::IconFromType(const Stream::Type &type)
QIcon Stream::icon() const
{
switch (type) {
case Stream::kVideo:
return icon::Video;
case Stream::kImage:
return icon::Image;
case Stream::kAudio:
return icon::Audio;
default:
break;
}
return QIcon();
}
@@ -144,10 +132,6 @@ QMutex *Stream::proxy_access_lock()
return &proxy_access_lock_;
}
void Stream::FootageSetEvent(Footage*)
{
}
void Stream::LoadCustomParameters(QXmlStreamReader* reader)
{
reader->skipCurrentElement();
+3 -5
View File
@@ -28,6 +28,7 @@
#include <QXmlStreamWriter>
#include "common/rational.h"
#include "ui/icons/icons.h"
OLIVE_NAMESPACE_ENTER
@@ -52,8 +53,7 @@ public:
kAudio,
kData,
kSubtitle,
kAttachment,
kImage = 100
kAttachment
};
/**
@@ -90,13 +90,11 @@ public:
bool enabled() const;
void set_enabled(bool e);
static QIcon IconFromType(const Type& type);
virtual QIcon icon() const;
QMutex* proxy_access_lock();
protected:
virtual void FootageSetEvent(Footage*);
virtual void LoadCustomParameters(QXmlStreamReader *reader);
virtual void SaveCustomParameters(QXmlStreamWriter* writer) const;
+87 -110
View File
@@ -23,21 +23,35 @@
#include <QFile>
#include "common/timecodefunctions.h"
#include "common/xmlutils.h"
#include "footage.h"
#include "project/project.h"
#include "render/colormanager.h"
OLIVE_NAMESPACE_ENTER
VideoStream::VideoStream() :
premultiplied_alpha_(false),
interlacing_(VideoParams::kInterlaceNone),
video_type_(VideoStream::kVideoTypeVideo),
pixel_aspect_ratio_(1),
start_time_(0),
is_image_sequence_(false)
{
set_type(kVideo);
set_type(Stream::kVideo);
}
QString VideoStream::description() const
{
return QCoreApplication::translate("Stream", "%1: Video - %2x%3").arg(QString::number(index()),
QString::number(width()),
QString::number(height()));
if (video_type_ == VideoStream::kVideoTypeStill) {
return QCoreApplication::translate("Stream", "%1: Image - %2x%3").arg(QString::number(index()),
QString::number(width()),
QString::number(height()));
} else {
return QCoreApplication::translate("Stream", "%1: Video - %2x%3").arg(QString::number(index()),
QString::number(width()),
QString::number(height()));
}
}
const rational &VideoStream::frame_rate() const
@@ -76,125 +90,88 @@ int64_t VideoStream::get_time_in_timebase_units(const rational &time) const
return Timecode::time_to_timestamp(time, timebase()) + start_time();
}
/*
int64_t VideoStream::get_closest_timestamp_in_frame_index(const rational &time)
QIcon VideoStream::icon() const
{
// Get rough approximation of what the timestamp would be in this timebase
int64_t target_ts = Timecode::time_to_timestamp(time, timebase());
// Find closest actual timebase in the file
return get_closest_timestamp_in_frame_index(target_ts);
if (video_type_ == kVideoTypeStill) {
return icon::Image;
} else {
return icon::Video;
}
}
int64_t VideoStream::get_closest_timestamp_in_frame_index(int64_t timestamp)
void VideoStream::LoadCustomParameters(QXmlStreamReader *reader)
{
QMutexLocker locker(proxy_access_lock());
if (!frame_index_.isEmpty()) {
if (timestamp <= frame_index_.first()) {
return frame_index_.first();
} else if (timestamp >= frame_index_.last()) {
return frame_index_.last();
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("colorspace")) {
set_colorspace(reader->readElementText());
} else {
// Use index to find closest frame in file
for (int i=1;i<frame_index_.size();i++) {
int64_t this_ts = frame_index_.at(i);
reader->skipCurrentElement();
}
}
}
if (this_ts == timestamp) {
return timestamp;
} else if (this_ts > timestamp) {
return frame_index_.at(i - 1);
}
}
void VideoStream::SaveCustomParameters(QXmlStreamWriter *writer) const
{
writer->writeTextElement("colorspace", colorspace_);
}
bool VideoStream::premultiplied_alpha() const
{
return premultiplied_alpha_;
}
void VideoStream::set_premultiplied_alpha(bool e)
{
premultiplied_alpha_ = e;
emit ParametersChanged();
}
const QString &VideoStream::colorspace(bool default_if_empty) const
{
if (colorspace_.isEmpty() && default_if_empty) {
return footage()->project()->color_manager()->GetDefaultInputColorSpace();
} else {
return colorspace_;
}
}
void VideoStream::set_colorspace(const QString &color)
{
colorspace_ = color;
emit ParametersChanged();
}
QString VideoStream::get_colorspace_match_string() const
{
return QStringLiteral("%1:%2").arg(footage()->project()->color_manager()->GetConfigFilename(),
colorspace());
}
void VideoStream::ColorConfigChanged()
{
ColorManager* color_manager = footage()->project()->color_manager();
// Check if this colorspace is in the new config
if (!colorspace_.isEmpty()) {
QStringList colorspaces = color_manager->ListAvailableColorspaces();
if (!colorspaces.contains(colorspace_)) {
// Set to empty if not
colorspace_.clear();
}
}
return -1;
// Either way, the color calculation has likely changed so we signal here
emit ParametersChanged();
}
*/
/*
void VideoStream::clear_frame_index()
void VideoStream::DefaultColorSpaceChanged()
{
{
QMutexLocker locker(&index_access_lock_);
frame_index_.clear();
// If no colorspace is set, this stream uses the default color space and it's just changed
if (colorspace_.isEmpty()) {
emit ParametersChanged();
}
emit IndexChanged();
}
void VideoStream::append_frame_index(const int64_t &ts)
{
{
QMutexLocker locker(&index_access_lock_);
frame_index_.append(ts);
}
emit IndexChanged();
}
bool VideoStream::is_frame_index_ready()
{
QMutexLocker locker(&index_access_lock_);
return !frame_index_.isEmpty() && frame_index_.last() == VideoStream::kEndTimestamp;
}
int64_t VideoStream::last_frame_index_timestamp()
{
QMutexLocker locker(&index_access_lock_);
return frame_index_.last();
}
bool VideoStream::load_frame_index(const QString &s)
{
// Load index from file
QFile index_file(s);
if (index_file.exists() && index_file.open(QFile::ReadOnly)) {
{
QMutexLocker locker(&index_access_lock_);
// Resize based on filesize
frame_index_.resize(static_cast<size_t>(index_file.size()) / sizeof(int64_t));
// Read frame index into vector
index_file.read(reinterpret_cast<char*>(frame_index_.data()),
index_file.size());
}
index_file.close();
emit IndexChanged();
return true;
}
return false;
}
bool VideoStream::save_frame_index(const QString &s)
{
QFile index_file(s);
if (index_file.open(QFile::WriteOnly)) {
// Write index in binary
QMutexLocker locker(&index_access_lock_);
index_file.write(reinterpret_cast<const char*>(frame_index_.constData()),
frame_index_.size() * static_cast<int>(sizeof(int64_t)));
index_file.close();
return true;
}
return false;
}
*/
OLIVE_NAMESPACE_EXIT
+111 -14
View File
@@ -21,18 +21,106 @@
#ifndef VIDEOSTREAM_H
#define VIDEOSTREAM_H
#include "imagestream.h"
#include "render/pixelformat.h"
#include "render/videoparams.h"
#include "stream.h"
OLIVE_NAMESPACE_ENTER
class VideoStream : public ImageStream
/**
* @brief A Stream derivative containing video-specific information
*/
class VideoStream : public Stream
{
Q_OBJECT
public:
VideoStream();
enum VideoType {
kVideoTypeVideo,
kVideoTypeStill,
kVideoTypeImageSequence
};
virtual QString description() const override;
VideoType video_type() const
{
return video_type_;
}
void set_video_type(VideoType t)
{
video_type_ = t;
}
const int& width() const
{
return width_;
}
void set_width(const int& width)
{
width_ = width;
}
const int& height() const
{
return height_;
}
void set_height(const int& height)
{
height_ = height;
}
const PixelFormat::Format& format() const
{
return format_;
}
void set_format(const PixelFormat::Format& format)
{
format_ = format;
}
bool premultiplied_alpha() const;
void set_premultiplied_alpha(bool e);
const QString& colorspace(bool default_if_empty = true) const;
void set_colorspace(const QString& color);
QString get_colorspace_match_string() const;
VideoParams::Interlacing interlacing() const
{
return interlacing_;
}
void set_interlacing(VideoParams::Interlacing i)
{
interlacing_ = i;
emit ParametersChanged();
}
const rational& pixel_aspect_ratio() const
{
return pixel_aspect_ratio_;
}
void set_pixel_aspect_ratio(const rational& r)
{
// Auto-correct null aspect ratio to 1:1
if (r.isNull()) {
pixel_aspect_ratio_ = 1;
} else {
pixel_aspect_ratio_ = r;
}
emit ParametersChanged();
}
/**
* @brief Get this video stream's frame rate
*
@@ -49,23 +137,32 @@ public:
int64_t get_time_in_timebase_units(const rational& time) const;
/*
int64_t get_closest_timestamp_in_frame_index(const rational& time);
int64_t get_closest_timestamp_in_frame_index(int64_t timestamp);
virtual QIcon icon() const override;
void clear_frame_index();
void append_frame_index(const int64_t& ts);
bool is_frame_index_ready();
int64_t last_frame_index_timestamp();
public slots:
void ColorConfigChanged();
bool load_frame_index(const QString& s);
bool save_frame_index(const QString& s);
*/
void DefaultColorSpaceChanged();
protected:
virtual void LoadCustomParameters(QXmlStreamReader *reader) override;
virtual void SaveCustomParameters(QXmlStreamWriter* writer) const override;
private:
rational frame_rate_;
int width_;
int height_;
bool premultiplied_alpha_;
QString colorspace_;
VideoParams::Interlacing interlacing_;
//QVector<int64_t> frame_index_;
VideoType video_type_;
PixelFormat::Format format_;
rational pixel_aspect_ratio_;
rational frame_rate_;
int64_t start_time_;
+14 -18
View File
@@ -278,33 +278,29 @@ void Sequence::set_parameters_from_footage(const QList<Footage *> footage)
VideoStream* vs = static_cast<VideoStream*>(s.get());
// If this is a video stream, use these parameters
if (!found_video_params && !vs->frame_rate().isNull()) {
if (!found_video_params) {
rational using_timebase;
if (vs->video_type() == VideoStream::kVideoTypeStill) {
// If this is a still image, we'll use it's resolution but won't set
// `found_video_params` in case something with a frame rate comes along which we'll
// prioritize
using_timebase = video_params().time_base();
} else {
using_timebase = vs->frame_rate().flipped();
found_video_params = true;
}
set_video_params(VideoParams(vs->width(),
vs->height(),
vs->frame_rate().flipped(),
using_timebase,
static_cast<PixelFormat::Format>(Config::Current()["DefaultSequencePreviewFormat"].toInt()),
vs->pixel_aspect_ratio(),
vs->interlacing(),
VideoParams::generate_auto_divider(vs->width(), vs->height())));
found_video_params = true;
}
break;
}
case Stream::kImage:
if (!found_video_params) {
// If this is an image stream, we'll use it's resolution but won't set `found_video_params` in case
// something with a frame rate comes along which we'll prioritize
ImageStream* is = static_cast<ImageStream*>(s.get());
set_video_params(VideoParams(is->width(),
is->height(),
video_params().time_base(),
static_cast<PixelFormat::Format>(Config::Current()["DefaultSequencePreviewFormat"].toInt()),
is->pixel_aspect_ratio(),
is->interlacing(),
VideoParams::generate_auto_divider(is->width(), is->height())));
}
break;
case Stream::kAudio:
if (!found_audio_params) {
AudioStream* as = static_cast<AudioStream*>(s.get());
+31
View File
@@ -36,6 +36,11 @@ Project::Project() :
autorecovery_saved_(true)
{
root_.set_project(this);
connect(&color_manager_, &ColorManager::ConfigChanged,
this, &Project::ColorConfigChanged);
connect(&color_manager_, &ColorManager::DefaultInputColorSpaceChanged,
this, &Project::DefaultColorSpaceChanged);
}
void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, const QAtomicInt* cancelled)
@@ -210,4 +215,30 @@ const QString &Project::cache_path(bool default_if_empty) const
return cache_path_;
}
void Project::ColorConfigChanged()
{
QList<ItemPtr> footage = this->get_items_of_type(Item::kFootage);
foreach (ItemPtr item, footage) {
foreach (StreamPtr s, std::static_pointer_cast<Footage>(item)->streams()) {
if (s->type() == Stream::kVideo) {
std::static_pointer_cast<VideoStream>(s)->ColorConfigChanged();
}
}
}
}
void Project::DefaultColorSpaceChanged()
{
QList<ItemPtr> footage = this->get_items_of_type(Item::kFootage);
foreach (ItemPtr item, footage) {
foreach (StreamPtr s, std::static_pointer_cast<Footage>(item)->streams()) {
if (s->type() == Stream::kVideo) {
std::static_pointer_cast<VideoStream>(s)->DefaultColorSpaceChanged();
}
}
}
}
OLIVE_NAMESPACE_EXIT
+5
View File
@@ -96,6 +96,11 @@ private:
QString cache_path_;
private slots:
void ColorConfigChanged();
void DefaultColorSpaceChanged();
};
using ProjectPtr = std::shared_ptr<Project>;