Playing a video with ExoPlayer in Jetpack Compose

This recipe shows how to create a video player using ExoPlayer.

For a more complete (non-Compose overview) of Exoplayer, check this page. This snippet only show how to do it in Compose.

Looping video

This shows how to create an ExoPlayer and show it in Compose. It loops a video from the /res/raw folder, without showing UI controls.

@Composable
fun LoopingVideo(
    @RawRes id: Int,
    modifier: Modifier = Modifier
) {

    val context = LocalContext.current
    val exoPlayer = remember(context) {
        ExoPlayer.Builder(context).build().apply {

            val dataSpec = DataSpec(RawResourceDataSource.buildRawResourceUri(id))
            val dataSource = RawResourceDataSource(context)
            dataSource.open(dataSpec)
            val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
            val dataFactory = DataSource.Factory { dataSource }
            dataSource.uri?.let {
                val mediaItem = MediaItem.Builder().setUri(it).build()
                val source = ProgressiveMediaSource
                    .Factory(dataFactory, extractorsFactory)
                    .createMediaSource(mediaItem)
                setMediaSource(source)
                prepare()
            }

            // Optional: loop the video
            repeatMode = Player.REPEAT_MODE_ONE
        }
    }

    // There is no Composable ExoPlayer yet, so we use an AndroidView instead
    AndroidView(
        modifier = modifier,
        factory = {
            PlayerView(context).apply {
                // Setting the background color prevents black flashes
                // when the video loops. Set this to the background color
                // of your view.
                // Unfortunately, Color.Transparent did not seem to work.
                setShutterBackgroundColor(Color.White.toArgb())
                player = exoPlayer
                exoPlayer.playWhenReady = true
                // Optional configuration of the UI,
                // remove this to show player controls
                hideController()
                controllerAutoShow = false
            }
        }
    )
}