@ WWDC 16
- Local File
- Progressiive Download
- HTTP Live Streaming
- Playback is at the mercy of the network!
- ๋๋ฌด ๋นจ๋ฆฌ ์์ํ๋ฉด playback์ด ๋ฒ๋ฒ ์ผ ์ ์์
- ๋๋ฌด ๋ฆ๊ฒ ์์ํ๋ฉด ์ ์ ๊ฐ ๋ถํ ใ
- ์ธ์ ์์ํด์ผ ํ ์ง๋ฅผ ์ ๊ฒฐ์ ํด์ผ ํจ
playbackLikelyToKeepUp
playbackBufferFull
playbackBufferEmpty
- For progressive-download playbackk, in iOS 9
- Wait until
playbackLkelyToKeepUp
orplaybackBufferFull
before settingAVPlayeer.rate
- Wait until
- For HLS, rules are simpler
- Set
AVPlayer.rate
and it will automatically wait for buffering before playback begins
- Set
- Same rules for progressive and HLS
- Set
AVPlayer.rate
when user clicks play - Automatically waits to buffer to avoid stalling
- Set
- If network dropps and playback stalls, playback will automatically resume when buffered
Might not mean what you thought it meant
- 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
ํ๋๊ฐ ๋๋๋ฉด ๋ค๋ฅธ ๊ฒ์ ์ฌ์์ํจ๋ค๋ฉด latency ๋ฐ์! ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ํ๋๊ฐ ๋ค ๋๋๊ธฐ ์ ์ ์์ํ๋ค.
- ์ผ์ข ์ 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 ...
}
player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: videoURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
player.play()
audio, video track์ด ๋์ผํ ๊ธธ์ด๋ฅผ ๊ฐ์ง์ ๋ณด์ฅํด๋ผ
- 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๋ฅผ ๋ณด์ฅํด๋ผ
let asset = AVURLAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
let playerLayer = AVPlayerLayer(player: player)
let asset = AVURLAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer() // ์์์๋ ์ฌ๊ธฐ์ playerItem์ ๋ฐ๋ก ๋ฃ์ด์คฌ์์
let playerLayer = AVPlayerLayer(player: player) // ํ์ง๋ง ์ฌ๊ธฐ๋ player ๋ฐ๋ก ๋ฃ์ด์ค
player.replaceCurrentItemWithPlayerItem(playerItem) // ๊ทธ๋ฐ ๋ค์, replace!
- Configure
AVPlayer
andAVPlayerItem
first - Connect
AVPlayerLayer
toAVPlayer
orAVPlayerIteVideoOutpput
toAVPlayerItem
player.play()
// ๋จผ์ ์์ํด๋๊ณplayer.replaceCurrentItemWithPlayerItem(playerItem)
// replace
- 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
var asset = AVURLAsset(url: url)
asset.resourceLoader.preloadsEligibleContentsKys = true
- Master playlist must contain SESSION-KEY declarations
- Size your AVPlayerLayer appropriately and connect it to AVPlayer early
- Before bringing in playerItem
- Set
AVPlayerLayer.contentsScale
ono retina iOS devices.
-
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
-
automaticallyWaitsToMinimizeStalliing
-
AVPlayerLooper
-
Enabling and disabling tracks during playback is smoother
-
Prepare for wide color video
-
Opptimize playback startup through currenting and measurement