diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index 7c035922..e948df02 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -24,23 +24,24 @@ Item { property int tempWidth: originalWidth < 1? 400: originalWidth implicitWidth: type == MtxEvent.VideoMessage ? Math.round(tempWidth*Math.min((timelineView.height/divisor)/(tempWidth*proportionalHeight), 1)) : 500 width: Math.min(parent?.width ?? implicitWidth, implicitWidth) - height: (type == MtxEvent.VideoMessage ? width*proportionalHeight : 80) + fileInfoLabel.height + height: (type == MtxEvent.VideoMessage ? width*proportionalHeight : mediaControls.height) + fileInfoLabel.height //implicitHeight: height property int metadataWidth - property bool fitsMetadata: (parent.width - fileInfoLabel.width) > metadataWidth+4 + property bool fitsMetadata: parent != null ? ((parent.width - fileInfoLabel.width) > metadataWidth+4) : false + + Component.onCompleted: mxcmedia.startDownload(true) MxcMedia { id: mxcmedia // TODO: Show error in overlay or so? roomm: room - // FIXME: This takes 500ms on my device, why and how can we avoid that? - audioOutput: AudioOutput { - muted: mediaControls.muted - volume: mediaControls.desiredVolume - } + eventId: content.eventId videoOutput: videoOutput + + muted: mediaControls.muted + volume: mediaControls.desiredVolume } Rectangle { @@ -56,6 +57,7 @@ Item { Image { anchors.fill: parent + visible: content.type == MtxEvent.VideoMessage source: content.thumbnailUrl ? thumbnailUrl.replace("mxc://", "image://MxcImage/") + "?scale" : "image://colorimage/:/icons/icons/ui/video-file.svg?" + palette.windowText asynchronous: true fillMode: Image.PreserveAspectFit @@ -85,7 +87,7 @@ Item { mediaState: mxcmedia.playbackState onPositionChanged: mxcmedia.position = position onPlayPauseActivated: mxcmedia.playbackState == MediaPlayer.PlayingState ? mxcmedia.pause() : mxcmedia.play() - onLoadActivated: mxcmedia.eventId = eventId + onLoadActivated: mxcmedia.startDownload() } } diff --git a/resources/qml/ui/media/MediaControls.qml b/resources/qml/ui/media/MediaControls.qml index 0519a194..f4373908 100644 --- a/resources/qml/ui/media/MediaControls.qml +++ b/resources/qml/ui/media/MediaControls.qml @@ -71,7 +71,7 @@ Rectangle { spacing: 0 anchors.bottom: control.bottom anchors.left: control.left - anchors.right: control.right + width: Math.max(implicitWidth, control.width) NhekoSlider { Layout.fillWidth: true @@ -134,8 +134,9 @@ Rectangle { state: "" Layout.alignment: Qt.AlignLeft - Layout.preferredWidth: 0 + Layout.preferredWidth: 100 opacity: 0 + enabled: false orientation: Qt.Horizontal value: 1 onDesiredVolumeChanged: { @@ -158,12 +159,6 @@ Rectangle { } } - - NumberAnimation { - properties: "Layout.preferredWidth" - duration: 150 - } - }, Transition { from: "shown" @@ -181,10 +176,6 @@ Rectangle { easing.type: Easing.InQuad } - NumberAnimation { - properties: "Layout.preferredWidth" - duration: 150 - } } @@ -197,28 +188,25 @@ Rectangle { name: "shown" when: Settings.mobileMode || volumeButton.hovered || volumeSlider.hovered || volumeSlider.pressed - PropertyChanges { - volumeSlider.implicitWidth: 100 - } - PropertyChanges { volumeSlider.opacity: 1 + volumeSlider.enabled: true } } } + Item { + Layout.fillWidth: true + } + Label { Layout.alignment: Qt.AlignRight text: (!control.mediaLoaded ? "-- " : durationToString(control.positionValue)) + " / " + durationToString(control.duration) color: palette.text } - Item { - Layout.fillWidth: true - } - } } diff --git a/src/ui/MxcMediaProxy.cpp b/src/ui/MxcMediaProxy.cpp index 5fae0654..3d486f6a 100644 --- a/src/ui/MxcMediaProxy.cpp +++ b/src/ui/MxcMediaProxy.cpp @@ -23,8 +23,6 @@ MxcMediaProxy::MxcMediaProxy(QObject *parent) : QMediaPlayer(parent) { - connect(this, &MxcMediaProxy::eventIdChanged, &MxcMediaProxy::startDownload); - connect(this, &MxcMediaProxy::roomChanged, &MxcMediaProxy::startDownload); connect( this, &QMediaPlayer::errorOccurred, this, [](QMediaPlayer::Error error, QString errorString) { nhlog::ui()->debug("Media player error {} and errorStr {}", @@ -36,6 +34,17 @@ MxcMediaProxy::MxcMediaProxy(QObject *parent) static_cast(status), static_cast(this->error())); }); + connect(this, &MxcMediaProxy::playbackStateChanged, [this](QMediaPlayer::PlaybackState status) { + // We only set the output when starting the playback because otherwise the audio device + // lookup takes about 500ms, which causes a lot of stutter... + if (status == QMediaPlayer::PlayingState && !audioOutput()) { + nhlog::ui()->debug("Set audio output"); + auto newOut = new QAudioOutput(this); + newOut->setMuted(muted_); + newOut->setVolume(volume_); + setAudioOutput(newOut); + } + }); connect(this, &MxcMediaProxy::metaDataChanged, [this]() { emit orientationChanged(); }); connect(ChatPage::instance()->timelineManager()->rooms(), @@ -55,7 +64,7 @@ MxcMediaProxy::orientation() const } void -MxcMediaProxy::startDownload() +MxcMediaProxy::startDownload(bool onlyCached) { if (!room_) return; @@ -126,6 +135,9 @@ MxcMediaProxy::startDownload() } } + if (onlyCached) + return; + http::client()->download(url, [filename, url, processBuffer](const std::string &data, const std::string &, diff --git a/src/ui/MxcMediaProxy.h b/src/ui/MxcMediaProxy.h index 64c61c4f..2e8b2fa1 100644 --- a/src/ui/MxcMediaProxy.h +++ b/src/ui/MxcMediaProxy.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -26,9 +27,16 @@ class MxcMediaProxy : public QMediaPlayer Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged) Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged) + Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ muted WRITE setMuted NOTIFY mutedChanged) public: MxcMediaProxy(QObject *parent = nullptr); + ~MxcMediaProxy() + { + stop(); + this->setSourceDevice(nullptr); + } bool loaded() const { return buffer.size() > 0; } QString eventId() const { return eventId_; } @@ -45,6 +53,25 @@ public: } int orientation() const; + float volume() const { return volume_; } + bool muted() const { return muted_; } + void setVolume(float val) + { + volume_ = val; + if (auto output = audioOutput()) { + output->setVolume(val); + } + emit volumeChanged(); + } + void setMuted(bool val) + { + muted_ = val; + if (auto output = audioOutput()) { + output->setMuted(val); + } + emit mutedChanged(); + } + signals: void roomChanged(); void eventIdChanged(); @@ -52,10 +79,12 @@ signals: void newBuffer(QUrl, QIODevice *buf); void orientationChanged(); - void videoSurfaceChanged(); -private slots: - void startDownload(); + void volumeChanged(); + void mutedChanged(); + +public slots: + void startDownload(bool onlyCached = false); private: TimelineModel *room_ = nullptr; @@ -63,4 +92,6 @@ private: QString filename_; QBuffer buffer; QObject *m_surface = nullptr; + float volume_ = 1.f; + bool muted_ = false; };