UxPlay投屏录制调试1
UxPlay 投屏录制与无显卡环境 GStreamer 管道调试笔记
1. 环境与硬件信息汇总
- 宿主机系统:Debian GNU/Linux 13 (trixie/testing),内核
6.12.96+deb13-amd64 - CPU 架构:Intel Celeron 2955U @ 1.40GHz (Haswell 架构,双核双线程,无 VA-API 硬件加速支持)
- 容器镜像:
docker.1ms.run/dachack/uxplay:latest - 基础依赖:GStreamer 1.0 工具链(
gst-inspect-1.0/gst-launch-1.0)
2. 核心问题定位
在无显示输出(无 X11/Wayland/DRM 硬件 Framebuffer)且缺乏 GPU 硬件编码器的底层服务器环境中,直接将 UxPlay 的视频流导向文件时,常见问题及根本原因如下:
2.1 产生 0 字节文件的原因
UxPlay 的 AppSrc 管道必须与下游元素(Element)完成 Caps(格式与参数)协商并建立正常的消费拉取逻辑。若下游管道缺乏有效的显示设备或完整的“编码+复用”链路,数据 Buffer 无法被正常消费,最终导致投屏文件大小持续为 0 字节。
2.2 触发 Internal Data Stream Error 并断开的原因
- 镜像组件缺失:默认 Minimal 镜像中缺失
x264enc、jpegenc、mp4mux等编码与封装组件。 - Caps 协商失败:
avimux等传统封装器对输入的帧率(framerate)、分辨率等参数要求严格,面对 AirPlay 的动态画面调整时容错率极低。
3. 容器内基础依赖补齐
为确保容器具备完整的编解码与录制能力,需要为容器环境补齐 GStreamer 扩展插件包:
apt-get update && apt-get install -yy \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
gstreamer1.0-libav \
gstreamer1.0-tools
4. GStreamer 工具链交互式排查
在容器内部,无需反复重启 Compose 服务,直接使用工具链测试插件可用性与管道逻辑。
4.1 检查已安装的编码器与复用器
# 查看所有可用视频编码器
gst-inspect-1.0 | grep -E "enc|encoder"
# 验证关键编码器组件
gst-inspect-1.0 x264enc # H.264 软件编码器
gst-inspect-1.0 jpegenc # MJPEG 编码器
# 查看所有可用复用器 (Muxers)
gst-inspect-1.0 | grep mux
# 验证关键复用器组件
gst-inspect-1.0 mp4mux # MP4 容器复用器
gst-inspect-1.0 matroskamux # MKV 容器复用器
4.2 管道模拟测试 (使用测试源)
在不依赖 iPhone 投屏的前提下,生成 100 帧测试数据验证“格式转换 -> 编码 -> 封装 -> 落盘”完整链路:
# 测试 H.264 + MP4 封装
gst-launch-1.0 -v videotestsrc num-buffers=100 ! videoconvert ! video/x-raw,format=I420 ! x264enc ! h264parse ! mp4mux ! filesink location=/recordings/test.mp4
# 测试 MJPEG + MKV 封装
gst-launch-1.0 -v videotestsrc num-buffers=100 ! videoconvert ! video/x-raw,format=I420 ! jpegenc ! matroskamux ! filesink location=/recordings/test.mkv
5. UxPlay 参数与录制管道配置
在命令行或 Compose 配置中,针对无显示输出服务器,建议使用以下 UxPlay 运行参数:
5.1 参数说明表
| 参数 | 含义与作用 |
|---|---|
-n Homeserver | 设置 AirPlay 广播服务显示名称 |
-nh | 禁用 Host 模式(Not Hosted) |
-p | 使用随机或特定网络端口绑定 |
-as fakesink | 音频流使用伪汇(丢弃音频或避免音频设备阻塞) |
-vs "..." | 自定义视频渲染/处理管道 |
speed-preset=ultrafast | x264 编码预设,大幅降低低性能 CPU(如 Celeron)占用 |
tune=zerolatency | 禁用 x264 编码缓存帧,确保实时流低延迟写入 |
fragment-duration=1000 | mp4mux 分片写入机制,避免异常断开导致 MP4 Header 损坏 |
5.2 推荐调试与录制管道命令
方案 A:H.264 + MP4 封装(标准录制方案)
适用于需要生成兼容性较好的 MP4 视频文件场景:
uxplay -n Homeserver -nh -p -as fakesink -vs "videoconvert ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency ! h264parse ! mp4mux fragment-duration=1000 ! filesink location=/recordings/iphone_stream.mp4"
方案 B:MJPEG + MKV 封装(高容错方案)
适用于 CPU 算力极低或 AirPlay 动态分辨率频繁切换的场景:
uxplay -n Homeserver -nh -p -as fakesink -vs "videoconvert ! video/x-raw,format=I420 ! jpegenc ! matroskamux ! filesink location=/recordings/iphone_stream.mkv"
方案 C:开启详细调试日志
若投屏仍发生中断,通过环境变量 GST_DEBUG 输出协商日志:
GST_DEBUG=3 uxplay -n Homeserver -nh -p -as fakesink -vs "videoconvert ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency ! h264parse ! mp4mux fragment-duration=1000 ! filesink location=/recordings/iphone_stream.mp4"
6:用临时交互容器进入调试
podman run --rm -it --network=host \
-v /dev/shm:/dev/shm \
-v /data/uxplay/recordings:/recordings \
-v /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket:ro \
docker.1ms.run/dachack/uxplay:latest sh
进入容器 Shell 后,我们依次测试 镜像内实际包含的通用 Sink/Encellers:
测试 1:测试 rawvideo + avi/matroska 封装(零额外编码器依赖)
直接把 Raw 视频写盘(无需 jpegenc 或 x264enc,只需要最基础的 rawvideo):
uxplay -nc -p -as fakesink -vs "videoconvert ! video/x-raw,format=I420 ! avimux ! filesink location=/recordings/iphone_stream.avi"
(敲回车后用 iPhone 尝试投屏,看是否还会抛出 GStreamer error)
测试 2:测试直接用 filesink 裸流或带 fdsink / multifilesink
如果镜像内连 avimux 都没有,测试 multifilesink 或 filesink:
uxplay -nc -p -as fakesink -vs "videoconvert ! filesink location=/recordings/iphone_raw.yuv"
测试 3:让 UxPlay 禁用内部解码,透传原始 AirPlay H.264(最推荐思路)
如果不想让 UxPlay 强行插入 decodebin ! videoconvert ! video/x-raw,我们需要加 -reset 或 -vs 配合 h264 模式。
请在容器 Shell 内运行下面这条直接提取 H.264 原始流的命令:
uxplay -nc -p -avdec -as fakesink -vs "filesink location=/recordings/iphone_stream.h264"
7. 持久化定制 Dockerfile
为防止容器重建后安装的 GStreamer 插件丢失,可编写如下 Dockerfile 进行镜像二次构建:
FROM docker.1ms.run/dachack/uxplay:latest
LABEL maintainer="sysadmin"
LABEL description="UxPlay minimal image with complete GStreamer plugins for video recording"
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -yy \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
gstreamer1.0-libav \
gstreamer1.0-tools \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["uxplay"]
8. 验证与总结流程
- 在容器内部执行依赖更新并安装 GStreamer 插件。
- 使用
gst-launch-1.0确认x264enc与mp4mux能够正常写出测试文件。 - 执行带
-vs "videoconvert ! ... ! mp4mux ... ! filesink"的 UxPlay 命令。 - 使用客户端进行 5 至 10 秒投屏测试,断开后检查
/recordings/目录下文件大小,确认已生成正常非 0 字节文件。