使用ExoPlayer(Jetpack)播放树莓派HLS流时应用崩溃求助
问题概述
使用PiCamera2在Raspberry Pi Zero 2W上生成HLS流媒体,该流可在VLC正常播放,但通过Jetpack Compose+Kotlin开发的Android应用调用ExoPlayer播放时,应用启动即崩溃。
Kotlin 代码示例
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { HlsPlayerTheme { val context = LocalContext.current val player = remember { ExoPlayer.Builder(context).build().apply { setMediaItem(MediaItem.fromUri("http://raspberrypi.local:8000/stream.m3u8")) prepare() play() } } DisposableEffect(Unit) { onDispose { player.release() } } AndroidView(factory = { PlayerView(it).apply { this.player = player } }) } } } }
Python 推流代码示例
from picamera2 import Picamera2 from picamera2.encoders import H264Encoder from picamera2.outputs import FileOutput import threading import subprocess picam2 = Picamera2() video_config = picam2.create_video_configuration(main={"size": (640, 480), "format": "RGB888"}) picam2.configure(video_config) encoder = H264Encoder(bitrate=1000000) output = FileOutput("stream.h264") def stream_hls(): subprocess.run([ "ffmpeg", "-re", "-i", "stream.h264", "-c:v", "copy", "-f", "hls", "-hls_time", "2", "-hls_list_size", "5", "-hls_flags", "delete_segments", "http://0.0.0.0:8000/stream.m3u8" ]) threading.Thread(target=stream_hls).start() picam2.start_recording(encoder, output) input("Press Enter to stop recording...") picam2.stop_recording()
崩溃日志示例
FATAL EXCEPTION: main Process: com.example.hlsplayer, PID: 12345 com.google.android.exoplayer2.ExoPlaybackException: Source error at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:655) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7872) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936) Caused by: com.google.android.exoplayer2.source.hls.HlsPlaylistException: HLS playlist has no media segments. at com.google.android.exoplayer2.source.hls.HlsMediaSource$PlaylistEventHandler.processPlaylist(HlsMediaSource.java:1872) at com.google.android.exoplayer2.source.hls.HlsMediaSource$PlaylistEventHandler.handleMessage(HlsMediaSource.java:1795) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) ... 4 more
问题分析及解决方案
1. HLS 播放列表格式不兼容
VLC对非标准HLS格式的容错性远高于ExoPlayer,当前推流生成的m3u8可能缺少ExoPlayer要求的关键标签:
- 缺少
#EXT-X-TARGETDURATION、#EXT-X-VERSION等标准标签 - 媒体片段使用相对路径,导致ExoPlayer解析失败
解决:修改ffmpeg转封装命令,生成符合标准的HLS播放列表:
ffmpeg -re -f h264 -i stream.h264 -c:v copy -f hls \ -hls_time 2 -hls_list_size 5 -hls_flags delete_segments \ -hls_version 7 -hls_base_url "http://raspberrypi.local:8000/" \ http://0.0.0.0:8000/stream.m3u8
2. Android 明文HTTP限制
Android 9及以上默认禁止明文HTTP请求,若使用http://协议访问流地址,需配置允许明文流量:
在AndroidManifest.xml的<application>标签中添加:
android:usesCleartextTraffic="true"
3. ExoPlayer 初始化时机错误
在Compose的remember块中直接调用prepare()和play(),可能因初始化过早导致线程阻塞或资源加载异常。应将播放操作移至LaunchedEffect中:
val player = remember { ExoPlayer.Builder(context).build().apply { setMediaItem(MediaItem.fromUri("http://raspberrypi.local:8000/stream.m3u8")) } } LaunchedEffect(player) { player.prepare() player.play() }
4. PiCamera2 编码输出格式问题
PiCamera2输出的裸H264流可能缺少必要元数据,导致ffmpeg转封装时无法生成正确的HLS片段。可在ffmpeg命令中明确指定输入格式为H264(即上述解决方案1中的-f h264参数)。
内容的提问来源于stack exchange,提问作者Andro Hide
相关产品推荐
相关产品推荐

