2

I'm using below code to retrieve video frame from remote url using MediaMetadataRetriever but it lags and results in very low performant UI. How can I make it fast and efficient?

@Composable
private fun ContentItem(
    modifier: Modifier = Modifier,
    content: Content,
    onClick: (Content) -> Unit
) {
    when (content.type) {
        ContentType.Image -> {
            // handle image
        }

        ContentType.Video -> {
            val bitmap = remember { mutableStateOf<Bitmap?>(null) }

            LaunchedEffect(content) {
                val retriever = MediaMetadataRetriever()
                retriever.setDataSource(content.url)
                // Retrieve frame at 1 second
                bitmap.value = retriever.getFrameAtTime(
                    1000000,
                    MediaMetadataRetriever.OPTION_CLOSEST_SYNC
                )
                retriever.release()
            }

            bitmap.value?.let {
                Image(
                    modifier = modifier,
                    bitmap = it.asImageBitmap(),
                    contentDescription = null
                )
            }
        }
    }
}
Annon
  • 633
  • 7
  • 26
  • I am aware about video support by [Coil](https://coil-kt.github.io/coil/videos/) but not sure how to build custom `VideoFrameDecoder` as my url does not contain file extension. – Annon Nov 14 '22 at 16:45
  • what exactly do you mean by lag and low performant UI? do you execute it many times? – zjmo Nov 14 '22 at 17:20

1 Answers1

5

Instead of doing heavy work on ui thread you can use withContext and Dispatchers.Default as

LaunchedEffect(content) {
    withContext(Dispatchers.Default){
        val retriever = MediaMetadataRetriever()
        retriever.setDataSource(content.url)
        // Retrieve frame at 1 second
        bitmap.value = retriever.getFrameAtTime(
            1000000,
            MediaMetadataRetriever.OPTION_CLOSEST_SYNC
        )
        retriever.release()
    }
}
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • On this note, shouldn't I use `Dispatchers.IO` instead of `Dispatchers.Default`? – Annon Nov 14 '22 at 17:38
  • If the operation of getFrameAtTime is computational and most of the time is spent on computation instead of blocking operation you can go with Dispatchers.Default. If file open and inputStream takes more time you can go with Dispatchers.IO. `Dispatchers.IO - This dispatcher is optimized to perform disk or network I/O outside of the main thread. Examples include using the Room component, reading from or writing to files, and running any network operations.` – Thracian Nov 14 '22 at 17:44