Media3 视频轨道更改问题:视频出现在屏幕的一部分中

问题描述 投票:0回答:2

此代码允许我播放视频,并且使用设置按钮(齿轮图标),我可以打开视频轨道选择器对话框,但是当我更改大小时,播放器会卡在屏幕上的循环中,并且视频大小调整为屏幕的一部分。

这是 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。

android kotlin exoplayer android-media3
2个回答
0
投票

为了实现在更改分辨率时视频保持屏幕宽度的所需行为,您可以利用 ExoPlayer 的宽高比处理功能。您可能还需要调整布局和配置。 以下是实现此目标的一些建议:

  1. 调整

    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)
    }
    
  2. 调整

    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
    }
    

0
投票

遵循@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
            }

        }

    })
© www.soinside.com 2019 - 2024. All rights reserved.