1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-09-14 22:42:34 +02:00

Add MultimediaWebView

This is for now macOS only because macOS MM only can play h264,
 so we still need the webview to render webm
This commit is contained in:
Elias Steurer 2021-10-23 10:35:15 +02:00
parent 6a081b4f25
commit 0419676af2
9 changed files with 279 additions and 10 deletions

View File

@ -102,4 +102,27 @@ namespace InstalledType {
Q_ENUM_NS(InstalledType)
}
/*!
\namespace ScreenPlay::InstalledType
\inmodule ScreenPlayUtil
\brief When changing the enum, one also needs to change:
GlobalVariables::getAvailableWallpaper
GlobalVariables::getAvailableWidgets
Common/Util.js isWallpaper() and isWidget()
ScreenPlayWallpaper: BaseWindow::parseWallpaperType()
*/
namespace VideoCodec {
Q_NAMESPACE
enum class VideoCodec {
Unknown,
VP8,
VP9,
AV1,
H264,
H265
};
Q_ENUM_NS(VideoCodec)
}
}

View File

@ -44,6 +44,7 @@ namespace ScreenPlayUtil {
QJsonArray fillArray(const QVector<QString>& items);
ScreenPlay::SearchType::SearchType getSearchTypeFromInstalledType(const ScreenPlay::InstalledType::InstalledType type);
std::optional<ScreenPlay::InstalledType::InstalledType> getInstalledTypeFromString(const QString& type);
std::optional<ScreenPlay::VideoCodec::VideoCodec> getVideoCodecFromString(const QString& type);
std::optional<QJsonObject> parseQByteArrayToQJsonObject(const QByteArray& byteArray);
std::optional<QJsonObject> openJsonFileToObject(const QString& path);
std::optional<QString> openJsonFileToString(const QString& path);

View File

@ -266,6 +266,33 @@ std::optional<ScreenPlay::InstalledType::InstalledType> getInstalledTypeFromStri
return std::nullopt;
}
/*!
\brief Maps the video codec type from a QString to an enum. Used for parsing the project.json.
*/
std::optional<ScreenPlay::VideoCodec::VideoCodec> getVideoCodecFromString(const QString &type)
{
if(type.isEmpty())
return std::nullopt;
if(type.contains("vp8",Qt::CaseInsensitive))
return ScreenPlay::VideoCodec::VideoCodec::VP8;
if(type.contains("vp9",Qt::CaseInsensitive))
return ScreenPlay::VideoCodec::VideoCodec::VP9;
if(type.contains("av1",Qt::CaseInsensitive))
return ScreenPlay::VideoCodec::VideoCodec::AV1;
if(type.contains("h264",Qt::CaseInsensitive))
return ScreenPlay::VideoCodec::VideoCodec::H264;
if(type.contains("h265",Qt::CaseInsensitive))
return ScreenPlay::VideoCodec::VideoCodec::H264;
return std::nullopt;
}
/*!
\brief Converts the given \a url string to a local file path.
*/
@ -368,4 +395,5 @@ std::optional<QVector<int>> parseStringToIntegerList(const QString string)
return list;
}
}

View File

@ -9,5 +9,6 @@
<file>qml/WebsiteWallpaper.qml</file>
<file>qml/WebView.qml</file>
<file>qml/MultimediaView.qml</file>
<file>qml/MultimediaWebView.qml</file>
</qresource>
</RCC>

View File

@ -13,11 +13,4 @@ Video {
if (Wallpaper.loops)
root.play()
}
//loops: MediaPlayer.Infinite
// onErrorOccurred: function (error, errorString) {
// console.log("[qmlvideo] VideoItem.onError error " + error
// + " errorString " + errorString)
// root.fatalError()
// }
}

View File

@ -0,0 +1,157 @@
import QtQuick
import QtWebEngine
import ScreenPlay.Enums.InstalledType 1.0
import ScreenPlayWallpaper 1.0
/*!
* The native macOS multimedia stack does not support VP8/VP9. For this we must use the WebEngine.
*/
Item {
id: root
signal requestFadeIn()
function getSetVideoCommand() {
// TODO 30:
// Currently wont work. Commit anyways til QtCreator and Qt work with js template literals
var src = ""
src += "var videoPlayer = document.getElementById('videoPlayer');"
src += "var videoSource = document.getElementById('videoSource');"
src += "videoSource.src = '" + Wallpaper.projectSourceFileAbsolute + "';"
src += "videoPlayer.load();"
src += "videoPlayer.volume = " + Wallpaper.volume + ";"
src += "videoPlayer.setAttribute('style', 'object-fit :" + Wallpaper.fillMode + ";');"
src += "videoPlayer.play();"
print(src)
return src
}
Component.onCompleted: {
WebEngine.settings.localContentCanAccessFileUrls = true
WebEngine.settings.localContentCanAccessRemoteUrls = true
WebEngine.settings.allowRunningInsecureContent = true
WebEngine.settings.accelerated2dCanvasEnabled = true
WebEngine.settings.javascriptCanOpenWindows = false
WebEngine.settings.showScrollBars = false
WebEngine.settings.playbackRequiresUserGesture = false
WebEngine.settings.focusOnNavigationEnabled = true
}
WebEngineView {
id: webView
anchors.fill: parent
// url:"https://www.google.de"
url: "qrc:/index.html"
onJavaScriptConsoleMessage:(lineNumber, message)=> print(lineNumber, message)
onLoadProgressChanged: {
if (loadProgress === 100) {
loadHtml("")
requestFadeIn()
return
webView.runJavaScript(root.getSetVideoCommand(),
function (result) {
requestFadeIn()
})
}
}
}
Text {
id: txtVisualsPaused
text: qsTr("If you can read this, then the VisualsPaused optimization does not work on your system. You can fix this by disable this in: \n Settings -> Perfromance -> Pause wallpaper video rendering while another app is in the foreground ")
font.pointSize: 32
visible: false
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
anchors.centerIn: parent
width: parent.width * 0.8
color: "white"
}
Timer {
id: timerCover
interval: 300
onTriggered: {
webView.visible = !Wallpaper.visualsPaused
txtVisualsPaused.visible = Wallpaper.visualsPaused
}
}
Connections {
function onReloadVideo(oldType) {
webView.runJavaScript(root.getSetVideoCommand())
}
function onQmlExit() {
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.volume = 0;")
}
function onMutedChanged(muted) {
if (muted)
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.volume = 0;")
else
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.volume = " + Wallpaper.volume + ";")
}
function onFillModeChanged(fillMode) {
if (webView.loadProgress === 100)
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.setAttribute('style', 'object-fit :" + fillMode + ";');")
}
function onLoopsChanged(loops) {
if (webView.loadProgress === 100)
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.loop = " + loops + ";")
}
function onVolumeChanged(volume) {
if (webView.loadProgress === 100)
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.volume = " + volume + ";")
}
function onCurrentTimeChanged(currentTime) {
if (webView.loadProgress === 100)
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.currentTime = "
+ currentTime + " * videoPlayer.duration;")
}
function onPlaybackRateChanged(playbackRate) {
if (webView.loadProgress === 100)
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.playbackRate = " + playbackRate + ";")
}
function onVisualsPausedChanged(visualsPaused) {
if (visualsPaused) {
// Wait until Wallpaper animation is finsihed
timerCover.restart()
} else {
webView.visible = true
txtVisualsPaused.visible = false
}
}
function onIsPlayingChanged(isPlaying) {
if (webView.loadProgress === 100) {
if (isPlaying)
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.play();")
else
webView.runJavaScript(
"var videoPlayer = document.getElementById('videoPlayer'); videoPlayer.pause();")
}
}
target: Wallpaper
}
}

View File

@ -3,16 +3,31 @@ import QtQuick
import QtQuick.Controls
import ScreenPlayWallpaper 1.0
import ScreenPlay.Enums.InstalledType 1.0
import ScreenPlay.Enums.VideoCodec 1.0
Rectangle {
id: root
onStateChanged: print(state)
property bool canFadeByWallpaperFillMode: true
function init() {
print("init")
switch (Wallpaper.type) {
case InstalledType.VideoWallpaper:
loader.source = "qrc:/qml/MultimediaView.qml";
if(Wallpaper.videoCodec === VideoCodec.Unknown){
Wallpaper.terminate()
}
if(Qt.platform.os === "osx") {
// macOS only supports h264 via the native Qt MM
if(Wallpaper.videoCodec === VideoCodec.VP8 || Wallpaper.videoCodec === VideoCodec.VP9){
print(Qt.resolvedUrl(Wallpaper.projectSourceFileAbsolute))
loader.source = "qrc:/qml/MultimediaWebView.qml";
print(loader.status)
}else {
loader.source = "qrc:/qml/MultimediaView.qml";
}
}
fadeIn();
break;
case InstalledType.HTMLWallpaper:
@ -106,11 +121,11 @@ Rectangle {
anchors.fill: parent
// QML Engine deadlocks in 5.15.2 when a loader cannot load
// an item. QApplication::quit(); waits for the destruction forever.
asynchronous: true
//asynchronous: true
onStatusChanged: {
if (loader.status === Loader.Error) {
loader.source = "";
Wallpaper.terminate();
// Wallpaper.terminate();
}
}

View File

@ -41,6 +41,12 @@ BaseWindow::BaseWindow(
"InstalledType",
"Error: only enums");
qmlRegisterUncreatableMetaObject(ScreenPlay::VideoCodec::staticMetaObject,
"ScreenPlay.Enums.VideoCodec",
1, 0,
"VideoCodec",
"Error: only enums");
qmlRegisterType<BaseWindow>("ScreenPlay.Wallpaper", 1, 0, "Wallpaper");
if (!appID.contains("appID=")) {
@ -76,8 +82,33 @@ BaseWindow::BaseWindow(
QApplication::exit(-4);
}
if (auto typeOpt = ScreenPlayUtil::getInstalledTypeFromString(project.value("type").toString())) {
setType(typeOpt.value());
if (!project.contains("videoCodec") ) {
qWarning("No videoCodec was specified inside the json object!");
// QApplication::exit(-4);
const QString filename = project.value("file").toString();
qInfo() << filename;
if(filename.endsWith(".mp4")){
setVideoCodec(ScreenPlay::VideoCodec::VideoCodec::H264);
} else if(filename.endsWith(".webm")){
setVideoCodec(ScreenPlay::VideoCodec::VideoCodec::VP8);
}
} else {
if(this->type() == ScreenPlay::InstalledType::InstalledType::VideoWallpaper){
if (auto videoCodecOpt = ScreenPlayUtil::getVideoCodecFromString(project.value("videoCodec").toString())) {
setVideoCodec(videoCodecOpt.value());
} else {
qCritical() << "Cannot parse Wallpaper video codec from value" << project.value("type");
}
}
}
} else {
qCritical() << "Cannot parse Wallpaper type from value" << project.value("type");
}
@ -239,3 +270,16 @@ void BaseWindow::setupLiveReloading()
QObject::connect(&m_liveReloadLimiter, &QTimer::timeout, this, reloadQMLLambda);
m_fileSystemWatcher.addPaths({ QUrl::fromUserInput(projectPath()).toLocalFile() });
}
ScreenPlay::VideoCodec::VideoCodec BaseWindow::videoCodec() const
{
return m_videoCodec;
}
void BaseWindow::setVideoCodec(ScreenPlay::VideoCodec::VideoCodec newVideoCodec)
{
if (m_videoCodec == newVideoCodec)
return;
m_videoCodec = newVideoCodec;
emit videoCodecChanged();
}

View File

@ -91,6 +91,7 @@ public:
Q_PROPERTY(float currentTime READ currentTime WRITE setCurrentTime NOTIFY currentTimeChanged)
Q_PROPERTY(ScreenPlay::InstalledType::InstalledType type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(ScreenPlay::VideoCodec::VideoCodec videoCodec READ videoCodec WRITE setVideoCodec NOTIFY videoCodecChanged)
Q_PROPERTY(QString OSVersion READ OSVersion WRITE setOSVersion NOTIFY OSVersionChanged)
Q_PROPERTY(ScreenPlaySDK* sdk READ sdk WRITE setSdk NOTIFY sdkChanged)
@ -117,6 +118,9 @@ public:
const QString& projectSourceFile() const { return m_projectSourceFile; }
const QUrl& projectSourceFileAbsolute() const { return m_projectSourceFileAbsolute; }
ScreenPlay::VideoCodec::VideoCodec videoCodec() const;
void setVideoCodec(ScreenPlay::VideoCodec::VideoCodec newVideoCodec);
signals:
void qmlExit();
void reloadQML(const ScreenPlay::InstalledType::InstalledType oldType);
@ -146,6 +150,8 @@ signals:
void projectSourceFileChanged(const QString& projectSourceFile);
void projectSourceFileAbsoluteChanged(const QUrl& rojectSourceFileAbsolute);
void videoCodecChanged();
public slots:
virtual void destroyThis() { }
virtual void setVisible(bool show) { Q_UNUSED(show) }
@ -385,4 +391,5 @@ private:
QSysInfo m_sysinfo;
std::unique_ptr<ScreenPlaySDK> m_sdk;
QUrl m_projectSourceFileAbsolute;
ScreenPlay::VideoCodec::VideoCodec m_videoCodec = ScreenPlay::VideoCodec::VideoCodec::Unknown;
};