Refactor video testapp.
This commit is contained in:
parent
3673fa4908
commit
8b24498fa7
9 changed files with 168 additions and 91 deletions
|
@ -1,5 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
@ -16,7 +15,6 @@
|
|||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Signal">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -24,6 +22,14 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".transcode.TranscodeTestActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.Signal" />
|
||||
<activity
|
||||
android:name=".playback.PlaybackTestActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.Signal" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -5,43 +5,36 @@
|
|||
|
||||
package org.thoughtcrime.video.app
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.NameNotFoundException
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.PickVisualMediaRequest
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.ui.PlayerView
|
||||
import org.thoughtcrime.video.app.playback.PlaybackTestActivity
|
||||
import org.thoughtcrime.video.app.transcode.TranscodeTestActivity
|
||||
import org.thoughtcrime.video.app.ui.composables.LabeledButton
|
||||
import org.thoughtcrime.video.app.ui.theme.SignalTheme
|
||||
|
||||
|
||||
/**
|
||||
* Main activity for this sample app.
|
||||
*/
|
||||
class MainActivity : ComponentActivity() {
|
||||
private val viewModel: MainScreenViewModel by viewModels()
|
||||
private lateinit var exoPlayer: ExoPlayer
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
viewModel.initialize(this)
|
||||
exoPlayer = ExoPlayer.Builder(this).build()
|
||||
val startPlaybackScreen = Intent(this, PlaybackTestActivity::class.java)
|
||||
val startTranscodeScreen = Intent(this, TranscodeTestActivity::class.java)
|
||||
setContent {
|
||||
SignalTheme {
|
||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
|
||||
|
@ -49,70 +42,11 @@ class MainActivity : ComponentActivity() {
|
|||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
val videoUri = viewModel.selectedVideo
|
||||
if (videoUri == null) {
|
||||
LabeledButton("Select Video") { pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.VideoOnly)) }
|
||||
} else {
|
||||
LabeledButton("Play Video") { viewModel.updateMediaSource(this@MainActivity) }
|
||||
LabeledButton("Play Video with slow download") { viewModel.updateMediaSourceTrickle(this@MainActivity) }
|
||||
ExoVideoView(source = viewModel.mediaSource, exoPlayer = exoPlayer)
|
||||
}
|
||||
LabeledButton("Test Playback") { startActivity(startPlaybackScreen) }
|
||||
LabeledButton("Test Transcode") { startActivity(startTranscodeScreen) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
exoPlayer.pause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
viewModel.releaseCache()
|
||||
exoPlayer.stop()
|
||||
exoPlayer.release()
|
||||
}
|
||||
|
||||
/**
|
||||
* This launches the system media picker and stores the resulting URI.
|
||||
*/
|
||||
private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
|
||||
if (uri != null) {
|
||||
Log.d("PhotoPicker", "Selected URI: $uri")
|
||||
viewModel.selectedVideo = uri
|
||||
viewModel.updateMediaSource(this)
|
||||
} else {
|
||||
Log.d("PhotoPicker", "No media selected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LabeledButton(buttonLabel: String, modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||
Button(onClick = onClick, modifier = modifier) {
|
||||
Text(buttonLabel)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
@Composable
|
||||
fun ExoVideoView(source: MediaSource, exoPlayer: ExoPlayer, modifier: Modifier = Modifier) {
|
||||
exoPlayer.playWhenReady = false
|
||||
exoPlayer.setMediaSource(source)
|
||||
exoPlayer.prepare()
|
||||
AndroidView(factory = { context ->
|
||||
PlayerView(context).apply {
|
||||
player = exoPlayer
|
||||
}
|
||||
}, modifier = modifier)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun GreetingPreview() {
|
||||
SignalTheme {
|
||||
LabeledButton("Preview Render") {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.video.app.playback
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.PickVisualMediaRequest
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.ui.PlayerView
|
||||
import org.thoughtcrime.video.app.ui.composables.LabeledButton
|
||||
import org.thoughtcrime.video.app.ui.theme.SignalTheme
|
||||
|
||||
class PlaybackTestActivity : AppCompatActivity() {
|
||||
private val viewModel: PlaybackTestViewModel by viewModels()
|
||||
private lateinit var exoPlayer: ExoPlayer
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
viewModel.initialize(this)
|
||||
exoPlayer = ExoPlayer.Builder(this).build()
|
||||
setContent {
|
||||
SignalTheme {
|
||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
val videoUri = viewModel.selectedVideo
|
||||
if (videoUri == null) {
|
||||
LabeledButton("Select Video") { pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.VideoOnly)) }
|
||||
} else {
|
||||
LabeledButton("Play Video") { viewModel.updateMediaSource(this@PlaybackTestActivity) }
|
||||
LabeledButton("Play Video with slow download") { viewModel.updateMediaSourceTrickle(this@PlaybackTestActivity) }
|
||||
ExoVideoView(source = viewModel.mediaSource, exoPlayer = exoPlayer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
exoPlayer.pause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
viewModel.releaseCache()
|
||||
exoPlayer.stop()
|
||||
exoPlayer.release()
|
||||
}
|
||||
|
||||
/**
|
||||
* This launches the system media picker and stores the resulting URI.
|
||||
*/
|
||||
private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
|
||||
if (uri != null) {
|
||||
Log.d("PhotoPicker", "Selected URI: $uri")
|
||||
viewModel.selectedVideo = uri
|
||||
viewModel.updateMediaSource(this)
|
||||
} else {
|
||||
Log.d("PhotoPicker", "No media selected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
@Composable
|
||||
fun ExoVideoView(source: MediaSource, exoPlayer: ExoPlayer, modifier: Modifier = Modifier) {
|
||||
exoPlayer.playWhenReady = false
|
||||
exoPlayer.setMediaSource(source)
|
||||
exoPlayer.prepare()
|
||||
AndroidView(factory = { context ->
|
||||
PlayerView(context).apply {
|
||||
player = exoPlayer
|
||||
}
|
||||
}, modifier = modifier)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun GreetingPreview() {
|
||||
SignalTheme {
|
||||
LabeledButton("Preview Render") {}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.video.app
|
||||
package org.thoughtcrime.video.app.playback
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
|
@ -28,7 +28,7 @@ import java.io.File
|
|||
* Main screen view model for the video sample app.
|
||||
*/
|
||||
@OptIn(UnstableApi::class)
|
||||
class MainScreenViewModel : ViewModel() {
|
||||
class PlaybackTestViewModel : ViewModel() {
|
||||
// Initialize an silent media source before the user selects a video. This is the closest I could find to an "empty" media source while still being nullsafe.
|
||||
private val value by lazy {
|
||||
val factory = SilenceMediaSource.Factory()
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.video.app
|
||||
package org.thoughtcrime.video.app.playback
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.video.app.transcode
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class TranscodeTestActivity : AppCompatActivity() {
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.video.app.ui.composables
|
||||
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun LabeledButton(buttonLabel: String, modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||
Button(onClick = onClick, modifier = modifier) {
|
||||
Text(buttonLabel)
|
||||
}
|
||||
}
|
|
@ -4,5 +4,5 @@
|
|||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">Video Player</string>
|
||||
<string name="app_name">Video Framework Tester</string>
|
||||
</resources>
|
|
@ -6,5 +6,5 @@
|
|||
|
||||
<resources>
|
||||
|
||||
<style name="Theme.Signal" parent="android:Theme.Material.Light.NoActionBar" />
|
||||
<style name="Theme.Signal" parent="Theme.AppCompat.DayNight" />
|
||||
</resources>
|
Loading…
Add table
Reference in a new issue