Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Customize & Debug ExoPlayer @droidkaigi 2020
Search
TakuSemba
March 17, 2020
Technology
2.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Customize & Debug ExoPlayer @droidkaigi 2020
TakuSemba
March 17, 2020
More Decks by TakuSemba
See All by TakuSemba
Jetpack Compose
takusemba
3
3.7k
Protobuf in Kotlin
takusemba
2
2.1k
Single Activity with MVVM
takusemba
4
1.4k
KotlinConf Report @ca.kt#7
takusemba
2
500
Request in a QUIC way @shibuya.apk#28
takusemba
2
1.2k
Lint for Kotlin @R.kt#3
takusemba
3
1.6k
Auto Release @potatochips#48
takusemba
1
1.3k
Media streaming on Android @droidkaigi 2018
takusemba
6
8.3k
gRPC on Android @DroidconSF Report
takusemba
1
650
Other Decks in Technology
See All in Technology
HRC_Frontend_Conference_Fukuoka_2026.pdf
ts020
0
740
AIで社員の自主発信に広報目線を組み込む
_mossann_t
0
120
30座EKS, 180次升級淬煉的EKS Upgrade Skill 的歷程
eric8230
0
170
AIエージェントの一手は 誰も見ていない - Falco拡張OSS「Prempti」とeBPFで サーバーレス実行基盤を二層防御する
keitah
0
140
aws-iot-platform-architecture-use-cases.pdf
ma2shita
0
280
アプリログインとWeb認証基盤をつなぐ ASWebAuthenticationSession 作法
shimastripe
1
340
銀行勘定系システムにおける開発プロセス刷新×AIによる環境モダナイゼーション / Development Process Transformation and AI-Driven Environment Modernization
muit
1
2.3k
CLIライブラリ開発を支える技術
htnabe
0
120
品質と信頼性を地続きにする
grimoh
0
710
白金鉱業Meetup Vol.25 アウトカムが二値のデータに対するCausal Impact
brainpadpr
0
230
その Lambda、8分で 管理者権限まで奪われます
k1nakayama
6
2.9k
技術的負債から考える、AI時代のエンジニアリング投資 — ビズリーチの技術的負債と向き合った経験から、変更し続けられるソフトウェアを考える/ technical-debt-con2026
visional_engineering_and_design
4
3.1k
Featured
See All Featured
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Product Roadmaps are Hard
iamctodd
55
13k
We Are The Robots
honzajavorek
0
380
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Marketing to machines
jonoalderson
1
5.8k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.1k
How to Think Like a Performance Engineer
csswizardry
28
2.8k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
530
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
230
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
200
Transcript
None
@takusemba https://github.com/TakuSemba
Media Streaming
None
None
None
None
None
Streaming Protocol
Streaming Protocol
None
None
None
None
None
None
None
None
None
None
...
Adaptive Bitrate
None
None
None
…
None
None
None
…
None
10s ~
~ 25s
val trackSelectionFactory = AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS, MAX_DURATION_FOR_QUALITY_DECREASE_MS, ... )
val trackSelectionFactory = AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS, MAX_DURATION_FOR_QUALITY_DECREASE_MS, ... ) AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS,
)
val trackSelectionFactory = AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS, MAX_DURATION_FOR_QUALITY_DECREASE_MS, ... ) AdaptiveTrackSelection.Factory( MAX_DURATION_FOR_QUALITY_DECREASE_MS,
)
val trackSelectionFactory = AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS, MAX_DURATION_FOR_QUALITY_DECREASE_MS, BUFFERED_FRACTION_TO_LIVE_EDGE_FOR_QUALITY_INCREASE, ... ) AdaptiveTrackSelection.Factory(
BUFFERED_FRACTION_TO_LIVE_EDGE_FOR_QUALITY_INCREASE,
val trackSelectionFactory = AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS, MAX_DURATION_FOR_QUALITY_DECREASE_MS, BUFFERED_FRACTION_TO_LIVE_EDGE_FOR_QUALITY_INCREASE, ... ) AdaptiveTrackSelection.Factory(
BUFFERED_FRACTION_TO_LIVE_EDGE_FOR_QUALITY_INCREASE, Edge Current Position Buffered Position 0.75
val bandwidthMeter = DefaultBandwidthMeter.Builder(context).build()
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps
Bandwidth Time 10Mbps 6Mbps
Bandwidth Time 10Mbps 6Mbps SlidingWindowMaxWeight
Time 6Mbps SlidingWindowMaxWeight
Time SlidingWindowMaxWeight 6Mbps * 0.75 = 4.5Mbps
Time 6Mbps * 0.75 = 4.5Mbps SlidingWindowMaxWeight BandwidthFraction
val trackSelectionFactory = AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS, MAX_DURATION_FOR_QUALITY_DECREASE_MS, BANDWIDTH_FRACTION ... ) val
bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setSlidingWindowMaxWeight(SLIDING_WINDOW_MAX_WEIGHT) .build()
val trackSelectionFactory = AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS, MAX_DURATION_FOR_QUALITY_DECREASE_MS, BANDWIDTH_FRACTION ... ) AdaptiveTrackSelection.Factory(
BANDWIDTH_FRACTION val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setSlidingWindowMaxWeight(SLIDING_WINDOW_MAX_WEIGHT) .build()
val trackSelectionFactory = AdaptiveTrackSelection.Factory( MIN_DURATION_FOR_QUALITY_INCREASE_MS, MAX_DURATION_FOR_QUALITY_DECREASE_MS, BANDWIDTH_FRACTION ... ) val
bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setSlidingWindowMaxWeight(SLIDING_WINDOW_MAX_WEIGHT) .build() .setSlidingWindowMaxWeight(SLIDING_WINDOW_MAX_WEIGHT)
Initial Bitrate
None
???
5.7Mbps Wifi
5.7Mbps Wifi
2.2Mbps 3G
2.2Mbps 3G
2.0Mbps Wifi
2.0Mbps Wifi
5.7Mbps Wifi
5.7Mbps Wifi
val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(INITIAL_BITRATE_ESTIMATE) .build()
val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(INITIAL_BITRATE_ESTIMATE) .build() .setInitialBitrateEstimate(INITIAL_BITRATE_ESTIMATE)
val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() 180p 360p 720p Session
Scope
Session Scope 720p val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build()
Session Scope 180p 360p 720p val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
.build() 720p
Session Scope val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() 180p 360p
720p
Session Scope val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() 720p
Session Scope val bandwidthMeter = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() 180p 360p
720p 720p
fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance == null) {
singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance } Application Scope 180p 360p 720p
Application Scope 720p fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance
== null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance }
Application Scope 720p 720p 720p fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
if (singletonInstance == null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance } 720p
Application Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance } 720p 720p 720p
Application Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance } 720p Launch App
Application Scope Launch App fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if
(singletonInstance == null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance } 720p 180p 360p 720p
Application Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance } 180p 360p 720p
Application Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance } 720p
Application Scope Wifi -> 4G fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
if (singletonInstance == null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .build() } return singletonInstance } 720p 720p
Application Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 720p 720p Wifi -> 4G
Application Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 720p Wifi -> 4G .setResetOnNetworkTypeChange(true) 720p
Application Scope Wifi -> 4G 720p 180p 360p fun getSingletonBandwidthMeter(context:
Context): DefaultBandwidthMeter { if (singletonInstance == null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 720p
Lifetime Scope 180p 360p 720p fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
if (singletonInstance == null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance }
Lifetime Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) 180p 360p 720p
Lifetime Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } .setResetOnNetworkTypeChange(true) 180p 360p 720p
Lifetime Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 180p 360p 720p
Lifetime Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 720p
720p 720p 720p Lifetime Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
if (singletonInstance == null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 720p
Lifetime Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 720p 720p 720p
Lifetime Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if (singletonInstance ==
null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 720p Launch App
Launch App Lifetime Scope fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter { if
(singletonInstance == null) { singletonInstance = DefaultBandwidthMeter.Builder(context) .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate()) .setResetOnNetworkTypeChange(true) .build() } return singletonInstance } 720p 720p 720p 720p
Limit Bitrate
None
None
val trackSelectionFactory = AdaptiveTrackSelection.Factory(...) val parameter = DefaultTrackSelector.ParametersBuilder(context) .setMaxVideoBitrate(MAX_VIDEO_BITRARE) .build()
val trackSelector = DefaultTrackSelector(parameter, trackSelectionFactory)
val trackSelectionFactory = AdaptiveTrackSelection.Factory(...) val parameter = DefaultTrackSelector.ParametersBuilder(context) .setMaxVideoBitrate(MAX_VIDEO_BITRARE) .build()
val trackSelector = DefaultTrackSelector(parameter, trackSelectionFactory) .setMaxVideoBitrate(MAX_VIDEO_BITRARE)
val trackSelectionFactory = AdaptiveTrackSelection.Factory(...) val parameter = DefaultTrackSelector.ParametersBuilder(context) .setMaxVideoSize(640, 360)
.build() val trackSelector = DefaultTrackSelector(parameter, trackSelectionFactory)
val trackSelectionFactory = AdaptiveTrackSelection.Factory(...) val parameter = DefaultTrackSelector.ParametersBuilder(context) .setMaxVideoSize(640, 360)
.build() val trackSelector = DefaultTrackSelector(parameter, trackSelectionFactory) .setMaxVideoSize(640, 360)
None
val newParameter = DefaultTrackSelector.ParametersBuilder(context) .setMaxVideoBitrate(NEW_MAX_VIDEO_BITRARE) .build() trackSelector.parameters = newParameter
val newParameter = DefaultTrackSelector.ParametersBuilder(context) .setMaxVideoBitrate(NEW_MAX_VIDEO_BITRARE) .build() trackSelector.parameters = newParameter trackSelector.parameters
= newParameter
None
None
None
None
None
class LimitTrackSelection(...) : AdaptiveTrackSelection(...) { private var maxVideoBitrate = Int.MAX_VALUE
fun setMaxVideoBitrate(maxVideoBitrate: Int) { this.maxVideoBitrate = maxVideoBitrate } override fun canSelectFormat( format: Format, trackBitrate: Int, playbackSpeed: Float, effectiveBitrate: Long ): Boolean { return trackBitrate <= maxVideoBitrate && super.canSelectFormat(...) } }
class LimitTrackSelection(...) : AdaptiveTrackSelection(...) { private var maxVideoBitrate = Int.MAX_VALUE
fun setMaxVideoBitrate(maxVideoBitrate: Int) { this.maxVideoBitrate = maxVideoBitrate } override fun canSelectFormat( format: Format, trackBitrate: Int, playbackSpeed: Float, effectiveBitrate: Long ): Boolean { return trackBitrate <= maxVideoBitrate && super.canSelectFormat(...) } } AdaptiveTrackSelection(...) { override fun canSelectFormat( format: Format, trackBitrate: Int, playbackSpeed: Float, effectiveBitrate: Long ): Boolean }
class LimitTrackSelection(...) : AdaptiveTrackSelection(...) { private var maxVideoBitrate = Int.MAX_VALUE
fun setMaxVideoBitrate(maxVideoBitrate: Int) { this.maxVideoBitrate = maxVideoBitrate } override fun canSelectFormat( format: Format, trackBitrate: Int, playbackSpeed: Float, effectiveBitrate: Long ): Boolean { return trackBitrate <= maxVideoBitrate && super.canSelectFormat(...) } } private var maxVideoBitrate = Int.MAX_VALUE fun setMaxVideoBitrate(maxVideoBitrate: Int) { this.maxVideoBitrate = maxVideoBitrate } override fun canSelectFormat( { return trackBitrate <= maxVideoBitrate } }
class LimitTrackSelection(...) : AdaptiveTrackSelection(...) { private var maxVideoBitrate = Int.MAX_VALUE
fun setMaxVideoBitrate(maxVideoBitrate: Int) { this.maxVideoBitrate = maxVideoBitrate } override fun canSelectFormat( format: Format, trackBitrate: Int, playbackSpeed: Float, effectiveBitrate: Long ): Boolean { return trackBitrate <= maxVideoBitrate && super.canSelectFormat(...) } } https://github.com/google/ExoPlayer/issues/2250
Chunkless Preparation
m3u8 Playlist
ts First Chunk Playlist
First Chunk Playlist Prepare Decoder
First Chunk Playlist Prepare Decoder Start Decodeing
#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=200000,CODECS="mp4a.40.2, avc1.4d4015" index1.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=600000,CODECS=“mp4a.40.2, avc1.4d401e" index2.m3u8 …
#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=200000,CODECS="mp4a.40.2, avc1.4d4015" index1.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=600000,CODECS=“mp4a.40.2, avc1.4d401e" index2.m3u8 … CODECS="mp4a.40.2, avc1.4d4015"
CODECS=“mp4a.40.2, avc1.4d401e"
#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=200000,CODECS="mp4a.40.2, avc1.4d4015" index1.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=600000,CODECS=“mp4a.40.2, avc1.4d401e" index2.m3u8 … CODECS="mp4a.40.2, avc1.4d4015"
CODECS=“mp4a.40.2, avc1.4d401e" val hlsMediaSource = HlsMediaSource.Factory(dataSourceFactory) .setAllowChunklessPreparation(true) .createMediaSource(uri)
#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=200000,CODECS="mp4a.40.2, avc1.4d4015" index1.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=600000,CODECS=“mp4a.40.2, avc1.4d401e" index2.m3u8 … CODECS="mp4a.40.2, avc1.4d4015"
CODECS=“mp4a.40.2, avc1.4d401e" val hlsMediaSource = HlsMediaSource.Factory(dataSourceFactory) .setAllowChunklessPreparation(true) .createMediaSource(uri) .setAllowChunklessPreparation(true)
m3u8 Playlist
ts First Chunk Playlist Prepare Decoder
First Chunk Playlist Prepare Decoder Start Decodeing
Reuse Decoder
Renderer
None
Disabled Enabled Started
Disabled Enabled Started No Streams No Decoders Have Streams Might
Have Decoders Decoding
Disabled Enabled Started No Streams No Decoders Have Streams Might
Have Decoders Decoding Prepare Player
Disabled Enabled Started ~ v2.10.0 No Streams No Decoders Have
Streams Might Have Decoders Decoding Prepare Player
Disabled Enabled Started ~ v2.10.0 No Streams No Decoders Have
Streams Might Have Decoders Decoding Prepare Player
Disabled Enabled Started ~ v2.10.0
Disabled Enabled Started ~ v2.10.0 v2.10.0 ~ Disabled Enabled Started
v2.10.0 ~ Disabled Enabled Started
v2.10.0 ~ Disabled Enabled Started
v2.10.0 ~ Disabled Enabled Started Prepare Decoder Content A Content
B Content C
Tunneled Video Playback
Media Source Renderer (Video) Renderer (Audio) Media Codec (Video) Media
Codec (Audio) Audio Track Surface A/V Sync
Media Source Renderer (Video) Renderer (Audio) Media Codec (Video) Media
Codec (Audio) Audio Track Surface A/V Sync
Media Source Renderer (Video) Renderer (Audio) Media Codec (Video) Media
Codec (Audio) Audio Track Surface A/V Sync
Media Source Renderer (Video) Renderer (Audio) Media Codec (Video) Media
Codec (Audio) Audio Track Surface A/V Sync
Media Source Renderer (Video) Renderer (Audio) Media Codec (Video) Media
Codec (Audio) Audio Track Surface A/V Sync
Media Source Renderer (Video) Renderer (Audio) Media Codec (Video) Media
Codec (Audio) Audio Track Surface A/V Sync
val parameter = DefaultTrackSelector.ParametersBuilder() .setTunnelingAudioSessionId(C.generateAudioSessionIdV21(this)) .build()
val parameter = DefaultTrackSelector.ParametersBuilder() .setTunnelingAudioSessionId(C.generateAudioSessionIdV21(this)) .build() .setTunnelingAudioSessionId(C.generateAudioSessionIdV21(this))
Systrace
thread(name = "example-thread") { Trace.beginSection("do something") // do something Trace.endSection()
}
thread(name = "example-thread") { Trace.beginSection("do something") // do something Trace.endSection()
} python systrace.py --app package-name --time=10 -o ~/Downloads/example.html
None
python systrace.py --app "com.google.android.exoplayer2.demo" --time=10 -o ~/Downloads/trace.html
Load Master Playlist
Load Media Playlist
Load First Chunk
Prepare Decoder
None
Initialize Video Decoder
Initialize Audio Decoder
None
Render Video Output Buffer
Traditional Preparation Chunkless Preparation
Traditional Preparation Chunkless Preparation
Video Decoder Audio Decoder Decoder Initialization (150ms)
~ v2.10.0 (reuse decoder) v2.10.0 ~ (create recoders)
~ v2.10.0 (reuse decoder) v2.10.0 ~ (create recoders)
with tunneling without tunneling
Reference https://medium.com/google-exoplayer/faster-hls-preparation-f6611aa15ea6 https://medium.com/google-exoplayer/tunneled-video-playback-in-exoplayer-84f084a8094d https://medium.com/google-exoplayer/improved-decoder-reuse-in-exoplayer-ef4c6d99591d https://exoplayer.dev