video: support direct playback

pull/653/merge
Varun Patil 2023-05-23 19:57:01 -07:00
parent 79aecab377
commit e5745d0c05
2 changed files with 55 additions and 27 deletions

View File

@ -14,12 +14,15 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.common.util.Util import androidx.media3.common.util.Util
import androidx.media3.datasource.DefaultDataSource import androidx.media3.datasource.DefaultDataSource
import androidx.media3.datasource.DefaultHttpDataSource import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.hls.HlsMediaSource
import androidx.media3.exoplayer.source.ProgressiveMediaSource
import gallery.memories.databinding.ActivityMainBinding import gallery.memories.databinding.ActivityMainBinding
@UnstableApi class MainActivity : AppCompatActivity() { @UnstableApi class MainActivity : AppCompatActivity() {
@ -30,7 +33,7 @@ import gallery.memories.databinding.ActivityMainBinding
private lateinit var nativex: NativeX private lateinit var nativex: NativeX
private var player: ExoPlayer? = null private var player: ExoPlayer? = null
private var playerUri: Uri? = null private var playerUris: Array<Uri>? = null
private var playerUid: String? = null private var playerUid: String? = null
private var playWhenReady = true private var playWhenReady = true
private var mediaItemIndex = 0 private var mediaItemIndex = 0
@ -72,8 +75,8 @@ import gallery.memories.databinding.ActivityMainBinding
public override fun onResume() { public override fun onResume() {
super.onResume() super.onResume()
if (playerUri != null && (Util.SDK_INT <= 23 || player == null)) { if (playerUris != null && (Util.SDK_INT <= 23 || player == null)) {
initializePlayer(playerUri!!, playerUid!!) initializePlayer(playerUris!!, playerUid!!)
} }
if (mNeedRefresh) { if (mNeedRefresh) {
refreshTimeline(true) refreshTimeline(true)
@ -212,7 +215,7 @@ import gallery.memories.databinding.ActivityMainBinding
requestPermissionLauncher.launch(android.Manifest.permission.READ_EXTERNAL_STORAGE) requestPermissionLauncher.launch(android.Manifest.permission.READ_EXTERNAL_STORAGE)
} }
fun initializePlayer(uri: Uri, uid: String) { fun initializePlayer(uris: Array<Uri>, uid: String) {
if (player != null) { if (player != null) {
if (playerUid.equals(uid)) return if (playerUid.equals(uid)) return
player?.release() player?.release()
@ -220,20 +223,9 @@ import gallery.memories.databinding.ActivityMainBinding
} }
// Prevent re-creating // Prevent re-creating
playerUri = uri playerUris = uris
playerUid = uid playerUid = uid
// Add cookies from webview to data source
val cookies = CookieManager.getInstance().getCookie(uri.toString())
val httpDataSourceFactory =
DefaultHttpDataSource.Factory()
.setDefaultRequestProperties(mapOf("cookie" to cookies))
.setAllowCrossProtocolRedirects(true)
val dataSourceFactory = DefaultDataSource.Factory(this, httpDataSourceFactory)
// Create media item from local or remote uri
val mediaItem = MediaItem.fromUri(uri)
// Build exoplayer // Build exoplayer
player = ExoPlayer.Builder(this) player = ExoPlayer.Builder(this)
.build() .build()
@ -244,13 +236,43 @@ import gallery.memories.databinding.ActivityMainBinding
binding.videoView.setShowNextButton(false) binding.videoView.setShowNextButton(false)
binding.videoView.setShowPreviousButton(false) binding.videoView.setShowPreviousButton(false)
for (uri in uris) {
// Create media item from URI
val mediaItem = MediaItem.fromUri(uri)
// Check if remote or local URI
if (uri.toString().contains("http")) {
// Add cookies from webview to data source
val cookies = CookieManager.getInstance().getCookie(uri.toString())
val httpDataSourceFactory =
DefaultHttpDataSource.Factory()
.setDefaultRequestProperties(mapOf("cookie" to cookies))
.setAllowCrossProtocolRedirects(true)
val dataSourceFactory = DefaultDataSource.Factory(this, httpDataSourceFactory)
// Check if HLS source from URI (contains .m3u8 anywhere) // Check if HLS source from URI (contains .m3u8 anywhere)
exoPlayer.addMediaSource(
if (uri.toString().contains(".m3u8")) { if (uri.toString().contains(".m3u8")) {
exoPlayer.addMediaSource(HlsMediaSource.Factory(dataSourceFactory) HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItem)) .createMediaSource(mediaItem)
} else {
ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItem)
}
)
} else { } else {
exoPlayer.setMediaItems(listOf(mediaItem), mediaItemIndex, playbackPosition) exoPlayer.setMediaItems(listOf(mediaItem), mediaItemIndex, playbackPosition)
} }
}
// Catch errors and fall back to other sources
exoPlayer.addListener(object : Player.Listener {
override fun onPlayerError(error: PlaybackException) {
exoPlayer.seekToNext()
exoPlayer.playWhenReady = true
exoPlayer.play()
}
})
// Start the player // Start the player
exoPlayer.playWhenReady = playWhenReady exoPlayer.playWhenReady = playWhenReady
@ -266,7 +288,7 @@ import gallery.memories.databinding.ActivityMainBinding
playWhenReady = true playWhenReady = true
mediaItemIndex = 0 mediaItemIndex = 0
playbackPosition = 0L playbackPosition = 0L
playerUri = null playerUris = null
playerUid = null playerUid = null
} }
} }

View File

@ -13,6 +13,7 @@ import gallery.memories.service.AccountService
import gallery.memories.service.DownloadService import gallery.memories.service.DownloadService
import gallery.memories.service.ImageService import gallery.memories.service.ImageService
import gallery.memories.service.TimelineQuery import gallery.memories.service.TimelineQuery
import org.json.JSONArray
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.net.URLDecoder import java.net.URLDecoder
@ -155,16 +156,21 @@ import java.net.URLDecoder
// Play with exoplayer // Play with exoplayer
mCtx.runOnUiThread { mCtx.runOnUiThread {
mCtx.initializePlayer(video.uri, fileId) mCtx.initializePlayer(arrayOf(video.uri), fileId)
} }
}.start() }.start()
} }
@JavascriptInterface @JavascriptInterface
fun playVideoHls(fileId: String?, url: String?) { fun playVideoRemote(fileId: String?, urlsArray: String?) {
if (fileId == null || url == null) return if (fileId == null || urlsArray == null) return
val urls = JSONArray(urlsArray)
val list = Array(urls.length()) {
Uri.parse(urls.getString(it))
}
mCtx.runOnUiThread { mCtx.runOnUiThread {
mCtx.initializePlayer(Uri.parse(url), fileId) mCtx.initializePlayer(list, fileId)
} }
} }