From c5e6a68272e795bdc75ceedf2cb1666acb7e02d9 Mon Sep 17 00:00:00 2001
From: silas <s.developer@4-dc.de>
Date: Thu, 11 Feb 2021 13:27:14 +0100
Subject: [PATCH] Feature complete (seeking)

 - fixed AVPlayer not restarted when transcoding already finished
 - TODO: Fix seeking in paused state results in resuming playback
---
 VanadiumCast/res/gui/fragments/PageMedia.qml  |  2 +-
 .../res/gui/fragments/PageStreaming.qml       | 39 ++++++++++++-------
 backend/backend.pro                           |  8 ++--
 backend/src/API/NetworkAPI.cpp                |  1 +
 backend/src/GUI/VideoGuiLauncher.cpp          |  7 ++--
 .../src/MediaProcessing/VideoTranscoder.cpp   | 20 ++++++++--
 backend/src/MediaProcessing/VideoTranscoder.h | 38 +++++++++---------
 backend/src/Networking/NetworkSinkHandler.cpp |  2 +-
 backend/src/Networking/StreamThread.cpp       |  3 +-
 9 files changed, 73 insertions(+), 47 deletions(-)

diff --git a/VanadiumCast/res/gui/fragments/PageMedia.qml b/VanadiumCast/res/gui/fragments/PageMedia.qml
index 0de70d4..8695bec 100644
--- a/VanadiumCast/res/gui/fragments/PageMedia.qml
+++ b/VanadiumCast/res/gui/fragments/PageMedia.qml
@@ -25,7 +25,7 @@ Page {
     FileDialog {
         id: mediaSelectionDialog
         title: "Please choose a media file"
-        folder: "file:///Users/Silas/Videos/Captures"
+        folder: "file:///home/silas/"
         selectMultiple: false
         selectExisting: true
         selectFolder: false
diff --git a/VanadiumCast/res/gui/fragments/PageStreaming.qml b/VanadiumCast/res/gui/fragments/PageStreaming.qml
index f004c03..15f44a8 100644
--- a/VanadiumCast/res/gui/fragments/PageStreaming.qml
+++ b/VanadiumCast/res/gui/fragments/PageStreaming.qml
@@ -8,6 +8,18 @@ Page {
     property alias togglePlayPauseBtn: playPauseBtn
     property alias positionChangeSlider: positionSlider
 
+    function msToTime(duration) {
+        var seconds = Math.floor((duration / 1000) % 60);
+        var minutes = Math.floor((duration / (1000 * 60)) % 60);
+        var hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
+
+        hours = (hours < 10) ? "0" + hours : hours;
+        minutes = (minutes < 10) ? "0" + minutes : minutes;
+        seconds = (seconds < 10) ? "0" + seconds : seconds;
+
+        return hours + ":" + minutes + ":" + seconds;
+    }
+
     header: Label {
         font.pixelSize: Qt.application.font.pixelSize * 2
         text: qsTr("Streaming Control Panel")
@@ -82,11 +94,18 @@ Page {
         anchors.right: parent.right
         anchors.rightMargin: 20
         id: positionSlider
+
         onPressedChanged: {
             if (!pressed) {
                 backendAPI.seek(value)
             }
         }
+
+        onMoved: {
+            currentPlayPos.text = pageStreaming.msToTime(positionSlider.value)
+//            positionSliderPopup.label.text = msToTime(value)
+        }
+
         from: 0
         value: 0
         to: 100
@@ -100,29 +119,21 @@ Page {
         }
 
         Connections {
-            function msToTime(duration) {
-                var seconds = Math.floor((duration / 1000) % 60);
-                var minutes = Math.floor((duration / (1000 * 60)) % 60);
-                var hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
 
-                hours = (hours < 10) ? "0" + hours : hours;
-                minutes = (minutes < 10) ? "0" + minutes : minutes;
-                seconds = (seconds < 10) ? "0" + seconds : seconds;
-
-                return hours + ":" + minutes + ":" + seconds;
-            }
 
             target: backendAPI
             function onPlaybackPositionChanged(position) {
-                positionSlider.value = position
-                console.log("[PageStreaming] position set:" + position + "/" + positionSlider.to)
-                currentPlayPos.text = msToTime(position)
+                if (!positionSlider.pressed) {
+                    positionSlider.value = position
+                    console.log("[PageStreaming] position set:" + position + "/" + positionSlider.to)
+                    currentPlayPos.text = pageStreaming.msToTime(position)
+                }
             }
 
             function onDurationLoaded(dur) {
                 positionSlider.to = dur
                 console.log("[PageStreaming] duration set")
-                duration.text = "/ " +  msToTime(dur)
+                duration.text = "/ " +  pageStreaming.msToTime(dur)
             }
         }
     }
diff --git a/backend/backend.pro b/backend/backend.pro
index 38a4986..6ba2e38 100644
--- a/backend/backend.pro
+++ b/backend/backend.pro
@@ -50,10 +50,10 @@ unix {
     LIBS += -lQtAV -lQtAVWidgets
     QMAKE_LFLAGS_RPATH=
     QMAKE_LFLAGS += "-Wl,-rpath,\'\$$ORIGIN\'"
-    copyToDestDir($$OUT_PWD/libbackend.so, $$OUT_PWD/VanadiumCast/)
-    copyToDestDir($$OUT_PWD/libbackend.so.1, $$OUT_PWD/VanadiumCast/)
-    copyToDestDir($$OUT_PWD/libbackend.so.1.0, $$OUT_PWD/VanadiumCast/)
-    copyToDestDir($$OUT_PWD/libbackend.so.1.0.0, $$OUT_PWD/VanadiumCast/)
+    copyToDestDir($$OUT_PWD/libbackend.so, $$OUT_PWD/../VanadiumCast/)
+    copyToDestDir($$OUT_PWD/libbackend.so.1, $$OUT_PWD/../VanadiumCast/)
+    copyToDestDir($$OUT_PWD/libbackend.so.1.0, $$OUT_PWD/../VanadiumCast/)
+    copyToDestDir($$OUT_PWD/libbackend.so.1.0.0, $$OUT_PWD/../VanadiumCast/)
 }
 
 
diff --git a/backend/src/API/NetworkAPI.cpp b/backend/src/API/NetworkAPI.cpp
index 8caefe0..4e21b5e 100644
--- a/backend/src/API/NetworkAPI.cpp
+++ b/backend/src/API/NetworkAPI.cpp
@@ -275,6 +275,7 @@ void NetworkAPI::streamThreadFinished() {
     disconnect(streamThreadCon3);
     delete streamThread;
     streamThread = nullptr;
+    firstPositionChange = false;
 }
 
 qint64 NetworkAPI::getDuration() {
diff --git a/backend/src/GUI/VideoGuiLauncher.cpp b/backend/src/GUI/VideoGuiLauncher.cpp
index 3478e4b..128fa55 100644
--- a/backend/src/GUI/VideoGuiLauncher.cpp
+++ b/backend/src/GUI/VideoGuiLauncher.cpp
@@ -42,9 +42,10 @@ bool VideoGuiLauncher::event(QEvent *event) {
                 break;
             }
             case EventAction::START_PLAYER: {
-                qDebug() << "[VideoGui] Starting resetted sink playback";
+                qDebug() << "[VideoGuiLauncher] Starting resetted sink playback";
                 avPlayer->play();
                 if (isPausedByUser) {
+                    qDebug() << "[VideoGuiLauncher] Pausing restarted Player";
                     avPlayer->pause(true);
                 }
                 emit actionFinished();
@@ -108,7 +109,7 @@ void VideoGuiLauncher::create() {
         qDebug() << "[VideoGui] nVidia CUVID decoder selected";
         videoCodecs << "CUDA";
     } else if (vendor.compare("AMD", Qt::CaseInsensitive) == 0) {
-        qDebug() << "[VideoGui] VAAPI decoder selected";
+        qDebug() << "[VideoGui] AMD VAAPI decoder selected";
         videoCodecs << "VAAPI";
     }
 #endif
@@ -120,7 +121,7 @@ void VideoGuiLauncher::create() {
 
     videoCodecs << "FFmpeg";
     avPlayer->setVideoDecoderPriority(videoCodecs);
-    videoRenderer->setPreferredPixelFormat(QtAV::VideoFormat::Format_YUV420P10LE);
+    videoRenderer->setPreferredPixelFormat(QtAV::VideoFormat::Format_YUV420P);
     //            avPlayer->setAutoLoad();
     //            avPlayer->setAsyncLoad();
     bufferCon1 = connect(inputDevice, &End::inputUnderrun, [&]() {
diff --git a/backend/src/MediaProcessing/VideoTranscoder.cpp b/backend/src/MediaProcessing/VideoTranscoder.cpp
index e339eaf..629019e 100644
--- a/backend/src/MediaProcessing/VideoTranscoder.cpp
+++ b/backend/src/MediaProcessing/VideoTranscoder.cpp
@@ -157,7 +157,9 @@ bool VideoTranscoder::isPaused() {
 }
 
 bool VideoTranscoder::seek(qint64 secPos) {
-    if (secPos <= avPlayer->duration() && secPos >= 0) {
+    if (secPos <= duration && secPos >= 0) {
+        qDebug() << "[VideoTranscoder] Seeking AVPlayer in state:" << (avPlayer->state() == QtAV::AVPlayer::PausedState ? "Paused"
+                                                                       : (avPlayer->state() == QtAV::AVPlayer::StoppedState ? "Stopped" : "Playing"));
         switch (avPlayer->state()) {
             case QtAV::AVPlayer::PlayingState: {
                 pause();
@@ -168,18 +170,30 @@ bool VideoTranscoder::seek(qint64 secPos) {
             case QtAV::AVPlayer::PausedState: {
                 avPlayer->setPosition(secPos);
                 resume();
-                QTimer::singleShot(1500, [&]() {
+                QTimer::singleShot(1000, [&]() {
                     pause();
                 });
+                break;
             }
             case QtAV::AVPlayer::StoppedState: {
+                qDebug() << "[VideoTranscoder] Restarting finished AVTranscoder and AVPlayer";
+                avTranscoder->stop();
+                qDebug() << "[VideoTranscoder] Stopped Transcoder";
+                avPlayer->stop();
+                qDebug() << "[VideoTranscoder] Stopped Player";
                 avTranscoder->start();
+                qDebug() << "[VideoTranscoder] Started Transcoder";
+                avPlayer->setStartPosition(secPos);
+                qDebug() << "[VideoTranscoder] Set Player start position";
                 avPlayer->play();
-                avPlayer->setPosition(secPos);
+                qDebug() << "[VideoTranscoder] Started Player";
+                qDebug() << "[VideoTranscoder] Restarted finished AVTranscoder and AVPlayer";
+                break;
             }
         }
         return true;
     }
+    qDebug() << "[VideoTranscoder] Invalid position";
     return false;
 }
 
diff --git a/backend/src/MediaProcessing/VideoTranscoder.h b/backend/src/MediaProcessing/VideoTranscoder.h
index e379e5c..729f647 100644
--- a/backend/src/MediaProcessing/VideoTranscoder.h
+++ b/backend/src/MediaProcessing/VideoTranscoder.h
@@ -106,30 +106,30 @@ private:
 
             // High profile
             HIGH.audioCodecName = "aac";
-            HIGH.videoCodecName = videoCodecSQ;
+            HIGH.videoCodecName = videoCodecHQ;
             HIGH.width = 1920;
             HIGH.height = 1080;
-            HIGH.rate = 10000000;
+            HIGH.rate = 15000000;
             HIGH.framerate = 60;
             HIGH.bytesPerColor = 1;
 
-            // Ultra profile
-            ULTRA.audioCodecName = "aac";
-            ULTRA.videoCodecName = videoCodecHQ;
-            ULTRA.width = 2560;
-            ULTRA.height = 1440;
-            ULTRA.rate = 15000000;
-            ULTRA.framerate = 60;
-            ULTRA.bytesPerColor = 2;
-
-            // Extreme profile
-            EXTREME.audioCodecName = "aac";
-            EXTREME.videoCodecName = videoCodecHQ;
-            EXTREME.width = 3840;
-            EXTREME.height = 2160;
-            EXTREME.rate = 30000000;
-            EXTREME.framerate = 60;
-            EXTREME.bytesPerColor = 2;
+//            // Ultra profile
+//            ULTRA.audioCodecName = "aac";
+//            ULTRA.videoCodecName = videoCodecHQ;
+//            ULTRA.width = 2560;
+//            ULTRA.height = 1440;
+//            ULTRA.rate = 15000000;
+//            ULTRA.framerate = 60;
+//            ULTRA.bytesPerColor = 2;
+
+//            // Extreme profile
+//            EXTREME.audioCodecName = "aac";
+//            EXTREME.videoCodecName = videoCodecHQ;
+//            EXTREME.width = 3840;
+//            EXTREME.height = 2160;
+//            EXTREME.rate = 30000000;
+//            EXTREME.framerate = 60;
+//            EXTREME.bytesPerColor = 2;
 
             encodingProfilesInitialized = true;
         }
diff --git a/backend/src/Networking/NetworkSinkHandler.cpp b/backend/src/Networking/NetworkSinkHandler.cpp
index ad5b95a..86e64d9 100644
--- a/backend/src/Networking/NetworkSinkHandler.cpp
+++ b/backend/src/Networking/NetworkSinkHandler.cpp
@@ -48,7 +48,7 @@ void NetworkSinkHandler::run() {
                 qDebug() << "[NetworkSinkHandler] Answered request";
                 if (dataConnectionServer->waitForNewConnection(30000)) {
                     dataConnection = dataConnectionServer->nextPendingConnection();
-                    cachedLocalStream = new CachedLocalStream(32 * 1024 * 1024, 128, 1024);
+                    cachedLocalStream = new CachedLocalStream(32 * 1024 * 1024, 64, 512);
                     controller = new SinkController(this);
                     videoGuiLauncher = new VideoGuiLauncher(cachedLocalStream->getEnd2());
                     videoGuiLauncher->moveToThread(QApplication::instance()->thread());
diff --git a/backend/src/Networking/StreamThread.cpp b/backend/src/Networking/StreamThread.cpp
index 32aa8a9..9faa3b4 100644
--- a/backend/src/Networking/StreamThread.cpp
+++ b/backend/src/Networking/StreamThread.cpp
@@ -32,7 +32,7 @@ void StreamThread::run() {
                 dataConnection->connectToHost(controlConnection->peerAddress(), 55556);
                 dataConnection->waitForConnected(1000);
                 cachedOutput = new CachedLocalStream(64 * 1024 * 1024, 128, 1024);
-                transcoder = new VideoTranscoder(inputFile, cachedOutput->getEnd2(), VideoTranscoder::MEDIUM);
+                transcoder = new VideoTranscoder(inputFile, cachedOutput->getEnd2(), VideoTranscoder::HIGH);
                 playbackController = new PlaybackController(controlConnection, transcoder, this);
                 qDebug() << "[StreamThread] Playback Controller lives in:" << playbackController->thread();
                 qDebug() << "[StreamThread] StreamThread::run() is running in:" << currentThread();
@@ -252,7 +252,6 @@ bool PlaybackController::isPaused() {
 
 bool PlaybackController::seek(qint64 absPos) {
     streamThread->suspendControlHandling();
-    streamThread->transcoder->pause();
     streamThread->cachedOutput->clear();
     controlConnection->write(Command::SEEK);
     controlConnection->readAll();
-- 
GitLab