webrtc服务端如何录像

1 前言

当前基于sfu服务的webrtc通信模式下,服务端录像和服务端旁路引流,是后端服务的一个重要需求。

本文介绍webrtc服务端如何进行录像,文章通过几部分进行讨论:

  • mediasoup sfu的旁路录像

  • srs webrtc的旁路录像

  • webrtc录像的格式讨论

2 mediasoup webrtc的旁路录像

基本的架构图如下:

如上图,这里主要讨论,如何建立一个mediasoup mcu服务,从sfu中拉取用户A和用户B的音视频流,并且录像后,上传到对应的文件存储系统(如阿里云,腾讯云等的存储系统)。

这里介绍开源cpp_streamer通过mediasoup webrtc拉流组件,拉取音频(opus)+视频流(H264 baseline),并存储成mpegts格式。

cpp_streamer开源自己构造一个简单的PeerConnection类,实现:

  • sdp 信息解析

  • stun 协商

  • dtls 协商

  • rtp/rtcp报文传输

  • 自定义快速jitterbuffer的实现

  • H264 in rtp的组装/解封装

通过以上的功能,构造mspull组件,也就是mediasoup pull拉流组件,实现webrtc的拉流,过内部jitterbuffer组装后,输出H264和opus。

这里录像采用的格式是mpegts,选取的原因是mpegts支持opus音频编码的封装。

2.1 代码实现

基于cpp_streamer的代码实现,其实比较简单,只需要3个组件,并且把他们联结在一起:

  • mspull: mediasoup拉流组件,把对应的音视频流拉取过来;

  • timesync: 音视频时间同步组件,因为webrtc的音视频流,rtp中的时间戳是完全不同步的。timesync组件帮助实现对音视频时间戳进行更新,让其同步;

  • mpegtsmux: mpegts封装组件,将拉取的音视频流(H264+Opus)封装成mpegts格式;

demo代码在: https://github.com/runner365/cpp_streamer/blob/v1.1/src/tools/mediasoup_pull_demo.cpp

cpp 复制代码
class MsPull2MpegtsStreamerMgr: public StreamerReport, public CppStreamerInterface
{
public:
    //src_url: 为mediasoup sfu对应音视频的信息地址
    // "https://xxxxx.com?roomId=100&userId=1000&vpid=xxxxx&apid=xxxx" 
    // 其中roomId: 房间id; vpid是video的producerId; apid是audio的producerId
    //output_ts: 要存的输出文件
    MsPull2MpegtsStreamerMgr(const std::string& src_url, 
            const std::string& output_ts):ts_file_(output_ts)
                                           , src_url_(src_url)
    {
    }
    virtual ~MsPull2MpegtsStreamerMgr()
    {
        mspull_ready_ = false;
    }

    int MakeStreamers(uv_loop_t* loop_handle) {
        loop_ = loop_handle;

        //构造一个mspull组件,拉去mediasoup sfu的音视频流
        mspull_streamer_ = CppStreamerFactory::MakeStreamer("mspull");
        mspull_streamer_->SetLogger(logger_);
        mspull_streamer_->SetReporter(this);

        //构造一个mpegts封装组件,将音视频流封装成mpegts格式
        ts_streamer_ = CppStreamerFactory::MakeStreamer("mpegtsmux");
        ts_streamer_->SetLogger(logger_);
        ts_streamer_->SetReporter(this);
        
        //构造一个timesync组件,实现音频与视频时间戳的同步
        timesync_streamer_ = CppStreamerFactory::MakeStreamer("timesync");
        timesync_streamer_->SetLogger(logger_);
        timesync_streamer_->SetReporter(this);

        //将mspull组件,timersync组件,mpegtsmux组件联结在一起
        // mspull--->timesync--->mpegtsmux--->this(存储mpegts成文件)
        mspull_streamer_->AddSinker(timesync_streamer_);
        timesync_streamer_->AddSinker(ts_streamer_);
        ts_streamer_->AddSinker(this);

        return 0;

    }
    //接收mpegtsmux输出的mpegt数据,存成mpegts的文件。
    virtual int SourceData(Media_Packet_Ptr pkt_ptr) override {
        FILE* file_p = fopen(ts_file_.c_str(), "ab+");
        if (file_p) {
            fwrite(pkt_ptr->buffer_ptr_->Data(), 1, pkt_ptr->buffer_ptr_->DataLen(), file_p);
            fclose(file_p);
        }

        return 0;
    }
}

3 Srs的旁路录像

Srs是强大的开源多媒体流服务器,支持webrtc sfu功能,并且还支持rtc2rtmp的功能(opus转码成aac),opus转码成aac对cpu的消耗不小,一个转码大概消耗2%左右的cpu。

如果用户接入路数不多,不考虑性能问题,也直接考虑用Srs配置rtc2rtmp,配置hls的录像,直接用srs实现录像功能。

本文主要考虑性能问题,介绍旁路录像的方案,也就是启动一个服务,从Srs拉取webrtc的音视频流,并保存成mpegts文件。

Srs支持Whep标准的webrtc拉流接口,这里cpp_streamer实现对应的whep拉流组件,对其拉流获取音视频,并通过mpegtsmux组件实现mpegts对音视频流(H264+Opus)的封装。

3.1 代码实现

基于cpp_streamer的代码实现,其实比较简单,只需要3个组件,并且把他们联结在一起:

  • whep: whep拉流组件,把对应srs webrtc的音视频流拉取过来;

  • mpegtsmux: mpegts封装组件,将拉取的音视频流(H264+Opus)封装成mpegts格式;

demo代码地址:

https://github.com/runner365/cpp_streamer/blob/v1.1/src/tools/whep_srs_demo.cpp

cpp 复制代码
class Whep2MpegtsStreamerMgr: public StreamerReport, public CppStreamerInterface
{
public:
    //src_url: srs的whep地址
    // eg: "http://10.0.8.5:1985/rtc/v1/whip-play/?app=live&stream=1000"
    //output_ts: 录像文件,mpegts格式
    Whep2MpegtsStreamerMgr(const std::string& src_url, 
            const std::string& output_ts):ts_file_(output_ts)
                                           , src_url_(src_url)
    {
    }
    virtual ~Whep2MpegtsStreamerMgr()
    {
        whep_ready_ = false;
    }

    int MakeStreamers(uv_loop_t* loop_handle) {
        loop_ = loop_handle;
        //whep组件:从srs拉流webrtc音视频流
        whep_streamer_ = CppStreamerFactory::MakeStreamer("whep");
        whep_streamer_->SetLogger(logger_);
        whep_streamer_->SetReporter(this);
        //mpgetsmux组件: 把H264+Opus保存为mpegts格式
        ts_streamer_ = CppStreamerFactory::MakeStreamer("mpegtsmux");
        ts_streamer_->SetLogger(logger_);
        ts_streamer_->SetReporter(this);

        //联结whep组件和mpegtsmux组件,
        // whep-->mpegtsmux-->this(保存mpegts文件)
        whep_streamer_->AddSinker(ts_streamer_);
        ts_streamer_->AddSinker(this);

        return 0;
    }
    
    //保存mpegts文件
    virtual int SourceData(Media_Packet_Ptr pkt_ptr) override {
        FILE* file_p = fopen(ts_file_.c_str(), "ab+");
        if (file_p) {
            fwrite(pkt_ptr->buffer_ptr_->Data(), 1, pkt_ptr->buffer_ptr_->DataLen(), file_p);
            fclose(file_p);
        }

        return 0;
    }
}

4 录像格式讨论

本文的录像demo都采用mpegts,而且保存的编码格式都是H264+Opus.

并没有支持视频编码: Vp8/Vp9/Av1。

这里讨论如果做兼容各种编码的录像,在不转码的情况下(视频转码非常消耗服务器性能),采用什么封装格式比较推荐。

当前支持codec类型较多的封装格式有: Mp4, Mkv。

都能支持H264/H265/Vp8/Vp9/Av1。

4.1 Mp4(fMp4)

对于流媒体格式,Mp4不能很好的支持动态连续的录像,不过fMp4格式是能支持动态的持续的添加音视频流。

今后的文章会专门讨论fMp4用了哪些mp4 box来支持动态持续添加音视频流,专门做一期详解。

4.2 Mkv

MKV(Matroska Video File)是一种Matroska媒体格式的多媒体封装格式(Multimedia Container Format,简称MCF)。Matroska来自于俄语,影射俄罗斯娃娃,就是下面这个啦,表示一层包着另外一层。

可以支持动态持续添加音视频流,并且支持H264/H265/Vp8/Vp9/Av1。

今后的文章会专门介绍Mkv的格式封装,MKV采用可扩展二进制元语言EBML(Extensible Binary Meta Language)来描述其文件结构,EBML用元素(Elements)来描述EBML文档。

今后cpp_streamer会加入,mp4(fmp4), mkv等流行封装的组件。

后面会专门有后续博文介绍:

  • mp4/fmp4格式详解

  • mkv格式详解

相关推荐
runner365.git1 小时前
如何使用RTCPilot--跨平台WebRTC开源服务
webrtc·音视频开发
runner365.git7 小时前
RTC实现VoiceAgent(二)
大模型·webrtc·实时音视频·voiceagent
runner365.git1 天前
WebRTC实现VoiceAgent智能体
webrtc
runner365.git1 天前
RTCPilot的信令流程
webrtc·音视频开发
runner365.git1 天前
如何使用RTCPilot配置一个集群RTC服务
webrtc·实时音视频·音视频开发
深念Y2 天前
从WebSocket到WebRTC,豆包级实时语音交互背后的技术演进
websocket·网络协议·实时互动·webrtc·语音识别·实时音视频
AI视觉网奇4 天前
webrtc 硬编码
ffmpeg·webrtc
REDcker4 天前
WebRTC 接收端音频流畅低延迟播放:原理与源码对照(NetEQ / Opus)
音视频·webrtc
SUNNY_SHUN5 天前
LiveKit Agents:基于WebRTC的实时语音视频AI Agent框架(9.9k Star)
人工智能·github·webrtc
Pending6 天前
从 400 行到 40 行:一个 WebRTC 播放器的简洁实现之道
开源·webrtc·前端工程化