Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Customize & Debug ExoPlayer @droidkaigi 2020

TakuSemba
March 17, 2020

Customize & Debug ExoPlayer @droidkaigi 2020

TakuSemba

March 17, 2020
Tweet

More Decks by TakuSemba

Other Decks in Technology

Transcript

  1. @takusemba
    https://github.com/TakuSemba

    View full-size slide

  2. Media Streaming

    View full-size slide

  3. Streaming
    Protocol

    View full-size slide

  4. Streaming
    Protocol

    View full-size slide

  5. Adaptive Bitrate

    View full-size slide

  6. val trackSelectionFactory = AdaptiveTrackSelection.Factory(
    MIN_DURATION_FOR_QUALITY_INCREASE_MS,
    MAX_DURATION_FOR_QUALITY_DECREASE_MS,
    ...
    )

    View full-size slide

  7. val trackSelectionFactory = AdaptiveTrackSelection.Factory(
    MIN_DURATION_FOR_QUALITY_INCREASE_MS,
    MAX_DURATION_FOR_QUALITY_DECREASE_MS,
    ...
    )
    AdaptiveTrackSelection.Factory(
    MIN_DURATION_FOR_QUALITY_INCREASE_MS,
    )

    View full-size slide

  8. val trackSelectionFactory = AdaptiveTrackSelection.Factory(
    MIN_DURATION_FOR_QUALITY_INCREASE_MS,
    MAX_DURATION_FOR_QUALITY_DECREASE_MS,
    ...
    )
    AdaptiveTrackSelection.Factory(
    MAX_DURATION_FOR_QUALITY_DECREASE_MS,
    )

    View full-size slide

  9. 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,

    View full-size slide

  10. 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

    View full-size slide

  11. val bandwidthMeter = DefaultBandwidthMeter.Builder(context).build()

    View full-size slide

  12. Bandwidth
    Time
    10Mbps

    View full-size slide

  13. Bandwidth
    Time
    10Mbps

    View full-size slide

  14. Bandwidth
    Time
    10Mbps

    View full-size slide

  15. Bandwidth
    Time
    10Mbps

    View full-size slide

  16. Bandwidth
    Time
    10Mbps

    View full-size slide

  17. Bandwidth
    Time
    10Mbps

    View full-size slide

  18. Bandwidth
    Time
    10Mbps

    View full-size slide

  19. Bandwidth
    Time
    10Mbps

    View full-size slide

  20. Bandwidth
    Time
    10Mbps

    View full-size slide

  21. Bandwidth
    Time
    10Mbps

    View full-size slide

  22. Bandwidth
    Time
    10Mbps
    6Mbps

    View full-size slide

  23. Bandwidth
    Time
    10Mbps
    6Mbps
    SlidingWindowMaxWeight

    View full-size slide

  24. Time
    6Mbps
    SlidingWindowMaxWeight

    View full-size slide

  25. Time
    SlidingWindowMaxWeight
    6Mbps * 0.75 = 4.5Mbps

    View full-size slide

  26. Time
    6Mbps * 0.75 = 4.5Mbps
    SlidingWindowMaxWeight
    BandwidthFraction

    View full-size slide

  27. 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()

    View full-size slide

  28. 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()

    View full-size slide

  29. 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)

    View full-size slide

  30. Initial Bitrate

    View full-size slide

  31. 5.7Mbps
    Wifi

    View full-size slide

  32. 5.7Mbps
    Wifi

    View full-size slide

  33. 2.0Mbps
    Wifi

    View full-size slide

  34. 2.0Mbps
    Wifi

    View full-size slide

  35. 5.7Mbps
    Wifi

    View full-size slide

  36. 5.7Mbps
    Wifi

    View full-size slide

  37. val bandwidthMeter = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(INITIAL_BITRATE_ESTIMATE)
    .build()

    View full-size slide

  38. val bandwidthMeter = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(INITIAL_BITRATE_ESTIMATE)
    .build()
    .setInitialBitrateEstimate(INITIAL_BITRATE_ESTIMATE)

    View full-size slide

  39. val bandwidthMeter = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    180p 360p 720p
    Session Scope

    View full-size slide

  40. Session Scope
    720p
    val bandwidthMeter = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()

    View full-size slide

  41. Session Scope
    180p 360p 720p
    val bandwidthMeter = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    720p

    View full-size slide

  42. Session Scope
    val bandwidthMeter = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    180p 360p 720p

    View full-size slide

  43. Session Scope
    val bandwidthMeter = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    720p

    View full-size slide

  44. Session Scope
    val bandwidthMeter = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    180p 360p 720p
    720p

    View full-size slide

  45. fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
    if (singletonInstance == null) {
    singletonInstance = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    }
    return singletonInstance
    }
    Application Scope
    180p 360p 720p

    View full-size slide

  46. Application Scope
    720p
    fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
    if (singletonInstance == null) {
    singletonInstance = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    }
    return singletonInstance
    }

    View full-size slide

  47. 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

    View full-size slide

  48. Application Scope
    fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
    if (singletonInstance == null) {
    singletonInstance = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    }
    return singletonInstance
    }
    720p 720p 720p

    View full-size slide

  49. Application Scope
    fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
    if (singletonInstance == null) {
    singletonInstance = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    }
    return singletonInstance
    }
    720p
    Launch App

    View full-size slide

  50. 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

    View full-size slide

  51. Application Scope
    fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
    if (singletonInstance == null) {
    singletonInstance = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    }
    return singletonInstance
    }
    180p 360p 720p

    View full-size slide

  52. Application Scope
    fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
    if (singletonInstance == null) {
    singletonInstance = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(LOWEST_RESOLUTION_BITRATE)
    .build()
    }
    return singletonInstance
    }
    720p

    View full-size slide

  53. 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

    View full-size slide

  54. 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

    View full-size slide

  55. 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

    View full-size slide

  56. 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

    View full-size slide

  57. 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
    }

    View full-size slide

  58. 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

    View full-size slide

  59. 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

    View full-size slide

  60. 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

    View full-size slide

  61. Lifetime Scope
    fun getSingletonBandwidthMeter(context: Context): DefaultBandwidthMeter {
    if (singletonInstance == null) {
    singletonInstance = DefaultBandwidthMeter.Builder(context)
    .setInitialBitrateEstimate(prefs.getLastEstimatedBitrate())
    .setResetOnNetworkTypeChange(true)
    .build()
    }
    return singletonInstance
    }
    720p

    View full-size slide

  62. 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

    View full-size slide

  63. 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

    View full-size slide

  64. 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

    View full-size slide

  65. 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

    View full-size slide

  66. Limit Bitrate

    View full-size slide

  67. val trackSelectionFactory = AdaptiveTrackSelection.Factory(...)
    val parameter = DefaultTrackSelector.ParametersBuilder(context)
    .setMaxVideoBitrate(MAX_VIDEO_BITRARE)
    .build()
    val trackSelector = DefaultTrackSelector(parameter, trackSelectionFactory)

    View full-size slide

  68. val trackSelectionFactory = AdaptiveTrackSelection.Factory(...)
    val parameter = DefaultTrackSelector.ParametersBuilder(context)
    .setMaxVideoBitrate(MAX_VIDEO_BITRARE)
    .build()
    val trackSelector = DefaultTrackSelector(parameter, trackSelectionFactory)
    .setMaxVideoBitrate(MAX_VIDEO_BITRARE)

    View full-size slide

  69. val trackSelectionFactory = AdaptiveTrackSelection.Factory(...)
    val parameter = DefaultTrackSelector.ParametersBuilder(context)
    .setMaxVideoSize(640, 360)
    .build()
    val trackSelector = DefaultTrackSelector(parameter, trackSelectionFactory)

    View full-size slide

  70. val trackSelectionFactory = AdaptiveTrackSelection.Factory(...)
    val parameter = DefaultTrackSelector.ParametersBuilder(context)
    .setMaxVideoSize(640, 360)
    .build()
    val trackSelector = DefaultTrackSelector(parameter, trackSelectionFactory)
    .setMaxVideoSize(640, 360)

    View full-size slide

  71. val newParameter = DefaultTrackSelector.ParametersBuilder(context)
    .setMaxVideoBitrate(NEW_MAX_VIDEO_BITRARE)
    .build()
    trackSelector.parameters = newParameter

    View full-size slide

  72. val newParameter = DefaultTrackSelector.ParametersBuilder(context)
    .setMaxVideoBitrate(NEW_MAX_VIDEO_BITRARE)
    .build()
    trackSelector.parameters = newParameter
    trackSelector.parameters = newParameter

    View full-size slide

  73. 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(...)
    }
    }

    View full-size slide

  74. 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
    }

    View full-size slide

  75. 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
    }
    }

    View full-size slide

  76. 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

    View full-size slide

  77. Chunkless Preparation

    View full-size slide

  78. m3u8
    Playlist

    View full-size slide

  79. ts
    First Chunk
    Playlist

    View full-size slide

  80. First Chunk
    Playlist Prepare Decoder

    View full-size slide

  81. First Chunk
    Playlist Prepare Decoder Start Decodeing

    View full-size slide

  82. #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

    View full-size slide

  83. #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"

    View full-size slide

  84. #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)

    View full-size slide

  85. #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)

    View full-size slide

  86. m3u8
    Playlist

    View full-size slide

  87. ts
    First Chunk
    Playlist
    Prepare Decoder

    View full-size slide

  88. First Chunk
    Playlist
    Prepare Decoder
    Start Decodeing

    View full-size slide

  89. Reuse Decoder

    View full-size slide

  90. Disabled Enabled Started

    View full-size slide

  91. Disabled Enabled Started
    No Streams
    No Decoders
    Have Streams
    Might Have Decoders
    Decoding

    View full-size slide

  92. Disabled Enabled Started
    No Streams
    No Decoders
    Have Streams
    Might Have Decoders
    Decoding
    Prepare Player

    View full-size slide

  93. Disabled Enabled Started
    ~ v2.10.0
    No Streams
    No Decoders
    Have Streams
    Might Have Decoders
    Decoding
    Prepare Player

    View full-size slide

  94. Disabled Enabled Started
    ~ v2.10.0
    No Streams
    No Decoders
    Have Streams
    Might Have Decoders
    Decoding
    Prepare Player

    View full-size slide

  95. Disabled Enabled Started
    ~ v2.10.0

    View full-size slide

  96. Disabled Enabled Started
    ~ v2.10.0
    v2.10.0 ~
    Disabled Enabled Started

    View full-size slide

  97. v2.10.0 ~
    Disabled Enabled Started

    View full-size slide

  98. v2.10.0 ~
    Disabled Enabled Started

    View full-size slide

  99. v2.10.0 ~
    Disabled Enabled Started
    Prepare Decoder Content A Content B Content C

    View full-size slide

  100. Tunneled Video Playback

    View full-size slide

  101. Media Source
    Renderer
    (Video)
    Renderer
    (Audio)
    Media Codec
    (Video)
    Media Codec
    (Audio)
    Audio Track Surface
    A/V Sync

    View full-size slide

  102. Media Source
    Renderer
    (Video)
    Renderer
    (Audio)
    Media Codec
    (Video)
    Media Codec
    (Audio)
    Audio Track Surface
    A/V Sync

    View full-size slide

  103. Media Source
    Renderer
    (Video)
    Renderer
    (Audio)
    Media Codec
    (Video)
    Media Codec
    (Audio)
    Audio Track Surface
    A/V Sync

    View full-size slide

  104. Media Source
    Renderer
    (Video)
    Renderer
    (Audio)
    Media Codec
    (Video)
    Media Codec
    (Audio)
    Audio Track Surface
    A/V Sync

    View full-size slide

  105. Media Source
    Renderer
    (Video)
    Renderer
    (Audio)
    Media Codec
    (Video)
    Media Codec
    (Audio)
    Audio Track Surface
    A/V Sync

    View full-size slide

  106. Media Source
    Renderer
    (Video)
    Renderer
    (Audio)
    Media Codec
    (Video)
    Media Codec
    (Audio)
    Audio Track Surface
    A/V Sync

    View full-size slide

  107. val parameter = DefaultTrackSelector.ParametersBuilder()
    .setTunnelingAudioSessionId(C.generateAudioSessionIdV21(this))
    .build()

    View full-size slide

  108. val parameter = DefaultTrackSelector.ParametersBuilder()
    .setTunnelingAudioSessionId(C.generateAudioSessionIdV21(this))
    .build()
    .setTunnelingAudioSessionId(C.generateAudioSessionIdV21(this))

    View full-size slide

  109. thread(name = "example-thread") {
    Trace.beginSection("do something")
    // do something
    Trace.endSection()
    }

    View full-size slide

  110. thread(name = "example-thread") {
    Trace.beginSection("do something")
    // do something
    Trace.endSection()
    }
    python systrace.py --app package-name --time=10 -o ~/Downloads/example.html

    View full-size slide

  111. python systrace.py --app "com.google.android.exoplayer2.demo" --time=10 -o ~/Downloads/trace.html

    View full-size slide

  112. Load Master Playlist

    View full-size slide

  113. Load Media Playlist

    View full-size slide

  114. Load First Chunk

    View full-size slide

  115. Prepare Decoder

    View full-size slide

  116. Initialize Video Decoder

    View full-size slide

  117. Initialize Audio Decoder

    View full-size slide

  118. Render Video Output Buffer

    View full-size slide

  119. Traditional Preparation
    Chunkless Preparation

    View full-size slide

  120. Traditional Preparation
    Chunkless Preparation

    View full-size slide

  121. Video Decoder Audio Decoder
    Decoder Initialization (150ms)

    View full-size slide

  122. ~ v2.10.0 (reuse decoder)
    v2.10.0 ~ (create recoders)

    View full-size slide

  123. ~ v2.10.0 (reuse decoder)
    v2.10.0 ~ (create recoders)

    View full-size slide

  124. with tunneling
    without tunneling

    View full-size slide

  125. 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

    View full-size slide