Skip to content

Commit

Permalink
feat: add video cache control
Browse files Browse the repository at this point in the history
  • Loading branch information
dsa28s committed Feb 1, 2023
1 parent c0d7fb0 commit c2d1d26
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ VideoPlayer(
- [x] Background Play
- [ ] Rate
- [ ] Resize Mode
- [x] Video Caching

### Contributing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,17 @@ import androidx.lifecycle.LifecycleEventObserver
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT
import com.google.android.exoplayer2.ui.StyledPlayerView
import com.google.android.exoplayer2.upstream.DefaultDataSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
import com.google.android.exoplayer2.util.RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL
import com.google.android.exoplayer2.util.RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE
import com.google.android.exoplayer2.util.RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE
import io.sanghun.compose.video.cache.VideoPlayerCacheConfig
import io.sanghun.compose.video.cache.VideoPlayerCacheManager
import io.sanghun.compose.video.controller.VideoPlayerControllerConfig
import io.sanghun.compose.video.controller.applyToExoPlayerView
import io.sanghun.compose.video.pip.enterPIPMode
Expand Down Expand Up @@ -77,15 +83,16 @@ import kotlinx.coroutines.delay
* @param autoPlay Autoplay when media item prepared. Default is true.
* @param usePlayerController Using player controller. Default is true.
* @param controllerConfig Player controller config. You can customize the Video Player Controller UI.
* @param seekBeforeMilliSeconds The seek back increment, in milliseconds. Default is 10sec (10000ms)
* @param seekAfterMilliSeconds The seek forward increment, in milliseconds. Default is 10sec (10000ms)
* @param seekBeforeMilliSeconds The seek back increment, in milliseconds. Default is 10sec (10000ms). Read-only props (Changes in values do not take effect.)
* @param seekAfterMilliSeconds The seek forward increment, in milliseconds. Default is 10sec (10000ms). Read-only props (Changes in values do not take effect.)
* @param repeatMode Sets the content repeat mode.
* @param volume Sets thie player volume. It's possible from 0.0 to 1.0.
* @param onCurrentTimeChanged A callback that returned once every second for player current time when the player is playing.
* @param fullScreenSecurePolicy Windows security settings to apply when full screen. Default is off. (For example, avoid screenshots that are not DRM-applied.)
* @param onFullScreenEnter A callback that occurs when the player is full screen. (The [VideoPlayerControllerConfig.showFullScreenButton] must be true to trigger a callback.)
* @param onFullScreenExit A callback that occurs when the full screen is turned off. (The [VideoPlayerControllerConfig.showFullScreenButton] must be true to trigger a callback.)
* @param enablePip Enable PIP (Picture-in-Picture). [handleLifecycle] must be false.
* @param cacheConfig Config for video cache. Read-only props (Changes in values do not take effect.)
* @param playerInstance Return exoplayer instance. This instance allows you to add [com.google.android.exoplayer2.analytics.AnalyticsListener] to receive various events from the player.
*/
@Composable
Expand All @@ -105,15 +112,26 @@ fun VideoPlayer(
onFullScreenEnter: () -> Unit = {},
onFullScreenExit: () -> Unit = {},
enablePip: Boolean = false,
cacheConfig: VideoPlayerCacheConfig = VideoPlayerCacheConfig.Default,
playerInstance: ExoPlayer.() -> Unit = {},
) {
val context = LocalContext.current
var currentTime by remember { mutableStateOf(0L) }

val player = remember(seekAfterMilliSeconds, seekBeforeMilliSeconds) {
val player = remember {
val httpDataSourceFactory = DefaultHttpDataSource.Factory()

ExoPlayer.Builder(context)
.setSeekBackIncrementMs(seekBeforeMilliSeconds)
.setSeekForwardIncrementMs(seekAfterMilliSeconds)
.apply {
if (cacheConfig.enableCache) {
val cacheDataSourceFactory = CacheDataSource.Factory()
.setCache(VideoPlayerCacheManager.initializeOrGetInstance(context, cacheConfig.maxCacheSize))
.setUpstreamDataSourceFactory(DefaultDataSource.Factory(context, httpDataSourceFactory))
setMediaSourceFactory(DefaultMediaSourceFactory(cacheDataSourceFactory))
}
}
.build()
.also(playerInstance)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.sanghun.compose.video.cache

import androidx.compose.runtime.Immutable

/**
* Settings for video cache.
* The cache method is the Last Recently Used (LRU) method.
*
* [VideoPlayerCacheConfig] lets you set whether to enable the cache and the maximum cache size in bytes.
*
* @param enableCache Sets whether cache is enabled. Default is true.
* @param maxCacheSize Sets the maximum cache capacity in bytes. If the cache builds up as much as the set capacity, it is deleted from the oldest cache. Default is 104857600 bytes (100MB).
*/
@Immutable
data class VideoPlayerCacheConfig(
val enableCache: Boolean,
val maxCacheSize: Long,
) {

companion object {

/**
* Default config for cache.
*/
val Default = VideoPlayerCacheConfig(
enableCache = true,
maxCacheSize = 100 * 1024 * 1024,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.sanghun.compose.video.cache

import android.content.Context
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
import com.google.android.exoplayer2.upstream.cache.Cache
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
import com.google.android.exoplayer2.upstream.cache.SimpleCache
import java.io.File

internal object VideoPlayerCacheManager {

private lateinit var cacheInstance: Cache

fun initializeOrGetInstance(context: Context, maxCacheBytes: Long): Cache {
if (::cacheInstance.isInitialized) {
return cacheInstance
}

cacheInstance = SimpleCache(
File(context.cacheDir, "video"),
LeastRecentlyUsedCacheEvictor(maxCacheBytes),
StandaloneDatabaseProvider(context)
)

return cacheInstance
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import android.content.ContextWrapper
* The environment in which Compose is hosted may not be an activity unconditionally.
* Gets the current activity that is open from various kinds of contexts such as Fragment, Dialog, etc.
*/
fun Context.findActivity(): Activity {
internal fun Context.findActivity(): Activity {
var context = this
while (context is ContextWrapper) {
if (context is Activity) return context
Expand Down
2 changes: 1 addition & 1 deletion sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ android {
compileSdk = 33

defaultConfig {
applicationId = "io.sanghun.compose.video"
applicationId = "io.sanghun.compose.video.sample"
minSdk = 21
targetSdk = 32
versionCode = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import com.google.android.exoplayer2.analytics.AnalyticsListener
import io.sanghun.compose.video.cache.VideoPlayerCacheConfig
import io.sanghun.compose.video.controller.VideoPlayerControllerConfig
import io.sanghun.compose.video.ui.theme.ComposeVideoSampleTheme

Expand Down Expand Up @@ -71,6 +72,7 @@ class MainActivity : ComponentActivity() {
showFullScreenButton = true,
),
repeatMode = repeatMode,
cacheConfig = VideoPlayerCacheConfig(enableCache = true, maxCacheSize = 1024 * 1024 * 1024),
onCurrentTimeChanged = {
Log.e("CurrentTime", it.toString())
},
Expand Down
3 changes: 3 additions & 0 deletions sample/src/main/kotlin/io/sanghun/compose/video/PlayList.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ val samplePlayList = listOf(
mediaMetadata = MediaMetadata.Builder().setTitle("Clear DASH: Tears").build(),
mimeType = MIME_TYPE_DASH,
),
VideoPlayerMediaItem.RawResourceMediaItem(
resourceId = R.raw.test_video,
),
VideoPlayerMediaItem.NetworkMediaItem(
url = "https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8",
mediaMetadata = MediaMetadata.Builder().setTitle("Clear HLS: Angel one").build(),
Expand Down
Binary file added sample/src/main/res/raw/test_video.mp4
Binary file not shown.

0 comments on commit c2d1d26

Please sign in to comment.