1、 live555
live555除了可以建立客户端,当然也可以做一个服务端了,快速做一个服务端就把live555的lib文件编译好,放进来进行。
以h264 为例子,实际上,无论是读取文件也好,还是web摄像头编码也好,需要的其实就是sps,pps信息,就是这么简单。
1.1 读取文件如果是读取文件,读的过程中要把sps,pps记录下来,如果是加密流,分为两种情况,一是解密,二是直接传输。
1.2 摄像头编码发送摄像头采用编码h264或者h265后可以发送到连接的客户端,建立一个CameraFrameSource从FramedSource继承,声明如下:
class CameraFrameSource : public FramedSource {
public:
static CameraFrameSource* createNew(UsageEnvironment&, CameraH264Encoder*);
CameraFrameSource(UsageEnvironment& env, CameraH264Encoder*);
~CameraFrameSource() = default;
private:
static void deliverFrameStub(void* clientData) {
((CameraFrameSource*)clientData)->deliverFrame();
};
void doGetNextFrame() override;
void deliverFrame();
void doStopGettingFrames() override;
void onFrame();
private:
CameraH264Encoder *fEncoder;
EventTriggerId fEventTriggerId;
};
主要转发的代码如下
void CameraFrameSource::deliverFrame()
{
if (!isCurrentlyAwaitingData()) return; // we're not ready for the buff yet
static uint8_t* newFrameDataStart;
static unsigned newFrameSize = 0;
/* get the buff frame from the Encoding thread.. */
if (fEncoder->fetch_packet(&newFrameDataStart, &newFrameSize)) {
if (newFrameDataStart != nullptr) {
/* This should never happen, but check anyway.. */
if (newFrameSize > fMaxSize) {
fFrameSize = fMaxSize;
fNumTruncatedBytes = newFrameSize - fMaxSize;
}
else {
fFrameSize = newFrameSize;
}
gettimeofday(&fPresentationTime, nullptr);
memcpy(fTo, newFrameDataStart, fFrameSize);
//delete newFrameDataStart;
//newFrameSize = 0;
fEncoder->release_packet();
}
else {
fFrameSize = 0;
fTo = nullptr;
handleClosure(this);
}
}
else {
fFrameSize = 0;
}
if (fFrameSize > 0)
FramedSource::afterGetting(this);
};
主main函数里面实现rtspserver的run,把刚才的framesource加入到里面。如果是h265,同样的流程。
CameraRTSPServer::CameraRTSPServer(CameraH264Encoder * enc, int port, int httpPort)
: fH264Encoder(enc), fPortNum(port), fHttpTunnelingPort(httpPort), fQuit(0), fBitRate(5120) //in kbs
{
fQuit = 0;
};
CameraRTSPServer::~CameraRTSPServer()
{
};
void CameraRTSPServer::run()
{
TaskScheduler *scheduler;
UsageEnvironment *env;
char stream_name[] = "your name";
scheduler = BasicTaskScheduler::createNew();
env = BasicUsageEnvironment::createNew(*scheduler);
UserAuthenticationDatabase* authDB = nullptr;
// if (m_Enable_Pass){
// authDB = new UserAuthenticationDatabase;
// authDB->addUserRecord(UserN, PassW);
// }
OutPacketBuffer::increaseMaxSizeTo(5242880); // 1M
RTSPServer* rtspServer = RTSPServer::createNew(*env, fPortNum, authDB);
if (rtspServer == nullptr)
{
*env setUpTunnelingOverHTTP(fHttpTunnelingPort);
}
char const* descriptionString = "Combined Multiple Cameras Streaming Session";
CameraFrameSource* source = CameraFrameSource::createNew(*env, fH264Encoder);
StreamReplicator* inputDevice = StreamReplicator::createNew(*env, source, false);
ServerMediaSession* sms = ServerMediaSession::createNew(*env, stream_name, stream_name, descriptionString);
CameraMediaSubsession* sub = CameraMediaSubsession::createNew(*env, inputDevice);
sub->set_PPS_NAL(fH264Encoder->PPS_NAL(), fH264Encoder->PPS_NAL_size());
sub->set_SPS_NAL(fH264Encoder->SPS_NAL(), fH264Encoder->SPS_NAL_size());
if (fH264Encoder->h264_bit_rate() > 102400) {
sub->set_bit_rate(fH264Encoder->h264_bit_rate());
}
else {
sub->set_bit_rate(static_cast(fH264Encoder->pict_width() * fH264Encoder->pict_height() * fH264Encoder->frame_rate() / 20));
}
sms->addSubsession(sub);
rtspServer->addServerMediaSession(sms);
char* url = rtspServer->rtspURL(sms);
*env taskScheduler().doEventLoop(&fQuit); // does not return
Medium::close(rtspServer);
Medium::close(inputDevice);
}
env->reclaim();
delete scheduler;
};
}
2、推流到其他服务器
2.1.OPTIONS会话
OPTIONS rtsp://x.x.x.x.:445/live/1001 RTSP/1.0
User-Agent: youragentname
CSeq: 1
2.2 ANNOUNCE
ANNOUNCE rtsp://x.x.x.x:445/live/1001 RTSP/1.0
User-Agent: youranentname
CSeq: 2
Content-Type: application/sdp
Content-Length: number
v=0
o=- 1464329709034587 1 IN IP4 127.0.0.1
s= h264 Transport Stream, streamed by qianbo
m= video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
a=control:control:streamid=0
m=audio 0 RTP/AVP 97
a=rtpmap:97 MPEG4-GENERIC/44100/1
a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=1208
a=control:streamid=1
2.3 SETUP tcp
SETUP rtsp://x.x.x.x:445/live/trackid1 RTSP/1.0
Transport: RTP/AVP/TCP;unicast;interleaved=0-1;mode=record
User-Agent: youragentname
CSeq: 3
2.4 RECORD
RECORD rtsp://x.x.x.x:445/live RTSP/1.0
Session: 0x11111
User-Agent: youragentname
CSeq: 4
2.5 TEARDOWN
TEARDOWN rtsp://x.x.x.x:445/live RTSP/1.0
Session: 0x11111
User-Agent: youragentname
CSeq: 4
这个方式并不是使用rtsp server 来接收下级的流,而是使用live555 来push到上级server,主代码如下所示
#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"
UsageEnvironment* env;
// To make the second and subsequent client for each stream reuse the same
// True:The client that is started later always starts playing from the position that the first client has already played
// False:Every client plays video files from the beginning
Boolean reuseFirstSource = False;
// This function prints relevant information
static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms, char const* streamName);
int main(int argc, char** argv) {
// 1. Create a task scheduler and initialize the use environment
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
// 2. Create an interactive environment
env = BasicUsageEnvironment::createNew(*scheduler);
// The following is the code for permission control. After setting, the client without permission cannot connect
UserAuthenticationDatabase* authDB = NULL;
authDB = new UserAuthenticationDatabase;
authDB->addUserRecord("admin", "Suntek123"); // replace these with real strings
// 3. Create an RTSP server and start monitoring the connection of the module client.
// Note that if the port here is not the default port 554, you must specify the port number when accessing the URL:
RTSPServer* rtspServer = RTSPServer::createNew(*env, 554, authDB);
if (rtspServer == NULL) {
*env setUpTunnelingOverHTTP(8080)) {
*env
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?