在iOS中作为背景的视频最有效的方法(Most effective method for video as background in iOS)

IPhone IT屋
百度翻译此文   有道翻译此文
问 题

Perhaps you have noticed one of the latest trend in iOS-apps: Using videos as backgrounds - mainly at login- or "first launch" screens. Yesterday I attempted to mimic this with a very simple test project (only one view controller) and I am pleased with the results except for the performance. When trying it out in the iOS Simulator (on a simulated iPhone 6) the CPU usage fluctuates between 70-110%. This seems very unreasonable for a simple login-screen.

This is what it looks like in action: http://oi57.tinypic.com/nqqntv.jpg

The question is then: Is there a more CPU-effective way to achieve this? How are the apps like Vine, Spotify and Instagram doing this?

Before you answer; the method I used was a full-HD video played back using 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];
}

Of course the edges of the video could have been trimmed so that the resolution would be something more along the lines of say 700x1080 instead of 1920x1080 but would that have made a huge difference in performance? Or should I compress the video with a certain format and settings to achieve optimal performance? Maybe there is an entirely alternate approach to this?

Actually I tried using GIFs as described in this article: https://medium.com/swift-programming/ios-make-an-awesome-video-background-view-objective-c-swift-318e1d71d0a2

The problem with that is:

  • Creating GIFs out of videos takes a lot of time and effort
  • I saw no significant decrease of CPU usage when I tried it
  • Supporting multiple screen sizes is a total pain with this approach (at least when I tried - with Autolayout and Size Classes enabled - I couldn't get the GIF to scale correctly across devices)
  • Quality of video is poor
解决方案

Best way is to use AVFoundation then you control the video layer itself

In header file declare @property (nonatomic, strong) 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()

}

Tested on iOS7 - iOS9

本文地址:IT屋 » Most effective method for video as background in iOS

问 题

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



这就是它的实际效果:
http://oi57.tinypic.com/nqqntv.jpg



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



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



   - (void)viewDidLoad {
[ super viewDidLoad];

//查找电影文件
NSString * moviePath = [[NSBundle mainBundle] pathForResource:@“arenaVideo”ofType:@“mp4”];
NSURL * movieURL = [NSURL fileURLWithPath:moviePath];

//加载电影
self.movi​​ePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
self.movi​​ePlayer.controlStyle = MPMovieControlStyleNone;
self.movi​​ePlayer.view.frame = self.view.frame;
self.movi​​ePlayer.scalingMode = MPMovieScalingModeAspectFill;
[self.view addSubview:self.movi​​ePlayer.view];
[self.view sendSubviewToBack:self.movi​​ePlayer.view];
[self.movi​​ePlayer play];

//循环电影
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(replayMovie :)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self .movi​​ePlayer];
}

#pragma mark - 助手方法

- (无效)replayMovie:(NSNotification *)通知
{
[self。 moviePlayer play];
}


当然,视频的边缘可能已被修剪,以便分辨率可以更像是700x1080而不是1920x1080,但这会在性能方面产生巨大的影响吗?或者我应该使用特定格式和设置压缩视频以获得最佳性能?也许有一种完全替代方法吗?



实际上我尝试使用本文所述的GIF: https://medium.com/swift-programming/ios-make-an-awesome-video-background- view-objective-c-swift-318e1d71d0a2



问题在于:




  • 从视频中创建GIF需要花费大量的时间和精力。

  • 我在尝试时没有看到CPU使用量显着下降

  • 使用这种方法支持多种屏幕尺寸是一种完全的痛苦(至少在我尝试时 - 启用了Autolayout和Size Classes - 我无法让GIF在各设备之间正确扩展)

  • 视频质量差


解决方案

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



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



   - (void)viewDidLoad {
[super viewDidLoad];


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

//循环电影
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(replayMovie :)
name:AVPlayerItemDidPlayToEndTimeNotification
object:nil ]。
}
- (AVPlayerLayer *)playerLayer {
if(!_ playerLayer){

//找到电影文件
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];

}
返回_playerLayer
}
- (无效)replayMovie:(NSNotification *)通知
{
[self.playerLayer.player玩];
}


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?

//这是必需的,因此它不会切断用户音频(如果听音乐等等)
do {
try AVAudioSession.sharedInstance()。setCategory(AVAudioSessionCategoryAmbient)
}捕获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)
返回playerLayer
}()

覆盖func viewDidLoad(){
super.viewDidLoad()
self.view.layer.addSublayer( self.playerLayer)
}
结束ride func viewWillDisappear(animated:Bool){
NSNotificationCenter.defaultCenter()。removeObserver(self)
}
//如果方向改变
覆盖func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation:UIInterfaceOrientation,duration :NSTimeInterval){
playerLayer.frame = self.view.frame
}
func playerDidReachEnd(){
self.playerLayer.player!.seekToTime(kCMTimeZero)
self.playerLayer.player!.play()

}


经过测试iOS7 - iOS9


本文地址:IT屋 » 在iOS中作为背景的视频最有效的方法

官方微信
扫一扫关注IT屋
微信公众号搜索 “ IT屋 ” ,选择关注
与百万开发者在一起