You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:55:16