在iOS中最有效的视频作为背景的方法

在iOS中最有效的视频作为背景的方法,ios,objective-c,iphone,user-interface,video,Ios,Objective C,Iphone,User Interface,Video,也许你已经注意到了iOS应用程序的一个最新趋势:使用视频作为背景——主要是在登录或“首次发布”屏幕上。昨天,我尝试用一个非常简单的测试项目(只有一个视图控制器)来模拟这一点,我对结果感到满意,除了性能。在iOS模拟器(在模拟的iPhone 6上)中试用时,CPU使用率在70-110%之间波动。对于一个简单的登录屏幕来说,这似乎非常不合理 这就是它在运行中的样子: 问题是:有没有更有效的CPU方法来实现这一点?Vine、Spotify和Instagram等应用程序是如何做到这一点的 在你回答之前

也许你已经注意到了iOS应用程序的一个最新趋势:使用视频作为背景——主要是在登录或“首次发布”屏幕上。昨天,我尝试用一个非常简单的测试项目(只有一个视图控制器)来模拟这一点,我对结果感到满意,除了性能。在iOS模拟器(在模拟的iPhone 6上)中试用时,CPU使用率70-110%之间波动。对于一个简单的登录屏幕来说,这似乎非常不合理

这就是它在运行中的样子:

问题是:有没有更有效的CPU方法来实现这一点?Vine、Spotify和Instagram等应用程序是如何做到这一点的

在你回答之前;我使用的方法是使用MPMoviePlayerController播放全高清视频:

- (void)viewDidLoad {
    [super viewDidLoad];

    // find movie file
    NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"arenaVideo" ofType:@"mp4"];
    NSURL *movieURL = [NSURL fileURLWithPath:moviePath];

    // load movie
    self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
    self.moviePlayer.controlStyle = MPMovieControlStyleNone;
    self.moviePlayer.view.frame = self.view.frame;
    self.moviePlayer.scalingMode = MPMovieScalingModeAspectFill;
    [self.view addSubview:self.moviePlayer.view];
    [self.view sendSubviewToBack:self.moviePlayer.view];
    [self.moviePlayer play];

    // loop movie
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(replayMovie:)
                                                 name: MPMoviePlayerPlaybackDidFinishNotification
                                               object: self.moviePlayer];
}

#pragma mark - Helper methods

-(void)replayMovie:(NSNotification *)notification
{
    [self.moviePlayer play];
}
当然,视频的边缘可以被修剪,这样分辨率会更接近700x1080,而不是1920x1080,但这会在性能上产生巨大的差异吗?或者我应该用特定的格式和设置压缩视频以获得最佳性能?也许有一种完全不同的方法来解决这个问题

实际上,我尝试使用本文中描述的GIF:

问题是:

  • 从视频中创建GIF需要花费大量的时间和精力
  • 当我尝试它时,我没有看到CPU使用率的显著降低
  • 支持多种屏幕尺寸是这种方法的一大难题(至少在我尝试时——启用了自动布局和大小类——我无法使GIF在设备间正确缩放)
  • 视频质量很差

我意识到这是一篇老文章,但由于我在降低iOS应用程序的CPU使用率方面有一些经验,我会做出回应

首先要看的是使用

实现应该有助于降低一点CPU


但最好的解决方案是使用Brad Larson的库,它利用OpenGl,将大大减少CPU的使用。下载该库,这里有一些如何使用的示例。我建议使用GPUImageMovieWriter

最好的方法是使用
AVFoundation
然后控制视频层本身

在头文件中声明
@property(非原子,强)AVPlayerLayer*playerLayer

- (void)viewDidLoad {
      [super viewDidLoad];


      [self.view.layer addSublayer:self.playerLayer];

      // loop movie
      [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(replayMovie:)
                                             name: AVPlayerItemDidPlayToEndTimeNotification 
                                             object:nil];
}
-(AVPlayerLayer*)playerLayer{
      if(!_playerLayer){

         // find movie file
         NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"arenaVideo" ofType:@"mp4"];
         NSURL *movieURL = [NSURL fileURLWithPath:moviePath];
         _playerLayer = [AVPlayerLayer playerLayerWithPlayer:[[AVPlayer alloc]initWithURL:movieURL]];
         _playerLayer.frame = CGRectMake(0,0,self.view.frame.size.width, self.view.frame.size.height);
         [_playerLayer.player play];

      }
    return _playerLayer
}
-(void)replayMovie:(NSNotification *)notification
{
    [self.playerLayer.player play];
}
Swift 2.0

lazy var playerLayer:AVPlayerLayer = {

    let player = AVPlayer(URL:  NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("LaunchMovie", ofType: "mov")!))
    player.muted = true
    player.allowsExternalPlayback = false
    player.appliesMediaSelectionCriteriaAutomatically = false
    var error:NSError?

    // This is needed so it would not cut off users audio (if listening to music etc.
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient)
    } catch var error1 as NSError {
        error = error1
    } catch {
        fatalError()
    }
    if error != nil {
        print(error)
    }

    var playerLayer = AVPlayerLayer(player: player)
    playerLayer.frame = self.view.frame
    playerLayer.videoGravity = "AVLayerVideoGravityResizeAspectFill"
    playerLayer.backgroundColor = UIColor.blackColor().CGColor
    player.play()
    NSNotificationCenter.defaultCenter().addObserver(self, selector:"playerDidReachEnd", name:AVPlayerItemDidPlayToEndTimeNotification, object:nil)
    return playerLayer
    }()

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.layer.addSublayer(self.playerLayer)
}
override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}
// If orientation changes
override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    playerLayer.frame = self.view.frame
}
func playerDidReachEnd(){
    self.playerLayer.player!.seekToTime(kCMTimeZero)
    self.playerLayer.player!.play()

}
在iOS7-iOS9上测试时,我发现这在iOS8/9中对我有效

- (void)viewDidLoad {
    [super viewDidLoad];

    // Load the video from the app bundle.
    NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"video" withExtension:@"mov"];

    // Create and configure the movie player.
    self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];

    self.moviePlayer.controlStyle = MPMovieControlStyleNone;
    self.moviePlayer.scalingMode = MPMovieScalingModeAspectFill;

    self.moviePlayer.view.frame = self.view.frame;
    [self.view insertSubview:self.moviePlayer.view atIndex:0];

    [self.moviePlayer play];

    // Loop video.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loopVideo) name:MPMoviePlayerPlaybackDidFinishNotification object:self.moviePlayer];
}

- (void)loopVideo {
    [self.moviePlayer play];
}

我使用Avassetrader、GLKView并通过CIImage管道进行渲染。 在模拟器上播放未经过滤的视频时,它消耗了大约80%的cpu。 在实际设备上,实时过滤(CIFilter)成本为1x%。它也可以设置为循环和控制FPS。我已经在Github上完成了,欢迎任何人复制。这将是一个很好的选择,因为有些人不想放弃整个GPUImage只是一个视频背景视图。 拖放视图,它就会工作。

对于iOS9,我使用了Andrius的代码,并为循环添加了以下内容:

-(void)replayBG:(NSNotification *)n {
    [playerLayer.player seekToTime:kCMTimeZero];
    [playerLayer.player play];
}

gif的文件大小也高于视频。我也对一个解决方案感兴趣。这个家伙有一个有趣的方法:在你发帖之前先看问题,我已经试过了@DavidDelMonte@EricAlford为什么不呢?在委托方法中重置时间:[playerLayer.player seekToTime:kCMTimeZero];[playerLayer.player play];当我实现它时,它崩溃了