我正在使用AVFoundation为iOS开发一个自定义视频播放器。这个想法是能够通过手势(点击、滑动等)切换到不同的视频现在玩家在模拟器上完美地工作,但当我在实际设备上测试它时,刷3或4次后视图就会变为空白。我甚至为我的播放器创建了播放控件,当视图变为空白时,这些控件会正确加载,但不会起任何作用。有什么想法吗?这是玩家的初始化
- (id)initWithContentURL:(NSString *)aContentURL delegate:(id)aDelegate {
self = [super initWithNibName:@"NoCashMoviePlayer" bundle:nil];
if (self == nil)
return nil;
delegate = aDelegate;
systemPath = [aContentURL retain];
contentURL = [[NSURL alloc]initFileURLWithPath:systemPath];
asset = [AVURLAsset URLAssetWithURL:contentURL options:nil];
playerItem = [AVPlayerItem playerItemWithAsset:asset];
isPaused = false;
controlsHidden = false;
self.player = [[AVPlayer playerWithPlayerItem:playerItem] retain];
duration = self.player.currentItem.asset.duration;
return self;
}
这是播放视频的代码:
-(void)playMovie{
UITapGestureRecognizer *tapRecon = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(toggleControls:)];
[tapRecon setNumberOfTapsRequired:2];
[self.movieContainer addGestureRecognizer:tapRecon];
[tapRecon release];
NSLog(@"Playing item: %@",contentURL);
playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
[movieContainer.layer addSublayer:playerLayer];
playerLayer.frame = movieContainer.layer.bounds;
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
self.seeker.alpha = 1.0;
[self.view addSubview:movieContainer];
[self.movieContainer addSubview:controls];
[self setSlider];
[player play];
player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[player currentItem]];
}
选择要播放的剪辑的代码:
-(void)viewSelect: (double) curTime{
self.myView.backgroundColor = [UIColor blackColor];
UISwipeGestureRecognizer *swipeRecognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeFrom:)];
swipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self.myView addGestureRecognizer:swipeRecognizer];
[swipeRecognizer release];
UISwipeGestureRecognizer *leftRecognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeFromLeft:)];
swipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[self.myView addGestureRecognizer:leftRecognizer];
[leftRecognizer release];
if(isMain){
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationTransitionFlipFromLeft animations:^{
self.myView.alpha = 1.0;
moviePlayer = [[NoCashMoviePlayer alloc]initWithContentURL:[self movieURL:vidIndex] delegate:self];
self.moviePlayer.view.frame = self.myView.bounds;
self.moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;
[self.myView addSubview:moviePlayer.view];
}completion:^(BOOL finished) {
[self.moviePlayer.player seekToTime:CMTimeMake(curTime, 1)];
[self.moviePlayer playMovie];
}];
}else{
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationTransitionFlipFromLeft animations:^{
self.otherView.alpha = 1.0;
moviePlayer = [[NoCashMoviePlayer alloc]initWithContentURL:[self movieURL:vidIndex] delegate:self];
self.moviePlayer.view.frame = self.otherView.bounds;
self.moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;
[self.otherView addSubview:moviePlayer.view];
}completion:^(BOOL finished) {
[self.moviePlayer.player seekToTime:CMTimeMake(curTime, 1)];
[self.moviePlayer playMovie];
}];
}
}
最后一个手势动作:
- (void)handleSwipeFromLeft:(UISwipeGestureRecognizer *)recognizer {
double elapsedTime = 0.0;
if(vidIndex==0){
vidIndex = 3;
}else vidIndex = vidIndex --;
elapsedTime = [self.moviePlayer currentTimeInSeconds];
[self.moviePlayer stopMovie];
isMain = !isMain;
[self viewSelect: elapsedTime];
}
编辑:尝试为每个视频文件使用不同的AVPlayerLayers,相同的情况下,在模拟器中工作,而不是在iPad上。
第2版:我运行了仪器来分析核心动画性能,当视频播放时,它显示的帧速率约为每秒30帧,当播放器变为空白时,它会一直下降到每秒1或2帧。这可能很奇怪,但如果它有助于提供更多的光线。。。。。
第三版:好吧,我终于有进展了,我知道问题是什么,我有一个核心动画内存泄漏,在模拟器中它"工作"了,因为电脑的内存比iPad多得多,但由于iPad的内存非常有限,它很快就停止了工作。如果有人对核心动画泄露有任何建议,我们会非常欢迎。
我终于解决了它。我的设计确实很糟糕,内存管理很糟糕等等。我所做的是,我没有发布我能发布的一切,包括视图、图层、玩家、资产等,而是创建了一个更新玩家资产和项目的方法,回收玩家、视图、图层等。
[player pause];
contentURL = [[NSURL alloc] initFileURLWithPath:newPath];
AVAsset *newAsset = [AVURLAsset URLAssetWithURL:contentURL options:nil];
AVPlayerItem *newPlayerItem = [AVPlayerItem playerItemWithAsset:newAsset];
[player replaceCurrentItemWithPlayerItem:newPlayerItem];
[contentURL release];
现在它正在创造奇迹。谢谢大家的帮助。
代码中有两个地方保留了一个对象,在您发布的代码中,我没有看到相应的发布版本。我首先要确保内存引用计数的递增和递减都是适当平衡的。
第一个保留在我看来很可疑。通常情况下,你应该先自动释放你分配给的变量,然后保留,如下所示:
[systemPath autorelease];
systemPath = [aContentURL retain]
在上面的代码中,很容易看出保留/释放匹配得到了维护,并且与其他方案相比,不太容易出错。请注意,如果systemPath
==aContentURL
,则不会释放对象。