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:
@@ -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
|
||||
|
||||
@@ -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
@@ -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_;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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();
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -131,6 +131,8 @@ signals:
|
||||
|
||||
void SizeChanged(int width, int height);
|
||||
|
||||
void PixelAspectChanged(const rational& pixel_aspect);
|
||||
|
||||
void VideoParamsChanged();
|
||||
void AudioParamsChanged();
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ OLIVE_NAMESPACE_ENTER
|
||||
|
||||
ImageStream::ImageStream() :
|
||||
premultiplied_alpha_(false),
|
||||
interlacing_(kInterlaceNone),
|
||||
interlacing_(VideoParams::kInterlaceNone),
|
||||
pixel_aspect_ratio_(1)
|
||||
{
|
||||
set_type(kImage);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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 ÷r) :
|
||||
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 ÷r) :
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user