Videoinhalt eines Exoplayers in einem anderen Exoplayer [Duplikat]Android

Forum für diejenigen, die für Android programmieren
Anonymous
 Videoinhalt eines Exoplayers in einem anderen Exoplayer [Duplikat]

Post by Anonymous »

Ich arbeite an einer Twitter -ähnlichen App und verwende Jetpack Compose und ExoPlayer3. In meiner Android -App gibt es eine Netzansicht, die aus Gitterartikeln besteht, die ein Video oder ein Bild sein können. Im Folgenden von 3 Elementen. Der erste und der 3. sind Videos. Die Ausrichtung des 2. Videos ist Porträt und überläuft den Rand des übergeordneten Containers in das erste Video. Ich stellte fest, dass es nur dann passiert, wenn sich zwei Exoplayer gegenseitig überlappen. Im folgenden Raster ist der 4. Element auch ein Porträtvideo. Das Element oben ist ein Bild und das Video belastet es in seinem Container fein.

Code: Select all

@Composable
fun MediaPreviewGrid(
mediaItems: List,
viewModel: TweetViewModel,
onFullScreenVideo: ((String, MimeiId) -> Unit)? = null, // Callback for full-screen video
) {
val tweet by viewModel.tweetState.collectAsState()
val navController = LocalNavController.current
val maxItems = when (mediaItems.size) {
1 -> 1
2, 3 -> mediaItems.size
else -> 4
}

// Set up sequential playback for multiple videos
val videoMids = remember {
limitedMediaList.mapIndexedNotNull { index, item ->
if (inferMediaTypeFromAttachment(item) == MediaType.Video) item.mid else null
}
}

Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentWidth(Alignment.CenterHorizontally)
) {
when (limitedMediaList.size) {
1 -> {
val aspectRatio = if (aspectRatioOf(limitedMediaList[0]) > 0.8f) {
aspectRatioOf(limitedMediaList[0])
} else {
0.8f
}
MediaItemView(
limitedMediaList,
modifier = Modifier
.fillMaxWidth()
.aspectRatio(aspectRatio)
.clipToBounds()
.clickable {
val params = MediaViewerParams(
mediaItems.map {
MediaItem(
getMediaUrl(it.mid, tweet.author?.baseUrl.orEmpty()).toString(),
it.type
)
}, 0, tweet.mid, tweet.authorId
)
navController.navigate(NavTweet.MediaViewer(params))
},
index = 0,
numOfHiddenItems = if (mediaItems.size > maxItems) mediaItems.size - maxItems else 0,
autoPlay = firstVideoIndex == 0,
inPreviewGrid = true,
viewModel = viewModel,
onFullScreenVideo = onFullScreenVideo
)
}
2 -> {}
3 -> {}
4 -> {}
}
}
}

@Composable
fun MediaItemView(
mediaItems: List,
modifier: Modifier = Modifier,
index: Int,
numOfHiddenItems: Int = 0,      // add a PLUS sign to indicate more items not shown
autoPlay: Boolean = false,      // autoplay first video item, index 0
inPreviewGrid: Boolean = true,  // use real aspectRatio when not displaying in preview grid.
viewModel: TweetViewModel,
onFullScreenVideo: ((String, MimeiId) -> Unit)? = null // Callback for full-screen video
) {
val tweet by viewModel.tweetState.collectAsState()
val attachments = mediaItems.map {
val inferredType = inferMediaTypeFromAttachment(it)
val mediaUrl = getMediaUrl(it.mid, tweet.author?.baseUrl.orEmpty()).toString()
MediaItem(mediaUrl, inferredType)
}
val attachment = attachments[index]
val navController = LocalNavController.current

Box(
modifier = modifier
.background(Color.Gray.copy(alpha = 0.1f))
.clipToBounds(),
contentAlignment = Alignment.Center
) {
when (attachment.type) {
MediaType.Image -> {
// Use a Box with clickable modifier to handle image clicks
Box(
modifier = modifier
.clipToBounds()
.clickable {
goto(index)
}
) {
ImageViewer(
attachment.url,
modifier = Modifier.fillMaxSize(),
enableLongPress = false // Disable long press to allow clickable to work
)
}
}
MediaType.Video ->  {
VideoPreview(
url = attachment.url,
modifier = modifier,
index = index,
autoPlay = autoPlay,
inPreviewGrid = inPreviewGrid,
aspectRatio = mediaItems[index].aspectRatio,
callback = { goto(index) },
videoMid = mediaItems[index].mid
)
}
MediaType.Audio -> {
val backgroundModifier = if (index % 2 != 0) { // Check if index is odd
modifier.background(Color.Black.copy(alpha = 0.05f)) // Slightly darker background
} else {
modifier
}
Box(
modifier = backgroundModifier
.clipToBounds()
.clickable {
goto(index)
}
) {
AudioPreview(mediaItems, index, Modifier.fillMaxSize(), tweet)
}
}
else -> {       // add link to download other file type
BlobLink(mediaItems[index], attachment.url, modifier)
}
}
if (numOfHiddenItems > 0) {
/**
* Show a PLUS sign and number to indicate more items not shown
* */
Box(
modifier = Modifier
.matchParentSize()
.background(Color(0x40FFFFFF)), // Lighter shaded background
contentAlignment = Alignment.Center
) {
Row(modifier = Modifier.align(Alignment.Center))
{
Icon(
imageVector = Icons.Outlined.Add,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.size(50.dp)
.alpha(0.8f)
)
Text(
text = numOfHiddenItems.toString(),
color = Color.White,
fontSize = 50.sp, // Adjust this value as needed
textAlign = TextAlign.Center,
modifier = Modifier
.alpha(0.8f)
)
}
}
}
}
}

@Composable
fun VideoPreview(
url: String,
modifier: Modifier,
index: Int,
autoPlay: Boolean = false,
inPreviewGrid: Boolean = true,
aspectRatio: Float?,
callback: (Int) ->  Unit,
videoMid: MimeiId? = null
) {
val context = LocalContext.current
var isVideoVisible by remember { mutableStateOf(false) }
var isMuted by remember { mutableStateOf(preferenceHelper.getSpeakerMute()) }
var isLoading by remember {
mutableStateOf(videoMid?.let { !VideoManager.isVideoPreloaded(it) } ?: true)
}

val exoPlayer = remember(url, videoMid) {
if (videoMid != null) {
VideoManager.getVideoPlayer(context, videoMid, url)
} else {
createExoPlayer(context, url, MediaType.Video)
}
}

// Preload video if not already cached

Box(
modifier = modifier
.clipToBounds()
.background(MaterialTheme.colorScheme.surfaceVariant) // Material3 surface variant for loading background
.onGloballyPositioned { layoutCoordinates ->
isVideoVisible = isElementVisible(layoutCoordinates)
}
.clickable {
// Auto-start video in full screen
callback(index)
}
) {
AndroidView(
factory = {
PlayerView(context).apply {
player = exoPlayer
useController = false // No controls in preview mode
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
// Set background color to light gray (Material3 surface variant equivalent)
setBackgroundColor(android.graphics.Color.rgb(245, 245, 245))
// Show buffering indicator
setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
}
},
modifier = Modifier.fillMaxWidth()
)

// Show loading indicator when video is loading
if (isLoading) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = androidx.compose.ui.Alignment.Center
) {
CircularProgressIndicator(
modifier = Modifier.size(32.dp),
color = MaterialTheme.colorScheme.primary
)
}
}
}
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post