1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-09-18 16:32:33 +02:00

Rewrote create to be more modular

This commit is contained in:
kelteseth 2018-10-14 16:16:40 +02:00
parent 3c38d0593b
commit ba4e9d2607
6 changed files with 385 additions and 354 deletions

View File

@ -122,5 +122,6 @@
<file>qml/Create/Wizards/CreateWallpaper/Page_0.qml</file> <file>qml/Create/Wizards/CreateWallpaper/Page_0.qml</file>
<file>qml/Create/Wizards/CreateWallpaper/Page_1.qml</file> <file>qml/Create/Wizards/CreateWallpaper/Page_1.qml</file>
<file>qml/Create/Wizards/CreateWallpaper/Page_2.qml</file> <file>qml/Create/Wizards/CreateWallpaper/Page_2.qml</file>
<file>qml/Create/Wizards/CreateWallpaper/NextButton.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -4,11 +4,11 @@ import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2 import QtQuick.Controls.Material 2.2
import Qt.labs.platform 1.0 import Qt.labs.platform 1.0
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import net.aimber.create 1.0
Item { Item {
id: createNew id: createNew
anchors.fill: parent anchors.fill: parent
Component.onCompleted: state = "in"
state: "out" state: "out"
property string filePath property string filePath
@ -18,6 +18,20 @@ Item {
anchors.fill: parent anchors.fill: parent
} }
Timer {
interval: 1000
triggeredOnStart: false
running: true
repeat: false
onTriggered: {
screenPlayCreate.createWallpaperStart(filePath)
}
}
Component.onCompleted: {
state = "in"
}
RectangularGlow { RectangularGlow {
id: effect id: effect
anchors { anchors {
@ -70,6 +84,7 @@ Item {
id: view id: view
clip: true clip: true
currentIndex: 0 currentIndex: 0
interactive: false
onCurrentIndexChanged: { onCurrentIndexChanged: {
} }
@ -84,10 +99,24 @@ Item {
topMargin: 0 topMargin: 0
} }
interactive: false
Page_0 { Page_0 {
id: firstPage id: page_0
onCanNextChanged: {
if (canNext) {
btnNext.state = "enabledPage0"
} else {
if (gifCreated) {
btnNext.state = "diabledPage0NoTitle"
} else {
btnNext.state = "diabledPage0"
}
}
}
onGifCreatedChanged: {
if (gifCreated) {
btnNext.state = "diabledPage0NoTitle"
}
}
} }
Page_1 { Page_1 {
id: secondPage id: secondPage
@ -148,7 +177,7 @@ Item {
} }
Row { Row {
width: 160 width: childrenRect.width
height: 50 height: 50
spacing: 20 spacing: 20
anchors { anchors {
@ -171,16 +200,14 @@ Item {
view.setCurrentIndex(view.currentIndex - 1) view.setCurrentIndex(view.currentIndex - 1)
} }
} }
Button { NextButton {
text: qsTr("Next") id: btnNext
Material.background: Material.Orange state: "diabledPage0"
Material.foreground: "white"
icon.source: "qrc:/assets/icons/icon_arrow_right.svg"
icon.color: "white"
icon.width: 16
icon.height: 16
onClicked: { onClicked: {
if (!page_0.canNext && !page_0.gifCreated )
return
if (view.currentIndex < view.count - 1) if (view.currentIndex < view.count - 1)
view.setCurrentIndex(view.currentIndex + 1) view.setCurrentIndex(view.currentIndex + 1)
} }

View File

@ -0,0 +1,62 @@
import QtQuick 2.9
import QtGraphicalEffects 1.0
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2
import Qt.labs.platform 1.0
import QtQuick.Layouts 1.3
Button {
id: root
text: qsTr("Next")
Material.background: Material.Orange
Material.foreground: "white"
icon.source: "qrc:/assets/icons/icon_arrow_right.svg"
icon.color: "white"
icon.width: 16
icon.height: 16
states: [
State {
name: "enabled"
PropertyChanges {
target: root
}
},
State {
name: "diabledPage0"
PropertyChanges {
target: root
text: qsTr("Creating preview")
Material.background: Material.Grey
}
},
State {
name: "diabledPage0NoTitle"
PropertyChanges {
target: root
text: qsTr("No title set!")
Material.background: Material.Grey
}
},
State {
name: "enabledPage0"
PropertyChanges {
target: root
text: qsTr("Next")
Material.background: Material.Orange
}
}
]
transitions: [
Transition {
from: "*"
to: "*"
NumberAnimation {
property: "width"
easing.type: Easing.InOutQuad
duration: 2000
}
}
]
}

View File

@ -1,12 +1,15 @@
import QtQuick 2.9 import QtQuick 2.9
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import net.aimber.create 1.0
Rectangle { Rectangle {
id: root id: root
property bool allNecessaryConfigsSet: false
Rectangle { property bool canNext: false
property bool gifCreated: false
Item {
id: rectangle1 id: rectangle1
width: parent.width * .5 width: parent.width * .5
anchors { anchors {
@ -33,21 +36,70 @@ Rectangle {
cornerRadius: 15 cornerRadius: 15
} }
Rectangle { Rectangle {
id: imgWrapper id: imgWrapper
width: parent.width * .9 width: parent.width * .9
anchors { anchors {
top:parent.top top: parent.top
margins: parent.width * .05 margins: parent.width * .05
right:parent.right right: parent.right
left:parent.left left: parent.left
} }
height: 200 height: 200
color: "gray" color: "gray"
Image {
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
running: true
}
Text {
id: text1
color: "white"
text: qsTr("Generating preview...")
font.pixelSize: 14
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 30
}
}
Connections {
target: screenPlayCreate
onCreateWallpaperStateChanged: {
if (state === Create.State.ConvertingPreviewGifFinished) {
imgPreview.source = "file:///"
+ screenPlayCreate.workingDir + "/preview.gif"
imgPreview.visible = true
gifCreated = true
}
}
}
AnimatedImage {
id: imgPreview id: imgPreview
asynchronous: true
playing: true
visible: false
anchors.fill: parent
}
}
ScrollView {
anchors {
top: imgWrapper.bottom
right: parent.right
bottom: parent.bottom
left: parent.left
margins: 20
}
Text {
id: txtOut
width: parent.width
} }
} }
} }
@ -72,7 +124,13 @@ Rectangle {
placeholderText: qsTr("Name") placeholderText: qsTr("Name")
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
onTextChanged: {
if (textField.text.length >= 3 && gifCreated) {
canNext = true
} else {
canNext = false
}
}
} }
TextField { TextField {
@ -98,9 +156,3 @@ Rectangle {
} }
} }
} }
/*##^## Designer {
D{i:0;autoSize:true;height:768;width:1366}D{i:4;anchors_height:200;anchors_x:200;anchors_y:0}
D{i:7;anchors_height:400;anchors_width:200}D{i:3;anchors_height:200;anchors_width:683}
}
##^##*/

View File

@ -6,17 +6,11 @@ Create::Create(Settings* st, QMLUtilities* util, QObject* parent)
m_settings = st; m_settings = st;
m_utils = util; m_utils = util;
qRegisterMetaType<Create::State>();
qmlRegisterType<Create>("net.aimber.create", 1, 0, "Create"); qmlRegisterType<Create>("net.aimber.create", 1, 0, "Create");
} }
Create::Create()
{
}
Create::~Create()
{
}
void Create::copyProject(QString relativeProjectPath, QString toPath) void Create::copyProject(QString relativeProjectPath, QString toPath)
{ {
if (toPath.contains("file:///")) { if (toPath.contains("file:///")) {
@ -53,321 +47,222 @@ bool Create::copyRecursively(const QString& srcFilePath, const QString& tgtFileP
return true; return true;
} }
void Create::importVideo(QString title, QUrl videoPath, QUrl previewPath, int videoDuration) void Create::createWallpaperStart(QString videoPath)
{ {
if (m_importState != Create::State::Idle) { videoPath.remove("file:///");
return;
}
QtConcurrent::run([=]() { QtConcurrent::run([=]() {
emit localWorkshopCreationStatusChanged(State::Started);
QString fromVideoPath = QString(videoPath.toString()).replace("file:///", ""); QDir dir;
QString fromImagePath = QString(previewPath.toString()).replace("file:///", ""); dir.cd(m_settings->localStoragePath().toString());
QString toPath = m_settings->localStoragePath().toString() + "/" + title;
QString toPathWithVideoFile = toPath + "/" + videoPath.fileName();
QString toPathWithImageFile = toPath + "/" + previewPath.fileName();
if (QDir(toPath).exists()) { CreateWallpaperData createWallpaperData;
if (!QDir(toPath).isEmpty()) { createWallpaperData.videoPath = videoPath;
emit localWorkshopCreationStatusChanged(State::ErrorFolder);
return;
} else {
//if(!QDir(toPath + ))
}
// Create a temp dir so we can later alter it to the workshop id
createWallpaperData.exportPath = QString(dir.path() + "/" + "_tmp_" + QTime::currentTime().toString()).replace(":", "");
if (dir.mkdir(createWallpaperData.exportPath)) {
// TODO
} else { } else {
//TODO: Display Error
if (!QDir().mkdir(toPath)) {
emit localWorkshopCreationStatusChanged(State::ErrorFolderCreation);
return;
}
}
//Copy Video File
if (QFile::copy(fromVideoPath, toPathWithVideoFile)) {
emit localWorkshopCreationStatusChanged(State::CopyVideoFinished);
} else {
emit localWorkshopCreationStatusChanged(State::ErrorCopyVideo);
}
//Copy Image File
if (QFile::copy(fromImagePath, toPathWithImageFile)) {
emit localWorkshopCreationStatusChanged(State::CopyImageFinished);
} else {
emit localWorkshopCreationStatusChanged(State::ErrorCopyImage);
}
//Copy Project File
QFile configFile(toPath + "/" + "project.json");
if (!configFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
emit localWorkshopCreationStatusChanged(State::ErrorCopyConfig);
return; return;
} }
QTextStream out(&configFile); // If we return early/false this means the creation
QJsonObject configObj; // process did not work
// Todo: cleanup!
configObj.insert("file", videoPath.fileName()); if (!this->createWallpaperInfo(createWallpaperData))
configObj.insert("preview", previewPath.fileName()); return;
//TODO
configObj.insert("description", "");
configObj.insert("title", title);
QJsonDocument configJsonDocument(configObj); if (!this->createWallpaperVideoPreview(createWallpaperData))
out << configJsonDocument.toJson(); return;
configFile.close();
emit localWorkshopCreationStatusChanged(State::Finished); if (!this->createWallpaperVideo(createWallpaperData))
return;
if (!this->createWallpaperProjectFile(createWallpaperData))
return;
}); });
} }
void Create::importVideo(QString title, QUrl videoPath, int timeStamp, int videoDuration, int videoFrameRate) bool Create::createWallpaperInfo(CreateWallpaperData& createWallpaperData)
{ {
// Get video info
QStringList args;
args.append("-print_format");
args.append("json");
args.append("-show_format");
args.append("-show_streams");
args.append(createWallpaperData.videoPath);
QScopedPointer<QProcess> pro(new QProcess());
pro.data()->setArguments(args);
if (m_importState != Create::State::Idle) {
return;
}
qDebug() << title << videoPath << timeStamp;
QString tmpPath = videoPath.toString();
tmpPath.remove("file:///");
QString tmpTimeStamp = QString::number(timeStamp);
QString ffmpegTimeStamp;
QString sHours;
QString sMinutes;
QString sSeconds;
int intTmpTimeStamp;
if (tmpTimeStamp.length() > 3) {
tmpTimeStamp.remove(tmpTimeStamp.length() - 3, 3);
intTmpTimeStamp = tmpTimeStamp.toInt();
const int cseconds_in_day = 86400;
const int cseconds_in_hour = 3600;
const int cseconds_in_minute = 60;
const int cseconds = 1;
int32 hours = (intTmpTimeStamp % cseconds_in_day) / cseconds_in_hour;
int32 minutes = ((intTmpTimeStamp % cseconds_in_day) % cseconds_in_hour) / cseconds_in_minute;
int32 seconds = (((intTmpTimeStamp % cseconds_in_day) % cseconds_in_hour) % cseconds_in_minute) / cseconds;
if (hours < 10) {
sHours = "0" + QString::number(hours);
} else {
sHours = QString::number(hours);
}
if (minutes < 10) {
sMinutes = "0" + QString::number(minutes);
} else {
sMinutes = QString::number(minutes);
}
if (seconds < 10) {
sSeconds = "0" + QString::number(seconds);
} else {
sSeconds = QString::number(seconds);
}
} else {
ffmpegTimeStamp = "00:00:00";
}
QString tmpVideoDuration = QString::number(videoDuration);
if (tmpVideoDuration.length() > 3)
tmpVideoDuration.remove(tmpVideoDuration.length() - 3, 3);
int videoDurationInSeconds = tmpVideoDuration.toInt();
ffmpegTimeStamp = sHours + ":" + sMinutes + ":" + sSeconds;
if (intTmpTimeStamp == 0 || videoFrameRate == 0)
qWarning() << "Cannot be zero!";
QtConcurrent::run([=]() {
QStringList args;
// Seek first because otherwise it will load
// the complete video first and this will make
// the conversion 50x slower!
args.append("-y");
args.append("-ss");
args.append(ffmpegTimeStamp);
args.append("-i");
args.append(tmpPath);
args.append("-speed");
args.append("ultrafast");
args.append("-vframes");
args.append("1");
args.append("preview.png");
QScopedPointer<QProcess> pro(new QProcess());
pro.data()->setArguments(args);
qDebug() << "Start converting video to thumbnail";
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
pro.data()->setProgram(QApplication::applicationDirPath() + "/ffmpeg.exe"); pro.data()->setProgram(QApplication::applicationDirPath() + "/ffprobe.exe");
#endif #endif
emit localWorkshopCreationStatusChanged(State::ConvertingPreviewImage);
pro.data()->start(); pro.data()->start();
pro.data()->waitForFinished(-1); pro.data()->waitForFinished(-1);
qDebug() << "Done converting video to thumbnail" << pro.data()->readAllStandardOutput(); QJsonObject obj;
emit localWorkshopCreationStatusChanged(State::ConvertingPreviewImageFinished); QJsonParseError err;
pro.data()->close(); QJsonDocument doc = QJsonDocument::fromJson(pro.data()->readAll(), &err);
}); if (err.error == QJsonParseError::NoError) {
obj = doc.object();
}
pro.data()->close();
// Get video length
QJsonObject objFormat = obj.value("format").toObject();
bool okParseDuration = false;
auto tmpLength = objFormat.value("duration").toVariant().toFloat(&okParseDuration);
if (!okParseDuration) {
qDebug() << "Error parsing video length";
return false;
}
int length = 0;
length = static_cast<int>(tmpLength);
createWallpaperData.length = length;
// Get framerate
QJsonArray arrSteams = obj.value("streams").toArray();
if (arrSteams.size() < 1) {
qDebug() << "Error container does not have any video streams";
return false;
}
QJsonObject tmpObjStreams = arrSteams.at(0).toObject();
// The paramter gets us the exact framerate
// "avg_frame_rate":"47850000/797509"
// so we need no calc the value by dividing the two numbers
QString avgFrameRate = tmpObjStreams.value("avg_frame_rate").toVariant().toString();
QStringList avgFrameRateList = avgFrameRate.split('/', QString::SkipEmptyParts);
if (avgFrameRateList.length() != 2) {
qDebug() << "Error could not parse streams with length: " << avgFrameRateList.length();
return false;
}
int framerate = 0;
float value1 = static_cast<float>(avgFrameRateList.at(0).toInt());
float value2 = static_cast<float>(avgFrameRateList.at(1).toInt());
framerate = qCeil(value1 / value2);
createWallpaperData.framerate = framerate;
return true;
} }
void Create::createVideoPreview(QString path, int frames, int frameRate) bool Create::createWallpaperVideoPreview(CreateWallpaperData& createWallpaperData)
{ {
if (m_importState != Create::State::Idle) { qDebug() << createWallpaperData.length << createWallpaperData.framerate;
return; QStringList args;
} args.append("-y");
qDebug() << frames << frameRate; args.append("-stats");
QtConcurrent::run([=]() { args.append("-i");
QStringList args; args.append(createWallpaperData.videoPath);
args.append("-y"); args.append("-speed");
args.append("-stats"); args.append("ultrafast");
args.append("-i"); args.append("-vf");
args.append(path); // We allways want to have a 5 second clip via 24fps -> 120 frames
args.append("-speed"); // Divided by the number of frames we can skip (timeInSeconds * Framrate)
args.append("ultrafast"); // scale & crop parameter: https://unix.stackexchange.com/a/284731
args.append("-vf"); args.append("select='not(mod(n," + QString::number((createWallpaperData.length / 5)) + "))',setpts=N/FRAME_RATE/TB,crop=in_h*16/9:in_h,scale=-2:400");
// We allways want to have a 5 second clip via 24fps -> 120 frames // Disable audio
// Divided by the number of frames we can skip (timeInSeconds * Framrate) args.append("-an");
// scale & crop parameter: https://unix.stackexchange.com/a/284731 args.append(createWallpaperData.exportPath + "/preview.mp4");
args.append("select='not(mod(n," + QString::number((frames / 5)) + "))',setpts=N/FRAME_RATE/TB,crop=in_h*16/9:in_h,scale=-2:400"); QScopedPointer<QProcess> proConvertPreviewMP4(new QProcess());
// Disable audio
args.append("-an");
args.append(m_workingDir + "/preview.mp4");
QScopedPointer<QProcess> proConvertPreviewMP4(new QProcess());
proConvertPreviewMP4.data()->setArguments(args); proConvertPreviewMP4.data()->setArguments(args);
qDebug() << "Start converting video to preview mp4"; qDebug() << "Start converting video to preview mp4";
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
proConvertPreviewMP4.data()->setProgram(QApplication::applicationDirPath() + "/ffmpeg.exe"); proConvertPreviewMP4.data()->setProgram(QApplication::applicationDirPath() + "/ffmpeg.exe");
#endif #endif
proConvertPreviewMP4.data()->start(); emit createWallpaperStateChanged(Create::State::ConvertingPreviewVideo);
proConvertPreviewMP4.data()->waitForFinished(-1);
qDebug() << proConvertPreviewMP4.data()->program() << proConvertPreviewMP4.data()->arguments();
qDebug() << "Done converting video to preview" << proConvertPreviewMP4.data()->readAll() << "\n"
<< proConvertPreviewMP4.data()->readAllStandardError();
proConvertPreviewMP4.data()->close();
/* proConvertPreviewMP4.data()->start();
QScopedPointer<QTimer> processOutputTimer(new QTimer());
connect(processOutputTimer.data(), &QTimer::timeout, [&]() {
qDebug() << "### " << proConvertPreviewMP4.data()->readAll();
this->processOutput(proConvertPreviewMP4.data()->readAll());
});
processOutputTimer.data()->start(100);
proConvertPreviewMP4.data()->waitForFinished(-1);
// qDebug() << proConvertPreviewMP4.data()->program() << proConvertPreviewMP4.data()->arguments();
// qDebug() << "Done converting video to preview" << proConvertPreviewMP4.data()->readAll() << "\n"
// << proConvertPreviewMP4.data()->readAllStandardError();
proConvertPreviewMP4.data()->close();
processOutputTimer.data()->stop();
emit createWallpaperStateChanged(Create::State::ConvertingPreviewVideoFinished);
/*
* *
* Create gif * Create gif
* *
*/ */
args.clear(); emit createWallpaperStateChanged(Create::State::ConvertingPreviewGif);
args.append("-y"); args.clear();
args.append("-stats"); args.append("-y");
args.append("-i"); args.append("-stats");
args.append(m_workingDir + "/preview.mp4"); args.append("-i");
args.append("-filter_complex"); args.append(createWallpaperData.exportPath + "/preview.mp4");
args.append("[0:v] fps=12,scale=w=480:h=-1,split [a][b];[a] palettegen=stats_mode=single [p];[b][p] paletteuse=new=1"); args.append("-filter_complex");
args.append(m_workingDir + "/preview.gif"); args.append("[0:v] fps=12,scale=w=480:h=-1,split [a][b];[a] palettegen=stats_mode=single [p];[b][p] paletteuse=new=1");
args.append(createWallpaperData.exportPath + "/preview.gif");
QScopedPointer<QProcess> proConvertGif(new QProcess()); QScopedPointer<QProcess> proConvertGif(new QProcess());
proConvertGif.data()->setArguments(args); proConvertGif.data()->setArguments(args);
qDebug() << "Start converting video to preview gif"; qDebug() << "Start converting video to preview gif";
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
proConvertGif.data()->setProgram(QApplication::applicationDirPath() + "/ffmpeg.exe"); proConvertGif.data()->setProgram(QApplication::applicationDirPath() + "/ffmpeg.exe");
#endif #endif
proConvertGif.data()->start(); proConvertGif.data()->start();
proConvertGif.data()->waitForFinished(-1); proConvertGif.data()->waitForFinished(-1);
qDebug() << proConvertGif.data()->program() << proConvertGif.data()->arguments(); // qDebug() << proConvertGif.data()->program() << proConvertGif.data()->arguments();
qDebug() << "Done converting video to preview" << proConvertGif.data()->readAll() << "\n" // qDebug() << "Done converting video to preview" << proConvertGif.data()->readAll() << "\n"
<< proConvertGif.data()->readAllStandardError(); // << proConvertGif.data()->readAllStandardError();
proConvertGif.data()->close(); proConvertGif.data()->close();
}); emit createWallpaperStateChanged(Create::State::ConvertingPreviewGifFinished);
return true;
} }
void Create::createWallpaper(QString videoPath) bool Create::createWallpaperVideo(CreateWallpaperData& createWallpaperData)
{ {
return true;
if (m_importState != Create::State::Idle) { }
return;
} bool Create::createWallpaperProjectFile(CreateWallpaperData& createWallpaperData)
videoPath.remove("file:///"); {
//Copy Project File
QDir dir; QFile configFile(createWallpaperData.exportPath + "/project.json");
dir.cd(m_settings->localStoragePath().toString());
m_workingDir = QString("_tmp_" + QTime::currentTime().toString()).replace(":", ""); if (!configFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
if (dir.mkdir(m_workingDir)) { return false;
}
} else {
return; // QTextStream out(&configFile);
} // QJsonObject configObj;
m_workingDir = dir.path() + "/" + m_workingDir; // configObj.insert("file", videoPath.fileName());
// configObj.insert("preview", previewPath.fileName());
QtConcurrent::run([=]() { // //TODO
// Get video info // configObj.insert("description", "");
QStringList args; // configObj.insert("title", title);
args.append("-print_format");
args.append("json"); // QJsonDocument configJsonDocument(configObj);
args.append("-show_format"); // out << configJsonDocument.toJson();
args.append("-show_streams"); configFile.close();
args.append(videoPath); return true;
QScopedPointer<QProcess> pro(new QProcess());
pro.data()->setArguments(args);
#ifdef Q_OS_WIN
pro.data()->setProgram(QApplication::applicationDirPath() + "/ffprobe.exe");
#endif
pro.data()->start();
pro.data()->waitForFinished(-1);
QJsonObject obj;
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(pro.data()->readAll(), &err);
if (err.error == QJsonParseError::NoError) {
obj = doc.object();
}
pro.data()->close();
// Get video length
QJsonObject objFormat = obj.value("format").toObject();
bool okParseDuration = false;
auto tmpLength = objFormat.value("duration").toVariant().toFloat(&okParseDuration);
if (!okParseDuration) {
qDebug() << "Error parsing video length";
return;
}
int length = 0;
length = static_cast<int>(tmpLength);
// Get framerate
QJsonArray arrSteams = obj.value("streams").toArray();
if (arrSteams.size() < 1) {
qDebug() << "Error container does not have any video streams";
return;
}
QJsonObject tmpObjStreams = arrSteams.at(0).toObject();
// The paramter gets us the exact framerate
// "avg_frame_rate":"47850000/797509"
// so we need no calc the value by dividing the two numbers
QString avgFrameRate = tmpObjStreams.value("avg_frame_rate").toVariant().toString();
QStringList avgFrameRateList = avgFrameRate.split('/', QString::SkipEmptyParts);
if (avgFrameRateList.length() != 2) {
qDebug() << "Error could not parse streams with length: " << avgFrameRateList.length();
return;
}
int framerate = 0;
float value1 = static_cast<float>(avgFrameRateList.at(0).toInt());
float value2 = static_cast<float>(avgFrameRateList.at(1).toInt());
framerate = qCeil(value1 / value2);
this->createVideoPreview(videoPath, length, framerate);
});
} }

View File

@ -3,43 +3,49 @@
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QObject> #include <QJsonArray>
#include <QProcess>
#include <QQmlEngine>
#include <QString>
#include <QStringList>
#include <QTime>
#include <QUrl>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonParseError> #include <QJsonParseError>
#include <QJsonArray> #include <QObject>
#include <QtMath> #include <QProcess>
#include <QQmlEngine>
#include <QScopedPointer>
#include <QString>
#include <QStringList>
#include <QTime> #include <QTime>
#include <QTimer>
#include <QUrl>
#include <QtMath>
#include "qmlutilities.h" #include "qmlutilities.h"
#include "settings.h" #include "settings.h"
struct CreateWallpaperData {
CreateWallpaperData() {}
QString videoPath = "";
QString exportPath = "";
int length = 0;
int framerate = 0;
};
class Create : public QObject { class Create : public QObject {
Q_OBJECT Q_OBJECT
public: public:
explicit Create(Settings* st, QMLUtilities* util,QObject *parent = nullptr); explicit Create(Settings* st, QMLUtilities* util, QObject* parent = nullptr);
Create(); Create() {}
~Create(); ~Create() {}
Q_PROPERTY(State importState READ importState WRITE setImportState NOTIFY importStateChanged)
enum class State { enum class State {
Idle, Idle,
Started, Started,
CopyVideoFinished,
CopyImageFinished,
CopyConfigFinished,
ConvertingPreviewImage, ConvertingPreviewImage,
ConvertingPreviewImageFinished, ConvertingPreviewImageFinished,
ConvertingPreviewVideo, ConvertingPreviewVideo,
ConvertingPreviewVideoFinished, ConvertingPreviewVideoFinished,
ConvertingPreviewGif,
ConvertingPreviewGifFinished,
Finished, Finished,
ErrorFolder, ErrorFolder,
ErrorFolderCreation, ErrorFolderCreation,
@ -52,37 +58,25 @@ public:
Q_ENUM(State) Q_ENUM(State)
State importState() const
{
return m_importState;
}
signals: signals:
void localWorkshopCreationStatusChanged(State status); void createWallpaperStateChanged(Create::State state);
void importStateChanged(State importState); void processOutput(QString text);
public slots: public slots:
void copyProject(QString relativeProjectPath, QString toPath); void copyProject(QString relativeProjectPath, QString toPath);
bool copyRecursively(const QString& srcFilePath, const QString& tgtFilePath); bool copyRecursively(const QString& srcFilePath, const QString& tgtFilePath);
void importVideo(QString title, QUrl videoPath, QUrl previewPath, int videoDuration); // Steps to convert any video to a wallpaper broken down into
void importVideo(QString title, QUrl videoPath, int timeStamp, int videoDuration, int videoFrameRate); // several methods in this order:
void createVideoPreview(QString path, int frames, int length); void createWallpaperStart(QString videoPath);
void createWallpaper(QString videoPath); bool createWallpaperInfo(CreateWallpaperData& createWallpaperData);
void setImportState(State importState) bool createWallpaperVideoPreview(CreateWallpaperData& createWallpaperData);
{ bool createWallpaperVideo(CreateWallpaperData& createWallpaperData);
if (m_importState == importState) bool createWallpaperProjectFile(CreateWallpaperData& createWallpaperData);
return;
m_importState = importState;
emit importStateChanged(m_importState);
}
private: private:
Settings* m_settings; Settings* m_settings;
QMLUtilities* m_utils; QMLUtilities* m_utils;
QString m_workingDir;
State m_importState = State::Idle;
}; };