Skip to content

Commit

Permalink
Add support for caching video compositions into disk file. (#989)
Browse files Browse the repository at this point in the history
* support disk cache of SequenceComposition

* support disk cache of SequenceComposition

* support disk cache of SequenceComposition

* Rename function.

* support disk cache of SequenceComposition

* support disk cache of SequenceComposition

* support disk cache of SequenceComposition

* support disk cache of SequenceComposition

* update comments.

---------

Co-authored-by: liamcli <liamcli@tencent.com>
Co-authored-by: kevingpqi <kevingpqi@tencent.com>
Co-authored-by: domrjchen <dom@idom.me>
  • Loading branch information
4 people authored Jun 27, 2023
1 parent ab70f75 commit 8f41528
Show file tree
Hide file tree
Showing 23 changed files with 406 additions and 46 deletions.
12 changes: 12 additions & 0 deletions android/libpag/src/main/java/org/libpag/PAGPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ public void setSurface(PAGSurface surface) {
*/
public native void setCacheEnabled(boolean value);

/**
* If set to true, PAG will cache the associated rendering data into a disk file, such as the
* decoded image frames of video compositions. This can help reduce memory usage and improve
* rendering performance.
*/
public native boolean useDiskCache();

/**
* Set the value of useDiskCache property.
*/
public native void setUseDiskCache(boolean value);

/**
* This value defines the scale factor for internal graphics caches, ranges from 0.0 to 1.0. The
* scale factors less than 1.0 may result in blurred output, but it can reduce the usage of
Expand Down
16 changes: 16 additions & 0 deletions android/libpag/src/main/java/org/libpag/PAGView.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,22 @@ public void setCacheEnabled(boolean value) {
pagPlayer.setCacheEnabled(value);
}

/**
* If set to true, PAG will cache the associated rendering data into a disk file, such as the
* decoded image frames of video compositions. This can help reduce memory usage and improve
* rendering performance.
*/
public boolean useDiskCache() {
return pagPlayer.useDiskCache();
}

/**
* Set the value of useDiskCache property.
*/
public void setUseDiskCache(boolean value) {
pagPlayer.setUseDiskCache(value);
}

/**
* This value defines the scale factor for internal graphics caches, ranges from 0.0 to 1.0. The
* scale factors less than 1.0 may result in blurred output, but it can reduce the usage of
Expand Down
17 changes: 17 additions & 0 deletions include/pag/pag.h
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,18 @@ class PAG_API PAGPlayer {
*/
void setCacheEnabled(bool value);

/**
* If set to true, PAG will cache the associated rendering data into a disk file, such as the
* decoded image frames of video compositions. This can help reduce memory usage and improve
* rendering performance.
*/
bool useDiskCache();

/**
* Set the value of useDiskCache property.
*/
void setUseDiskCache(bool value);

/**
* This value defines the scale factor for internal graphics caches, ranges from 0.0 to 1.0. The
* scale factors less than 1.0 may result in blurred output, but it can reduce the usage of
Expand Down Expand Up @@ -1621,6 +1633,8 @@ class PAG_API PAGDecoder {
std::shared_ptr<SequenceFile> sequenceFile = nullptr;
std::shared_ptr<CompositionReader> reader = nullptr;
std::vector<TimeRange> staticTimeRanges = {};
std::function<std::string(PAGDecoder*, std::shared_ptr<PAGComposition>)> cacheKeyGeneratorFun =
nullptr;

static Composition* GetSingleComposition(std::shared_ptr<PAGComposition> pagComposition);
static std::pair<int, float> GetFrameCountAndRate(std::shared_ptr<PAGComposition> pagComposition,
Expand All @@ -1638,6 +1652,9 @@ class PAG_API PAGDecoder {
void checkCompositionChange(std::shared_ptr<PAGComposition> composition);
std::string generateCacheKey(std::shared_ptr<PAGComposition> composition);
std::shared_ptr<PAGComposition> getComposition();
void setCacheKeyGeneratorFun(
std::function<std::string(PAGDecoder*, std::shared_ptr<PAGComposition>)> fun);
friend class DiskSequenceReader;
};

/**
Expand Down
16 changes: 16 additions & 0 deletions src/platform/android/JPAGPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,20 @@ PAG_API jboolean Java_org_libpag_PAGPlayer_hitTestPoint(JNIEnv* env, jobject thi
auto pagLayer = ToPAGLayerNativeObject(env, layer);
return (jboolean)player->hitTestPoint(pagLayer, x, y, pixelHitTest);
}

PAG_API void Java_org_libpag_PAGPlayer_setUseDiskCache(JNIEnv* env, jobject thiz, jboolean value) {
auto player = getPAGPlayer(env, thiz);
if (player == nullptr) {
return;
}
player->setUseDiskCache(value);
}

PAG_API jboolean Java_org_libpag_PAGPlayer_useDiskCache(JNIEnv* env, jobject thiz) {
auto player = getPAGPlayer(env, thiz);
if (player == nullptr) {
return JNI_FALSE;
}
return player->useDiskCache();
}
}
12 changes: 12 additions & 0 deletions src/platform/cocoa/PAGPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ PAG_API @interface PAGPlayer : NSObject
*/
- (void)setCacheEnabled:(BOOL)value;

/**
* If set to true, PAG will cache the associated rendering data into a disk file, such as the
* decoded image frames of video compositions. This can help reduce memory usage and improve
* rendering performance.
*/
- (BOOL)useDiskCache;

/**
* Set the value of useDiskCache property.
*/
- (void)setUseDiskCache:(BOOL)value;

/**
* This value defines the scale factor for internal graphics caches, ranges from 0.0 to 1.0. The
* scale factors less than 1.0 may result in blurred output, but it can reduce the usage of graphics
Expand Down
8 changes: 8 additions & 0 deletions src/platform/cocoa/PAGPlayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ - (void)setCacheEnabled:(BOOL)value {
[pagPlayer setCacheEnabled:value];
}

- (BOOL)useDiskCache {
return [pagPlayer useDiskCache];
}

- (void)setUseDiskCache:(BOOL)value {
[pagPlayer setUseDiskCache:value];
}

- (float)cacheScale {
return [pagPlayer cacheScale];
}
Expand Down
4 changes: 4 additions & 0 deletions src/platform/cocoa/private/PAGPlayerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@

- (void)setCacheEnabled:(BOOL)value;

- (BOOL)useDiskCache;

- (void)setUseDiskCache:(BOOL)value;

- (float)cacheScale;

- (void)setCacheScale:(float)value;
Expand Down
8 changes: 8 additions & 0 deletions src/platform/cocoa/private/PAGPlayerImpl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ - (void)setCacheEnabled:(BOOL)value {
pagPlayer->setCacheEnabled(value);
}

- (BOOL)useDiskCache {
return pagPlayer->useDiskCache();
}

- (void)setUseDiskCache:(BOOL)value {
pagPlayer->setUseDiskCache(value);
}

- (float)cacheScale {
return pagPlayer->cacheScale();
}
Expand Down
12 changes: 12 additions & 0 deletions src/platform/ios/PAGView.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ PAG_API @interface PAGView : UIView
*/
- (void)setCacheEnabled:(BOOL)value;

/**
* If set to true, PAG will cache the associated rendering data into a disk file, such as the
* decoded image frames of video compositions. This can help reduce memory usage and improve
* rendering performance.
*/
- (BOOL)useDiskCache;

/**
* Set the value of useDiskCache property.
*/
- (void)setUseDiskCache:(BOOL)value;

/**
* This value defines the scale factor for internal graphics caches, ranges from 0.0 to 1.0. The
* scale factors less than 1.0 may result in blurred output, but it can reduce the usage of graphics
Expand Down
8 changes: 8 additions & 0 deletions src/platform/ios/PAGView.m
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ - (void)setCacheEnabled:(BOOL)value {
[pagPlayer setCacheEnabled:value];
}

- (BOOL)useDiskCache {
return [pagPlayer useDiskCache];
}

- (void)setUseDiskCache:(BOOL)value {
[pagPlayer setUseDiskCache:value];
}

- (float)cacheScale {
return [pagPlayer cacheScale];
}
Expand Down
32 changes: 23 additions & 9 deletions src/rendering/PAGDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@
#include "rendering/utils/LockGuard.h"

namespace pag {

static std::string DefaultCacheKeyGeneratorFunc(PAGDecoder* decoder,
std::shared_ptr<PAGComposition> composition) {
if (!composition->isPAGFile() || pag::ContentVersion::Get(composition) > 0) {
return "";
}
auto filePath = static_cast<PAGFile*>(composition.get())->path();
filePath = Platform::Current()->getSandboxPath(filePath);
if (filePath.empty()) {
return "";
}
return filePath + "." + std::to_string(decoder->width()) + "x" +
std::to_string(decoder->height());
}

Composition* PAGDecoder::GetSingleComposition(std::shared_ptr<PAGComposition> pagComposition) {
auto numChildren = pagComposition->numChildren();
if (numChildren == 0) {
Expand Down Expand Up @@ -258,15 +273,8 @@ void PAGDecoder::checkCompositionChange(std::shared_ptr<PAGComposition> composit
}

std::string PAGDecoder::generateCacheKey(std::shared_ptr<PAGComposition> composition) {
if (!composition->isPAGFile() || composition->contentModified()) {
return "";
}
auto filePath = static_cast<PAGFile*>(composition.get())->path();
filePath = Platform::Current()->getSandboxPath(filePath);
if (filePath.empty()) {
return "";
}
return filePath + "." + std::to_string(_width) + "x" + std::to_string(_height);
return cacheKeyGeneratorFun == nullptr ? DefaultCacheKeyGeneratorFunc(this, composition)
: cacheKeyGeneratorFun(this, composition);
}

std::shared_ptr<PAGComposition> PAGDecoder::getComposition() {
Expand All @@ -278,4 +286,10 @@ std::shared_ptr<PAGComposition> PAGDecoder::getComposition() {
}
return nullptr;
}

void PAGDecoder::setCacheKeyGeneratorFun(
std::function<std::string(PAGDecoder*, std::shared_ptr<PAGComposition> composition)> fun) {
cacheKeyGeneratorFun = fun;
}

} // namespace pag
10 changes: 10 additions & 0 deletions src/rendering/PAGPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ void PAGPlayer::setCacheEnabled(bool value) {
renderCache->setSnapshotEnabled(value);
}

bool PAGPlayer::useDiskCache() {
LockGuard autoLock(rootLocker);
return renderCache->useDiskCache();
}

void PAGPlayer::setUseDiskCache(bool value) {
LockGuard autoLock(rootLocker);
renderCache->setUseDiskCache(value);
}

float PAGPlayer::cacheScale() {
LockGuard autoLock(rootLocker);
return stage->cacheScale();
Expand Down
2 changes: 1 addition & 1 deletion src/rendering/caches/RenderCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ SequenceImageQueue* RenderCache::makeSequenceImageQueue(std::shared_ptr<Sequence
return nullptr;
}
auto layer = stage->getLayerFromReferenceMap(sequence->uniqueID());
auto queue = SequenceImageQueue::MakeFrom(sequence, layer).release();
auto queue = SequenceImageQueue::MakeFrom(sequence, layer, _useDiskCache).release();
if (queue == nullptr) {
return nullptr;
}
Expand Down
17 changes: 17 additions & 0 deletions src/rendering/caches/RenderCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,22 @@ class RenderCache : public Performance {
return snapshotCaches.count(assetID) > 0;
}

/**
* If set to true, PAG will cache the associated rendering data into a disk file, such as the
* decoded image frames of video compositions. This can help reduce memory usage and improve
* rendering performance.
*/
bool useDiskCache() const {
return _useDiskCache;
}

/**
* Set the value of useDiskCache property.
*/
void setUseDiskCache(bool value) {
_useDiskCache = value;
}

/**
* Returns a snapshot cache of specified asset id. Returns null if there is no associated cache
* available. This is a read-only query which is used usually during hit testing.
Expand Down Expand Up @@ -171,6 +187,7 @@ class RenderCache : public Performance {
size_t graphicsMemory = 0;
bool _videoEnabled = true;
bool _snapshotEnabled = true;
bool _useDiskCache = false;
std::unordered_set<ID> usedAssets = {};
std::unordered_map<ID, Snapshot*> snapshotCaches = {};
std::list<Snapshot*> snapshotLRU = {};
Expand Down
32 changes: 22 additions & 10 deletions src/rendering/sequences/BitmapSequenceReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,42 @@ BitmapSequenceReader::BitmapSequenceReader(std::shared_ptr<File> file, BitmapSeq
: file(std::move(file)), sequence(sequence) {
// Force allocating a raster PixelBuffer if staticContent is false, otherwise the asynchronous
// decoding will fail due to the memory sharing mechanism.
auto staticContent = sequence->composition->staticContent();
if (staticContent) {
bitmap.allocPixels(sequence->width, sequence->height, false);
bitmap.clear();
} else {
if (tgfx::HardwareBufferAvailable() && sequence->composition->staticContent()) {
hardWareBuffer = tgfx::HardwareBufferAllocate(sequence->width, sequence->height, false);
info = tgfx::HardwareBufferGetInfo(hardWareBuffer);
}
if (hardWareBuffer == nullptr) {
info = tgfx::ImageInfo::Make(sequence->width, sequence->height, tgfx::ColorType::RGBA_8888);
tgfx::Buffer buffer(info.byteSize());
buffer.clear();
pixels = buffer.release();
}
}

BitmapSequenceReader::~BitmapSequenceReader() {
if (hardWareBuffer) {
tgfx::HardwareBufferRelease(hardWareBuffer);
}
}

std::shared_ptr<tgfx::ImageBuffer> BitmapSequenceReader::onMakeBuffer(Frame targetFrame) {
// a locker is required here because decodeFrame() could be called from multiple threads.
std::lock_guard<std::mutex> autoLock(locker);
if (lastDecodeFrame == targetFrame) {
return imageBuffer;
}
if (bitmap.isEmpty() && pixels == nullptr) {
if (hardWareBuffer == nullptr && pixels == nullptr) {
return nullptr;
}
imageBuffer = nullptr;
lastDecodeFrame = -1;
tgfx::Pixmap pixmap = {};
if (!bitmap.isEmpty()) {
pixmap.reset(bitmap);
if (hardWareBuffer) {
auto hardwarePixels = tgfx::HardwareBufferLock(hardWareBuffer);
if (hardwarePixels == nullptr) {
return nullptr;
}
pixmap.reset(info, hardwarePixels);
} else {
pixmap.reset(info, const_cast<void*>(pixels->data()));
}
Expand All @@ -75,14 +85,16 @@ std::shared_ptr<tgfx::ImageBuffer> BitmapSequenceReader::onMakeBuffer(Frame targ
auto result = codec->readPixels(
pixmap.info(), reinterpret_cast<uint8_t*>(pixmap.writablePixels()) + offset);
if (!result) {
tgfx::HardwareBufferUnlock(hardWareBuffer);
return nullptr;
}
firstRead = false;
}
}
}
if (!bitmap.isEmpty()) {
imageBuffer = bitmap.makeBuffer();
if (hardWareBuffer) {
tgfx::HardwareBufferUnlock(hardWareBuffer);
imageBuffer = tgfx::ImageBuffer::MakeFrom(hardWareBuffer);
} else {
imageBuffer = tgfx::ImageBuffer::MakeFrom(info, pixels);
}
Expand Down
4 changes: 3 additions & 1 deletion src/rendering/sequences/BitmapSequenceReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class BitmapSequenceReader : public SequenceReader {
return sequence->height;
}

~BitmapSequenceReader() override;

protected:
std::shared_ptr<tgfx::ImageBuffer> onMakeBuffer(Frame targetFrame) override;

Expand All @@ -49,8 +51,8 @@ class BitmapSequenceReader : public SequenceReader {
BitmapSequence* sequence = nullptr;
Frame lastDecodeFrame = -1;
std::shared_ptr<tgfx::ImageBuffer> imageBuffer = nullptr;
tgfx::Bitmap bitmap = {};
tgfx::ImageInfo info = {};
std::shared_ptr<tgfx::Data> pixels = nullptr;
HardwareBufferRef hardWareBuffer = nullptr;
};
} // namespace pag
Loading

0 comments on commit 8f41528

Please sign in to comment.