[转]live555 客户端代码分析

程序从rtsp_player_task 这个线程开始进入进入到 live555 的客户端。

1 char *argv[5]={"openRTSP", "-b", "80000", "-t", ""}; 这是输入参数。 b 代表 FileSink 的大小具体值为 80000. T 代表用 tcp   run_live_rtsp(int argc, char **argv)  这个函数来处理这些参数。

2:在 run_live_rtsp(int argc, char **argv)  这个函数里接着 ourClient = createClient(*env, verbosityLevel, progName); 来创建一个客户端实例。 char* optionsResponse = getOptionsResponse(ourClient, url, username, password);  来发送接受并判断 options

 char* sdpDescription= getSDPDescriptionFromURL(ourClient, url, username, password,

       proxyServerName, proxyServerPortNum,

       desiredPortNum);这个函数用来用来发送接受 description ,并得到 sdp

v=0

o=- 1266888546188420 1 IN IP4 10.0.4.152

s=MPEG Transport Stream, streamed by the LIVE555 Media Server

i=question.ts

t=0 0

a=tool:LIVE555 Streaming Media v2009.07.09

a=type:broadcast

a=control:*

a=range:npt=0-182.512

a=x-qt-text-nam:MPEG Transport Stream, streamed by the LIVE555 Media Server

a=x-qt-text-inf:question.ts

m=video 0 RTP/AVP 33

c=IN IP4 0.0.0.0

a=control:track1

 

根据sdp 创建会话 session = MediaSession::createNew(*env, sdpDescription);

MediaSession* newSession = new MediaSession(env);创建会话。 newSession->initializeWithSDP(sdpDescription) 初始化变量 最主要是依据 m= 。。。。来创建子会话和选用 rtp 协议

 

subsession->initiate(simpleRTPoffsetArg)创建接收区的一些东西进入 initiate 仔细看。首先是 fRTPSocket = new Groupsock(env(), tempAddr, rtpPortNum, 255); 设置 rtpsocket 。调用到 OutputSocket------- Socket(env, port)------ setupDatagramSocke 在这个函数里面 int newSocket = socket(AF_INET, SOCK_DGRAM, 0); 创建 newsocket 。。 port.num() =0 ReceivingInterfaceAddr==0    INADDR_ANY==0adddddddr=0 所以  if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) 就没进去。。。在  if (!socketJoinGroup(env, socketNum(), groupAddr.s_addr)) if (!IsMulticastAddress(groupAddress)) return True; 直接返回然后再 ourSourceAddressForMulticast 这个函数里调用 setupDatagramSocket 函数,里面由于有了 port 所以会执行 bind 。回到 ourSourceAddressForMulticast 里  if (!socketJoinGroup(env, sock, testAddr.s_addr)) 就可以加入成功了。 writeSocket 和  readSocket 是通过写和读 hostIdTest 来获取本地 ip 。。。这个 fRTPSocket = new Groupsock(env(), tempAddr, rtpPortNum, 255); 其实就是申请一个 socket 放在那,然后再申请一个,绑定后 writeSocket 和  readSocket 组播得到本机 ip 然后撤销 socket....

 

getSourcePort(env(), fRTPSocket->socketNum(), clientPort)随即得到一个 rtp 端口号然后把 fRTPSocket = new Groupsock 第一次创建的那个 socket 和这个 rtp 端口进行绑定。

 

 

 

 

frtcpsocket 没有加入 到组播地址里。接着依据 fCodecName 来创建 fRTPSource fReadSource 。。由于我的 ts 流是 MP2T 的所以 if (strcmp(fCodecName, "MP2T") == 0) { // MPEG-2 Transport Stream

      printf("keke/n");

fRTPSource = SimpleRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat,

fRTPTimestampFrequency, "video/MP2T",

0, False);

 

fReadSource = MPEG2TransportStreamFramer::createNew(env(), fRTPSource);

printf("defr/n");

    // this sets "durationInMicroseconds" correctly, based on the PCR values

      } 

fRTPSource创造媒体流名字并加入列表,而 fReadSource 有点像 filter 其输入端像是 fRTPSource fRTCPInstance = RTCPInstance::createNew(env(), fRTCPSocket,

      totSessionBandwidth,

      (unsigned char const*)

      fParent.CNAME(),

      NULL /* we're a client */,

      fRTPSource);创造 fRTCPInstance 进行 rtp 的控制。

 

 

 

现在进入setupStreams(); 一步一步调用到 setupMediaSubsession 它主 要完成

Sending request: SETUP rtsp://10.0.4.152/question.ts/track1 RTSP/1.0

CSeq: 3

Transport: RTP/AVP;unicast;client_port=32770-32771

User-Agent: openRTSP (LIVE555 Streaming Media v2006.11.15)

本地的端口号和获取server 的端口号

Received SETUP response: RTSP/1.0 200 OK

CSeq: 3

Date: Mon, Mar 01 2010 07:56:37 GMT

Transport: RTP/AVP;unicast;destination=10.0.4.155;source=10.0.4.152;client_port=32770-32771;server_port=6970-6971

Session: 16

 

 

 

 fileSink = FileSink::createNew(*env, outFileName,

 fileSinkBufferSize, oneFilePerFrame);

      if (strcmp(subsession->mediumName(), "video") == 0){

   printf("fileSink->set_media_type(1);/n");

               fileSink->set_media_type(1);

       }创建 sink 文件并设置文件类型。

 subsession->sink->startPlaying(*(subsession->readSource()),

 subsessionAfterPlaying,

 subsession);开始取数据

 

startPlayingStreams(-1);告诉 server 可以发数据了

 

现在进入不断循环取数据的阶段:

env->taskScheduler().doEventLoop() -------> BasicTaskScheduler::SingleStep .

  它首先接受描述符fd_set readSet = fReadSet;  fReadSet 在之前就已经创建了并且通过 turnOnBackgroundReadHandling(int socketNum,

BackgroundHandlerProc* handlerProc,

void* clientData) 这个函数把每个套接口加入进去并组织好了队列。

接下来就是不断循环看哪个套接口可读呢。然后调用 MultiFramedRTPSource:: networkReadHandler 这个函数来读取数据。

 

bPacket->fillInData(source->fRTPInterface)取数据最后调用到 Boolean RTPInterface::handleRead(unsigned char* buffer,

 unsigned bufferMaxSize,

 unsigned& bytesRead,

 struct sockaddr_in& fromAddress) 

由于用的是传输层用的是udp 所以 fNextTCPReadStreamSocketNum<0 。调用 readSuccess = fGS->handleRead(buffer, bufferMaxSize, bytesRead, fromAddress); 调用到 Boolean Groupsock::handleRead(unsigned char* buffer, unsigned bufferMaxSize,

      unsigned& bytesRead,

      struct sockaddr_in& fromAddress)接着调用到

int readSocket(UsageEnvironment& env,

       int socket, unsigned char* buffer, unsigned bufferSize,

       struct sockaddr_in& fromAddress,

       struct timeval* timeout) 里面 bytesRead = recvfrom(socket, (char*)buffer, bufferSize, 0,

 (struct sockaddr*)&fromAddress,

 &addressSize);读取数据

 statsIncoming.countPacket(numBytes); statsGroupIncoming.countPacket(numBytes);这两个函数统计读入的字节数。 fillInData 这个函数到 此就执行完。接下来的工作是分析包头直到 The rest of the packet is the usable data.  Record and save it:  storePacket(bPacket) 这个函数是把 bPacket 组织成队列形式,接下来调用到 MultiFramedRTPSource::doGetNextFrame1() 别被他名字骗了,其实他就死去取我们刚刚得到的那包数据 BufferedPacket* nextPacket

      = fReorderingBuffer->getNextCompletedPacket(packetLossPrecededThis);然后判断是不是我们希望的。然后调用 FramedSource::afterGetting ,接着调用 FileSink::afterGettingFrame

接着 FileSink::afterGettingFrame 1然后 addData(unsigned char* data, unsigned dataSize,

       struct timeval presentationTime)这时调用 notify_rtp_frame(get_media_type(), data, dataSize, presentationTime); 这个函数告诉 dma 有数据来了  continuePlaying(); 用从头开始循环

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Live555是一款开源的多媒体流服务器,支持实时流媒体的传输。下面是部分Live555代码分析: 1. MediaSessionMediaSession类是Live555中最核心的类之一,它表示了一个媒体会话,包括了媒体流的传输协议、媒体编码格式、传输方式等信息。MediaSession类中的成员变量包括: - fServerMediaSession:代表了一个媒体服务器会话,负责提供媒体流的传输。 - fSubsessions:代表了一个或多个媒体流的传输会话,可以是RTP/RTCP、HTTP/RTSP等协议。 - fSdpLines:代表了SDP协议中的信息,可以是媒体流的编码格式、传输方式等信息。 MediaSession类中的核心方法包括: - createNew:用于创建一个新的媒体会话。 - addSubsession:用于添加一个媒体流的传输会话。 - generateSdpDescription:用于生成SDP协议描述信息。 - startStream:用于开始媒体流的传输。 - pauseStream:用于暂停媒体流的传输。 - seekStream:用于跳媒体流的传输。 2. MediaSubsessionMediaSubsession类表示了一个媒体流的传输会话,包括了媒体流的传输协议、媒体编码格式、传输方式等信息。MediaSubsession类中的成员变量包括: - fParentSession:代表了父级MediaSession类的实例。 - fRTPSink:代表了RTP数据的发送器。 - fRTCPInstance:代表了RTCP数据的发送器。 - fTrackNumber:代表了媒体流的轨道编号。 - fCodecName:代表了媒体流的编码格式。 - fMediumName:代表了媒体流的传输方式。 MediaSubsession类中的核心方法包括: - initiate:用于初始化媒体流的传输。 - startStream:用于开始媒体流的传输。 - pauseStream:用于暂停媒体流的传输。 - seekStream:用于跳媒体流的传输。 3. RTSPServer类 RTSPServer类是Live555中实现RTSP协议的服务器类。RTSPServer类中的成员变量包括: - fServerMediaSession:代表了一个媒体服务器会话,负责提供媒体流的传输。 - fHTTPServerPort:代表了HTTP服务器的端口号。 - fRTSPServerPort:代表了RTSP服务器的端口号。 RTSPServer类中的核心方法包括: - createNew:用于创建一个新的RTSP服务器。 - start:用于启动RTSP服务器。 - stop:用于停止RTSP服务器。 - incomingConnectionHandler:用于处理RTSP客户端的连接请求。 - handleCmd_DESCRIBE:用于处理DESCRIBE命令。 - handleCmd_SETUP:用于处理SETUP命令。 - handleCmd_PLAY:用于处理PLAY命令。 - handleCmd_PAUSE:用于处理PAUSE命令。 - handleCmd_TEARDOWN:用于处理TEARDOWN命令。 以上是Live555代码的部分分析,希望对你有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值