mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Load preset input from JSON file in EffectActivity
The JSON file contains a list of playlists, each with a name and a list of media items. The EffectActivity loads the JSON file and creates a list of PlaylistHolder objects, which contain the playlist name and the list of media items. PiperOrigin-RevId: 703069411
This commit is contained in:
parent
f1a0e4b0b7
commit
b6724e2115
27
demos/effect/src/main/assets/media.playlist.json
Normal file
27
demos/effect/src/main/assets/media.playlist.json
Normal file
@ -0,0 +1,27 @@
|
||||
[
|
||||
{
|
||||
"name": "Cats -> Dogs",
|
||||
"playlist": [
|
||||
{
|
||||
"uri": "https://html5demos.com/assets/dizzy.mp4"
|
||||
},
|
||||
{
|
||||
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Android Block -> Dogs -> BigBuckBunny",
|
||||
"playlist": [
|
||||
{
|
||||
"uri": "https://storage.googleapis.com/exoplayer-test-media-0/android-block-1080-hevc.mp4"
|
||||
},
|
||||
{
|
||||
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv"
|
||||
},
|
||||
{
|
||||
"uri": "https://storage.googleapis.com/exoplayer-test-media-0/BigBuckBunny_320x180.mp4"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -49,6 +49,7 @@ import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.common.util.Util.SDK_INT
|
||||
@ -60,11 +61,16 @@ class EffectActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent { EffectDemo() }
|
||||
val playlistHolderList = mutableStateOf<List<PlaylistHolder>>(emptyList())
|
||||
lifecycleScope.launch {
|
||||
playlistHolderList.value =
|
||||
loadPlaylistsFromJson(JSON_FILENAME, this@EffectActivity, "EffectActivity")
|
||||
}
|
||||
setContent { EffectDemo(playlistHolderList.value) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EffectDemo() {
|
||||
private fun EffectDemo(playlistHolderList: List<PlaylistHolder>) {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
@ -100,7 +106,7 @@ class EffectActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InputChooser(onException: (String) -> Unit, onNewUri: (Uri) -> Unit) {
|
||||
private fun InputChooser(onException: (String) -> Unit, onNewUri: (Uri) -> Unit) {
|
||||
var showLocalFilePicker by remember { mutableStateOf(false) }
|
||||
Row(
|
||||
modifier = Modifier.padding(vertical = dimensionResource(id = R.dimen.small_padding)),
|
||||
@ -128,7 +134,7 @@ class EffectActivity : ComponentActivity() {
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
@Composable
|
||||
fun LocalFilePicker(onException: (String) -> Unit, onFileSelected: (Uri) -> Unit) {
|
||||
private fun LocalFilePicker(onException: (String) -> Unit, onFileSelected: (Uri) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val localFilePickerLauncher =
|
||||
rememberLauncherForActivityResult(
|
||||
@ -166,7 +172,7 @@ class EffectActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PlayerScreen(exoPlayer: ExoPlayer) {
|
||||
private fun PlayerScreen(exoPlayer: ExoPlayer) {
|
||||
val context = LocalContext.current
|
||||
AndroidView(
|
||||
factory = { PlayerView(context).apply { player = exoPlayer } },
|
||||
@ -177,9 +183,13 @@ class EffectActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Effects(onException: (String) -> Unit) {
|
||||
private fun Effects(onException: (String) -> Unit) {
|
||||
Button(onClick = { onException("Button is not yet implemented.") }) {
|
||||
Text(text = stringResource(id = R.string.apply_effects))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val JSON_FILENAME = "media.playlist.json"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package androidx.media3.demo.effect
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.JsonReader
|
||||
import android.util.Log
|
||||
import androidx.media3.common.MediaItem
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal suspend fun loadPlaylistsFromJson(
|
||||
jsonFilename: String,
|
||||
context: Context,
|
||||
tag: String,
|
||||
): List<PlaylistHolder> =
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
context.assets.open(jsonFilename).use { inputStream ->
|
||||
val reader = JsonReader(InputStreamReader(inputStream, StandardCharsets.UTF_8))
|
||||
val playlistHolders = buildList {
|
||||
reader.beginArray()
|
||||
while (reader.hasNext()) {
|
||||
readPlaylist(reader)?.let { add(it) }
|
||||
}
|
||||
reader.endArray()
|
||||
}
|
||||
playlistHolders
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e(tag, context.getString(R.string.playlist_loading_error, jsonFilename, e))
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun readPlaylist(reader: JsonReader): PlaylistHolder? {
|
||||
val playlistHolder = PlaylistHolder("", emptyList())
|
||||
reader.beginObject()
|
||||
while (reader.hasNext()) {
|
||||
val name = reader.nextName()
|
||||
if (name.equals("name")) {
|
||||
playlistHolder.title = reader.nextString()
|
||||
} else if (name.equals("playlist")) {
|
||||
playlistHolder.mediaItems = buildList {
|
||||
reader.beginArray()
|
||||
while (reader.hasNext()) {
|
||||
reader.beginObject()
|
||||
reader.nextName()
|
||||
add(MediaItem.fromUri(Uri.parse(reader.nextString())))
|
||||
reader.endObject()
|
||||
}
|
||||
reader.endArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
reader.endObject()
|
||||
// Only return the playlistHolder object if it has media items
|
||||
return if (playlistHolder.mediaItems.isNotEmpty()) playlistHolder else null
|
||||
}
|
||||
|
||||
internal data class PlaylistHolder(var title: String, var mediaItems: List<MediaItem>)
|
@ -19,4 +19,5 @@
|
||||
<string name="choose_local_file">Choose local file</string>
|
||||
<string name="apply_effects">Apply effects</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="playlist_loading_error">Error loading playlist from %1$s: %2$s</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user