Media playback with AVKit
AVKit의 포지션
iOS 예제
import AVKit
let player = AVPlayer(url: "<https://my.example/video.m3u8>")
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true)
그 외에도 수많은 기반 기술들을 기반으로 하고 있다.
What's new
FullScreen callbacks
@available(iOS 12.0, *)
func playerViewController(_ playerViewController: AVPlayerViewController,
willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator)
func playerViewController(_ playerViewController: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator)
func playerViewController(_ playerViewController: AVPlayerViewController,
willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (context) in
// Add coordinated animations
}) { context in
if context.isCancelled {
// 여전히 embedding상태
} else {
// 풀스크린 상태
// playerViewController의 레퍼런스를 잡아야 하면 여기서 잡아준다.
}
}
}
스크롤 때문에 원래 위치가 화면에서 벗어나거나, 아예 플레이어 자체가 뷰 계층에서 제거될 수도 있다. → 이때를 대비해 따로 레퍼런스를 잡아야 한다.
func playerViewController(_ playerViewController: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
// 스크롤로 인해 벗어났다면, playerViewController의 레이아웃을 복구한다.
}
AVPlayerViewController in iPad apps on the Mac
External Metadata
@available(iOS 12.0, *)
extension AVPlayerItem {
open var extenalMetadata: [AVMetadataItem]
}
Improved support for custom controls
Best Practices
Showing FullScreen
뷰컨트롤러 containment
parent.addChild(playerViewController)
parent.view.addSubView(playerViewController.view)
playerViewController.didMove(toParent: parent)
playerViewController.willMove(toParent: nil)
playerViewController.view.removeFromSuperView()
playerViewController.removeFromParent()
컨트롤 제거
playerViewController.showsPlaybackControls = false
화면 채우기 설정
playerViewController.videoGravity = .resizeAspectFill
백그라운드 컬러 설정(필요시)
playerViewController.view.backgroundColor = .clear
외부에 재생되는 것을 막는다.
AVPlayer.allowsExternalPlayback = false
부가 오디오 재생: AVAudioSession
AVAudioSession.silenceSecondaryAudioHintNotification을 감시해라
요구사항
필요 코드: 대부분은 AVPlayerViewController()를 쓰면 자동으로 얻을 수 있다.
import AVKit
let player = AVPlayer(url: "<https://my.example/video.m3u8>")
player.currentItem?.externalMetadata = // [AVMetaData]
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true)
베스트 프렉티스
AVPlayerItem은 버퍼링되기 전에 설정하고 AVPlayer에 넘겨라
AVPlayer.status와 AVPlayerItem.status를 Observing하라. → KVO로
useExternalPlaybackWhileExternalScreenIsActive 옵션을 키면, 미러링에 최적화된다.
AudioSession 설정은 .playback
Embedding inline
fullscreen playback 캐치는 마찬가지로 AVPlayerViewControllerDelegate를 통해서
AVViewController는 풀스크린일 때 리테인을 해놔야 한다.
내릴때 다시 원복시키는 것도 잊지 말고
modalPresentationStyle은 fullScreen으로 해서 UIKit이 최적화를 하도록 유도한다.
videoGravity, view.layer.cornerRadius, cornerCurve, maskedCorners, view.backgroundColor 옵션은 fullscreen 모드에 영향을 주지 않고 동작한다.
embeding에서 자동으로 풀스크린으로 동작하고 종료할 때 꺼지는 등의 옵션은 프로퍼티로 조정할 수 있다.
entersFullScreenWhenPlaybackBegins
exitsFullScreenWhenPlaybackEnds // 사용자 행동을 추적하고 있다가 적절한 시점에만 내려가는 것을 보장한다.
당연히 UIViewController Containment API를 도입해야한다.
비디오가 여러개 있고 스크롤해야하는 경우는 비디오 로딩을 기다리지말고 .contentOverlayView로 포스터 이미지를 보여주는 게 좋을 수 있다.
let token = pvc.observe(\\.isReadyForDisplay, options: [.initial]) }
[weak self] observed, _ in
if observed.isReadyForDisplay {
// 포스터 이미지나 플레이스 홀더 감추가
}
}
Picture-in-Picture
modal fullscreen일 때랑다르게, 플레이중에는 deallocate되지 않는다.
modal이 아닌 경우는, delegate에서 UserInterface를 복구해야 한다.
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void)
{
presentingViewController.present(playerViewController, animated: true) {
// 반드시 호출할 것
completionHandler(true)
}
}
Playback in TvOS