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

Improving Video Playback with ExoPlayer

Improving Video Playback with ExoPlayer

Video has become an integral part of our life, and we are witnessing a significant rise in the integration of video content within Android apps. Sadly, there isn't much information out there about videos on Android. I've personally had a hard time finding practical ways to make videos better.

In this talk, my primary focus will be on sharing practical approaches with ExoPlayer that go beyond what is documented: We'll discuss the common problems with playbacks, solutions and will find a performant approach to use ExoPlayer.

Alexey Bykov

October 27, 2023
Tweet

More Decks by Alexey Bykov

Other Decks in Programming

Transcript

  1. 5 1. Starter ~ What is a Video? ~ Frames

    ~ Codecs ~ Resolutions & Bitrate ~ Adaptive Playback ~ Android Media3
  2. 6 2. Practical ~ Caching & Prefetching ~ Decoders ~

    Delivery ~ BandwidthMeter ~ UI & Jetpack Compose ~ LoadControl + Buffers You ExoPlayer and me 6 ~ Improve resolution
  3. 13 Motion 30 FPS * 1/30 = 33.33 ms 24

    FPS * 1/24 = 41.67 ms … …
  4. 14 Motion … … 30 FPS * 1/30 = 33.33

    ms 24 FPS * 1/24 = 41.67 ms 60 FPS * 1/60 = 16.67 ms
  5. 15 Storage consumption * Resolution: 1920x1080p * Duration: 10 sec

    * Bitrate: 10 mbps * File size: ~12 MB ~40 KB Frame * FPS: 30 1 second = 1.2 MB
  6. 18 Frames processing I-Frame * Has all data * Reference

    point P-Frame * Diff from prev. frame
  7. 19 Frames processing B-Frame * Diffs from prev. 
 and

    next frame I-Frame * Has all data * Reference point P-Frame * Diff from prev. frame
  8. 20 Frames processing B-Frame * Diffs from prev. 
 and

    next frame I-Frame * Has all data * Reference point P-Frame * Diff from prev. frame I-Frame
  9. 22 Mr. Codec * Goal: Compress/decompress data * Short: Coder

    / Decoder * Types: Software/Hardware * Variety: Just a lot of them!
  10. 23 VOD Codecs in production 2022-2023 * H.264/AVC * H.265/HEVC

    * H.266/VVC * AV1 * VP8 * MPEG/EVC * VP9 https://bitmovin.com/wp-content/uploads/2022/12/bitmovin-6th-video-developer-report-2022-2023.pdf ~85% —> 30% ~42% —> 48% ~15% —> 29% ~14% —> 42% ~14% —> 21% ~12% —> 17% ~10% —> 30% * MPEG5/LCEVC ~10% —> 22%
  11. 24 Quality, Resolution & Bitrate Frame Quality Resolution 320x240p 640x360

    Low VGA 1280x720 1920x1080 3840x2160 HD Full HD 4K https://castr.com/blog/bitrate-vs-resolution-whats-the-difference/ Target Bitrate ~18 mbps ~9 mbps (c) VP9 encoding recommendations ~1.8 mbps ~0.2 mbps ~0.1 mbps
  12. 25 Popular delivery methods Pure binary: mp4 - Uses a

    single bitrate + Easy setup + Supported everywhere - Not adaptive for network + Single roundtrip
  13. 26 Popular delivery methods Pure binary: mp4 Adaptive: Dash, Hls

    - Uses a single bitrate + Easy setup + Supported everywhere - Not adaptive for network + Multiple bitrates + Adapts to network change - Complex setup - Additional roundtrips + Single roundtrip
  14. 27 Adaptive + Works on Android & Web + Minimum

    2 roundtrips: - Manifest 
 - Segment Dash: Hls: + Works everywhere - Minimum 3 roundtrips 
 - Master Manifest 
 - Variant playlist - Segment - No native support for iOS
  15. 28 Adaptive Playback Mr. Backend Give me batch of videos

    Sr. CDN .mpd <Period duration="PT0H4M40.414S">
  16. 29 .mpd or Manifest <MPD xmlns="urn:mpeg:DASH:schema:MPD:2011"> <Period duration="PT0H4M40.414S"> <AdaptationSet mimeType="video/mp4">

    <Representation bandwidth="250000" id="video_lowest" /> <Representation bandwidth="500000" id="video_low" /> <Representation bandwidth="1000000" id="video_medium" /> <Representation bandwidth="2000000" id="video_high" /> </AdaptationSet> <AdaptationSet mimeType="audio/mp4"> <Representation bandwidth="64000" id="audio_low" /> <Representation bandwidth="128000" id="audio_high" /> </AdaptationSet> </Period> </MPD>
  17. 30 .mpd or Manifest <MPD xmlns="urn:mpeg:DASH:schema:MPD:2011"> <Period duration="PT0H4M40.414S"> <AdaptationSet mimeType="video/mp4">

    <Representation bandwidth="250000" id="video_lowest" /> <Representation bandwidth="500000" id="video_low" /> <Representation bandwidth="1000000" id="video_medium" /> <Representation bandwidth="2000000" id="video_high" /> </AdaptationSet> <AdaptationSet mimeType="audio/mp4"> <Representation bandwidth="64000" id="audio_low" /> <Representation bandwidth="128000" id="audio_high" /> </AdaptationSet> </Period> </MPD>
  18. 31 .mpd or Manifest <MPD xmlns="urn:mpeg:DASH:schema:MPD:2011"> <Period duration="PT0H4M40.414S"> <AdaptationSet mimeType="video/mp4">

    <Representation bandwidth="250000" id="video_lowest" /> <Representation bandwidth="500000" id="video_low" /> <Representation bandwidth="1000000" id="video_medium" /> <Representation bandwidth="2000000" id="video_high" /> </AdaptationSet> <AdaptationSet mimeType="audio/mp4"> <Representation bandwidth="64000" id="audio_low" /> <Representation bandwidth="128000" id="audio_high" /> </AdaptationSet> </Period> </MPD>
  19. 32 Dash Playback Mr. Backend Give me batch of videos

    Sr. CDN audio (selected quality) video (selected quality) .mpd <Period duration="PT0H4M40.414S">
  20. 35 Media 3 https://github.com/androidx/media 34 libraries exoplayer exoplayer-hls exoplayer-dash exoplayer-smoothstreaming

    exoplayer-datasource muxer ui transformer test_utils datasource_okhttp datasource_cronet decoder_av1 decoder_vp9 decoder_ffmpeg decoder_workmanager
  21. 39 Dash playback Sr. CDN audio (selected quality) video (selected

    quality) .mpd ¯\_(ツ)_/¯ Something went wrong
  22. 40 Playback errors: Video view: -5% +1.7% Mp4 vs Adaptive

    * This slide is my own opinion and does not reflect my employer
  23. 41 >45 seconds Playback errors: Video view: -5% +1.7% Use

    dash/hls if: Use mp4 if: <45 seconds Mp4 vs Adaptive DO
  24. 52 Where to cache? context.internalDir context.externalDir Availability Isolation from other

    apps System can clean up this ! Availability ! Isolation from other apps ! System is not cleaning this
  25. 54 ExoPlayer’s SimpleCache SimpleCache( cacheDir = file, evictor = )

    LatestRecentlyUsedCacheEvictor(maxCacheSizeBytes)
  26. 61 DownloadHelper Select a proper track Paired with DownloadManager You

    can’t define how much data you need to download ! https://github.com/google/ExoPlayer/issues/1497 Select track manually !
  27. 62 Playback errors: The same +2% Load < 500ms: Video

    view: +1.7% * This slide is my own opinion and does not reflect my employer Prefetching
  28. 65 Bandwidth-based prefetching 2 mbps 5 mbps 10 mbps 15

    mbps -4% -7% Load<500ms -1% -11% * This slide is my own opinion and does not reflect my employer
  29. 66 Bandwidth-based prefetching 2 mbps 5 mbps 10 mbps 15

    mbps -4% -7% Load<500ms -1% -11% * This slide is my own opinion and does not reflect my employer DON’T
  30. 67 Future Prefetch next N videos but 5-10 seconds each?

    Download them in parallel? Download segments of one in parallel?
  31. 69 LoadControl * Manages data buffering * Has a lot

    of customisations - shouldContinueLoading? - shouldStartPlayback?
  32. 75 2 flags: 2.5 60 52.5 Blocking buffering * bufferForPlaybackMs

    = 2.5s - First Frame - Playback stopped by user * bufferForPlaybackAfterRebuffer = 5s - Network latency problems
  33. 76 * bufferForPlaybackMs Load control: Recommendation Default: 2.5s ~1s —>

    * bufferForPlaybackAfterRebuffer Default: 5s ~1-2s —> * minBufferMs & maxBufferMs Default: 50s ~20-30s —> * setPrioritizeTimeOverSizeThresholds Default: false true —> Keep them equal !
  34. 83 Dash playback Sr. CDN audio (selected quality) video (selected

    quality) .mpd val bitrate = bandwidthMeter.bitrateEstimate
  35. 85 Dash playback audio video .mpd val bitrate = bandwidthMeter.bitrateEstimate

    Sr. CDN bitrate bitrate bandwidthMeter.onTransferEnd()
  36. 92 Initial bitrate public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI = ImmutableList.of(4_400_000L,

    3_200_000L, 2_300_000L, 1_600_000L, 810_000L); public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_4G = ImmutableList.of(2_600_000L, 1_700_000L, 1_300_000L, 1_000_000L, 700_000L); /** Default initial 5G-NSA bitrate estimates in bits per second. */ public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA = ImmutableList.of(5_700_000L, 3_700_000L, 2_300_000L, 1_700_000L, 990_000L);
  37. 93 Initial bitrate public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI = ImmutableList.of(4_400_000L,

    3_200_000L, 2_300_000L, 1_600_000L, 810_000L); public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_4G = ImmutableList.of(2_600_000L, 1_700_000L, 1_300_000L, 1_000_000L, 700_000L); public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA = ImmutableList.of(5_700_000L, 3_700_000L, 2_300_000L, 1_700_000L, 990_000L);
  38. 94 Initial bitrate private static int[] getInitialBitrateCountryGroupAssignment(String country) { switch

    (country) { case "AD": case "CW": return new int[] {2, 2, 0, 0, 2, 2}; case "AE": return new int[] {1, 4, 3, 4, 4, 2}; case "AG": return new int[] {2, 4, 3, 4, 2, 2}; case "AL": return new int[] {1, 1, 1, 3, 2, 2}; case "AM": return new int[] {2, 3, 2, 3, 2, 2}; case "AO": return new int[] {4, 4, 4, 3, 2, 2};
  39. 98 Ideas to experiment Decrease initial bitrate? Use last known

    per networkType? Use last known per networkType - threshold?
  40. 101 Mr. Backend Sr. CDN audio (selected quality) video (selected

    quality) .mpd 101 Idea Give me batch of videos
  41. 102 Mr. Backend Sr. CDN audio (selected quality) video (selected

    quality) .mpd 102 Idea 1080p 720p 480p + bitrateInfo Give me batch of videos:
  42. 103 Mr. Backend Sr. CDN 103 Idea val bitrate =

    bandwidthMeter.bitrateEstimate 1080p 720p 480p + bitrateInfo Give me batch of videos:
  43. 104 Mr. Backend Sr. CDN 104 Idea val bitrate =

    bandwidthMeter.bitrateEstimate val url = getUrl(bitrate) 1080p 720p 480p + bitrateInfo Give me batch of videos:
  44. 105 Mr. Backend Sr. CDN 105 Idea val url =

    getUrl(bitrate) val bitrate = bandwidthMeter.bitrateEstimate Give me batch of videos: 1080p 720p 480p + bitrateInfo (1080p) url
  45. 112 Mr. Backend Sr. CDN audio (selected quality) video (selected

    quality) .mpd 112 Give me batch of videos
  46. 113 Mr. Backend Sr. CDN 113 audio (selected quality) video

    (selected quality) .mpd Give me batch of videos decoding()
  47. 119 Where to render? TextureView SurfaceView + Scaling/Rotation/Alpha + Performance

    + DRM support + Simple to use - Battery consumption - Performance - DRM Support + More accurate frame timing - Complexity - API 24+ (animations/scrolling)
  48. 120 Where to render? TextureView SurfaceView + Scaling/Rotation/Alpha + Performance

    + DRM support + Simple to use - Battery consumption - Performance - DRM Support + More accurate frame timing - Complexity - API 24+ (animations) Suits: Complex clipping 
 Translucency 
 Arbitrary rotations Suits: Most of the other cases
  49. 127 Other things Analytics first: TTFF, Rebuffing, Playback errors, Watch

    time Single ExoPlayer instance to reuse decoders