From c27456277e4cdddc3841214a9e34f00c6d3ef198 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Mon, 4 Mar 2019 16:26:29 +0400 Subject: [PATCH] Support streaming of local files. --- Telegram/SourceFiles/data/data_document.cpp | 19 +++-- .../media_streaming_loader_local.cpp | 83 +++++++++++++++++++ .../streaming/media_streaming_loader_local.h | 47 +++++++++++ .../media/view/media_view_overlay_widget.cpp | 5 ++ Telegram/gyp/telegram_sources.txt | 2 + 5 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 Telegram/SourceFiles/media/streaming/media_streaming_loader_local.cpp create mode 100644 Telegram/SourceFiles/media/streaming/media_streaming_loader_local.h diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 83e1f4fbef..7f439980df 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwindow.h" #include "core/application.h" #include "media/streaming/media_streaming_loader_mtproto.h" +#include "media/streaming/media_streaming_loader_local.h" namespace { @@ -1214,14 +1215,14 @@ bool DocumentData::inappPlaybackFailed() const { auto DocumentData::createStreamingLoader(Data::FileOrigin origin) const -> std::unique_ptr<Media::Streaming::Loader> { - // #TODO streaming create local file loader - //auto &location = this->location(true); - //if (!_doc->data().isEmpty()) { - // initStreaming(); - //} else if (location.accessEnable()) { - // initStreaming(); - // location.accessDisable(); - //} + const auto &location = this->location(true); + if (!data().isEmpty()) { + return Media::Streaming::MakeBytesLoader(data()); + } else if (!location.isEmpty() && location.accessEnable()) { + auto result = Media::Streaming::MakeFileLoader(location.name()); + location.accessDisable(); + return result; + } return hasRemoteLocation() ? std::make_unique<Media::Streaming::LoaderMtproto>( &session().api(), @@ -1590,7 +1591,7 @@ void HandleUnsupportedMedia( not_null<DocumentData*> document, FullMsgId contextId) { document->setInappPlaybackFailed(); - auto filepath = document->filepath( + const auto filepath = document->filepath( DocumentData::FilePathResolveSaveFromData); if (filepath.isEmpty()) { const auto save = [=] { diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_loader_local.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_loader_local.cpp new file mode 100644 index 0000000000..47c7274714 --- /dev/null +++ b/Telegram/SourceFiles/media/streaming/media_streaming_loader_local.cpp @@ -0,0 +1,83 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "media/streaming/media_streaming_loader_local.h" + +#include "storage/cache/storage_cache_types.h" + +namespace Media { +namespace Streaming { + +LoaderLocal::LoaderLocal(std::unique_ptr<QIODevice> device) +: _device(std::move(device)) { + Expects(_device != nullptr); + + if (!_device->open(QIODevice::ReadOnly)) { + fail(); + } +} + +std::optional<Storage::Cache::Key> LoaderLocal::baseCacheKey() const { + return std::nullopt; +} + +int LoaderLocal::size() const { + return _device->size(); +} + +void LoaderLocal::load(int offset) { + if (_device->pos() != offset && !_device->seek(offset)) { + fail(); + return; + } + auto result = _device->read(kPartSize); + if (result.isEmpty() + || ((result.size() != kPartSize) + && (offset + result.size() != size()))) { + fail(); + return; + } + crl::on_main(this, [=, result = std::move(result)]() mutable { + _parts.fire({ offset, std::move(result) }); + }); +} + +void LoaderLocal::fail() { + crl::on_main(this, [=] { + _parts.fire({ LoadedPart::kFailedOffset }); + }); +} + +void LoaderLocal::cancel(int offset) { +} + +void LoaderLocal::increasePriority() { +} + +void LoaderLocal::stop() { +} + +rpl::producer<LoadedPart> LoaderLocal::parts() const { + return _parts.events(); +} + +std::unique_ptr<LoaderLocal> MakeFileLoader(const QString &path) { + return std::make_unique<LoaderLocal>(std::make_unique<QFile>(path)); +} + +std::unique_ptr<LoaderLocal> MakeBytesLoader(const QByteArray &bytes) { + auto device = std::make_unique<QBuffer>(); + auto copy = new QByteArray(bytes); + QObject::connect(device.get(), &QBuffer::destroyed, [=] { + delete copy; + }); + device->setBuffer(copy); + return std::make_unique<LoaderLocal>(std::move(device)); +} + +} // namespace Streaming +} // namespace Media diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_loader_local.h b/Telegram/SourceFiles/media/streaming/media_streaming_loader_local.h new file mode 100644 index 0000000000..6a856d468b --- /dev/null +++ b/Telegram/SourceFiles/media/streaming/media_streaming_loader_local.h @@ -0,0 +1,47 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "media/streaming/media_streaming_loader.h" +#include "mtproto/sender.h" +#include "data/data_file_origin.h" + +class ApiWrap; + +namespace Media { +namespace Streaming { + +class LoaderLocal : public Loader, public base::has_weak_ptr { +public: + LoaderLocal(std::unique_ptr<QIODevice> device); + + [[nodiscard]] auto baseCacheKey() const + ->std::optional<Storage::Cache::Key> override; + [[nodiscard]] int size() const override; + + void load(int offset) override; + void cancel(int offset) override; + void increasePriority() override; + void stop() override; + + // Parts will be sent from the main thread. + [[nodiscard]] rpl::producer<LoadedPart> parts() const override; + +private: + void fail(); + + std::unique_ptr<QIODevice> _device; + rpl::event_stream<LoadedPart> _parts; + +}; + +std::unique_ptr<LoaderLocal> MakeFileLoader(const QString &path); +std::unique_ptr<LoaderLocal> MakeBytesLoader(const QByteArray &bytes); + +} // namespace Streaming +} // namespace Media diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index bcb8a479b9..c6dfd745f4 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1895,6 +1895,11 @@ void OverlayWidget::initStreamingThumbnail() { const auto thumb = _doc->thumbnail(); const auto useThumb = (thumb && thumb->loaded()); const auto blurred = _doc->thumbnailInline(); + if (good && !useGood) { + good->load({}); + } else if (thumb && !useThumb) { + thumb->load(fileOrigin()); + } if (!useGood && !thumb && !blurred) { return; } else if (_doc->dimensions.isEmpty()) { diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index d3452c8a8e..6063ba3136 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -460,6 +460,8 @@ <(src_loc)/media/streaming/media_streaming_file_delegate.h <(src_loc)/media/streaming/media_streaming_loader.cpp <(src_loc)/media/streaming/media_streaming_loader.h +<(src_loc)/media/streaming/media_streaming_loader_local.cpp +<(src_loc)/media/streaming/media_streaming_loader_local.h <(src_loc)/media/streaming/media_streaming_loader_mtproto.cpp <(src_loc)/media/streaming/media_streaming_loader_mtproto.h <(src_loc)/media/streaming/media_streaming_player.cpp