diff --git a/demos/composition/src/main/java/androidx/media3/demo/composition/CompositionPreviewViewModel.kt b/demos/composition/src/main/java/androidx/media3/demo/composition/CompositionPreviewViewModel.kt index 6a0062a075c..7fc319f356e 100644 --- a/demos/composition/src/main/java/androidx/media3/demo/composition/CompositionPreviewViewModel.kt +++ b/demos/composition/src/main/java/androidx/media3/demo/composition/CompositionPreviewViewModel.kt @@ -104,11 +104,13 @@ import kotlinx.coroutines.guava.await import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.json.JSONException +import kotlin.math.min @OptIn(ExperimentalApi::class) class CompositionPreviewViewModel(application: Application) : AndroidViewModel(application) { - val compositionLayouts = listOf(Preset.SEQUENCE, Preset.GRID, Preset.PIP) + val compositionLayouts = + listOf(Preset.SEQUENCE, Preset.GRID, Preset.PIP, Preset.AV_SPLIT_REPRO) private val _uiState = MutableStateFlow(createInitialState()) val uiState: StateFlow = _uiState.asStateFlow() @@ -227,13 +229,18 @@ class CompositionPreviewViewModel(application: Application) : AndroidViewModel(a when (preset) { Preset.GRID -> 4 // 2x2 Grid Preset.PIP -> 2 // PiP Overlay + Preset.AV_SPLIT_REPRO -> 2 // video-only + audio-only else -> 1 // Sequence } val currentTrackTypes = currentState.sequenceTrackTypes val newTrackTypes = - List(numSequences) { i -> - if (i < currentTrackTypes.size) currentTrackTypes[i] - else setOf(C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO) + if (preset == Preset.AV_SPLIT_REPRO) { + listOf(setOf(C.TRACK_TYPE_VIDEO), setOf(C.TRACK_TYPE_AUDIO)) + } else { + List(numSequences) { i -> + if (i < currentTrackTypes.size) currentTrackTypes[i] + else setOf(C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO) + } } val firstItem = currentState.mediaState.availableItems.firstOrNull()?.copy() val newItemsBySequence: List> = @@ -249,6 +256,11 @@ class CompositionPreviewViewModel(application: Application) : AndroidViewModel(a Preset.SEQUENCE -> { List(1) { if (firstItem != null) List(4) { firstItem.copy() } else emptyList() } } + Preset.AV_SPLIT_REPRO -> { + // Same 3 clips in both sequences, so the audio-only sequence's item transitions + // mirror the video-only one exactly, as CompositionBuilder's split does. + List(2) { if (firstItem != null) List(3) { firstItem.copy() } else emptyList() } + } Preset.CUSTOM -> { val currentItemsBySequence = currentState.mediaState.selectedItemsBySequence List(numSequences) { i -> currentItemsBySequence[i] } @@ -840,7 +852,7 @@ class CompositionPreviewViewModel(application: Application) : AndroidViewModel(a .setFrameRate(DEFAULT_FRAME_RATE_FPS) // Setting duration explicitly is only required for preview with CompositionPlayer, // and is not needed for export with Transformer. - .setDurationUs(item.durationUs) + .setDurationUs(min(item.durationUs, 400000L)) sequenceBuilder.addItem(itemBuilder.build()) } } diff --git a/demos/composition/src/main/java/androidx/media3/demo/composition/data/CompositionState.kt b/demos/composition/src/main/java/androidx/media3/demo/composition/data/CompositionState.kt index b913add6d29..4d0f97be4b9 100644 --- a/demos/composition/src/main/java/androidx/media3/demo/composition/data/CompositionState.kt +++ b/demos/composition/src/main/java/androidx/media3/demo/composition/data/CompositionState.kt @@ -151,5 +151,8 @@ enum class Preset { SEQUENCE, GRID, PIP, + // Two sequences (video-only, audio-only) from the same clips, to test whether that + // structure is required to repro the short-clips playback freeze. + AV_SPLIT_REPRO, CUSTOM, } diff --git a/demos/composition/src/main/java/androidx/media3/demo/composition/ui/CompositionPreviewPane.kt b/demos/composition/src/main/java/androidx/media3/demo/composition/ui/CompositionPreviewPane.kt index 8919daef0d5..99dc8e39dbb 100644 --- a/demos/composition/src/main/java/androidx/media3/demo/composition/ui/CompositionPreviewPane.kt +++ b/demos/composition/src/main/java/androidx/media3/demo/composition/ui/CompositionPreviewPane.kt @@ -252,6 +252,7 @@ private fun presetToString(preset: Preset): String { Preset.SEQUENCE -> stringResource(R.string.preset_sequence) Preset.GRID -> stringResource(R.string.preset_grid) Preset.PIP -> stringResource(R.string.preset_pip) + Preset.AV_SPLIT_REPRO -> stringResource(R.string.preset_av_split_repro) Preset.CUSTOM -> stringResource(R.string.preset_custom) } } diff --git a/demos/composition/src/main/res/values/strings.xml b/demos/composition/src/main/res/values/strings.xml index 5f1cc093c84..ecb61607ecd 100644 --- a/demos/composition/src/main/res/values/strings.xml +++ b/demos/composition/src/main/res/values/strings.xml @@ -71,6 +71,7 @@ Sequential 2x2 grid PiP overlay + AV split repro Preset Preview: %s Add sequence