1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-07 03:22:33 +01:00

Add gif preview

This commit is contained in:
kelteseth 2018-11-13 12:13:37 +01:00
parent d647b28733
commit e4fe59db71
13 changed files with 384 additions and 565 deletions

View File

@ -12,6 +12,7 @@ Item {
state: "out" state: "out"
property string filePath property string filePath
property bool canNext: false
//Blocks some MouseArea from create page //Blocks some MouseArea from create page
MouseArea { MouseArea {
@ -24,9 +25,10 @@ Item {
print(state) print(state)
if (state === Create.State.ConvertingPreviewGifError if (state === Create.State.ConvertingPreviewGifError
|| state === Create.State.ConvertingPreviewVideoError || state === Create.State.ConvertingPreviewVideoError
|| state === Create.State.AnalyseVideoError) || state === Create.State.ConvertingPreviewImageError
{ || state === Create.State.AnalyseVideoError) {
createNew.state = "error" createNew.state = "error"
return
} }
} }
} }
@ -77,8 +79,8 @@ Item {
height: 560 height: 560
Item { Item {
id: wrapperSteps id: wrapperContent
z:10 z: 10
anchors.fill: parent anchors.fill: parent
Text { Text {
@ -98,140 +100,148 @@ Item {
} }
} }
SwipeView { Item {
id: view id: wrapperLeft
clip: true width: parent.width * .5
currentIndex: 0
interactive: false
onCurrentIndexChanged: {
}
anchors { anchors {
left: parent.left
top: txtHeadline.bottom top: txtHeadline.bottom
right: parent.right margins: 30
bottom: indicator.top
left: parent.left
margins: 40
bottomMargin: 20
topMargin: 0
}
Page_0 {
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 {
id: secondPage
}
Page_2 {
id: thirdPage
}
}
PageIndicator {
id: indicator
count: view.count
currentIndex: view.currentIndex
anchors {
bottom: parent.bottom bottom: parent.bottom
bottomMargin: 20
left: parent.left
leftMargin: 40
} }
delegate: Item { Rectangle {
width: txtStep.paintedWidth + 20 id: imgWrapper
height: 30 width: 425
property bool filled height: 247
anchors {
top: parent.top
left: parent.left
}
color: "gray"
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
running: true
}
Text { Text {
id: txtStep id: txtConvert
text: { color: "white"
switch (index) { text: qsTr("Generating preview video...")
case 0:
return "1. Configure"
case 1:
return "2. Convert"
case 2:
return "3. Finish"
default:
return "Undefiend"
}
}
color: view.currentIndex == index ? "orange" : "gray"
renderType: Text.NativeRendering
font.family: "Roboto"
font.pixelSize: 14 font.pixelSize: 14
anchors { anchors {
left: parent.left horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter bottom: parent.bottom
bottomMargin: 30
} }
}
MouseArea { Connections {
anchors.fill: parent target: screenPlayCreate
onClicked: {
if (!page_0.canNext || !page_0.gifCreated) onCreateWallpaperStateChanged: {
return if (state === Create.State.ConvertingPreviewGif) {
txtConvert.text = qsTr(
view.setCurrentIndex(index) "Generating preview gif...")
} }
cursorShape: Qt.PointingHandCursor if (state === Create.State.ConvertingPreviewGifFinished) {
imgPreview.source = "file:///"
+ screenPlayCreate.workingDir + "/preview.gif"
imgPreview.visible = true
}
}
}
AnimatedImage {
id: imgPreview
asynchronous: true
playing: true
visible: false
anchors.fill: parent
}
}
}
Item {
id: wrapperRight
width: parent.width * .5
anchors {
top: txtHeadline.bottom
topMargin: 30
bottom: parent.bottom
right: parent.right
}
Column {
id: column
spacing: 20
anchors.fill: parent
anchors.margins: 30
anchors.topMargin: 0
TextField {
id: textField
placeholderText: qsTr("Name")
anchors.right: parent.right
anchors.left: parent.left
onTextChanged: {
if (textField.text.length >= 3 ) {
canNext = true
} else {
canNext = false
}
}
}
TextField {
id: textField1
placeholderText: qsTr("Description")
anchors.right: parent.right
anchors.left: parent.left
}
TextField {
id: textField2
placeholderText: qsTr("Youtube URL")
anchors.right: parent.right
anchors.left: parent.left
}
TextField {
id: textField3
placeholderText: qsTr("Tags")
anchors.right: parent.right
anchors.left: parent.left
}
}
NextButton {
id: btnFinish
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
margins: 30
}
onClicked: {
if (btnFinish.state === "enabled" && canNext) {
screenPlayCreate.createWallpaperProjectFile(
textField.text, textField1.text)
} }
} }
} }
} Connections {
target: screenPlayCreate
Row { onCreateWallpaperStateChanged: {
width: childrenRect.width if (state === Create.State.ConvertingVideoFinished) {
height: 50 btnFinish.state = "enabled"
spacing: 20 }
anchors {
bottom: parent.bottom
right: parent.right
margins: 20
rightMargin: 40
}
Button {
text: qsTr("Back")
Material.background: Material.Gray
Material.foreground: "white"
icon.source: "qrc:/assets/icons/icon_arrow_left.svg"
icon.color: "white"
icon.width: 16
icon.height: 16
onClicked: {
if (view.currentIndex > 0)
view.setCurrentIndex(view.currentIndex - 1)
}
}
NextButton {
id: btnNext
state: "diabledPage0"
onClicked: {
if (!page_0.canNext || !page_0.gifCreated)
return
if (view.currentIndex < view.count - 1)
view.setCurrentIndex(view.currentIndex + 1)
} }
} }
} }
@ -240,6 +250,7 @@ Item {
Item { Item {
id: wrapperError id: wrapperError
anchors.fill: parent anchors.fill: parent
opacity: 0
Text { Text {
id: txtErrorHeadline id: txtErrorHeadline
@ -250,7 +261,7 @@ Item {
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
} }
height: 40 height: 40
font.family: "Roboto" font.family: "Segoe UI, Roboto"
font.weight: Font.Light font.weight: Font.Light
color: Material.color(Material.Red) color: Material.color(Material.Red)
renderType: Text.NativeRendering renderType: Text.NativeRendering
@ -273,13 +284,13 @@ Item {
Flickable { Flickable {
anchors.fill: parent anchors.fill: parent
clip: true clip: true
contentHeight: txtFFMPEG.paintedHeight contentHeight: txtFFMPEGDebug.paintedHeight
ScrollBar.vertical: ScrollBar { ScrollBar.vertical: ScrollBar {
snapMode: ScrollBar.SnapOnRelease snapMode: ScrollBar.SnapOnRelease
policy: ScrollBar.AlwaysOn policy: ScrollBar.AlwaysOn
} }
Text { Text {
id: txtFFMPEG id: txtFFMPEGDebug
anchors { anchors {
top: parent.top top: parent.top
right: parent.right right: parent.right
@ -289,12 +300,12 @@ Item {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
color: "#626262" color: "#626262"
renderType: Text.NativeRendering renderType: Text.NativeRendering
height: txtFFMPEG.paintedHeight height: txtFFMPEGDebug.paintedHeight
} }
Connections { Connections {
target: screenPlayCreate target: screenPlayCreate
onProcessOutput: { onProcessOutput: {
txtFFMPEG.text = text txtFFMPEGDebug.text = text
} }
} }
} }
@ -316,6 +327,43 @@ Item {
} }
} }
Item {
id: wrapperSuccess
anchors.fill: parent
opacity: 0
Text {
id: txtSuccessHeadline
text: qsTr("An error occurred!")
anchors {
top: parent.top
topMargin: 30
horizontalCenter: parent.horizontalCenter
}
height: 40
font.family: "Segoe UI, Roboto"
font.weight: Font.Light
color: Material.color(Material.Orange)
renderType: Text.NativeRendering
font.pixelSize: 32
}
Button {
id: btnSuccessBack
text: qsTr("Back to create!")
Material.background: Material.Orange
Material.foreground: "white"
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
margins: 10
}
onClicked: {
utility.setNavigation("Create")
}
}
}
MouseArea { MouseArea {
anchors { anchors {
top: parent.top top: parent.top
@ -397,15 +445,35 @@ Item {
opacity: .4 opacity: .4
} }
PropertyChanges { PropertyChanges {
target: wrapperSteps target: wrapperContent
opacity: 0 opacity: 0
z:0 z: 0
}
PropertyChanges {
target: wrapperError
opacity: 1
}
},
State {
name: "success"
PropertyChanges {
target: wrapper
anchors.topMargin: 40
opacity: 1
}
PropertyChanges {
target: effect
opacity: .4
}
PropertyChanges {
target: wrapperContent
opacity: 0
z: 0
} }
PropertyChanges { PropertyChanges {
target: wrapperError target: wrapperError
opacity: 1 opacity: 1
} }
} }
] ]
transitions: [ transitions: [
@ -483,7 +551,7 @@ Item {
to: "error" to: "error"
SequentialAnimation { SequentialAnimation {
PropertyAnimation { PropertyAnimation {
target: wrapperSteps target: wrapperContent
duration: 600 duration: 600
property: "opacity" property: "opacity"
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
@ -498,6 +566,33 @@ Item {
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
} }
},
Transition {
from: "in"
to: "success"
SequentialAnimation {
PropertyAnimation {
target: wrapperContent
duration: 600
property: "opacity"
easing.type: Easing.InOutQuad
}
PauseAnimation {
duration: 50
}
PropertyAnimation {
target: wrapperSuccess
duration: 200
property: "opacity"
easing.type: Easing.InOutQuad
}
}
} }
] ]
} }
/*##^## Designer {
D{i:0;autoSize:true;height:767;width:1366}
}
##^##*/

View File

@ -8,44 +8,25 @@ import QtQuick.Layouts 1.3
Button { Button {
id: root id: root
text: qsTr("Next") text: qsTr("Next")
state: "disabled"
Material.background: Material.Orange Material.background: Material.Orange
Material.foreground: "white" Material.foreground: "white"
icon.source: "qrc:/assets/icons/icon_arrow_right.svg"
icon.color: "white"
icon.width: 16
icon.height: 16
states: [ states: [
State { State {
name: "enabled" name: "enabled"
PropertyChanges { PropertyChanges {
target: root target: root
text: qsTr("Finish")
} }
}, },
State { State {
name: "diabledPage0" name: "disabled"
PropertyChanges { PropertyChanges {
target: root target: root
text: qsTr("Creating preview") text: qsTr("Creating")
Material.background: Material.Grey 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
}
} }
] ]
// TODO find a way to smoothly change with on text change // TODO find a way to smoothly change with on text change

View File

@ -1,163 +0,0 @@
import QtQuick 2.9
import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0
import net.aimber.create 1.0
Rectangle {
id: root
property bool canNext: false
property bool gifCreated: false
Item {
id: rectangle1
width: parent.width * .5
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
}
RectangularGlow {
id: effect
anchors {
top: imgWrapper.top
left: imgWrapper.left
right: imgWrapper.right
topMargin: 3
}
height: imgWrapper.height
width: imgWrapper.width
cached: true
glowRadius: 3
spread: 0.2
color: "black"
opacity: 0.4
cornerRadius: 15
}
Rectangle {
id: imgWrapper
width: parent.width * .9
anchors {
top: parent.top
margins: parent.width * .05
right: parent.right
left: parent.left
}
height: 200
color: "gray"
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
running: true
}
Text {
id: txtConvert
color: "white"
text: qsTr("Generating preview video...")
font.pixelSize: 14
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 30
}
}
Connections {
target: screenPlayCreate
onCreateWallpaperStateChanged: {
if (state === Create.State.ConvertingPreviewGif) {
txtConvert.text = qsTr("Generating preview gif...")
}
if (state === Create.State.ConvertingPreviewGifFinished) {
imgPreview.source = "file:///"
+ screenPlayCreate.workingDir + "/preview.gif"
imgPreview.visible = true
gifCreated = true
}
}
}
AnimatedImage {
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
}
}
}
Rectangle {
id: rectangle
width: parent.width * .5
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
}
Column {
id: column
spacing: 20
anchors.fill: parent
anchors.margins: 30
TextField {
id: textField
placeholderText: qsTr("Name")
anchors.right: parent.right
anchors.left: parent.left
onTextChanged: {
if (textField.text.length >= 3 && gifCreated) {
canNext = true
} else {
canNext = false
}
}
}
TextField {
id: textField1
placeholderText: qsTr("Description")
anchors.right: parent.right
anchors.left: parent.left
}
TextField {
id: textField2
placeholderText: qsTr("Youtube URL")
anchors.right: parent.right
anchors.left: parent.left
}
TextField {
id: textField3
placeholderText: qsTr("Tags")
anchors.right: parent.right
anchors.left: parent.left
}
}
}
}

View File

@ -1,162 +0,0 @@
import QtQuick 2.9
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.3
import net.aimber.create 1.0
Item {
id: root
Connections {
target: screenPlayCreate
onCreateWallpaperStateChanged: {
print(state)
if (state === Create.State.ConvertingVideoFinished) {
root.state = "finished"
}
}
}
Rectangle {
id: wrapperProgressbar
height: parent.height * .5
z:1
anchors {
top: parent.top
right: parent.right
left: parent.left
}
Text {
id: txtProgress
text: Math.floor(screenPlayCreate.progress) + "%"
font.pixelSize: 42
color: "#626262"
renderType: Text.NativeRendering
anchors {
horizontalCenter: parent.horizontalCenter
bottom: progressBar.top
bottomMargin: 30
}
}
ProgressBar {
id: progressBar
value: screenPlayCreate.progress
from: 0
to: 100
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 30
}
}
}
Rectangle {
id: wrapperFFMPEGOutput
color: "#eeeeee"
radius: 3
z:1
anchors {
top: wrapperProgressbar.bottom
topMargin: 30
right: parent.right
bottom: parent.bottom
left: parent.left
}
Flickable {
anchors.fill: parent
focus: true
clip: true
contentHeight: txtFFMPEG.paintedHeight
ScrollBar.vertical: ScrollBar {
snapMode: ScrollBar.SnapOnRelease
policy: ScrollBar.AlwaysOn
}
Text {
id: txtFFMPEG
anchors {
top: parent.top
right: parent.right
left: parent.left
margins: 20
}
wrapMode: Text.WordWrap
color: "#626262"
text: "asasas"
renderType: Text.NativeRendering
height: txtFFMPEG.paintedHeight
}
}
}
Item {
id: wrapperFinished
z:0
anchors.fill: parent
opacity: 0
Text {
id: txtDone
text: qsTr("Video creation successful!")
font.pixelSize: 42
color: Material.color(Material.Green)
renderType: Text.NativeRendering
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 30
}
}
}
Connections {
target: screenPlayCreate
onProcessOutput: {
txtFFMPEG.text += text
}
}
states: [
State {
name: "finished"
PropertyChanges {
target: wrapperProgressbar
opacity:0
}
PropertyChanges {
target: wrapperFFMPEGOutput
opacity:0
}
PropertyChanges {
target: wrapperFinished
opacity:1
}
}
]
transitions: [
Transition {
from: "0"
to: "finished"
PropertyAnimation {
target: wrapperFFMPEGOutput
duration: 200
property: "opacity"
easing.type: Easing.InOutQuad
}
PropertyAnimation {
target: wrapperProgressbar
duration: 200
property: "opacity"
easing.type: Easing.InOutQuad
}
PropertyAnimation {
target: wrapperFinished
duration: 200
property: "opacity"
easing.type: Easing.InOutQuad
}
}
]
}

View File

@ -1,5 +0,0 @@
import QtQuick 2.9
Item {
}

View File

@ -2,6 +2,7 @@ import QtQuick 2.9
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
Item { Item {
id: screenPlayItem id: screenPlayItem
width: 320 width: 320
@ -140,6 +141,16 @@ Item {
sourceImage: Qt.resolvedUrl( sourceImage: Qt.resolvedUrl(
"file:///" + screenPlayItem.absoluteStoragePath "file:///" + screenPlayItem.absoluteStoragePath
+ "/" + screenPreview) + "/" + screenPreview)
sourceImageGIF: {
if (screenPreviewGIF === undefined) {
return ""
} else {
return Qt.resolvedUrl(
"file:///" + screenPlayItem.absoluteStoragePath
+ "/" + screenPreviewGIF)
}
}
} }
Image { Image {
@ -181,7 +192,7 @@ Item {
color: "#2F2F2F" color: "#2F2F2F"
font.pointSize: 9 font.pointSize: 9
renderType: Text.NativeRendering renderType: Text.NativeRendering
font.family: "Roboto" font.family: "Segoe UI, Roboto"
} }
} }
} }
@ -198,12 +209,16 @@ Item {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onEntered: { onEntered: {
if (!hasMenuOpen) if (!hasMenuOpen) {
screenPlayItem.state = "hover" screenPlayItem.state = "hover"
screenPlayItemImage.enter()
}
} }
onExited: { onExited: {
if (!hasMenuOpen) if (!hasMenuOpen) {
screenPlayItem.state = "visible" screenPlayItem.state = "visible"
screenPlayItemImage.exit()
}
} }
onClicked: { onClicked: {

View File

@ -4,13 +4,46 @@ Item {
id: screenPlayItemImage id: screenPlayItemImage
width: 320 width: 320
height: 121 height: 121
anchors.bottomMargin: 0
state: "loading" state: "loading"
property string sourceImage: "" property string sourceImage: ""
property string sourceImageGIF: ""
onSourceImageChanged: { function enter() {
image.source = screenPlayItemImage.sourceImage if (screenPlayItemImage.sourceImageGIF != "") {
imgGIFPreview.playing = true
}
}
function exit() {
imgGIFPreview.playing = false
}
Image {
id: image
anchors.fill: parent
antialiasing: false
asynchronous: true
fillMode: Image.PreserveAspectCrop
source: screenPlayItemImage.sourceImage.trim()
onStatusChanged: {
if (image.status === Image.Ready) {
screenPlayItemImage.state = "loaded"
} else if (image.status === Image.Error) {
source = "qrc:/assets/images/missingPreview.png"
screenPlayItemImage.state = "loaded"
}
}
}
AnimatedImage {
id: imgGIFPreview
asynchronous: true
playing: false
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: screenPlayItemImage.sourceImageGIF.trim()
} }
states: [ states: [
@ -61,34 +94,4 @@ Item {
} }
} }
] ]
Image {
id:image
anchors.fill: parent
antialiasing: false
asynchronous: true
//sourceSize: Qt.size(320,121)
fillMode: Image.PreserveAspectCrop
source: screenPlayItemImage.sourceImage.trim()
onStatusChanged: {
if (image.status === Image.Ready){
screenPlayItemImage.state = "loaded"
} else if(image.status === Image.Error){
source = "qrc:/assets/images/missingPreview.png"
screenPlayItemImage.state = "loaded"
}
}
}
Text {
id: text1
text: ""
anchors.fill: parent
font.pixelSize: 12
}
} }

View File

@ -55,8 +55,7 @@ void Create::createWallpaperStart(QString videoPath)
QDir dir; QDir dir;
dir.cd(this->m_settings->localStoragePath().toString()); dir.cd(this->m_settings->localStoragePath().toString());
CreateWallpaperData createWallpaperData; m_createWallpaperData.videoPath = videoPath;
createWallpaperData.videoPath = videoPath;
// Create a temp dir so we can later alter it to the workshop id // Create a temp dir so we can later alter it to the workshop id
auto folderName = QString("_tmp_" + QTime::currentTime().toString()).replace(":", ""); auto folderName = QString("_tmp_" + QTime::currentTime().toString()).replace(":", "");
@ -64,28 +63,25 @@ void Create::createWallpaperStart(QString videoPath)
if (!dir.mkdir(folderName)) if (!dir.mkdir(folderName))
return; return;
createWallpaperData.exportPath = dir.path() + "/" + folderName; m_createWallpaperData.exportPath = dir.path() + "/" + folderName;
m_workingDir = createWallpaperData.exportPath; m_workingDir = m_createWallpaperData.exportPath;
// If we return early/false this means the creation // If we return early/false this means the creation
// process did not work // process did not work
// Todo: cleanup! // Todo: cleanup!
if (!this->createWallpaperInfo(createWallpaperData)) if (!this->createWallpaperInfo())
return; return;
if (!this->createWallpaperVideoPreview(createWallpaperData)) if (!this->createWallpaperVideoPreview())
return; return;
if (!this->createWallpaperVideo(createWallpaperData)) if (!this->createWallpaperVideo())
return;
if (!this->createWallpaperProjectFile(createWallpaperData))
return; return;
}); });
} }
bool Create::createWallpaperInfo(CreateWallpaperData& createWallpaperData) bool Create::createWallpaperInfo()
{ {
// Get video info // Get video info
QStringList args; QStringList args;
@ -93,7 +89,7 @@ bool Create::createWallpaperInfo(CreateWallpaperData& createWallpaperData)
args.append("json"); args.append("json");
args.append("-show_format"); args.append("-show_format");
args.append("-show_streams"); args.append("-show_streams");
args.append(createWallpaperData.videoPath); args.append(m_createWallpaperData.videoPath);
QScopedPointer<QProcess> pro(new QProcess()); QScopedPointer<QProcess> pro(new QProcess());
pro.data()->setArguments(args); pro.data()->setArguments(args);
@ -131,7 +127,7 @@ bool Create::createWallpaperInfo(CreateWallpaperData& createWallpaperData)
int length = 0; int length = 0;
length = static_cast<int>(tmpLength); length = static_cast<int>(tmpLength);
createWallpaperData.length = length; m_createWallpaperData.length = length;
// Get framerate // Get framerate
QJsonArray arrSteams = obj.value("streams").toArray(); QJsonArray arrSteams = obj.value("streams").toArray();
@ -158,15 +154,15 @@ bool Create::createWallpaperInfo(CreateWallpaperData& createWallpaperData)
float value2 = static_cast<float>(avgFrameRateList.at(1).toInt()); float value2 = static_cast<float>(avgFrameRateList.at(1).toInt());
framerate = qCeil(value1 / value2); framerate = qCeil(value1 / value2);
createWallpaperData.framerate = framerate; m_createWallpaperData.framerate = framerate;
return true; return true;
} }
bool Create::createWallpaperVideoPreview(CreateWallpaperData& createWallpaperData) bool Create::createWallpaperVideoPreview()
{ {
qDebug() << createWallpaperData.length << createWallpaperData.framerate; qDebug() << m_createWallpaperData.length << m_createWallpaperData.framerate;
QStringList args; QStringList args;
// args.append("-hide_banner"); // args.append("-hide_banner");
args.append("-loglevel"); args.append("-loglevel");
@ -174,17 +170,17 @@ bool Create::createWallpaperVideoPreview(CreateWallpaperData& createWallpaperDat
args.append("-y"); args.append("-y");
args.append("-stats"); args.append("-stats");
args.append("-i"); args.append("-i");
args.append(createWallpaperData.videoPath); args.append(m_createWallpaperData.videoPath);
args.append("-speed"); args.append("-speed");
args.append("ultrafast"); args.append("ultrafast");
args.append("-vf"); args.append("-vf");
// We allways want to have a 5 second clip via 24fps -> 120 frames // We allways want to have a 5 second clip via 24fps -> 120 frames
// Divided by the number of frames we can skip (timeInSeconds * Framrate) // Divided by the number of frames we can skip (timeInSeconds * Framrate)
// scale & crop parameter: https://unix.stackexchange.com/a/284731 // scale & crop parameter: https://unix.stackexchange.com/a/284731
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"); args.append("select='not(mod(n," + QString::number((m_createWallpaperData.length / 5)) + "))',setpts=N/FRAME_RATE/TB,crop=in_h*16/9:in_h,scale=-2:400");
// Disable audio // Disable audio
args.append("-an"); args.append("-an");
args.append(createWallpaperData.exportPath + "/preview.mp4"); args.append(m_createWallpaperData.exportPath + "/preview.mp4");
QScopedPointer<QProcess> proConvertPreviewMP4(new QProcess()); QScopedPointer<QProcess> proConvertPreviewMP4(new QProcess());
proConvertPreviewMP4.data()->setArguments(args); proConvertPreviewMP4.data()->setArguments(args);
@ -203,7 +199,7 @@ bool Create::createWallpaperVideoPreview(CreateWallpaperData& createWallpaperDat
} }
QString tmpErr = proConvertPreviewMP4.data()->readAllStandardError(); QString tmpErr = proConvertPreviewMP4.data()->readAllStandardError();
if (!tmpErr.isEmpty()) { if (!tmpErr.isEmpty()) {
QFile previewVideo(createWallpaperData.exportPath + "/preview.mp4"); QFile previewVideo(m_createWallpaperData.exportPath + "/preview.mp4");
if (!previewVideo.exists() && !(previewVideo.size() > 0)) { if (!previewVideo.exists() && !(previewVideo.size() > 0)) {
emit processOutput(tmpErr); emit processOutput(tmpErr);
emit createWallpaperStateChanged(Create::State::ConvertingPreviewVideoError); emit createWallpaperStateChanged(Create::State::ConvertingPreviewVideoError);
@ -227,10 +223,10 @@ bool Create::createWallpaperVideoPreview(CreateWallpaperData& createWallpaperDat
args.append("-y"); args.append("-y");
args.append("-stats"); args.append("-stats");
args.append("-i"); args.append("-i");
args.append(createWallpaperData.exportPath + "/preview.mp4"); args.append(m_createWallpaperData.exportPath + "/preview.mp4");
args.append("-filter_complex"); args.append("-filter_complex");
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("[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"); args.append(m_createWallpaperData.exportPath + "/preview.gif");
QScopedPointer<QProcess> proConvertGif(new QProcess()); QScopedPointer<QProcess> proConvertGif(new QProcess());
proConvertGif.data()->setArguments(args); proConvertGif.data()->setArguments(args);
@ -242,7 +238,7 @@ bool Create::createWallpaperVideoPreview(CreateWallpaperData& createWallpaperDat
proConvertGif.data()->waitForFinished(-1); proConvertGif.data()->waitForFinished(-1);
QString tmpErrGif = proConvertGif.data()->readAllStandardError(); QString tmpErrGif = proConvertGif.data()->readAllStandardError();
if (!tmpErrGif.isEmpty()) { if (!tmpErrGif.isEmpty()) {
QFile previewGif(createWallpaperData.exportPath + "/preview.gif"); QFile previewGif(m_createWallpaperData.exportPath + "/preview.gif");
if (!previewGif.exists() && !(previewGif.size() > 0)) { if (!previewGif.exists() && !(previewGif.size() > 0)) {
emit createWallpaperStateChanged(Create::State::ConvertingPreviewGifError); emit createWallpaperStateChanged(Create::State::ConvertingPreviewGifError);
return false; return false;
@ -253,10 +249,51 @@ bool Create::createWallpaperVideoPreview(CreateWallpaperData& createWallpaperDat
proConvertGif.data()->close(); proConvertGif.data()->close();
emit createWallpaperStateChanged(Create::State::ConvertingPreviewGifFinished); emit createWallpaperStateChanged(Create::State::ConvertingPreviewGifFinished);
/*
*
* Create png
*
*/
emit createWallpaperStateChanged(Create::State::ConvertingPreviewImage);
args.clear();
args.append("-y");
args.append("-stats");
args.append("-ss");
args.append("00:00:02");
args.append("-i");
args.append(m_createWallpaperData.videoPath);
args.append("-vframes");
args.append("1");
args.append("-q:v");
args.append("2");
args.append(m_createWallpaperData.exportPath + "/preview.png");
QScopedPointer<QProcess> proConvertImage(new QProcess());
proConvertImage.data()->setArguments(args);
qDebug() << "Start converting video to preview gif";
#ifdef Q_OS_WIN
proConvertImage.data()->setProgram(QApplication::applicationDirPath() + "/ffmpeg.exe");
#endif
proConvertImage.data()->start();
proConvertImage.data()->waitForFinished(-1);
QString tmpErrImg = proConvertImage.data()->readAllStandardError();
if (!tmpErrImg.isEmpty()) {
QFile previewImg(m_createWallpaperData.exportPath + "/preview.png");
if (!previewImg.exists() && !(previewImg.size() > 0)) {
emit createWallpaperStateChanged(Create::State::ConvertingPreviewImageError);
return false;
}
}
this->processOutput(proConvertImage.data()->readAll());
proConvertImage.data()->close();
emit createWallpaperStateChanged(Create::State::ConvertingPreviewImageFinished);
return true; return true;
} }
bool Create::createWallpaperVideo(CreateWallpaperData& createWallpaperData) bool Create::createWallpaperVideo()
{ {
emit createWallpaperStateChanged(Create::State::ConvertingVideo); emit createWallpaperStateChanged(Create::State::ConvertingVideo);
@ -265,7 +302,7 @@ bool Create::createWallpaperVideo(CreateWallpaperData& createWallpaperData)
args.append("-y"); args.append("-y");
args.append("-stats"); args.append("-stats");
args.append("-i"); args.append("-i");
args.append(createWallpaperData.videoPath); args.append(m_createWallpaperData.videoPath);
args.append("-c:v"); args.append("-c:v");
args.append("libvpx-vp9"); args.append("libvpx-vp9");
args.append("-crf"); args.append("-crf");
@ -280,7 +317,7 @@ bool Create::createWallpaperVideo(CreateWallpaperData& createWallpaperData)
args.append("yuv420p"); args.append("yuv420p");
args.append("-b:v"); args.append("-b:v");
args.append("0"); args.append("0");
args.append(createWallpaperData.exportPath + "/video.webm"); args.append(m_createWallpaperData.exportPath + "/video.webm");
QScopedPointer<QProcess> proConvertVideo(new QProcess()); QScopedPointer<QProcess> proConvertVideo(new QProcess());
proConvertVideo.data()->setArguments(args); proConvertVideo.data()->setArguments(args);
@ -290,6 +327,7 @@ bool Create::createWallpaperVideo(CreateWallpaperData& createWallpaperData)
connect(proConvertVideo.data(), &QProcess::readyReadStandardOutput, this, [&]() { connect(proConvertVideo.data(), &QProcess::readyReadStandardOutput, this, [&]() {
QString tmpOut = proConvertVideo.data()->readAllStandardOutput(); QString tmpOut = proConvertVideo.data()->readAllStandardOutput();
qDebug() << tmpOut << m_createWallpaperData.length;
auto tmpList = tmpOut.split(QRegExp("\\s+"), QString::SkipEmptyParts); auto tmpList = tmpOut.split(QRegExp("\\s+"), QString::SkipEmptyParts);
if (tmpList.length() > 2) { if (tmpList.length() > 2) {
bool ok = false; bool ok = false;
@ -298,7 +336,7 @@ bool Create::createWallpaperVideo(CreateWallpaperData& createWallpaperData)
if (!ok) if (!ok)
return; return;
float progress = currentFrame / createWallpaperData.length; float progress = currentFrame / m_createWallpaperData.length;
this->setProgress(progress); this->setProgress(progress);
} }
@ -311,12 +349,14 @@ bool Create::createWallpaperVideo(CreateWallpaperData& createWallpaperData)
#endif #endif
proConvertVideo.data()->start(QIODevice::ReadOnly); proConvertVideo.data()->start(QIODevice::ReadOnly);
proConvertVideo.data()->waitForFinished(-1); proConvertVideo.data()->waitForFinished(-1);
disconnect(proConvertVideo.data(), &QProcess::readyReadStandardOutput, 0, 0);
QString out = proConvertVideo.data()->readAllStandardOutput(); QString out = proConvertVideo.data()->readAllStandardOutput();
this->processOutput(out); this->processOutput(out);
QString tmpErrVideo = proConvertVideo.data()->readAllStandardError(); QString tmpErrVideo = proConvertVideo.data()->readAllStandardError();
if (!tmpErrVideo.isEmpty()) { if (!tmpErrVideo.isEmpty()) {
QFile video(createWallpaperData.exportPath + "/video.webm"); QFile video(m_createWallpaperData.exportPath + "/video.webm");
if (!video.exists() && !(video.size() > 0)) { if (!video.exists() && !(video.size() > 0)) {
emit createWallpaperStateChanged(Create::State::ConvertingVideoError); emit createWallpaperStateChanged(Create::State::ConvertingVideoError);
return false; return false;
@ -329,27 +369,29 @@ bool Create::createWallpaperVideo(CreateWallpaperData& createWallpaperData)
return true; return true;
} }
bool Create::createWallpaperProjectFile(CreateWallpaperData& createWallpaperData) bool Create::createWallpaperProjectFile(const QString title, const QString description)
{ {
//Copy Project File //Copy Project File
QFile configFile(createWallpaperData.exportPath + "/project.json"); QFile configFile(m_createWallpaperData.exportPath + "/project.json");
if (!configFile.open(QIODevice::ReadWrite | QIODevice::Text)) { if (!configFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
return false; return false;
} }
// QTextStream out(&configFile); QTextStream out(&configFile);
// QJsonObject configObj; QJsonObject configObj;
// configObj.insert("file", videoPath.fileName()); configObj.insert("description", description);
// configObj.insert("preview", previewPath.fileName()); configObj.insert("title", title);
// //TODO
// configObj.insert("description", "");
// configObj.insert("title", title);
// QJsonDocument configJsonDocument(configObj); configObj.insert("file", "video.webm");
// out << configJsonDocument.toJson(); configObj.insert("preview", "preview.png");
configObj.insert("previewGIF", "preview.gif");
configObj.insert("previewMP4", "preview.mp4");
configObj.insert("type", "video");
QJsonDocument configJsonDocument(configObj);
out << configJsonDocument.toJson();
configFile.close(); configFile.close();
return true; return true;
} }

View File

@ -89,10 +89,10 @@ public slots:
// Steps to convert any video to a wallpaper broken down into // Steps to convert any video to a wallpaper broken down into
// several methods in this order: // several methods in this order:
void createWallpaperStart(QString videoPath); void createWallpaperStart(QString videoPath);
bool createWallpaperInfo(CreateWallpaperData& createWallpaperData); bool createWallpaperInfo();
bool createWallpaperVideoPreview(CreateWallpaperData& createWallpaperData); bool createWallpaperVideoPreview();
bool createWallpaperVideo(CreateWallpaperData& createWallpaperData); bool createWallpaperVideo();
bool createWallpaperProjectFile(CreateWallpaperData& createWallpaperData); bool createWallpaperProjectFile(const QString title, const QString description);
void setWorkingDir(QString workingDir) void setWorkingDir(QString workingDir)
{ {
@ -116,7 +116,7 @@ public slots:
private: private:
Settings* m_settings; Settings* m_settings;
QMLUtilities* m_utils; QMLUtilities* m_utils;
CreateWallpaperData m_createWallpaperData;
QString m_workingDir; QString m_workingDir;
float m_progress = 0.0f; float m_progress = 0.0f;
}; };

View File

@ -28,6 +28,8 @@ QVariant InstalledListModel::data(const QModelIndex& index, int role) const
return m_screenPlayFiles.at(index.row()).m_title; return m_screenPlayFiles.at(index.row()).m_title;
case PreviewRole: case PreviewRole:
return m_screenPlayFiles.at(index.row()).m_preview; return m_screenPlayFiles.at(index.row()).m_preview;
case PreviewGIFRole:
return m_screenPlayFiles.at(index.row()).m_previewGIF;
case TypeRole: case TypeRole:
return m_screenPlayFiles.at(index.row()).m_type; return m_screenPlayFiles.at(index.row()).m_type;
case FolderIdRole: case FolderIdRole:
@ -50,6 +52,7 @@ QHash<int, QByteArray> InstalledListModel::roleNames() const
{ TitleRole, "screenTitle" }, { TitleRole, "screenTitle" },
{ TypeRole, "screenType" }, { TypeRole, "screenType" },
{ PreviewRole, "screenPreview" }, { PreviewRole, "screenPreview" },
{ PreviewGIFRole, "screenPreviewGIF" },
{ FolderIdRole, "screenFolderId" }, { FolderIdRole, "screenFolderId" },
{ FileIdRole, "screenFile" }, { FileIdRole, "screenFile" },
{ AbsoluteStoragePathRole, "screenAbsoluteStoragePath" }, { AbsoluteStoragePathRole, "screenAbsoluteStoragePath" },
@ -125,6 +128,10 @@ void InstalledListModel::loadScreens()
if (fileEnding.endsWith(".webm") || (obj.value("type").toString() == "qmlScene") || fileEnding.endsWith(".html")) if (fileEnding.endsWith(".webm") || (obj.value("type").toString() == "qmlScene") || fileEnding.endsWith(".html"))
emit addInstalledItem(obj, item.baseName()); emit addInstalledItem(obj, item.baseName());
if(obj.value("type") == "qmlWidget")
emit addInstalledItem(obj, item.baseName());
} }
} }
emit installedLoadingFinished(); emit installedLoadingFinished();
@ -143,6 +150,7 @@ QVariantMap InstalledListModel::get(QString folderId)
if (m_screenPlayFiles[i].m_folderId == folderId) { if (m_screenPlayFiles[i].m_folderId == folderId) {
map.insert("screenTitle", m_screenPlayFiles[i].m_title); map.insert("screenTitle", m_screenPlayFiles[i].m_title);
map.insert("screenPreview", m_screenPlayFiles[i].m_preview); map.insert("screenPreview", m_screenPlayFiles[i].m_preview);
map.insert("screenPreviewGIF", m_screenPlayFiles[i].m_previewGIF);
map.insert("screenFile", m_screenPlayFiles[i].m_file); map.insert("screenFile", m_screenPlayFiles[i].m_file);
map.insert("screenType", m_screenPlayFiles[i].m_type); map.insert("screenType", m_screenPlayFiles[i].m_type);
map.insert("screenAbsoluteStoragePath", m_screenPlayFiles[i].m_absoluteStoragePath); map.insert("screenAbsoluteStoragePath", m_screenPlayFiles[i].m_absoluteStoragePath);

View File

@ -43,6 +43,7 @@ public:
TitleRole, TitleRole,
TypeRole, TypeRole,
PreviewRole, PreviewRole,
PreviewGIFRole,
FolderIdRole, FolderIdRole,
FileIdRole, FileIdRole,
AbsoluteStoragePathRole, AbsoluteStoragePathRole,

View File

@ -12,6 +12,9 @@ ProjectFile::ProjectFile(QJsonObject obj, QString folderName, QUrl absolutePath)
if (obj.contains("preview")) if (obj.contains("preview"))
m_preview = obj.value("preview"); m_preview = obj.value("preview");
if (obj.contains("previewGIF"))
m_previewGIF = obj.value("previewGIF");
if (obj.contains("title")) if (obj.contains("title"))
m_title = obj.value("title"); m_title = obj.value("title");

View File

@ -23,6 +23,7 @@ public:
QVariant m_description; QVariant m_description;
QVariant m_file; QVariant m_file;
QVariant m_preview; QVariant m_preview;
QVariant m_previewGIF;
QVariant m_title; QVariant m_title;
QString m_folderId; QString m_folderId;
QUrl m_absoluteStoragePath; QUrl m_absoluteStoragePath;