mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Show video userpics in media viewer.
This commit is contained in:
parent
0126578dbd
commit
8c45b5e0f8
15 changed files with 402 additions and 131 deletions
|
@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_photo_media.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/streaming/media_streaming_loader_local.h"
|
||||
#include "media/streaming/media_streaming_loader_mtproto.h"
|
||||
#include "mainwidget.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "core/application.h"
|
||||
|
@ -296,7 +298,8 @@ void PhotoData::updateImages(
|
|||
const ImageWithLocation &small,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &large,
|
||||
const ImageWithLocation &video) {
|
||||
const ImageWithLocation &video,
|
||||
crl::time videoStartTime) {
|
||||
if (!inlineThumbnailBytes.isEmpty()
|
||||
&& _inlineThumbnailBytes.isEmpty()) {
|
||||
_inlineThumbnailBytes = inlineThumbnailBytes;
|
||||
|
@ -318,6 +321,9 @@ void PhotoData::updateImages(
|
|||
update(PhotoSize::Thumbnail, thumbnail);
|
||||
update(PhotoSize::Large, large);
|
||||
|
||||
if (video.location.valid()) {
|
||||
_videoStartTime = videoStartTime;
|
||||
}
|
||||
Data::UpdateCloudFile(
|
||||
_video,
|
||||
video,
|
||||
|
@ -378,6 +384,32 @@ int PhotoData::videoByteSize() const {
|
|||
return _video.byteSize;
|
||||
}
|
||||
|
||||
bool PhotoData::videoCanBePlayed() const {
|
||||
return hasVideo() && !videoPlaybackFailed();
|
||||
}
|
||||
|
||||
auto PhotoData::createStreamingLoader(
|
||||
Data::FileOrigin origin,
|
||||
bool forceRemoteLoader) const
|
||||
-> std::unique_ptr<Media::Streaming::Loader> {
|
||||
if (!hasVideo()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!forceRemoteLoader) {
|
||||
const auto media = activeMediaView();
|
||||
if (media && !media->videoContent().isEmpty()) {
|
||||
return Media::Streaming::MakeBytesLoader(media->videoContent());
|
||||
}
|
||||
}
|
||||
return videoLocation().file().data.is<StorageFileLocation>()
|
||||
? std::make_unique<Media::Streaming::LoaderMtproto>(
|
||||
&session().downloader(),
|
||||
videoLocation().file().data.get_unchecked<StorageFileLocation>(),
|
||||
videoByteSize(),
|
||||
origin)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
PhotoClickHandler::PhotoClickHandler(
|
||||
not_null<PhotoData*> photo,
|
||||
FullMsgId context,
|
||||
|
|
|
@ -14,6 +14,12 @@ namespace Main {
|
|||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Media {
|
||||
namespace Streaming {
|
||||
class Loader;
|
||||
} // namespace Streaming
|
||||
} // namespace Media
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Session;
|
||||
|
@ -83,7 +89,8 @@ public:
|
|||
const ImageWithLocation &small,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &large,
|
||||
const ImageWithLocation &video);
|
||||
const ImageWithLocation &video,
|
||||
crl::time videoStartTime);
|
||||
[[nodiscard]] int validSizeIndex(Data::PhotoSize size) const;
|
||||
|
||||
[[nodiscard]] QByteArray inlineThumbnailBytes() const {
|
||||
|
@ -118,6 +125,20 @@ public:
|
|||
void loadVideo(Data::FileOrigin origin);
|
||||
[[nodiscard]] const ImageLocation &videoLocation() const;
|
||||
[[nodiscard]] int videoByteSize() const;
|
||||
[[nodiscard]] crl::time videoStartPosition() const {
|
||||
return _videoStartTime;
|
||||
}
|
||||
void setVideoPlaybackFailed() {
|
||||
_videoPlaybackFailed = true;
|
||||
}
|
||||
[[nodiscard]] bool videoPlaybackFailed() const {
|
||||
return _videoPlaybackFailed;
|
||||
}
|
||||
[[nodiscard]] bool videoCanBePlayed() const;
|
||||
[[nodiscard]] auto createStreamingLoader(
|
||||
Data::FileOrigin origin,
|
||||
bool forceRemoteLoader) const
|
||||
-> std::unique_ptr<Media::Streaming::Loader>;
|
||||
|
||||
// For now they return size of the 'large' image.
|
||||
int width() const;
|
||||
|
@ -136,6 +157,8 @@ private:
|
|||
QByteArray _inlineThumbnailBytes;
|
||||
std::array<Data::CloudFile, Data::kPhotoSizeCount> _images;
|
||||
Data::CloudFile _video;
|
||||
crl::time _videoStartTime = 0;
|
||||
bool _videoPlaybackFailed = false;
|
||||
|
||||
int32 _dc = 0;
|
||||
uint64 _access = 0;
|
||||
|
|
|
@ -190,6 +190,14 @@ std::vector<UnavailableReason> ExtractUnavailableReasons(
|
|||
return FindInlineThumbnail(data.vsizes().v);
|
||||
}
|
||||
|
||||
[[nodiscard]] int VideoStartTime(const MTPDvideoSize &data) {
|
||||
return int(
|
||||
std::clamp(
|
||||
std::floor(data.vvideo_start_ts().value_or_empty() * 1000),
|
||||
0.,
|
||||
double(std::numeric_limits<int>::max())));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Session::Session(not_null<Main::Session*> session)
|
||||
|
@ -2158,7 +2166,8 @@ not_null<PhotoData*> Session::processPhoto(
|
|||
small,
|
||||
thumbnail,
|
||||
large,
|
||||
ImageWithLocation{});
|
||||
ImageWithLocation{},
|
||||
crl::time(0));
|
||||
}, [&](const MTPDphotoEmpty &data) {
|
||||
return photo(data.vid().v);
|
||||
});
|
||||
|
@ -2175,7 +2184,8 @@ not_null<PhotoData*> Session::photo(
|
|||
const ImageWithLocation &small,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &large,
|
||||
const ImageWithLocation &video) {
|
||||
const ImageWithLocation &video,
|
||||
crl::time videoStartTime) {
|
||||
const auto result = photo(id);
|
||||
photoApplyFields(
|
||||
result,
|
||||
|
@ -2188,7 +2198,8 @@ not_null<PhotoData*> Session::photo(
|
|||
small,
|
||||
thumbnail,
|
||||
large,
|
||||
video);
|
||||
video,
|
||||
videoStartTime);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2237,7 +2248,8 @@ PhotoData *Session::photoFromWeb(
|
|||
ImageWithLocation{},
|
||||
ImageWithLocation{ .location = thumbnailLocation },
|
||||
ImageWithLocation{ .location = large },
|
||||
ImageWithLocation{});
|
||||
ImageWithLocation{},
|
||||
crl::time(0));
|
||||
}
|
||||
|
||||
void Session::photoApplyFields(
|
||||
|
@ -2275,24 +2287,24 @@ void Session::photoApplyFields(
|
|||
? ImageWithLocation()
|
||||
: Images::FromPhotoSize(_session, data, *i);
|
||||
};
|
||||
const auto video = [&] {
|
||||
const auto findVideoSize = [&]() -> std::optional<MTPVideoSize> {
|
||||
const auto sizes = data.vvideo_sizes();
|
||||
if (!sizes || sizes->v.isEmpty()) {
|
||||
return ImageWithLocation();
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto area = [](const MTPVideoSize &size) {
|
||||
return size.match([](const MTPDvideoSize &data) {
|
||||
return data.vw().v * data.vh().v;
|
||||
});
|
||||
};
|
||||
const auto max = ranges::max_element(
|
||||
return *ranges::max_element(
|
||||
sizes->v,
|
||||
std::greater<>(),
|
||||
area);
|
||||
return Images::FromVideoSize(_session, data, *max);
|
||||
};
|
||||
const auto large = image(LargeLevels);
|
||||
if (large.location.valid()) {
|
||||
const auto video = findVideoSize();
|
||||
photoApplyFields(
|
||||
photo,
|
||||
data.vaccess_hash().v,
|
||||
|
@ -2304,7 +2316,13 @@ void Session::photoApplyFields(
|
|||
image(SmallLevels),
|
||||
image(ThumbnailLevels),
|
||||
large,
|
||||
video());
|
||||
(video
|
||||
? Images::FromVideoSize(_session, data, *video)
|
||||
: ImageWithLocation()),
|
||||
(video
|
||||
? VideoStartTime(
|
||||
*video->match([](const auto &data) { return &data; }))
|
||||
: 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2319,7 +2337,8 @@ void Session::photoApplyFields(
|
|||
const ImageWithLocation &small,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &large,
|
||||
const ImageWithLocation &video) {
|
||||
const ImageWithLocation &video,
|
||||
crl::time videoStartTime) {
|
||||
if (!date) {
|
||||
return;
|
||||
}
|
||||
|
@ -2331,7 +2350,8 @@ void Session::photoApplyFields(
|
|||
small,
|
||||
thumbnail,
|
||||
large,
|
||||
video);
|
||||
video,
|
||||
videoStartTime);
|
||||
}
|
||||
|
||||
not_null<DocumentData*> Session::document(DocumentId id) {
|
||||
|
|
|
@ -404,7 +404,8 @@ public:
|
|||
const ImageWithLocation &small,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &large,
|
||||
const ImageWithLocation &video);
|
||||
const ImageWithLocation &video,
|
||||
crl::time videoStartTime);
|
||||
void photoConvert(
|
||||
not_null<PhotoData*> original,
|
||||
const MTPPhoto &data);
|
||||
|
@ -673,7 +674,8 @@ private:
|
|||
const ImageWithLocation &small,
|
||||
const ImageWithLocation &thumbnail,
|
||||
const ImageWithLocation &large,
|
||||
const ImageWithLocation &video);
|
||||
const ImageWithLocation &video,
|
||||
crl::time videoStartTime);
|
||||
|
||||
void documentApplyFields(
|
||||
not_null<DocumentData*> document,
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "data/data_streaming.h"
|
||||
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_file_origin.h"
|
||||
|
@ -19,16 +20,16 @@ namespace {
|
|||
|
||||
constexpr auto kKeepAliveTimeout = 5 * crl::time(1000);
|
||||
|
||||
template <typename Object>
|
||||
template <typename Object, typename Data>
|
||||
bool PruneDestroyedAndSet(
|
||||
base::flat_map<
|
||||
not_null<DocumentData*>,
|
||||
not_null<Data*>,
|
||||
std::weak_ptr<Object>> &objects,
|
||||
not_null<DocumentData*> document,
|
||||
not_null<Data*> data,
|
||||
const std::shared_ptr<Object> &object) {
|
||||
auto result = false;
|
||||
for (auto i = begin(objects); i != end(objects);) {
|
||||
if (i->first == document) {
|
||||
if (i->first == data) {
|
||||
(i++)->second = object;
|
||||
result = true;
|
||||
} else if (i->second.lock() != nullptr) {
|
||||
|
@ -49,54 +50,87 @@ Streaming::Streaming(not_null<Session*> owner)
|
|||
|
||||
Streaming::~Streaming() = default;
|
||||
|
||||
std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
|
||||
not_null<DocumentData*> document,
|
||||
|
||||
template <typename Data>
|
||||
[[nodiscard]] std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
|
||||
base::flat_map<not_null<Data*>, std::weak_ptr<Reader>> &readers,
|
||||
not_null<Data*> data,
|
||||
FileOrigin origin,
|
||||
bool forceRemoteLoader) {
|
||||
const auto i = _readers.find(document);
|
||||
if (i != end(_readers)) {
|
||||
const auto i = readers.find(data);
|
||||
if (i != end(readers)) {
|
||||
if (auto result = i->second.lock()) {
|
||||
if (!forceRemoteLoader || result->isRemoteLoader()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto loader = document->createStreamingLoader(origin, forceRemoteLoader);
|
||||
auto loader = data->createStreamingLoader(origin, forceRemoteLoader);
|
||||
if (!loader) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = std::make_shared<Reader>(
|
||||
std::move(loader),
|
||||
&_owner->cacheBigFile());
|
||||
if (!PruneDestroyedAndSet(_readers, document, result)) {
|
||||
_readers.emplace_or_assign(document, result);
|
||||
if (!PruneDestroyedAndSet(readers, data, result)) {
|
||||
readers.emplace_or_assign(data, result);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
template <typename Data>
|
||||
[[nodiscard]] std::shared_ptr<Streaming::Document> Streaming::sharedDocument(
|
||||
base::flat_map<not_null<Data*>, std::weak_ptr<Document>> &documents,
|
||||
base::flat_map<not_null<Data*>, std::weak_ptr<Reader>> &readers,
|
||||
not_null<Data*> data,
|
||||
FileOrigin origin) {
|
||||
const auto i = documents.find(data);
|
||||
if (i != end(documents)) {
|
||||
if (auto result = i->second.lock()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
auto reader = sharedReader(readers, data, origin);
|
||||
if (!reader) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = std::make_shared<Document>(data, std::move(reader));
|
||||
if (!PruneDestroyedAndSet(documents, data, result)) {
|
||||
documents.emplace_or_assign(data, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
|
||||
not_null<DocumentData*> document,
|
||||
FileOrigin origin,
|
||||
bool forceRemoteLoader) {
|
||||
return sharedReader(_fileReaders, document, origin, forceRemoteLoader);
|
||||
}
|
||||
|
||||
std::shared_ptr<Streaming::Document> Streaming::sharedDocument(
|
||||
not_null<DocumentData*> document,
|
||||
FileOrigin origin) {
|
||||
const auto i = _documents.find(document);
|
||||
if (i != end(_documents)) {
|
||||
if (auto result = i->second.lock()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
auto reader = sharedReader(document, origin);
|
||||
if (!reader) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = std::make_shared<Document>(document, std::move(reader));
|
||||
if (!PruneDestroyedAndSet(_documents, document, result)) {
|
||||
_documents.emplace_or_assign(document, result);
|
||||
}
|
||||
return result;
|
||||
return sharedDocument(_fileDocuments, _fileReaders, document, origin);
|
||||
}
|
||||
|
||||
std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
|
||||
not_null<PhotoData*> photo,
|
||||
FileOrigin origin,
|
||||
bool forceRemoteLoader) {
|
||||
return sharedReader(_photoReaders, photo, origin, forceRemoteLoader);
|
||||
}
|
||||
|
||||
std::shared_ptr<Streaming::Document> Streaming::sharedDocument(
|
||||
not_null<PhotoData*> photo,
|
||||
FileOrigin origin) {
|
||||
return sharedDocument(_photoDocuments, _photoReaders, photo, origin);
|
||||
}
|
||||
|
||||
void Streaming::keepAlive(not_null<DocumentData*> document) {
|
||||
const auto i = _documents.find(document);
|
||||
if (i == end(_documents)) {
|
||||
const auto i = _fileDocuments.find(document);
|
||||
if (i == end(_fileDocuments)) {
|
||||
return;
|
||||
}
|
||||
auto shared = i->second.lock();
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "base/timer.h"
|
||||
|
||||
class PhotoData;
|
||||
class DocumentData;
|
||||
|
||||
namespace Media {
|
||||
|
@ -41,17 +42,46 @@ public:
|
|||
not_null<DocumentData*> document,
|
||||
FileOrigin origin);
|
||||
|
||||
[[nodiscard]] std::shared_ptr<Reader> sharedReader(
|
||||
not_null<PhotoData*> photo,
|
||||
FileOrigin origin,
|
||||
bool forceRemoteLoader = false);
|
||||
[[nodiscard]] std::shared_ptr<Document> sharedDocument(
|
||||
not_null<PhotoData*> photo,
|
||||
FileOrigin origin);
|
||||
|
||||
void keepAlive(not_null<DocumentData*> document);
|
||||
|
||||
private:
|
||||
void clearKeptAlive();
|
||||
|
||||
template <typename Data>
|
||||
[[nodiscard]] std::shared_ptr<Reader> sharedReader(
|
||||
base::flat_map<not_null<Data*>, std::weak_ptr<Reader>> &readers,
|
||||
not_null<Data*> data,
|
||||
FileOrigin origin,
|
||||
bool forceRemoteLoader = false);
|
||||
|
||||
template <typename Data>
|
||||
[[nodiscard]] std::shared_ptr<Document> sharedDocument(
|
||||
base::flat_map<not_null<Data*>, std::weak_ptr<Document>> &documents,
|
||||
base::flat_map<not_null<Data*>, std::weak_ptr<Reader>> &readers,
|
||||
not_null<Data*> data,
|
||||
FileOrigin origin);
|
||||
|
||||
const not_null<Session*> _owner;
|
||||
|
||||
base::flat_map<not_null<DocumentData*>, std::weak_ptr<Reader>> _readers;
|
||||
base::flat_map<
|
||||
not_null<DocumentData*>,
|
||||
std::weak_ptr<Document>> _documents;
|
||||
std::weak_ptr<Reader>> _fileReaders;
|
||||
base::flat_map<
|
||||
not_null<DocumentData*>,
|
||||
std::weak_ptr<Document>> _fileDocuments;
|
||||
|
||||
base::flat_map<not_null<PhotoData*>, std::weak_ptr<Reader>> _photoReaders;
|
||||
base::flat_map<
|
||||
not_null<PhotoData*>,
|
||||
std::weak_ptr<Document>> _photoDocuments;
|
||||
|
||||
base::flat_map<std::shared_ptr<Document>, crl::time> _keptAlive;
|
||||
base::Timer _keptAliveTimer;
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "media/streaming/media_streaming_reader.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -34,19 +35,29 @@ constexpr auto kGoodThumbnailQuality = 87;
|
|||
Document::Document(
|
||||
not_null<DocumentData*> document,
|
||||
std::shared_ptr<Reader> reader)
|
||||
: Document(std::move(reader), document) {
|
||||
: Document(std::move(reader), document, nullptr) {
|
||||
_player.fullInCache(
|
||||
) | rpl::start_with_next([=](bool fullInCache) {
|
||||
_document->setLoadedInMediaCache(fullInCache);
|
||||
}, _player.lifetime());
|
||||
}
|
||||
|
||||
Document::Document(std::unique_ptr<Loader> loader)
|
||||
: Document(std::make_shared<Reader>(std::move(loader)), nullptr) {
|
||||
Document::Document(
|
||||
not_null<PhotoData*> photo,
|
||||
std::shared_ptr<Reader> reader)
|
||||
: Document(std::move(reader), nullptr, photo) {
|
||||
}
|
||||
|
||||
Document::Document(std::shared_ptr<Reader> reader, DocumentData *document)
|
||||
Document::Document(std::unique_ptr<Loader> loader)
|
||||
: Document(std::make_shared<Reader>(std::move(loader)), nullptr, nullptr) {
|
||||
}
|
||||
|
||||
Document::Document(
|
||||
std::shared_ptr<Reader> reader,
|
||||
DocumentData *document,
|
||||
PhotoData *photo)
|
||||
: _document(document)
|
||||
, _photo(photo)
|
||||
, _player(std::move(reader))
|
||||
, _radial(
|
||||
[=] { waitingCallback(); },
|
||||
|
@ -71,10 +82,6 @@ const Information &Document::info() const {
|
|||
return _info;
|
||||
}
|
||||
|
||||
//not_null<DocumentData*> Document::data() const {
|
||||
// return _document;
|
||||
//}
|
||||
|
||||
void Document::play(const PlaybackOptions &options) {
|
||||
_player.play(options);
|
||||
_info.audio.state.position
|
||||
|
@ -160,6 +167,10 @@ void Document::handleError(Error &&error) {
|
|||
} else if (error == Error::OpenFailed) {
|
||||
_document->setInappPlaybackFailed();
|
||||
}
|
||||
} else if (_photo) {
|
||||
if (error == Error::NotStreamable || error == Error::OpenFailed) {
|
||||
_photo->setVideoPlaybackFailed();
|
||||
}
|
||||
}
|
||||
waitingChange(false);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ public:
|
|||
Document(
|
||||
not_null<DocumentData*> document,
|
||||
std::shared_ptr<Reader> reader);
|
||||
Document(
|
||||
not_null<PhotoData*> photo,
|
||||
std::shared_ptr<Reader> reader);
|
||||
explicit Document(std::unique_ptr<Loader> loader);
|
||||
|
||||
void play(const PlaybackOptions &options);
|
||||
|
@ -33,14 +36,16 @@ public:
|
|||
[[nodiscard]] Player &player();
|
||||
[[nodiscard]] const Player &player() const;
|
||||
[[nodiscard]] const Information &info() const;
|
||||
// [[nodiscard]] not_null<DocumentData*> data() const;
|
||||
|
||||
[[nodiscard]] bool waitingShown() const;
|
||||
[[nodiscard]] float64 waitingOpacity() const;
|
||||
[[nodiscard]] Ui::RadialState waitingState() const;
|
||||
|
||||
private:
|
||||
Document(std::shared_ptr<Reader> reader, DocumentData *document);
|
||||
Document(
|
||||
std::shared_ptr<Reader> reader,
|
||||
DocumentData *document,
|
||||
PhotoData *photo);
|
||||
|
||||
friend class Instance;
|
||||
|
||||
|
@ -59,6 +64,7 @@ private:
|
|||
void validateGoodThumbnail();
|
||||
|
||||
DocumentData *_document = nullptr;
|
||||
PhotoData *_photo = nullptr;
|
||||
Player _player;
|
||||
Information _info;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "media/streaming/media_streaming_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_streaming.h"
|
||||
|
@ -35,6 +36,15 @@ Instance::Instance(
|
|||
std::move(waitingCallback)) {
|
||||
}
|
||||
|
||||
Instance::Instance(
|
||||
not_null<PhotoData*> photo,
|
||||
Data::FileOrigin origin,
|
||||
Fn<void()> waitingCallback)
|
||||
: Instance(
|
||||
photo->owner().streaming().sharedDocument(photo, origin),
|
||||
std::move(waitingCallback)) {
|
||||
}
|
||||
|
||||
Instance::~Instance() {
|
||||
if (_shared) {
|
||||
unlockPlayer();
|
||||
|
|
|
@ -34,6 +34,10 @@ public:
|
|||
not_null<DocumentData*> document,
|
||||
Data::FileOrigin origin,
|
||||
Fn<void()> waitingCallback);
|
||||
Instance(
|
||||
not_null<PhotoData*> photo,
|
||||
Data::FileOrigin origin,
|
||||
Fn<void()> waitingCallback);
|
||||
~Instance();
|
||||
|
||||
[[nodiscard]] bool valid() const;
|
||||
|
|
|
@ -130,7 +130,7 @@ QWidget *PipDelegate::pipParentWidget() {
|
|||
return _parent;
|
||||
}
|
||||
|
||||
Images::Options VideoThumbOptions(not_null<DocumentData*> document) {
|
||||
Images::Options VideoThumbOptions(DocumentData *document) {
|
||||
const auto result = Images::Option::Smooth | Images::Option::Blurred;
|
||||
return (document && document->isVideoMessage())
|
||||
? (result | Images::Option::Circled)
|
||||
|
@ -240,6 +240,12 @@ struct OverlayWidget::Streamed {
|
|||
QWidget *controlsParent,
|
||||
not_null<PlaybackControls::Delegate*> controlsDelegate,
|
||||
Fn<void()> waitingCallback);
|
||||
Streamed(
|
||||
not_null<PhotoData*> photo,
|
||||
Data::FileOrigin origin,
|
||||
QWidget *controlsParent,
|
||||
not_null<PlaybackControls::Delegate*> controlsDelegate,
|
||||
Fn<void()> waitingCallback);
|
||||
|
||||
Streaming::Instance instance;
|
||||
PlaybackControls controls;
|
||||
|
@ -277,6 +283,16 @@ OverlayWidget::Streamed::Streamed(
|
|||
, controls(controlsParent, controlsDelegate) {
|
||||
}
|
||||
|
||||
OverlayWidget::Streamed::Streamed(
|
||||
not_null<PhotoData*> photo,
|
||||
Data::FileOrigin origin,
|
||||
QWidget *controlsParent,
|
||||
not_null<PlaybackControls::Delegate*> controlsDelegate,
|
||||
Fn<void()> waitingCallback)
|
||||
: instance(photo, origin, std::move(waitingCallback))
|
||||
, controls(controlsParent, controlsDelegate) {
|
||||
}
|
||||
|
||||
OverlayWidget::PipWrap::PipWrap(
|
||||
QWidget *parent,
|
||||
not_null<DocumentData*> document,
|
||||
|
@ -356,7 +372,7 @@ OverlayWidget::OverlayWidget()
|
|||
|
||||
Core::App().calls().currentCallValue(
|
||||
) | rpl::start_with_next([=](Calls::Call *call) {
|
||||
if (!_streamed) {
|
||||
if (!_streamed || videoIsGifOrUserpic()) {
|
||||
return;
|
||||
} else if (call) {
|
||||
playbackPauseOnCall();
|
||||
|
@ -441,8 +457,10 @@ QSize OverlayWidget::videoSize() const {
|
|||
return flipSizeByRotation(_streamed->instance.info().video.size);
|
||||
}
|
||||
|
||||
bool OverlayWidget::videoIsGifv() const {
|
||||
return _streamed && _document->isAnimation() && !_document->isVideoMessage();
|
||||
bool OverlayWidget::videoIsGifOrUserpic() const {
|
||||
return _streamed
|
||||
&& (!_document
|
||||
|| (_document->isAnimation() && !_document->isVideoMessage()));
|
||||
}
|
||||
|
||||
QImage OverlayWidget::videoFrame() const {
|
||||
|
@ -709,7 +727,7 @@ void OverlayWidget::refreshCaptionGeometry() {
|
|||
_groupThumbs = nullptr;
|
||||
_groupThumbsRect = QRect();
|
||||
}
|
||||
const auto captionBottom = (_streamed && !videoIsGifv())
|
||||
const auto captionBottom = (_streamed && !videoIsGifOrUserpic())
|
||||
? (_streamed->controls.y() - st::mediaviewCaptionMargin.height())
|
||||
: _groupThumbs
|
||||
? _groupThumbsTop
|
||||
|
@ -884,7 +902,7 @@ void OverlayWidget::contentSizeChanged() {
|
|||
}
|
||||
|
||||
void OverlayWidget::resizeContentByScreenSize() {
|
||||
const auto bottom = (!_streamed || videoIsGifv())
|
||||
const auto bottom = (!_streamed || videoIsGifOrUserpic())
|
||||
? height()
|
||||
: (_streamed->controls.y()
|
||||
- st::mediaviewCaptionPadding.bottom()
|
||||
|
@ -942,8 +960,10 @@ float64 OverlayWidget::radialProgress() const {
|
|||
}
|
||||
|
||||
bool OverlayWidget::radialLoading() const {
|
||||
if (_document) {
|
||||
return _document->loading() && !_streamed;
|
||||
if (_streamed) {
|
||||
return false;
|
||||
} else if (_document) {
|
||||
return _document->loading();
|
||||
} else if (_photo) {
|
||||
return _photo->displayLoading();
|
||||
}
|
||||
|
@ -1133,7 +1153,9 @@ void OverlayWidget::assignMediaPointer(not_null<PhotoData*> photo) {
|
|||
_photo = photo;
|
||||
_photoMedia = _photo->createMediaView();
|
||||
_photoMedia->wanted(Data::PhotoSize::Small, fileOrigin());
|
||||
_photo->load(fileOrigin(), LoadFromCloudOrLocal, true);
|
||||
if (!_photo->hasVideo() || _photo->videoPlaybackFailed()) {
|
||||
_photo->load(fileOrigin(), LoadFromCloudOrLocal, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1186,7 +1208,7 @@ void OverlayWidget::onHideControls(bool force) {
|
|||
|| _menu
|
||||
|| _mousePressed
|
||||
|| (_fullScreenVideo
|
||||
&& !videoIsGifv()
|
||||
&& !videoIsGifOrUserpic()
|
||||
&& _streamed->controls.geometry().contains(_lastMouseMovePos))) {
|
||||
return;
|
||||
}
|
||||
|
@ -1307,7 +1329,9 @@ void OverlayWidget::onSaveAs() {
|
|||
updateOver(_lastMouseMovePos);
|
||||
}
|
||||
} else {
|
||||
if (!_photo || !_photoMedia->loaded()) return;
|
||||
if (!_photo || !_photoMedia->loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto image = _photoMedia->image(Data::PhotoSize::Large)->original();
|
||||
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
|
||||
|
@ -1858,7 +1882,7 @@ void OverlayWidget::refreshCaption(HistoryItem *item) {
|
|||
|
||||
using namespace HistoryView;
|
||||
_caption = Ui::Text::String(st::msgMinWidth);
|
||||
const auto duration = (_streamed && !videoIsGifv())
|
||||
const auto duration = (_streamed && _document && !videoIsGifOrUserpic())
|
||||
? _document->getDuration()
|
||||
: 0;
|
||||
const auto base = duration
|
||||
|
@ -2045,18 +2069,29 @@ void OverlayWidget::displayPhoto(not_null<PhotoData*> photo, HistoryItem *item)
|
|||
_radial.stop();
|
||||
|
||||
refreshMediaViewer();
|
||||
|
||||
_staticContent = QPixmap();
|
||||
if (_photo->videoCanBePlayed()) {
|
||||
initStreaming();
|
||||
}
|
||||
|
||||
refreshCaption(item);
|
||||
|
||||
_zoom = 0;
|
||||
_zoomToScreen = _zoomToDefault = 0;
|
||||
_blurred = true;
|
||||
_staticContent = QPixmap();
|
||||
_down = OverNone;
|
||||
const auto size = style::ConvertScale(flipSizeByRotation(QSize(
|
||||
photo->width(),
|
||||
photo->height())));
|
||||
_w = size.width();
|
||||
_h = size.height();
|
||||
if (!_staticContent.isNull()) {
|
||||
// Video thumbnail.
|
||||
const auto size = style::ConvertScale(
|
||||
flipSizeByRotation(_staticContent.size()));
|
||||
_w = size.width();
|
||||
_h = size.height();
|
||||
} else {
|
||||
const auto size = style::ConvertScale(flipSizeByRotation(QSize(
|
||||
photo->width(),
|
||||
photo->height())));
|
||||
_w = size.width();
|
||||
_h = size.height();
|
||||
}
|
||||
contentSizeChanged();
|
||||
refreshFromLabel(item);
|
||||
displayFinished();
|
||||
|
@ -2252,16 +2287,24 @@ void OverlayWidget::displayFinished() {
|
|||
}
|
||||
}
|
||||
|
||||
bool OverlayWidget::canInitStreaming() const {
|
||||
return (_document && _documentMedia->canBePlayed())
|
||||
|| (_photo && _photo->videoCanBePlayed());
|
||||
}
|
||||
|
||||
bool OverlayWidget::initStreaming(bool continueStreaming) {
|
||||
Expects(_document != nullptr);
|
||||
Expects(_documentMedia->canBePlayed());
|
||||
Expects(canInitStreaming());
|
||||
|
||||
if (_streamed) {
|
||||
return true;
|
||||
}
|
||||
initStreamingThumbnail();
|
||||
if (!createStreamingObjects()) {
|
||||
_document->setInappPlaybackFailed();
|
||||
if (_document) {
|
||||
_document->setInappPlaybackFailed();
|
||||
} else {
|
||||
_photo->setVideoPlaybackFailed();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2301,22 +2344,47 @@ void OverlayWidget::startStreamingPlayer() {
|
|||
|
||||
const auto position = _document
|
||||
? _document->session().settings().mediaLastPlaybackPosition(_document->id)
|
||||
: _photo
|
||||
? _photo->videoStartPosition()
|
||||
: 0;
|
||||
restartAtSeekPosition(position);
|
||||
}
|
||||
|
||||
void OverlayWidget::initStreamingThumbnail() {
|
||||
Expects(_document != nullptr);
|
||||
Expects(_photo || _document);
|
||||
|
||||
_touchbarDisplay.fire(TouchBarItemType::Video);
|
||||
|
||||
const auto good = _documentMedia->goodThumbnail();
|
||||
const auto useGood = (good != nullptr);
|
||||
const auto thumbnail = _documentMedia->thumbnail();
|
||||
const auto useThumb = (thumbnail != nullptr);
|
||||
const auto blurred = _documentMedia->thumbnailInline();
|
||||
const auto size = useGood ? good->size() : _document->dimensions;
|
||||
if (!useGood && !thumbnail && !blurred) {
|
||||
const auto computePhotoThumbnail = [&] {
|
||||
const auto thumbnail = _photoMedia->image(Data::PhotoSize::Thumbnail);
|
||||
if (thumbnail) {
|
||||
return thumbnail;
|
||||
} else if (_peer && _peer->userpicPhotoId() == _photo->id) {
|
||||
if (const auto view = _peer->activeUserpicView()) {
|
||||
if (const auto image = view->image()) {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
return thumbnail;
|
||||
};
|
||||
const auto good = _document
|
||||
? _documentMedia->goodThumbnail()
|
||||
: _photoMedia->image(Data::PhotoSize::Large);
|
||||
const auto thumbnail = _document
|
||||
? _documentMedia->thumbnail()
|
||||
: computePhotoThumbnail();
|
||||
const auto blurred = _document
|
||||
? _documentMedia->thumbnailInline()
|
||||
: _photoMedia->thumbnailInline();
|
||||
const auto size = _photo
|
||||
? QSize(
|
||||
_photo->videoLocation().width(),
|
||||
_photo->videoLocation().height())
|
||||
: good
|
||||
? good->size()
|
||||
: _document->dimensions;
|
||||
if (!good && !thumbnail && !blurred) {
|
||||
return;
|
||||
} else if (size.isEmpty()) {
|
||||
return;
|
||||
|
@ -2325,16 +2393,16 @@ void OverlayWidget::initStreamingThumbnail() {
|
|||
const auto h = size.height();
|
||||
const auto options = VideoThumbOptions(_document);
|
||||
const auto goodOptions = (options & ~Images::Option::Blurred);
|
||||
_staticContent = (useGood
|
||||
_staticContent = (good
|
||||
? good
|
||||
: useThumb
|
||||
: thumbnail
|
||||
? thumbnail
|
||||
: blurred
|
||||
? blurred
|
||||
: Image::BlankMedia().get())->pixNoCache(
|
||||
w,
|
||||
h,
|
||||
useGood ? goodOptions : options,
|
||||
good ? goodOptions : options,
|
||||
w / cIntRetinaFactor(),
|
||||
h / cIntRetinaFactor());
|
||||
_staticContent.setDevicePixelRatio(cRetinaFactor());
|
||||
|
@ -2358,24 +2426,36 @@ void OverlayWidget::applyVideoSize() {
|
|||
}
|
||||
|
||||
bool OverlayWidget::createStreamingObjects() {
|
||||
_streamed = std::make_unique<Streamed>(
|
||||
_document,
|
||||
fileOrigin(),
|
||||
this,
|
||||
static_cast<PlaybackControls::Delegate*>(this),
|
||||
[=] { waitingAnimationCallback(); });
|
||||
Expects(_photo || _document);
|
||||
|
||||
if (_document) {
|
||||
_streamed = std::make_unique<Streamed>(
|
||||
_document,
|
||||
fileOrigin(),
|
||||
this,
|
||||
static_cast<PlaybackControls::Delegate*>(this),
|
||||
[=] { waitingAnimationCallback(); });
|
||||
} else {
|
||||
_streamed = std::make_unique<Streamed>(
|
||||
_photo,
|
||||
fileOrigin(),
|
||||
this,
|
||||
static_cast<PlaybackControls::Delegate*>(this),
|
||||
[=] { waitingAnimationCallback(); });
|
||||
}
|
||||
if (!_streamed->instance.valid()) {
|
||||
_streamed = nullptr;
|
||||
return false;
|
||||
}
|
||||
_streamed->instance.setPriority(kOverlayLoaderPriority);
|
||||
_streamed->instance.lockPlayer();
|
||||
_streamed->withSound = _document->isAudioFile()
|
||||
|| _document->isVideoFile()
|
||||
|| _document->isVoiceMessage()
|
||||
|| _document->isVideoMessage();
|
||||
_streamed->withSound = _document
|
||||
&& (_document->isAudioFile()
|
||||
|| _document->isVideoFile()
|
||||
|| _document->isVoiceMessage()
|
||||
|| _document->isVideoMessage());
|
||||
|
||||
if (videoIsGifv()) {
|
||||
if (videoIsGifOrUserpic()) {
|
||||
_streamed->controls.hide();
|
||||
} else {
|
||||
refreshClipControllerGeometry();
|
||||
|
@ -2430,17 +2510,25 @@ void OverlayWidget::handleStreamingUpdate(Streaming::Update &&update) {
|
|||
}
|
||||
|
||||
void OverlayWidget::handleStreamingError(Streaming::Error &&error) {
|
||||
Expects(_document != nullptr);
|
||||
Expects(_document || _photo);
|
||||
|
||||
if (error == Streaming::Error::NotStreamable) {
|
||||
_document->setNotSupportsStreaming();
|
||||
if (_document) {
|
||||
_document->setNotSupportsStreaming();
|
||||
} else {
|
||||
_photo->setVideoPlaybackFailed();
|
||||
}
|
||||
} else if (error == Streaming::Error::OpenFailed) {
|
||||
_document->setInappPlaybackFailed();
|
||||
if (_document) {
|
||||
_document->setInappPlaybackFailed();
|
||||
} else {
|
||||
_photo->setVideoPlaybackFailed();
|
||||
}
|
||||
}
|
||||
if (!_documentMedia->canBePlayed()) {
|
||||
redisplayContent();
|
||||
} else {
|
||||
if (canInitStreaming()) {
|
||||
updatePlaybackState();
|
||||
} else {
|
||||
redisplayContent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2543,7 +2631,7 @@ void OverlayWidget::initThemePreview() {
|
|||
}
|
||||
|
||||
void OverlayWidget::refreshClipControllerGeometry() {
|
||||
if (!_streamed || videoIsGifv()) {
|
||||
if (!_streamed || videoIsGifOrUserpic()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2578,7 +2666,7 @@ void OverlayWidget::playbackControlsFromFullScreen() {
|
|||
}
|
||||
|
||||
void OverlayWidget::playbackControlsToPictureInPicture() {
|
||||
if (!videoIsGifv()) {
|
||||
if (!videoIsGifOrUserpic()) {
|
||||
switchToPip();
|
||||
}
|
||||
}
|
||||
|
@ -2608,7 +2696,7 @@ void OverlayWidget::playbackPauseResume() {
|
|||
_streamed->resumeOnCallEnd = false;
|
||||
if (_streamed->instance.player().failed()) {
|
||||
clearStreaming();
|
||||
if (!_documentMedia->canBePlayed() || !initStreaming()) {
|
||||
if (!canInitStreaming() || !initStreaming()) {
|
||||
redisplayContent();
|
||||
}
|
||||
} else if (_streamed->instance.player().finished()
|
||||
|
@ -2627,7 +2715,6 @@ void OverlayWidget::playbackPauseResume() {
|
|||
|
||||
void OverlayWidget::restartAtSeekPosition(crl::time position) {
|
||||
Expects(_streamed != nullptr);
|
||||
Expects(_document != nullptr);
|
||||
|
||||
if (videoShown()) {
|
||||
_streamed->instance.saveFrameToCover();
|
||||
|
@ -2638,11 +2725,12 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
|
|||
}
|
||||
auto options = Streaming::PlaybackOptions();
|
||||
options.position = position;
|
||||
options.audioId = AudioMsgId(_document, _msgid);
|
||||
if (!_streamed->withSound) {
|
||||
options.mode = Streaming::Mode::Video;
|
||||
options.loop = true;
|
||||
} else {
|
||||
Assert(_document != nullptr);
|
||||
options.audioId = AudioMsgId(_document, _msgid);
|
||||
options.speed = Core::App().settings().videoPlaybackSpeed();
|
||||
if (_pip) {
|
||||
_pip = nullptr;
|
||||
|
@ -2706,7 +2794,7 @@ void OverlayWidget::playbackControlsSpeedChanged(float64 speed) {
|
|||
Core::App().settings().setVideoPlaybackSpeed(speed);
|
||||
Core::App().saveSettingsDelayed();
|
||||
}
|
||||
if (_streamed && !videoIsGifv()) {
|
||||
if (_streamed && !videoIsGifOrUserpic()) {
|
||||
DEBUG_LOG(("Media playback speed: %1 to _streamed.").arg(speed));
|
||||
_streamed->instance.setSpeed(speed);
|
||||
}
|
||||
|
@ -2743,7 +2831,7 @@ void OverlayWidget::switchToPip() {
|
|||
void OverlayWidget::playbackToggleFullScreen() {
|
||||
Expects(_streamed != nullptr);
|
||||
|
||||
if (!videoShown() || (videoIsGifv() && !_fullScreenVideo)) {
|
||||
if (!videoShown() || (videoIsGifOrUserpic() && !_fullScreenVideo)) {
|
||||
return;
|
||||
}
|
||||
_fullScreenVideo = !_fullScreenVideo;
|
||||
|
@ -2797,7 +2885,7 @@ void OverlayWidget::playbackPauseMusic() {
|
|||
void OverlayWidget::updatePlaybackState() {
|
||||
Expects(_streamed != nullptr);
|
||||
|
||||
if (videoIsGifv()) {
|
||||
if (videoIsGifOrUserpic()) {
|
||||
return;
|
||||
}
|
||||
const auto state = _streamed->instance.player().prepareLegacyState();
|
||||
|
|
|
@ -283,7 +283,7 @@ private:
|
|||
void refreshClipControllerGeometry();
|
||||
void refreshCaptionGeometry();
|
||||
|
||||
[[nodiscard]] bool initStreaming(bool continueStreaming = false);
|
||||
bool initStreaming(bool continueStreaming = false);
|
||||
void startStreamingPlayer();
|
||||
void initStreamingThumbnail();
|
||||
void streamingReady(Streaming::Information &&info);
|
||||
|
@ -346,7 +346,7 @@ private:
|
|||
void applyVideoSize();
|
||||
[[nodiscard]] bool videoShown() const;
|
||||
[[nodiscard]] QSize videoSize() const;
|
||||
[[nodiscard]] bool videoIsGifv() const;
|
||||
[[nodiscard]] bool videoIsGifOrUserpic() const;
|
||||
[[nodiscard]] QImage videoFrame() const;
|
||||
[[nodiscard]] QImage videoFrameForDirectPaint() const;
|
||||
[[nodiscard]] QImage transformVideoFrame(QImage frame) const;
|
||||
|
@ -356,6 +356,7 @@ private:
|
|||
void paintTransformedVideoFrame(Painter &p);
|
||||
void paintTransformedStaticContent(Painter &p);
|
||||
void clearStreaming(bool savePosition = true);
|
||||
bool canInitStreaming() const;
|
||||
|
||||
QBrush _transparentBrush;
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ namespace {
|
|||
|
||||
constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL;
|
||||
constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL;
|
||||
constexpr auto kPhotoBaseCacheTag = 0x0000000000020000ULL;
|
||||
constexpr auto kPhotoBaseCacheMask = 0x000000000000FF00ULL;
|
||||
constexpr auto kSerializeTypeShift = quint8(0x08);
|
||||
constexpr auto kNonStorageLocationToken = quint8(0x10);
|
||||
const auto kInMediaCacheLocation = QString("*media_cache*");
|
||||
|
@ -405,9 +407,6 @@ Storage::Cache::Key StorageFileLocation::cacheKey() const {
|
|||
}
|
||||
|
||||
Storage::Cache::Key StorageFileLocation::bigFileBaseCacheKey() const {
|
||||
// Skip '1' and '2' for legacy document cache keys.
|
||||
const auto shifted = ((uint64(_type) + 3) << 8);
|
||||
const auto sliced = uint64(_dcId) & 0xFFULL;
|
||||
switch (_type) {
|
||||
case Type::Document: {
|
||||
const auto high = kDocumentBaseCacheTag
|
||||
|
@ -425,6 +424,18 @@ Storage::Cache::Key StorageFileLocation::bigFileBaseCacheKey() const {
|
|||
| ((uint64(_dcId) & 0xFFULL) << 8)
|
||||
| (_volumeId >> 56);
|
||||
const auto low = (_volumeId << 8);
|
||||
|
||||
Ensures((low & 0xFFULL) == 0);
|
||||
return Storage::Cache::Key{ high, low };
|
||||
}
|
||||
|
||||
case Type::Photo: {
|
||||
const auto high = kPhotoBaseCacheTag
|
||||
| ((uint64(_dcId) << 16) & kPhotoBaseCacheMask)
|
||||
| (_id >> 48);
|
||||
const auto low = (_id << 16);
|
||||
|
||||
Ensures((low & 0xFFULL) == 0);
|
||||
return Storage::Cache::Key{ high, low };
|
||||
}
|
||||
|
||||
|
@ -432,7 +443,6 @@ Storage::Cache::Key StorageFileLocation::bigFileBaseCacheKey() const {
|
|||
case Type::PeerPhoto:
|
||||
case Type::Encrypted:
|
||||
case Type::Secure:
|
||||
case Type::Photo:
|
||||
case Type::Takeout:
|
||||
Unexpected("Not implemented file location type.");
|
||||
|
||||
|
|
|
@ -611,9 +611,9 @@ inline bool operator>=(
|
|||
|
||||
struct ImageWithLocation {
|
||||
ImageLocation location;
|
||||
int bytesCount = 0;
|
||||
QByteArray bytes;
|
||||
QImage preloaded;
|
||||
int bytesCount = 0;
|
||||
};
|
||||
|
||||
InMemoryKey inMemoryKey(const StorageFileLocation &location);
|
||||
|
|
|
@ -51,8 +51,8 @@ ImageWithLocation FromPhotoSize(
|
|||
data.vtype())) },
|
||||
data.vw().v,
|
||||
data.vh().v),
|
||||
.bytes = bytes,
|
||||
.bytesCount = bytes.size(),
|
||||
.bytes = bytes
|
||||
};
|
||||
}, [&](const MTPDphotoStrippedSize &data) {
|
||||
return ImageWithLocation();
|
||||
|
@ -69,8 +69,8 @@ ImageWithLocation FromPhotoSize(
|
|||
// data.vtype())) },
|
||||
// width, // ???
|
||||
// height), // ???
|
||||
// .bytes = bytes,
|
||||
// .bytesCount = bytes.size(),
|
||||
// .bytes = bytes
|
||||
//};
|
||||
}, [&](const MTPDphotoSizeEmpty &) {
|
||||
return ImageWithLocation();
|
||||
|
@ -110,8 +110,8 @@ ImageWithLocation FromPhotoSize(
|
|||
data.vtype())) },
|
||||
data.vw().v,
|
||||
data.vh().v),
|
||||
.bytes = bytes,
|
||||
.bytesCount = bytes.size(),
|
||||
.bytes = bytes
|
||||
};
|
||||
}, [&](const MTPDphotoStrippedSize &data) {
|
||||
return ImageWithLocation();
|
||||
|
@ -128,8 +128,8 @@ ImageWithLocation FromPhotoSize(
|
|||
// data.vtype())) },
|
||||
// width, // ???
|
||||
// height), // ???
|
||||
// .bytes = bytes,
|
||||
// .bytesCount = bytes.size(),
|
||||
// .bytes = bytes
|
||||
//};
|
||||
}, [&](const MTPDphotoSizeEmpty &) {
|
||||
return ImageWithLocation();
|
||||
|
@ -172,8 +172,8 @@ ImageWithLocation FromPhotoSize(
|
|||
location.vlocal_id())) },
|
||||
data.vw().v,
|
||||
data.vh().v),
|
||||
.bytes = bytes,
|
||||
.bytesCount = bytes.size(),
|
||||
.bytes = bytes
|
||||
};
|
||||
}, [&](const MTPDphotoStrippedSize &data) {
|
||||
return ImageWithLocation();
|
||||
|
@ -190,8 +190,8 @@ ImageWithLocation FromPhotoSize(
|
|||
// data.vtype())) },
|
||||
// width, // ???
|
||||
// height), // ???
|
||||
// .bytes = bytes,
|
||||
// .bytesCount = bytes.size(),
|
||||
// .bytes = bytes
|
||||
//};
|
||||
}, [&](const MTPDphotoSizeEmpty &) {
|
||||
return ImageWithLocation();
|
||||
|
@ -212,9 +212,9 @@ ImageWithLocation FromImageInMemory(
|
|||
DownloadLocation{ InMemoryLocation{ bytes } },
|
||||
image.width(),
|
||||
image.height()),
|
||||
.bytesCount = bytes.size(),
|
||||
.bytes = bytes,
|
||||
.preloaded = image
|
||||
.preloaded = image,
|
||||
.bytesCount = bytes.size(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ ImageWithLocation FromVideoSize(
|
|||
data.vtype())) },
|
||||
data.vw().v,
|
||||
data.vh().v),
|
||||
.bytesCount = data.vsize().v
|
||||
.bytesCount = data.vsize().v,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ ImageWithLocation FromVideoSize(
|
|||
data.vtype())) },
|
||||
data.vw().v,
|
||||
data.vh().v),
|
||||
.bytesCount = data.vsize().v
|
||||
.bytesCount = data.vsize().v,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue