Add local video playback

pull/653/merge
Varun Patil 2023-05-14 13:32:25 -07:00
parent ce3ee760d0
commit 403e4404a7
4 changed files with 144 additions and 18 deletions

View File

@ -13,8 +13,6 @@ android {
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@ -32,16 +30,18 @@ android {
}
}
def mediaVersion = "1.0.1"
dependencies {
implementation 'androidx.core:core-ktx:1.10.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
implementation 'androidx.exifinterface:exifinterface:1.3.6'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "androidx.media3:media3-exoplayer:$mediaVersion"
implementation "androidx.media3:media3-ui:$mediaVersion"
implementation "androidx.media3:media3-exoplayer-dash:$mediaVersion"
}

View File

@ -1,21 +1,36 @@
package gallery.memories
import android.annotation.SuppressLint
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.media3.common.MediaItem
import androidx.media3.common.util.UnstableApi
import androidx.media3.common.util.Util
import androidx.media3.exoplayer.ExoPlayer
import gallery.memories.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@UnstableApi class MainActivity : AppCompatActivity() {
private val binding by lazy(LazyThreadSafetyMode.NONE) {
ActivityMainBinding.inflate(layoutInflater)
}
private lateinit var mNativeX: NativeX
private var player: ExoPlayer? = null
private var playerUri: Uri? = null
private var playerUid: String? = null
private var playWhenReady = true
private var mediaItemIndex = 0
private var playbackPosition = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Initialize services
@ -25,8 +40,35 @@ class MainActivity : AppCompatActivity() {
initializeWebView()
}
@SuppressLint("SetJavaScriptEnabled")
override fun onDestroy() {
super.onDestroy()
mNativeX.destroy()
}
public override fun onResume() {
super.onResume()
if (playerUri != null && (Util.SDK_INT <= 23 || player == null)) {
initializePlayer(playerUri!!, playerUid!!)
}
}
public override fun onPause() {
super.onPause()
if (Util.SDK_INT <= 23) {
releasePlayer()
}
}
public override fun onStop() {
super.onStop()
if (Util.SDK_INT > 23) {
releasePlayer()
}
}
@SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility")
private fun initializeWebView() {
// Intercept local APIs
binding.webview.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
view.loadUrl(request.url.toString())
@ -39,6 +81,15 @@ class MainActivity : AppCompatActivity() {
} else null
}
}
// Pass through touch events
binding.webview.setOnTouchListener { _, event ->
if (player != null) {
binding.videoView.dispatchTouchEvent(event)
}
false
}
val webSettings = binding.webview.settings
webSettings.javaScriptEnabled = true
webSettings.javaScriptCanOpenWindowsAutomatically = true
@ -49,11 +100,52 @@ class MainActivity : AppCompatActivity() {
binding.webview.clearCache(true)
binding.webview.addJavascriptInterface(mNativeX, "nativex")
binding.webview.loadUrl("http://10.0.2.2:8035/index.php/apps/memories/")
binding.webview.setBackgroundColor(0x00000000)
}
// Cleanup
override fun onDestroy() {
super.onDestroy()
mNativeX.destroy()
fun initializePlayer(uri: Uri, uid: String) {
if (player != null) {
if (playerUid.equals(uid)) return
player?.release()
player = null
}
playerUri = uri
playerUid = uid
player = ExoPlayer.Builder(this)
.build()
.also { exoPlayer ->
binding.videoView.player = exoPlayer
binding.videoView.visibility = View.VISIBLE
val mediaItem = MediaItem.fromUri(uri)
exoPlayer.setMediaItems(listOf(mediaItem), mediaItemIndex, playbackPosition)
exoPlayer.playWhenReady = playWhenReady
exoPlayer.prepare()
}
}
fun destroyPlayer(uid: String) {
if (playerUid.equals(uid)) {
releasePlayer()
// Reset vars
playWhenReady = true
mediaItemIndex = 0
playbackPosition = 0L
playerUri = null
playerUid = null
}
}
private fun releasePlayer() {
player?.let { exoPlayer ->
playbackPosition = exoPlayer.currentPosition
mediaItemIndex = exoPlayer.currentMediaItemIndex
playWhenReady = exoPlayer.playWhenReady
exoPlayer.release()
}
player = null
binding.videoView.visibility = View.GONE
}
}

View File

@ -9,14 +9,15 @@ import android.view.WindowInsetsController
import android.webkit.JavascriptInterface
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import androidx.appcompat.app.AppCompatActivity
import androidx.media3.common.util.UnstableApi
import gallery.memories.mapper.SystemImage
import gallery.memories.service.DownloadService
import gallery.memories.service.ImageService
import gallery.memories.service.TimelineQuery
import java.io.ByteArrayInputStream
import java.net.URLDecoder
class NativeX(private val mActivity: AppCompatActivity) {
@UnstableApi class NativeX(private val mActivity: MainActivity) {
val TAG = "NativeX"
private val mImageService: ImageService = ImageService(mActivity)
@ -99,6 +100,31 @@ class NativeX(private val mActivity: AppCompatActivity) {
mDlService!!.queue(url, filename)
}
@JavascriptInterface
fun playVideoLocal(fileId: String?) {
if (fileId == null) return;
Thread {
// Get URI of local video
val videos = SystemImage.getByIds(mActivity, arrayListOf(fileId.toLong()))
if (videos.isEmpty()) return@Thread
val video = videos[0]
// Play with exoplayer
mActivity.runOnUiThread {
mActivity.initializePlayer(video.uri, fileId)
}
}.start()
}
@JavascriptInterface
fun destroyVideo(fileId: String?) {
if (fileId == null) return;
mActivity.runOnUiThread {
mActivity.destroyPlayer(fileId)
}
}
@Throws(Exception::class)
private fun routerGet(path: String): WebResourceResponse {
val parts = path.split("/").toTypedArray()

View File

@ -6,6 +6,14 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.media3.ui.PlayerView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:visibility="gone"
/>
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"