Android音视频开发:基于 Camera2 API 实现RTMP推流、RTSP服务与录像一体化方案

在移动端音视频领域,单纯的 RTMP 推流已不再是技术天花板。真正的挑战在于:如何在资源受限的 Android 设备上,构建一个既能"对外"进行 RTMP 直播、又能"对内"提供低延迟 RTSP 分发,同时还能完成"本地"高保真录像的『全功能媒体节点』?

面对这一需求,传统的串行处理模式往往会导致 CPU 负载过高、画面卡顿甚至 OOM。本文将深入源码,结合 MainActivity.java 及核心辅助类,剖析如何利用 Android Camera2 API 的高效采集能力,配合 大牛直播SDK (SmartPublisher) 的多路分发架构,打造一套集采集、编码、推流、服务、存储于一体的高可靠、低延迟音视频解决方案。

1. 整体架构设计

在提供的源码中,MainActivity 充当了控制中心的角色,而核心的音视频处理逻辑被封装在 LibPublisherWrapperSmartPublisherJniV2 中。整体数据流向如下:

  1. 数据采集Camera2Helper 负责调用 Camera2 API,通过 ImageReader 获取 YUV_420_888 格式的视频帧。

  2. 数据前处理LayerPostThread 负责处理视频层叠加(如时间戳、文字水印、图片Logo)。

  3. 核心编码与分发SmartPublisherJniV2 (Native层) 接收处理后的YUV数据,进行H.264/H.265编码,并同时分发给:

    • RTMP Publisher:推送到CDN或流媒体服务器。

    • RTSP Server:内置轻量级RTSP服务,供局域网内拉流。

    • Recorder:写入MP4文件进行本地存储。

这种架构的优势在于一次采集、一次编码、多路复用,极大地降低了CPU和内存的开销。

2. Camera2 API 的高效采集与YUV处理

Camera2 API 相比旧版 Camera API 提供了更强大的控制力,但也更为复杂。源码中的 Camera2Helper.java 封装了繁琐的 Session 创建和 Surface 配置。

关键点:YUV数据的获取与旋转

MainActivity 中,实现了 Camera2Listener 接口。核心数据回调在 onCameraImageData 方法中:

java 复制代码
@Override
public void onCameraImageData(Image image) {
    // 校验格式是否为 YUV_420_888
    if (image.getFormat() != ImageFormat.YUV_420_888) {
        return;
    }

    Image.Plane[] planes = image.getPlanes();
    // 获取 Y, U, V 平面的 Buffer 及 Stride 信息
    // ... (省略部分裁剪代码)

    // 处理设备旋转角度
    int rotation_degree = cameraImageRotationDegree_;
    if (rotation_degree < 0) return;

    // 将数据投递给 SDK
    for (LibPublisherWrapper i : publisher_array_)
        i.PostLayerImageYUV420888ByteBuffer(0, 0, 0,
            planes[0].getBuffer(), y_offset, planes[0].getRowStride(),
            planes[1].getBuffer(), u_offset, planes[1].getRowStride(),
            planes[2].getBuffer(), v_offset, planes[2].getRowStride(), planes[1].getPixelStride(),
            w, h, 0, 0,
            scale_w, scale_h, scale_filter_mode, rotation_degree);
}

技术解读:

  • 直接传递 ByteBuffer :代码直接将 Image.Plane 的 ByteBuffer 传递给 Native 层(PostLayerImageYUV420888ByteBuffer),避免了在 Java 层进行大量的数据拷贝,这是降低延迟和 CPU 占用的关键。

  • 处理 Stride:Camera2 输出的数据通常包含 Padding (Stride > Width),直接处理容易造成花屏。大牛直播SDK 提供了带 Stride 参数的接口,完美兼容了不同机型的 Camera2 输出。

  • publisher_array_ :这里设计了一个数组,包含 stream_publisher_snap_shot_publisher_,意味着同一份 YUV 数据被同时用于推流/录像和快照处理。

安卓轻量级RTSP服务采集摄像头,PC端到安卓拉取RTSP流

3. 并发核心:LibPublisherWrapper 的设计

为了保证多线程环境下的稳定性(UI线程操作开关,采集线程投递数据,编码线程处理数据),源码封装了 LibPublisherWrapper 类。它通过 ReentrantReadWriteLock 读写锁来保证 SDK 句柄的安全访问。

java 复制代码
public class LibPublisherWrapper implements AutoCloseable {
    private final ReadWriteLock rw_lock_ = new ReentrantReadWriteLock(true);
    // ...
    
    public boolean PostLayerImageYUV420888ByteBuffer(...) {
        if (!check_native_handle()) return false;
        if (!read_lock_.tryLock()) return false; // 尝试获取读锁,避免阻塞采集线程

        try {
            return OK == lib_publisher_.PostLayerImageYUV420888ByteBuffer(get(), ...);
        } finally {
            read_lock_.unlock();
        }
    }
}

这种 Wrapper 模式在音视频开发中非常推荐,能有效防止在 SDK 销毁过程中(如切换摄像头或关闭 Activity)因数据投递造成的 Crash。

4. 特色功能解析

4.1 内置轻量级 RTSP 服务 (Lightweight RTSP Service)

这是大牛直播SDK的一大特色。传统的推流端通常只负责推流,拉流需要依赖 Nginx 或 SRS 等服务器。但该 SDK 允许 Android 设备变身为 RTSP 服务器。

MainActivity 中:

java 复制代码
// 初始化 RTSP Server 上下文
LibPublisherWrapper.RTSPServer.initialize_sdk(libPublisher, context_);

// 启动服务
int port = 8554;
LibPublisherWrapper.RTSPServer.Handle server_handle = 
    LibPublisherWrapper.RTSPServer.create_and_start_server(libPublisher, port, user_name, password);
    
// 将 RTSP Server 关联到 Publisher
stream_publisher_.AddRtspStreamServer(rtsp_server_.get_native());

应用场景:

  • 内网低延迟监控 :同一个局域网内的 PC 或其他手机可以直接通过 rtsp://device_ip:8554/stream1 拉取低延迟流,无需经过云端 CDN,延迟可控制在毫秒级。

  • 教学/会议:讲师端作为 RTSP Server,学生端直接拉流。

4.2 动态水印与图层叠加 (LayerPostThread)

源码中包含一个 LayerPostThread.java,它展示了 SDK 强大的视频层叠加能力。

  • 动态时间戳 :通过 makeTimestampString() 生成当前时间 Bitmap。

  • 文字/图片水印:支持添加 Logo 或文字。

  • 矩形框绘制:演示了动态绘制 RGB 图层。

这些图层并不是在 Java 层通过 Canvas 绘制到视频 Bitmap 上(那样效率太低),而是生成 Overlay 数据后,通过 PostLayerBitmapPostLayerImageRGBA8888ByteBuffer 传递给底层,由 GPU 或 Native 高效混合。

java 复制代码
// LayerPostThread.java 核心循环
private void on_run() {
    while(!is_exit()) {
        // 更新时间戳图层
        post_timestamp_layer(...);
        // 更新文字图层
        postText1Layer(...);
        // ...
        sleep_ms(update_interval);
    }
}

4.3 实时录像与断网重连

  • 录像stream_publisher_.StartRecorder() 即可开启本地录像。SDK 内部处理了音视频同步和 MP4 封装,且支持设置文件分片大小(SetRecorderFileMaxSize)。

  • 异常处理EventHandlerPublisherV2 监听 SDK 回调。例如 EVENT_DANIULIVE_ERC_PUBLISHER_DISCONNECTED 事件触发时,应用层可以进行 UI 提示或自动重连逻辑。

5. 性能优化总结

通过分析这份代码,我们可以总结出几个关键的性能优化点:

  1. 零拷贝设计:Camera2 的 DirectByteBuffer 直接送入 Native,避免 Java Heap 内存抖动。

  2. 硬编码优先initialize_publisher 方法中优先尝试开启 H.264/H.265 硬编码 (SetSmartPublisherVideoHWEncoder),大幅降低 CPU 占用。

  3. 线程模型:采集、UI、数据投递、编码分发分离,利用读写锁保证线程安全且不阻塞高频的视频采集回调。

结语:从"功能实现"到"工业级交付"的跨越

纵观这份 Demo 源码,我们看到的不仅仅是一个功能的堆砌,而是一套经得起生产环境考验的 Android 音视频架构范本。它展示了大牛直播 SDK 如何在复杂的 Android 碎片化生态中,提供一种"确定性"的解决方案:

  1. 架构的鲁棒性设计 源码中 LibPublisherWrapper 的封装不仅仅是为了代码整洁,更体现了生命周期管理 的智慧。通过引入 ReentrantReadWriteLock(读写锁)和 WeakReference(弱引用),这套架构巧妙地解决了音视频开发中最为棘手的"高并发数据竞争"与"对象引用泄漏"问题。它确保了在 Activity 销毁、摄像头切换或网络抖动等极端情况下,底层 Native 资源依然能被安全、有序地释放,这是从"Demo"走向"商用产品"的关键一步。

  2. "一次采集,多端分发"的效能极限 在移动端,算力和功耗是永远的痛点。本方案通过 Camera2Helper 实现了一次 YUV 数据采集,却能同时支撑 RTMP 远端直播RTSP 局域网分发 以及 MP4 本地存证 三大业务流。这种"单源多汇"的 pipeline 设计,最大程度地复用了编码前的 YUV 数据和编码后的 H.264/H.265 数据,避免了重复的内存拷贝与色彩空间转换,将 CPU 和内存的开销压到了极致。

  3. 从"推流端"到"边缘计算节点"的角色蜕变 最令人印象深刻的,是 SDK 内置的 轻量级 RTSP 服务。这一功能打破了传统推流端只能"单向上传"的刻板印象,让每一台 Android 设备都能瞬间变身为一台独立的 IP Camera 或流媒体服务器。这意味着在无公网、无云服务器的内网环境中(如车载监控、应急救援、无人机图传),该方案依然具备独立组网和视频分发的能力,为"边缘计算"和"物联网"场景提供了无限的想象空间。

对于广大音视频开发者而言,不仅是一把打开 RTMP/RTSP 协议大门的钥匙,更是一份关于高性能、低延迟、高稳定性音视频应用开发的最佳实践指南。

📎 CSDN官方博客:音视频牛哥-CSDN博客

相关推荐
2501_937145411 小时前
2025 IPTV 源码优化版:稳定兼容 + 智能升级
android·源码·电视盒子·源代码管理·机顶盒
Nerve5 小时前
FluxImageLoader : 基于Coil3封装的 Android 图片加载库,旨在提供简单、高效且功能丰富的图片加载解决方案
android·android jetpack
元气满满-樱5 小时前
MySQL基础管理
android·mysql·adb
summerkissyou19875 小时前
android13-audio-AudioTrack-写数据流程
android·音视频
卢卡上学6 小时前
【AI工具】Coze智能体工作流:5分钟制作10个10w+治愈视频,无需拍摄剪辑
人工智能·音视频·ai视频·ai智能体
董三毛8 小时前
Kotlin Coroutine 底层实现原理
android
zimoyin8 小时前
WSL音频转发配置流程:WSL2/WSL1全适配
linux·音视频·wsl·虚拟机·ekho
L108708 小时前
AutoJsPro GoogleMaterial3 M3组件使用示例
android
枣把儿9 小时前
「zotepad」用Gemini3pro写出一个高效写作和发文的记事本应用
android·前端·nuxt.js