Skip to content

Latest commit

ย 

History

History
240 lines (147 loc) ยท 5.97 KB

AdvancesinAVFoundationPlayback.md

File metadata and controls

240 lines (147 loc) ยท 5.97 KB

@ WWDC 16

Kinds of Playback

  • Local File
  • Progressiive Download
  • HTTP Live Streaming

Media Playback Over the Internet

  • Playback is at the mercy of the network!
    • ๋„ˆ๋ฌด ๋นจ๋ฆฌ ์‹œ์ž‘ํ•˜๋ฉด playback์ด ๋ฒ„๋ฒ…์ผ ์ˆ˜ ์žˆ์Œ
    • ๋„ˆ๋ฌด ๋Šฆ๊ฒŒ ์‹œ์ž‘ํ•˜๋ฉด ์œ ์ €๊ฐ€ ๋ถˆํ–‰ ใ… 
    • ์–ธ์ œ ์‹œ์ž‘ํ•ด์•ผ ํ•  ์ง€๋ฅผ ์ž˜ ๊ฒฐ์ •ํ•ด์•ผ ํ•จ

AVPlayerItem Buffering State Properties

playbackLikelyToKeepUp
playbackBufferFull
playbackBufferEmpty
  • For progressive-download playbackk, in iOS 9
    • Wait until playbackLkelyToKeepUp or playbackBufferFull before setting AVPlayeer.rate
  • For HLS, rules are simpler
    • Set AVPlayer.rate and it will automatically wait for buffering before playback begins

AVPlayer in iOS 10 / macOS Sierra / tvOS 10

  • Same rules for progressive and HLS
    • Set AVPlayer.rate when user clicks play
    • Automatically waits to buffer to avoid stalling
  • If network dropps and playback stalls, playback will automatically resume when buffered

automaticallyWaitsToMinimizeStalling

image

AVPlayer.rate

Might not mean what you thought it meant

image

Cautions

  • Enabled automatically if app linked on or after iOS 10, OSX 10.12, tvOS 10
    • AVPlayer.automatiicallyWaitsToMiinimizeStalling = true
  • Opt out if using `setRate(..., time:, atHostTime:...) to synchronize playback with external timeline
    • AVPlayer.automatcallyWaitsToMinimizeStallng = false
    • Otherwise, NSException
  • Never use the player rate to project currentTime into the future
    • Use currentItem's timebase rate for that instead

How Do You Loop an AVPlayeerItem?

ํ•˜๋‚˜๊ฐ€ ๋๋‚˜๋ฉด ๋‹ค๋ฅธ ๊ฒƒ์„ ์žฌ์ƒ์‹œํ‚จ๋‹ค๋ฉด latency ๋ฐœ์ƒ! ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜๊ฐ€ ๋‹ค ๋๋‚˜๊ธฐ ์ „์— ์‹œ์ž‘ํ•œ๋‹ค.

AVQueuePlayer

  • ์ผ์ข…์˜ Threadmill
  • AVPlayerItem์˜ ๋ฐฐ์—ด
  • ์žฌ์ƒ์ด ๋๋‚œ AVPlayerItem์€ ๋งจ ๋’ค๋กœ ์˜ฎ๊น€
override func observeValue(forKeyPath keyPath: String?, of object: AnyObjct?, change: [NSKeyValueChangeKey : AnyObject]?, context: UnsafeMutablePointer<Vooid>?) {
  if context == &ObserverContexts.currentItem {
    guard let player = player else { return }
    if player.items().isEmpty {
      // PPlay queue emptied out due to bad player item. End looping.
    }
    else {
      if let itemRemoved = change?[.oldKey] as? AVPlayerItem {
        itemRemoved.seek(to: kCMTimeZero)
        stopObserving()
        player.insert(itemRemoved, after: nil)
        startObserving()
      }
    }
  }
  // else ...
}

AVPlayerLooper

player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: videoURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
player.play()

Optimizing Movies foro Looping

audio, video track์ด ๋™์ผํ•œ ๊ธธ์ด๋ฅผ ๊ฐ€์ง์„ ๋ณด์žฅํ•ด๋ผ

Some More Smoothness

  • Adding / Removing the only AVPlayerLayer on playing AVPlayer
  • Changing subtitle language on playing AVPlayer
  • Changing audio language on playing AVPlayer
  • Manually disabling / enabling tracks on playing AVPlayer

์ปฌ๋Ÿฌ

์ปฌ๋Ÿฌ ์ค‘์š”ํ•ด์ง€๊ณ  ์žˆ๋‹ค. wide color space๋ฅผ ๋ณด์žฅํ•ด๋ผ

Speeding Up Local File Playback

let asset = AVURLAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
let playerLayer = AVPlayerLayer(player: player)

Order Matters

let asset = AVURLAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer() // ์œ„์—์„œ๋Š” ์—ฌ๊ธฐ์— playerItem์„ ๋ฐ”๋กœ ๋„ฃ์–ด์คฌ์—ˆ์Œ
let playerLayer = AVPlayerLayer(player: player) // ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ๋Š” player ๋ฐ”๋กœ ๋„ฃ์–ด์คŒ
player.replaceCurrentItemWithPlayerItem(playerItem) // ๊ทธ๋Ÿฐ ๋‹ค์Œ, replace!

Best Practice

  • Configure AVPlayer and AVPlayerItem first
  • Connect AVPlayerLayer to AVPlayer or AVPlayerIteVideoOutpput to AVPlayerItem
  • player.play() // ๋จผ์ € ์‹œ์ž‘ํ•ด๋‘๊ณ 
  • player.replaceCurrentItemWithPlayerItem(playerItem) // replace

Speeding Up HTTP Live Streaming

  • master playlist๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋”ฉ
var asset = AVURLAsset(url: url)
asset.loadValuesAsynchronously(forKeys: ["duration"], completionHandler: nil)
  • Compress Master Playlists and Varient Playlists with gzip
    • Your serveer may be able to do this for you
  • ๊ทธ ์™ธ์— ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค
    • Retrieve master playlist
    • Retrieve content keys
    • Retrieve selected variant playlist
    • Retrieve segments
  • playback ์ด์ „์— ๋ฏธ๋ฆฌ segment ๋กœ๋”ฉ
// on title card
var playerIItem = AVPlayerIitme(asset: asset)
playerItem.preferredForwardBufferDuration = CMTime(vallue: 5, timescale: 1)
let player = AVPlayer()
let playerLayer = AVPlayerLayer() // ๋ ˆ์ด์–ด๋Š” ํžˆ๋“  ์ƒํƒœ๋กœ ๋‘์ž
player.replaceCurrentItemWithPlayerItem(playerItem)

// as soon as playback begins, reset it it to default
playerItem.preferredForwardBufferDuration = kCMTimzeZero

Speeding Up FairPlay Streaming Startup

var asset = AVURLAsset(url: url)
asset.resourceLoader.preloadsEligibleContentsKys = true
  • Master playlist must contain SESSION-KEY declarations

Improving Initial Quality

  • Size your AVPlayerLayer appropriately and connect it to AVPlayer early
    • Before bringing in playerItem
  • Set AVPlayerLayer.contentsScale ono retina iOS devices.

Profile Your Code

  • Look for delays in your code, before AVFoundation is called

  • Don't wait for likelyToKeepUp notification before setting rate

  • Make sure you release AVPlayers and AVPlayerItems from old playback sessions

  • Use Allocations Instrument to check AVPlayer and AVPlayerItem lifespans

  • Suspend other network activity in your appp during network playback

    Summary

  • automaticallyWaitsToMinimizeStalliing

  • AVPlayerLooper

  • Enabling and disabling tracks during playback is smoother

  • Prepare for wide color video

  • Opptimize playback startup through currenting and measurement