From 832d86c4ec96e828e989f7a40e25c8f0b6b01242 Mon Sep 17 00:00:00 2001 From: kevingpqi123 Date: Thu, 7 Nov 2024 16:42:33 +0800 Subject: [PATCH] Add thread safety checks for PAGView and PAGImageView. (#2572) --- src/platform/ios/PAGImageView.mm | 58 +++++++++++++++++++++++--------- src/platform/ios/PAGView.mm | 5 +++ 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/platform/ios/PAGImageView.mm b/src/platform/ios/PAGImageView.mm index b4f74698a3..4aaf48636f 100644 --- a/src/platform/ios/PAGImageView.mm +++ b/src/platform/ios/PAGImageView.mm @@ -73,6 +73,9 @@ @implementation PAGImageView { PAGDecoder* pagDecoder; NSInteger duartion; float renderScaleFactor; + NSInteger width; + NSInteger height; + NSUInteger numFrames; NSMutableDictionary* imagesMap; std::mutex imageViewLock; @@ -97,6 +100,9 @@ - (void)initPAG { self.memeoryCacheFinished = NO; self.isVisible = NO; filePath = nil; + width = 0; + height = 0; + numFrames = 0; self.backgroundColor = [UIColor clearColor]; animator = [[PAGAnimator alloc] initWithUpdater:(id)self]; @@ -162,6 +168,7 @@ - (void)setCompositionInternal:(PAGComposition*)newComposition maxFrameRate:(flo duartion = [newComposition duration]; [self reset]; + [self updatePAGDecoder]; if (self.isVisible) { [animator setDuration:duartion]; } @@ -171,8 +178,8 @@ - (CVPixelBufferRef)getDiskCacheCVPixelBuffer { if (diskBufferPool == nil) { NSDictionary* options = @{ (id)kCVPixelBufferIOSurfacePropertiesKey : @{}, - (id)kCVPixelBufferWidthKey : @([[self getPAGDecoder] width]), - (id)kCVPixelBufferHeightKey : @([[self getPAGDecoder] height]), + (id)kCVPixelBufferWidthKey : @(width), + (id)kCVPixelBufferHeightKey : @(height), (id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) }; CVReturn status = CVPixelBufferPoolCreate(kCFAllocatorDefault, nil, (CFDictionaryRef)options, @@ -194,8 +201,7 @@ - (CVPixelBufferRef)getDiskCacheCVPixelBuffer { - (CVPixelBufferRef)getMemoryCacheCVPixelBuffer { CVPixelBufferRef pixelBuffer = - pag::PixelBufferUtil::Make(static_cast([[self getPAGDecoder] width]), - static_cast([[self getPAGDecoder] height])); + pag::PixelBufferUtil::Make(static_cast(width), static_cast(height)); if (pixelBuffer == nil) { NSLog(@"PAGImageView: CVPixelBufferRef create failed!"); return nil; @@ -203,7 +209,7 @@ - (CVPixelBufferRef)getMemoryCacheCVPixelBuffer { return pixelBuffer; } -- (PAGDecoder*)getPAGDecoder { +- (void)updatePAGDecoder { if (pagDecoder == nil) { float scaleFactor; if (self.viewSize.width >= self.viewSize.height) { @@ -224,10 +230,12 @@ - (PAGDecoder*)getPAGDecoder { scale:scaleFactor]; } if (pagDecoder) { + width = [pagDecoder width]; + height = [pagDecoder height]; + numFrames = [pagDecoder numFrames]; [pagDecoder retain]; } } - return pagDecoder; } - (void)onAnimationFlush:(double)progress { @@ -262,14 +270,17 @@ - (BOOL)updateImageViewFrom:(CVPixelBufferRef)pixelBuffer atIndex:(NSInteger)fra self.currentUIImage = image; [self submitToImageView]; } - if ([imagesMap count] == (NSUInteger)[[self getPAGDecoder] numFrames]) { + if ([imagesMap count] == numFrames) { self.memeoryCacheFinished = YES; } return YES; } - PAGDecoder* decoder = [self getPAGDecoder]; - if ([decoder checkFrameChanged:(int)frameIndex]) { - BOOL status = [decoder readFrame:frameIndex to:pixelBuffer]; + [self updatePAGDecoder]; + if (pagDecoder == nil) { + return false; + } + if ([pagDecoder checkFrameChanged:(int)frameIndex]) { + BOOL status = [pagDecoder readFrame:frameIndex to:pixelBuffer]; if (!status) { return status; } @@ -294,6 +305,7 @@ - (BOOL)checkPAGCompositionChanged { if ([PAGContentVersion Get:pagComposition] != self.pagContentVersion) { self.pagContentVersion = [PAGContentVersion Get:pagComposition]; [self reset]; + [self updatePAGDecoder]; if (self.isVisible) { [animator setDuration:[pagComposition duration]]; } @@ -317,8 +329,7 @@ - (void)applicationDidBecomeActive:(NSNotification*)notification { } - (void)freeCache { - if (self.memoryCacheEnabled && self->pagDecoder && - [self->imagesMap count] == (NSUInteger)[self->pagDecoder numFrames]) { + if (self.memoryCacheEnabled && self->pagDecoder && [self->imagesMap count] == numFrames) { [self->pagDecoder release]; self->pagDecoder = nil; } @@ -339,6 +350,9 @@ - (void)reset { [pagDecoder release]; pagDecoder = nil; } + width = 0; + height = 0; + numFrames = 0; } - (UIImage*)imageForCVPixelBuffer:(CVPixelBufferRef)pixelBuffer { @@ -370,6 +384,7 @@ - (void)setBounds:(CGRect)bounds { std::lock_guard autoLock(imageViewLock); if (pagComposition || filePath) { [self reset]; + [self updatePAGDecoder]; if (oldBounds.size.width == 0 || oldBounds.size.height == 0) { [animator update]; } @@ -385,6 +400,7 @@ - (void)setFrame:(CGRect)frame { std::lock_guard autoLock(imageViewLock); if (pagComposition || filePath) { [self reset]; + [self updatePAGDecoder]; if (oldRect.size.width == 0 || oldRect.size.height == 0) { [animator update]; } @@ -400,6 +416,7 @@ - (void)setRenderScale:(float)scale { renderScaleFactor = scale; if (pagComposition || filePath) { [self reset]; + [self updatePAGDecoder]; } } @@ -415,6 +432,7 @@ - (void)setContentScaleFactor:(CGFloat)scaleFactor { if (pagComposition || filePath) { std::lock_guard autoLock(imageViewLock); [self reset]; + [self updatePAGDecoder]; self.viewSize = CGSizeMake(self.frame.size.width, self.frame.size.height); } } @@ -457,7 +475,7 @@ - (void)pause { - (NSUInteger)numFrames { std::lock_guard autoLock(imageViewLock); - return [[self getPAGDecoder] numFrames]; + return numFrames; } - (UIImage*)currentImage { @@ -486,6 +504,7 @@ - (void)setRepeatCount:(int)repeatCount { } - (NSString*)getPath { + std::lock_guard autoLock(imageViewLock); return filePath == nil ? nil : [[filePath retain] autorelease]; } @@ -516,6 +535,7 @@ - (void)setPathAsync:(NSString*)path completionBlock:(void (^)(PAGFile*))callbac - (void)setPathAsync:(NSString*)path maxFrameRate:(float)maxFrameRate completionBlock:(void (^)(PAGFile*))callback { + std::lock_guard autoLock(imageViewLock); if (filePath != nil) { [filePath release]; filePath = nil; @@ -533,6 +553,7 @@ - (void)setPathAsync:(NSString*)path } - (PAGComposition*)getComposition { + std::lock_guard autoLock(imageViewLock); if (filePath) { return nil; } @@ -554,16 +575,21 @@ - (void)setComposition:(PAGComposition*)newComposition maxFrameRate:(float)maxFr - (void)setCurrentFrame:(NSUInteger)currentFrame { std::lock_guard autoLock(imageViewLock); - [animator setProgress:pag::FrameToProgress(currentFrame, [[self getPAGDecoder] numFrames])]; + [animator setProgress:pag::FrameToProgress(currentFrame, numFrames)]; } - (NSUInteger)currentFrame { - return pag::ProgressToFrame([animator progress], [[self getPAGDecoder] numFrames]); + std::lock_guard autoLock(imageViewLock); + return [self currentFrameInternal]; +} + +- (NSUInteger)currentFrameInternal { + return pag::ProgressToFrame([animator progress], numFrames); } - (BOOL)flush { std::lock_guard autoLock(imageViewLock); - NSInteger frameIndex = [self currentFrame]; + NSInteger frameIndex = [self currentFrameInternal]; if (self.memeoryCacheFinished) { if ([self checkPAGCompositionChanged] == NO) { if (self.currentFrameIndex != frameIndex) { diff --git a/src/platform/ios/PAGView.mm b/src/platform/ios/PAGView.mm index ec51a31f91..f9626f5630 100644 --- a/src/platform/ios/PAGView.mm +++ b/src/platform/ios/PAGView.mm @@ -28,6 +28,7 @@ @implementation PAGView { NSString* filePath; PAGAnimator* animator; BOOL _isVisible; + std::mutex lock; } - (instancetype)initWithFrame:(CGRect)frame { @@ -192,10 +193,12 @@ - (void)stop { } - (NSString*)getPath { + std::lock_guard autoLock(lock); return filePath == nil ? nil : [[filePath retain] autorelease]; } - (BOOL)setPath:(NSString*)path { + std::lock_guard autoLock(lock); if (filePath != nil) { [filePath release]; filePath = nil; @@ -207,6 +210,7 @@ - (BOOL)setPath:(NSString*)path { } - (void)setPathAsync:(NSString*)path completionBlock:(void (^)(PAGFile*))callback { + std::lock_guard autoLock(lock); if (filePath != nil) { [filePath release]; filePath = nil; @@ -226,6 +230,7 @@ - (PAGComposition*)getComposition { } - (void)setComposition:(PAGComposition*)newComposition { + std::lock_guard autoLock(lock); if (filePath != nil) { [filePath release]; filePath = nil;