2026-05-22 17:35:49 +08:00

229 lines
6.0 KiB
Plaintext

//
// TGFlutterPageRender.m
// Tgclub
//
// Created by 黎敬茂 on 2021/11/25.
// Copyright © 2021 Tencent. All rights reserved.
//
#import "TGFlutterPagRender.h"
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#import <CoreVideo/CoreVideo.h>
#import <UIKit/UIKit.h>
#include <libpag/PAGFile.h>
#include <libpag/PAGImage.h>
#include <libpag/PAGPlayer.h>
#include <libpag/PAGScaleMode.h>
#include <chrono>
#include <mutex>
@interface TGFlutterPagRender()
@property(nonatomic, strong)PAGSurface *surface;
@property(nonatomic, strong)PAGPlayer* player;
@property(nonatomic, strong)PAGFile* pagFile;
@property(nonatomic, assign)double initProgress;
@property(nonatomic, assign)BOOL endEvent;
@end
static int64_t GetCurrentTimeUS() {
static auto START_TIME = std::chrono::high_resolution_clock::now();
auto now = std::chrono::high_resolution_clock::now();
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(now - START_TIME);
return static_cast<int64_t>(ns.count() * 1e-3);
}
@implementation TGFlutterPagRender
{
FrameUpdateCallback _frameUpdateCallback;
PAGEventCallback _eventCallback;
CADisplayLink *_displayLink;
int _lastUpdateTs;
int _repeatCount;
int64_t start;
int64_t _currRepeatCount;
}
- (CVPixelBufferRef)copyPixelBuffer {
int64_t duration = [_player duration];
if(duration <= 0){
duration = 1;
}
int64_t timestamp = GetCurrentTimeUS();
if(start <= 0){
start = timestamp;
}
auto count = (timestamp - start) / duration;
double value = 0;
if (_repeatCount >= 0 && count >= _repeatCount) {
value = 1;
if(!_endEvent){
_endEvent = YES;
_eventCallback(EventEnd);
}
} else {
_endEvent = NO;
double playTime = (timestamp - start) % duration;
value = static_cast<double>(playTime) / duration;
if (_currRepeatCount < count) {
_currRepeatCount = count;
_eventCallback(EventRepeat);
}
}
[_player setProgress:value];
[_player flush];
CVPixelBufferRef target = [_surface getCVPixelBuffer];
CVBufferRetain(target);
return target;
}
- (instancetype)initWithPagData:(NSData*)pagData
progress:(double)initProgress
imageReplacementsByName:(NSDictionary<NSString*, NSData*>*)imageReplacementsByName
frameUpdateCallback:(FrameUpdateCallback)frameUpdateCallback
eventCallback:(PAGEventCallback)eventCallback
{
if (self = [super init]) {
_frameUpdateCallback = frameUpdateCallback;
_eventCallback = eventCallback;
_initProgress = initProgress;
if(pagData){
_pagFile = [PAGFile Load:pagData.bytes size:pagData.length];
if (_pagFile == nil || _pagFile.width <= 0 || _pagFile.height <= 0) {
return self;
}
[self applyImageReplacementsByName:imageReplacementsByName];
_player = [[PAGPlayer alloc] init];
[_player setComposition:_pagFile];
_surface = [PAGSurface MakeFromGPU:CGSizeMake(_pagFile.width, _pagFile.height)];
[_player setSurface:_surface];
[_player setProgress:initProgress];
[_player flush];
_frameUpdateCallback();
}
}
return self;
}
- (void)applyImageReplacementsByName:(NSDictionary<NSString*, NSData*>*)imageReplacementsByName
{
if (_pagFile == nil || imageReplacementsByName == nil || imageReplacementsByName.count == 0) {
return;
}
[imageReplacementsByName enumerateKeysAndObjectsUsingBlock:^(NSString* layerName, NSData* data, BOOL* stop) {
if (![layerName isKindOfClass:NSString.class] || layerName.length == 0 ||
![data isKindOfClass:NSData.class] || data.length == 0) {
return;
}
PAGImage* image = [PAGImage FromBytes:data.bytes size:data.length];
if (image == nil) {
return;
}
[image setScaleMode:PAGScaleModeZoom];
[_pagFile replaceImageByName:layerName data:image];
}];
}
- (void)startRender
{
if (_player == nil || _surface == nil) {
return;
}
if (!_displayLink) {
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
if(start <= 0){
start = GetCurrentTimeUS();
}
_eventCallback(EventStart);
}
- (void)stopRender
{
if (_player == nil) {
return;
}
if (_displayLink) {
[_displayLink invalidate];
_displayLink = nil;
}
[_player setProgress:_initProgress];
[_player flush];
_frameUpdateCallback();
if(!_endEvent){
_endEvent = YES;
_eventCallback(EventEnd);
}
_eventCallback(EventCancel);
}
- (void)pauseRender{
if (_player == nil) {
return;
}
if (_displayLink) {
[_displayLink invalidate];
_displayLink = nil;
}
}
- (void)setRepeatCount:(int)repeatCount{
_repeatCount = repeatCount;
}
- (void)setProgress:(double)progress{
if (_player == nil) {
return;
}
[_player setProgress:progress];
[_player flush];
_frameUpdateCallback();
}
- (NSArray<NSString *> *)getLayersUnderPoint:(CGPoint)point{
if (_player == nil) {
return @[];
}
NSArray<PAGLayer*>* layers = [_player getLayersUnderPoint:point];
NSMutableArray<NSString *> *layerNames = [[NSMutableArray alloc] init];
for (PAGLayer *layer in layers) {
[layerNames addObject:layer.layerName];
}
return layerNames;
}
- (CGSize)size{
return CGSizeMake(_pagFile.width, _pagFile.height);
}
- (void)update
{
_frameUpdateCallback();
}
- (void)releaseRender{
if (_displayLink) {
[_displayLink invalidate];
_displayLink = nil;
}
}
- (void)dealloc {
_frameUpdateCallback = nil;
_eventCallback = nil;
_surface = nil;
self.pagFile = nil;
self.player = nil;
}
@end