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