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 以内,适合嵌入式监控场景。

相关推荐
..过云雨2 小时前
13.【Linux系统编程】从ELF格式深入理解动静态库
linux·c语言·c++·后端
一名机电研究生2 小时前
华为、阿里巴巴、字节跳动 100+ Linux面试问题总结(一)
linux·华为·面试
讨厌下雨的天空3 小时前
环境变量与地址
linux
阿巴~阿巴~3 小时前
深入解析UDP服务器核心开发机制
linux·服务器·网络协议·网络编程·udp服务器·recvfrom函数
wa的一声哭了3 小时前
Linux服务器配置ssh免密登陆多台服务器、服务器别名配置
linux·运维·服务器·网络·arm开发·python·ssh
beijingliushao3 小时前
93-MongoDB-Linux
linux·数据库·mongodb
YongCheng_Liang4 小时前
openEuler 22.03 LTS 部署 ELK(Elasticsearch+Logstash+Kibana)完整教程
linux·运维·elk·elasticsearch
go_bai4 小时前
Linux-线程
linux·开发语言·c++·经验分享·笔记
清浅儿4 小时前
Linux权限知识点
linux·运维·服务器