Jetpack Compose中ExoPlayer在Android11及以下仅播音频无画面问题
问题:Android 11及以下版本播放视频仅输出音频,画面呈白色
我使用ExoPlayer Media3库播放视频,先将视频下载保存至本地存储(路径:/storage/emulated/0/Android/data/packagename/files/video/BigBuckBunny.mp4)。播放时,Android 12及以上版本正常,但Android 11及以下版本仅能播放音频,视频画面呈白色。
我尝试了自定义的VideoPlayerScreenNew组件,也试过系统默认的VideoView,两种方式均出现相同问题;同时直接播放网络视频链接(https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4)也存在该问题。
相关代码如下:
VideoPlayerScreenNew.kt
import android.net.Uri import android.widget.Toast import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.viewinterop.AndroidView import androidx.media3.common.MediaItem import androidx.media3.common.PlaybackException import androidx.media3.common.Player import androidx.media3.common.Player.Listener import androidx.media3.common.Player.STATE_BUFFERING import androidx.media3.common.util.Log import androidx.media3.common.util.UnstableApi import androidx.media3.datasource.DefaultDataSource import androidx.media3.datasource.DefaultHttpDataSource import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.dash.DashMediaSource import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.source.MediaSource import androidx.media3.exoplayer.source.ProgressiveMediaSource import androidx.media3.ui.PlayerView import app.mashmari.miniplayer.ui.theme.purpleTheme import app.mashmari.miniplayer.utilitys.CustomCircularProgressBar @androidx.annotation.OptIn(UnstableApi::class) @Composable fun VideoPlayerScreenNew( videoUrl: String?, onBackPressed: () -> Unit, onError: () -> Unit = {}, ) { Log.e("TAG", "VideoPlayerScreenNew: video link : $videoUrl") val isShowLoader = remember { mutableStateOf(true) } val context = LocalContext.current var exoPlayer by remember { mutableStateOf<ExoPlayer?>(null) } BackHandler(onBack = onBackPressed) // Create the ExoPlayer only once DisposableEffect(Unit) { android.util.Log.e("TAG", "VideoPlayerScreenNew: DisposableEffect") val player = ExoPlayer.Builder(context).build().also { exoPlayer = it } exoPlayer?.repeatMode = Player.REPEAT_MODE_ONE // player.addAnalyticsListener(EventLogger()) exoPlayer?.addListener(object : Listener { override fun onPlaybackStateChanged(playbackState: Int) { super.onPlaybackStateChanged(playbackState) if (playbackState == STATE_BUFFERING) { // Log.e("TAG", "onPlaybackStateChanged: isbuffering") isShowLoader.value = true } else { // Log.e("TAG", "onPlaybackStateChanged: isbuffering not $playbackState ") isShowLoader.value = false } } override fun onPlayerError(error: PlaybackException) { super.onPlayerError(error) Log.e("TAG", "VideoPlayerScreenNew onPlayerError: called ${error.errorCode}") Toast.makeText( context, "Video playback issue ${error.message}", Toast.LENGTH_SHORT ).show() onError() } }) onDispose { player.release() } } // Update the media source when videoUrl changes LaunchedEffect(videoUrl) { android.util.Log.e("TAG", "VideoPlayerScreenNew: LaunchedEffect$videoUrl") exoPlayer?.let { player -> val isOnline: Boolean = videoUrl?.startsWith("http") == true val url = videoUrl ?: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" val mediaSourceFactory = when { url.contains(".m3u8") -> HlsMediaSource.Factory(DefaultHttpDataSource.Factory()) url.contains(".mpd") -> DashMediaSource.Factory(DefaultHttpDataSource.Factory()) isOnline -> ProgressiveMediaSource.Factory(DefaultHttpDataSource.Factory()) else -> ProgressiveMediaSource.Factory(DefaultDataSource.Factory(context)) } val mediaSource: MediaSource = mediaSourceFactory.createMediaSource(MediaItem.fromUri(Uri.parse(url))) player.setMediaSource(mediaSource) player.prepare() player.playWhenReady = true } } Box(modifier = Modifier.fillMaxSize()) { android.util.Log.e("TAG", "VideoPlayerScreenNew: Box called") exoPlayer?.let { player -> AndroidView( factory = { PlayerView(context).apply { useController = false hideController() this.player = player } }, modifier = Modifier.fillMaxSize() ) } CustomCircularProgressBar( isShowLoader = isShowLoader, progressColor = purpleTheme ) } }
VideoPlayerScreenNew调用代码
composable<VideoPlay> { val allVideo = getAllVideoLink() val file = appUtils.getLocalFileFromUri(allVideo.get(1)) // VideoPlayer(file.absolutePath) Log.e("TAG", "VideoPlayerScreenNew: App: VideoPlay called") VideoPlayerScreenNew(videoUrl = file.absolutePath, onBackPressed = { navController.popBackStack() }, onError = { navController.popBackStack() }) }
VideoPlayer.kt
@Composable fun VideoPlayer(videoUrl: String) { AndroidView(factory = { context -> VideoView(context).apply { // Set up MediaController for playback controls val mediaController = MediaController(context) mediaController.setAnchorView(this) setMediaController(mediaController) // Set the video URL setVideoPath(videoUrl) // Start playing the video setOnPreparedListener { start() } } }, update = { videoView -> // Update logic if needed, e.g., change video source }) }
内容的提问来源于stack exchange,提问作者Vishal Bhimporwala
相关产品推荐
相关产品推荐

