Skip to content

Commit

Permalink
Fixes animated frame timing (facebook#44622)
Browse files Browse the repository at this point in the history
Summary:
Fixes facebook#44608 .

## Changelog:

[IOS] [FIXED] - Fixes animated frame timing

Pull Request resolved: facebook#44622

Test Plan: Example in facebook#44608 .

Reviewed By: sammy-SC

Differential Revision: D57559884

Pulled By: cipolleschi

fbshipit-source-id: 33eaf71c24eb83715403a67b3471dd1ac2dd9d2f
  • Loading branch information
zhongwuzw authored and kosmydel committed Jun 11, 2024
1 parent df0f849 commit a36e27f
Showing 1 changed file with 21 additions and 17 deletions.
38 changes: 21 additions & 17 deletions packages/react-native/Libraries/Image/RCTUIImageViewAnimated.mm
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ - (void)setImage:(UIImage *)image
// Calculate max buffer size
[self calculateMaxBufferCount];

[self prefetchNextFrame:nil fetchFrameIndex:1];

if ([self paused]) {
[self start];
}
Expand Down Expand Up @@ -167,6 +169,21 @@ - (CADisplayLink *)displayLink
return _displayLink;
}

- (void)prefetchNextFrame:(UIImage *)fetchFrame fetchFrameIndex:(NSInteger)fetchFrameIndex
{
if (!fetchFrame && !(self.frameBuffer.count == self.totalFrameCount) && self.fetchQueue.operationCount == 0) {
// Prefetch next frame in background queue
UIImage<RCTAnimatedImage> *animatedImage = self.animatedImage;
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
UIImage *frame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex];
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
self.frameBuffer[@(fetchFrameIndex)] = frame;
dispatch_semaphore_signal(self.lock);
}];
[self.fetchQueue addOperation:operation];
}
}

#pragma mark - Animation

- (void)start
Expand Down Expand Up @@ -210,6 +227,9 @@ - (void)displayDidRefresh:(CADisplayLink *)displayLink
// Do not skip frame
self.currentTime = nextDuration;
}
currentFrameIndex = nextFrameIndex;
self.currentFrameIndex = nextFrameIndex;
nextFrameIndex = (currentFrameIndex + 1) % totalFrameCount;
}

// Update the current frame
Expand All @@ -219,20 +239,14 @@ - (void)displayDidRefresh:(CADisplayLink *)displayLink
currentFrame = self.frameBuffer[@(currentFrameIndex)];
fetchFrame = currentFrame ? self.frameBuffer[@(nextFrameIndex)] : nil;
dispatch_semaphore_signal(self.lock);
BOOL bufferFull = NO;
if (currentFrame) {
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
// Remove the frame buffer if need
if (self.frameBuffer.count > self.maxBufferCount) {
self.frameBuffer[@(currentFrameIndex)] = nil;
}
// Check whether we can stop fetch
if (self.frameBuffer.count == totalFrameCount) {
bufferFull = YES;
}
dispatch_semaphore_signal(self.lock);
self.currentFrame = currentFrame;
self.currentFrameIndex = nextFrameIndex;
self.bufferMiss = NO;
[self.layer setNeedsDisplay];
} else {
Expand Down Expand Up @@ -261,17 +275,7 @@ - (void)displayDidRefresh:(CADisplayLink *)displayLink
fetchFrameIndex = nextFrameIndex;
}

if (!fetchFrame && !bufferFull && self.fetchQueue.operationCount == 0) {
// Prefetch next frame in background queue
UIImage<RCTAnimatedImage> *animatedImage = self.animatedImage;
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
UIImage *frame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex];
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
self.frameBuffer[@(fetchFrameIndex)] = frame;
dispatch_semaphore_signal(self.lock);
}];
[self.fetchQueue addOperation:operation];
}
[self prefetchNextFrame:fetchFrame fetchFrameIndex:fetchFrameIndex];
}

#pragma mark - CALayerDelegate
Expand Down

0 comments on commit a36e27f

Please sign in to comment.