Commit bc48b717 authored by Scott Petrovic's avatar Scott Petrovic

D7833: Add options for render animation dialog - height, width, fps

parent f05a29ad
......@@ -35,6 +35,7 @@ struct KisAsyncAnimationFramesSavingRenderer::Private
sequenceNumberingOffset(_sequenceNumberingOffset),
exportConfiguration(_exportConfiguration)
{
savingDoc->setAutoSaveDelay(0);
savingDoc->setFileBatchMode(true);
......@@ -59,6 +60,7 @@ struct KisAsyncAnimationFramesSavingRenderer::Private
KisTimeRange range;
int sequenceNumberingOffset = 0;
QString filenamePrefix;
QString filenameSuffix;
......@@ -71,7 +73,7 @@ KisAsyncAnimationFramesSavingRenderer::KisAsyncAnimationFramesSavingRenderer(Kis
const QString &fileNameSuffix,
const QByteArray &outputMimeType,
const KisTimeRange &range,
int sequenceNumberingOffset,
const int sequenceNumberingOffset,
KisPropertiesConfigurationSP exportConfiguration)
: m_d(new Private(image, range, sequenceNumberingOffset, exportConfiguration))
{
......@@ -83,6 +85,9 @@ KisAsyncAnimationFramesSavingRenderer::KisAsyncAnimationFramesSavingRenderer(Kis
connect(this, SIGNAL(sigCancelRegenerationInternal(int)), SLOT(notifyFrameCancelled(int)));
}
KisAsyncAnimationFramesSavingRenderer::~KisAsyncAnimationFramesSavingRenderer()
{
}
......
......@@ -162,6 +162,7 @@ KisAsyncAnimationRendererBase *KisAsyncAnimationFramesSaveDialog::createRenderer
m_d->exportConfiguration);
}
QString KisAsyncAnimationFramesSaveDialog::savedFilesMask() const
{
return m_d->filenamePrefix + "%04d" + m_d->filenameSuffix;
......
......@@ -68,7 +68,11 @@ void KisAnimationExporterTest::testAnimationExport()
KisAsyncAnimationFramesSaveDialog exporter(document->image(),
KisTimeRange::fromTime(0,2),
"export-test.png",
0, 0);
0,
0);
exporter.setBatchMode(true);
exporter.regenerateRange(0);
......
......@@ -109,6 +109,7 @@ void AnimaterionRenderer::slotRenderAnimation()
dlgAnimationRenderer.getFrameExportConfiguration());
exporter.setBatchMode(batchMode);
KisAsyncAnimationFramesSaveDialog::Result result =
exporter.regenerateRange(m_view->mainWindow()->viewManager());
......
......@@ -46,6 +46,8 @@
#include <kis_file_name_requester.h>
#include <KisDocument.h>
#include <KoDialog.h>
#include "kis_slider_spin_box.h"
#include "kis_acyclic_signal_connector.h"
DlgAnimationRenderer::DlgAnimationRenderer(KisDocument *doc, QWidget *parent)
: KoDialog(parent)
......@@ -78,6 +80,25 @@ DlgAnimationRenderer::DlgAnimationRenderer(KisDocument *doc, QWidget *parent)
//m_page->intEnd->setMaximum(doc->image()->animationInterface()->fullClipRange().end()); // animators sometimes want to export after end frame
m_page->intEnd->setValue(doc->image()->animationInterface()->playbackRange().end());
m_page->intHeight->setMinimum(1);
m_page->intHeight->setMaximum(10000);
m_page->intHeight->setValue(doc->image()->height());
m_page->intWidth->setMinimum(1);
m_page->intWidth->setMaximum(10000);
m_page->intWidth->setValue(doc->image()->width());
// try to lock the width and height being updated
KisAcyclicSignalConnector *constrainsConnector = new KisAcyclicSignalConnector(this);
constrainsConnector->createCoordinatedConnector()->connectBackwardInt(m_page->intWidth, SIGNAL(valueChanged(int)), this, SLOT(slotLockAspectRatioDimensionsWidth(int)));
constrainsConnector->createCoordinatedConnector()->connectForwardInt(m_page->intHeight, SIGNAL(valueChanged(int)), this, SLOT(slotLockAspectRatioDimensionsHeight(int)));
m_page->intFramesPerSecond->setValue(doc->image()->animationInterface()->framerate());
QFileInfo audioFileInfo(doc->image()->animationInterface()->audioChannelFileName());
const bool hasAudio = audioFileInfo.exists();
m_page->chkIncludeAudio->setEnabled(hasAudio);
......@@ -246,9 +267,10 @@ void DlgAnimationRenderer::setSequenceConfiguration(KisPropertiesConfigurationSP
}
m_page->dirRequester->setFileName(cfg->getString("directory", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)));
m_page->intStart->setValue(cfg->getInt("first_frame", m_image->animationInterface()->playbackRange().start()));
m_page->intStart->setValue(cfg->getInt("first_frame", m_image->animationInterface()->playbackRange().start()));
m_page->intEnd->setValue(cfg->getInt("last_frame", m_image->animationInterface()->playbackRange().end()));
m_page->sequenceStart->setValue(cfg->getInt("sequence_start", m_image->animationInterface()->playbackRange().start()));
QString mimetype = cfg->getString("mimetype");
for (int i = 0; i < m_page->cmbMimetype->count(); ++i) {
if (m_page->cmbMimetype->itemData(i).toString() == mimetype) {
......@@ -287,7 +309,6 @@ KisPropertiesConfigurationSP DlgAnimationRenderer::getVideoConfiguration() const
cfg->setProperty("last_frame", m_page->intEnd->value());
cfg->setProperty("sequence_start", m_page->sequenceStart->value());
// delete image sequence if we are only exporting out video
cfg->setProperty("delete_sequence", m_page->shouldExportOnlyVideo->isChecked());
......@@ -314,6 +335,9 @@ KisPropertiesConfigurationSP DlgAnimationRenderer::getEncoderConfiguration() con
cfg->setProperty("directory", fetchRenderingDirectory());
cfg->setProperty("first_frame", m_page->intStart->value());
cfg->setProperty("last_frame", m_page->intEnd->value());
cfg->setProperty("framerate", m_page->intFramesPerSecond->value());
cfg->setProperty("height", m_page->intHeight->value());
cfg->setProperty("width", m_page->intWidth->value());
cfg->setProperty("sequence_start", m_page->sequenceStart->value());
cfg->setProperty("include_audio", m_page->chkIncludeAudio->isChecked());
......@@ -322,6 +346,10 @@ KisPropertiesConfigurationSP DlgAnimationRenderer::getEncoderConfiguration() con
void DlgAnimationRenderer::setEncoderConfiguration(KisPropertiesConfigurationSP cfg)
{
m_page->intHeight->setValue(cfg->getInt("height", int(m_image->height())));
m_page->intWidth->setValue(cfg->getInt("width", int(m_image->width())));
m_page->intFramesPerSecond->setValue(cfg->getInt("framerate", int(m_image->animationInterface()->framerate())));
if (m_encoderConfigWidget) {
m_encoderConfigWidget->setConfiguration(cfg);
}
......@@ -498,9 +526,11 @@ void DlgAnimationRenderer::slotExportTypeChanged()
{
KisConfig cfg;
// if a video format needs to be outputted
if (m_page->shouldExportAll->isChecked() || m_page->shouldExportOnlyVideo->isChecked()) {
bool willEncodeVideo =
m_page->shouldExportAll->isChecked() || m_page->shouldExportOnlyVideo->isChecked();
// if a video format needs to be outputted
if (willEncodeVideo) {
// videos always uses PNG for creating video, so disable the ability to change the format
m_page->cmbMimetype->setEnabled(false);
for (int i = 0; i < m_page->cmbMimetype->count(); ++i) {
......@@ -511,6 +541,13 @@ void DlgAnimationRenderer::slotExportTypeChanged()
}
}
m_page->intWidth->setVisible(willEncodeVideo);
m_page->intHeight->setVisible(willEncodeVideo);
m_page->intFramesPerSecond->setVisible(willEncodeVideo);
m_page->fpsLabel->setVisible(willEncodeVideo);
m_page->lblWidth->setVisible(willEncodeVideo);
m_page->lblHeight->setVisible(willEncodeVideo);
// if only exporting video
if (m_page->shouldExportOnlyVideo->isChecked()) {
m_page->cmbMimetype->setEnabled(false); // allow to change image format
......@@ -526,6 +563,7 @@ void DlgAnimationRenderer::slotExportTypeChanged()
if (m_page->shouldExportOnlyImageSequence->isChecked()) {
m_page->cmbMimetype->setEnabled(true); // allow to change image format
m_page->videoOptionsGroup->setVisible(false);
m_page->imageSequenceOptionsGroup->setVisible(false);
m_page->imageSequenceOptionsGroup->setVisible(true);
cfg.writeEntry<QString>("AnimationRenderer/export_type", "ImageSequence");
......@@ -544,3 +582,28 @@ void DlgAnimationRenderer::slotExportTypeChanged()
// if the widget gets bigger at any point, the resize will use that, even if elements are hidden later to make it smaller
resize(m_page->sizeHint());
}
void DlgAnimationRenderer::slotLockAspectRatioDimensionsWidth(int width)
{
Q_UNUSED(width);
float aspectRatio = (float)m_image->width() / (float)m_image->height();
// update height here
float newHeight = m_page->intWidth->value() / aspectRatio ;
m_page->intHeight->setValue(newHeight);
}
void DlgAnimationRenderer::slotLockAspectRatioDimensionsHeight(int height)
{
Q_UNUSED(height);
float aspectRatio = (float)m_image->width() / (float)m_image->height();
// update width here
float newWidth = aspectRatio * m_page->intHeight->value();
m_page->intWidth->setValue(newWidth);
}
......@@ -76,6 +76,9 @@ private Q_SLOTS:
void sequenceMimeTypeSelected();
void ffmpegLocationChanged(const QString&);
void slotLockAspectRatioDimensionsWidth(int width);
void slotLockAspectRatioDimensionsHeight(int height);
void slotExportTypeChanged();
......
......@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>904</width>
<height>309</height>
<width>621</width>
<height>381</height>
</rect>
</property>
<property name="sizePolicy">
......@@ -20,9 +20,6 @@
<string>AnimationRenderer Image</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>18</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
......@@ -41,14 +38,14 @@
<item>
<widget class="QRadioButton" name="shouldExportOnlyImageSequence">
<property name="text">
<string>Image Sequence</string>
<string>Image Se&amp;quence</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="shouldExportOnlyVideo">
<property name="text">
<string>Video</string>
<string>&amp;Video</string>
</property>
</widget>
</item>
......@@ -75,56 +72,121 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>20</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1">
<widget class="QSpinBox" name="intStart">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>First frame:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="intStart">
<item row="0" column="4">
<widget class="QLabel" name="fpsLabel">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>FPS:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QSpinBox" name="intFramesPerSecond">
<property name="minimum">
<number>1</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="intEnd">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Last frame:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="intEnd">
<item row="0" column="3">
<widget class="QSpinBox" name="intWidth">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string> px</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="0" column="2">
<widget class="QLabel" name="lblWidth">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
<property name="text">
<string>Width:</string>
</property>
</spacer>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="lblHeight">
<property name="text">
<string>Height:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QSpinBox" name="intHeight">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string> px</string>
</property>
</widget>
</item>
</layout>
</item>
......
......@@ -219,18 +219,29 @@ KisImageBuilder_Result VideoSaver::encode(const QString &filename, KisProperties
KisImageBuilder_Result result = KisImageBuilder_RESULT_OK;
KisImageAnimationInterface *animation = m_image->animationInterface();
const KisTimeRange fullRange = animation->fullClipRange();
const int frameRate = animation->framerate();
KIS_SAFE_ASSERT_RECOVER_NOOP(configuration->hasProperty("first_frame"));
KIS_SAFE_ASSERT_RECOVER_NOOP(configuration->hasProperty("last_frame"));
KIS_SAFE_ASSERT_RECOVER_NOOP(configuration->hasProperty("height"));
KIS_SAFE_ASSERT_RECOVER_NOOP(configuration->hasProperty("width"));
KIS_SAFE_ASSERT_RECOVER_NOOP(configuration->hasProperty("include_audio"));
KIS_SAFE_ASSERT_RECOVER_NOOP(configuration->hasProperty("directory"));
KIS_SAFE_ASSERT_RECOVER_NOOP(configuration->hasProperty("framerate"));
KisImageAnimationInterface *animation = m_image->animationInterface();
const KisTimeRange fullRange = animation->fullClipRange();
const int frameRate = configuration->getInt("framerate", animation->framerate());
const KisTimeRange clipRange(configuration->getInt("first_frame", fullRange.start()), configuration->getInt("last_frame", fullRange.end()));
const bool includeAudio = configuration->getBool("include_audio", true);
const int exportHeight = configuration->getInt("height", int(m_image->height()));
const int exportWidth = configuration->getInt("width", int(m_image->width()));
// export dimensions could be off a little bit, so the last force option tweaks the pixels for the export to work
const QString exportDimensions = QString("scale=w=").append(QString::number(exportWidth)).append(":h=")
.append(QString::number(exportHeight)).append(":force_original_aspect_ratio=decrease");
const QDir framesDir(configuration->getString("directory"));
QString resultFile;
......@@ -278,6 +289,12 @@ KisImageBuilder_Result VideoSaver::encode(const QString &filename, KisProperties
<< additionalOptionsList
<< "-y" << resultFile;
// if we are exporting out at a different image size, we apply scaling filter
if (m_image->height() != exportHeight || m_image->width() != exportWidth) {
args << "-vf" << exportDimensions;
}
dbgFile << "savedFilesMask" << savedFilesMask << "start" << QString::number(clipRange.start()) << "duration" << clipRange.duration();
KisImageBuilder_Result result =
......@@ -295,6 +312,11 @@ KisImageBuilder_Result VideoSaver::encode(const QString &filename, KisProperties
<< "-start_number" << QString::number(clipRange.start())
<< "-i" << savedFilesMask;
// if we are exporting out at a different image size, we apply scaling filter
if (m_image->height() != exportHeight || m_image->width() != exportWidth) {
args << "-vf" << exportDimensions;
}
QFileInfo audioFileInfo = animation->audioChannelFileName();
if (includeAudio && audioFileInfo.exists()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment