1、live555
live555是一个优秀的rtsp lib,坚持了很多年,细看代码,是精炼的,值得研读。
2、rtsp
rtsp协议包含了rtp,rtcp,sdp等协议,需要把这几个协议都有一定的了解,才能更好地理解代码。
3、show me the code
以下是客户端代码,不作过多解释,值得注意的地方:
1 需要设定接收缓冲区大小,对于高分辨率的视频来说,系统socket缓冲区需要设大一些
2 需要知道服务端支持tcp方式还是udp方式
3 断线需要重连
4 实际上,live555帮我们做了保活连接
/* ---------------------------------------------------------------------------
**
2021-02-13
email 418511899@qq.com
**
** -------------------------------------------------------------------------*/
#pragma once
#include "BasicUsageEnvironment.hh"
#include "liveMedia.hh"
#include <string>
#include <iostream>
#ifdef WIN32
#pragma warning (disable: 4512)
#pragma warning (disable: 4100)
#pragma warning (disable: 4091)
#include <stdint.h>
typedef int ssize_t;
#endif
#define RTSP_CALLBACK(uri, resultCode, resultString) \
static void continueAfter ## uri(RTSPClient* rtspClient, int resultCode, char* resultString) {
static_cast<c_rtsp::RTSPClientConnection*>(rtspClient)->continueAfter ## uri(resultCode, resultString); } \
void continueAfter ## uri (int resultCode, char* resultString); \
/**/
#define TASK_CALLBACK(class,task) \
TaskToken m_ ## task ## Task; \
static void Task ## task(void* rtspClient) {
static_cast<class*>(rtspClient)->Task ## task(); } \
void Task ## task (); \
/**/
#if LIVEMEDIA_LIBRARY_VERSION_INT > 1371168000
#define RTSPClientConstrutor(env, url, verbosity, appname, httpTunnelPort) RTSPClient(env, url, verbosity, appname, httpTunnelPort ,-1)
#else
#define RTSPClientConstrutor(env, url, verbosity, appname, httpTunnelPort) RTSPClient(env, url, verbosity, appname, httpTunnelPort)
#endif
class Environment : public BasicUsageEnvironment
{
public:
Environment(char * stop) : BasicUsageEnvironment(*BasicTaskScheduler::createNew()), m_stop(stop)
{
m_stop = stop;
}
~Environment()
{
TaskScheduler* scheduler = &this->taskScheduler();
delete scheduler;
}
void mainloop()
{
this->taskScheduler().doEventLoop(m_stop);
}
void stop()
{
*m_stop = 1;
}
protected:
char* m_stop;
};
typedef void (*callback_onData)(void * puser, uint8_t*, ssize_t len);
class c_rtsp
{
public:
class Callback
{
public:
virtual bool onNewSession(const char* id, const char* media,
const char* codec, const char* sdp) {
return true; }
virtual bool onData(const char* id, unsigned char* buffer,
ssize_t size, struct timeval presentationTime)
{
if (v_callback != NULL) {
//回调函数,传回名称和数据,数据大小+头部的大小
v_callback(v_user, buffer, size);
return true;
}
return false;
}
virtual ssize_t onNewBuffer(unsigned char* buffer, ssize_t size)
{
return 0;
}
virtual void onError(c_rtsp&, const char*message) {
std::cout << v_name << ":Error:" << message << std::endl;
}
virtual void onConnectionTimeout(c_rtsp& connection)
{
std::cout << v_name << ":Connection timeout -> retry" << std::endl;
v_callback(v_user, NULL, -1);
connection.start();
}
virtual void onDataTimeout(c_rtsp& connection)
{
std::cout << v_name << ":Data timeout -> retry" << std::endl;
v_callback(v_user, NULL, -1);
connection.start();
}
//增加的头部长度
int v_header = 0;
std::string v_name= "empty" ;
void RegisterCallBack(void * puser, int headlen, callback_onData cb) {
v_user = puser;
v_header = headlen;
v_callback = cb;
}
callback_onData v_callback = NULL;
void * v_user = NULL;
};
protected:
class SessionSink: public MediaSink
{
public:
static SessionSink* createNew(UsageEnvironment& env, Callback* callback) {
return new SessionSink(env, callback); }
private:
SessionSink(UsageEnvironment& env, Callback* callback);
virtual ~SessionSink();
void allocate(ssize_t bufferSize);
static void afterGettingFrame(void* clientData, unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds)
{
static_cast<SessionSink*>(clientData)->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime, durationInMicroseconds);
}
void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds);
virtual Boolean continuePlaying();
private:
u_int8_t* m_buffer;
ssize_t m_bufferSize;
Callback* m_callback;
};
class RTSPClientConnection : public RTSPClient
{
public:
RTSPClientConnection(c_rtsp& connection, Environment& env, Callback* callback, const char* rtspURL, int timeout, bool rtpovertcp, int verbosityLevel);
virtual ~RTSPClientConnection();
protected:
void sendNextCommand();
RTSP_CALLBACK(DESCRIBE,resultCode,resultString);
RTSP_CALLBACK(SETUP,resultCode,resultString);
RTSP_CALLBACK(PLAY,resultCode,resultString);
TASK_CALLBACK(c_rtsp::RTSPClientConnection,ConnectionTimeout);
TASK_CALLBACK(c_rtsp::RTSPClientConnection,DataArrivalTimeout);
protected:
c_rtsp& m_connection;
int m_timeout;
bool m_rtpovertcp;
MediaSession* m_session;
MediaSubsession* m_subSession;
MediaSubsessionIterator* m_subSessionIter;
Callback * m_callback;
unsigned int m_nbPacket;
};
public:
c_rtsp(const char* rtspURL,
int header = 4,
int timeout = 5,
bool rtpovertcp = false,
int verbosityLevel = 0);
virtual ~c_rtsp();
void Register_Callcack(void *