菜鸟初看live555,故做下笔记
MediaServer的主函数,代码没多少,但是前面的几个构造过程可谓是完成了大部分的工作啊
#include
#include "DynamicRTSPServer.hh"
#include "version.hh"
int main(int argc, char** argv) {
// Begin by setting up our usage environment:
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
UserAuthenticationDatabase* authDB = NULL;
#ifdef ACCESS_CONTROL
// To implement client access control to the RTSP server, do the following:
authDB = new UserAuthenticationDatabase;
authDB->addUserRecord("username1", "password1"); // replace these with real strings
// Repeat the above with each , that you wish to allow
// access to the server.
#endif
// Create the RTSP server. Try first with the default port number (554),
// and then with the alternative port number (8554):
RTSPServer* rtspServer;
portNumBits rtspServerPortNum = 554;
rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);
if (rtspServer == NULL) {
rtspServerPortNum = 8554;
rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);
}
if (rtspServer == NULL) {
*env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
exit(1);
}
*env << "LIVE555 Media Server\n";
*env << "\tversion " << MEDIA_SERVER_VERSION_STRING
<< " (LIVE555 Streaming Media library version "
<< LIVEMEDIA_LIBRARY_VERSION_STRING << ").\n";
char* urlPrefix = rtspServer->rtspURLPrefix();
*env << "Play streams from this server using the URL\n\t"
<< urlPrefix << "\nwhere is a file present in the current directory.\n";
*env << "Each file's type is inferred from its name suffix:\n";
*env << "\t\".aac\" => an AAC Audio (ADTS format) file\n";
*env << "\t\".amr\" => an AMR Audio file\n";
*env << "\t\".m4e\" => a MPEG-4 Video Elementary Stream file\n";
*env << "\t\".264\" => a H.264 Video Elementary Stream file\n";
*env << "\t\".dv\" => a DV Video file\n";
*env << "\t\".mp3\" => a MPEG-1 or 2 Audio file\n";
*env << "\t\".mpg\" => a MPEG-1 or 2 Program Stream (audio+video) file\n";
*env << "\t\".ts\" => a MPEG Transport Stream file\n";
*env << "\t\t(a \".tsx\" index file - if present - provides server 'trick play' support)\n";
*env << "\t\".wav\" => a WAV Audio file\n";
*env << "See http://www.live555.com/mediaServer/ for additional documentation.\n";
// Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling.
// Try first with the default HTTP port (80), and then with the alternative HTTP
// port numbers (8000 and 8080).
if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) {
*env << "(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling.)\n";
} else {
*env << "(RTSP-over-HTTP tunneling is not available.)\n";
}
env->taskScheduler().doEventLoop(); // does not return
return 0; // only to prevent compiler warning
}
一、BasicTaskScheduler初始化的构造过程
BasicTaskScheduler* BasicTaskScheduler::createNew() {
return new BasicTaskScheduler();
}
/**************************************************/
BasicTaskScheduler::BasicTaskScheduler()
: fMaxNumSockets(0) {
FD_ZERO(&fReadSet);
FD_ZERO(&fWriteSet);
FD_ZERO(&fExceptionSet);
schedulerTickTask(this); // ensures that we handle events frequently
//这个函数没看懂
}
/**************************************************/
#define MAX_SCHEDULER_GRANULARITY 10000 // 10 microseconds: We will return to the event loop at least this often
static void schedulerTickTask(void* clientData) {
((BasicTaskScheduler*)clientData)->scheduleDelayedTask(MAX_SCHEDULER_GRANULARITY, schedulerTickTask, clientData);
}
二、BasicUsageEnvironment初始化的构造过程
BasicUsageEnvironment*
BasicUsageEnvironment::createNew(TaskScheduler& taskScheduler) {
return new BasicUsageEnvironment(taskScheduler);
}
/**************************************************/
BasicUsageEnvironment::BasicUsageEnvironment(TaskScheduler& taskScheduler)
: BasicUsageEnvironment0(taskScheduler) {
#if defined(__WIN32__) || defined(_WIN32)//如果在window32系统下就进行winsock的初始化,否则就是一个宏直接返回1
if (!initializeWinsockIfNecessary()) {
setResultErrMsg("Failed to initialize 'winsock': ");//初始化失败则向标准错误输出错误信息
reportBackgroundError();//把错误fputs到标准错误输出
internalError();//终止程序
}
#endif
}
/**************************************************/
BasicUsageEnvironment0(TaskScheduler& taskScheduler)
: UsageEnvironment(taskScheduler),
fBufferMaxSize(RESULT_MSG_BUFFER_MAX) {//最大的fBufferMaxSize初始化为1000
reset();//将当前值设置为""只有'\0'空字符串
}
/**************************************************/
UsageEnvironment::UsageEnvironment(TaskScheduler& scheduler)
: liveMediaPriv(NULL), groupsockPriv(NULL), fScheduler(scheduler) {//fScheduler 是TaskScheduler类的引用,无数据,
//TaskScheduler类的构造函数是空函数,也执行了
}
三、DynamicRTSPServer初始化的构造过程
static DynamicRTSPServer* createNew(UsageEnvironment& env, Port ourPort,
UserAuthenticationDatabase* authDatabase,
unsigned reclamationTestSeconds = 65);//声明,最后一个参数如果不指定的话就是65
/**************************************************/
DynamicRTSPServer*
DynamicRTSPServer::createNew(UsageEnvironment& env, Port ourPort,
UserAuthenticationDatabase* authDatabase,
unsigned reclamationTestSeconds) {
int ourSocket = -1;
do {
int ourSocket = setUpOurSocket(env, ourPort);
if (ourSocket == -1) break;
return new DynamicRTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds);
} while (0);
if (ourSocket != -1) ::closeSocket(ourSocket);//如果前面break了也就是出错了,就会返回NULL
return NULL;
}
/**************************************************/
int RTSPServer::setUpOurSocket(UsageEnvironment& env, Port& ourPort) {
int ourSocket = -1;
do {
NoReuse dummy; // Don't use this socket if there's already a local server using it
//定义了则会调用NoReuse()构造函数,将全局变量reuseFlag置为0,即不重用,析构函数将reuseFlag置为1
ourSocket = setupStreamSocket(env, ourPort);//建立TCP的socket并绑定端口和INADDR_ANY,设置非阻塞
if (ourSocket < 0) break;
// Make sure we have a big send buffer:
if (!increaseSendBufferTo(env, ourSocket, 50*1024)) break;//先获取原来的缓冲如果请求的缓冲大于原来的
//则设置发送缓冲为所请求的缓冲大小
// Allow multiple simultaneous connections:
if (listen(ourSocket, LISTEN_BACKLOG_SIZE) < 0) {//监听最大的队列为20
env.setResultErrMsg("listen() failed: ");
break;
}
if (ourPort.num() == 0) {
// bind() will have chosen a port for us; return it also:
if (!getSourcePort(env, ourSocket, ourPort)) break;
}
return ourSocket;
} while (0);
if (ourSocket != -1) ::closeSocket(ourSocket);//没看懂
return -1;
}
/**************************************************/
int setupStreamSocket(UsageEnvironment& env,
Port port, Boolean makeNonBlocking) {//makeNonBlocking不指定默认为非阻塞即为1
if (!initializeWinsockIfNecessary()) {//window32系统下就进行winsock的初始化,否则就是一个宏直接返回1
socketErr(env, "Failed to initialize 'winsock': ");
return -1;
}
int newSocket = socket(AF_INET, SOCK_STREAM, 0);
if (newSocket < 0) {
socketErr(env, "unable to create stream socket: ");
return newSocket;
}
if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
(const char*)&reuseFlag, sizeof reuseFlag) < 0) {
socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
closeSocket(newSocket);
return -1;
}
// SO_REUSEPORT doesn't really make sense for TCP sockets, so we
// normally don't set them. However, if you really want to do this
// #define REUSE_FOR_TCP
#ifdef REUSE_FOR_TCP
#if defined(__WIN32__) || defined(_WIN32)
// Windoze doesn't properly handle SO_REUSEPORT
#else
#ifdef SO_REUSEPORT
if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
(const char*)&reuseFlag, sizeof reuseFlag) < 0) {//reuseFlag为全局变量,初始值为1
socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
closeSocket(newSocket);
return -1;
}
#endif
#endif
#endif
// Note: Windoze requires binding, even if the port number is 0
#if defined(__WIN32__) || defined(_WIN32)
#else
if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
#endif
MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());//MAKE_SOCKADDR_IN为一个宏
if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
char tmpBuffer[100];
sprintf(tmpBuffer, "bind() error (port number: %d): ",
ntohs(port.num()));
socketErr(env, tmpBuffer);
closeSocket(newSocket);
return -1;
}
#if defined(__WIN32__) || defined(_WIN32)
#else
}
#endif
if (makeNonBlocking) {
if (!makeSocketNonBlocking(newSocket)) {
socketErr(env, "failed to make non-blocking: ");
closeSocket(newSocket);
return -1;
}
}
return newSocket;
}
/**************************************************/
DynamicRTSPServer::DynamicRTSPServer(UsageEnvironment& env, int ourSocket,
Port ourPort,
UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds)
: RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds) {//没啥好看的,只是起到一个过度作用调用父类的构造函数
}
/**************************************************/
RTSPServer::RTSPServer(UsageEnvironment& env,
int ourSocket, Port ourPort,
UserAuthenticationDatabase* authDatabase,
unsigned reclamationTestSeconds)
: Medium(env),//调用父类的构造函数
fRTSPServerSocket(ourSocket), fRTSPServerPort(ourPort),//把我们创建的socket交给RTSPServer来管理
fHTTPServerSocket(-1), fHTTPServerPort(0), fClientSessionsForHTTPTunneling(NULL),//默认不用HTTP
fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds),//这个值默认为65
fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)) {//STRING_HASH_KEYS为0,有重复生成了一份供RTSPServer使用
#ifdef USE_SIGNALS
// Ignore the SIGPIPE signal, so that clients on the same host that are killed
// don't also kill us:
signal(SIGPIPE, SIG_IGN);//服务端必须忽略客户端死掉的信号,否则默认服务端也会终止
#endif
// Arrange to handle connections from others:
env.taskScheduler().turnOnBackgroundReadHandling(fRTSPServerSocket,//中间过度了一下,请往下看278
(TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandlerRTSP, this);
}
/**************************************************/
Medium::Medium(UsageEnvironment& env)
: fEnviron(env), fNextTask(NULL) {//fEnviron 是UsageEnvironment的引用,fNextTask是void*指针
// First generate a name for the new medium:
MediaLookupTable::ourMedia(env)->generateNewName(fMediumName, mediumNameMaxLen);//MediaLookupTable是Medium的友元类
//生成fMediumName名字,为liveMedia1,第一次fNameGenerator初始值为0,自增后为1
env.setResultMsg(fMediumName);
// Then add it to our table:
MediaLookupTable::ourMedia(env)->addNew(this, fMediumName);//请往下看258行
}//回看188行
/**************************************************/
MediaLookupTable* MediaLookupTable::ourMedia(UsageEnvironment& env) {
_Tables* ourTables = _Tables::getOurTables(env);//创建表, 请看行225
if (ourTables->mediaTable == NULL) {//由行234可知这时候是NULL的
// Create a new table to record the media that are to be created in
// this environment:
ourTables->mediaTable = new MediaLookupTable(env);//创建媒体查找表,用mediaTable指针来保存MediaLookupTable的指针,请往下看行237
}
return (MediaLookupTable*)(ourTables->mediaTable);//得到初始化创建了哈希表的指针,回看208
}
/**************************************************/
_Tables* _Tables::getOurTables(UsageEnvironment& env, Boolean createIfNotPresent) {//如果不存在则创建
if (env.liveMediaPriv == NULL && createIfNotPresent) {//第一次先创建
env.liveMediaPriv = new _Tables(env);//建立env.liveMediaPriv指针指向_Tables的关系,请往下看行233
}
return (_Tables*)(env.liveMediaPriv);//返回指向_Tables的指针,因为env.liveMediaPriv是void*型,所以要强制类型转换,回看217
}
/**************************************************/
_Tables::_Tables(UsageEnvironment& env)//初始化_Tables类的指针,且置为NULL,回看227
: mediaTable(NULL), socketTable(NULL), fEnv(env) {
}
/**************************************************/
MediaLookupTable::MediaLookupTable(UsageEnvironment& env)
: fEnv(env), fTable(HashTable::create(STRING_HASH_KEYS)), fNameGenerator(0) {//创建哈希表STRING_HASH_KEYS为0
//请往下看242
}
/**************************************************/
HashTable* HashTable::create(int keyType) {
return new BasicHashTable(keyType);//起到过度作用,调用构造函数,请往下看248
}
/**************************************************/
BasicHashTable::BasicHashTable(int keyType)//对哈希表的一系列初始化操作,具体的数据没看懂是为什么设置
: fBuckets(fStaticBuckets), fNumBuckets(SMALL_HASH_TABLE_SIZE),
fNumEntries(0), fRebuildSize(SMALL_HASH_TABLE_SIZE*REBUILD_MULTIPLIER),
fDownShift(28), fMask(0x3), fKeyType(keyType) {
for (unsigned i = 0; i < SMALL_HASH_TABLE_SIZE; ++i) {//所有的指针都设置为NULL,回看220
fStaticBuckets[i] = NULL;
}
}
/**************************************************/
void* BasicHashTable::Add(char const* key, void* value) {//暂且不管,回看213
void* oldValue;
unsigned index;
TableEntry* entry = lookupKey(key, index);
if (entry != NULL) {
// There's already an item with this key
oldValue = entry->value;
} else {
// There's no existing entry; create a new one:
entry = insertNewEntry(index, key);
oldValue = NULL;
}
entry->value = value;
// If the table has become too large, rebuild it with more buckets:
if (fNumEntries >= fRebuildSize) rebuild();
return oldValue;
}
/**************************************************/
void turnOnBackgroundReadHandling(int socketNum, BackgroundHandlerProc* handlerProc, void* clientData) {
setBackgroundHandling(socketNum, SOCKET_READABLE, handlerProc, clientData);//SOCKET_READABLE值为(1<<1),往下看283
}
/**************************************************/
void BasicTaskScheduler
::setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData) {
if (socketNum < 0) return;
FD_CLR((unsigned)socketNum, &fReadSet);//在集合中删除socketNum描述符
FD_CLR((unsigned)socketNum, &fWriteSet);
FD_CLR((unsigned)socketNum, &fExceptionSet);
if (conditionSet == 0) {//conditionSet此时为2
fHandlers->clearHandler(socketNum);
if (socketNum+1 == fMaxNumSockets) {
--fMaxNumSockets;
}
} else {
fHandlers->assignHandler(socketNum, conditionSet, handlerProc, clientData);//请往下305
if (socketNum+1 > fMaxNumSockets) {//为了select
fMaxNumSockets = socketNum+1;
}
if (conditionSet&SOCKET_READABLE) FD_SET((unsigned)socketNum, &fReadSet);//第一次是可读的,把socketNum加到可读集合里
if (conditionSet&SOCKET_WRITABLE) FD_SET((unsigned)socketNum, &fWriteSet);
if (conditionSet&SOCKET_EXCEPTION) FD_SET((unsigned)socketNum, &fExceptionSet);//回看200
}
}
/**************************************************/
void HandlerSet
::assignHandler(int socketNum, int conditionSet, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData) {
// First, see if there's already a handler for this socket:
HandlerDescriptor* handler = lookupHandler(socketNum);//请往下看319,第一次是找不到的,返回NULL
if (handler == NULL) { // No existing handler, so create a new descr:
handler = new HandlerDescriptor(fHandlers.fNextHandler);//申请一个描述符,请往下328
handler->socketNum = socketNum;//初始化
}
handler->conditionSet = conditionSet;//要select的集合
handler->handlerProc = handlerProc;//函数指针
handler->clientData = clientData;//函数的参数,回看295
}
/**************************************************/
HandlerDescriptor* HandlerSet::lookupHandler(int socketNum) {
HandlerDescriptor* handler;
HandlerIterator iter(*this);
while ((handler = iter.next()) != NULL) {
if (handler->socketNum == socketNum) break;
}
return handler;
}
HandlerDescriptor::HandlerDescriptor(HandlerDescriptor* nextHandler)
: conditionSet(0), handlerProc(NULL) {//函数指针
// Link this descriptor into a doubly-linked list:
if (nextHandler == this) { // initialization
//如果HandlerSet中的HandlerDescriptor fHandlers和新创建的相等
fNextHandler = fPrevHandler = this;
} else {
fNextHandler = nextHandler;
fPrevHandler = nextHandler->fPrevHandler;//没搞懂
nextHandler->fPrevHandler = this;
fPrevHandler->fNextHandler = this;//回看310
}
}