various: implement sequence pixel aspect ratios and interlacing settings

Implements the following:
- Sequences have pixel aspect ratios that work in tandem with footage PARs
  to render footage correctly. Viewer and export also acknowledge PARs
- Sequences can have interlacing settings. This doesn't do anything yet,
  eventually the renderer will need to interlace/deinterlace/reinterlace
  appropriately in order to conform all the footage to the sequence. Export
  acknowledges interlacing, but this only affects metadata, not the image.
This commit is contained in:
itsmattkc
2020-08-10 01:47:26 +10:00
parent 901f1001af
commit 28dcff10c0
51 changed files with 1201 additions and 605 deletions
+11 -5
View File
@@ -463,8 +463,9 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled)
if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
bool image_is_still = false;
ImageStream::Interlacing interlacing = ImageStream::kInterlaceNone;
rational pixel_aspect_ratio;
rational frame_rate;
VideoParams::Interlacing interlacing = VideoParams::kInterlaceNone;
{
// Read at least two frames to get more information about this video stream
@@ -479,15 +480,19 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled)
// Check if video is interlaced and what field dominance it has if so
if (frame->interlaced_frame) {
if (frame->top_field_first) {
interlacing = ImageStream::kInterlacedTopFirst;
interlacing = VideoParams::kInterlacedTopFirst;
} else {
interlacing = ImageStream::kInterlacedBottomFirst;
interlacing = VideoParams::kInterlacedBottomFirst;
}
}
pixel_aspect_ratio = av_guess_sample_aspect_ratio(instance.fmt_ctx(),
instance.stream(),
frame);
frame_rate = av_guess_frame_rate(instance.fmt_ctx(),
instance.stream(),
frame);
}
// Read second frame
@@ -521,7 +526,7 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled)
} else {
VideoStreamPtr video_stream = std::make_shared<VideoStream>();
video_stream->set_frame_rate(av_guess_frame_rate(fmt_ctx, avstream, nullptr));
video_stream->set_frame_rate(frame_rate);
video_stream->set_start_time(avstream->start_time);
image_stream = video_stream;
@@ -783,9 +788,10 @@ FramePtr FFmpegDecoder::BuffersToNativeFrame(int divider, int width, int height,
copy->set_video_params(VideoParams(width,
height,
native_pix_fmt_,
std::static_pointer_cast<ImageStream>(stream())->pixel_aspect_ratio(),
std::static_pointer_cast<ImageStream>(stream())->interlacing(),
divider));
copy->set_timestamp(Timecode::timestamp_to_time(ts, time_base_));
copy->set_sample_aspect_ratio(std::static_pointer_cast<ImageStream>(stream())->pixel_aspect_ratio());
copy->allocate();
// Convert frame to RGB/A for the rest of the pipeline
+30 -1
View File
@@ -138,6 +138,17 @@ bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time)
encoded_frame->height = frame->height();
encoded_frame->format = video_codec_ctx_->pix_fmt;
// Set interlacing
if (frame->video_params().interlacing() != VideoParams::kInterlaceNone) {
encoded_frame->interlaced_frame = 1;
if (frame->video_params().interlacing() == VideoParams::kInterlacedTopFirst) {
encoded_frame->top_field_first = 1;
} else {
encoded_frame->top_field_first = 0;
}
}
error_code = av_frame_get_buffer(encoded_frame, 0);
if (error_code < 0) {
FFmpegError("Failed to create AVFrame buffer", error_code);
@@ -443,10 +454,28 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV
if (type == AVMEDIA_TYPE_VIDEO) {
codec_ctx->width = params().video_params().width();
codec_ctx->height = params().video_params().height();
codec_ctx->sample_aspect_ratio = {1, 1};
codec_ctx->sample_aspect_ratio = params().video_params().pixel_aspect_ratio().toAVRational();
codec_ctx->time_base = params().video_params().time_base().toAVRational();
codec_ctx->pix_fmt = av_get_pix_fmt(params().video_pix_fmt().toUtf8());
if (params().video_params().interlacing() != VideoParams::kInterlaceNone) {
// FIXME: I actually don't know what these flags do, the documentation helpfully doesn't
// explain them at all. I hope using both of them is the right thing to do.
codec_ctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME;
if (params().video_params().interlacing() == VideoParams::kInterlacedTopFirst) {
codec_ctx->field_order = AV_FIELD_TT;
} else {
codec_ctx->field_order = AV_FIELD_BB;
if (codec_id == AV_CODEC_ID_H264) {
// For some reason, FFmpeg doesn't set libx264's bff flag so we have to do it ourselves
av_opt_set(video_codec_ctx_->priv_data, "x264opts", "bff=1", AV_OPT_SEARCH_CHILDREN);
}
}
}
// Set custom options
{
QHash<QString, QString>::const_iterator i;
+1 -16
View File
@@ -27,8 +27,7 @@
OLIVE_NAMESPACE_ENTER
Frame::Frame() :
timestamp_(0),
sample_aspect_ratio_(1)
timestamp_(0)
{
}
@@ -106,20 +105,6 @@ void Frame::set_pixel(int x, int y, const Color &c)
c.toData(data_.data() + byte_offset, video_params().format());
}
const rational &Frame::sample_aspect_ratio() const
{
return sample_aspect_ratio_;
}
void Frame::set_sample_aspect_ratio(const rational &aspect_ratio)
{
if (aspect_ratio.isNull()) {
sample_aspect_ratio_ = 1;
} else {
sample_aspect_ratio_ = aspect_ratio;
}
}
const rational &Frame::timestamp() const
{
return timestamp_;
-5
View File
@@ -57,9 +57,6 @@ public:
bool contains_pixel(int x, int y) const;
void set_pixel(int x, int y, const Color& c);
const rational& sample_aspect_ratio() const;
void set_sample_aspect_ratio(const rational& sample_aspect_ratio);
/**
* @brief Get frame's timestamp.
*
@@ -116,8 +113,6 @@ private:
int64_t native_timestamp_;
rational sample_aspect_ratio_;
int linesize_;
};
+10 -5
View File
@@ -118,16 +118,14 @@ bool OIIODecoder::Probe(Footage *f, const QAtomicInt *cancelled)
image_stream->set_width(in->spec().width);
image_stream->set_height(in->spec().height);
image_stream->set_format(GetFormatFromOIIOBasetype(in->spec()));
// FIXME: Haven't looked, does OIIO report pixel aspect ratio somewhere?
image_stream->set_pixel_aspect_ratio(1);
image_stream->set_pixel_aspect_ratio(GetPixelAspectRatioFromOIIO(in->spec()));
// Images will always have just one stream
image_stream->set_index(0);
// OIIO automatically premultiplies alpha
// FIXME: We usually disassociate the alpha for the color management later, for 8-bit images this likely reduces the
// fidelity?
// FIXME: We usually disassociate the alpha for the color management later, for 8-bit images this
// likely reduces the fidelity?
image_stream->set_premultiplied_alpha(true);
// Get stats for this image and dump them into the Footage file
@@ -181,6 +179,8 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider
frame->set_video_params(VideoParams(buffer_->spec().width,
buffer_->spec().height,
pix_fmt_,
GetPixelAspectRatioFromOIIO(buffer_->spec()),
VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us?
divider));
frame->allocate();
@@ -294,6 +294,11 @@ PixelFormat::Format OIIODecoder::GetFormatFromOIIOBasetype(const OIIO::ImageSpec
}
}
rational OIIODecoder::GetPixelAspectRatioFromOIIO(const OpenImageIO_v2_1::ImageSpec &spec)
{
return rational::fromDouble(spec.extra_attribs.get_float("PixelAspectRatio", 1));
}
bool OIIODecoder::FileTypeIsSupported(const QString& fn)
{
// We prioritize OIIO over FFmpeg to pick up still images more effectively, but some OIIO decoders (notably OpenJPEG)
+2
View File
@@ -57,6 +57,8 @@ public:
static PixelFormat::Format GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec);
static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec);
private:
#if OIIO_VERSION < 10903
OIIO::ImageInput* image_;
+2 -1
View File
@@ -70,7 +70,8 @@ double GetFloatRatioFromUser(QWidget* parent,
if (numer_ok
&& denom_ok
&& num > 0) {
&& num > 0
&& den > 0) {
// Exit loop and set this ratio
if (ok_in) {
*ok_in = true;
+3 -1
View File
@@ -107,7 +107,9 @@ void Config::SetDefaults()
SetEntryInternal(QStringLiteral("DefaultSequenceWidth"), NodeParam::kInt, 1920);
SetEntryInternal(QStringLiteral("DefaultSequenceHeight"), NodeParam::kInt, 1080);
SetEntryInternal(QStringLiteral("DefaultSequencePixelAspect"), NodeParam::kRational, QVariant::fromValue(rational(1)));
SetEntryInternal(QStringLiteral("DefaultSequenceFrameRate"), NodeParam::kRational, QVariant::fromValue(rational(1001, 30000)));
SetEntryInternal(QStringLiteral("DefaultSequenceInterlacing"), NodeParam::kInt, VideoParams::kInterlaceNone);
SetEntryInternal(QStringLiteral("DefaultSequenceAudioFrequency"), NodeParam::kInt, 48000);
SetEntryInternal(QStringLiteral("DefaultSequenceAudioLayout"), NodeParam::kInt, QVariant::fromValue(static_cast<int64_t>(AV_CH_LAYOUT_STEREO)));
SetEntryInternal(QStringLiteral("DefaultSequencePreviewFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA16F);
@@ -158,7 +160,7 @@ void Config::Load()
double config_fr = value.toDouble();
QList<rational> supported_frame_rates = Core::SupportedFrameRates();
const QVector<rational>& supported_frame_rates = VideoParams::kSupportedFrameRates;
rational match = supported_frame_rates.first();
double match_diff = qAbs(match.toDouble() - config_fr);
+1 -84
View File
@@ -171,6 +171,7 @@ void Core::DeclareTypesForQt()
qRegisterMetaType<OLIVE_NAMESPACE::ShaderJob>();
qRegisterMetaType<OLIVE_NAMESPACE::GenerateJob>();
qRegisterMetaType<OLIVE_NAMESPACE::VideoParams>();
qRegisterMetaType<OLIVE_NAMESPACE::VideoParams::Interlacing>();
qRegisterMetaType<OLIVE_NAMESPACE::MainWindowLayoutInfo>();
qRegisterMetaType<OLIVE_NAMESPACE::RenderTicketPtr>();
}
@@ -868,90 +869,6 @@ bool Core::CloseAllExceptActiveProject()
return true;
}
QList<rational> Core::SupportedFrameRates()
{
QList<rational> frame_rates;
frame_rates.append(rational(10, 1)); // 10 FPS
frame_rates.append(rational(15, 1)); // 15 FPS
frame_rates.append(rational(24000, 1001)); // 23.976 FPS
frame_rates.append(rational(24, 1)); // 24 FPS
frame_rates.append(rational(25, 1)); // 25 FPS
frame_rates.append(rational(30000, 1001)); // 29.97 FPS
frame_rates.append(rational(30, 1)); // 30 FPS
frame_rates.append(rational(48000, 1001)); // 47.952 FPS
frame_rates.append(rational(48, 1)); // 48 FPS
frame_rates.append(rational(50, 1)); // 50 FPS
frame_rates.append(rational(60000, 1001)); // 59.94 FPS
frame_rates.append(rational(60, 1)); // 60 FPS
return frame_rates;
}
QList<int> Core::SupportedSampleRates()
{
QList<int> sample_rates;
sample_rates.append(8000); // 8000 Hz
sample_rates.append(11025); // 11025 Hz
sample_rates.append(16000); // 16000 Hz
sample_rates.append(22050); // 22050 Hz
sample_rates.append(24000); // 24000 Hz
sample_rates.append(32000); // 32000 Hz
sample_rates.append(44100); // 44100 Hz
sample_rates.append(48000); // 48000 Hz
sample_rates.append(88200); // 88200 Hz
sample_rates.append(96000); // 96000 Hz
return sample_rates;
}
QList<uint64_t> Core::SupportedChannelLayouts()
{
QList<uint64_t> channel_layouts;
channel_layouts.append(AV_CH_LAYOUT_MONO);
channel_layouts.append(AV_CH_LAYOUT_STEREO);
channel_layouts.append(AV_CH_LAYOUT_2_1);
channel_layouts.append(AV_CH_LAYOUT_5POINT1);
channel_layouts.append(AV_CH_LAYOUT_7POINT1);
return channel_layouts;
}
QList<int> Core::SupportedDividers()
{
return {1, 2, 3, 4, 6, 8, 12, 16};
}
QString Core::FrameRateToString(const rational &frame_rate)
{
return tr("%1 FPS").arg(frame_rate.toDouble());
}
QString Core::SampleRateToString(const int &sample_rate)
{
return tr("%1 Hz").arg(sample_rate);
}
QString Core::ChannelLayoutToString(const uint64_t &layout)
{
switch (layout) {
case AV_CH_LAYOUT_MONO:
return tr("Mono");
case AV_CH_LAYOUT_STEREO:
return tr("Stereo");
case AV_CH_LAYOUT_2_1:
return tr("2.1");
case AV_CH_LAYOUT_5POINT1:
return tr("5.1");
case AV_CH_LAYOUT_7POINT1:
return tr("7.1");
default:
return tr("Unknown (0x%1)").arg(layout, 1, 16);
}
}
QString Core::GetProjectFilter()
{
return QStringLiteral("%1 (*.ove)").arg(tr("Olive Project"));
-36
View File
@@ -169,42 +169,6 @@ public:
static QString PasteStringFromClipboard();
/**
* @brief Return a list of supported frame rates in rational form
*
* These rationals can be flipped to create a timebase in this frame rate.
*/
static QList<rational> SupportedFrameRates();
/**
* @brief Return a list of supported sample rates in integer form
*/
static QList<int> SupportedSampleRates();
/**
* @brief Return a list of supported channel layouts as or'd flags
*/
static QList<uint64_t> SupportedChannelLayouts();
/**
* @brief Return a list of supported dividers
*/
static QList<int> SupportedDividers();
/**
* @brief Convert rational frame rate (i.e. flipped timebase) to a user-friendly string
*/
static QString FrameRateToString(const rational& frame_rate);
/**
* @brief Convert integer sample rate to a user-friendly string
*/
static QString SampleRateToString(const int &sample_rate);
/**
* @brief Convert channel layout to a user-friendly string
*/
static QString ChannelLayoutToString(const uint64_t &layout);
/**
* @brief Recursively count files in a file/directory list
*/
+11 -7
View File
@@ -177,9 +177,11 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) :
video_tab_->width_slider()->SetDefaultValue(viewer_node_->video_params().width());
video_tab_->height_slider()->SetValue(viewer_node_->video_params().height());
video_tab_->height_slider()->SetDefaultValue(viewer_node_->video_params().height());
video_tab_->set_frame_rate(viewer_node_->video_params().time_base().flipped());
audio_tab_->set_sample_rate(viewer_node_->audio_params().sample_rate());
audio_tab_->set_channel_layout(viewer_node_->audio_params().channel_layout());
video_tab_->frame_rate_combobox()->SetFrameRate(viewer_node_->video_params().time_base().flipped());
video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(viewer_node_->video_params().pixel_aspect_ratio());
video_tab_->interlaced_combobox()->SetInterlaceMode(viewer_node_->video_params().interlacing());
audio_tab_->sample_rate_combobox()->SetSampleRate(viewer_node_->audio_params().sample_rate());
audio_tab_->channel_layout_combobox()->SetChannelLayout(viewer_node_->audio_params().channel_layout());
video_aspect_ratio_ = static_cast<double>(viewer_node_->video_params().width()) / static_cast<double>(viewer_node_->video_params().height());
@@ -423,12 +425,14 @@ ExportParams ExportDialog::GenerateParams() const
VideoParams video_render_params(static_cast<int>(video_tab_->width_slider()->GetValue()),
static_cast<int>(video_tab_->height_slider()->GetValue()),
video_tab_->frame_rate().flipped(),
video_tab_->frame_rate_combobox()->GetFrameRate().flipped(),
PixelFormat::instance()->GetConfiguredFormatForMode(render_mode),
video_tab_->pixel_aspect_combobox()->GetPixelAspectRatio(),
video_tab_->interlaced_combobox()->GetInterlaceMode(),
render_mode);
AudioParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(),
audio_tab_->channel_layout_combobox()->currentData().toULongLong(),
audio_tab_->channel_layout_combobox()->GetChannelLayout(),
SampleFormat::kInternalFormat);
ExportParams params;
@@ -462,8 +466,8 @@ ExportParams ExportDialog::GenerateParams() const
void ExportDialog::UpdateViewerDimensions()
{
preview_viewer_->SetOverrideSize(static_cast<int>(video_tab_->width_slider()->GetValue()),
static_cast<int>(video_tab_->height_slider()->GetValue()));
preview_viewer_->SetViewerResolution(static_cast<int>(video_tab_->width_slider()->GetValue()),
static_cast<int>(video_tab_->height_slider()->GetValue()));
QMatrix4x4 transform =
ExportParams::GenerateMatrix(static_cast<ExportParams::VideoScalingMethod>(video_tab_->scaling_method_combobox()->currentData().toInt()),
+2 -35
View File
@@ -46,22 +46,14 @@ ExportAudioTab::ExportAudioTab(QWidget* parent) :
layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0);
sample_rate_combobox_ = new QComboBox();
sample_rates_ = Core::SupportedSampleRates();
foreach (const int& sr, sample_rates_) {
sample_rate_combobox_->addItem(Core::SampleRateToString(sr), sr);
}
sample_rate_combobox_ = new SampleRateComboBox();
layout->addWidget(sample_rate_combobox_, row, 1);
row++;
layout->addWidget(new QLabel(tr("Channel Layout:")), row, 0);
channel_layout_combobox_ = new QComboBox();
channel_layouts_ = Core::SupportedChannelLayouts();
foreach (const uint64_t& ch_layout, channel_layouts_) {
channel_layout_combobox_->addItem(Core::ChannelLayoutToString(ch_layout), QVariant::fromValue(ch_layout));
}
channel_layout_combobox_ = new ChannelLayoutComboBox();
layout->addWidget(channel_layout_combobox_, row, 1);
row++;
@@ -72,29 +64,4 @@ ExportAudioTab::ExportAudioTab(QWidget* parent) :
outer_layout->addStretch();
}
QComboBox *ExportAudioTab::codec_combobox() const
{
return codec_combobox_;
}
QComboBox *ExportAudioTab::sample_rate_combobox() const
{
return sample_rate_combobox_;
}
QComboBox *ExportAudioTab::channel_layout_combobox() const
{
return channel_layout_combobox_;
}
void ExportAudioTab::set_sample_rate(int rate)
{
sample_rate_combobox_->setCurrentIndex(sample_rates_.indexOf(rate));
}
void ExportAudioTab::set_channel_layout(uint64_t layout)
{
channel_layout_combobox_->setCurrentIndex(channel_layouts_.indexOf(layout));
}
OLIVE_NAMESPACE_EXIT
+16 -9
View File
@@ -25,6 +25,7 @@
#include <QWidget>
#include "common/define.h"
#include "widget/standardcombos/standardcombos.h"
OLIVE_NAMESPACE_ENTER
@@ -33,20 +34,26 @@ class ExportAudioTab : public QWidget
public:
ExportAudioTab(QWidget* parent = nullptr);
QComboBox* codec_combobox() const;
QComboBox* sample_rate_combobox() const;
QComboBox* channel_layout_combobox() const;
QComboBox* codec_combobox() const
{
return codec_combobox_;
}
void set_sample_rate(int rate);
void set_channel_layout(uint64_t layout);
SampleRateComboBox* sample_rate_combobox() const
{
return sample_rate_combobox_;
}
ChannelLayoutComboBox* channel_layout_combobox() const
{
return channel_layout_combobox_;
}
private:
QComboBox* codec_combobox_;
QComboBox* sample_rate_combobox_;
QComboBox* channel_layout_combobox_;
SampleRateComboBox* sample_rate_combobox_;
ChannelLayoutComboBox* channel_layout_combobox_;
QList<int> sample_rates_;
QList<uint64_t> channel_layouts_;
};
OLIVE_NAMESPACE_EXIT
+15 -71
View File
@@ -49,71 +49,6 @@ ExportVideoTab::ExportVideoTab(ColorManager* color_manager, QWidget *parent) :
outer_layout->addStretch();
}
ExportCodec::Codec ExportVideoTab::GetSelectedCodec() const
{
return static_cast<ExportCodec::Codec>(codec_combobox()->currentData().toInt());
}
QComboBox *ExportVideoTab::codec_combobox() const
{
return codec_combobox_;
}
IntegerSlider *ExportVideoTab::width_slider() const
{
return width_slider_;
}
IntegerSlider *ExportVideoTab::height_slider() const
{
return height_slider_;
}
QCheckBox *ExportVideoTab::maintain_aspect_checkbox() const
{
return maintain_aspect_checkbox_;
}
QComboBox *ExportVideoTab::scaling_method_combobox() const
{
return scaling_method_combobox_;
}
const rational &ExportVideoTab::frame_rate() const
{
return frame_rates_.at(frame_rate_combobox_->currentIndex());
}
void ExportVideoTab::set_frame_rate(const rational &frame_rate)
{
frame_rate_combobox_->setCurrentIndex(frame_rates_.indexOf(frame_rate));
}
QString ExportVideoTab::CurrentOCIOColorSpace()
{
return color_space_chooser_->input();
}
CodecSection *ExportVideoTab::GetCodecSection() const
{
return static_cast<CodecSection*>(codec_stack_->currentWidget());
}
void ExportVideoTab::SetCodecSection(CodecSection *section)
{
codec_stack_->setCurrentWidget(section);
}
ImageSection *ExportVideoTab::image_section() const
{
return image_section_;
}
H264Section *ExportVideoTab::h264_section() const
{
return h264_section_;
}
QWidget* ExportVideoTab::SetupResolutionSection()
{
int row = 0;
@@ -163,14 +98,23 @@ QWidget* ExportVideoTab::SetupResolutionSection()
layout->addWidget(new QLabel(tr("Frame Rate:")), row, 0);
frame_rate_combobox_ = new QComboBox();
frame_rates_ = Core::SupportedFrameRates();
foreach (const rational& fr, frame_rates_) {
frame_rate_combobox_->addItem(Core::FrameRateToString(fr));
}
frame_rate_combobox_ = new FrameRateComboBox();
layout->addWidget(frame_rate_combobox_, row, 1);
row++;
layout->addWidget(new QLabel(tr("Pixel Aspect Ratio:")), row, 0);
pixel_aspect_combobox_ = new PixelAspectRatioComboBox();
layout->addWidget(pixel_aspect_combobox_, row, 1);
row++;
layout->addWidget(new QLabel(tr("Interlacing:")), row, 0);
interlaced_combobox_ = new InterlacedComboBox();
layout->addWidget(interlaced_combobox_, row, 1);
return resolution_group;
}
+69 -16
View File
@@ -31,6 +31,7 @@
#include "render/colormanager.h"
#include "widget/colorwheel/colorspacechooser.h"
#include "widget/slider/integerslider.h"
#include "widget/standardcombos/standardcombos.h"
OLIVE_NAMESPACE_ENTER
@@ -40,24 +41,75 @@ class ExportVideoTab : public QWidget
public:
ExportVideoTab(ColorManager* color_manager, QWidget* parent = nullptr);
ExportCodec::Codec GetSelectedCodec() const;
ExportCodec::Codec GetSelectedCodec() const
{
return static_cast<ExportCodec::Codec>(codec_combobox()->currentData().toInt());
}
QComboBox* codec_combobox() const;
QComboBox* codec_combobox() const
{
return codec_combobox_;
}
IntegerSlider* width_slider() const;
IntegerSlider* height_slider() const;
QCheckBox* maintain_aspect_checkbox() const;
QComboBox* scaling_method_combobox() const;
IntegerSlider* width_slider() const
{
return width_slider_;
}
const rational& frame_rate() const;
void set_frame_rate(const rational& frame_rate);
IntegerSlider* height_slider() const
{
return height_slider_;
}
QString CurrentOCIOColorSpace();
QCheckBox* maintain_aspect_checkbox() const
{
return maintain_aspect_checkbox_;
}
CodecSection* GetCodecSection() const;
void SetCodecSection(CodecSection* section);
ImageSection* image_section() const;
H264Section* h264_section() const;
QComboBox* scaling_method_combobox() const
{
return scaling_method_combobox_;
}
FrameRateComboBox* frame_rate_combobox() const
{
return frame_rate_combobox_;
}
QString CurrentOCIOColorSpace()
{
return color_space_chooser_->input();
}
CodecSection* GetCodecSection() const
{
return static_cast<CodecSection*>(codec_stack_->currentWidget());
}
void SetCodecSection(CodecSection* section)
{
codec_stack_->setCurrentWidget(section);
}
ImageSection* image_section() const
{
return image_section_;
}
H264Section* h264_section() const
{
return h264_section_;
}
InterlacedComboBox* interlaced_combobox() const
{
return interlaced_combobox_;
}
PixelAspectRatioComboBox* pixel_aspect_combobox() const
{
return pixel_aspect_combobox_;
}
const int& threads() const
{
@@ -80,7 +132,7 @@ private:
QWidget* SetupCodecSection();
QComboBox* codec_combobox_;
QComboBox* frame_rate_combobox_;
FrameRateComboBox* frame_rate_combobox_;
QCheckBox* maintain_aspect_checkbox_;
QComboBox* scaling_method_combobox_;
@@ -93,10 +145,11 @@ private:
IntegerSlider* width_slider_;
IntegerSlider* height_slider_;
QList<rational> frame_rates_;
ColorManager* color_manager_;
InterlacedComboBox* interlaced_combobox_;
PixelAspectRatioComboBox* pixel_aspect_combobox_;
int threads_;
QString pix_fmt_;
@@ -28,7 +28,7 @@
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#include "common/ratiodialog.h"
#include "core.h"
#include "project/item/footage/footage.h"
#include "project/project.h"
#include "undo/undostack.h"
@@ -45,45 +45,16 @@ VideoStreamProperties::VideoStreamProperties(ImageStreamPtr stream) :
video_layout->addWidget(new QLabel(tr("Pixel Aspect:")), row, 0);
pixel_aspect_combo_ = new QComboBox();
pixel_aspect_combo_ = new PixelAspectRatioComboBox();
pixel_aspect_combo_->SetPixelAspectRatio(stream->pixel_aspect_ratio());
video_layout->addWidget(pixel_aspect_combo_, row, 1);
AddPixelAspectRatio(tr("Square Pixels"), rational(1));
AddPixelAspectRatio(tr("NTSC Standard"), rational(8, 9));
AddPixelAspectRatio(tr("NTSC Widescreen"), rational(32, 27));
AddPixelAspectRatio(tr("PAL Standard"), rational(16, 15));
AddPixelAspectRatio(tr("PAL Widescreen"), rational(64, 45));
AddPixelAspectRatio(tr("HD Anamorphic 1080"), rational(4, 3));
// Always add custom item last, much of the logic relies on this. Set this to the current AR so
// that if none of the above are ==, it will eventually select this item
AddPixelAspectRatio(QString(), rational());
UpdateCustomItem(stream->pixel_aspect_ratio());
// Determine which index to select on startup
for (int i=0; i<pixel_aspect_combo_->count(); i++) {
if (pixel_aspect_combo_->itemData(i).value<rational>() == stream->pixel_aspect_ratio()) {
pixel_aspect_combo_->setCurrentIndex(i);
break;
}
}
// Pick up index signal to query for custom aspect ratio if requested
connect(pixel_aspect_combo_, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &VideoStreamProperties::PixelAspectComboBoxChanged);
row++;
video_layout->addWidget(new QLabel(tr("Interlacing:")), row, 0);
video_interlace_combo_ = new QComboBox();
// These must match the Interlacing enum in ImageStream
video_interlace_combo_->addItem(tr("None (Progressive)"));
video_interlace_combo_->addItem(tr("Top-Field First"));
video_interlace_combo_->addItem(tr("Bottom-Field First"));
video_interlace_combo_->setCurrentIndex(stream->interlacing());
video_interlace_combo_ = new InterlacedComboBox();
video_interlace_combo_->SetInterlaceMode(stream->interlacing());
video_layout->addWidget(video_interlace_combo_, row, 1);
@@ -153,14 +124,14 @@ void VideoStreamProperties::Accept(QUndoCommand *parent)
if (video_premultiply_alpha_->isChecked() != stream_->premultiplied_alpha()
|| set_colorspace != stream_->colorspace(false)
|| static_cast<ImageStream::Interlacing>(video_interlace_combo_->currentIndex()) != stream_->interlacing()
|| pixel_aspect_combo_->currentData().value<rational>() != stream_->pixel_aspect_ratio()) {
|| static_cast<VideoParams::Interlacing>(video_interlace_combo_->currentIndex()) != stream_->interlacing()
|| pixel_aspect_combo_->GetPixelAspectRatio() != stream_->pixel_aspect_ratio()) {
new VideoStreamChangeCommand(stream_,
video_premultiply_alpha_->isChecked(),
set_colorspace,
static_cast<ImageStream::Interlacing>(video_interlace_combo_->currentIndex()),
pixel_aspect_combo_->currentData().value<rational>(),
static_cast<VideoParams::Interlacing>(video_interlace_combo_->currentIndex()),
pixel_aspect_combo_->GetPixelAspectRatio(),
parent);
}
@@ -199,46 +170,10 @@ bool VideoStreamProperties::IsImageSequence(ImageStream *stream)
return (stream->type() == Stream::kVideo && static_cast<VideoStream*>(stream)->is_image_sequence());
}
void VideoStreamProperties::AddPixelAspectRatio(const QString &name, const rational &ratio)
{
pixel_aspect_combo_->addItem(GetPixelAspectRatioItemText(name, ratio),
QVariant::fromValue(ratio));
}
QString VideoStreamProperties::GetPixelAspectRatioItemText(const QString &name, const rational &ratio)
{
return tr("%1 (%2)").arg(name, QString::number(ratio.toDouble(), 'f', 4));
}
void VideoStreamProperties::UpdateCustomItem(const rational &ratio)
{
const int custom_index = pixel_aspect_combo_->count() - 1;
pixel_aspect_combo_->setItemText(custom_index,
GetPixelAspectRatioItemText(tr("Custom"), ratio));
pixel_aspect_combo_->setItemData(custom_index,
QVariant::fromValue(ratio));
}
void VideoStreamProperties::PixelAspectComboBoxChanged(int index)
{
// Detect if custom was selected, in which case query what the new AR should be
if (index == pixel_aspect_combo_->count() - 1) {
// Query for custom pixel aspect ratio
bool ok;
double custom_ratio = GetFloatRatioFromUser(this, tr("Set Custom Pixel Aspect Ratio"), &ok);
if (ok) {
UpdateCustomItem(rational::fromDouble(custom_ratio));
}
}
}
VideoStreamProperties::VideoStreamChangeCommand::VideoStreamChangeCommand(ImageStreamPtr stream,
bool premultiplied,
QString colorspace,
ImageStream::Interlacing interlacing,
VideoParams::Interlacing interlacing,
const rational &pixel_ar,
QUndoCommand *parent) :
UndoCommand(parent),
@@ -28,6 +28,7 @@
#include "streamproperties.h"
#include "undo/undocommand.h"
#include "widget/slider/integerslider.h"
#include "widget/standardcombos/standardcombos.h"
OLIVE_NAMESPACE_ENTER
@@ -43,12 +44,6 @@ public:
private:
static bool IsImageSequence(ImageStream* stream);
void AddPixelAspectRatio(const QString& name, const rational& ratio);
static QString GetPixelAspectRatioItemText(const QString& name, const rational& ratio);
void UpdateCustomItem(const rational& ratio);
/**
* @brief Attached video stream
*/
@@ -67,7 +62,7 @@ private:
/**
* @brief Setting for video interlacing
*/
QComboBox* video_interlace_combo_;
InterlacedComboBox* video_interlace_combo_;
/**
* @brief Sets the start index for image sequences
@@ -82,14 +77,14 @@ private:
/**
* @brief Sets the pixel aspect ratio of the stream
*/
QComboBox* pixel_aspect_combo_;
PixelAspectRatioComboBox* pixel_aspect_combo_;
class VideoStreamChangeCommand : public UndoCommand {
public:
VideoStreamChangeCommand(ImageStreamPtr stream,
bool premultiplied,
QString colorspace,
ImageStream::Interlacing interlacing,
VideoParams::Interlacing interlacing,
const rational& pixel_ar,
QUndoCommand* parent = nullptr);
@@ -104,12 +99,12 @@ private:
bool new_premultiplied_;
QString new_colorspace_;
ImageStream::Interlacing new_interlacing_;
VideoParams::Interlacing new_interlacing_;
rational new_pixel_ar_;
bool old_premultiplied_;
QString old_colorspace_;
ImageStream::Interlacing old_interlacing_;
VideoParams::Interlacing old_interlacing_;
rational old_pixel_ar_;
};
@@ -138,9 +133,6 @@ private:
};
private slots:
void PixelAspectComboBoxChanged(int index);
};
OLIVE_NAMESPACE_EXIT
+5 -12
View File
@@ -102,24 +102,17 @@ void SequenceDialog::accept()
return;
}
// Get the rational at the combobox's index (which will be correct provided AddFrameRate() was used at all time)
rational video_time_base = parameter_tab_->GetSelectedVideoFrameRate().flipped();
// Get the rational at the combobox's index (which will be correct provided AddFrameRate() was used at all time)
int audio_sample_rate = parameter_tab_->GetSelectedAudioSampleRate();
// Get the audio channel layout value
uint64_t channels = parameter_tab_->GetSelectedAudioChannelLayout();
// Generate video and audio parameter structs from data
VideoParams video_params = VideoParams(parameter_tab_->GetSelectedVideoWidth(),
parameter_tab_->GetSelectedVideoHeight(),
video_time_base,
parameter_tab_->GetSelectedVideoFrameRate().flipped(),
parameter_tab_->GetSelectedPreviewFormat(),
parameter_tab_->GetSelectedVideoPixelAspect(),
parameter_tab_->GetSelectedVideoInterlacingMode(),
parameter_tab_->GetSelectedPreviewResolution());
AudioParams audio_params = AudioParams(audio_sample_rate,
channels,
AudioParams audio_params = AudioParams(parameter_tab_->GetSelectedAudioSampleRate(),
parameter_tab_->GetSelectedAudioChannelLayout(),
SampleFormat::kInternalFormat);
if (make_undoable_) {
@@ -35,8 +35,16 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg
video_layout->addWidget(video_height_field_, row, 1);
row++;
video_layout->addWidget(new QLabel(tr("Frame Rate:")), row, 0);
video_frame_rate_field_ = new QComboBox();
video_frame_rate_field_ = new FrameRateComboBox();
video_layout->addWidget(video_frame_rate_field_, row, 1);
row++;
video_layout->addWidget(new QLabel(tr("Pixel Aspect Ratio:")), row, 0);
video_pixel_aspect_field_ = new PixelAspectRatioComboBox();
video_layout->addWidget(video_pixel_aspect_field_, row, 1);
row++;
video_layout->addWidget(new QLabel(tr("Interlacing:")));
video_interlaced_field_ = new InterlacedComboBox();
video_layout->addWidget(video_interlaced_field_, row, 1);
layout->addWidget(video_group);
row = 0;
@@ -46,11 +54,11 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg
audio_group->setTitle(tr("Audio"));
QGridLayout* audio_layout = new QGridLayout(audio_group);
audio_layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0);
audio_sample_rate_field_ = new QComboBox();
audio_sample_rate_field_ = new SampleRateComboBox();
audio_layout->addWidget(audio_sample_rate_field_, row, 1);
row++;
audio_layout->addWidget(new QLabel(tr("Channels:")), row, 0);
audio_channels_field_ = new QComboBox();
audio_channels_field_ = new ChannelLayoutComboBox();
audio_layout->addWidget(audio_channels_field_, row, 1);
layout->addWidget(audio_group);
@@ -61,83 +69,29 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg
preview_group->setTitle(tr("Preview"));
QGridLayout* preview_layout = new QGridLayout(preview_group);
preview_layout->addWidget(new QLabel(tr("Resolution:")), row, 0);
preview_resolution_field_ = new QComboBox();
preview_resolution_field_ = new VideoDividerComboBox();
preview_layout->addWidget(preview_resolution_field_, row, 1);
preview_resolution_label_ = new QLabel();
preview_layout->addWidget(preview_resolution_label_, row, 2);
row++;
preview_layout->addWidget(new QLabel(tr("Format:")), row, 0);
preview_format_field_ = new QComboBox();
preview_format_field_ = new PixelFormatComboBox(true, true);
preview_layout->addWidget(preview_format_field_, row, 1, 1, 2);
layout->addWidget(preview_group);
// Set up available frame rates
frame_rate_list_ = Core::SupportedFrameRates();
foreach (const rational& fr, frame_rate_list_) {
video_frame_rate_field_->addItem(Core::FrameRateToString(fr));
}
// Set up available sample rates
sample_rate_list_ = Core::SupportedSampleRates();
foreach (const int& sr, sample_rate_list_) {
audio_sample_rate_field_->addItem(Core::SampleRateToString(sr));
}
// Set up available channel layouts
channel_layout_list_ = Core::SupportedChannelLayouts();
foreach (const uint64_t& ch_layout, channel_layout_list_) {
audio_channels_field_->addItem(Core::ChannelLayoutToString(ch_layout), QVariant::fromValue(ch_layout));
}
// Set up preview dividers
divider_list_ = Core::SupportedDividers();
foreach (int d, divider_list_) {
QString name;
if (d == 1) {
name = tr("Full");
} else {
name = tr("1/%1").arg(d);
}
preview_resolution_field_->addItem(name);
}
connect(preview_resolution_field_, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &SequenceDialogParameterTab::UpdatePreviewResolutionLabel);
// Set up preview formats
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)) {
preview_format_field_->addItem(PixelFormat::GetName(pix_fmt));
preview_format_list_.append(pix_fmt);
}
}
// Set values based on input sequence
video_width_field_->SetValue(sequence->video_params().width());
video_height_field_->SetValue(sequence->video_params().height());
video_frame_rate_field_->SetFrameRate(sequence->video_params().time_base().flipped());
video_pixel_aspect_field_->SetPixelAspectRatio(sequence->video_params().pixel_aspect_ratio());
video_interlaced_field_->SetInterlaceMode(sequence->video_params().interlacing());
preview_resolution_field_->SetDivider(sequence->video_params().divider());
preview_format_field_->SetPixelFormat(sequence->video_params().format());
audio_sample_rate_field_->SetSampleRate(sequence->audio_params().sample_rate());
audio_channels_field_->SetChannelLayout(sequence->audio_params().channel_layout());
int frame_rate_index = frame_rate_list_.indexOf(sequence->video_params().time_base().flipped());
video_frame_rate_field_->setCurrentIndex(frame_rate_index);
int sample_rate_index = sample_rate_list_.indexOf(sequence->audio_params().sample_rate());
audio_sample_rate_field_->setCurrentIndex(sample_rate_index);
for (int i=0;i<audio_channels_field_->count();i++) {
if (audio_channels_field_->itemData(i).toULongLong() == sequence->audio_params().channel_layout()) {
audio_channels_field_->setCurrentIndex(i);
break;
}
}
preview_resolution_field_->setCurrentIndex(divider_list_.indexOf(sequence->video_params().divider()));
preview_format_field_->setCurrentIndex(preview_format_list_.indexOf(sequence->video_params().format()));
connect(preview_resolution_field_, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &SequenceDialogParameterTab::UpdatePreviewResolutionLabel);
layout->addStretch();
@@ -148,62 +102,31 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg
UpdatePreviewResolutionLabel();
}
int SequenceDialogParameterTab::GetSelectedVideoWidth() const
{
return video_width_field_->GetValue();
}
int SequenceDialogParameterTab::GetSelectedVideoHeight() const
{
return video_height_field_->GetValue();
}
const rational &SequenceDialogParameterTab::GetSelectedVideoFrameRate() const
{
return frame_rate_list_.at(video_frame_rate_field_->currentIndex());
}
int SequenceDialogParameterTab::GetSelectedAudioSampleRate() const
{
return sample_rate_list_.at(audio_sample_rate_field_->currentIndex());
}
uint64_t SequenceDialogParameterTab::GetSelectedAudioChannelLayout() const
{
return audio_channels_field_->currentData().toULongLong();
}
int SequenceDialogParameterTab::GetSelectedPreviewResolution() const
{
return divider_list_.at(preview_resolution_field_->currentIndex());
}
PixelFormat::Format SequenceDialogParameterTab::GetSelectedPreviewFormat() const
{
return preview_format_list_.at(preview_format_field_->currentIndex());
}
void SequenceDialogParameterTab::PresetChanged(const SequencePreset &preset)
{
video_width_field_->SetValue(preset.width());
video_height_field_->SetValue(preset.height());
video_frame_rate_field_->setCurrentIndex(frame_rate_list_.indexOf(preset.frame_rate()));
audio_sample_rate_field_->setCurrentIndex(sample_rate_list_.indexOf(preset.sample_rate()));
audio_channels_field_->setCurrentIndex(channel_layout_list_.indexOf(preset.channel_layout()));
preview_resolution_field_->setCurrentIndex(divider_list_.indexOf(preset.preview_divider()));
preview_format_field_->setCurrentIndex(preview_format_list_.indexOf(preset.preview_format()));
video_frame_rate_field_->SetFrameRate(preset.frame_rate());
video_pixel_aspect_field_->SetPixelAspectRatio(preset.pixel_aspect());
video_interlaced_field_->SetInterlaceMode(preset.interlacing());
audio_sample_rate_field_->SetSampleRate(preset.sample_rate());
audio_channels_field_->SetChannelLayout(preset.channel_layout());
preview_resolution_field_->SetDivider(preset.preview_divider());
preview_format_field_->SetPixelFormat(preset.preview_format());
}
void SequenceDialogParameterTab::SavePresetClicked()
{
emit SaveParametersAsPreset({QString(),
static_cast<int>(video_width_field_->GetValue()),
static_cast<int>(video_height_field_->GetValue()),
frame_rate_list_.at(video_frame_rate_field_->currentIndex()),
sample_rate_list_.at(audio_sample_rate_field_->currentIndex()),
channel_layout_list_.at(audio_channels_field_->currentIndex()),
divider_list_.at(preview_resolution_field_->currentIndex()),
preview_format_list_.at(preview_format_field_->currentIndex())});
GetSelectedVideoWidth(),
GetSelectedVideoHeight(),
GetSelectedVideoFrameRate(),
GetSelectedVideoPixelAspect(),
GetSelectedVideoInterlacingMode(),
GetSelectedAudioSampleRate(),
GetSelectedAudioChannelLayout(),
GetSelectedPreviewResolution(),
GetSelectedPreviewFormat()});
}
void SequenceDialogParameterTab::UpdatePreviewResolutionLabel()
@@ -211,7 +134,9 @@ void SequenceDialogParameterTab::UpdatePreviewResolutionLabel()
VideoParams test_param(video_width_field_->GetValue(),
video_height_field_->GetValue(),
PixelFormat::PIX_FMT_INVALID,
divider_list_.at(preview_resolution_field_->currentIndex()));
rational(1),
VideoParams::kInterlaceNone,
preview_resolution_field_->currentData().toInt());
preview_resolution_label_->setText(tr("(%1x%2)").arg(QString::number(test_param.effective_width()),
QString::number(test_param.effective_height())));
@@ -8,6 +8,7 @@
#include "project/item/sequence/sequence.h"
#include "sequencepreset.h"
#include "widget/slider/integerslider.h"
#include "widget/standardcombos/standardcombos.h"
OLIVE_NAMESPACE_ENTER
@@ -17,19 +18,50 @@ class SequenceDialogParameterTab : public QWidget
public:
SequenceDialogParameterTab(Sequence* sequence, QWidget* parent = nullptr);
int GetSelectedVideoWidth() const;
int GetSelectedVideoWidth() const
{
return video_width_field_->GetValue();
}
int GetSelectedVideoHeight() const;
int GetSelectedVideoHeight() const
{
return video_height_field_->GetValue();
}
const rational& GetSelectedVideoFrameRate() const;
rational GetSelectedVideoFrameRate() const
{
return video_frame_rate_field_->GetFrameRate();
}
int GetSelectedAudioSampleRate() const;
rational GetSelectedVideoPixelAspect() const
{
return video_pixel_aspect_field_->GetPixelAspectRatio();
}
uint64_t GetSelectedAudioChannelLayout() const;
VideoParams::Interlacing GetSelectedVideoInterlacingMode() const
{
return video_interlaced_field_->GetInterlaceMode();
}
int GetSelectedPreviewResolution() const;
int GetSelectedAudioSampleRate() const
{
return audio_sample_rate_field_->GetSampleRate();
}
PixelFormat::Format GetSelectedPreviewFormat() const;
uint64_t GetSelectedAudioChannelLayout() const
{
return audio_channels_field_->GetChannelLayout();
}
int GetSelectedPreviewResolution() const
{
return preview_resolution_field_->GetDivider();
}
PixelFormat::Format GetSelectedPreviewFormat() const
{
return preview_format_field_->GetPixelFormat();
}
public slots:
void PresetChanged(const SequencePreset& preset);
@@ -42,27 +74,21 @@ private:
IntegerSlider* video_height_field_;
QComboBox* video_frame_rate_field_;
FrameRateComboBox* video_frame_rate_field_;
QComboBox* audio_sample_rate_field_;
PixelAspectRatioComboBox* video_pixel_aspect_field_;
QComboBox* audio_channels_field_;
InterlacedComboBox* video_interlaced_field_;
QComboBox* preview_resolution_field_;
SampleRateComboBox* audio_sample_rate_field_;
ChannelLayoutComboBox* audio_channels_field_;
VideoDividerComboBox* preview_resolution_field_;
QLabel* preview_resolution_label_;
QComboBox* preview_format_field_;
QList<rational> frame_rate_list_;
QList<int> sample_rate_list_;
QList<uint64_t> channel_layout_list_;
QList<int> divider_list_;
QList<PixelFormat::Format> preview_format_list_;
PixelFormatComboBox* preview_format_field_;
private slots:
void SavePresetClicked();
+31 -10
View File
@@ -31,6 +31,7 @@
#include "common/filefunctions.h"
#include "node/input.h"
#include "render/videoparams.h"
#include "ui/icons/icons.h"
#include "widget/menu/menu.h"
@@ -40,6 +41,8 @@ const int kDataIsPreset = Qt::UserRole;
const int kDataPresetIsCustomRole = Qt::UserRole + 1;
const int kDataPresetDataRole = Qt::UserRole + 2;
const PixelFormat::Format kDefaultPreviewFormat = PixelFormat::PIX_FMT_RGBA16F;
SequenceDialogPresetTab::SequenceDialogPresetTab(QWidget* parent) :
QWidget(parent),
PresetManager<SequencePreset>(this, QStringLiteral("sequencepresets"))
@@ -65,8 +68,12 @@ SequenceDialogPresetTab::SequenceDialogPresetTab(QWidget* parent) :
preset_tree_->addTopLevelItem(CreateHDPresetFolder(tr("1080p"), 1920, 1080, 3));
preset_tree_->addTopLevelItem(CreateHDPresetFolder(tr("720p"), 1280, 720, 2));
preset_tree_->addTopLevelItem(CreateSDPresetFolder(tr("NTSC"), 720, 480, rational(30000, 1001), 1));
preset_tree_->addTopLevelItem(CreateSDPresetFolder(tr("PAL"), 720, 576, rational(25, 1), 1));
preset_tree_->addTopLevelItem(CreateSDPresetFolder(tr("NTSC"), 720, 480, rational(30000, 1001),
VideoParams::kPixelAspectNTSCStandard,
VideoParams::kPixelAspectNTSCWidescreen, 1));
preset_tree_->addTopLevelItem(CreateSDPresetFolder(tr("PAL"), 720, 576, rational(25, 1),
VideoParams::kPixelAspectPALStandard,
VideoParams::kPixelAspectPALWidescreen, 1));
// Load custom presets
for (int i=0;i<GetNumberOfPresets();i++) {
@@ -98,46 +105,56 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na
width,
height,
rational(24000, 1001),
VideoParams::kPixelAspectSquare,
VideoParams::kInterlaceNone,
48000,
AV_CH_LAYOUT_STEREO,
divider,
PixelFormat::PIX_FMT_RGBA16F));
kDefaultPreviewFormat));
AddStandardItem(parent, SequencePreset::Create(tr("%1 25 FPS").arg(name),
width,
height,
rational(25, 1),
VideoParams::kPixelAspectSquare,
VideoParams::kInterlaceNone,
48000,
AV_CH_LAYOUT_STEREO,
divider,
PixelFormat::PIX_FMT_RGBA16F));
kDefaultPreviewFormat));
AddStandardItem(parent, SequencePreset::Create(tr("%1 29.97 FPS").arg(name),
width,
height,
rational(30000, 1001),
VideoParams::kPixelAspectSquare,
VideoParams::kInterlaceNone,
48000,
AV_CH_LAYOUT_STEREO,
divider,
PixelFormat::PIX_FMT_RGBA16F));
kDefaultPreviewFormat));
AddStandardItem(parent, SequencePreset::Create(tr("%1 50 FPS").arg(name),
width,
height,
rational(50, 1),
VideoParams::kPixelAspectSquare,
VideoParams::kInterlaceNone,
48000,
AV_CH_LAYOUT_STEREO,
divider,
PixelFormat::PIX_FMT_RGBA16F));
kDefaultPreviewFormat));
AddStandardItem(parent, SequencePreset::Create(tr("%1 59.94 FPS").arg(name),
width,
height,
rational(60000, 1001),
VideoParams::kPixelAspectSquare,
VideoParams::kInterlaceNone,
48000,
AV_CH_LAYOUT_STEREO,
divider,
PixelFormat::PIX_FMT_RGBA16F));
kDefaultPreviewFormat));
return parent;
}
QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &name, int width, int height, const rational& frame_rate, int divider)
QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &name, int width, int height, const rational& frame_rate, const rational &standard_par, const rational &wide_par, int divider)
{
QTreeWidgetItem* parent = CreateFolder(name);
preset_tree_->addTopLevelItem(parent);
@@ -145,18 +162,22 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &na
width,
height,
frame_rate,
standard_par,
VideoParams::kInterlacedTopFirst,
48000,
AV_CH_LAYOUT_STEREO,
divider,
PixelFormat::PIX_FMT_RGBA16F));
kDefaultPreviewFormat));
AddStandardItem(parent, SequencePreset::Create(tr("%1 Widescreen").arg(name),
width,
height,
frame_rate,
wide_par,
VideoParams::kInterlacedTopFirst,
48000,
AV_CH_LAYOUT_STEREO,
divider,
PixelFormat::PIX_FMT_RGBA16F));
kDefaultPreviewFormat));
return parent;
}
@@ -49,7 +49,7 @@ private:
QTreeWidgetItem *CreateHDPresetFolder(const QString& name, int width, int height, int divider);
QTreeWidgetItem *CreateSDPresetFolder(const QString& name, int width, int height, const rational &frame_rate, int divider);
QTreeWidgetItem *CreateSDPresetFolder(const QString& name, int width, int height, const rational &frame_rate, const rational& standard_par, const rational& wide_par, int divider);
QTreeWidgetItem* GetSelectedItem();
QTreeWidgetItem* GetSelectedCustomPreset();
+28 -2
View File
@@ -27,6 +27,7 @@
#include "common/xmlutils.h"
#include "dialog/sequence/presetmanager.h"
#include "render/pixelformat.h"
#include "render/videoparams.h"
OLIVE_NAMESPACE_ENTER
@@ -38,6 +39,8 @@ public:
int width,
int height,
const rational& frame_rate,
const rational& pixel_aspect,
VideoParams::Interlacing interlacing,
int sample_rate,
uint64_t channel_layout,
int preview_divider,
@@ -45,6 +48,8 @@ public:
width_(width),
height_(height),
frame_rate_(frame_rate),
pixel_aspect_(pixel_aspect),
interlacing_(interlacing),
sample_rate_(sample_rate),
channel_layout_(channel_layout),
preview_divider_(preview_divider),
@@ -57,13 +62,16 @@ public:
int width,
int height,
const rational& frame_rate,
const rational& pixel_aspect,
VideoParams::Interlacing interlacing,
int sample_rate,
uint64_t channel_layout,
int preview_divider,
PixelFormat::Format preview_format)
{
return std::make_shared<SequencePreset>(name, width, height, frame_rate, sample_rate,
channel_layout, preview_divider, preview_format);
return std::make_shared<SequencePreset>(name, width, height, frame_rate, pixel_aspect,
interlacing, sample_rate, channel_layout,
preview_divider, preview_format);
}
virtual void Load(QXmlStreamReader* reader) override
@@ -77,6 +85,10 @@ public:
height_ = reader->readElementText().toInt();
} else if (reader->name() == QStringLiteral("framerate")) {
frame_rate_ = rational::fromString(reader->readElementText());
} else if (reader->name() == QStringLiteral("pixelaspect")) {
pixel_aspect_ = rational::fromString(reader->readElementText());
} else if (reader->name() == QStringLiteral("interlacing")) {
interlacing_ = static_cast<VideoParams::Interlacing>(reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("samplerate")) {
sample_rate_ = reader->readElementText().toInt();
} else if (reader->name() == QStringLiteral("chlayout")) {
@@ -97,6 +109,8 @@ public:
writer->writeTextElement(QStringLiteral("width"), QString::number(width_));
writer->writeTextElement(QStringLiteral("height"), QString::number(height_));
writer->writeTextElement(QStringLiteral("framerate"), frame_rate_.toString());
writer->writeTextElement(QStringLiteral("pixelaspect"), pixel_aspect_.toString());
writer->writeTextElement(QStringLiteral("interlacing_"), QString::number(interlacing_));
writer->writeTextElement(QStringLiteral("samplerate"), QString::number(sample_rate_));
writer->writeTextElement(QStringLiteral("chlayout"), QString::number(channel_layout_));
writer->writeTextElement(QStringLiteral("divider"), QString::number(preview_divider_));
@@ -118,6 +132,16 @@ public:
return frame_rate_;
}
const rational& pixel_aspect() const
{
return pixel_aspect_;
}
VideoParams::Interlacing interlacing() const
{
return interlacing_;
}
int sample_rate() const
{
return sample_rate_;
@@ -142,6 +166,8 @@ private:
int width_;
int height_;
rational frame_rate_;
rational pixel_aspect_;
VideoParams::Interlacing interlacing_;
int sample_rate_;
uint64_t channel_layout_;
int preview_divider_;
+5
View File
@@ -136,6 +136,7 @@ void ViewerOutput::set_video_params(const VideoParams &video)
{
bool size_changed = video_params_.width() != video.width() || video_params_.height() != video.height();
bool timebase_changed = video_params_.time_base() != video.time_base();
bool pixel_aspect_changed = video_params_.pixel_aspect_ratio() != video.pixel_aspect_ratio();
video_params_ = video;
@@ -143,6 +144,10 @@ void ViewerOutput::set_video_params(const VideoParams &video)
emit SizeChanged(video_params_.width(), video_params_.height());
}
if (pixel_aspect_changed) {
emit PixelAspectChanged(video_params_.pixel_aspect_ratio());
}
if (timebase_changed) {
video_frame_cache_.SetTimebase(video_params_.time_base());
emit TimebaseChanged(video_params_.time_base());
+2
View File
@@ -131,6 +131,8 @@ signals:
void SizeChanged(int width, int height);
void PixelAspectChanged(const rational& pixel_aspect);
void VideoParamsChanged();
void AudioParamsChanged();
+1 -1
View File
@@ -29,7 +29,7 @@ OLIVE_NAMESPACE_ENTER
ImageStream::ImageStream() :
premultiplied_alpha_(false),
interlacing_(kInterlaceNone),
interlacing_(VideoParams::kInterlaceNone),
pixel_aspect_ratio_(1)
{
set_type(kImage);
+4 -9
View File
@@ -22,6 +22,7 @@
#define IMAGESTREAM_H
#include "render/pixelformat.h"
#include "render/videoparams.h"
#include "stream.h"
OLIVE_NAMESPACE_ENTER
@@ -75,18 +76,12 @@ public:
QString get_colorspace_match_string() const;
enum Interlacing {
kInterlaceNone,
kInterlacedTopFirst,
kInterlacedBottomFirst
};
Interlacing interlacing() const
VideoParams::Interlacing interlacing() const
{
return interlacing_;
}
void set_interlacing(Interlacing i)
void set_interlacing(VideoParams::Interlacing i)
{
interlacing_ = i;
@@ -122,7 +117,7 @@ private:
int height_;
bool premultiplied_alpha_;
QString colorspace_;
Interlacing interlacing_;
VideoParams::Interlacing interlacing_;
PixelFormat::Format format_;
+16 -2
View File
@@ -65,7 +65,8 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const
if (reader->name() == QStringLiteral("video")) {
int video_width = 0, video_height = 0, preview_div = 1;
rational video_timebase;
rational video_timebase, video_pixel_aspect;
VideoParams::Interlacing video_interlacing = VideoParams::kInterlaceNone;
PixelFormat::Format preview_format = PixelFormat::PIX_FMT_INVALID;
while (XMLReadNextStartElement(reader)) {
@@ -83,12 +84,17 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const
preview_div = reader->readElementText().toInt();
} else if (reader->name() == QStringLiteral("format")) {
preview_format = static_cast<PixelFormat::Format>(reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("pixelaspect")) {
video_pixel_aspect = rational::fromString(reader->readElementText());
} else if (reader->name() == QStringLiteral("interlacing")) {
video_interlacing = static_cast<VideoParams::Interlacing>(reader->readElementText().toInt());
} else {
reader->skipCurrentElement();
}
}
set_video_params(VideoParams(video_width, video_height, video_timebase, preview_format, preview_div));
set_video_params(VideoParams(video_width, video_height, video_timebase, preview_format,
video_pixel_aspect, video_interlacing, preview_div));
} else if (reader->name() == QStringLiteral("audio")) {
int rate = 0;
uint64_t layout = 0;
@@ -156,6 +162,8 @@ void Sequence::Save(QXmlStreamWriter *writer) const
writer->writeTextElement(QStringLiteral("width"), QString::number(video_params().width()));
writer->writeTextElement(QStringLiteral("height"), QString::number(video_params().height()));
writer->writeTextElement(QStringLiteral("timebase"), video_params().time_base().toString());
writer->writeTextElement(QStringLiteral("pixelaspect"), video_params().pixel_aspect_ratio().toString());
writer->writeTextElement(QStringLiteral("interlacing"), QString::number(video_params().interlacing()));
writer->writeTextElement(QStringLiteral("divider"), QString::number(video_params().divider()));
writer->writeTextElement(QStringLiteral("format"), QString::number(video_params().format()));
@@ -245,6 +253,8 @@ void Sequence::set_default_parameters()
height,
Config::Current()["DefaultSequenceFrameRate"].value<rational>(),
static_cast<PixelFormat::Format>(Config::Current()["DefaultSequencePreviewFormat"].toInt()),
Config::Current()["DefaultSequencePixelAspect"].value<rational>(),
Config::Current()["DefaultSequenceInterlacing"].value<VideoParams::Interlacing>(),
VideoParams::generate_auto_divider(width, height)));
set_audio_params(AudioParams(Config::Current()["DefaultSequenceAudioFrequency"].toInt(),
Config::Current()["DefaultSequenceAudioLayout"].toULongLong(),
@@ -269,6 +279,8 @@ void Sequence::set_parameters_from_footage(const QList<Footage *> footage)
vs->height(),
vs->frame_rate().flipped(),
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;
}
@@ -284,6 +296,8 @@ void Sequence::set_parameters_from_footage(const QList<Footage *> footage)
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;
+46
View File
@@ -24,8 +24,31 @@ extern "C" {
#include <libavformat/avformat.h>
}
#include <QCoreApplication>
OLIVE_NAMESPACE_ENTER
const QVector<int> AudioParams::kSupportedSampleRates = {
8000, // 8000 Hz
11025, // 11025 Hz
16000, // 16000 Hz
22050, // 22050 Hz
24000, // 24000 Hz
32000, // 32000 Hz
44100, // 44100 Hz
48000, // 48000 Hz
88200, // 88200 Hz
96000 // 96000 Hz
};
const QVector<uint64_t> AudioParams::kSupportedChannelLayouts = {
AV_CH_LAYOUT_MONO,
AV_CH_LAYOUT_STEREO,
AV_CH_LAYOUT_2_1,
AV_CH_LAYOUT_5POINT1,
AV_CH_LAYOUT_7POINT1
};
int AudioParams::time_to_bytes(const double &time) const
{
Q_ASSERT(is_valid());
@@ -127,4 +150,27 @@ bool AudioParams::is_valid() const
&& format_ != SampleFormat::SAMPLE_FMT_COUNT);
}
QString AudioParams::SampleRateToString(const int &sample_rate)
{
return QCoreApplication::translate("AudioParams", "%1 Hz").arg(sample_rate);
}
QString AudioParams::ChannelLayoutToString(const uint64_t &layout)
{
switch (layout) {
case AV_CH_LAYOUT_MONO:
return QCoreApplication::translate("AudioParams", "Mono");
case AV_CH_LAYOUT_STEREO:
return QCoreApplication::translate("AudioParams", "Stereo");
case AV_CH_LAYOUT_2_1:
return QCoreApplication::translate("AudioParams", "2.1");
case AV_CH_LAYOUT_5POINT1:
return QCoreApplication::translate("AudioParams", "5.1");
case AV_CH_LAYOUT_7POINT1:
return QCoreApplication::translate("AudioParams", "7.1");
default:
return QCoreApplication::translate("AudioParams", "Unknown (0x%1)").arg(layout, 1, 16);
}
}
OLIVE_NAMESPACE_EXIT
+13
View File
@@ -80,6 +80,19 @@ public:
bool operator==(const AudioParams& other) const;
bool operator!=(const AudioParams& other) const;
static const QVector<uint64_t> kSupportedChannelLayouts;
static const QVector<int> kSupportedSampleRates;
/**
* @brief Convert integer sample rate to a user-friendly string
*/
static QString SampleRateToString(const int &sample_rate);
/**
* @brief Convert channel layout to a user-friendly string
*/
static QString ChannelLayoutToString(const uint64_t &layout);
private:
int sample_rate_;
+12 -4
View File
@@ -149,22 +149,26 @@ QVariant OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, const Video
VideoParams frame_params = frame->video_params();
// Check frame aspect ratio
if (frame->sample_aspect_ratio() != 1) {
rational true_pixel_aspect_ratio = frame_params.pixel_aspect_ratio() / params.pixel_aspect_ratio();
if (true_pixel_aspect_ratio != 1) {
int new_width = frame_params.width();
int new_height = frame_params.height();
// Scale the frame in a way that does not reduce the resolution
if (frame->sample_aspect_ratio() > 1) {
if (frame_params.pixel_aspect_ratio() > 1) {
// Make wider
new_width = qRound(static_cast<double>(new_width) * frame->sample_aspect_ratio().toDouble());
new_width = qRound(static_cast<double>(new_width) * frame_params.pixel_aspect_ratio().toDouble());
} else {
// Make taller
new_height = qRound(static_cast<double>(new_height) / frame->sample_aspect_ratio().toDouble());
new_height = qRound(static_cast<double>(new_height) / frame_params.pixel_aspect_ratio().toDouble());
}
frame_params = VideoParams(new_width,
new_height,
frame_params.format(),
frame_params.pixel_aspect_ratio(),
frame_params.interlacing(),
frame_params.divider());
}
@@ -178,6 +182,8 @@ QVariant OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, const Video
VideoParams dest_params(frame_params.width(),
frame_params.height(),
texture_fmt,
frame_params.pixel_aspect_ratio(),
frame_params.interlacing(),
frame_params.divider());
// Create destination texture
@@ -420,6 +426,8 @@ QVariant OpenGLProxy::RunNodeAccelerated(const Node *node,
params.height(),
params.time_base(),
output_format,
params.pixel_aspect_ratio(),
params.interlacing(),
params.divider());
int real_iteration_count;
+6
View File
@@ -127,6 +127,8 @@ void RenderWorker::RenderFrame(RenderTicketPtr ticket, ViewerOutput* viewer, con
video_params_.height(),
video_params_.time_base(),
output_format,
video_params_.pixel_aspect_ratio(),
video_params_.interlacing(),
video_params_.divider()));
frame->set_timestamp(time);
frame->allocate();
@@ -295,6 +297,8 @@ QVariant RenderWorker::ProcessFrameGeneration(const Node* node, const GenerateJo
video_params_.height(),
video_params_.time_base(),
output_fmt,
video_params_.pixel_aspect_ratio(),
video_params_.interlacing(),
video_params_.divider()));
frame->allocate();
@@ -316,6 +320,8 @@ QVariant RenderWorker::GetCachedFrame(const Node* node, const rational& time)
f->height() * video_params_.divider(),
f->video_params().time_base(),
f->video_params().format(),
f->video_params().pixel_aspect_ratio(),
f->video_params().interlacing(),
video_params_.divider()));
return CachedFrameToTexture(f);
+2 -2
View File
@@ -263,8 +263,8 @@ FramePtr PixelFormat::ConvertPixelFormat(FramePtr frame, const PixelFormat::Form
// Create a destination frame with the same parameters
FramePtr converted = Frame::Create();
converted->set_video_params(VideoParams(frame->video_params().width(),
frame->video_params().height(),
dest_format));
frame->video_params().height(),
dest_format));
converted->set_timestamp(frame->timestamp());
converted->allocate();
+90 -12
View File
@@ -26,28 +26,70 @@
OLIVE_NAMESPACE_ENTER
const rational VideoParams::kPixelAspectSquare(1);
const rational VideoParams::kPixelAspectNTSCStandard(8, 9);
const rational VideoParams::kPixelAspectNTSCWidescreen(32, 27);
const rational VideoParams::kPixelAspectPALStandard(16, 15);
const rational VideoParams::kPixelAspectPALWidescreen(64, 45);
const rational VideoParams::kPixelAspect1080Anamorphic(4, 3);
const QVector<rational> VideoParams::kSupportedFrameRates = {
rational(10, 1), // 10 FPS
rational(15, 1), // 15 FPS
rational(24000, 1001), // 23.976 FPS
rational(24, 1), // 24 FPS
rational(25, 1), // 25 FPS
rational(30000, 1001), // 29.97 FPS
rational(30, 1), // 30 FPS
rational(48000, 1001), // 47.952 FPS
rational(48, 1), // 48 FPS
rational(50, 1), // 50 FPS
rational(60000, 1001), // 59.94 FPS
rational(60, 1) // 60 FPS
};
const QVector<int> VideoParams::kSupportedDividers = {1, 2, 3, 4, 6, 8, 12, 16};
const QVector<rational> VideoParams::kStandardPixelAspects = {
VideoParams::kPixelAspectSquare,
VideoParams::kPixelAspectNTSCStandard,
VideoParams::kPixelAspectNTSCWidescreen,
VideoParams::kPixelAspectPALStandard,
VideoParams::kPixelAspectPALWidescreen,
VideoParams::kPixelAspect1080Anamorphic
};
VideoParams::VideoParams() :
format_(PixelFormat::PIX_FMT_INVALID)
width_(0),
height_(0),
format_(PixelFormat::PIX_FMT_INVALID),
interlacing_(Interlacing::kInterlaceNone)
{
}
VideoParams::VideoParams(const int &width, const int &height, const PixelFormat::Format &format, const int& divider) :
VideoParams::VideoParams(const int &width, const int &height, const PixelFormat::Format &format, const rational& pixel_aspect_ratio, const Interlacing &interlacing, const int& divider) :
width_(width),
height_(height),
format_(format),
pixel_aspect_ratio_(pixel_aspect_ratio),
interlacing_(interlacing),
divider_(divider)
{
calculate_effective_size();
validate_pixel_aspect_ratio();
}
VideoParams::VideoParams(const int &width, const int &height, const rational &time_base, const PixelFormat::Format &format, const int &divider) :
VideoParams::VideoParams(const int &width, const int &height, const rational &time_base, const PixelFormat::Format &format, const rational& pixel_aspect_ratio, const Interlacing &interlacing, const int &divider) :
width_(width),
height_(height),
time_base_(time_base),
format_(format),
pixel_aspect_ratio_(pixel_aspect_ratio),
interlacing_(interlacing),
divider_(divider)
{
calculate_effective_size();
validate_pixel_aspect_ratio();
}
int VideoParams::generate_auto_divider(qint64 width, qint64 height)
@@ -60,16 +102,14 @@ int VideoParams::generate_auto_divider(qint64 width, qint64 height)
double squared_divider = double(megapixels) / double(target_res);
double divider = qSqrt(squared_divider);
QList<int> supported_dividers = Core::SupportedDividers();
if (divider <= supported_dividers.first()) {
return supported_dividers.first();
} else if (divider >= supported_dividers.last()) {
return supported_dividers.last();
if (divider <= kSupportedDividers.first()) {
return kSupportedDividers.first();
} else if (divider >= kSupportedDividers.last()) {
return kSupportedDividers.last();
} else {
for (int i=1; i<supported_dividers.size(); i++) {
int prev_divider = supported_dividers.at(i-1);
int next_divider = supported_dividers.at(i);
for (int i=1; i<kSupportedDividers.size(); i++) {
int prev_divider = kSupportedDividers.at(i-1);
int next_divider = kSupportedDividers.at(i);
if (divider >= prev_divider && divider <= next_divider) {
double prev_diff = qAbs(prev_divider - divider);
@@ -94,6 +134,7 @@ bool VideoParams::operator==(const VideoParams &rhs) const
&& height() == rhs.height()
&& time_base() == rhs.time_base()
&& format() == rhs.format()
&& pixel_aspect_ratio() == rhs.pixel_aspect_ratio()
&& divider() == rhs.divider();
}
@@ -109,12 +150,49 @@ void VideoParams::calculate_effective_size()
effective_height_ = qCeil(height() / divider_ * 0.5) * 2;
}
void VideoParams::validate_pixel_aspect_ratio()
{
if (pixel_aspect_ratio_.isNull()) {
pixel_aspect_ratio_ = 1;
}
}
bool VideoParams::is_valid() const
{
return (width() > 0
&& height() > 0
&& !pixel_aspect_ratio_.isNull()
&& format_ != PixelFormat::PIX_FMT_INVALID
&& format_ != PixelFormat::PIX_FMT_COUNT);
}
QString VideoParams::FrameRateToString(const rational &frame_rate)
{
return QCoreApplication::translate("VideoParams", "%1 FPS").arg(frame_rate.toDouble());
}
QStringList VideoParams::GetStandardPixelAspectRatioNames()
{
QStringList strings = {
QCoreApplication::translate("VideoParams", "Square Pixels (%1)"),
QCoreApplication::translate("VideoParams", "NTSC Standard (%1)"),
QCoreApplication::translate("VideoParams", "NTSC Widescreen (%1)"),
QCoreApplication::translate("VideoParams", "PAL Standard (%1)"),
QCoreApplication::translate("VideoParams", "PAL Widescreen (%1)"),
QCoreApplication::translate("VideoParams", "HD Anamorphic 1080 (%1)")
};
// Format each
for (int i=0; i<strings.size(); i++) {
strings.replace(i, FormatPixelAspectRatioString(strings.at(i), kStandardPixelAspects.at(i)));
}
return strings;
}
QString VideoParams::FormatPixelAspectRatioString(const QString &format, const rational &ratio)
{
return format.arg(QString::number(ratio.toDouble(), 'f', 4));
}
OLIVE_NAMESPACE_EXIT
+48 -2
View File
@@ -29,9 +29,19 @@ OLIVE_NAMESPACE_ENTER
class VideoParams {
public:
enum Interlacing {
kInterlaceNone,
kInterlacedTopFirst,
kInterlacedBottomFirst
};
VideoParams();
VideoParams(const int& width, const int& height, const PixelFormat::Format& format, const int& divider = 1);
VideoParams(const int& width, const int& height, const rational& time_base, const PixelFormat::Format& format, const int& divider = 1);
VideoParams(const int& width, const int& height, const PixelFormat::Format& format,
const rational& pixel_aspect_ratio = 1,
const Interlacing& interlacing = kInterlaceNone, const int& divider = 1);
VideoParams(const int& width, const int& height, const rational& time_base,
const PixelFormat::Format& format, const rational& pixel_aspect_ratio = 1,
const Interlacing& interlacing = kInterlaceNone, const int& divider = 1);
const int& width() const
{
@@ -68,6 +78,16 @@ public:
return format_;
}
const rational& pixel_aspect_ratio() const
{
return pixel_aspect_ratio_;
}
Interlacing interlacing() const
{
return interlacing_;
}
static int generate_auto_divider(qint64 width, qint64 height);
bool is_valid() const;
@@ -75,15 +95,40 @@ public:
bool operator==(const VideoParams& rhs) const;
bool operator!=(const VideoParams& rhs) const;
static const rational kPixelAspectSquare;
static const rational kPixelAspectNTSCStandard;
static const rational kPixelAspectNTSCWidescreen;
static const rational kPixelAspectPALStandard;
static const rational kPixelAspectPALWidescreen;
static const rational kPixelAspect1080Anamorphic;
static const QVector<rational> kSupportedFrameRates;
static const QVector<rational> kStandardPixelAspects;
static const QVector<int> kSupportedDividers;
/**
* @brief Convert rational frame rate (i.e. flipped timebase) to a user-friendly string
*/
static QString FrameRateToString(const rational& frame_rate);
static QStringList GetStandardPixelAspectRatioNames();
static QString FormatPixelAspectRatioString(const QString& format, const rational& ratio);
private:
void calculate_effective_size();
void validate_pixel_aspect_ratio();
int width_;
int height_;
rational time_base_;
PixelFormat::Format format_;
rational pixel_aspect_ratio_;
Interlacing interlacing_;
int divider_;
int effective_width_;
int effective_height_;
@@ -92,5 +137,6 @@ private:
OLIVE_NAMESPACE_EXIT
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::VideoParams)
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::VideoParams::Interlacing)
#endif // VIDEOPARAMS_H
+1
View File
@@ -41,6 +41,7 @@ add_subdirectory(projecttoolbar)
add_subdirectory(resizablescrollbar)
add_subdirectory(scope)
add_subdirectory(slider)
add_subdirectory(standardcombos)
add_subdirectory(taskview)
add_subdirectory(timebased)
add_subdirectory(timelinewidget)
@@ -29,7 +29,8 @@ QVariant NodeTableTraverser::ProcessVideoFootage(StreamPtr stream, const rationa
return QVariant::fromValue(VideoParams(video_stream->width(),
video_stream->height(),
video_stream->timebase(),
video_stream->format()));
video_stream->format(),
video_stream->pixel_aspect_ratio()));
}
QVariant NodeTableTraverser::ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time)
+28
View File
@@ -0,0 +1,28 @@
# 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}
widget/standardcombos/channellayoutcombobox.h
widget/standardcombos/frameratecombobox.h
widget/standardcombos/interlacedcombobox.h
widget/standardcombos/pixelaspectratiocombobox.h
widget/standardcombos/pixelformatcombobox.h
widget/standardcombos/sampleratecombobox.h
widget/standardcombos/standardcombos.h
widget/standardcombos/videodividercombobox.h
PARENT_SCOPE
)
@@ -0,0 +1,62 @@
/***
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 CHANNELLAYOUTCOMBOBOX_H
#define CHANNELLAYOUTCOMBOBOX_H
#include <QComboBox>
#include "render/audioparams.h"
OLIVE_NAMESPACE_ENTER
class ChannelLayoutComboBox : public QComboBox
{
Q_OBJECT
public:
ChannelLayoutComboBox(QWidget* parent = nullptr) :
QComboBox(parent)
{
foreach (const uint64_t& ch_layout, AudioParams::kSupportedChannelLayouts) {
this->addItem(AudioParams::ChannelLayoutToString(ch_layout),
QVariant::fromValue(ch_layout));
}
}
uint64_t GetChannelLayout() const
{
return this->currentData().toULongLong();
}
void SetChannelLayout(uint64_t ch)
{
for (int i=0; i<this->count(); i++) {
if (this->itemData(i).toULongLong() == ch) {
this->setCurrentIndex(i);
break;
}
}
}
};
OLIVE_NAMESPACE_EXIT
#endif // CHANNELLAYOUTCOMBOBOX_H
@@ -0,0 +1,62 @@
/***
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 FRAMERATECOMBOBOX_H
#define FRAMERATECOMBOBOX_H
#include <QComboBox>
#include "common/rational.h"
#include "render/videoparams.h"
OLIVE_NAMESPACE_ENTER
class FrameRateComboBox : public QComboBox
{
Q_OBJECT
public:
FrameRateComboBox(QWidget* parent = nullptr) :
QComboBox(parent)
{
foreach (const rational& fr, VideoParams::kSupportedFrameRates) {
this->addItem(VideoParams::FrameRateToString(fr), QVariant::fromValue(fr));
}
}
rational GetFrameRate() const
{
return this->currentData().value<rational>();
}
void SetFrameRate(const rational& r)
{
for (int i=0; i<this->count(); i++) {
if (this->itemData(i).value<rational>() == r) {
this->setCurrentIndex(i);
break;
}
}
}
};
OLIVE_NAMESPACE_EXIT
#endif // FRAMERATECOMBOBOX_H
@@ -0,0 +1,57 @@
/***
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 INTERLACEDCOMBOBOX_H
#define INTERLACEDCOMBOBOX_H
#include <QComboBox>
#include "render/videoparams.h"
OLIVE_NAMESPACE_ENTER
class InterlacedComboBox : public QComboBox
{
Q_OBJECT
public:
InterlacedComboBox(QWidget* parent = nullptr) :
QComboBox(parent)
{
// These must match the Interlacing enum in VideoParams
this->addItem(tr("None (Progressive)"));
this->addItem(tr("Top-Field First"));
this->addItem(tr("Bottom-Field First"));
}
VideoParams::Interlacing GetInterlaceMode() const
{
return static_cast<VideoParams::Interlacing>(this->currentIndex());
}
void SetInterlaceMode(VideoParams::Interlacing mode)
{
this->setCurrentIndex(mode);
}
};
OLIVE_NAMESPACE_EXIT
#endif // INTERLACEDCOMBOBOX_H
@@ -0,0 +1,127 @@
/***
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 PIXELASPECTRATIOCOMBOBOX_H
#define PIXELASPECTRATIOCOMBOBOX_H
#include <QComboBox>
#include "common/ratiodialog.h"
#include "render/videoparams.h"
OLIVE_NAMESPACE_ENTER
class PixelAspectRatioComboBox : public QComboBox
{
Q_OBJECT
public:
PixelAspectRatioComboBox(QWidget* parent = nullptr) :
QComboBox(parent),
dont_prompt_custom_par_(false)
{
QStringList par_names = VideoParams::GetStandardPixelAspectRatioNames();
for (int i=0; i<VideoParams::kStandardPixelAspects.size(); i++) {
const rational& ratio = VideoParams::kStandardPixelAspects.at(i);
this->addItem(par_names.at(i),
QVariant::fromValue(ratio));
}
// Always add custom item last, much of the logic relies on this. Set this to the current AR so
// that if none of the above are ==, it will eventually select this item
this->addItem(QString());
UpdateCustomItem(rational());
// Pick up index signal to query for custom aspect ratio if requested
connect(this, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &PixelAspectRatioComboBox::IndexChanged);
}
rational GetPixelAspectRatio() const
{
return this->currentData().value<rational>();
}
void SetPixelAspectRatio(const rational& r)
{
// Determine which index to select on startup
for (int i=0; i<this->count(); i++) {
if (this->itemData(i).value<rational>() == r) {
this->setCurrentIndex(i);
return;
}
}
// Must not have found the ratio, so it must be custom
UpdateCustomItem(r);
dont_prompt_custom_par_ = true;
this->setCurrentIndex(this->count() - 1);
dont_prompt_custom_par_ = false;
}
private slots:
void IndexChanged(int index)
{
if (dont_prompt_custom_par_) {
return;
}
// Detect if custom was selected, in which case query what the new AR should be
if (index == this->count() - 1) {
// Query for custom pixel aspect ratio
bool ok;
double custom_ratio = GetFloatRatioFromUser(this,
tr("Set Custom Pixel Aspect Ratio"),
&ok);
if (ok) {
UpdateCustomItem(rational::fromDouble(custom_ratio));
}
}
}
private:
void UpdateCustomItem(const rational &ratio)
{
const int custom_index = this->count() - 1;
if (ratio.isNull()) {
this->setItemText(custom_index,
tr("Custom..."));
// Use 1:1 to prevent any real chance of the PAR being set to 0
this->setItemData(custom_index,
QVariant::fromValue(rational(1)));
} else {
this->setItemText(custom_index,
VideoParams::FormatPixelAspectRatioString(tr("Custom (%1)"), ratio));
this->setItemData(custom_index,
QVariant::fromValue(ratio));
}
}
bool dont_prompt_custom_par_;
};
OLIVE_NAMESPACE_EXIT
#endif // PIXELASPECTRATIOCOMBOBOX_H
@@ -0,0 +1,67 @@
/***
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 PIXELFORMATCOMBOBOX_H
#define PIXELFORMATCOMBOBOX_H
#include <QComboBox>
#include "render/pixelformat.h"
OLIVE_NAMESPACE_ENTER
class PixelFormatComboBox : public QComboBox
{
Q_OBJECT
public:
PixelFormatComboBox(bool alpha_only, bool float_only, QWidget* parent = nullptr) :
QComboBox(parent)
{
// Set up preview formats
for (int i=0;i<PixelFormat::PIX_FMT_COUNT;i++) {
PixelFormat::Format pix_fmt = static_cast<PixelFormat::Format>(i);
if ((!alpha_only || PixelFormat::FormatHasAlphaChannel(pix_fmt))
&& (!float_only || PixelFormat::FormatIsFloat(pix_fmt))) {
this->addItem(PixelFormat::GetName(pix_fmt), pix_fmt);
}
}
}
PixelFormat::Format GetPixelFormat() const
{
return static_cast<PixelFormat::Format>(this->currentData().toInt());
}
void SetPixelFormat(PixelFormat::Format fmt)
{
for (int i=0; i<this->count(); i++) {
if (this->itemData(i).toInt() == fmt) {
this->setCurrentIndex(i);
break;
}
}
}
};
OLIVE_NAMESPACE_EXIT
#endif // PIXELFORMATCOMBOBOX_H
@@ -0,0 +1,61 @@
/***
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 SAMPLERATECOMBOBOX_H
#define SAMPLERATECOMBOBOX_H
#include <QComboBox>
#include "render/audioparams.h"
OLIVE_NAMESPACE_ENTER
class SampleRateComboBox : public QComboBox
{
Q_OBJECT
public:
SampleRateComboBox(QWidget* parent = nullptr) :
QComboBox(parent)
{
foreach (int sr, AudioParams::kSupportedSampleRates) {
this->addItem(AudioParams::SampleRateToString(sr), sr);
}
}
int GetSampleRate() const
{
return this->currentData().toInt();
}
void SetSampleRate(int rate)
{
for (int i=0; i<this->count(); i++) {
if (this->itemData(i).toInt() == rate) {
this->setCurrentIndex(i);
break;
}
}
}
};
OLIVE_NAMESPACE_EXIT
#endif // SAMPLERATECOMBOBOX_H
@@ -0,0 +1,32 @@
/***
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 STANDARDCOMBOS_H
#define STANDARDCOMBOS_H
#include "channellayoutcombobox.h"
#include "frameratecombobox.h"
#include "interlacedcombobox.h"
#include "pixelaspectratiocombobox.h"
#include "pixelformatcombobox.h"
#include "sampleratecombobox.h"
#include "videodividercombobox.h"
#endif // STANDARDCOMBOS_H
@@ -0,0 +1,69 @@
/***
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 VIDEODIVIDERCOMBOBOX_H
#define VIDEODIVIDERCOMBOBOX_H
#include <QComboBox>
#include "render/videoparams.h"
OLIVE_NAMESPACE_ENTER
class VideoDividerComboBox : public QComboBox
{
Q_OBJECT
public:
VideoDividerComboBox(QWidget* parent = nullptr) :
QComboBox(parent)
{
foreach (int d, VideoParams::kSupportedDividers) {
QString name;
if (d == 1) {
name = tr("Full");
} else {
name = tr("1/%1").arg(d);
}
this->addItem(name, d);
}
}
int GetDivider() const
{
return this->currentData().toInt();
}
void SetDivider(int d)
{
for (int i=0; i<this->count(); i++) {
if (this->itemData(i).toInt() == d) {
this->setCurrentIndex(i);
break;
}
}
}
};
OLIVE_NAMESPACE_EXIT
#endif // VIDEODIVIDERCOMBOBOX_H
+4
View File
@@ -88,6 +88,8 @@ void FootageViewerWidget::SetFootage(Footage *footage)
video_stream->height(),
video_stream->frame_rate().flipped(),
static_cast<PixelFormat::Format>(Config::Current()["DefaultSequencePreviewFormat"].toInt()),
video_stream->pixel_aspect_ratio(),
video_stream->interlacing(),
VideoParams::generate_auto_divider(video_stream->width(), video_stream->height())));
NodeParam::ConnectEdge(video_node_->output(), viewer_node_->texture_input());
} else {
@@ -98,6 +100,8 @@ void FootageViewerWidget::SetFootage(Footage *footage)
height,
Config::Current()["DefaultSequenceFrameRate"].value<rational>(),
static_cast<PixelFormat::Format>(Config::Current()["DefaultSequencePreviewFormat"].toInt()),
Config::Current()["DefaultSequencePixelAspect"].value<rational>(),
Config::Current()["DefaultSequenceInterlacing"].value<VideoParams::Interlacing>(),
VideoParams::generate_auto_divider(width, height)));
}
+15 -10
View File
@@ -164,7 +164,8 @@ void ViewerWidget::TimeChangedEvent(const int64_t &i)
void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
{
connect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot);
connect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SetViewerResolution);
connect(n, &ViewerOutput::PixelAspectChanged, this, &ViewerWidget::SetViewerPixelAspect);
connect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot);
connect(n, &ViewerOutput::VideoParamsChanged, this, &ViewerWidget::UpdateRendererVideoParameters);
connect(n, &ViewerOutput::AudioParamsChanged, this, &ViewerWidget::UpdateRendererAudioParameters);
@@ -176,7 +177,8 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
n->audio_playback_cache()->SetParameters(n->audio_params());
SizeChangedSlot(n->video_params().width(), n->video_params().height());
SetViewerResolution(n->video_params().width(), n->video_params().height());
SetViewerPixelAspect(n->video_params().pixel_aspect_ratio());
last_length_ = rational();
LengthChangedSlot(n->GetLength());
@@ -213,7 +215,8 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
{
PauseInternal();
disconnect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot);
disconnect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SetViewerResolution);
disconnect(n, &ViewerOutput::PixelAspectChanged, this, &ViewerWidget::SetViewerPixelAspect);
disconnect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot);
disconnect(n, &ViewerOutput::VideoParamsChanged, this, &ViewerWidget::UpdateRendererVideoParameters);
disconnect(n, &ViewerOutput::AudioParamsChanged, this, &ViewerWidget::UpdateRendererAudioParameters);
@@ -224,7 +227,7 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
ruler()->SetPlaybackCache(nullptr);
// Effectively disables the viewer and clears the state
SizeChangedSlot(0, 0);
SetViewerResolution(0, 0);
display_widget_->DisconnectColorManager();
foreach (ViewerWindow* window, windows_) {
@@ -280,11 +283,6 @@ void ViewerWidget::SetColorMenuEnabled(bool enabled)
color_menu_enabled_ = enabled;
}
void ViewerWidget::SetOverrideSize(int width, int height)
{
SizeChangedSlot(width, height);
}
void ViewerWidget::SetMatrix(const QMatrix4x4 &mat)
{
display_widget_->SetMatrix(mat);
@@ -1061,7 +1059,7 @@ void ViewerWidget::PlaybackTimerUpdate()
}
}
void ViewerWidget::SizeChangedSlot(int width, int height)
void ViewerWidget::SetViewerResolution(int width, int height)
{
sizer_->SetChildSize(width, height);
@@ -1070,6 +1068,13 @@ void ViewerWidget::SizeChangedSlot(int width, int height)
}
}
void ViewerWidget::SetViewerPixelAspect(const rational &ratio)
{
sizer_->SetPixelAspectRatio(ratio);
// FIXME: Update windows too
}
void ViewerWidget::LengthChangedSlot(const rational &length)
{
if (last_length_ != length) {
+4 -4
View File
@@ -73,8 +73,6 @@ public:
*/
void SetColorMenuEnabled(bool enabled);
void SetOverrideSize(int width, int height);
void SetMatrix(const QMatrix4x4& mat);
/**
@@ -124,6 +122,10 @@ public slots:
void CacheSequenceInOut();
void SetViewerResolution(int width, int height);
void SetViewerPixelAspect(const rational& ratio);
signals:
/**
* @brief Wrapper for ViewerGLWidget::CursorColor()
@@ -257,8 +259,6 @@ private:
private slots:
void PlaybackTimerUpdate();
void SizeChangedSlot(int width, int height);
void LengthChangedSlot(const rational& length);
void UpdateRendererVideoParameters();
+15 -10
View File
@@ -27,7 +27,9 @@ OLIVE_NAMESPACE_ENTER
ViewerSizer::ViewerSizer(QWidget *parent) :
QWidget(parent),
widget_(nullptr),
aspect_ratio_(0),
width_(0),
height_(0),
pixel_aspect_(1),
zoom_(0)
{
}
@@ -51,11 +53,12 @@ void ViewerSizer::SetChildSize(int width, int height)
width_ = width;
height_ = height;
if (!width_ || !height_) {
aspect_ratio_ = 0;
} else {
aspect_ratio_ = static_cast<double>(width_) / static_cast<double>(height_);
}
UpdateSize();
}
void ViewerSizer::SetPixelAspectRatio(const rational &pixel_aspect)
{
pixel_aspect_ = pixel_aspect;
UpdateSize();
}
@@ -81,7 +84,7 @@ void ViewerSizer::UpdateSize()
}
// If the aspect ratio is 0, the widget is always hidden
if (qIsNull(aspect_ratio_)) {
if (!width_ || !height_) {
widget_->setVisible(false);
return;
}
@@ -91,6 +94,8 @@ void ViewerSizer::UpdateSize()
QSize child_size;
QMatrix4x4 child_matrix;
double sequence_aspect_ratio = static_cast<double>(width_) / static_cast<double>(height_) * pixel_aspect_.toDouble();
if (zoom_ <= 0) {
// If zoom is 0, we auto-fit
@@ -98,12 +103,12 @@ void ViewerSizer::UpdateSize()
child_size = size();
if (our_aspect_ratio > aspect_ratio_) {
if (our_aspect_ratio > sequence_aspect_ratio) {
// This container is wider than the image, scale by height
child_size = QSize(qRound(child_size.height() * aspect_ratio_), height());
child_size = QSize(qRound(child_size.height() * sequence_aspect_ratio), height());
} else {
// This container is taller than the image, scale by width
child_size = QSize(width(), qRound(child_size.width() / aspect_ratio_));
child_size = QSize(width(), qRound(child_size.width() / sequence_aspect_ratio));
}
} else {
+7 -4
View File
@@ -24,6 +24,7 @@
#include <QWidget>
#include "common/define.h"
#include "common/rational.h"
OLIVE_NAMESPACE_ENTER
@@ -56,6 +57,11 @@ public:
*/
void SetChildSize(int width, int height);
/**
* @brief Set pixel aspect ratio
*/
void SetPixelAspectRatio(const rational& pixel_aspect);
/**
* @brief Set the zoom value of the child widget
*
@@ -91,10 +97,7 @@ private:
int width_;
int height_;
/**
* @brief Aspect ratio calculated from the size provided by SetChildSize()
*/
double aspect_ratio_;
rational pixel_aspect_;
/**
* @brief Internal zoom value