SlideShare a Scribd company logo
1 of 92
動画アプリをなめらかに動かす技術
Yuji Hato
iOSDC 2018
Yuji Hato
CyberAgent, Inc. / AbemaTV, Inc.
dekatotoro
@dekatotoro
Contributed services
About me
動画再生
HLS
実装ポイント
最適なbitrate
プレイヤーの監視
Agenda
動画再生
Download
Progressive Download
Streaming
動画再生
HTTP Adaptive Streaming
Local File
動画コンテンツ
Download
Progressive Download
Streaming
HTTP Adaptive Streaming
Local File
動画コンテンツ
動画再生
HDS (HTTP Dynamic Streaming) … Adobe
SS (Smooth Streaming) … Microsoft
MPEG-DASH(Dynamic Adaptive Streaming over HTTP) …
ISO/IEC 23009
HLS (HTTP Live Streaming) … Apple
HTTP Adaptive Streaming プロトコル
動画再生
HDS (HTTP Dynamic Streaming) … Adobe
SS (Smooth Streaming) … Microsoft
MPEG-DASH(Dynamic Adaptive Streaming over HTTP) …
ISO/IEC 23009
HLS (HTTP Live Streaming) … Apple
HTTP Adaptive Streaming プロトコル
動画再生
Container Format / codec
Container Format Video codec Audio codec
MPEG2-TS .ts/m2t/.m2ts H.264/MPEG-2 AAC/AC-3/MP3
MP4 .mp4/.m4a H.264/Xvid/Divx//MPEG-4/H.265 AAC/MP3/AC-3/Voribis
MOV .mov/.qt H.264/MJEG/MPEG-4 AAC/MP3/LPCM
AVI .avi H.264/Xvid/Divx/MPEG-4 AAC/MP3/LPCM
WebM .webm VP8/VP9 Vorbis
etc
動画再生
Container Format / codec
Container Format Video codec Audio codec
MPEG2-TS .ts/m2t/.m2ts H.264/MPEG-2 AAC/AC-3/MP3
MP4 .mp4/.m4a H.264/Xvid/Divx//MPEG-4/H.265/AV1 AAC/MP3/AC-3/Voribis
MOV .mov/.qt H.264/MJEG/MPEG-4 AAC/MP3/LPCM
AVI .avi H.264/Xvid/Divx/MPEG-4 AAC/MP3/LPCM
WebM .webm VP8/VP9/AV1 Vorbis
etc
動画再生
Encoder Server System CDN
Live
動画再生
VOD
Encoder Server System CDN動画ソース
動画再生
HLS
Media Playlist
HLS
Master Playlist
Playlist
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=232370,CODECS="mp4a.40.2, avc1.4d4015"
gear1/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=649879,CODECS="mp4a.40.2, avc1.4d401e"
gear2/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=991714,CODECS="mp4a.40.2, avc1.4d401e"
gear3/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1927833,CODECS="mp4a.40.2, avc1.4d401f"
gear4/prog_index.m3u8
…
HLS
https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8
Master Playlist (.m3u8)
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=232370,CODECS="mp4a.40.2, avc1.4d4015"
gear1/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=649879,CODECS="mp4a.40.2, avc1.4d401e"
gear2/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=991714,CODECS="mp4a.40.2, avc1.4d401e"
gear3/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1927833,CODECS="mp4a.40.2, avc1.4d401f"
gear4/prog_index.m3u8
…
HLS
https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8
Master Playlist (.m3u8)
HLS
Master Playlist (.m3u8)
HLS
Header
playlist1.m3u8
playlist2.m3u8
Playlist3.m3u8
Playlist4.m3u8
BANDWIDTH=232370
BANDWIDTH=649879
BANDWIDTH=991714
BANDWIDTH=1927833
Master Playlist (.m3u8)
CODECS=xxxx
CODECS=xxxx
CODECS=xxxx
CODECS=xxxx
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:9.97667,
fileSequence0.ts
#EXTINF:9.97667,
fileSequence1.ts
#EXTINF:9.97667,
fileSequence2.ts
#EXTINF:9.97667,
fileSequence3.ts
#EXTINF:9.97667,
fileSequence4.ts
…
#EXT-X-ENDLIST
HLS
http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8
Media Playlist (.m3u8)
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:9.97667,
fileSequence0.ts
#EXTINF:9.97667,
fileSequence1.ts
#EXTINF:9.97667,
fileSequence2.ts
#EXTINF:9.97667,
fileSequence3.ts
#EXTINF:9.97667,
fileSequence4.ts
…
#EXT-X-ENDLIST
HLS
http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8
Media Playlist (.m3u8)
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:9.97667,
fileSequence0.ts
#EXTINF:9.97667,
fileSequence1.ts
#EXTINF:9.97667,
fileSequence2.ts
#EXTINF:9.97667,
fileSequence3.ts
#EXTINF:9.97667,
fileSequence4.ts
…
#EXT-X-ENDLIST
ts
セグメントファイル (.ts)
HLS
http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8
Media Playlist (.m3u8)
ts
ts
ts
ts
HLS
Header
segment1.ts
segment2.ts
segment3.ts
segment4.ts
length=10sec
Footer
length=10sec
length=10sec
length=10sec
Media Playlist (.m3u8)
HLS
https://developer.apple.com/streaming/
Documents
実装ポイント
実装ポイント
動画再生
UIWebView / WKWebView WKWebVIewはiOS8~
MPMoviePlayerController iOS2 ~ iOS9
AVPlayer iOS4~
AVPlayerViewController iOS8~
Other Metalなど
実装ポイント
動画再生
UIWebView / WKWebView WKWebVIewはiOS8~
MPMoviePlayerController iOS2 ~ iOS9
AVPlayer iOS4~
AVPlayerViewController iOS8~
Other Metalなど
実装ポイント
動画再生 コンポーネント
AVPlayer
AVAsset
AVPlayerViewController
iOS/tvOS
AVPlayerView
macOS
AVPlayerLayer
AVPlayerItem
AVAsset
実装ポイント
動画再生の流れ
AVPlayerItem
URL
AVPlayer
AVPlayerLayer UIView
実装ポイント
動画再生
let asset = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
playerView.player = player
動画
実装ポイント
最適化する
動画再生
実装ポイント
動画
動画再生
動画
動画動画動画
動画
実装ポイント
動画A
動画再生
実装ポイント
動画B
thumbnail
動画再生
動画A
動画A破棄
実装ポイント
動画B
thumbnail
動画再生
動画A
thumbnail
動画A破棄
実装ポイント
動画B
thumbnail
動画再生
動画A
thumbnail
動画B生成
実装ポイント
動画B
動画再生
動画A
thumbnail
動画B生成
実装ポイント
動画B
動画再生
実装ポイント
実装
動画再生
実装ポイント
Playback start process
https://developer.apple.com/videos/play/wwdc2018/502/
実装ポイント
Playback start process
https://developer.apple.com/videos/play/wwdc2018/502/
実装ポイント
VideoPlayer class
class VideoPlayer {
private(set) var player: AVPlayer!
let playerItem: AVPlayerItem
init(url: URL) {
let asset: AVAsset = AVAsset(url: url)
playerItem = AVPlayerItem(asset: asset)
}
…
}
実装ポイント
サブスレッドでPlayerを生成
class VideoPlayer {
init(url: URL) {
let asset: AVAsset = AVAsset(url: url)
playerItem = AVPlayerItem(asset: asset)
}
…
}
// サブスレッドでプレイヤーを生成
streamURL.asObservable()
.observeOn(scheduler)
.subscribe(onNext: { [weak self] streamURL in
self?.createPlayer(url: streamURL) // createPlayerでVideoPlayerを生成
})
.disposed(by: disposeBag)
AVAsset
実装ポイント
サブスレッドでAVAssetとAVPlayerItemを生成
AVPlayerItem
URL
AVPlayer
AVPlayerLayer UIView
サブスレッド
実装ポイント
RxでAVAssetのloadValuesAsynchronouslyをobserve
extension Reactive where Base: AVAsset {
var isPlayable: Observable<Bool> {
return Observable.create { [weak base] observer in
base?.loadValuesAsynchronously(forKeys: [#keyPath(AVAsset.isPlayable)]) {
if let me = base {
observer.onNext(me.isPlayable)
}
}
return Disposables.create()
}
}
…
}
実装ポイント
RxでAVPlayerItemのKVO, notificationなどをobserve
extension Reactive where Base: AVPlayerItem {
var status: Observable<AVPlayerItemStatus> {
return observe(AVPlayerItemStatus.self, #keyPath(AVPlayerItem.status)).filterNil()
}
var seekableTimeRanges: Observable<[NSValue]> {
return observe([NSValue].self, #keyPath(AVPlayerItem.seekableTimeRanges)).filterNil()
}
func asEndTimeObervable(notification: NotificationCenter = .default) -> Observable<Void> {
return notification.rx.notification(.AVPlayerItemDidPlayToEndTime, object: base).map(void)
}
…
}
実装ポイント
class VideoPlayer {
…
init(url: URL) {
let asset: AVAsset = AVAsset(url: url)
playerItem = AVPlayerItem(asset: asset)
asset.rx.isPlayable
.filter { $0 }
.observeOn(ConcurrentMainScheduler.instance)
.subscribe(onNext: { [weak self] _ in
guard let me = self else { return }
// メインスレッドで生成
me.player = AVPlayer(playerItem: playerItem)
})
.disposed(by: disposeBag)
}
…
}
AVAssetのplayableのtrueを待ってAVPlayerを生成
実装ポイント
AVPlayerを生成後、Playerの状態をobserve
// サブスレッド
asset.rx.isPlayable
.filter { $0 }
.observeOn(ConcurrentMainScheduler.instance)
.subscribe(onNext: { [weak self] _ in
// メインスレッド
guard let me = self else { return }
me.player = AVPlayer(playerItem: playerItem)
me.observePlayer()
me.playerCreated.accept(())
})
.disposed(by: disposeBag)
AVAsset
実装ポイント
メインスレッドでAVPlayerを生成
AVPlayerItem
URL
AVPlayer
AVPlayerLayer UIView
サブスレッド
メインスレッ
ド
実装ポイント
AVPlayer生成処理など全てサブスレッドは?
// サブスレッド
asset.rx.isPlayable
.filter { $0 }
.subscribe(onNext: { [weak self] _ in
// サブスレッド
guard let me = self else { return }
me.player = AVPlayer(playerItem: playerItem)
me.observePlayer()
me.playerCreated.accept(())
})
.disposed(by: disposeBag)
注: AVPlayerのKVOはmain thread推奨
実装ポイント
playerの状態をobserve
private func observePlayer() {
player.rx.periodicTime(for: CMTime(seconds: 1.0, preferredTimescale: Int32(NSEC_PER_SEC)))
.bind(to: periodicTime)
.disposed(by: disposeBag)
playerItem.rx.errorStatus
.bind(to: playerItemError)
.disposed(by: disposeBag)
playerItem.rx.asEndTimeObervable()
.bind(to: playerItemEndTime)
.disposed(by: disposeBag)
…
}
実装ポイント
AVPlayerItem.statusがreadyToPlayになるを待って再生開始
private func observePlayer() {
…
Observable.combineLatest(asset.rx.isPlayable,
playerItem.rx.status,
playerCreated)
.map { $0.0 && $0.1 == .readyToPlay }
.bind(to: isPlayableAndReadyToPlay)
.disposed(by: disposeBag)
…
}
AVAsset
実装ポイント
AVPlayerLayer
AVPlayerItem
URL
AVPlayer
AVPlayerLayer UIView
実装ポイント
RxでAVPlayerLayerのreadyForDisplayをobserve
extension Reactive where Base: AVPlayerLayer {
var ready: Observable<Void> {
return observe(Bool.self, #keyPath(AVPlayerLayer.isReadyForDisplay), options: .init(rawValue: 0), retainSelf:
false)
.filter { _ in self.base.isReadyForDisplay }
.map(void)
}
…
}
実装ポイント
AVPlayerLayerのreadyForDisplayを待って表示
playerLayer.isHidden = true
playerLayer.rx.ready
.observeOn(ConcurrentMainScheduler.instance)
.subscribe(onNext: { [weak self] _ in
self?.playerLayer.isHidden = false
})
.disposed(by: rx.disposeBag)
実装ポイント
AVPlayerとAVPlayerLayerはサブスレッドで破棄
deinit {
let layer = playerLayer
DispatchQueue.global(qos: .background).async {
layer.videoPlayer?.dispose()
layer.videoPlayer = nil
layer.player = nil
}
}
実装ポイント
動画B
thumbnail
動画再生
動画A
動画A破棄 動画B生成
なめらかに!
実装ポイント
UI/UX × 動画再生
の最適なバランスを模索する
動画再生
最適なbitrate
最適なbitrate
preferredPeakBitRate
AVPlayerItem.preferredPeakBitRate
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=232370,CODECS="mp4a.40.2, avc1.4d4015"
gear1/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=649879,CODECS="mp4a.40.2, avc1.4d401e"
gear2/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=991714,CODECS="mp4a.40.2, avc1.4d401e"
gear3/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1927833,CODECS="mp4a.40.2, avc1.4d401f"
gear4/prog_index.m3u8
…
https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8
Master Playlist (.m3u8)
最適なbitrate
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=232370,CODECS="mp4a.40.2, avc1.4d4015"
gear1/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=649879,CODECS="mp4a.40.2, avc1.4d401e"
gear2/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=991714,CODECS="mp4a.40.2, avc1.4d401e"
gear3/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1927833,CODECS="mp4a.40.2, avc1.4d401f"
gear4/prog_index.m3u8
…
https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8
Master Playlist (.m3u8)
最適なbitrate
最適なbitrate
動画サイズに応じた最適化
縦 横
iPhone
最適なbitrate
動画サイズに応じた最適化
iPad
縦 横
最適なbitrate
端末解像度応じた最適化
https://www.apple.com/jp/ios/ios-11/
最適なbitrate
preferredPeakBitRate
端末解像度 × 動画サイズ
による最適なbitrateを指定する
Playerの監視
Playerの監視
HLS Playback Session
https://developer.apple.com/videos/play/wwdc2018/502/
Playerの監視
HLS Playback Session
https://developer.apple.com/videos/play/wwdc2018/502/
AVPlayerItemErrorLog
Playerの監視
AVPlayerItemAccessLog
Playerの情報
AVPlayerItem
Notification
AVPlayer
Playerの監視
Notification
public static let AVPlayerItemTimeJumped: NSNotification.Name
public static let AVPlayerItemDidPlayToEndTime: NSNotification.Name
public static let AVPlayerItemFailedToPlayToEndTime: NSNotification.Name
public static let AVPlayerItemPlaybackStalled: NSNotification.Name
public static let AVPlayerItemNewAccessLogEntry: NSNotification.Name
public static let AVPlayerItemNewErrorLogEntry: NSNotification.Name
Playerの監視
Notification
extension Reactive where Base: AVPlayerItem {
var failedToPlay: Observable<Void> {
return NotificationCenter.default.rx.notification(.AVPlayerItemFailedToPlayToEndTime, object: base)
.map(void)
}
var stalled: Observable<Void> {
return NotificationCenter.default.rx.notification(.AVPlayerItemPlaybackStalled, object: base)
.map(void)
}
…
}
Playerの監視
Notification
extension Notification.Name {
static let timebaseEffectiveRateChanged = NSNotification.Name(rawValue:
String(kCMTimebaseNotification_EffectiveRateChanged))
}
var timebaseEffectiveRateChanged: Observable<Float64> {
return NotificationCenter.default.rx.notification(.timebaseEffectiveRateChanged, object: base.timebase)
.flatMap { [weak base] _ -> Observable<Float64> in
guard let timebase = base?.timebase else { return .empty() }
return .just(CMTimebaseGetRate(timebase))
}
}
AVPlayerItem - AVPlayerItemStatus
public enum AVPlayerItemStatus : Int {
case unknown
case readyToPlay
case failed
}
Playerの監視
AVPlayerItem - AVPlayerItemStatus
extension Reactive where Base: AVPlayerItem {
var status: Observable<AVPlayerItemStatus> {
return observe(AVPlayerItemStatus.self, #keyPath(AVPlayerItem.status)).filterNil()
}
}
playerItem.rx.status,
.filter { $0 == AVPlayerItemStatus.failed }
.subscribe(onNext: { [weak playerItem] _ in
if let event = playerItem?.errorLog()?.events.last {
print("(event.errorStatusCode): (event.errorDomain): (event.errorComment ?? "-")")
}
}
Playerの監視
AVPlayerItem - playback buffer
isPlaybackLikelyToKeepUp
isPlaybackBufferFull
isPlaybackBufferEmpty
extension Reactive where Base: AVPlayerItem {
var isPlaybackLikelyToKeepUp: Observable<Bool> {
return observe(Bool.self, #keyPath(AVPlayerItem.isPlaybackLikelyToKeepUp)
).filterNil()
}
var isPlaybackBufferFull: Observable<Bool> {
return observe(Bool.self, #keyPath(AVPlayerItem.isPlaybackBufferFull)).filterNil()
}
var isPlaybackBufferEmpty: Observable<Bool> {
return observe(Bool.self, #keyPath(AVPlayerItem.isPlaybackBufferEmpty)).filterNil()
}
…
}
Playerの監視
AVPlayerItem - playback buffer
extension Reactive where Base: AVPlayerItem {
var loadedTimeRanges: Observable<[NSValue]> {
return observe([NSValue].self, #keyPath(AVPlayerItem.loadedTimeRanges)).filterNil()
}
}
playerItem.rx.loadedTimeRanges
.subscribe(onNext: { [weak playerItem] loadedTimeRanges in
guard let playerItem = playerItem else { return }
let buffer: Double = (loadedTimeRanges.last as? CMTimeRange)
.map { range in (range.end - playerItem.currentTime()).seconds } ?? 0
print("buffer: (buffer)")
})
.disposed(by: disposeBag)
Playerの監視
AVPlayer - TimeControlStatus
@available(iOS 10.0, *)
public enum AVPlayerTimeControlStatus : Int {
case paused
case waitingToPlayAtSpecifiedRate
case playing
}
Playerの監視
AVPlayer - TimeControlStatus
extension Reactive where Base: AVPlayer {
var timeControlStatus: Observable<AVPlayerTimeControlStatus> {
return base.rx.observe(AVPlayerTimeControlStatus.self, #keyPath(AVPlayer.timeControlStatus))
.filterNil()
}
}
player.rx.timeControlStatus
.subscribe(onNext: { timeControlStatus in
// timeControlStatus
})
.disposed(by: disposeBag)
Playerの監視
AVPlayerItemAccessLog
https://developer.apple.com/videos/play/wwdc2018/502/
Playerの監視
AVPlayerItemAccessLog
playerItem.accessLog()?.events
Playerの監視
AVPlayerItemAccessLog
if let accessLog = videoPlayer.playerItem.accessLog()?.events.last {
let log = """
uri: (accessLog.uri ?? "-")")
serverAddress: (accessLog.serverAddress ?? "-")")
mediaRequestsWWAN: (accessLog.mediaRequestsWWAN)")
numberOfMediaRequests: (accessLog.numberOfMediaRequests)")
playbackStartDate: (accessLog.playbackStartDate ?? Date.distantPast)")
playbackSessionID: (accessLog.playbackSessionID ?? "-")")
playbackStartOffset: (accessLog.playbackStartOffset)")
playbackType: (accessLog.playbackType ?? "-")")
startupTime: (accessLog.startupTime)")
durationWatched: (accessLog.durationWatched)")
numberOfDroppedVideoFrames: (accessLog.numberOfDroppedVideoFrames)")
numberOfStalls: (accessLog.numberOfStalls)")
observedMaxBitrate: (accessLog.observedMaxBitrate)")
observedMinBitrate: (accessLog.observedMinBitrate)")
switchBitrate: (accessLog.switchBitrate)”)
…
"""
print(log)
}
Playerの監視
AVPlayerItemAccessLog
https://developer.apple.com/videos/play/wwdc2018/502/
Playerの監視
AVPlayerItemAccessLog
https://developer.apple.com/videos/play/wwdc2018/502/
Playerの監視
AVPlayerItemErrorLog
https://developer.apple.com/videos/play/wwdc2018/502/
Playerの監視
AVPlayerItemErrorLog
playerItem.errorLog()?.events
Playerの監視
AVPlayerItemErrorLog
if let errorLog = playerItem.errorLog()?.events.last {
let log = """
uri: (errorLog.uri ?? "")")
date: (errorLog.date ?? Date.distantPast)")
serverAddress: (errorLog.serverAddress ?? "-")")
playbackSessionID: (errorLog.playbackSessionID ?? “-")")
errorStatusCode: (errorLog.errorStatusCode)")
errorDomain: (errorLog.errorDomain)”)
errorComment: (errorLog.errorComment ?? "-")")
"""
print(log)
}
Playerの監視
AVPlayerItemErrorLog
https://developer.apple.com/videos/play/wwdc2018/502/
Playerの監視
Metrics
https://developer.apple.com/videos/play/wwdc2018/502/
Playerの監視
Metrics Solution
MUX
CONVIVA
Akamai Media Analytics
YOUBORA
etc..
Playerの監視
まとめ
まとめ
動画配信の技術を知る
最適な動画再生 × UXを追求する
ユーザーの視聴体験を追求する
Thank you

More Related Content

What's hot

CloudFrontのリアルタイムログをKibanaで可視化しよう
CloudFrontのリアルタイムログをKibanaで可視化しようCloudFrontのリアルタイムログをKibanaで可視化しよう
CloudFrontのリアルタイムログをKibanaで可視化しようEiji KOMINAMI
 
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~Daisuke Morishita
 
Cesiumを動かしてみよう
Cesiumを動かしてみようCesiumを動かしてみよう
Cesiumを動かしてみようKazutaka ishizaki
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使うKazuhiro Suga
 
ABEMA を次のフェーズへ進化させる技術への取り組み
ABEMA を次のフェーズへ進化させる技術への取り組みABEMA を次のフェーズへ進化させる技術への取り組み
ABEMA を次のフェーズへ進化させる技術への取り組みYusuke Goto
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなKentaro Matsui
 
限界性能試験を自動化するOperatorを作ってみた(Kubernetes Novice Tokyo #14 発表資料)
限界性能試験を自動化するOperatorを作ってみた(Kubernetes Novice Tokyo #14 発表資料)限界性能試験を自動化するOperatorを作ってみた(Kubernetes Novice Tokyo #14 発表資料)
限界性能試験を自動化するOperatorを作ってみた(Kubernetes Novice Tokyo #14 発表資料)NTT DATA Technology & Innovation
 
Debianの修正はどのように出荷されるか
Debianの修正はどのように出荷されるかDebianの修正はどのように出荷されるか
Debianの修正はどのように出荷されるかHideki Yamane
 
画像処理ライブラリ OpenCV で 出来ること・出来ないこと
画像処理ライブラリ OpenCV で 出来ること・出来ないこと画像処理ライブラリ OpenCV で 出来ること・出来ないこと
画像処理ライブラリ OpenCV で 出来ること・出来ないことNorishige Fukushima
 
AbemaTVの動画配信を支えるサーバーサイドシステム
AbemaTVの動画配信を支えるサーバーサイドシステムAbemaTVの動画配信を支えるサーバーサイドシステム
AbemaTVの動画配信を支えるサーバーサイドシステムyuichiro nakazawa
 
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略祐司 伊藤
 
20191112 AWS Black Belt Online Seminar AWS Media Services で始めるライブ動画配信
20191112 AWS Black Belt Online Seminar AWS Media Services で始めるライブ動画配信20191112 AWS Black Belt Online Seminar AWS Media Services で始めるライブ動画配信
20191112 AWS Black Belt Online Seminar AWS Media Services で始めるライブ動画配信Amazon Web Services Japan
 
AWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティスAWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティスAmazon Web Services Japan
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxShota Shinogi
 
Power BI をアプリに埋め込みたい? ならば Power BI Embedded だ!
Power BI をアプリに埋め込みたい? ならば Power BI Embedded だ!Power BI をアプリに埋め込みたい? ならば Power BI Embedded だ!
Power BI をアプリに埋め込みたい? ならば Power BI Embedded だ!Teruchika Yamada
 
AppiumのWebViewアプリテストの仕組みとハマりどころ
AppiumのWebViewアプリテストの仕組みとハマりどころAppiumのWebViewアプリテストの仕組みとハマりどころ
AppiumのWebViewアプリテストの仕組みとハマりどころMasayuki Wakizaka
 
より高品質なメディアサービスを目指す ABEMA の技術進化
より高品質なメディアサービスを目指す ABEMA の技術進化より高品質なメディアサービスを目指す ABEMA の技術進化
より高品質なメディアサービスを目指す ABEMA の技術進化Yusuke Goto
 
コンテナで始める柔軟な AWS Lambda 生活
コンテナで始める柔軟な AWS Lambda 生活コンテナで始める柔軟な AWS Lambda 生活
コンテナで始める柔軟な AWS Lambda 生活Drecom Co., Ltd.
 
Unity対応してるmbass全部紹介する
Unity対応してるmbass全部紹介するUnity対応してるmbass全部紹介する
Unity対応してるmbass全部紹介するTakaaki Ichijo
 
インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方Shohei Koyama
 

What's hot (20)

CloudFrontのリアルタイムログをKibanaで可視化しよう
CloudFrontのリアルタイムログをKibanaで可視化しようCloudFrontのリアルタイムログをKibanaで可視化しよう
CloudFrontのリアルタイムログをKibanaで可視化しよう
 
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
 
Cesiumを動かしてみよう
Cesiumを動かしてみようCesiumを動かしてみよう
Cesiumを動かしてみよう
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
 
ABEMA を次のフェーズへ進化させる技術への取り組み
ABEMA を次のフェーズへ進化させる技術への取り組みABEMA を次のフェーズへ進化させる技術への取り組み
ABEMA を次のフェーズへ進化させる技術への取り組み
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
 
限界性能試験を自動化するOperatorを作ってみた(Kubernetes Novice Tokyo #14 発表資料)
限界性能試験を自動化するOperatorを作ってみた(Kubernetes Novice Tokyo #14 発表資料)限界性能試験を自動化するOperatorを作ってみた(Kubernetes Novice Tokyo #14 発表資料)
限界性能試験を自動化するOperatorを作ってみた(Kubernetes Novice Tokyo #14 発表資料)
 
Debianの修正はどのように出荷されるか
Debianの修正はどのように出荷されるかDebianの修正はどのように出荷されるか
Debianの修正はどのように出荷されるか
 
画像処理ライブラリ OpenCV で 出来ること・出来ないこと
画像処理ライブラリ OpenCV で 出来ること・出来ないこと画像処理ライブラリ OpenCV で 出来ること・出来ないこと
画像処理ライブラリ OpenCV で 出来ること・出来ないこと
 
AbemaTVの動画配信を支えるサーバーサイドシステム
AbemaTVの動画配信を支えるサーバーサイドシステムAbemaTVの動画配信を支えるサーバーサイドシステム
AbemaTVの動画配信を支えるサーバーサイドシステム
 
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
 
20191112 AWS Black Belt Online Seminar AWS Media Services で始めるライブ動画配信
20191112 AWS Black Belt Online Seminar AWS Media Services で始めるライブ動画配信20191112 AWS Black Belt Online Seminar AWS Media Services で始めるライブ動画配信
20191112 AWS Black Belt Online Seminar AWS Media Services で始めるライブ動画配信
 
AWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティスAWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティス
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
 
Power BI をアプリに埋め込みたい? ならば Power BI Embedded だ!
Power BI をアプリに埋め込みたい? ならば Power BI Embedded だ!Power BI をアプリに埋め込みたい? ならば Power BI Embedded だ!
Power BI をアプリに埋め込みたい? ならば Power BI Embedded だ!
 
AppiumのWebViewアプリテストの仕組みとハマりどころ
AppiumのWebViewアプリテストの仕組みとハマりどころAppiumのWebViewアプリテストの仕組みとハマりどころ
AppiumのWebViewアプリテストの仕組みとハマりどころ
 
より高品質なメディアサービスを目指す ABEMA の技術進化
より高品質なメディアサービスを目指す ABEMA の技術進化より高品質なメディアサービスを目指す ABEMA の技術進化
より高品質なメディアサービスを目指す ABEMA の技術進化
 
コンテナで始める柔軟な AWS Lambda 生活
コンテナで始める柔軟な AWS Lambda 生活コンテナで始める柔軟な AWS Lambda 生活
コンテナで始める柔軟な AWS Lambda 生活
 
Unity対応してるmbass全部紹介する
Unity対応してるmbass全部紹介するUnity対応してるmbass全部紹介する
Unity対応してるmbass全部紹介する
 
インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方
 

Similar to HLS Optimal Bitrate

yapi.js introduction (mopcon 2016 version)
yapi.js introduction (mopcon 2016 version)yapi.js introduction (mopcon 2016 version)
yapi.js introduction (mopcon 2016 version)Jesse (Chien Chen) Chen
 
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...Amazon Web Services
 
HTML5 APIs - native multimedia support and beyond - University of Leeds 05.05...
HTML5 APIs - native multimedia support and beyond - University of Leeds 05.05...HTML5 APIs - native multimedia support and beyond - University of Leeds 05.05...
HTML5 APIs - native multimedia support and beyond - University of Leeds 05.05...Patrick Lauke
 
audio, video and canvas in HTML5 - standards>next Manchester 29.09.2010
audio, video and canvas in HTML5 - standards>next Manchester 29.09.2010audio, video and canvas in HTML5 - standards>next Manchester 29.09.2010
audio, video and canvas in HTML5 - standards>next Manchester 29.09.2010Patrick Lauke
 
Capture, record, clip, embed and play, search: video from newbie to ninja
Capture, record, clip, embed and play, search: video from newbie to ninjaCapture, record, clip, embed and play, search: video from newbie to ninja
Capture, record, clip, embed and play, search: video from newbie to ninjaVito Flavio Lorusso
 
An Introduction into Bosh | anynines
An Introduction into Bosh | anynines An Introduction into Bosh | anynines
An Introduction into Bosh | anynines anynines GmbH
 
Maxim Salnikov - Service Worker: taking the best from the past experience for...
Maxim Salnikov - Service Worker: taking the best from the past experience for...Maxim Salnikov - Service Worker: taking the best from the past experience for...
Maxim Salnikov - Service Worker: taking the best from the past experience for...Codemotion
 
20200331 AWS Black Belt Online Seminar AWS Elemental MediaConvert
20200331 AWS Black Belt Online Seminar AWS Elemental MediaConvert20200331 AWS Black Belt Online Seminar AWS Elemental MediaConvert
20200331 AWS Black Belt Online Seminar AWS Elemental MediaConvertAmazon Web Services Japan
 
Modern Web Application Development Workflow - web2day 2014
Modern Web Application Development Workflow - web2day 2014Modern Web Application Development Workflow - web2day 2014
Modern Web Application Development Workflow - web2day 2014Stéphane Bégaudeau
 
Web Standards for AR workshop at ISMAR13
Web Standards for AR workshop at ISMAR13Web Standards for AR workshop at ISMAR13
Web Standards for AR workshop at ISMAR13Rob Manson
 
JUDCon 2010 Boston : BoxGrinder
JUDCon 2010 Boston : BoxGrinderJUDCon 2010 Boston : BoxGrinder
JUDCon 2010 Boston : BoxGrindermarekgoldmann
 
Passenger 6 generic language support presentation
Passenger 6 generic language support presentationPassenger 6 generic language support presentation
Passenger 6 generic language support presentationHongli Lai
 
HTML5 Multimedia: where we are, where we're going
HTML5 Multimedia: where we are, where we're goingHTML5 Multimedia: where we are, where we're going
HTML5 Multimedia: where we are, where we're goingbrucelawson
 
(DEV309) From Asgard to Zuul: How Netflix’s Proven Open Source Tools Can Help...
(DEV309) From Asgard to Zuul: How Netflix’s Proven Open Source Tools Can Help...(DEV309) From Asgard to Zuul: How Netflix’s Proven Open Source Tools Can Help...
(DEV309) From Asgard to Zuul: How Netflix’s Proven Open Source Tools Can Help...Amazon Web Services
 
Progressive web apps
Progressive web appsProgressive web apps
Progressive web appsFastly
 
PHP on Heroku: Deploying and Scaling Apps in the Cloud
PHP on Heroku: Deploying and Scaling Apps in the CloudPHP on Heroku: Deploying and Scaling Apps in the Cloud
PHP on Heroku: Deploying and Scaling Apps in the CloudSalesforce Developers
 
Creating Flash Content for Multiple Screens
Creating Flash Content for Multiple ScreensCreating Flash Content for Multiple Screens
Creating Flash Content for Multiple Screenspaultrani
 
Mike Taulty Beyond Silverlight With W P F
Mike Taulty  Beyond  Silverlight  With  W P FMike Taulty  Beyond  Silverlight  With  W P F
Mike Taulty Beyond Silverlight With W P Fukdpe
 
WebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at GoogleWebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at GoogleRobert Nyman
 
Dev309 from asgard to zuul - netflix oss-final
Dev309  from asgard to zuul - netflix oss-finalDev309  from asgard to zuul - netflix oss-final
Dev309 from asgard to zuul - netflix oss-finalRuslan Meshenberg
 

Similar to HLS Optimal Bitrate (20)

yapi.js introduction (mopcon 2016 version)
yapi.js introduction (mopcon 2016 version)yapi.js introduction (mopcon 2016 version)
yapi.js introduction (mopcon 2016 version)
 
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
TLS303 How to Deploy Python Applications on AWS Elastic Beanstalk - AWS re:In...
 
HTML5 APIs - native multimedia support and beyond - University of Leeds 05.05...
HTML5 APIs - native multimedia support and beyond - University of Leeds 05.05...HTML5 APIs - native multimedia support and beyond - University of Leeds 05.05...
HTML5 APIs - native multimedia support and beyond - University of Leeds 05.05...
 
audio, video and canvas in HTML5 - standards>next Manchester 29.09.2010
audio, video and canvas in HTML5 - standards>next Manchester 29.09.2010audio, video and canvas in HTML5 - standards>next Manchester 29.09.2010
audio, video and canvas in HTML5 - standards>next Manchester 29.09.2010
 
Capture, record, clip, embed and play, search: video from newbie to ninja
Capture, record, clip, embed and play, search: video from newbie to ninjaCapture, record, clip, embed and play, search: video from newbie to ninja
Capture, record, clip, embed and play, search: video from newbie to ninja
 
An Introduction into Bosh | anynines
An Introduction into Bosh | anynines An Introduction into Bosh | anynines
An Introduction into Bosh | anynines
 
Maxim Salnikov - Service Worker: taking the best from the past experience for...
Maxim Salnikov - Service Worker: taking the best from the past experience for...Maxim Salnikov - Service Worker: taking the best from the past experience for...
Maxim Salnikov - Service Worker: taking the best from the past experience for...
 
20200331 AWS Black Belt Online Seminar AWS Elemental MediaConvert
20200331 AWS Black Belt Online Seminar AWS Elemental MediaConvert20200331 AWS Black Belt Online Seminar AWS Elemental MediaConvert
20200331 AWS Black Belt Online Seminar AWS Elemental MediaConvert
 
Modern Web Application Development Workflow - web2day 2014
Modern Web Application Development Workflow - web2day 2014Modern Web Application Development Workflow - web2day 2014
Modern Web Application Development Workflow - web2day 2014
 
Web Standards for AR workshop at ISMAR13
Web Standards for AR workshop at ISMAR13Web Standards for AR workshop at ISMAR13
Web Standards for AR workshop at ISMAR13
 
JUDCon 2010 Boston : BoxGrinder
JUDCon 2010 Boston : BoxGrinderJUDCon 2010 Boston : BoxGrinder
JUDCon 2010 Boston : BoxGrinder
 
Passenger 6 generic language support presentation
Passenger 6 generic language support presentationPassenger 6 generic language support presentation
Passenger 6 generic language support presentation
 
HTML5 Multimedia: where we are, where we're going
HTML5 Multimedia: where we are, where we're goingHTML5 Multimedia: where we are, where we're going
HTML5 Multimedia: where we are, where we're going
 
(DEV309) From Asgard to Zuul: How Netflix’s Proven Open Source Tools Can Help...
(DEV309) From Asgard to Zuul: How Netflix’s Proven Open Source Tools Can Help...(DEV309) From Asgard to Zuul: How Netflix’s Proven Open Source Tools Can Help...
(DEV309) From Asgard to Zuul: How Netflix’s Proven Open Source Tools Can Help...
 
Progressive web apps
Progressive web appsProgressive web apps
Progressive web apps
 
PHP on Heroku: Deploying and Scaling Apps in the Cloud
PHP on Heroku: Deploying and Scaling Apps in the CloudPHP on Heroku: Deploying and Scaling Apps in the Cloud
PHP on Heroku: Deploying and Scaling Apps in the Cloud
 
Creating Flash Content for Multiple Screens
Creating Flash Content for Multiple ScreensCreating Flash Content for Multiple Screens
Creating Flash Content for Multiple Screens
 
Mike Taulty Beyond Silverlight With W P F
Mike Taulty  Beyond  Silverlight  With  W P FMike Taulty  Beyond  Silverlight  With  W P F
Mike Taulty Beyond Silverlight With W P F
 
WebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at GoogleWebRTC & Firefox OS - presentation at Google
WebRTC & Firefox OS - presentation at Google
 
Dev309 from asgard to zuul - netflix oss-final
Dev309  from asgard to zuul - netflix oss-finalDev309  from asgard to zuul - netflix oss-final
Dev309 from asgard to zuul - netflix oss-final
 

More from Yuji Hato

継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」Yuji Hato
 
Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -
Adaptive UI  - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ - Adaptive UI  - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -
Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ - Yuji Hato
 
5分で学ぶ差分更新とRxDataSources
5分で学ぶ差分更新とRxDataSources5分で学ぶ差分更新とRxDataSources
5分で学ぶ差分更新とRxDataSourcesYuji Hato
 
AbemaTV モバイルアプリの開発体制と開発プロセスの話
AbemaTV モバイルアプリの開発体制と開発プロセスの話AbemaTV モバイルアプリの開発体制と開発プロセスの話
AbemaTV モバイルアプリの開発体制と開発プロセスの話Yuji Hato
 
Apple TV tvOS入門 Iosdc2017
Apple TV tvOS入門 Iosdc2017Apple TV tvOS入門 Iosdc2017
Apple TV tvOS入門 Iosdc2017Yuji Hato
 
AbemaTV on tvOS
AbemaTV on tvOSAbemaTV on tvOS
AbemaTV on tvOSYuji Hato
 
Flux with RxSwift
Flux with RxSwiftFlux with RxSwift
Flux with RxSwiftYuji Hato
 
CarPlayの対応方法と日本での現状
CarPlayの対応方法と日本での現状CarPlayの対応方法と日本での現状
CarPlayの対応方法と日本での現状Yuji Hato
 
AWA with Realm
AWA with RealmAWA with Realm
AWA with RealmYuji Hato
 

More from Yuji Hato (9)

継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
継続的な開発スタイル 「AbemaTV iOSアプリを週一でリリースしている話」
 
Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -
Adaptive UI  - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ - Adaptive UI  - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -
Adaptive UI - 解像度の異なるデバイスや画面の向きに対応する 最適なレイアウトへ -
 
5分で学ぶ差分更新とRxDataSources
5分で学ぶ差分更新とRxDataSources5分で学ぶ差分更新とRxDataSources
5分で学ぶ差分更新とRxDataSources
 
AbemaTV モバイルアプリの開発体制と開発プロセスの話
AbemaTV モバイルアプリの開発体制と開発プロセスの話AbemaTV モバイルアプリの開発体制と開発プロセスの話
AbemaTV モバイルアプリの開発体制と開発プロセスの話
 
Apple TV tvOS入門 Iosdc2017
Apple TV tvOS入門 Iosdc2017Apple TV tvOS入門 Iosdc2017
Apple TV tvOS入門 Iosdc2017
 
AbemaTV on tvOS
AbemaTV on tvOSAbemaTV on tvOS
AbemaTV on tvOS
 
Flux with RxSwift
Flux with RxSwiftFlux with RxSwift
Flux with RxSwift
 
CarPlayの対応方法と日本での現状
CarPlayの対応方法と日本での現状CarPlayの対応方法と日本での現状
CarPlayの対応方法と日本での現状
 
AWA with Realm
AWA with RealmAWA with Realm
AWA with Realm
 

Recently uploaded

TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 

Recently uploaded (20)

TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 

HLS Optimal Bitrate

Editor's Notes

  1. アジェンダでですが、 動画アプリをなめらかに動かすための技術要素として 動画再生とHLSについて簡単に説明して その後に実装ポイントと最適なbitrate 最後にプレイヤーの監視について説明していきたいと思います
  2. 動画が再生されるまでについてまず簡単に説明したいと思います。
  3. まず動画コンテンツの再生ですが、いくつかの種類に分類できます。 Localのfileを再生や、ダウンロード再生、ダウンロードしながら再生する方式のプログレッシブダウンロード、 あとはRTSPやRTMPなどのstreaming再生と、 HTTPののせたHTTP Adaptive streamingのような種類に分けられます。
  4. 幅広いデバイスに対応したり、大規模配信でCDNのソリューションを活用する場合は、HTTP Adaptive Streaingが選択肢となります。
  5. その中でもいくつかプロトコルがあって AdobeのHDSやちょっと古いですがMicrosoftのSmooth Streaming あとはMPEG-DASH、AppleのHLSなどがあります。
  6. iOSの場合はもちろんこのAppleのHLSが選択肢となります。
  7. 次にContainer Formatとcodecです。この表はContainer とcodecの組み合わせを表にしたものですが、動画のRawデータはとてもじゃないですが大きくて配信できないので、 だいたい何らかのcodecにエンコードされて Playerがdecodeして再生しています。 H265/HEVCなんかはHardware DecodeがA9チップ以降だったりとcodecとサポート端末も考慮する必要があります。
  8. で、この中でHLSの配信はMPEG2-TSか、iOS10以降は fragmented MP4も使用できます Container formatとCodecの種類はまぁ色々あるんですが、上記の2つがHLSで使えるものになります。
  9. 動画が再生されるまでの簡単な流れですが、すごくおおざっぱですがこれはLiveの場合ですが カメラで撮った映像をエンコーダーに送って、エンコーダーがエンコードしてHLSに変換、サーバシステムでAbemaTVの場合だとさらにCMの挿入などを行ってCDNを通して配信といった形になります。
  10. VODも大体同じで動画ソースをエンコードしてHLSに変換してサーバーがCDNを通して配信といった流れになります。
  11. 次にHLSについて見ていきます。
  12. まずMaster PlaylistとMedia Playlistの2つがあります。
  13. Master Playlistの例です。 それぞれ単純にMediaPlaylistが並んでいて、
  14. エクストstream-infにバンドワイズ の指定だったり、先程お話したCODECの指定したMediaPlaylistを定義できます。
  15. で、ここのエクスト ストリームインフタグでResolutionやFrame-rateなど色々なattributeが他にも指定できます
  16. 図にするとこんな感じで、Headerがあってあとはbitrateごとのメディアプレイリストが並んでいる感じです。
  17. 次にMedia Playlistですが、こちらは実際のsegmentedされた動画ファイルの羅列になります。
  18. ヘッダーにHLSのversionやMedia Sequence、TARGETDURATIONやplaylistのTYPEを指定します。これはVODですが、liveの場合はtypeがEventになり、プレイヤーがTARGETDURATION内でmedia playlistを何度も取得して更新されていく動作になります。
  19. コンテンツはセグメントファイルの羅列でプレイヤーはこの順番に再生していきます。
  20. 図にすると単純なんですけど、HeaderとFooterがあってあとはセグメントファイルが並んでいるといった形になります
  21. HLSはけっこうシンプルでわかりやすいプロトコルで、他にもいろいろなTAGがあったり仕様があるので、ドキュメントがこちらに纏まっています
  22. 次に実装のポイントについてです。
  23. iOSで動画を再生する場合、WebViewを使うか、あとはちょっと前だとMPMoviewPlayerControllerなんかもありました。あとはAVplayerと、AVPlayerのControllerとしてAVPlayerViewControllerがあります。あとは、streamからpixcelbuffer取得してMetalで再生とかなんかも考えられます
  24. で今日はiOSで一番再生するのに一般的なAVPlayerを使った再生の説明になります。
  25. これは動画の再生コンポーネントを図にしたものですが、下から AVAssetが 動画自体のメディアデータやメタデータをロードし、保持するクラス AVPlayerItemが動画の再生ステータスやメタデータを取得するクラス AVPlayerが動画の再生、停止を管理するクラス AVPlayerLayerが動画を描画するクラス となります。
  26. 動画を表示するまでの流れとしては、 動画URLを基に、AVAsset => AVPlayerItem => AVPlayer => AVPlayerLayerを作成。 UIViewに適応させるイメージです。
  27. コードにするとこんな感じですね。 とてもシンプルなんですが、urlからAVAsset生成してAVPlayerItem生成してAVPlayer生成してAVPlayerLayerに適応したUIViewにplayerをセットしてあげるといった流れになります
  28. 一つの動画ならこの実装で良いかもしれませんが、複数再生したり、スクロールさせて動画を切り替えたりといった場合、工夫する点がいくつかあります。
  29. 複数再生する場合として、いろいろなUIのパターンがあると思いますが、基本ユーザーがちゃんと見れる動画はひとつだし、動画は再生するだけで帯域やCPUを食うので、画面に現れたらすぐに再生ではなく、画面の真ん中に近づいてきたら再生を開始するなどのUXと、動画の生成と破棄のポイントが大事になってきます。
  30. AbemaTVの例ですが、これは起動してすぐのテレビ画面の例になります。 左右にスクロールしてチャンネルを切り替えることができ次々と別の動画が再生する作りになっています。
  31. 右にスクロールしていく例ですが、画面に現れたらすぐに再生するのではなく、この時点で動画Aは再生中で、動画Bが現れますが動画Bは再生しておらずサムネイルを表示しています。
  32. ここの破棄ポイントに来たところで動画Aを破棄してサムネイルに差し替えています。
  33. ここはまだサムネイルを表示していて
  34. 生成ポイントに来たところで動画Bを生成して再生を開始しています。
  35. これで動画Bが真ん中にきてといった繰り返しの挙動になります。 こういった工夫をすることで、帯域やリソース消費を気にしつつ、UXにも気を使った再生が可能になります。
  36. こういったスクロール中にプレイヤーの生成・破棄などを行う上での実装ポイントを紹介します。 実装はRxSwiftを使った例になります。
  37. これはWWDC2018の資料ですが AVAssetを生成してからAVAssetがm3u8をロードしてinspectしてAVPlayerがbufferingを開始、DRM暗号化されている場合は複合のためのFairplay key Fetchingをしてbuffering, seekしたらrebufferingしてといった動画再生開始の流れを図にしたものになります。
  38. AVAssetのinspectionとkey Fetchは先にやって動画開始の時間を短縮できるよと言ったことが紹介されているんですが、今日はkey fetchに関しては割愛して、その他の部分にフォーカスしたいと思います。
  39. 具体的な実装のポイントについてですが、基本はプレイヤーの生成処理やプレイヤーの破棄のスレッドを工夫しましょうというのがポイントになります。 これはAVPlayerなどを保持してるVideoPlayer classの例です initializeでurlを受け取ってurlからAVAssetを生成、assetからAVPlayerItemを生成します。
  40. streamURLを受け取って、サブスレッドでVideoPlayerクラスを生成します。
  41. 先程図でいうとここになります。 AVAssetとAVPlayerItemをサブスレッドで生成します
  42. AVAssetのloadValuesAsynchronouslyでisPlayableを購読できるようにしておきます。
  43. AVPlayerItemのstatusやnotificationもobserveできるようにしておきます。 ここは特に難し考えず、playerItem.rx.status などで購読できるようにしていると考えてください。
  44. AVAssetのplayableがtrueになるのを待ってメインスレッドでAVPlayerを生成します。
  45. 続きでAVplayer生成後、Player状態をobserveしてプレイヤー生成を通知します。
  46. 先程図でいうとここになります。 AVPlayerをメインスレッドで生成します
  47. AVPlayerの生成もサブスレッドで行っても再生は特に問題ありませんが、プレイヤーのKVOはmainスレッドが推奨されていることと、すべてサブスレッドにするとメインスレッドに負けてしまうので、動画の表示が余計遅くなる場合もあるため、検証した限りではメインスレッドの方がバランスが良かったです。
  48. こちらはplayerのobserve処理の例ですが、periodicTimeやerrorStatus、endTimeなどのobserveをしてVideoPlayerのstreamとしてObservableを公開しておくと扱いやすいです
  49. 再生の開始ですが、通常AVPlayerは自動で再生可能になったら再生されますが、rateを0にしてアプリケーション側でUIに合わせてコントールできるようにしておくとUIに合わせて応用が効きます。
  50. 次にAVPlayerLayer部分の工夫ですが、AVPlayerLayerにはisReadyForDisplayというpropertyがあるのでこちらをobserveします。
  51. AVPlayerLayerのisReadyForDisplayをobserveできるようにしておきます
  52. AVPlayerLayerのisReadyForDisplayを待ってPlayerLayerを表示するようにして、AVPlayerLayerが準備できるまで表示せず負荷を減らす工夫をしています。
  53. あとはAVPlayerとAVPlayerLayerの破棄ですがサブスレッドで破棄するようにして、UIをblockしないようにしています
  54. 先程の図ですが、こういったスレッドの細かい調整などをすることによって、UIと動画の再生がなめらかに動くようになります。
  55. UIのなめらかさと動画再生開始を速くすることでユーザーにストレスを感じさせないUXを目指して、UIと動画再生の最適なバランスを調整する点がポイントとなります。
  56. 次に最適なbitrateということですが、
  57. AVPlayerItemにpreferredPeakBitRate というpropertyがあるのでここに転送速度を設定するこでmaxBitRateを設定できます。
  58. これはHLSのところで説明したmaster palylistの例ですが、
  59. ここのバンドワイズの指定bpsに依存します。 ネットワークの帯域に応じてplayerがmedia playlistを自動で切り替えてくれるので preferredPeakBitRateにmaxのバンドワイズを指定していればそれ以上上のメディアプレイリストは取得しにいかなくなる動作となります。
  60. こちらAbemaTVのUIの例ですが様々な大きさの動画があって
  61. iPadあってそれぞれ大きさが違うことがわかります。
  62. あとは端末による解像度の差も無視できなくて、 iPhoneでも5sと8 plusの解像度の差は大きいですし、iPadになると低bitrateだと画質の粗さが目立ってしまったりします。
  63. 高bitrateの動画になるとCPUやネットワーク帯域の消費、サーバリソースも無駄に消費することになり小さい動画サイズや解像度の低い端末でフルHDなどを再生しても無駄が多くなるので、動画のサイズと端末解像度の組み合わせでpreferredPeakBitRateの指定を切り替えることで、再生開始時間の短縮やCPU負荷の低減の効果が見込めます。
  64. 最後にPlayerの監視についてです。
  65. こちらはWWDC2018の資料の抜粋ですが、HLSの再生sessionを表しています。 再生されるまでにAVPlayer、AVPlayerItemのreadyToPlay、isPlaybackLikelyToKeepUp、AVPlayerのtimeControlStatusがplaying、AVPlayerItemのtimebaseといった順番で変わっていくことがわかります。
  66. これはm3u8を呼んでから再生開始のstartup timeまでのtsファイルの取得と(バッファリングですね)bitrateが2Mbpsの再生から1Mbpsにswitch、一度stallしてまた1Mbpsで再生再開といった流れを表しています。
  67. こういったユーザの視聴体験、プレイヤの状態を知るのにNotificationやKVO、eventログなど様々ものが用意されています。全ては紹介できませんがいくつか紹介したいと思います。
  68. まずNotificationですが、AVPlayerItemのnotificationがいくつかあります。 上からTimeJumped、これはseekなどしたときですね。DidPlayToEndTimeは再生が終了したとき、playlistのendplaylistに到達したときに飛んできます。 FailedToPlayToEndTimeは再生に失敗して終了したとき、PlaybackStalledはネットワークが悪くバッファリングが足りなくなって再生続行不能になったとき、 NewAccessLogEntryとNewErrorLogEntryはaccesslogとerrorlogのeventlogが新たに追加されたときに発火します
  69. これもRx化してobserveできるようにしておくと使いやすいです。
  70. 先程の図にあった再生開始直前にrateが変わるタイミングで飛んでくるEffectiveRateChangedなんかもあります。AVPlayerのplay関数を呼び出してもすぐにrateが1に変更されるわけではなく、Playerの再生の準備が整ってから実際にrateが変更されるタイミングで飛んできます。
  71. これは何度かコードの中で出てきているAVPlayerItemのstatusで unknown, readyToPlay, failedがあります。
  72. これはRx化してstatsuをobserveしていてfailedが発火されたタイミングerrorログを確認している例になります
  73. AVPlayerItemからは再生バッファの状態もとれます。 isPlaybackLikeyToKeepUpは再生が続行可能かどうか playbackBufferFullはメディアのバッファリングが上限に達している状態、 playbackBufferEmptyはバッファが空の状態でplayer生成直後やstallすとき、再生終了するときにtrueとなります、 こちらのpropertyはiOS9, 10, 11で微妙に異なる動作をしており制御に使うのは確実ではなさそうなので現状は使っていません
  74. あとはどれくらいバッファしているかloadedTimeRangesから計算することもできます 。シークバーにバッファリングを表示したい場合などにも使えます。
  75. AVPlayerのTimeControlStatusはiOS10からのものですが、停止状態、指定rateで再生可能になるまで待っている状態、再生状態が判定できます。
  76. これはtimeControlStatusをobserveする例になります。
  77. 次にAVPlayerItemAccessLogですが、これは再生セッションの履歴が全て取得できます。AccessLogからはURIやbitrate情報、再生時間、stall回数など様々な情報が取得できますが、
  78. 取得は簡単でplayerItemのaccessLogからeventsが取得できます
  79. これはeventの最後を出力している例になります AccessLogはKVOできませんが、最新の情報はNewAccessLogEntryのNotificationをobserveして取得したり、timerで取得したりしますが、 accessログから再生開始までの時間であるstartupTimeや、bitrate関連情報など豊富に取得できます。
  80. eventは複数あって、再生開始からの履歴を全て持っているのでeventsをloopでまわして計算することもできます。この例はdurationWatchedという視聴時間を全て足し合わせて再生した総視聴時間を計算しています。
  81. こちらはindicatedBitrateと視聴時間から全体の視聴のbitrateの平均値を取得して、視聴のクオリティを評価することができる例になります。
  82. 次にAVPlayerItemErrorLogですが、Player内で発生したErrorの履歴を持っています。 これを見ることでplayerがstallした理由や、再生に失敗した理由などがわかります。
  83. 取得の仕方はaccesslogと同じでAVPlayerItemのerrorLogからeventsを取得できます
  84. errorlogのeventからはuriや発生時間、code,Domain,errorCommentなどの貴重な情報が取得できます。
  85. errorlogは必ずしもfatalなものだけではなくて non-fatalなエラー情報も含まれいて 404だったり、segmentがバンドワイズを超えるbitrateだったりといった情報も出力されます
  86. 以上のようにPlayerやPlayerItemから様々なmetricsが取得できるんですが、 WWDCでユーザの視聴体験を評価するのにstartup timeとstallの数、stallの長さ、ストリームの全体的なbitrateとエラーをユーザー視聴体験のmetricsとして取るように推奨しています。
  87. プレイヤーから様々な情報が取得できて、ユーザーの視聴体験を評価できることを説明しましたが、実際にやろうとした場合、サーバーにプレイヤーの状態を適時postして、サーバー側でデータを蓄積しダッシュボードで統計見れる必要があり、けっこう大変です。そのsolutionを提供しているものとして、有名どころでCONVIVAやYOUBORA,MUXやAkamaiさんのMediaNalyticsといったものがあり、iOS用のSDKも提供されているので検討して見る価値はあるかと思います。
  88. はい、まとめです。
  89. 今回お伝えしたかったポイントは3つで、まず動画の配信技術を知るということと、最適な動画再生/UXを追求することとユーザーの視聴体験を追求するということで、えー、動画再生が問題なくてもUIがガタガタだとストレスになりますし、逆にUIは問題なくても、動画の再生が遅いとユーザーはストレスになります。そこで最適な動画再生やユーザーの視聴体験を追求していくのに、動画の配信と動画の再生は密接に関わっているので配信技術を知るこよで、より良いチューニングができ、視聴体験をメトリクスしていくことで、さらに良いUXが追求できるかなと考えています。