使用AVPlayer在iPhone上播放多种不同的视频

5

我正在使用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];

    }

编辑:尝试为每个视频文件使用不同的AVPlayerLayer,但情况相同,在模拟器中可以运行,但在iPad上无法运行。

编辑2:我使用instruments来分析核心动画性能,当视频正在播放时,它显示约30 fps的帧率,当播放器变空白时,帧率降至1或2 fps。这可能很明显,但如果它有助于提供更多信息.....

编辑3:好了,我终于有所进展,我知道问题出在哪里了,我有一个核心动画内存泄漏,在模拟器中它“工作”,因为计算机比iPad具有更多的内存,但由于iPad的内存非常有限,它会很快停止工作。如果有人对核心动画泄漏有任何建议,那将非常受欢迎。

2个回答

4

我终于解决了它。我的设计确实非常糟糕,它有非常糟糕的内存管理等问题。我所做的是,不是释放我能释放的所有东西,包括视图、层、播放器、资源等,而是创建了一个方法来更新玩家的资产和物品,回收玩家、视图、层等。

    [player pause];
    contentURL = [[NSURL alloc] initFileURLWithPath:newPath];
    AVAsset *newAsset = [AVURLAsset URLAssetWithURL:contentURL options:nil];
    AVPlayerItem *newPlayerItem = [AVPlayerItem playerItemWithAsset:newAsset];
    [player replaceCurrentItemWithPlayerItem:newPlayerItem];
    [contentURL release];

现在它正在奇迹般地发挥作用。感谢你们的帮助。


1

代码中有2个地方你保留了一个对象,但我在你发布的代码中没有看到相应的释放。我建议首先确保内存引用计数的增减是平衡的。

第一个保留对我来说看起来可疑。通常你应该先将要分配的变量设置为自动释放,然后再进行保留操作,如下所示:

[systemPath autorelease];
systemPath = [aContentURL retain]

在上述代码中,很容易看出保留/释放匹配是得到维护的,而且比其他方案出错的可能性要小得多。请注意,如果systemPath == aContentURL,则该对象将不会被释放。

所有保留的对象都会在“dealloc”方法中释放。这样就足够了吗?实际上,我曾经使用过没有“retain”关键字的播放器,但是效果更差,最终导致崩溃,因为对象在运行时某个时刻被释放了。 - Samssonart
不确定没有看到确切的代码。但是第一个保留似乎不遵循标准模式。 - Himadri Choudhury
谢谢你的帮助,Himadri。我尝试了几种不同的内存/引用计数解决方案,但仍然没有效果。我尝试使用工具进行调试,发现了一些泄漏问题,我已经处理了它们,但还是没有改善。我会继续尝试。 - Samssonart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接