0

I have a local HTTP server where I'm hosting an MP4 file (about 50MB). I set up the following Composable in my app:

@Composable
private fun VideoItem(
    url: String,
    modifier: Modifier = Modifier
) {
    val context = LocalContext.current

    val player = remember(context) {
        ExoPlayer.Builder(context)
            .build()
            .apply {
                val mediaItem = MediaItem.fromUri(url)
                setMediaItem(mediaItem)
                prepare()
                play()
            }
    }

    DisposableEffect(Unit) {
        onDispose {
            player.release()
        }
    }

    Box(
        modifier = modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        AndroidView(
            factory = { context ->
                PlayerView(context).apply {
                    this.player = player
                }
            }
        )
    }
}

The URL is something like "http://192.168.123.123:8080/sample.mp4", and I make sure that the phone is connected to the same network when accessing it. However, it takes around 50 seconds for the initial prepare() to finish - that is, the video takes about 50 seconds to load before it even shows the total time and starts playing. That raises a few questions for me:

  1. Is it possible that ExoPlayer attempts to download the entire file before it even begins to play it? That would explain the delay of 50 seconds for 50MB, as 1 MB/s seems about right for the network.
  2. If 1) is true, how come the full video is not loaded immediately? That is, if I skip to some further point in the video, the "buffering" still appears and it takes a few seconds to start playing from that point.
  3. Is there a way to speed up this initial loading? Or somehow stream the video instead?

I am using Compose BOM 2023.06.01 and Media3 1.1.1.

Sharp
  • 1,335
  • 1
  • 12
  • 27
  • Add logging to the player to see what's going on using `player.addAnalyticsListener(EventLogger())` – sdex Aug 23 '23 at 05:56
  • I did, and it would show everything to be 0 (current position, video length, buffer, etc.) until the video has been loaded. It would log "isLoading = true", and then only after 50 seconds it would log again "isLoading = false" with the actual values of the video. – Sharp Aug 23 '23 at 20:02

2 Answers2

0

if you want to speed up the process, i suggest to use cache mechanism in exoplayer, this can improve the loading process especially if you preload the video using cache before starting to play it. use CacheDataSourceFactory for your dataSource:

cacheDataSourceFactory = new CacheDataSourceFactory(
                SimplePlayerCache.getInstance(),
                dataSourceFactory,
                CacheDataSource.FLAG_BLOCK_ON_CACHE | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)

and for the preload process create dataSource instance using

CacheDataSource cacheDataSource =cacheDataSourceFactory.createDataSource()

and then open the source like:

cacheDataSource.open(new DataSpec(Uri.parse(play_url)))

and after that, start to read & cache the media using

cacheDataSource.read(buffer,offset,length)

now, when you want to play the media, it will start playing with no delay

Sep
  • 147
  • 8
  • This makes sense in general, but in my case, I'm displaying something similar to a gallery with thumbnails of videos. I cannot know which video will the user select, so unfortunately I cannot preload it. – Sharp Aug 22 '23 at 09:08
  • well i guess you can cache a small amout of visible video items, like 10KB. i didn't implement this situation, so maybe this doesn't work. but give it a shot if you could. maybe it solved your problem. – Sep Aug 22 '23 at 14:06
0

Try to set playWhenReady flag:

val player = remember(context) {
    ExoPlayer.Builder(context)
        .build()
        .apply {
            val mediaItem = MediaItem.fromUri(url)
            setMediaItem(mediaItem)
            playWhenReady = true
            prepare()
            play()
        }
}
sdex
  • 3,169
  • 15
  • 28