RV1106 通过 4G 网络基于 libdatachannel 实现 WebRTC 实时视频传输”

以下是对 "RV1106 通过 4G 网络基于 libdatachannel 实现 WebRTC 实时视频传输" 的完整总结,包含核心方案、关键步骤及源码实现:

一、核心方案概述

为解决 RV1106 在 4G 网络下的实时视频传输需求(客户端可直接观看),采用libdatachannel(轻量级 WebRTC 库)替代原生 WebRTC,结合 STUN/TURN 服务器解决 NAT 穿透问题,流程如下:

  1. 硬件层:RV1106 通过 V4L2 采集摄像头数据,利用硬件编码器(H.264)压缩。
  2. 传输层:基于 libdatachannel 建立 WebRTC 连接,通过 STUN 获取公网地址、TURN 中继解决 4G NAT 穿透。
  3. 客户端:浏览器 / APP 用原生 WebRTC API 接收视频流,实时播放。

二、关键步骤与实现

1. 环境准备
  • 硬件:RV1106 开发板(带 MIPI 摄像头)、4G 模块(如 EC20)、SIM 卡。
  • 交叉编译工具链 :RV1106 官方工具链(arm-rockchip830-linux-uclibcgnueabihf-*)。
  • 依赖库:交叉编译 OpenSSL(加密)和 libdatachannel(WebRTC 核心)。
2. 交叉编译依赖库
(1)交叉编译 OpenSSL

bash

复制代码
# 下载源码
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar -zxf openssl-1.1.1w.tar.gz && cd openssl-1.1.1w

# 配置交叉编译(安装到/opt/openssl-arm)
./Configure linux-armv4 no-asm shared --prefix=/opt/openssl-arm \
--cross-compile-prefix=arm-rockchip830-linux-uclibcgnueabihf-

# 编译安装
make -j4 && sudo make install
(2)交叉编译 libdatachannel

bash

复制代码
# 下载源码
git clone https://github.com/paullouisageneau/libdatachannel.git
cd libdatachannel && git submodule update --init --recursive

# 创建交叉编译配置(toolchain.cmake)
cat > toolchain.cmake << EOF
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-rockchip830-linux-uclibcgnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-rockchip830-linux-uclibcgnueabihf-g++)
set(OPENSSL_ROOT_DIR /opt/openssl-arm)
EOF

# 编译安装(到/opt/libdatachannel-arm)
mkdir build-arm && cd build-arm
cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
-DCMAKE_INSTALL_PREFIX=/opt/libdatachannel-arm \
-DUSE_GNUTLS=OFF -DBUILD_SHARED_LIBS=OFF
make -j4 && sudo make install
3. RV1106 端核心代码(视频采集 + WebRTC 推流)

cpp

运行

复制代码
#include <rtc/rtc.hpp>
#include <thread>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include "rk_mpi.h"  // 瑞芯微硬件编码接口

// 全局变量
int camera_fd;
MppCtx encoder;
std::unique_ptr<rtc::PeerConnection> peerConnection;
std::unique_ptr<rtc::Track> videoTrack;

// 1. 初始化摄像头(V4L2)
bool initCamera(const char* dev = "/dev/video0") {
    camera_fd = open(dev, O_RDWR);
    if (camera_fd < 0) return false;

    // 配置摄像头(1280x720,YUV420格式)
    struct v4l2_format fmt;
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = 1280;
    fmt.fmt.pix.height = 720;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
    return ioctl(camera_fd, VIDIOC_S_FMT, &fmt) == 0;
}

// 2. 初始化硬件编码器(H.264)
bool initEncoder() {
    RKMEDIA_Init();
    MppCtx ctx;
    mpp_create(&ctx, MPP_CTX_ENC, MPP_CODEC_ID_H264);
    encoder = ctx;
    return encoder != nullptr;
}

// 3. 视频采集与推流线程
void videoThreadFunc() {
    struct v4l2_buffer buf;
    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    while (true) {
        // 采集YUV帧
        ioctl(camera_fd, VIDIOC_DQBUF, &buf);  // 出队缓冲区
        void* yuv_data = mmap(nullptr, buf.length, PROT_READ, MAP_SHARED, camera_fd, buf.m.offset);

        // 硬件编码为H.264 NAL单元
        MppPacket packet;
        mpp_encode(encoder, yuv_data, buf.length, &packet);  // 编码

        // 封装为RTP包并通过libdatachannel发送
        rtc::Buffer nal((uint8_t*)packet->data, packet->size);
        videoTrack->send(nal, rtc::MediaPacketFlag::KeyFrame);  // 发送关键帧(按需切换)

        // 清理
        munmap(yuv_data, buf.length);
        ioctl(camera_fd, VIDIOC_QBUF, &buf);  // 入队缓冲区
        usleep(40000);  // 25fps
    }
}

// 4. 初始化WebRTC(NAT穿透配置)
void initWebRTC() {
    // 配置STUN/TURN服务器(NAT穿透核心)
    rtc::Configuration config;
    config.iceServers = {
        "stun:stun.aliyun.com:3478",  // 阿里云STUN(获取公网地址)
        "turn:123.45.67.89:3478?username=rv1106&password=123456"  // 自建TURN(中继)
    };
    config.iceTransports = rtc::IceTransportPolicy::All;  // 允许所有传输方式
    peerConnection = rtc::make_unique<rtc::PeerConnection>(config);

    // 创建视频轨道
    videoTrack = peerConnection->addTrack(rtc::MediaKind::Video);

    // 生成SDP Offer并发送给信令服务器
    peerConnection->onLocalDescription([](const rtc::Description& desc) {
        std::string offer = desc.sdp();
        // 发送offer到信令服务器(例如通过HTTP/MQTT)
        sendToSignalingServer(offer);
    });

    // 接收客户端的SDP Answer
    onSignalingMessage([&](const std::string& answer) {
        peerConnection->setRemoteDescription(rtc::Description(answer, "answer"));
    });

    // 监听ICE连接状态
    peerConnection->onStateChange([](rtc::PeerConnection::State state) {
        if (state == rtc::PeerConnection::State::Connected) {
            printf("P2P连接成功!\n");
        }
    });

    // 启用ICE续活(维持NAT映射)
    peerConnection->setKeepAliveInterval(30);  // 30秒心跳
}

int main() {
    if (!initCamera() || !initEncoder()) {
        printf("摄像头或编码器初始化失败!\n");
        return -1;
    }
    initWebRTC();

    // 启动视频推流线程
    std::thread videoThread(videoThreadFunc);
    videoThread.join();

    return 0;
}
4. 客户端代码(浏览器观看)

html

预览

复制代码
<video id="remoteVideo" autoplay playsinline width="1280" height="720"></video>
<script>
// 初始化WebRTC连接
const pc = new RTCPeerConnection({
    iceServers: [
        { urls: "stun:stun.aliyun.com:3478" },
        { urls: "turn:123.45.67.89:3478", username: "rv1106", credential: "123456" }
    ]
});

// 接收视频流并播放
pc.ontrack = (e) => {
    document.getElementById("remoteVideo").srcObject = e.streams[0];
};

// 从信令服务器获取RV1106的SDP Offer
fetch("/get-offer").then(async (res) => {
    const offer = await res.json();
    await pc.setRemoteDescription(new RTCSessionDescription(offer));
    
    // 生成Answer并发送给RV1106
    const answer = await pc.createAnswer();
    await pc.setLocalDescription(answer);
    fetch("/send-answer", {
        method: "POST",
        body: JSON.stringify(answer)
    });
});
</script>
5. NAT 穿透关键配置说明
  • STUN 服务器 :用于获取 RV1106 的公网 IP 和端口(如阿里云stun.aliyun.com:3478),解决简单 NAT 穿透。
  • TURN 服务器 :自建coturn服务器(部署在公网云服务器),当 STUN 失败时中继数据,支持 4G 对称型 NAT。
  • ICE 续活 :通过setKeepAliveInterval(30)定期发送心跳,维持 NAT 映射不失效。

三、编译与运行

  1. 编译 RV1106 程序

    bash

    复制代码
    arm-rockchip830-linux-uclibcgnueabihf-g++ main.cpp -o webrtc_streamer \
    -I/opt/libdatachannel-arm/include -I/opt/openssl-arm/include \
    -L/opt/libdatachannel-arm/lib -L/opt/openssl-arm/lib \
    -ldatachannel -lssl -lcrypto -lpthread -lm
  2. 推送至 RV1106scp webrtc_streamer root@192.168.1.100:/usr/bin/

  3. 运行./webrtc_streamer,客户端打开 HTML 页面即可观看。

四、问题排查

  • NAT 穿透失败 :检查 STUN/TURN 服务器配置,用stunclientturnutils工具验证服务器可用性。
  • 视频卡顿:降低码率(如 1Mbps)、调整帧率(15fps),确保 4G 带宽适配。
  • 连接断连:启用 ICE 续活,检查 4G 信号强度,避免 NAT 映射超时。

通过以上方案,可在 RV1106 上实现轻量级 WebRTC 视频传输,客户端实时观看延迟控制在 300ms 以内,适合嵌入式监控场景。

相关推荐
摇滚侠24 分钟前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush41 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5201 小时前
Linux 11 动态监控指令top
linux
不会C语言的男孩2 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
古城小栈3 小时前
Unix 与 Linux 异同小叙
linux·服务器·unix
凡人叶枫4 小时前
Effective C++ 条款42:了解 typename 的双重意义
java·linux·服务器·c++
2601_961875244 小时前
决战申论100题2026|最新|范文
linux·容器·centos·debian·ssh·fabric·vagrant
java_cj4 小时前
深入kube-apiserver认证机制:从Bearer Token到mTLS的完整认证链解析
linux·运维·服务器·云原生·容器·kubernetes
lsyeei4 小时前
linux 系统目录详解
linux·运维·服务器
森G4 小时前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt