| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /*
- 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 "data/data_media_preload.h"
- #include "data/data_document.h"
- #include "data/data_document_media.h"
- #include "data/data_file_origin.h"
- #include "data/data_photo.h"
- #include "data/data_photo_media.h"
- #include "data/data_session.h"
- #include "main/main_session.h"
- #include "main/main_session_settings.h"
- #include "media/streaming/media_streaming_reader.h"
- #include "storage/file_download.h" // kMaxFileInMemory.
- namespace Data {
- namespace {
- constexpr auto kDefaultPreloadPrefix = 4 * 1024 * 1024;
- [[nodiscard]] int64 ChoosePreloadPrefix(not_null<DocumentData*> video) {
- const auto result = video->videoPreloadPrefix();
- return result
- ? result
- : std::min(int64(kDefaultPreloadPrefix), video->size);
- }
- } // namespace
- MediaPreload::MediaPreload(Fn<void()> done)
- : _done(std::move(done)) {
- }
- void MediaPreload::callDone() {
- if (const auto onstack = _done) {
- onstack();
- }
- }
- PhotoPreload::PhotoPreload(
- not_null<PhotoData*> photo,
- FileOrigin origin,
- Fn<void()> done)
- : MediaPreload(std::move(done))
- , _photo(photo->createMediaView()) {
- start(origin);
- }
- PhotoPreload::~PhotoPreload() {
- if (_photo) {
- base::take(_photo)->owner()->cancel();
- }
- }
- bool PhotoPreload::Should(
- not_null<PhotoData*> photo,
- not_null<PeerData*> context) {
- return !photo->cancelled()
- && AutoDownload::Should(
- photo->session().settings().autoDownload(),
- context,
- photo);
- }
- void PhotoPreload::start(FileOrigin origin) {
- if (_photo->loaded()) {
- callDone();
- } else {
- _photo->owner()->load(origin, LoadFromCloudOrLocal, true);
- _photo->owner()->session().downloaderTaskFinished(
- ) | rpl::filter([=] {
- return _photo->loaded();
- }) | rpl::start_with_next([=] { callDone(); }, _lifetime);
- }
- }
- VideoPreload::VideoPreload(
- not_null<DocumentData*> video,
- FileOrigin origin,
- Fn<void()> done)
- : MediaPreload(std::move(done))
- , DownloadMtprotoTask(
- &video->session().downloader(),
- video->videoPreloadLocation(),
- origin)
- , _video(video)
- , _full(video->size) {
- if (Can(video)) {
- check();
- } else {
- callDone();
- }
- }
- void VideoPreload::check() {
- const auto key = _video->bigFileBaseCacheKey();
- const auto weak = base::make_weak(static_cast<has_weak_ptr*>(this));
- _video->owner().cacheBigFile().get(key, [weak](
- const QByteArray &result) {
- if (!result.isEmpty()) {
- crl::on_main([weak] {
- if (const auto strong = weak.get()) {
- static_cast<VideoPreload*>(strong)->callDone();
- }
- });
- } else {
- crl::on_main([weak] {
- if (const auto strong = weak.get()) {
- static_cast<VideoPreload*>(strong)->load();
- }
- });
- }
- });
- }
- void VideoPreload::load() {
- if (!Can(_video)) {
- callDone();
- return;
- }
- const auto prefix = ChoosePreloadPrefix(_video);
- Assert(prefix > 0 && prefix <= _video->size);
- const auto part = Storage::kDownloadPartSize;
- const auto parts = (prefix + part - 1) / part;
- for (auto i = 0; i != parts; ++i) {
- _parts.emplace(i * part, QByteArray());
- }
- addToQueue();
- }
- void VideoPreload::done(QByteArray result) {
- const auto key = _video->bigFileBaseCacheKey();
- if (!result.isEmpty() && key) {
- Assert(result.size() < Storage::kMaxFileInMemory);
- _video->owner().cacheBigFile().putIfEmpty(
- key,
- Storage::Cache::Database::TaggedValue(std::move(result), 0));
- }
- callDone();
- }
- VideoPreload::~VideoPreload() {
- if (!_finished && !_failed) {
- cancelAllRequests();
- }
- }
- bool VideoPreload::Can(not_null<DocumentData*> video) {
- return video->canBeStreamed(nullptr)
- && video->videoPreloadLocation().valid()
- && video->bigFileBaseCacheKey();
- }
- bool VideoPreload::readyToRequest() const {
- const auto part = Storage::kDownloadPartSize;
- return !_failed && (_nextRequestOffset < _parts.size() * part);
- }
- int64 VideoPreload::takeNextRequestOffset() {
- Expects(readyToRequest());
- _requestedOffsets.emplace(_nextRequestOffset);
- _nextRequestOffset += Storage::kDownloadPartSize;
- return _requestedOffsets.back();
- }
- bool VideoPreload::feedPart(
- int64 offset,
- const QByteArray &bytes) {
- Expects(offset < _parts.size() * Storage::kDownloadPartSize);
- Expects(_requestedOffsets.contains(int(offset)));
- Expects(bytes.size() <= Storage::kDownloadPartSize);
- const auto part = Storage::kDownloadPartSize;
- _requestedOffsets.remove(int(offset));
- _parts[offset] = bytes;
- if ((_nextRequestOffset + part >= _parts.size() * part)
- && _requestedOffsets.empty()) {
- _finished = true;
- removeFromQueue();
- auto result = ::Media::Streaming::SerializeComplexPartsMap(_parts);
- if (result.size() == _full) {
- // Make sure it is parsed as a complex map.
- result.push_back(char(0));
- }
- done(std::move(result));
- }
- return true;
- }
- void VideoPreload::cancelOnFail() {
- _failed = true;
- cancelAllRequests();
- done({});
- }
- bool VideoPreload::setWebFileSizeHook(int64 size) {
- _failed = true;
- cancelAllRequests();
- done({});
- return false;
- }
- } // namespace Data
|