循环 SKVideoNode 的内存泄漏(仅在实际设备上)
Memory leak from looping SKVideoNode (only on actual device)
我有无法诊断的内存泄漏。我尝试了多种创建无缝循环视频的方法——除了 AVPlayerLooper,我遇到并尝试过的所有方法都涉及创建一个观察者来观看 AVPlayerItemDidPlayToEndTimeNotification
,然后寻找视频的开头(在这种情况下AVPlayer)或将要循环播放的视频插入视频队列(在 AVQueuePlayer 的情况下)。两者似乎具有相似的性能,但两者也具有与 seekToTime 方法(在 AVPlayer 的情况下)和 insertItem 方法(在 AVQueuePlayer 的情况下)相关的一致内存保持。我的最终目标是创建一个默认循环的 SKVideoNode 子类。下面是我的子类代码:
#import "SDLoopingVideoNode.h"
#import <AVFoundation/AVFoundation.h>
@interface SDLoopingVideoNode()
@property AVQueuePlayer *avQueuePlayer;
@property AVPlayerLooper *playerLooper;
@end
@implementation SDLoopingVideoNode
-(instancetype)initWithPathToResource:(NSString *)path withFiletype:(NSString *)filetype
{
if(self == [super init])
{
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:path ofType:filetype];
NSURL *videoURL = [NSURL fileURLWithPath:resourcePath];
AVAsset *videoAsset = [AVAsset assetWithURL:videoURL];
AVPlayerItem * videoItem = [AVPlayerItem playerItemWithAsset:videoAsset];
self.avQueuePlayer = [[AVQueuePlayer alloc] initWithItems:@[videoItem]];
NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
[noteCenter addObserverForName:AVPlayerItemDidPlayToEndTimeNotification
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
AVPlayerItem *video = [[AVPlayerItem alloc] initWithURL:videoURL];
[self.avQueuePlayer insertItem:video afterItem:nil];
NSLog(@"Video changed");
}];
self = (SDLoopingVideoNode*)[[SKVideoNode alloc] initWithAVPlayer: self.avQueuePlayer];
return self;
}
return nil;
}
@end
下面是子类在 didMoveToView 中的初始化方式:
SDLoopingVideoNode *videoNode = [[SDLoopingVideoNode alloc]initWithPathToResource:@"147406" withFiletype:@"mp4"];
[videoNode setSize:CGSizeMake(self.size.width, self.size.height)];
[videoNode setAnchorPoint:CGPointMake(0.5, 0.5)];
[videoNode setPosition:CGPointMake(0, 0)];
[self addChild:videoNode];
[videoNode play];
简短的回答是,您将无法使用 AVPlayer 来实现它。相信我,我试过了。相反,可以通过使用 H264 硬件解码然后将每个视频帧重新编码为关键帧来进行无缝循环,github link here。我还构建了一个支持完整 alpha 通道的无缝循环层。即使是全屏 1x1 视频和 iPad 或 iPad pro 的性能也很棒。此外,此代码没有内存泄漏。
我有无法诊断的内存泄漏。我尝试了多种创建无缝循环视频的方法——除了 AVPlayerLooper,我遇到并尝试过的所有方法都涉及创建一个观察者来观看 AVPlayerItemDidPlayToEndTimeNotification
,然后寻找视频的开头(在这种情况下AVPlayer)或将要循环播放的视频插入视频队列(在 AVQueuePlayer 的情况下)。两者似乎具有相似的性能,但两者也具有与 seekToTime 方法(在 AVPlayer 的情况下)和 insertItem 方法(在 AVQueuePlayer 的情况下)相关的一致内存保持。我的最终目标是创建一个默认循环的 SKVideoNode 子类。下面是我的子类代码:
#import "SDLoopingVideoNode.h"
#import <AVFoundation/AVFoundation.h>
@interface SDLoopingVideoNode()
@property AVQueuePlayer *avQueuePlayer;
@property AVPlayerLooper *playerLooper;
@end
@implementation SDLoopingVideoNode
-(instancetype)initWithPathToResource:(NSString *)path withFiletype:(NSString *)filetype
{
if(self == [super init])
{
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:path ofType:filetype];
NSURL *videoURL = [NSURL fileURLWithPath:resourcePath];
AVAsset *videoAsset = [AVAsset assetWithURL:videoURL];
AVPlayerItem * videoItem = [AVPlayerItem playerItemWithAsset:videoAsset];
self.avQueuePlayer = [[AVQueuePlayer alloc] initWithItems:@[videoItem]];
NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
[noteCenter addObserverForName:AVPlayerItemDidPlayToEndTimeNotification
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
AVPlayerItem *video = [[AVPlayerItem alloc] initWithURL:videoURL];
[self.avQueuePlayer insertItem:video afterItem:nil];
NSLog(@"Video changed");
}];
self = (SDLoopingVideoNode*)[[SKVideoNode alloc] initWithAVPlayer: self.avQueuePlayer];
return self;
}
return nil;
}
@end
下面是子类在 didMoveToView 中的初始化方式:
SDLoopingVideoNode *videoNode = [[SDLoopingVideoNode alloc]initWithPathToResource:@"147406" withFiletype:@"mp4"];
[videoNode setSize:CGSizeMake(self.size.width, self.size.height)];
[videoNode setAnchorPoint:CGPointMake(0.5, 0.5)];
[videoNode setPosition:CGPointMake(0, 0)];
[self addChild:videoNode];
[videoNode play];
简短的回答是,您将无法使用 AVPlayer 来实现它。相信我,我试过了。相反,可以通过使用 H264 硬件解码然后将每个视频帧重新编码为关键帧来进行无缝循环,github link here。我还构建了一个支持完整 alpha 通道的无缝循环层。即使是全屏 1x1 视频和 iPad 或 iPad pro 的性能也很棒。此外,此代码没有内存泄漏。