基于Live555实现RTSP服务器来推送H264实时码流

本文描述了一个使用liveMedia库创建的单播rtsp服务器,用于推送实时的H264视频码流。代码将编码后的H264数据放入缓冲队列,然后从队列中读取数据进行推流。H264LiveServerMediaSession类处理流媒体会话,包括创建新的流源和RTPSink,而H264VideoStreamSource类作为自定义的数据源,负责从缓冲队列获取并发送帧数据。
摘要由CSDN通过智能技术生成

实现了一个单播的rtsp服务器来推送实时的h264码流,参考了官方的testProgs目录下的testOnDemandRTSPServer例程和liveMedia目录下的DeviceSource.cpp文件。我这边是把编码出来的h264码流放入了一个缓冲队列,然后从缓冲队列里取出来进行推流。

rtsp.h:

#ifndef _RTSP_H_
#define _RTSP_H_

#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"

void create_rtsp_server(void);

class H264LiveServerMediaSession : public OnDemandServerMediaSubsession
{
public:
    static H264LiveServerMediaSession *createNew(UsageEnvironment &env, Boolean reuseFirstSource);
    void checkForAuxSDPLine1();
    void afterPlayingDummy1();

protected:
    H264LiveServerMediaSession(UsageEnvironment &env, Boolean reuseFirstSource);
    virtual ~H264LiveServerMediaSession(void);
    void setDoneFlag() { fDoneFlag = ~0; }

protected:
    virtual char const *getAuxSDPLine(RTPSink *rtpSink, FramedSource *inputSource);
    virtual FramedSource *createNewStreamSource(unsigned clientSessionId, unsigned &estBitrate);
    virtual RTPSink *createNewRTPSink(Groupsock *rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource *inputSource);

private:
    char *fAuxSDPLine;
    char fDoneFlag;
    RTPSink *fDummyRTPSink;
};

// 创建一个自定义的实时码流数据源类
class H264VideoStreamSource : public FramedSource
{
public:
    static H264VideoStreamSource *createNew(UsageEnvironment &env);
    unsigned maxFrameSize() const;

protected:
    H264VideoStreamSource(UsageEnvironment &env);
    virtual ~H264VideoStreamSource();

private:
    virtual void doGetNextFrame();
    virtual void doStopGettingFrames();
};

#endif // _RTSP_H_

rtsp.cpp:
 

#include <iostream>
#include "rtsp.h"
#include "ringQueue.h"

extern ringQueue *rQueue;

void create_rtsp_server(void)
{
    TaskScheduler *scheduler;
    UsageEnvironment *env;
    RTSPServer *rtspServer;

    scheduler = BasicTaskScheduler::createNew();
    env = BasicUsageEnvironment::createNew(*scheduler);
    rtspServer = RTSPServer::createNew(*env, 8554);
    if (rtspServer == NULL)
    {
        *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
        return;
    }

    ServerMediaSession *sms = ServerMediaSession::createNew(*env);
    sms->addSubsession(H264LiveServerMediaSession::createNew(*env, true));
    rtspServer->addServerMediaSession(sms);
    char *url = rtspServer->rtspURL(sms);
    *env << "Play the stream using url " << url << "\n";
    delete[] url;
    env->taskScheduler().doEventLoop(); // 进入事件循环
}

// H264LiveServerMediaSession 实现:
H264LiveServerMediaSession *H264LiveServerMediaSession::createNew(UsageEnvironment &env, Boolean reuseFirstSource)
{
    return new H264LiveServerMediaSession(env, reuseFirstSource);
}

H264LiveServerMediaSession::H264LiveServerMediaSession(UsageEnvironment &env, Boolean reuseFirstSource) : OnDemandServerMediaSubsession(env, reuseFirstSource)
{
    fAuxSDPLine = NULL;
    fDoneFlag = 0;
    fDummyRTPSink = NULL;
}

H264LiveServerMediaSession::~H264LiveServerMediaSession()
{
    delete[] fAuxSDPLine;
}

static void afterPlayingDummy(void *clientData)
{
    H264LiveServerMediaSession *subsess = (H264LiveServerMediaSession *)clientData;
    subsess->afterPlayingDummy1();
}

void H264LiveServerMediaSession::afterPlayingDummy1()
{
    envir().taskScheduler().unscheduleDelayedTask(nextTask());
    setDoneFlag();
}

static void checkForAuxSDPLine(void *clientData)
{
    H264LiveServerMediaSession *subsess = (H264LiveServerMediaSession *)clientData;
    subsess->checkForAuxSDPLine1();
}

void H264LiveServerMediaSession::checkForAuxSDPLine1()
{
    nextTask() = NULL;

    char const *dasl;
    if (fAuxSDPLine != NULL)
    {
        setDoneFlag();
    }
    else if (fDummyRTPSink != NULL && (dasl = fDummyRTPSink->auxSDPLine()) != NULL)
    {
        fAuxSDPLine = strDup(dasl);
        fDummyRTPSink = NULL;
        setDoneFlag();
    }
    else if (!fDoneFlag)
    {
        // try again after a brief delay:
        int uSecsToDelay = 100000; // 100 ms
        nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay,
                                                                 (TaskFunc *)checkForAuxSDPLine, this);
    }
}

char const *H264LiveServerMediaSession::getAuxSDPLine(RTPSink *rtpSink, FramedSource *inputSource)
{
    if (fAuxSDPLine != NULL)
    {
        return fAuxSDPLine;
    }

    if (fDummyRTPSink == NULL)
    {
        fDummyRTPSink = rtpSink;
        fDummyRTPSink->startPlaying(*inputSource, afterPlayingDummy, this);
        checkForAuxSDPLine(this);
    }
    envir().taskScheduler().doEventLoop(&fDoneFlag);

    return fAuxSDPLine;
}

FramedSource *H264LiveServerMediaSession::createNewStreamSource(unsigned clientSessionId, unsigned &estBitrate)
{
    estBitrate = 5000; // kbps, estimate

    H264VideoStreamSource *videoSource = H264VideoStreamSource::createNew(envir());
    if (videoSource == NULL)
    {
        return NULL;
    }

    return H264VideoStreamFramer::createNew(envir(), videoSource);
}

RTPSink *H264LiveServerMediaSession ::createNewRTPSink(Groupsock *rtpGroupsock,
                                                       unsigned char rtpPayloadTypeIfDynamic,
                                                       FramedSource *inputSource)
{
    // OutPacketBuffer::maxSize = 2000000;
    return H264VideoRTPSink::createNew(envir(), rtpGroupsock, rtpPayloadTypeIfDynamic);
}

// H264VideoStreamSource 实现:
H264VideoStreamSource *H264VideoStreamSource::createNew(UsageEnvironment &env)
{
    return new H264VideoStreamSource(env);
}

H264VideoStreamSource::H264VideoStreamSource(UsageEnvironment &env) : FramedSource(env)
{
}

H264VideoStreamSource::~H264VideoStreamSource()
{
}

unsigned  int H264VideoStreamSource::maxFrameSize() const
{
    return 100000; // 设置fMaxSize的值
}

void H264VideoStreamSource::doGetNextFrame()
{
    rQueue_data e;
    uint32_t timestamp = 0;
    static uint8_t buffer_data[1024 * 512] = {0};

    // 还没准备好要数据
    if (!isCurrentlyAwaitingData())
    {
        std::cout << "isCurrentlyAwaitingData" << std::endl;
        return;
    }

    // 从队列中取出数据
    e.buffer = buffer_data;
    e.len = sizeof(buffer_data);
    if(rQueue_de(rQueue, &e) == -1)
    {
        FramedSource::afterGetting(this);
        return;
    }

    if (e.len > fMaxSize)
    {
        fFrameSize = fMaxSize;
        fNumTruncatedBytes = e.len - fMaxSize;
    }
    else
    {
        fFrameSize = e.len;
    }
    gettimeofday(&fPresentationTime, NULL);
    memcpy(fTo, buffer_data, fFrameSize);
    FramedSource::afterGetting(this);
}

void H264VideoStreamSource::doStopGettingFrames()
{
    std::cout << "doStopGettingFrames" << std::endl;
}

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
### 回答1: live555是一个基于C++的开源流媒体服务器,是由美国的Live Networks公司开发并维护。它的主要功能是在网络上实现实时流传输,支持RTSP、RTP/RTCP和SIP等协议。 在使用live555推送实时流之前,我们需要先设置好服务器地址、端口号以及媒体文件等参数。然后,我们通过live555中的MediaSession类,创建一个媒体会话,将需要传输的媒体流加入到会话中。媒体流可以是音频或视频,也可以是音视频混合的多媒体流。 接着,我们使用live555提供的MediaSubsession类,将加入媒体会话的媒体流进行分割。分割后的媒体流将按照RTSP或RTP协议进行传输,可以通过RTSP或RTP服务器进行接收。其中,RTSP用于控制媒体流的播放、暂停、停止等操作;而RTP则是在网络传输中实现实时数据传输和同步的协议。 总的来说,通过使用live555的媒体会话和媒体分割功能,我们可以轻松地实现实时流的推送和传输,为视频监控、视频会议、实时视频直播等应用提供了非常可靠和高效的技术支持。 ### 回答2: Live555是一个开源的C++多媒体流框架,可用于实现实时流的推送Live555提供了一套完整的库和工具,能够支持常见的视频和音频流协议,例如RTSP,RTP,RTCP等。 实时推送的过程可以概括为以下几个步骤: 1. 创建一个`RTSPServer`实例,用于接收客户端的连接请求。 2. 为需要推送的媒体资源创建一个`MediaSession`实例,并将其添加到`RTSPServer`中。 3. 创建一个`RTSPClientConnection`实例,用于处理客户端的连接和请求。 4. 在`RTSPSession`中添加需要推送的媒体资源,并为其创建一个`RTPSink`实例,用于将媒体数据发送到客户端。 5. 创建一个`MediaSource`实例,用于从媒体源(例如摄像头或音频设备)中获取实时数据。 6. 将`MediaSource`连接到`RTPSink`,并启动数据传输。 7. 开始监听客户端的连接请求,并响应相应的RTSP请求。 8. 当有客户端连接成功后,将媒体数据通过RTP协议发送给客户端。 9. 如果有多个客户端连接,可以使用多线程或多进程来处理并发连接。 通过以上步骤,Live555可以实现实时流从媒体源推送到客户端。实时推送广泛应用于视频直播、视频会议等领域,能够实现高效的实时数据传输和播放。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值