Commit 080352e0 authored by Halla Rempt's avatar Halla Rempt
Browse files

Render the frames and call the ffmpeg converter

The converter still errors out, but at least the frames are
exported correctly now and all the correct options are passed
to the video converter plugin.
parent 23f7e499
......@@ -43,6 +43,12 @@ public:
{
}
inline KisTimeRange(int start, int end, bool)
: m_start(start),
m_end(end)
{
}
bool operator==(const KisTimeRange &rhs) const {
return rhs.m_start == m_start && rhs.m_end == m_end;
}
......@@ -123,12 +129,6 @@ public:
static void calculateTimeRangeRecursive(const KisNode *node, int time, KisTimeRange &range, bool exclusive);
private:
inline KisTimeRange(int start, int end, bool)
: m_start(start),
m_end(end)
{
}
private:
int m_start;
......
......@@ -624,7 +624,6 @@ bool KisDocument::exportDocument(const QUrl &_url, KisPropertiesConfigurationSP
// save...
ret = saveAs(_url, exportConfiguration);
//
// This is sooooo hacky :(
// Hopefully we will restore enough state.
......@@ -643,7 +642,6 @@ bool KisDocument::exportDocument(const QUrl &_url, KisPropertiesConfigurationSP
d->mimeType = oldMimeType;
}
d->isExporting = false;
return ret;
......@@ -2125,9 +2123,6 @@ bool KisDocument::saveAs(const QUrl &kurl, KisPropertiesConfigurationSP exportCo
return result;
}
bool KisDocument::save(KisPropertiesConfigurationSP exportConfiguration)
{
d->m_saveOk = false;
......
......@@ -117,22 +117,30 @@ QString KisFilterChain::inputFile()
m_inputQueried = File;
if (m_state & Beginning) {
if (static_cast<KisImportExportManager::Direction>(filterManagerDirection()) ==
KisImportExportManager::Import)
if (static_cast<KisImportExportManager::Direction>(filterManagerDirection()) == KisImportExportManager::Import) {
m_inputFile = filterManagerImportFile();
else
}
else {
inputFileHelper(filterManagerKisDocument(), filterManagerImportFile());
} else
if (m_inputFile.isEmpty())
}
}
else {
if (m_inputFile.isEmpty()) {
inputFileHelper(m_inputDocument, QString());
}
}
return m_inputFile;
}
QString KisFilterChain::outputFile()
{
if (m_outputQueried == File)
qDebug() << m_outputQueried << m_outputFile;
if (m_outputQueried == File) {
return m_outputFile;
}
else if (m_outputQueried != Nil) {
warnFile << "You already asked for some different destination.";
return QString();
......@@ -140,35 +148,38 @@ QString KisFilterChain::outputFile()
m_outputQueried = File;
if (m_state & End) {
if (static_cast<KisImportExportManager::Direction>(filterManagerDirection()) ==
KisImportExportManager::Import)
if (static_cast<KisImportExportManager::Direction>(filterManagerDirection()) == KisImportExportManager::Import) {
outputFileHelper(false); // This (last) one gets deleted by the caller
else
}
else {
m_outputFile = filterManagerExportFile();
} else
}
}
else {
outputFileHelper(true);
}
return m_outputFile;
}
void KisFilterChain::setOutputFile(const QString &outputFile)
{
m_outputQueried = File;
m_outputFile = outputFile;
}
KisDocument* KisFilterChain::inputDocument()
KisDocument *KisFilterChain::inputDocument()
{
if (m_inputQueried == Document)
if (m_inputQueried == Document) {
return m_inputDocument;
else if (m_inputQueried != Nil) {
}
else if (m_inputQueried) {
warnFile << "You already asked for some different source.";
return 0;
}
if ((m_state & Beginning) &&
static_cast<KisImportExportManager::Direction>(filterManagerDirection()) == KisImportExportManager::Export &&
filterManagerKisDocument()) {
m_inputDocument = filterManagerKisDocument();
}
else if (!m_inputDocument) {
m_inputDocument = KisPart::instance()->createDocument();
}
m_inputDocument = filterManagerKisDocument();
m_inputQueried = Document;
return m_inputDocument;
......
......@@ -87,11 +87,13 @@ public:
* is for the filters in our chain.
*/
QString inputFile();
/**
* Get the current file to write to. This part of the API
* is for the filters in our chain.
*/
QString outputFile();
void setOutputFile(const QString &outputFile);
/**
* This method allows your filter to work directly on the
......@@ -99,7 +101,7 @@ public:
* This part of the API is for the filters in our chain.
* @return The document containing the data. May return 0 on error.
*/
KisDocument* inputDocument();
KisDocument *inputDocument();
/**
* This method allows your filter to work directly on the
......@@ -107,7 +109,7 @@ public:
* This part of the API is for the filters in our chain.
* @return The document you have to write to. May return 0 on error.
*/
KisDocument* outputDocument();
KisDocument *outputDocument();
KisPropertiesConfigurationSP filterManagerExportConfiguration() const;
......
......@@ -69,13 +69,29 @@ public:
* Feel free to add some more error conditions @em before the last item
* if it's needed.
*/
enum ConversionStatus { OK, StupidError, UsageError, CreationError, FileNotFound,
StorageCreationError, BadMimeType, BadConversionGraph,
EmbeddedDocError, WrongFormat, NotImplemented,
ParsingError, InternalError, UnexpectedEOF,
UnexpectedOpcode, UserCancelled, OutOfMemory,
PasswordProtected, InvalidFormat, FilterEntryNull,
NoDocumentCreated, DownloadFailed, FilterCreationError,
enum ConversionStatus { OK,
StupidError,
UsageError,
CreationError,
FileNotFound,
StorageCreationError,
BadMimeType,
BadConversionGraph,
EmbeddedDocError,
WrongFormat,
NotImplemented,
ParsingError,
InternalError,
UnexpectedEOF,
UnexpectedOpcode,
UserCancelled,
OutOfMemory,
PasswordProtected,
InvalidFormat,
FilterEntryNull,
NoDocumentCreated,
DownloadFailed,
FilterCreationError,
ProgressCancelled,
JustInCaseSomeBrokenCompilerUsesLessThanAByte = 255
};
......
......@@ -229,9 +229,9 @@ void KisAnimationExporter::frameReadyToSave()
(m_d->lastFrame - m_d->firstFrame));
}
if (result == KisImportExportFilter::OK &&
time < m_d->lastFrame) {
qDebug() << result << time << m_d->lastFrame;
if (result == KisImportExportFilter::OK && time < m_d->lastFrame) {
m_d->currentFrame = time + 1;
m_d->image->animationInterface()->requestFrameRegeneration(m_d->currentFrame, m_d->image->bounds());
} else {
......@@ -267,8 +267,6 @@ struct KisAnimationExportSaver::Private
tmpDevice = paintLayer->paintDevice();
}
KisDocument *document;
KisImageWSP image;
int firstFrame;
......@@ -316,6 +314,7 @@ KisImportExportFilter::ConversionStatus KisAnimationExportSaver::exportAnimation
KisImportExportFilter::ConversionStatus KisAnimationExportSaver::saveFrameCallback(int time, KisPaintDeviceSP frame, KisPropertiesConfigurationSP exportConfiguration)
{
qDebug() << ">>>>>>>>>> saveFrameCallback" << time << frame << exportConfiguration;
KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK;
QString frameNumber = QString("%1").arg(time + m_d->sequenceNumberingOffset, 4, 10, QChar('0'));
......@@ -324,7 +323,10 @@ KisImportExportFilter::ConversionStatus KisAnimationExportSaver::saveFrameCallba
QRect rc = m_d->image->bounds();
KisPainter::copyAreaOptimized(rc.topLeft(), frame, m_d->tmpDevice, rc);
if (!m_d->tmpDoc->exportDocument(QUrl::fromLocalFile(filename)), exportConfiguration) {
qDebug() << "filename" << filename << exportConfiguration->toXML();
if (!m_d->tmpDoc->exportDocument(QUrl::fromLocalFile(filename), exportConfiguration)) {
qDebug() << "eeek" << m_d->tmpDoc->errorMessage();
status = KisImportExportFilter::InternalError;
}
......
......@@ -74,7 +74,7 @@ KoFileDialog::DialogType KisFileNameRequester::mode() const
}
void KisFileNameRequester::setMimeTypeFilters(const QStringList &filterList,
QString defaultFilter)
QString defaultFilter)
{
m_mime_filter_list = filterList;
m_mime_default_filter = defaultFilter;
......@@ -91,7 +91,6 @@ void KisFileNameRequester::slotSelectFile()
{
dialog.setCaption(i18n("Select a directory to load..."));
}
dialog.setDefaultDir(m_basePath.isEmpty() ? QDesktopServices::storageLocation(QDesktopServices::PicturesLocation) : m_basePath);
Q_ASSERT(!m_mime_filter_list.isEmpty());
......
......@@ -18,6 +18,8 @@
#include "AnimationRenderer.h"
#include <QMessageBox>
#include <klocalizedstring.h>
#include <kpluginfactory.h>
......@@ -28,14 +30,17 @@
#include <kis_action.h>
#include <kis_image_animation_interface.h>
#include <kis_properties_configuration.h>
#include "DlgAnimationRenderer.h"
#include <kis_config.h>
#include <kis_animation_exporter.h>
#include <KisDocument.h>
#include <KisMimeDatabase.h>
#include <kis_time_range.h>
#include <KisImportExportManager.h>
#include <KisFilterChain.h>
#include "DlgAnimationRenderer.h"
K_PLUGIN_FACTORY_WITH_JSON(AnimaterionRendererFactory, "kritaanimationrenderer.json", registerPlugin<AnimaterionRenderer>();)
AnimaterionRenderer::AnimaterionRenderer(QObject *parent, const QVariantList &)
......@@ -67,7 +72,7 @@ void AnimaterionRenderer::slotRenderAnimation()
doc->setFileProgressProxy();
doc->setFileProgressUpdater(i18n("Export frames"));
DlgAnimationRenderer dlgAnimationRenderer(image, m_view->mainWindow());
DlgAnimationRenderer dlgAnimationRenderer(doc, m_view->mainWindow());
dlgAnimationRenderer.setCaption(i18n("Render Animation"));
......@@ -90,7 +95,6 @@ void AnimaterionRenderer::slotRenderAnimation()
if (dlgAnimationRenderer.exec() == QDialog::Accepted) {
KisPropertiesConfigurationSP sequenceConfig = dlgAnimationRenderer.getSequenceConfiguration();
qDebug() << sequenceConfig->toXML();
kisConfig.setExportConfiguration("IMAGESEQUENCE", *sequenceConfig.data());
QString mimetype = sequenceConfig->getString("mimetype");
QString extension = KisMimeDatabase::suffixesForMimeType(mimetype).first();
......@@ -101,19 +105,26 @@ void AnimaterionRenderer::slotRenderAnimation()
KisAnimationExportSaver exporter(doc, baseFileName, sequenceConfig->getInt("first_frame"), sequenceConfig->getInt("last_frame"), sequenceConfig->getInt("sequence_start"));
bool success = exporter.exportAnimation(dlgAnimationRenderer.getFrameExportConfiguration());
Q_ASSERT(success);
QString savedFilesMask = exporter.savedFilesMask();
KisPropertiesConfigurationSP videoConfig = dlgAnimationRenderer.getVideoConfiguration();
if (videoConfig) {
kisConfig.setExportConfiguration("ANIMATION_RENDERER", *videoConfig.data());
KisPropertiesConfigurationSP encoderConfig = dlgAnimationRenderer.getEncoderConfiguration();
kisConfig.setExportConfiguration("FFMPEG_CONFIG", *encoderConfig.data());
if (encoderConfig) {
kisConfig.setExportConfiguration("FFMPEG_CONFIG", *encoderConfig.data());
encoderConfig->setProperty("savedFilesMask", savedFilesMask);
}
QSharedPointer<KisImportExportFilter> encoder = dlgAnimationRenderer.encoderFilter();
KisFilterChainSP chain(new KisFilterChain(doc->importExportManager()));
chain->setOutputFile(videoConfig->getString("filename"));
encoder->setChain(chain);
encoder->convert(KisDocument::nativeFormatMimeType(), encoderConfig->getString("mimetype").toLatin1(), encoderConfig);
KisImportExportFilter::ConversionStatus res = encoder->convert(KisDocument::nativeFormatMimeType(), encoderConfig->getString("mimetype").toLatin1(), encoderConfig);
if (res != KisImportExportFilter::OK) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not render animation:\n%1", doc->errorMessage()));
}
}
}
......
......@@ -42,11 +42,15 @@
#include <KisImportExportFilter.h>
#include <kis_config.h>
#include <kis_file_name_requester.h>
#include <KisDocument.h>
DlgAnimationRenderer::DlgAnimationRenderer(KisImageWSP image, QWidget *parent)
DlgAnimationRenderer::DlgAnimationRenderer(KisDocument *doc, QWidget *parent)
: KoDialog(parent)
, m_image(image)
, m_image(doc->image())
, m_defaultFileName(QFileInfo(doc->url().toLocalFile()).completeBaseName())
{
KisConfig cfg;
setCaption(i18n("Render Animation"));
setButtons(Ok | Cancel);
setDefaultButton(Ok);
......@@ -54,15 +58,16 @@ DlgAnimationRenderer::DlgAnimationRenderer(KisImageWSP image, QWidget *parent)
m_page = new WdgAnimaterionRenderer(this);
m_page->layout()->setMargin(0);
m_page->dirRequester->setMode(KoFileDialog::OpenDirectory);
m_page->dirRequester->setFileName(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
QString lastLocation = cfg.readEntry<QString>("last_sequence_export_location", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
m_page->dirRequester->setFileName(lastLocation);
m_page->intStart->setMinimum(image->animationInterface()->fullClipRange().start());
m_page->intStart->setMaximum(image->animationInterface()->fullClipRange().end());
m_page->intStart->setValue(image->animationInterface()->playbackRange().start());
m_page->intStart->setMinimum(doc->image()->animationInterface()->fullClipRange().start());
m_page->intStart->setMaximum(doc->image()->animationInterface()->fullClipRange().end());
m_page->intStart->setValue(doc->image()->animationInterface()->playbackRange().start());
m_page->intEnd->setMinimum(image->animationInterface()->fullClipRange().start());
m_page->intEnd->setMaximum(image->animationInterface()->fullClipRange().end());
m_page->intEnd->setValue(image->animationInterface()->playbackRange().end());
m_page->intEnd->setMinimum(doc->image()->animationInterface()->fullClipRange().start());
m_page->intEnd->setMaximum(doc->image()->animationInterface()->fullClipRange().end());
m_page->intEnd->setValue(doc->image()->animationInterface()->playbackRange().end());
m_sequenceConfigLayout = new QHBoxLayout(m_page->grpExportOptions);
m_encoderConfigLayout = new QHBoxLayout(m_page->grpRenderOptions);
......@@ -120,24 +125,30 @@ DlgAnimationRenderer::DlgAnimationRenderer(KisImageWSP image, QWidget *parent)
}
}
m_page->videoFilename->setMode(KoFileDialog::SaveFile);
m_page->dirRequester->setStartDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
m_page->videoFilename->setStartDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
qDeleteAll(list);
connect(m_page->cmbRenderType, SIGNAL(activated(int)), this, SLOT(selectRenderType(int)));
selectRenderType(m_page->cmbRenderType->currentIndex());
connect(m_page->grpRender, SIGNAL(toggled(bool)), this, SLOT(toggleSequenceType(bool)));
connect(m_page->cmbMimetype, SIGNAL(activated(int)), this, SLOT(sequenceMimeTypeSelected(int)));
sequenceMimeTypeSelected(m_page->cmbMimetype->currentIndex());
KisConfig cfg;
QString ffmpeg = cfg.readEntry<QString>("ffmpeg_location", "");
QString ffmpeg = cfg.customFFMpegPath();
m_page->ffmpegLocation->setFileName(ffmpeg);
m_page->ffmpegLocation->setMode(KoFileDialog::OpenFile);
connect(m_page->ffmpegLocation, SIGNAL(fileSelected(QString)), this, SLOT(ffmpegLocationChanged(QString)));
m_page->grpRender->setChecked(cfg.readEntry<bool>("render_animation", false));
}
DlgAnimationRenderer::~DlgAnimationRenderer()
{
KisConfig cfg;
cfg.writeEntry<bool>("render_animation", m_page->grpRender->isChecked());
cfg.writeEntry<QString>("last_sequence_export_location", m_page->dirRequester->fileName());
cfg.setCustomFFMpegPath(m_page->ffmpegLocation->fileName());
m_encoderConfigWidget->setParent(0);
m_encoderConfigWidget->deleteLater();
m_frameExportConfigWidget->setParent(0);
......@@ -179,6 +190,13 @@ void DlgAnimationRenderer::setSequenceConfiguration(KisPropertiesConfigurationSP
KisPropertiesConfigurationSP DlgAnimationRenderer::getFrameExportConfiguration() const
{
if (m_frameExportConfigWidget) {
KisPropertiesConfigurationSP cfg = m_frameExportConfigWidget->configuration();
cfg->setProperty("basename", m_page->txtBasename->text());
cfg->setProperty("directory", m_page->dirRequester->fileName());
cfg->setProperty("first_frame", m_page->intStart->value());
cfg->setProperty("last_frame", m_page->intEnd->value());
cfg->setProperty("sequence_start", m_page->sequenceStart->value());
return m_frameExportConfigWidget->configuration();
}
return 0;
......@@ -200,7 +218,7 @@ KisPropertiesConfigurationSP DlgAnimationRenderer::getVideoConfiguration() const
return cfg;
}
void DlgAnimationRenderer::setVideoConfiguration(KisPropertiesConfigurationSP cfg)
void DlgAnimationRenderer::setVideoConfiguration(KisPropertiesConfigurationSP /*cfg*/)
{
}
......@@ -215,7 +233,7 @@ KisPropertiesConfigurationSP DlgAnimationRenderer::getEncoderConfiguration() con
return cfg;
}
void DlgAnimationRenderer::setEncoderConfiguration(KisPropertiesConfigurationSP cfg)
void DlgAnimationRenderer::setEncoderConfiguration(KisPropertiesConfigurationSP /*cfg*/)
{
}
......@@ -242,7 +260,12 @@ void DlgAnimationRenderer::selectRenderType(int index)
QSharedPointer<KisImportExportFilter> filter = m_renderFilters[index];
QString mimetype = m_page->cmbRenderType->itemData(index).toString();
if (!m_page->videoFilename->fileName().isEmpty() && QFileInfo(m_page->videoFilename->fileName()).completeBaseName() != m_defaultFileName) {
m_defaultFileName = QFileInfo(m_page->videoFilename->fileName()).completeBaseName();
}
m_page->videoFilename->setMimeTypeFilters(QStringList() << mimetype, mimetype);
m_page->videoFilename->setFileName(m_defaultFileName + "." + KisMimeDatabase::suffixesForMimeType(mimetype).first());
if (filter) {
m_encoderConfigWidget = filter->createConfigurationWidget(m_page->grpExportOptions, KisDocument::nativeFormatMimeType(), mimetype.toLatin1());
......@@ -298,7 +321,7 @@ void DlgAnimationRenderer::sequenceMimeTypeSelected(int index)
void DlgAnimationRenderer::ffmpegLocationChanged(const QString &s)
{
KisConfig cfg;
cfg.writeEntry<QString>("ffmpeg_location", s);
cfg.setCustomFFMpegPath(s);
}
void DlgAnimationRenderer::slotButtonClicked(int button)
......
......@@ -26,6 +26,7 @@
#include <QSharedPointer>
#include <kis_types.h>
class KisDocument;
class KisImportExportFilter;
class KisConfigWidget;
class QHBoxLayout;
......@@ -49,7 +50,7 @@ class DlgAnimationRenderer: public KoDialog
public:
DlgAnimationRenderer(KisImageWSP image, QWidget *parent = 0);
DlgAnimationRenderer(KisDocument *doc, QWidget *parent = 0);
~DlgAnimationRenderer();
KisPropertiesConfigurationSP getSequenceConfiguration() const;
......@@ -87,6 +88,7 @@ private:
KisConfigWidget *m_encoderConfigWidget {0};
QHBoxLayout *m_sequenceConfigLayout;
KisConfigWidget *m_frameExportConfigWidget {0};
QString m_defaultFileName;
};
#endif // DLG_ANIMATIONRENDERERIMAGE
......@@ -209,7 +209,7 @@
<string>FF&amp;Mpeg: </string>
</property>
<property name="buddy">
<cstring>txtLayerName</cstring>
<cstring>videoFileName</cstring>
</property>
</widget>
</item>
......
......@@ -71,7 +71,7 @@ bool hasVisibleWidgets()
KisImportExportFilter::ConversionStatus KisPNGExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration)
{
dbgFile << "Png export! From:" << from << ", To:" << to;
dbgFile << "Png export! From:" << from << ", To:" << to << "";
KisDocument *input = inputDocument();
QString filename = outputFile();
......
......@@ -65,59 +65,20 @@ KisImportExportFilter::ConversionStatus KisVideoExport::convert(const QByteArray
KisDocument *input = inputDocument();
QString filename = outputFile();
qDebug() << "inputDocument" << input << "output filename" << filename;
if (!input)
return KisImportExportFilter::NoDocumentCreated;
if (filename.isEmpty()) return KisImportExportFilter::FileNotFound;
bool askForOptions = false;
const QFileInfo fileInfo(filename);
const QString suffix = fileInfo.suffix().toLower();
VideoExportOptionsDialog::CodecIndex codecIndex = VideoExportOptionsDialog::CODEC_H264;
if (suffix == "mkv" || suffix == "mp4") {
codecIndex = VideoExportOptionsDialog::CODEC_H264;
askForOptions = true;
} else if (suffix == "ogv") {
codecIndex = VideoExportOptionsDialog::CODEC_THEORA;
askForOptions = true;
}
QStringList additionalOptionsList;
askForOptions &=
!qApp->applicationName().toLower().contains("test") &
!getBatchMode();
if (askForOptions) {
KisCursorOverrideHijacker badGuy;
KoDialog kdb(0);
kdb.setCaption(i18n("Video Export Options"));
kdb.setModal(true);
kdb.setButtons(KoDialog::Ok | KoDialog::Cancel);
VideoSaver videoSaver(input, getBatchMode());
VideoExportOptionsDialog dlg;
dlg.setCodec(codecIndex);
kdb.setMainWidget(&dlg);
if (kdb.exec() == QDialog::Accepted) {
additionalOptionsList = dlg.customUserOptions();
} else {
return KisImportExportFilter::UserCancelled;
}
}
VideoSaver kpc(input, getBatchMode());
if (!kpc.hasFFMpeg()) {
if (!videoSaver.hasFFMpeg()) {
const QString warningMessage =
i18n("Couldn not find \'ffmpeg\' binary. Saving to video formats is impossible.");
if (askForOptions) {
if (!getBatchMode()) {
QMessageBox::critical(KisPart::instance()->currentMainwindow(),
i18n("Video Export Error"),
warningMessage);
......@@ -128,11 +89,12 @@ KisImportExportFilter::ConversionStatus KisVideoExport::convert(const QByteArray
return KisImportExportFilter::UsageError;
}
KisImageBuilder_Result res = kpc.encode(filename, additionalOptionsList);
KisImageBuilder_Result res = videoSaver.encode(filename, configuration);
if (res == KisImageBuilder_RESULT_OK) {
return KisImportExportFilter::OK;
} else if (res == KisImageBuilder_RESULT_CANCEL) {