xcode 使用 AVPlayer 在 iphone 上播放许多不同的视频

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6258573/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 21:12:25  来源:igfitidea点击:

Playing many different videos on iphone using AVPlayer

iphonexcodeipadmedia-playeravfoundation

提问by Samssonart

I'm working on a custom video player for iOS using AVFoundation. The idea is to be able to switch to a different video with a gesture (tap, swipe, whatever). Right now the player is working flawlessly on simulator, but when I test it on an actual device, the view goes blank after 3 or 4 swipes. I've even created playback controls for my player, when the view goes blank, these controls load correctly but do nothing. Any ideas guys? This is the initialization for the player

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

This is the code that plays the video:

这是播放视频的代码:

    -(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]];


    }

The code to select the clip to be played:

选择要播放的剪辑的代码:

    -(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];
            }];
        }
    }

And last the gesture action:

最后是手势动作:

    - (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];

    }

EDIT: Tried using different AVPlayerLayers for each video file, same situation, works in the simulator, not on the iPad.

编辑:尝试为每个视频文件使用不同的 AVPlayerLayers,相同的情况,在模拟器中工作,而不是在 iPad 上。

EDIT 2: I ran instruments to analyze core animation performance, and when the video is playing it's showing framerates of about 30 fps, when the player goes blank it drops all the way down to 1 or 2 fps. This may be ovbious, but still, if it helps give a little more light.....

编辑 2:我运行仪器来分析核心动画性能,当播放视频时,它显示的帧速率约为 30 fps,当播放器变为空白时,它会一直下降到 1 或 2 fps。这可能是显而易见的,但是,如果它有助于提供更多的光.....

EDIT 3: Ok, I'm finally getting somewhere, I know what the problem is, I have a core animation memory leak, in the simulator it "works" because the computer has A LOT more memory than the iPad, but since the iPad has very limited memory it stops working very quickly. If anyone has any advice regarding Core Animation leaks, it will be very well received.

编辑 3:好的,我终于到了某个地方,我知道问题是什么,我有一个核心动画内存泄漏,在模拟器中它“有效”,因为计算机的内存比 iPad 多很多,但是由于 iPad内存非常有限,它很快就会停止工作。如果有人对 Core Animation 泄漏有任何建议,将会很受欢迎。

采纳答案by Samssonart

I FINALLY SOLVED IT. The design I had was indeed very poor, It had a very bad memory management and so on. What I did was, instead of releasing everything I could, including views, layers, players, assets, etc, I just created a method to update the player's asset and item, recycling the player, views, layers, etc.

我终于解决了。我的设计确实很糟糕,它有一个非常糟糕的内存管理等等。我所做的是,我没有发布我能发布的所有内容,包括视图、图层、播放器、资产等,而是创建了一个方法来更新播放器的资产和项目,回收播放器、视图、图层等。

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

And now it's working wonders. Thank you all for your help.

现在它正在创造奇迹。谢谢大家的帮助。

回答by Himadri Choudhury

There are 2 places in the code where you have retained an object, and I don't see the corresponding release anywhere in the code you have posted. I would start by making sure that the memory reference count increments and decrements are all appropriately balanced.

您在代码中有 2 个地方保留了一个对象,我在您发布的代码中的任何地方都没有看到相应的版本。我首先要确保内存引用计数的增量和减量都得到适当的平衡。

The first retain looks suspicious to me. Generally you should first autoreleasethe variable you are assigning to and then retainas follows:

第一个保留在我看来很可疑。通常,您应该首先自动释放您分配给的变量,然后按如下方式保留

[systemPath autorelease];
systemPath = [aContentURL retain]

In the above code is easy to see that the retain/release matching is maintained, and is far less error prone than other schemes. Note that if systemPath== aContentURLthe object will not be released.

在上面的代码中很容易看出保留/释放匹配被维护,并且比其他方案更不容易出错。请注意,如果systemPath==aContentURL对象将不会被释放。