1. 程式人生 > >Live555原始碼徹底解密(根據testRTSPClient講解)

Live555原始碼徹底解密(根據testRTSPClient講解)

RTSPClient建立流程(testProgs中的testRTSPClient示例)

 參考文件:

testRtspClient流程圖請參考下面連結:

1)      
Sink
source

Source是接收資料,Sink是消費資料;

int main(intargc,char**
argv) {

     // Begin by setting up our usage environment:

     TaskScheduler
scheduler
 = BasicTaskScheduler::createNew();

     UsageEnvironment
env
 = BasicUsageEnvironment::createNew(*scheduler);

     // We need at least one "rtsp://" URL argument:

     if (argc < 2) {

         usage(*env,argv[0]);

         return 1;

     }

     // There are argc-1 URLs: argv[1] through argv[argc-1]. Open and start streaming each one:

     for (inti = 1;i <=argc-1; ++i) {

         openURL(*env,argv[0],argv[i]);

     }

     // All subsequent activity takes place within the event loop:

     env->taskScheduler().doEventLoop(&eventLoopWatchVariable);

     // This function call does not return, unless, at some point in time, "eventLoopWatchVariable" gets set to something non-zero.

     return 0;

}

TestRtspClient的堆疊呼叫流程如下:

1)  
首先OpenURL,函式如下:

void 
openURL
(UsageEnvironment
env
char const*progName,charconst*
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);

2)  }

首先通過ourRTSPClient::createNew函式最終會呼叫ourRTSPClient的建構函式,基類RTSPClient的指標指向派生類ourRTSPClient物件,並且最終會呼叫RTSPClient的建構函式;

sendDescribeCommand函式往伺服器端傳送Describe請求;continueAfterDESCRIBE為回撥函式;在DoEventLoop中的SingleStep中呼叫;RTP over tcp 還是udp 由巨集#defineREQUEST_STREAMING_OVER_TCPFalse進行控制;

unsigned 
RTSPClient
::sendDescribeCommand(responseHandler*responseHandler,Authenticator*authenticator)
{

  if (authenticator !=NULL)fCurrentAuthenticator = *authenticator;

  return 
sendRequest
(new 
RequestRecord
(++fCSeq
"DESCRIBE"
responseHandler));

}

continueAfterDESCRIBE函式傳遞到responseHandler,相當於continueAfterDESCRIBE為一個回撥函式;注意RequestRecord這個類的作用;在SendRequest中呼叫RequestRecord的建構函式

RTSPClient::RequestRecord::RequestRecord(unsignedcseq,char
constcommandName,
responseHandler*handler,MediaSession*session,MediaSubsession*subsession,u_int32_tbooleanFlags,doublestart,double
endfloat 
scale
,charconst*
contentStr)

  :fNext(NULL),fCSeq(cseq),fCommandName(commandName),fSession(session),fSubsession(subsession),fBooleanFlags(booleanFlags),

   fStart(start),fEnd(end),fAbsStartTime(NULL),fAbsEndTime(NULL),fScale(scale),fContentStr(strDup(contentStr)),fHandler(handler)
{

}

將回調函式儲存在RequestRecord類的fHandler上; RequestRecord類定義如下:

  // The state of a request-in-progress:

  class 
RequestRecord
 {

  public:

    RequestRecord(unsignedcseq,char
constcommandName,
responseHandlerhandler,

           MediaSession
session
 = NULL
MediaSubsession
subsession = 
NULL
u_int32_t 
booleanFlags
 = 0,

           double 
start
 = 0.0f, double 
end
 = -1.0f, float 
scale
 = 1.0f, char 
const
contentStr = 
NULL
);

    RequestRecord(unsignedcseq,responseHandler*handler,

           char 
const
absStartTime
char
 constabsEndTime =NULL,float
scale = 1.0f,

           MediaSession
session
 = NULL
MediaSubsession
subsession = 
NULL
);

        // alternative constructor for creating "PLAY" requests that include 'absolute' time values

    virtual ~RequestRecord();

    RequestRecord*& 
next
() { return 
fNext
; }

    unsigned
cseq
() { return 
fCSeq
; }

    char 
const
commandName() 
const
 { return 
fCommandName
; }

    MediaSession
session
() const { 
return
 fSession; }

    MediaSubsession
subsession
() const { 
return
 fSubsession; }

    u_int32_t 
booleanFlags
() const { 
return
 fBooleanFlags; }

    double 
start
() const { returnfStart; }

    double 
end
() const { returnfEnd; }

    char 
const
absStartTime() 
const
 { return 
fAbsStartTime
; }

    char 
const
absEndTime() 
const
 { return 
fAbsEndTime
; }

    float 
scale
() const { returnfScale; }

    char
contentStr
() const { 
return
 fContentStr; }

    responseHandler*& 
handler
() { return 
fHandler
; }

  private:

    RequestRecord
fNext
;

    unsigned 
fCSeq
;

    char 
const
fCommandName;

    MediaSession
fSession
;

    MediaSubsession
fSubsession
;

    u_int32_t 
fBooleanFlags
;

    double 
fStart
fEnd;

    char *fAbsStartTime, *fAbsEndTime;// used for optional 'absolute' (i.e., "time=") range specifications

    float 
fScale
;

    char
fContentStr
;

   responseHandler* fHandler;

  };

在其他地方就通過RequestRecord類的fHandler 呼叫到回撥函式continueAfterDESCRIBE;注意跟蹤在哪個地方呼叫了RequestRecord類的fHandler,我猜是在DoEvent();中呼叫的。在DoEvent的函式incomingDataHandler1中的handleResponseBytes中呼叫    
(*foundRequest->handler())(this,resultCode,resultString);

  typedef 
void
 (responseHandler)(RTSPClient*rtspClient,

                    int 
resultCode
char
resultString
);

      // A function that is called in response to a RTSP command. The parameters are as follows:

      //     "rtspClient": The "RTSPClient" object on which the original command was issued.

      //     "resultCode": If zero, then the command completed successfully.  If non-zero, then the command did not complete

      //         successfully, and "resultCode" indicates the error, as follows:

      //             A positive "resultCode" is a RTSP error code (for example, 404 means "not found")

      //             A negative "resultCode" indicates a socket/network error; 0-"resultCode" is the standard "errno" code.

      //     "resultString": A ('\0'-terminated) string returned along with the response, or else NULL.

      //         In particular:

      /