此代码允许我播放视频,并且使用设置按钮(齿轮图标),我可以打开视频轨道选择器对话框,但是当我更改大小时,播放器会卡在屏幕上的循环中,并且视频大小调整为屏幕的一部分。
这是 Exoplayer 屏幕。
@UnstableApi
@Preview(device = "id:pixel_5", showSystemUi = true, showBackground = true)
@Composable
fun ExoplayerScreenPreview() {
ExoplayerScreen()
}
@UnstableApi
@Composable
fun ExoplayerScreen() {
MyStatusBar(color = colorResource(id = R.color.colorPrimaryDark))
Scaffold(topBar = { MyToolBar() }, content = { padding ->
ExoplayerScreenContent(Modifier.padding(padding))
})
}
@UnstableApi
@Composable
fun ExoplayerScreenContent(modifier: Modifier) {
Box(
modifier = modifier
.fillMaxWidth()
.height(230.dp)
) {
VideoScreen()
}
}
这是视频屏幕
@SuppressLint("OpaqueUnitKey")
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
@Composable
fun VideoScreen() {
val context = LocalContext.current
val playerView = PlayerView(context)
val exoPlayer = remember {
ExoPlayer.Builder(context).build().apply {
setMediaItem(
MediaItem.fromUri(
"https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8"
)
)
prepare()
play()
videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
}
}
var isPlaying by remember {
mutableStateOf(false)
}
exoPlayer.addListener(object : Player.Listener {
override fun onIsPlayingChanged(isPlayingValue: Boolean) {
isPlaying = isPlayingValue
}
})
DisposableEffect(Box {
AndroidView(modifier = Modifier.fillMaxSize(), factory = {
playerView.apply {
// Resizes the video in order to be able to fill the whole screen
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
player = exoPlayer
// Hides the default Player Controller
useController = false
// Fills the whole screen
layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
}
})
VideoLayout(
isPlaying = isPlaying,
onPlay = { exoPlayer.play() },
onPause = { exoPlayer.pause() },
exoPlayer = exoPlayer,
)
}) {
onDispose { exoPlayer.release() }
}
}
这是视频布局
@Composable
fun VideoLayout(
isPlaying: Boolean,
onPlay: () -> Unit,
onPause: () -> Unit,
exoPlayer: ExoPlayer,
) {
Box(modifier = Modifier
.fillMaxSize()
.clickable {
if (isPlaying) {
onPause()
} else {
onPlay()
}
}) {
AnimatedVisibility(
visible = !isPlaying, enter = fadeIn(tween(200)), exit = fadeOut(tween(200))
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(
Color.Black.copy(alpha = 0.6f)
), contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Rounded.Pause, contentDescription = null, tint = Color.White
)
}
Box(
modifier = Modifier
.fillMaxSize()
.padding(vertical = 15.dp, horizontal = 20.dp),
contentAlignment = Alignment.BottomEnd
) {
val context = LocalContext.current
Column(
verticalArrangement = Arrangement.spacedBy(15.dp)
) {
IconButton(onClick = { trackSeleccion(exoPlayer, context) }) {
Icon(
imageVector = Icons.Rounded.Settings,
contentDescription = null,
tint = Color.White
)
}
IconButton(onClick = { /*TODO*/ }) {
Icon(
imageVector = Icons.Rounded.Comment,
contentDescription = null,
tint = Color.White
)
}
IconButton(onClick = { /*TODO*/ }) {
Icon(
imageVector = Icons.Rounded.IosShare,
contentDescription = null,
tint = Color.White
)
}
}
}
}
}
}
这是曲目选择
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
fun trackSeleccion(exoplayer: ExoPlayer, context: Context) {
val trackSelector = exoplayer.trackSelector as DefaultTrackSelector
val mappedTrackInfo = trackSelector.currentMappedTrackInfo
if (mappedTrackInfo != null) {
val rendererIndex = 2
val rendererType = mappedTrackInfo.getRendererType(rendererIndex)
val allowAdaptiveSelections =
rendererType == C.TRACK_TYPE_VIDEO || (rendererType == C.TRACK_TYPE_AUDIO && mappedTrackInfo.getTypeSupport(
C.TRACK_TYPE_VIDEO
) == MappingTrackSelector.MappedTrackInfo.RENDERER_SUPPORT_NO_TRACKS)
val builder =
TrackSelectionDialogBuilder(context, "Selección de pistas", exoplayer, rendererIndex)
builder.setShowDisableOption(false)
builder.setAllowAdaptiveSelections(allowAdaptiveSelections)
builder.setOverrides(exoplayer.trackSelectionParameters.overrides)
builder.build().show()
}
exoplayer.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
Log.e("trackSeleccion", "trackSeleccion: ")
}
红色方块是播放器开始播放视频时,蓝色方块是我将视频轨道更改为较低分辨率时
我已经尝试过该代码,但是在更改分辨率时我无法让视频保持在屏幕宽度,并且它只会改变质量。
我正在使用Media3。
为了实现在更改分辨率时视频保持屏幕宽度的所需行为,您可以利用 ExoPlayer 的宽高比处理功能。您可能还需要调整布局和配置。 以下是实现此目标的一些建议:
调整
VideoScreen
和Layout
:
修改您的
VideoScreen
可组合项以包含包裹 AspectRatioFrameLayout
的 PlayerView
。此帧布局允许您控制视频的宽高比。确保将 resizeMode
设置为 AspectRatioFrameLayout.RESIZE_MODE_FILL
,这将使视频填满整个帧,同时保持正确的宽高比。
@Composable
fun VideoScreen() {
val context = LocalContext.current
// ... (other code)
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = {
val aspectRatioFrameLayout = AspectRatioFrameLayout(context)
aspectRatioFrameLayout.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
playerView.apply {
player = exoPlayer
useController = false
layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
}
aspectRatioFrameLayout.addView(playerView)
aspectRatioFrameLayout
}
)
// ... (other code)
}
调整
trackSeleccion
功能:
在您的
trackSeleccion
功能中,更改视频轨道后,您可以强制调整视频播放器的大小以确保其适合屏幕宽度。您可以使用 exoPlayer.videoScalingMode
来控制视频缩放行为。将其设置为 C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
可确保视频填充屏幕宽度,同时保持宽高比。
fun trackSeleccion(exoplayer: ExoPlayer, context: Context) {
// ... (existing code)
// Change video scaling mode to scale and fit the screen width
exoplayer.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
}
遵循@Hisham的推荐。
最后我用下一个代码解决了这个问题:
exoplayer.addListener(object : Player.Listener {
override fun onIsPlayingChanged(isPlayingValue: Boolean) {
isPlaying = isPlayingValue
}
override fun onTrackSelectionParametersChanged(parameters: TrackSelectionParameters) {
super.onTrackSelectionParametersChanged(parameters)
Log.e("VideoScreen", "onTrackSelectionParametersChanged")
val currentProgressTime = exoplayer.currentPosition
exoplayer.stop()
exoplayer.seekTo(currentProgressTime)
exoplayer.apply {
prepare()
playWhenReady = true
}
}
})