Подтвердить что ты не робот

Самый эффективный метод для видео в качестве фона в iOS

Возможно, вы заметили одну из последних тенденций в iOS-приложениях: использование видео в качестве фона - в основном на экранах входа или "первого запуска". Вчера я попытался подражать этому с помощью очень простого тестового проекта (только одного контроллера представления), и я доволен результатами, за исключением производительности. При тестировании в iOS Simulator (на моделированном iPhone 6) использование ЦП колеблется между 70-110%. Это кажется очень необоснованным для простого экрана входа в систему.

Вот как это выглядит в действии: http://oi57.tinypic.com/nqqntv.jpg

Вопрос заключается в следующем: есть ли более эффективный для CPU способ достичь этого? Как это делают такие приложения, как Vine, Spotify и Instagram?

Прежде чем ответить; метод, который я использовал, - это воспроизведение полного HD-видео с помощью 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, как описано в этой статье: https://medium.com/swift-programming/ios-make-an-awesome-video-background-view-objective-c-swift-318e1d71d0a2

Проблема с этим:

  • Создание GIF файлов из видео занимает много времени и усилий.
  • Я не видел значительного снижения использования ЦП, когда я его пробовал
  • Поддержка нескольких размеров экрана является общей болью при таком подходе (по крайней мере, когда я пытался - с включенными режимами Autolayout и Size), я не мог правильно настроить GIF на всех устройствах.
  • Качество видео плохое
4b9b3361

Ответ 1

Лучший способ - использовать AVFoundation, тогда вы сами управляете самим слоем видео

В заголовочном файле 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()

}

Протестировано на iOS7 - iOS9

Ответ 2

Я понимаю, что это старый пост, но поскольку у меня был некоторый опыт, снижающий использование процессора в моем приложении iOS, я отвечу.

Первое место для поиска - AVFoundationFramework

Внедрение AVPlayer должно помочь немного снизить процессор

но лучшим решением является использование библиотеки Brad Larson GPUImage, которая использует OpenGl и значительно уменьшит использование ЦП. Загрузите библиотеку, и есть примеры того, как ее использовать. Я рекомендую использовать GPUImageMovieWriter

Ответ 3

Я делаю это с помощью AVAssetReader, GLKView и рендеринга через конвейер CIImage. При воспроизведении нефильтрованного видео на симуляторе он потребляет около 80% процессора. На реальном устройстве он стоит 1% при фильтрации в реальном времени (CIFilter). Он также может быть установлен на петлю и управлять FPS. Я сделал это на Github и приветствую любого, чтобы иметь копию. Это будет хороший альтернативный вариант, потому что кто-то не хочет бросать весь GPUImage только для просмотра видеофайлов. Перетащите представление, и оно работает. https://github.com/matthewlui/FSVideoView

Ответ 4

Я нашел этот код на GitHub, который работал у меня в 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];
}

Ответ 5

Для iOS9 я использовал код Andrius и добавил для цикла следующее:

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