Skip to content

Latest commit

ย 

History

History
323 lines (209 loc) ยท 8.73 KB

DeliveringIntuitiveMediaPlaybackWithAVKit.md

File metadata and controls

323 lines (209 loc) ยท 8.73 KB

@ WWDC 19

AVKit in the Stack

image

import AVKit

// ์‹ค์ œ๋กœ๋Š” url ์ƒ์„ฑ ํ›„ ๋„ฃ์–ด์ค˜์•ผ ํ•จ ๊ตฌ๋ผ์Ÿ์ด ์•„์ €์”จ ํฅ
// 1) Create an AVPlayer
let player = AVPlayer(url: "https://my.example.video.m3u8") 

// 2) Create an AVPlayerViewController
let playerViewController = AVPlayerViewController()
playerViewController.player = player

// 3) Show it
present(playerViewController, animated: true)

AVPlayerViewController on iOS: What's new for iOS 13

Full screen callbacks (ํ’€์Šคํฌ๋ฆฐ enter, exit ๊ฐ์ง€)

  • Extends AVPlayerViewControllerDelegate
  • Notifies delegate when beginning or ending full screen presentation
@available(iOS 12.0, *)

func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator)

func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator)

// Implementing AVPlayerViewControllerDelegate's full screen callbacks

func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
  coordinator.animate(alongsideTransition: { (context) in
		// Add coordinated animations
  }) { (context) in
     if context.isCancelled {
       // Still embedded inline
     } else {
       // Presented full screen
       // Take strong reference to playerViewController if needed
     }
	}
}
  • Keep embeded player view controller alive when full screen (ํ’€์Šคํฌ๋ฆฐ์œผ๋กœ ๋„์› ๋Š”๋ฐ ์›๋ž˜ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ์‚ฌ๋ผ์ง€๋ฉด ์•ˆ ๋˜๊ฒ ์ง€?!)
    • Deallocating will stop full screen playback
    • Okay to be offscreen or removed from superview / parent
  • Use delegate to restore playerViewController or retarget animation
func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
  // If scrolled away, update playerViewController's layout here
}
  • Track full screen presentation state with AVPlayerViewControllerDelegate
    • Do not rely on viewWillAppear(_:) and friends
  • Works for both embedded and full screen presentations
  • Keep embedded player view controller alive when full screen
  • Can retarget dismissal animation when embedding inline

AVPlayerViewController in iPad Apps on the Mac

  • Exact same API as on iOS
  • Picture-in-picture support
    • Including AVPictureInPictureController (also for AppKit)
    • And AVPlayerView, for AppKit-based apps
  • Touch Bar, keyboard, and Now Playing support
  • Audio and Airplay routing
  • Available in macOS 10.15

External Metadata

: ์ž ๊ธˆ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ํ”Œ๋ ˆ์ด์–ด ์•Œ์ง€? ๊ทธ๋Ÿฐ ๋ฐ์— ์ •๋ณด๋ฅผ ์ž˜ ๋ณด์—ฌ์ฃผ๋ ค๋ฉด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ๋ผ.

  • Supplement missing metadata
    • Title, artwork, and more
  • Same API as tvOS
@available(iOS 12.0, *)
extension AVPlayerItem {
  open var externalMetadata: [AVMetadataItem]
}

Improved Support for Custom Controls

  • Interactive dismissals
  • Landscape support for portrait-only apps
  • Keyboard and Touch Bar support
  • Now playing management
  • Automatic video zoom

Custom Playback Controls

  • Set showsPlaybackControls to false
  • Present modally
  • Add controls to contentOverlayView
  • For the best user experience, you should:
    • Override UIViewController methods for status bar, home indicator
    • Pass unhandled touches through your view
    • Let AVKit handle double-tap for video zoom

What's New

  • Full screen callbacks
  • AVPlayerViewController in iPad apps for the Mac
    • Plus picture-in-picture support for AppKit-based apps
  • External metadata
  • Improved support for custom controls

AVPlayerViewController on iOS: Best practices

Showing Full Screen

  • Covers UIWindowScene coordinate

  • Use cases:

    • Splash screen
    • Full screen playback

Splash Screen

  • Underneath your UI

  • No interaction playback controls

  • No need to hide status bar or home indicator

  • Possibly looping

  • Video should always fill screen

  • For video with alpha, custom background color

  • Audio is secondary

  • Add as child:

    parent.addChild(playerViewController)
    parent.view.addSubview(playerViewController.view) // Or other UIView insertion API
    playerViewController.didMove(toParent: parent)
  • Remove from parent:

    playerViewController.willMove(toParent: nil)
    playerViewController.view.removeFromSuperview()
    playerViewController.removeFromParent()
  • Disable playback controls:

    playerViewController.showsPlaybackControls = false
  • Make video fill entire screen:

    playerViewController.videoGravity = .resizeAspectFill
  • Set background color (if needed):

    playerViewController.view.backgroundColor = .clear // Or any other UIColor
  • Disable AVPlayer.allowsExternalPlayback

  • Configure AVAudioSession for secondary media playback

    • Use .ambient category
  • Observe AVAudioSession.silenceSecondaryAudioHintNotification

    • Honor AVAudioSession.secondaryAudioShouldBeSilenceHint

Full Screen Playback

  • Present modally
  • Use the default modalPresentationStyle <- iOS 13์—์„œ default๊ฐ€ automatic์ด๋‹ˆ๊นŒ ๊ฑ default ์“ฐ๋ž˜!
  • Do not set AVPlayerViewController.videoGravity
  • Use AVPlayerViewControllerDelegate to track full screen presentation state
    • Do not rely on viewWillAppear(_:) and friends
  • Set up AVPlayerItem before buffering
    • Set AVPlayer.rate for setting item
  • Observe AVPlayer.status and AVPlayerItem.status
    • Don't begin playback until status is .readyToPlay
    • Check error property when staus is .failed
      • Rebuild AVFoundation object if .mediaServicesWereReset
  • Enable AVPlayer.usesExternalPlaybackWhileExternalScreenIsActive
  • Configure AVAudioSession for .playback

Embeding AVPlayerViewController Inline

  • Be prepared to begin and end full screen playback

    • Track state using AVPlayerViewControllerDelegate
    • Keep strong reference to embedded AVPlayerViewController when full screen
    • Retarget dismissal animations when ending full screen presentation
  • Leave modalPresentationStyle as .fullScreen

  • Can style embedded content without impacting full screen:

    • videoGravity
    • view.layer.cornerRadius, cornerCurve, and maskedCorners
    • view.backgroundColor
  • For automatically entering and exiting full screen:

    • entersFullScreenWhenPlaybackBegins
    • exitsFullScreenWhenPlaybackEnds
  • Adopt UIViewController containment API

  • Add as child:

    parent.addChild(playerViewController)
    containerView.addSubview(playerViewController.view) // Don't put views on top
    playerViewController.didMove(toParent: parent)
  • Remove from parent:

    playerViewController.willMove(toParent: nil)
    playerViewController.view.removeFromSuperview()
    playerViewController.removeFromParent()
  • Use .contentOverlayView <- ์•ฝ๊ฐ„ ๋‚ด๊ฐ€ ์ฐพ๋˜ ๋Š๋‚Œ์“ฐ, ์ข€ ๋” ๊ณต๋ถ€ํ•ด ๋ณด์ž.

    • Okay to use before setting player or player item
  • Observe .isReadyForDisplay

    • Returns true when first frame is ready
    let token = pvc.observe(\.isReadyForDisplay, options: [.initial]) { [weak self] in
      if observed.isReadyForDisplay {
        // Hide any poster frame or placeholder
      }
    }

Picture-in-picture

  • Configure AVAudioSession for .playback

  • Add background audio mode entitlement in Xcode

  • Don't pause playback when entering background

    • Picture-in-picture may be starting!
  • If you must pause, wait until in background

    • Only if picture-in-picture hasn't started
    • Pre-iOS 13: UIApplicationStateBackground
    • iOS 13 and later: UISceneActivationStateBackground
  • Track state using AVPlayerViewControllerDelegate

  • Application can stop picture-in-picture

    • Toggle AVPlayerViewController.allowsPictureInPicturePlayback
  • Be prepared for dismissal when starting

    • AVKit prevents deallocation while active
  • Always restore user interface when requested by user

    // Restoring from picture-in-picture using AVPlayerViewControllerDelegate
    func playerViewController(_ playerViewController: AVPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
      presentingViewController.present(playerViewController, animated: true) {
        // Must invoke completionHandler
        completionHandler(true)
      }
    }

tvOS ๋‚ด์šฉ์€ ์ •๋ฆฌ๋Š” ๋”ฑํžˆ ์ •๋ฆฌํ•˜์ง€ ์•Š๊ฒ ๋‹ค!