RTSP学习笔记1——testRTSPClient

由main函数开始分析


//没有传入任何参数
TaskScheduler* scheduler = BasicTaskScheduler::createNew();


BasicTaskScheduler* BasicTaskScheduler::createNew(unsigned maxSchedulerGranularity) {
	return new BasicTaskScheduler(maxSchedulerGranularity);
}

<pre name="code" class="cpp">//maxSchedulerGranularity =10000 默认值,最大的调度时间间隔
//fMaxNumSockets = 0

 
BasicTaskScheduler::BasicTaskScheduler(unsigned maxSchedulerGranularity)
  : fMaxSchedulerGranularity(maxSchedulerGranularity), fMaxNumSockets(0)
#if defined(__WIN32__) || defined(_WIN32)
  , fDummySocketNum(-1)
#endif
{
	//set一种数据结构,long类型
  FD_ZERO(&fReadSet);//清空fReadSet集合
  FD_ZERO(&fWriteSet);//清空fExceptionSet集合
  FD_ZERO(&fExceptionSet);//清空fExceptionSet集合

  if (maxSchedulerGranularity > 0) schedulerTickTask(); // ensures that we handle events frequently
}
//schedulerTickTask函数
void BasicTaskScheduler::schedulerTickTask() {
  scheduleDelayedTask(fMaxSchedulerGranularity, schedulerTickTask, this);
}


void BasicTaskScheduler::schedulerTickTask(void* clientData) {
  ((BasicTaskScheduler*)clientData)->schedulerTickTask();
}

//microseconds = 10000
TaskToken BasicTaskScheduler0::scheduleDelayedTask(int64_t microseconds,
						 TaskFunc* proc,
						 void* clientData) {
  if (microseconds < 0) microseconds = 0;
  
  //timeToDelay(0,10000)秒、微秒
  //fTv.tv_sec= 0,  fTv.tv_usec= 10000 
  
  DelayInterval timeToDelay((long)(microseconds/1000000), (long)(microseconds%1000000)); 
  AlarmHandler* alarmHandler = new AlarmHandler(proc, clientData, timeToDelay);
  
  //alarmHandler->fProc =proc = schedulerTickTask(void* clientData) clientData = scheduler
  //alarmHandler->DelayQueueEntry = timeToDelay
  //把函数schedulerTickTask(void* clientData)注册到了alarmHandler ,然后把新建alarmHandler插入到调度器中。
  fDelayQueue.addEntry(alarmHandler);
  return (void*)(alarmHandler->token());
}
// 把新的任务作为新的节点插入到调度队列入口
void DelayQueue::addEntry(DelayQueueEntry* newEntry) {
  synchronize();
  DelayQueueEntry* cur = head();
  while (newEntry->fDeltaTimeRemaining >= cur->fDeltaTimeRemaining) {
    newEntry->fDeltaTimeRemaining -= cur->fDeltaTimeRemaining;
    cur = cur->fNext;
  }


  cur->fDeltaTimeRemaining -= newEntry->fDeltaTimeRemaining;


  // Add "newEntry" to the queue, just before "cur":
  newEntry->fNext = cur;
  newEntry->fPrev = cur->fPrev;
  cur->fPrev = newEntry->fPrev->fNext = newEntry;
}

DelayInterval operator-(const Timeval& arg1, const Timeval& arg2) {
  time_base_seconds secs = arg1.seconds() - arg2.seconds();
  time_base_seconds usecs = arg1.useconds() - arg2.useconds();


  if ((int)usecs < 0) {
    usecs += MILLION;
    --secs;
  }
  if ((int)secs < 0)
    return DELAY_ZERO;
  else
    return DelayInterval(secs, usecs);
}
</pre><pre code_snippet_id="634470" snippet_file_name="blog_20150402_10_2569867" name="code" class="cpp">//========================================================================================
UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
/**********************************************************************************
BasicUsageEnvironment::BasicUsageEnvironment(TaskScheduler& taskScheduler)
: BasicUsageEnvironment0(taskScheduler) {
#if defined(__WIN32__) || defined(_WIN32)
  if (!initializeWinsockIfNecessary()) {
    setResultErrMsg("Failed to initialize 'winsock': ");
    reportBackgroundError();
    internalError();
  }
#endif
}
#define RESULT_MSG_BUFFER_MAX 1000
BasicUsageEnvironment::createNew(TaskScheduler& taskScheduler) {
  return new BasicUsageEnvironment(taskScheduler);
}
BasicUsageEnvironment0::BasicUsageEnvironment0(TaskScheduler& taskScheduler)
  : UsageEnvironment(taskScheduler),
    fBufferMaxSize(RESULT_MSG_BUFFER_MAX) {
  reset();
}
//fBufferMaxSize = 1000
void BasicUsageEnvironment0::reset() {
  fCurBufferSize = 0;
  fResultMsgBuffer[fCurBufferSize] = '\0';
}
</pre><pre code_snippet_id="634470" snippet_file_name="blog_20150402_18_8235671" name="code" class="cpp">UsageEnvironment::UsageEnvironment(TaskScheduler& scheduler)
  : liveMediaPriv(NULL), groupsockPriv(NULL), fScheduler(scheduler) {
}
//env->liveMediaPriv = NULL env->groupsockPriv =NULL env->fScheduler = scheduler
// TaskScheduler* scheduler = BasicTaskScheduler::createNew(); 第一句
//========================================================================================================
//假设只有1个RTSP客户端
//arv, 
//输入命令为:./testRTDPClient  rtsp://192.168.2.1:8080/123456.sdp
// argv[1] =  rtsp://192.168.2.1:8080/123456.sdp
//argv[0] = ./testRTDPClient
 for (int i = 1; i <= argc-1; ++i) {
    openURL(*env, argv[0], argv[i]);
  }
</pre><pre code_snippet_id="634470" snippet_file_name="blog_20150402_20_5623429" name="code" class="cpp">void openURL(UsageEnvironment& env, char const* progName, char const* rtspURL) {
  // Begin by creating a "RTSPClient" object.  Note that there is a separate "RTSPClient" object for each stream that we wish
  // to receive (even if more than stream uses the same "rtsp://" URL).
  RTSPClient* rtspClient = ourRTSPClient::createNew(env, rtspURL, RTSP_CLIENT_VERBOSITY_LEVEL, progName);
  if (rtspClient == NULL) {
    env << "Failed to create a RTSP client for URL \"" << rtspURL << "\": " << env.getResultMsg() << "\n";
    return;
  }


  ++rtspClientCount;


  // Next, send a RTSP "DESCRIBE" command, to get a SDP description for the stream.
  // Note that this command - like all RTSP commands - is sent asynchronously; we do not block, waiting for a response.
  // Instead, the following function call returns immediately, and we handle the RTSP response later, from within the event loop:
  rtspClient->sendDescribeCommand(continueAfterDESCRIBE); 
}
</pre><pre code_snippet_id="634470" snippet_file_name="blog_20150402_22_4930015" name="code" class="cpp">ourRTSPClient* ourRTSPClient::createNew(UsageEnvironment& env, char const* rtspURL,
int verbosityLevel, char const* applicationName, portNumBits tunnelOverHTTPPortNum) {
  return new ourRTSPClient(env, rtspURL, verbosityLevel, applicationName, tunnelOverHTTPPortNum);
}


ourRTSPClient::ourRTSPClient(UsageEnvironment& env, char const* rtspURL,
<span style="white-space:pre">			</span>     int verbosityLevel, char const* applicationName, portNumBits tunnelOverHTTPPortNum)
  : RTSPClient(env,rtspURL, verbosityLevel, applicationName, tunnelOverHTTPPortNum, -1) {
}
</pre><pre code_snippet_id="634470" snippet_file_name="blog_20150402_24_332906" name="code" class="cpp">RTSPClient::RTSPClient(UsageEnvironment& env, char const* rtspURL,
int verbosityLevel, char const* applicationName,
portNumBits tunnelOverHTTPPortNum, int socketNumToServer)
  : Medium(env),
  /*
 1、 
 rtspClient->fEnviron = env 
 rtspClient->fNextTask = NULL
  
2、
Medium::Medium(UsageEnvironment& env): fEnviron(env), fNextTask(NULL) {
  // First generate a name for the new medium:
  MediaLookupTable::ourMedia(env)->generateNewName(fMediumName, mediumNameMaxLen);
  env.setResultMsg(fMediumName);


  // Then add it to our table:
  MediaLookupTable::ourMedia(env)->addNew(this, fMediumName);
}  
3、
MediaLookupTable* MediaLookupTable::ourMedia(UsageEnvironment& env) {
    _Tables* ourTables = _Tables::getOurTables(env);
   if (ourTables->mediaTable == NULL) {
    // Create a new table to record the media that are to be created in
    // this environment:
    ourTables->mediaTable = new MediaLookupTable(env);
   }
  return ourTables->mediaTable;
}
4、
_Tables* _Tables::getOurTables(UsageEnvironment& env, Boolean createIfNotPresent) {
  if (env.liveMediaPriv == NULL && createIfNotPresent) {
    env.liveMediaPriv = new _Tables(env); // The first time to excute this line
  }
  return (_Tables*)(env.liveMediaPriv);
}
_Tables::_Tables(UsageEnvironment& env)
  : mediaTable(NULL), socketTable(NULL), fEnv(env) {
}
5、
env->liveMediaPriv = new _Tables(env)
env->liveMediaPriv->fEnv=env
env->liveMediaPriv->mediaTable = NULL
env->liveMediaPriv->socketTable = NULL


ourTables = env->liveMediaPriv 
5、
create hash table!!!
int const STRING_HASH_KEYS = 0;
env->mediaTable= new MediaLookupTable()
ourTables->mediaTable->fEnv=env
ourTables->mediaTable->fTable = new HashTable(STRING_HASH_KEYS)
ourTables->mediaTable->fNameGenerator=0


MediaLookupTable::MediaLookupTable(UsageEnvironment& env)
  : fEnv(env), fTable(HashTable::create(STRING_HASH_KEYS)), fNameGenerator(0) {
}
class BasicHashTable: public HashTable
7、
return env->liveMediaPriv->mediaTable 


8、
void MediaLookupTable::generateNewName(char* mediumName,unsigned ) 
{
  // We should really use snprintf() here, but not all systems have it
  sprintf(mediumName, "liveMedia%d", fNameGenerator++);
}
一个 RtspClient 客户端对应一个媒体名字为liveMediax,x=0、1 、2、3...
这里只有一个客户端:故:liveMedia0,即:Medium->fMediumName = liveMedia0


9、
env.setResultMsg(fMediumName);
void BasicUsageEnvironment0::setResultMsg(MsgString msg) {
  reset();
  appendToResultMsg(msg);
}


fResultMsgBuffe[] = fMediumName = "liveMedia0"
fCurBufferSize = strlen("liveedia0") 


10、


MediaLookupTable::ourMedia(env)->addNew(this, fMediumName);
<==>(ourTables->mediaTable)->addNew(this, fMediumName);
<==>((env->liveMediaPriv)->mediaTable)->addNew(this, fMediumName);


11、
void MediaLookupTable::addNew(Medium* medium, char* mediumName) {
  fTable->Add(mediumName, (void*)medium);
}
((ourTables->mediaTable)->fTable)->Add(mediumName, (void*)medium);


12、(一个Medium ,一个名字)插入到 hash table中并映射一个Entry给他
void* BasicHashTable::Add(char const* key, void* value) {
  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;
}


*/
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

john_liqinghan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值