2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 06:35:14 +00:00

Keep document byte data only in DocumentMedia.

This commit is contained in:
John Preston
2020-04-10 17:18:51 +04:00
parent 97bab388ea
commit 40f12a2584
26 changed files with 280 additions and 241 deletions

View File

@@ -44,17 +44,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
// Updated Mar 3, 2020: Increase the size of the memory cache for media, to prevent items still being displayed from being unloaded.
constexpr auto kMemoryForCache = 128 * 1024 * 1024; // was 32, updated to 128
const auto kAnimatedStickerDimensions = QSize(512, 512);
Core::MediaActiveCache<DocumentData> &ActiveCache() {
static auto Instance = Core::MediaActiveCache<DocumentData>(
kMemoryForCache,
[](DocumentData *document) { document->unload(); });
return Instance;
}
QString JoinStringList(const QStringList &list, const QString &separator) {
const auto count = list.size();
if (!count) {
@@ -320,11 +311,12 @@ void DocumentOpenClickHandler::Open(
}
LaunchWithWarning(location.name(), context);
};
const auto media = data->createMediaView();
const auto &location = data->location(true);
if (data->isTheme() && data->loaded(true)) {
if (data->isTheme() && media->loaded(true)) {
Core::App().showDocument(data, context);
location.accessDisable();
} else if (data->canBePlayed()) {
} else if (media->canBePlayed()) {
if (data->isAudioFile()
|| data->isVoiceMessage()
|| data->isVideoMessage()) {
@@ -458,7 +450,6 @@ DocumentData::DocumentData(not_null<Data::Session*> owner, DocumentId id)
DocumentData::~DocumentData() {
destroyLoader();
unload();
ActiveCache().remove(this);
}
Data::Session &DocumentData::owner() const {
@@ -578,7 +569,6 @@ void DocumentData::validateLottieSticker() {
}
void DocumentData::setDataAndCache(const QByteArray &data) {
_data = data;
if (const auto media = activeMediaView()) {
media->setBytes(data);
}
@@ -744,16 +734,13 @@ void DocumentData::unload() {
//
//_thumbnail->unload();
_replyPreview = nullptr;
if (!_data.isEmpty()) {
ActiveCache().decrement(_data.size());
_data.clear();
}
}
void DocumentData::automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item) {
if (status != FileReady || loaded() || cancelled()) {
const auto media = activeMediaView();
if (status != FileReady || !media || media->loaded() || cancelled()) {
return;
} else if (!item && type != StickerDocument && !isAnimation()) {
return;
@@ -794,10 +781,6 @@ void DocumentData::automaticLoadSettingsChanged() {
_flags &= ~Flag::DownloadCancelled;
}
bool DocumentData::loaded(bool check) const {
return !rawBytes().isEmpty() || !filepath(check).isEmpty();
}
void DocumentData::finishLoad() {
const auto guard = gsl::finally([&] {
destroyLoader();
@@ -807,18 +790,11 @@ void DocumentData::finishLoad() {
return;
}
setLocation(FileLocation(_loader->fileName()));
ActiveCache().decrement(_data.size());
_data = _loader->bytes();
ActiveCache().increment(_data.size());
setGoodThumbnailDataReady();
if (const auto media = activeMediaView()) {
media->setBytes(_loader->bytes());
media->checkStickerLarge(_loader.get());
}
if (!_data.isEmpty()) {
ActiveCache().up(this);
}
}
void DocumentData::destroyLoader() const {
@@ -854,7 +830,7 @@ float64 DocumentData::progress() const {
}
return 0.;
}
return loading() ? _loader->currentProgress() : (loaded() ? 1. : 0.);
return loading() ? _loader->currentProgress() : 0.;
}
int DocumentData::loadOffset() const {
@@ -909,13 +885,13 @@ void DocumentData::save(
const QString &toFile,
LoadFromCloudSetting fromCloud,
bool autoLoading) {
if (loaded(true)) {
if (const auto media = activeMediaView(); media->loaded(true)) {
auto &l = location(true);
if (!toFile.isEmpty()) {
if (!rawBytes().isEmpty()) {
if (!media->bytes().isEmpty()) {
QFile f(toFile);
f.open(QIODevice::WriteOnly);
f.write(rawBytes());
f.write(media->bytes());
f.close();
setLocation(FileLocation(toFile));
@@ -1108,13 +1084,6 @@ QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform) {
return result;
}
QByteArray DocumentData::rawBytes() const {
if (!_data.isEmpty()) {
ActiveCache().up(const_cast<DocumentData*>(this));
}
return _data;
}
const FileLocation &DocumentData::location(bool check) const {
if (check && !_location.check()) {
const auto location = Local::readFileLocation(mediaKey());
@@ -1272,12 +1241,6 @@ bool DocumentData::canBeStreamed() const {
return hasRemoteLocation() && supportsStreaming();
}
bool DocumentData::canBePlayed() const {
return !(_flags & Flag::StreamingPlaybackFailed)
&& useStreamingLoader()
&& (loaded() || canBeStreamed());
}
void DocumentData::setInappPlaybackFailed() {
_flags |= Flag::StreamingPlaybackFailed;
}
@@ -1294,9 +1257,10 @@ auto DocumentData::createStreamingLoader(
return nullptr;
}
if (!forceRemoteLoader) {
const auto media = activeMediaView();
const auto &location = this->location(true);
if (!rawBytes().isEmpty()) {
return Media::Streaming::MakeBytesLoader(rawBytes());
if (media && !media->bytes().isEmpty()) {
return Media::Streaming::MakeBytesLoader(media->bytes());
} else if (!location.isEmpty() && location.accessEnable()) {
auto result = Media::Streaming::MakeFileLoader(location.name());
location.accessDisable();
@@ -1574,15 +1538,10 @@ void DocumentData::collectLocalData(not_null<DocumentData*> local) {
}
_owner->cache().copyIfEmpty(local->cacheKey(), cacheKey());
if (!local->_data.isEmpty()) {
ActiveCache().decrement(_data.size());
_data = local->_data;
const auto localMedia = local->activeMediaView();
if (!localMedia->bytes().isEmpty()) {
if (const auto media = activeMediaView()) {
media->setBytes(local->_data);
}
ActiveCache().increment(_data.size());
if (!_data.isEmpty()) {
ActiveCache().up(this);
media->setBytes(localMedia->bytes());
}
}
if (!local->_location.inMediaCache() && !local->_location.isEmpty()) {
@@ -1672,13 +1631,13 @@ website ws wsc wsf wsh xbap xll xnk xs");
}
base::binary_guard ReadImageAsync(
not_null<DocumentData*> document,
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,
FnMut<void(QImage&&)> done) {
auto result = base::binary_guard();
crl::async([
bytes = document->rawBytes(),
path = document->filepath(),
bytes = media->bytes(),
path = media->owner()->filepath(),
postprocess = std::move(postprocess),
guard = result.make_guard(),
callback = std::move(done)

View File

@@ -100,7 +100,6 @@ public:
const HistoryItem *item);
void automaticLoadSettingsChanged();
[[nodiscard]] bool loaded(bool check = false) const;
[[nodiscard]] bool loading() const;
[[nodiscard]] QString loadingFilePath() const;
[[nodiscard]] bool displayLoading() const;
@@ -120,7 +119,6 @@ public:
void setWaitingForAlbum();
[[nodiscard]] bool waitingForAlbum() const;
[[nodiscard]] QByteArray rawBytes() const;
[[nodiscard]] const FileLocation &location(bool check = false) const;
void setLocation(const FileLocation &loc);
@@ -225,12 +223,12 @@ public:
const QString &songPerformer);
[[nodiscard]] QString composeNameString() const;
[[nodiscard]] bool canBePlayed() const;
[[nodiscard]] bool canBeStreamed() const;
[[nodiscard]] auto createStreamingLoader(
Data::FileOrigin origin,
bool forceRemoteLoader) const
-> std::unique_ptr<Media::Streaming::Loader>;
[[nodiscard]] bool useStreamingLoader() const;
void setInappPlaybackFailed();
[[nodiscard]] bool inappPlaybackFailed() const;
@@ -291,7 +289,6 @@ private:
void handleLoaderUpdates();
void destroyLoader() const;
[[nodiscard]] bool useStreamingLoader() const;
bool saveFromDataChecked();
// Two types of location: from MTProto by dc+access or from web by url
@@ -312,7 +309,6 @@ private:
not_null<Data::Session*> _owner;
FileLocation _location;
QByteArray _data;
std::unique_ptr<DocumentAdditionalData> _additional;
int32 _duration = -1;
mutable Flags _flags = kStreamingSupportedUnknown;
@@ -440,7 +436,7 @@ QString FileExtension(const QString &filepath);
bool IsValidMediaFile(const QString &filepath);
bool IsExecutableName(const QString &filepath);
base::binary_guard ReadImageAsync(
not_null<DocumentData*> document,
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,
FnMut<void(QImage&&)> done);

View File

@@ -82,8 +82,7 @@ enum class FileType {
} // namespace
DocumentMedia::DocumentMedia(not_null<DocumentData*> owner)
: _owner(owner)
, _bytes(owner->rawBytes()) {
: _owner(owner) {
}
DocumentMedia::~DocumentMedia() = default;
@@ -140,8 +139,7 @@ void DocumentMedia::checkStickerLarge() {
if (data->animated || !loaded()) {
return;
}
const auto bytes = _owner->rawBytes();
if (bytes.isEmpty()) {
if (_bytes.isEmpty()) {
const auto &loc = _owner->location(true);
if (loc.accessEnable()) {
_sticker = std::make_unique<Image>(
@@ -150,11 +148,11 @@ void DocumentMedia::checkStickerLarge() {
}
} else {
auto format = QByteArray();
auto image = App::readImage(bytes, &format, false);
auto image = App::readImage(_bytes, &format, false);
_sticker = std::make_unique<Image>(
std::make_unique<Images::LocalFileSource>(
QString(),
bytes,
_bytes,
format,
std::move(image)));
}
@@ -171,7 +169,19 @@ QByteArray DocumentMedia::bytes() const {
}
bool DocumentMedia::loaded(bool check) const {
return !_bytes.isEmpty() || _owner->loaded(check);// checkLoadedTo(this);
return !_bytes.isEmpty() || !_owner->filepath(check).isEmpty();
}
float64 DocumentMedia::progress() const {
return (owner()->uploading() || owner()->loading())
? owner()->progress()
: (loaded() ? 1. : 0.);
}
bool DocumentMedia::canBePlayed() const {
return !owner()->inappPlaybackFailed()
&& owner()->useStreamingLoader()
&& (loaded() || owner()->canBeStreamed());
}
void DocumentMedia::checkStickerSmall() {
@@ -203,18 +213,19 @@ void DocumentMedia::checkStickerLarge(not_null<FileLoader*> loader) {
if (_owner->sticker()
&& !_sticker
&& !loader->imageData().isNull()
&& !_owner->rawBytes().isEmpty()) {
&& !_bytes.isEmpty()) {
_sticker = std::make_unique<Image>(
std::make_unique<Images::LocalFileSource>(
QString(),
_owner->rawBytes(),
_bytes,
loader->imageFormat(),
loader->imageData()));
}
}
void DocumentMedia::GenerateGoodThumbnail(not_null<DocumentData*> document) {
const auto data = document->rawBytes();
void DocumentMedia::GenerateGoodThumbnail(
not_null<DocumentData*> document,
QByteArray data) {
const auto type = document->isWallPaper()
? FileType::WallPaper
: document->isTheme()
@@ -282,8 +293,9 @@ void DocumentMedia::ReadOrGenerateThumbnail(
const auto active = document->activeMediaView();
const auto got = [=](QByteArray value) {
if (value.isEmpty()) {
const auto bytes = active ? active->bytes() : QByteArray();
crl::on_main(guard, [=] {
GenerateGoodThumbnail(document);
GenerateGoodThumbnail(document, bytes);
});
} else if (active) {
crl::async([=] {

View File

@@ -35,6 +35,8 @@ public:
void setBytes(const QByteArray &bytes);
[[nodiscard]] QByteArray bytes() const;
[[nodiscard]] bool loaded(bool check = false) const;
[[nodiscard]] float64 progress() const;
[[nodiscard]] bool canBePlayed() const;
// For DocumentData.
static void CheckGoodThumbnail(not_null<DocumentData*> document);
@@ -47,7 +49,9 @@ private:
using Flags = base::flags<Flag>;
static void ReadOrGenerateThumbnail(not_null<DocumentData*> document);
static void GenerateGoodThumbnail(not_null<DocumentData*> document);
static void GenerateGoodThumbnail(
not_null<DocumentData*> document,
QByteArray data);
const not_null<DocumentData*> _owner;
std::unique_ptr<Image> _goodThumbnail;