From 990474de8e93bf295e2aa65610c5298c4faac364 Mon Sep 17 00:00:00 2001 From: zheng_wenlong Date: Wed, 14 Nov 2018 13:00:59 +0900 Subject: Add videoplayer for vertical mode Add videoplayer for vertical mode for restriction display. Change-Id: I1ab3df7d245a8d4e7267e907dbf3812e75877b67 Signed-off-by: zheng_wenlong --- demo3/vertical/videoplayer/app/VideoPlayer.qml | 244 +++++++++++++++++++++ .../vertical/videoplayer/app/api/MediaScanner.qml | 117 ++++++++++ demo3/vertical/videoplayer/app/app.pri | 3 + demo3/vertical/videoplayer/app/app.pro | 14 ++ .../app/images/AGL_MediaPlayer_BackArrow.svg | 29 +++ .../app/images/AGL_MediaPlayer_DividingLine.svg | 60 +++++ .../app/images/AGL_MediaPlayer_ForwardArrow.svg | 29 +++ .../app/images/AGL_MediaPlayer_Loop_Active.svg | 58 +++++ .../app/images/AGL_MediaPlayer_Loop_Inactive.svg | 58 +++++ .../app/images/AGL_MediaPlayer_Player_Pause.svg | 37 ++++ .../app/images/AGL_MediaPlayer_Player_Play.svg | 36 +++ .../app/images/AGL_MediaPlayer_Shuffle_Active.svg | 56 +++++ .../images/AGL_MediaPlayer_Shuffle_Inactive.svg | 56 +++++ demo3/vertical/videoplayer/app/images/images.qrc | 13 ++ demo3/vertical/videoplayer/app/main.cpp | 139 ++++++++++++ .../vertical/videoplayer/app/pkg-config_wrapper.sh | 6 + demo3/vertical/videoplayer/app/videoplayer.qrc | 6 + 17 files changed, 961 insertions(+) create mode 100644 demo3/vertical/videoplayer/app/VideoPlayer.qml create mode 100644 demo3/vertical/videoplayer/app/api/MediaScanner.qml create mode 100644 demo3/vertical/videoplayer/app/app.pri create mode 100644 demo3/vertical/videoplayer/app/app.pro create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_BackArrow.svg create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_DividingLine.svg create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_ForwardArrow.svg create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Loop_Active.svg create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Loop_Inactive.svg create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Player_Pause.svg create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Player_Play.svg create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Shuffle_Active.svg create mode 100644 demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Shuffle_Inactive.svg create mode 100644 demo3/vertical/videoplayer/app/images/images.qrc create mode 100644 demo3/vertical/videoplayer/app/main.cpp create mode 100644 demo3/vertical/videoplayer/app/pkg-config_wrapper.sh create mode 100644 demo3/vertical/videoplayer/app/videoplayer.qrc (limited to 'demo3/vertical/videoplayer/app') diff --git a/demo3/vertical/videoplayer/app/VideoPlayer.qml b/demo3/vertical/videoplayer/app/VideoPlayer.qml new file mode 100644 index 0000000..4fae69d --- /dev/null +++ b/demo3/vertical/videoplayer/app/VideoPlayer.qml @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2018 The Qt Company Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import QtQuick 2.6 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 +import QtMultimedia 5.6 +import AGL.Demo.Controls 1.0 +import 'api' as API + +ApplicationWindow { + id: root + + API.MediaScanner { + id: scanner + url: bindingAddress + + property var titles: Object + onAdded: { + playlist.addItem(media.path) + titles[media.path] = media.title + } + onRemoved: { + playlist.removeItem(index) + } + } + + MediaPlayer { + id: player + audioRole: MediaPlayer.MusicRole + autoLoad: true + playlist: playlist + function time2str(value) { + return Qt.formatTime(new Date(value), 'mm:ss') + } + onPositionChanged: slider.value = player.position + } + + Playlist { + id: playlist + playbackMode: Playlist.Loop + +// PlaylistItem { source: 'file:///home/root/Videos/Qt_Mashup_DO_NOT_MODIFY.mp4' } +// PlaylistItem { source: 'file:///home/root/Videos/Qt_is_everywhere-071116.mp4' } + } + + ColumnLayout { + anchors.fill: parent + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredHeight: 1080 + clip: true + + VideoOutput { + source: player + anchors.fill: parent + Rectangle { + anchors.fill: parent + color: 'black' + opacity: 0.75 + z: -1 + } + + MouseArea{ + anchors.fill: parent + onClicked:{ + controls.visible = !controls.visible; + } + } + + Item { + id: controls + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + visible: false + height: 240 + z: 100 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 5 + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Row { + spacing: 20 + ToggleButton { + id: random + offImage: './images/AGL_MediaPlayer_Shuffle_Inactive.svg' + onImage: './images/AGL_MediaPlayer_Shuffle_Active.svg' + } + ToggleButton { + id: loop + offImage: './images/AGL_MediaPlayer_Loop_Inactive.svg' + onImage: './images/AGL_MediaPlayer_Loop_Active.svg' + } + } + ColumnLayout { + anchors.fill: parent + Label { + id: title + Layout.alignment: Layout.Center + text: player.metaData.title ? player.metaData.title : '' + horizontalAlignment: Label.AlignHCenter + verticalAlignment: Label.AlignVCenter + } + Label { + id: artist + Layout.alignment: Layout.Center + text: player.metaData.author ? player.metaData.author : '' + horizontalAlignment: Label.AlignHCenter + verticalAlignment: Label.AlignVCenter + font.pixelSize: title.font.pixelSize * 0.6 + } + } + } + Slider { + id: slider + Layout.fillWidth: true + to: player.duration + Label { + id: position + anchors.left: parent.left + anchors.bottom: parent.top + font.pixelSize: 24 + text: player.time2str(player.position) + } + Label { + id: duration + anchors.right: parent.right + anchors.bottom: parent.top + font.pixelSize: 24 + text: player.time2str(player.duration) + } + onPressedChanged: player.seek(value) + } + RowLayout { + Layout.fillHeight: true + Item { Layout.fillWidth: true } + ImageButton { + offImage: './images/AGL_MediaPlayer_BackArrow.svg' + onClicked: playlist.previous() + } + ImageButton { + id: play + offImage: './images/AGL_MediaPlayer_Player_Play.svg' + onClicked: player.play() + states: [ + State { + when: player.playbackState === MediaPlayer.PlayingState + PropertyChanges { + target: play + offImage: './images/AGL_MediaPlayer_Player_Pause.svg' + onClicked: player.pause() + } + } + ] + } + ImageButton { + offImage: './images/AGL_MediaPlayer_ForwardArrow.svg' + onClicked: playlist.next() + } + + Item { Layout.fillWidth: true } + } + } + } + } + } + Item { + id: playlistArea + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredHeight: 407 + ListView { + anchors.fill: parent + clip: true + header: Label { + x: 50 + text: 'PLAYLIST' + opacity: 0.5 + } + model: playlist + currentIndex: playlist.currentIndex + + delegate: MouseArea { + id: delegate + width: ListView.view.width + height: ListView.view.height / 4 + RowLayout { + anchors.fill: parent + anchors.leftMargin: 50 + anchors.rightMargin: 50 + ColumnLayout { + Layout.fillWidth: true + Label { + Layout.fillWidth: true + text: scanner.titles[model.source] ? scanner.titles[model.source] : model.source.toString().split('/').reverse()[0] + } + } + Label { + text: player.time2str(model.duration) + color: '#66FF99' + font.pixelSize: 32 + } + } + property var m: model + onClicked: { + playlist.currentIndex = model.index + player.play() + } + } + + highlight: Rectangle { + color: 'white' + opacity: 0.25 + } + } + } + } + + + function changeArea(area) { + if (area === 'normal') { + playlistArea.visible = true; + } else { + playlistArea.visible = false; + } + } +} diff --git a/demo3/vertical/videoplayer/app/api/MediaScanner.qml b/demo3/vertical/videoplayer/app/api/MediaScanner.qml new file mode 100644 index 0000000..add261b --- /dev/null +++ b/demo3/vertical/videoplayer/app/api/MediaScanner.qml @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2018 The Qt Company Ltd. + * Copyright (C) 2017 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import QtQuick 2.6 +import QtWebSockets 1.0 + +WebSocket { + id: root + active: true + url: bindingAddress + + property string statusString: "waiting..." + property string apiString: "mediascanner" + property var verbs: [] + property string payloadLength: "9999" + + readonly property var msgid: { + "call": 2, + "retok": 3, + "reterr": 4, + "event": 5 + } + + signal added(var media) + signal removed(var index) + + property var cache: [] + function add(files) { + for (var i = 0; i < files.length; i++) { + var media = files[i] + + if (cache.indexOf(media.path) < 0) { + root.added(media) + cache.push(media.path) + } + } + } + + function remove(prefix) { + for (var i = cache.length - 1; i > -1; i--) { + var media = cache[i] + if (media.substr(0, prefix.length) === prefix) { + root.removed(i) + cache.splice(i, 1) + } + } + } + + onTextMessageReceived: { + console.debug("Raw response: " + message) + var json = JSON.parse(message) + var request = json[2].request + var response = json[2].response +// console.debug("response: " + JSON.stringify(response)) + switch (json[0]) { + case msgid.call: + break + case msgid.retok: + root.statusString = request.status + var verb = verbs.shift() + if (verb === "media_result") { + root.add(response.Media) + } + break + case msgid.reterr: + root.statusString = "Bad return value, binding probably not installed" + var verb = verbs.shift() + break + case msgid.event: + var payload = JSON.parse(JSON.stringify(json[2])) + var event = payload.event + if (event == "mediascanner/media_added") { + console.debug("Media playlist is updated") + root.add(json[2].data.Media) + } else if (event == "mediascanner/media_removed") { + root.remove(json[2].data.Path) + } + break + } + } + + onStatusChanged: { + switch (status) { + case WebSocket.Open: + console.debug("onStatusChanged: Open") + sendSocketMessage("subscribe", { value: "media_added" }) + sendSocketMessage("subscribe", { value: "media_removed" }) + sendSocketMessage("media_result", { type: 'video' }) + break + case WebSocket.Error: + root.statusString = "WebSocket error: " + root.errorString + break + } + } + + function sendSocketMessage(verb, parameter) { + var requestJson = [ msgid.call, payloadLength, apiString + '/' + + verb, parameter ] + console.debug("sendSocketMessage: " + JSON.stringify(requestJson)) + verbs.push(verb) + sendTextMessage(JSON.stringify(requestJson)) + } +} diff --git a/demo3/vertical/videoplayer/app/app.pri b/demo3/vertical/videoplayer/app/app.pri new file mode 100644 index 0000000..f22f540 --- /dev/null +++ b/demo3/vertical/videoplayer/app/app.pri @@ -0,0 +1,3 @@ +TEMPLATE = app + +DESTDIR = $${OUT_PWD}/../package/root/bin diff --git a/demo3/vertical/videoplayer/app/app.pro b/demo3/vertical/videoplayer/app/app.pro new file mode 100644 index 0000000..fdb0bc2 --- /dev/null +++ b/demo3/vertical/videoplayer/app/app.pro @@ -0,0 +1,14 @@ +TARGET = videoplayer +QT = quickcontrols2 multimedia + +SOURCES = main.cpp + +CONFIG += link_pkgconfig +PKGCONFIG += libhomescreen qlibwindowmanager + +RESOURCES += \ + videoplayer.qrc \ + images/images.qrc + +include(app.pri) + diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_BackArrow.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_BackArrow.svg new file mode 100644 index 0000000..061c6ec --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_BackArrow.svg @@ -0,0 +1,29 @@ + + + + + + + + + + +]> + + + + + + + + + + + + diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_DividingLine.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_DividingLine.svg new file mode 100644 index 0000000..51ed1ee --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_DividingLine.svg @@ -0,0 +1,60 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_ForwardArrow.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_ForwardArrow.svg new file mode 100644 index 0000000..ea17210 --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_ForwardArrow.svg @@ -0,0 +1,29 @@ + + + + + + + + + + +]> + + + + + + + + + + + + diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Loop_Active.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Loop_Active.svg new file mode 100644 index 0000000..fed253d --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Loop_Active.svg @@ -0,0 +1,58 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Loop_Inactive.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Loop_Inactive.svg new file mode 100644 index 0000000..27ae317 --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Loop_Inactive.svg @@ -0,0 +1,58 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Player_Pause.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Player_Pause.svg new file mode 100644 index 0000000..03eacc1 --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Player_Pause.svg @@ -0,0 +1,37 @@ + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Player_Play.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Player_Play.svg new file mode 100644 index 0000000..7e89297 --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Player_Play.svg @@ -0,0 +1,36 @@ + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Shuffle_Active.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Shuffle_Active.svg new file mode 100644 index 0000000..c2c04f8 --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Shuffle_Active.svg @@ -0,0 +1,56 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Shuffle_Inactive.svg b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Shuffle_Inactive.svg new file mode 100644 index 0000000..068370a --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/AGL_MediaPlayer_Shuffle_Inactive.svg @@ -0,0 +1,56 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/demo3/vertical/videoplayer/app/images/images.qrc b/demo3/vertical/videoplayer/app/images/images.qrc new file mode 100644 index 0000000..fe8a58d --- /dev/null +++ b/demo3/vertical/videoplayer/app/images/images.qrc @@ -0,0 +1,13 @@ + + + AGL_MediaPlayer_BackArrow.svg + AGL_MediaPlayer_DividingLine.svg + AGL_MediaPlayer_ForwardArrow.svg + AGL_MediaPlayer_Loop_Active.svg + AGL_MediaPlayer_Loop_Inactive.svg + AGL_MediaPlayer_Player_Pause.svg + AGL_MediaPlayer_Player_Play.svg + AGL_MediaPlayer_Shuffle_Active.svg + AGL_MediaPlayer_Shuffle_Inactive.svg + + diff --git a/demo3/vertical/videoplayer/app/main.cpp b/demo3/vertical/videoplayer/app/main.cpp new file mode 100644 index 0000000..8227411 --- /dev/null +++ b/demo3/vertical/videoplayer/app/main.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 The Qt Company Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) { + // AGLApplication app(argc, argv); + // app.setApplicationName("VideoPlayer"); + // app.setupApplicationRole("Video"); + // app.load(QUrl(QStringLiteral("qrc:/VideoPlayer.qml"))); + // return app.exec(); + + QString role = QString("Video"); + QGuiApplication app(argc, argv); + + app.setApplicationName("VideoPlayer"); + + QQuickStyle::setStyle("AGL"); + + QQmlApplicationEngine engine; + QQmlContext* context = engine.rootContext(); + + QCommandLineParser parser; + parser.addPositionalArgument("port", + app.translate("main", "port for binding")); + parser.addPositionalArgument("secret", + app.translate("main", "secret for binding")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(app); + QStringList positionalArguments = parser.positionalArguments(); + + if (positionalArguments.length() == 2) { + int port = positionalArguments.takeFirst().toInt(); + QString secret = positionalArguments.takeFirst(); + QUrl bindingAddress; + bindingAddress.setScheme(QStringLiteral("ws")); + bindingAddress.setHost(QStringLiteral("localhost")); + bindingAddress.setPort(port); + bindingAddress.setPath(QStringLiteral("/api")); + QUrlQuery query; + query.addQueryItem(QStringLiteral("token"), secret); + bindingAddress.setQuery(query); + context->setContextProperty(QStringLiteral("bindingAddress"), + bindingAddress); + std::string token = secret.toStdString(); + LibHomeScreen* hs = new LibHomeScreen(); + QLibWindowmanager* qwm = new QLibWindowmanager(); + + QString area; + + // WindowManager + if (qwm->init(port, secret) != 0) { + exit(EXIT_FAILURE); + } + // Request a surface as described in layers.json windowmanager’s file + if (qwm->requestSurface(role) != 0) { + exit(EXIT_FAILURE); + } + + engine.load(QUrl(QStringLiteral("qrc:/VideoPlayer.qml"))); + QObject* root = engine.rootObjects().first(); + + // Create an event callback against an event type. Here a lambda is + // called when SyncDraw event occurs + qwm->set_event_handler( + QLibWindowmanager::Event_SyncDraw, + [qwm, role, &area, root](json_object* object) { + fprintf(stderr, "Surface got syncDraw!\n"); + + // get area + json_object* areaJ = nullptr; + if (json_object_object_get_ex(object, "drawing_area", &areaJ)) { + area = QLatin1String(json_object_get_string(areaJ)); + + QMetaObject::invokeMethod(root, "changeArea", + Q_ARG(QVariant, area)); + } + + qwm->endDraw(role); + }); + + // HomeScreen + hs->init(port, token.c_str()); + // Set the event handler for Event_TapShortcut which will activate the + // surface for windowmanager + hs->set_event_handler( + LibHomeScreen::Event_TapShortcut, [qwm, role](json_object* object) { + qDebug("Surface Video got tapShortcut\n"); + qwm->activateSurface(role); + }); + + // Set the event handler for Event_Restriction which will allocate or + // release restriction area for homescreen + qwm->set_event_handler( + QLibWindowmanager::Event_LightstatusBrakeOff, + [hs, &area](json_object* object) { + qDebug() << "Event_LightstatusBrakeOff!"; + hs->allocateRestriction(area.toStdString().c_str()); + }); + + qwm->set_event_handler( + QLibWindowmanager::Event_LightstatusBrakeOn, + [hs, &area](json_object* object) { + qDebug() << "Event_LightstatusBrakeOn!"; + hs->releaseRestriction(area.toStdString().c_str()); + }); + + QQuickWindow* window = qobject_cast(root); + QObject::connect(window, SIGNAL(frameSwapped()), qwm, + SLOT(slotActivateSurface())); + } + return app.exec(); +} diff --git a/demo3/vertical/videoplayer/app/pkg-config_wrapper.sh b/demo3/vertical/videoplayer/app/pkg-config_wrapper.sh new file mode 100644 index 0000000..02ed39b --- /dev/null +++ b/demo3/vertical/videoplayer/app/pkg-config_wrapper.sh @@ -0,0 +1,6 @@ +#!/bin/sh +PKG_CONFIG_SYSROOT_DIR=/opt/sdk/sysroots/aarch64-agl-linux +export PKG_CONFIG_SYSROOT_DIR +PKG_CONFIG_LIBDIR=/opt/sdk/sysroots/aarch64-agl-linux/usr/lib/pkgconfig:/opt/sdk/sysroots/aarch64-agl-linux/usr/share/pkgconfig +export PKG_CONFIG_LIBDIR +exec pkg-config "$@" diff --git a/demo3/vertical/videoplayer/app/videoplayer.qrc b/demo3/vertical/videoplayer/app/videoplayer.qrc new file mode 100644 index 0000000..a1bbeb0 --- /dev/null +++ b/demo3/vertical/videoplayer/app/videoplayer.qrc @@ -0,0 +1,6 @@ + + + VideoPlayer.qml + api/MediaScanner.qml + + -- cgit 1.2.3-korg