Ejemplo n.º 1
0
MP3HTTPSource* MP3HTTPSource::createNew(UsageEnvironment& env,
					NetAddress const& remoteAddress,
					Port remotePort,
					char const* remoteHostName,
					char const* fileName) {
  int ourSocket = -1;
  MP3HTTPSource* newSource = NULL;

  do {
    // Create a stream socket for this source.
    // Note: We don't make the socket non-blocking, because we want
    // to read from it synchronously (as we do with real file sources)
    ourSocket = setupStreamSocket(env, 0, False);
    if (ourSocket < 0) break;

    // Connect to the remote endpoint:
    MAKE_SOCKADDR_IN(remoteName, *(unsigned*)(remoteAddress.data()), remotePort.num());
    if (connect(ourSocket, (struct sockaddr*)&remoteName, sizeof remoteName)
	!= 0) {
      env.setResultErrMsg("connect() failed: ");
      break;
    }

    // Make sure we have a big receive buffer:
    if (!increaseReceiveBufferTo(env, ourSocket, 100*1024)) break;
    
    // Try to make the new socket into a FILE*:
    unsigned streamLength = 0; //#####
    FILE* fid = NULL;
#if !defined(IMN_PIM) && !defined(CRIS) && !defined(_WIN32_WCE)
    fid = fdopen(ourSocket, "r+b");
#endif
    if (fid == NULL) {
      // HACK HACK HACK #####
      // We couldn't convert the socket to a FILE*; perhaps this is Windoze?
      // Instead, tell the low-level to read it directly as a socket:
      long ourSocket_long = (long)ourSocket;
      fid = (FILE*)ourSocket_long;
      streamLength = (unsigned)(-1);
    }

    newSource = new MP3HTTPSource(env, fid);
    if (newSource == NULL) break;
    
    newSource->assignStream(fid, streamLength);

    // Write the HTTP 'GET' command:
    newSource->writeGetCmd(remoteHostName, ntohs(remotePort.num()),
			   fileName);

    // Now read the first frame header, to finish initializing the stream:
    if (!newSource->initializeStream()) break;

    return newSource;
  } while (0);

  if (ourSocket != -1) ::closeSocket(ourSocket);
  Medium::close(newSource);
  return NULL;
}
Ejemplo n.º 2
0
BasicUDPSource::BasicUDPSource(UsageEnvironment& env, Groupsock* inputGS)
	: FramedSource(env), fInputGS(inputGS), fHaveStartedReading(False) {
	// Try to use a large receive buffer (in the OS):
  increaseReceiveBufferTo(env, inputGS->socketNum(), 50*1024);

	// Make the socket non-blocking, even though it will be read from only asynchronously, when packets arrive.
	// The reason for this is that, in some OSs, reads on a blocking socket can (allegedly) sometimes block,
	// even if the socket was previously reported (e.g., by "select()") as having data available.
	// (This can supposedly happen if the UDP checksum fails, for example.)
  makeSocketNonBlocking(fInputGS->socketNum());
}
Ejemplo n.º 3
0
MultiFramedRTPSource
::MultiFramedRTPSource(UsageEnvironment& env, Groupsock* RTPgs,
		       unsigned char rtpPayloadFormat,
		       unsigned rtpTimestampFrequency,
		       BufferedPacketFactory* packetFactory)
  : RTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency) {
  reset();
  fReorderingBuffer = new ReorderingPacketBuffer(packetFactory);

  // Try to use a big receive buffer for RTP:
  increaseReceiveBufferTo(env, RTPgs->socketNum(), 50*1024);
}
Ejemplo n.º 4
0
extern "C" demuxer_t* demux_open_rtp(demuxer_t* demuxer) {
  struct MPOpts *opts = demuxer->opts;
  Boolean success = False;
  do {
    TaskScheduler* scheduler = BasicTaskScheduler::createNew();
    if (scheduler == NULL) break;
    UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
    if (env == NULL) break;

    RTSPClient* rtspClient = NULL;
    SIPClient* sipClient = NULL;

    if (demuxer == NULL || demuxer->stream == NULL) break;  // shouldn't happen
    demuxer->stream->eof = 0; // just in case

    // Look at the stream's 'priv' field to see if we were initiated
    // via a SDP description:
    char* sdpDescription = (char*)(demuxer->stream->priv);
    if (sdpDescription == NULL) {
      // We weren't given a SDP description directly, so assume that
      // we were given a RTSP or SIP URL:
      char const* protocol = demuxer->stream->streaming_ctrl->url->protocol;
      char const* url = demuxer->stream->streaming_ctrl->url->url;
      extern int verbose;
      if (strcmp(protocol, "rtsp") == 0) {
	rtspClient = RTSPClient::createNew(*env, verbose, "MPlayer");
	if (rtspClient == NULL) {
	  fprintf(stderr, "Failed to create RTSP client: %s\n",
		  env->getResultMsg());
	  break;
	}
	sdpDescription = openURL_rtsp(rtspClient, url);
      } else { // SIP
	unsigned char desiredAudioType = 0; // PCMU (use 3 for GSM)
	sipClient = SIPClient::createNew(*env, desiredAudioType, NULL,
					 verbose, "MPlayer");
	if (sipClient == NULL) {
	  fprintf(stderr, "Failed to create SIP client: %s\n",
		  env->getResultMsg());
	  break;
	}
	sipClient->setClientStartPortNum(8000);
	sdpDescription = openURL_sip(sipClient, url);
      }

      if (sdpDescription == NULL) {
	fprintf(stderr, "Failed to get a SDP description from URL \"%s\": %s\n",
		url, env->getResultMsg());
	break;
      }
    }

    // Now that we have a SDP description, create a MediaSession from it:
    MediaSession* mediaSession = MediaSession::createNew(*env, sdpDescription);
    if (mediaSession == NULL) break;


    // Create a 'RTPState' structure containing the state that we just created,
    // and store it in the demuxer's 'priv' field, for future reference:
    RTPState* rtpState = new RTPState;
    rtpState->sdpDescription = sdpDescription;
    rtpState->rtspClient = rtspClient;
    rtpState->sipClient = sipClient;
    rtpState->mediaSession = mediaSession;
    rtpState->audioBufferQueue = rtpState->videoBufferQueue = NULL;
    rtpState->flags = 0;
    rtpState->firstSyncTime.tv_sec = rtpState->firstSyncTime.tv_usec = 0;
    demuxer->priv = rtpState;

    int audiofound = 0, videofound = 0;
    // Create RTP receivers (sources) for each subsession:
    MediaSubsessionIterator iter(*mediaSession);
    MediaSubsession* subsession;
    unsigned desiredReceiveBufferSize;
    while ((subsession = iter.next()) != NULL) {
      // Ignore any subsession that's not audio or video:
      if (strcmp(subsession->mediumName(), "audio") == 0) {
	if (audiofound) {
	  fprintf(stderr, "Additional subsession \"audio/%s\" skipped\n", subsession->codecName());
	  continue;
	}
	desiredReceiveBufferSize = 100000;
      } else if (strcmp(subsession->mediumName(), "video") == 0) {
	if (videofound) {
	  fprintf(stderr, "Additional subsession \"video/%s\" skipped\n", subsession->codecName());
	  continue;
	}
	desiredReceiveBufferSize = 2000000;
      } else {
	continue;
      }

      if (rtsp_port)
          subsession->setClientPortNum (rtsp_port);

      if (!subsession->initiate()) {
	fprintf(stderr, "Failed to initiate \"%s/%s\" RTP subsession: %s\n", subsession->mediumName(), subsession->codecName(), env->getResultMsg());
      } else {
	fprintf(stderr, "Initiated \"%s/%s\" RTP subsession on port %d\n", subsession->mediumName(), subsession->codecName(), subsession->clientPortNum());

	// Set the OS's socket receive buffer sufficiently large to avoid
	// incoming packets getting dropped between successive reads from this
	// subsession's demuxer.  Depending on the bitrate(s) that you expect,
	// you may wish to tweak the "desiredReceiveBufferSize" values above.
	int rtpSocketNum = subsession->rtpSource()->RTPgs()->socketNum();
	int receiveBufferSize
	  = increaseReceiveBufferTo(*env, rtpSocketNum,
				    desiredReceiveBufferSize);
	if (verbose > 0) {
	  fprintf(stderr, "Increased %s socket receive buffer to %d bytes \n",
		  subsession->mediumName(), receiveBufferSize);
	}

	if (rtspClient != NULL) {
	  // Issue a RTSP "SETUP" command on the chosen subsession:
	  if (!rtspClient->setupMediaSubsession(*subsession, False,
						rtsp_transport_tcp)) break;
	  if (!strcmp(subsession->mediumName(), "audio"))
	    audiofound = 1;
	  if (!strcmp(subsession->mediumName(), "video"))
            videofound = 1;
	}
      }
    }

    if (rtspClient != NULL) {
      // Issue a RTSP aggregate "PLAY" command on the whole session:
      if (!rtspClient->playMediaSession(*mediaSession)) break;
    } else if (sipClient != NULL) {
      sipClient->sendACK(); // to start the stream flowing
    }

    // Now that the session is ready to be read, do additional
    // MPlayer codec-specific initialization on each subsession:
    iter.reset();
    while ((subsession = iter.next()) != NULL) {
      if (subsession->readSource() == NULL) continue; // not reading this

      unsigned flags = 0;
      if (strcmp(subsession->mediumName(), "audio") == 0) {
	rtpState->audioBufferQueue
	  = new ReadBufferQueue(subsession, demuxer, "audio");
	rtpState->audioBufferQueue->otherQueue = &(rtpState->videoBufferQueue);
	rtpCodecInitialize_audio(demuxer, subsession, flags);
      } else if (strcmp(subsession->mediumName(), "video") == 0) {
	rtpState->videoBufferQueue
	  = new ReadBufferQueue(subsession, demuxer, "video");
	rtpState->videoBufferQueue->otherQueue = &(rtpState->audioBufferQueue);
	rtpCodecInitialize_video(demuxer, subsession, flags);
      }
      rtpState->flags |= flags;
    }
    success = True;
  } while (0);
  if (!success) return NULL; // an error occurred

  // Hack: If audio and video are demuxed together on a single RTP stream,
  // then create a new "demuxer_t" structure to allow the higher-level
  // code to recognize this:
  if (demux_is_multiplexed_rtp_stream(demuxer)) {
    stream_t* s = new_ds_stream(demuxer->video);
    demuxer_t* od = demux_open(opts, s, DEMUXER_TYPE_UNKNOWN,
			       opts->audio_id, opts->video_id, opts->sub_id,
                               NULL);
    demuxer = new_demuxers_demuxer(od, od, od);
  }

  return demuxer;
}
Ejemplo n.º 5
0
Boolean MediaSubsession::initiate(int useSpecialRTPoffset) {
  if (fReadSource != NULL) return True; // has already been initiated

  do {
    if (fCodecName == NULL) {
      env().setResultMsg("Codec is unspecified");
      break;
    }

    // Create RTP and RTCP 'Groupsocks' on which to receive incoming data.
    // (Groupsocks will work even for unicast addresses)
    struct in_addr tempAddr;
    tempAddr.s_addr = connectionEndpointAddress();
        // This could get changed later, as a result of a RTSP "SETUP"

    if (fClientPortNum != 0) {
      // The sockets' port numbers were specified for us.  Use these:
      Boolean const protocolIsRTP = strcmp(fProtocolName, "RTP") == 0;
      if (protocolIsRTP) {
	fClientPortNum = fClientPortNum&~1; // use an even-numbered port for RTP, and the next (odd-numbered) port for RTCP
      }
      if (isSSM()) {
	fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, fClientPortNum);
      } else {
	fRTPSocket = new Groupsock(env(), tempAddr, fClientPortNum, 255);
      }
      if (fRTPSocket == NULL) {
	env().setResultMsg("Failed to create RTP socket");
	break;
      }
      
      if (protocolIsRTP) {
	// Set our RTCP port to be the RTP port +1
	portNumBits const rtcpPortNum = fClientPortNum|1;
	if (isSSM()) {
	  fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
	} else {
	  fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
	}
      }
    } else {
      // Port numbers were not specified in advance, so we use ephemeral port numbers.
      // Create sockets until we get a port-number pair (even: RTP; even+1: RTCP).
      // We need to make sure that we don't keep trying to use the same bad port numbers over and over again.
      // so we store bad sockets in a table, and delete them all when we're done.
      HashTable* socketHashTable = HashTable::create(ONE_WORD_HASH_KEYS);
      if (socketHashTable == NULL) break;
      Boolean success = False;
      NoReuse dummy(env()); // ensures that our new ephemeral port number won't be one that's already in use

      while (1) {
	// Create a new socket:
	if (isSSM()) {
	  fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, 0);
	} else {
	  fRTPSocket = new Groupsock(env(), tempAddr, 0, 255);
	}
	if (fRTPSocket == NULL) {
	  env().setResultMsg("MediaSession::initiate(): unable to create RTP and RTCP sockets");
	  break;
	}

	// Get the client port number, and check whether it's even (for RTP):
	Port clientPort(0);
	if (!getSourcePort(env(), fRTPSocket->socketNum(), clientPort)) {
	  break;
	}
	fClientPortNum = ntohs(clientPort.num()); 
	if ((fClientPortNum&1) != 0) { // it's odd
	  // Record this socket in our table, and keep trying:
	  unsigned key = (unsigned)fClientPortNum;
	  Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket);
	  delete existing; // in case it wasn't NULL
	  continue;
	}

	// Make sure we can use the next (i.e., odd) port number, for RTCP:
	portNumBits rtcpPortNum = fClientPortNum|1;
	if (isSSM()) {
	  fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
	} else {
	  fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
	}
	if (fRTCPSocket != NULL && fRTCPSocket->socketNum() >= 0) {
	  // Success! Use these two sockets.
	  success = True;
	  break;
	} else {
	  // We couldn't create the RTCP socket (perhaps that port number's already in use elsewhere?).
	  delete fRTCPSocket;

	  // Record the first socket in our table, and keep trying:
	  unsigned key = (unsigned)fClientPortNum;
	  Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket);
	  delete existing; // in case it wasn't NULL
	  continue;
	}
      }

      // Clean up the socket hash table (and contents):
      Groupsock* oldGS;
      while ((oldGS = (Groupsock*)socketHashTable->RemoveNext()) != NULL) {
	delete oldGS;
      }
      delete socketHashTable;

      if (!success) break; // a fatal error occurred trying to create the RTP and RTCP sockets; we can't continue
    }

    // Try to use a big receive buffer for RTP - at least 0.1 second of
    // specified bandwidth and at least 50 KB
    unsigned rtpBufSize = fBandwidth * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes
    if (rtpBufSize < 50 * 1024)
      rtpBufSize = 50 * 1024;
    increaseReceiveBufferTo(env(), fRTPSocket->socketNum(), rtpBufSize);

    if (isSSM() && fRTCPSocket != NULL) {
      // Special case for RTCP SSM: Send RTCP packets back to the source via unicast:
      fRTCPSocket->changeDestinationParameters(fSourceFilterAddr,0,~0);
    }

    // Create "fRTPSource" and "fReadSource":
    if (!createSourceObjects(useSpecialRTPoffset)) break;

    if (fReadSource == NULL) {
      env().setResultMsg("Failed to create read source");
      break;
    }

    // Finally, create our RTCP instance. (It starts running automatically)
    if (fRTPSource != NULL && fRTCPSocket != NULL) {
      // If bandwidth is specified, use it and add 5% for RTCP overhead.
      // Otherwise make a guess at 500 kbps.
      unsigned totSessionBandwidth
	= fBandwidth ? fBandwidth + fBandwidth / 20 : 500;
      fRTCPInstance = RTCPInstance::createNew(env(), fRTCPSocket,
					      totSessionBandwidth,
					      (unsigned char const*)
					      fParent.CNAME(),
					      NULL /* we're a client */,
					      fRTPSource);
      if (fRTCPInstance == NULL) {
	env().setResultMsg("Failed to create RTCP instance");
	break;
      }
    }

    return True;
  } while (0);

  delete fRTPSocket; fRTPSocket = NULL;
  delete fRTCPSocket; fRTCPSocket = NULL;
  Medium::close(fRTCPInstance); fRTCPInstance = NULL;
  Medium::close(fReadSource); fReadSource = fRTPSource = NULL;
  fClientPortNum = 0;
  return False;
}
Ejemplo n.º 6
0
int CLvRtspClient::InitAudio( MediaSubsession *pss )
{_STT();

	if ( !m_pRtspClient )
	{	setLastError( -200, oexT( "Invalid rtsp client object" ) );
		return 0;
	} // end if

	if ( !pss )
	{	setLastError( -201, oexT( "Invalid video object" ) );
		return 0;
	} // end if

	// Create receiver for stream
	if ( !pss->initiate() )
	{	setLastError( -203, sqbind::oex2std( oexMks( oexT( "initiate() video stream failed : " ), oexT( " : " ), m_pEnv->getResultMsg() ) ) );
		return 0;
	} // end if

	if ( !pss->rtpSource() )
	{	setLastError( -204, sqbind::oex2std( oexMks( oexT( "RTP source is null : " ), oexT( " : " ), m_pEnv->getResultMsg() ) ) );
		return 0;
	} // end if

	if ( oex::CStr8( "MP4A-LATM" ) == pss->codecName() )
	{
		((MPEG4LATMAudioRTPSource*)pss->rtpSource())->omitLATMDataLengthField();

		const char *pCfg = pss->fmtp_config();
		if ( pCfg )
		{	unsigned elen = 0;
			unsigned char *pExtra = parseStreamMuxConfigStr( pCfg, elen );
			if ( pExtra && elen )
				m_extraAudio.AppendBuffer( (const char*)pExtra, elen );

		} // end if

	} // end if

	else if ( oex::CStr8( "MPEG4-GENERIC" ) == pss->codecName() )
	{
		const char *pCfg = pss->fmtp_config();
		if ( pCfg )
		{	unsigned elen = 0;
			unsigned char *pExtra = parseGeneralConfigStr( pCfg, elen );
			if ( pExtra && elen )
				m_extraAudio.AppendBuffer( (const char*)pExtra, elen );

		} // end if

	} // end if

	// Read extradata
    const char *props = pss->fmtp_spropparametersets();
    if ( props )
    {	oex::TList< oex::CStr8 > lst = oex::CParser::Explode( props, oexT( "," ) );
        for ( oex::TList< oex::CStr8 >::iterator it; lst.Next( it ); )
        {	m_extraAudio.AppendBuffer( "\x00\x00\x01", 3 );
            m_extraAudio.Mem().appendString( oex::CBase64::Decode( *it ) );
        } // end for
    } // end if

	// Set minimum rx buffer size
	if ( 2000000 > m_nRxBufferSize )
		m_nRxBufferSize = 2000000;

	// Set rx buffer size
	int sn = pss->rtpSource()->RTPgs()->socketNum();
	increaseReceiveBufferTo( *m_pEnv, sn, m_nRxBufferSize );

	pss->rtpSource()->setPacketReorderingThresholdTime( 2000000 );

	if ( pss->codecName() )
		m_sAudioCodec = oexMbToStrPtr( pss->codecName() );

	if ( !m_pRtspClient->setupMediaSubsession( *pss, False, False ) )
	{	setLastError( -205, sqbind::oex2std( oexMks( oexT( "setupMediaSubsession() failed : " ), oexT( " : " ), m_pEnv->getResultMsg() ) ) );
		return 0;
	} // end if

	// Save away important audio parameters
	m_nAudioNumChannels = pss->numChannels();
	m_nAudioRate = pss->rtpTimestampFrequency();
	m_nAudioBps = 0;

	m_pAs = new CAudioSink( *m_pEnv );
	if ( !m_pAs )
	{	setLastError( -206, sqbind::oex2std( oexMks( oexT( "CAudioSink::createNew() failed : " ), oexT( " : " ), m_pEnv->getResultMsg() ) ) );
		return 0;
	} // end if

	m_pAs->setDataEvent( &m_evtData );
	m_pAsPss = pss;

	return 1;
}
Ejemplo n.º 7
0
int CLvRtspClient::InitVideo( MediaSubsession *pss )
{_STT();

	if ( !m_pRtspClient )
	{	setLastError( -100, oexT( "Invalid rtsp client object" ) );
		return 0;
	} // end if

	if ( !pss )
	{	setLastError( -101, oexT( "Invalid video object" ) );
		return 0;
	} // end if

	// Create receiver for stream
	if ( !pss->initiate() )
	{	setLastError( -102, sqbind::oex2std( oexMks( oexT( "initiate() video stream failed : " ), m_pEnv->getResultMsg() ) ) );
		return 0;
	} // end if

	if ( !pss->rtpSource() )
	{	setLastError( -103, sqbind::oex2std( oexMks( oexT( "RTP source is null : " ), m_pEnv->getResultMsg() ) ) );
		return 0;
	} // end if

	// +++ Think fmtp_config() needs to be handled

	// sprop-parameter-sets= base64(SPS),base64(PPS)[,base64(SEI)]
	const char *props = pss->fmtp_spropparametersets();
	if ( props )
	{	oex::TList< oex::CStr8 > lst = oex::CParser::Explode( props, oexT( "," ) );
		for ( oex::TList< oex::CStr8 >::iterator it; lst.Next( it ); )
		{	m_extraVideo.AppendBuffer( "\x00\x00\x01", 3 );
			m_extraVideo.Mem().appendString( oex::CBase64::Decode( *it ) );
		} // end for
	} // end if
//	oexEcho( oexBinToAsciiHexStr( m_extraVideo.Mem(), 0, 16, 16 ).Ptr() );

	// Try to get the image width / height
	m_width = pss->videoWidth();
	m_height = pss->videoWidth();
	m_fps = pss->videoFPS();

	// a=framesize:96 176-144
	if ( !m_width || !m_height )
	{	sqbind::stdString s = m_mSdp[ oexT( "a=framesize" ) ].str();
		if ( s.length() )
		{	oex::TList< oex::CStr > lst = oex::CParser::Split( s.c_str(), s.length(), oexT( " " ) );
			if ( 1 < lst.Size() )
			{	oex::TList< oex::CStr > nums = oex::CParser::Split( lst[ 1 ]->Ptr(), lst[ 1 ]->Length(), oexT( "-" ) );
				if ( 1 < nums.Size() )
					m_width = nums[ 0 ]->ToLong(),
					m_height = nums[ 1 ]->ToLong();
			} // end if
		} // end if
	} // end if

	// a=cliprect:0,0,144,176
	if ( !m_width || !m_height )
	{	sqbind::stdString s = m_mSdp[ oexT( "a=cliprect" ) ].str();
		if ( s.length() )
		{	oex::TList< oex::CStr > nums = oex::CParser::Split( s.c_str(), s.length(), oexT( "," ) );
			if ( 3 < nums.Size() )
				m_width = nums[ 3 ]->ToLong(),
				m_height = nums[ 2 ]->ToLong();
		} // end if
	} // end if

	// a=framerate:30
	if ( !m_fps )
		m_fps = m_mSdp[ oexT( "a=framerate" ) ].toint();

	// a=maxprate:30
	if ( !m_fps )
		m_fps = m_mSdp[ oexT( "a=maxprate" ) ].toint();

	// Set minimum rx buffer size
	if ( 2000000 > m_nRxBufferSize )
		m_nRxBufferSize = 2000000;

	// Set rx buffer size
	int sn = pss->rtpSource()->RTPgs()->socketNum();
	increaseReceiveBufferTo( *m_pEnv, sn, m_nRxBufferSize );

	pss->rtpSource()->setPacketReorderingThresholdTime( 2000000 );

	if ( pss->codecName() )
		m_sVideoCodec = oexMbToStrPtr( pss->codecName() );

	if ( !m_pRtspClient->setupMediaSubsession( *pss, m_bStreamOverTCP, False ) )
	{	setLastError( -103, sqbind::oex2std( oexMks( oexT( "setupMediaSubsession() failed, Codec : " ), m_sVideoCodec.c_str(), oexT( " : " ), m_pEnv->getResultMsg() ) ) );
		return 0;
	} // end if

	m_pVs = new CVideoSink( *m_pEnv );
	if ( !m_pVs )
	{	setLastError( -104, sqbind::oex2std( oexMks( oexT( "CVideoSink::createNew() failed" ), oexT( " : " ), m_pEnv->getResultMsg() ) ) );
		return 0;
	} // end if

	m_pVs->setDataEvent( &m_evtData );
	m_pVsPss = pss;

	return 1;
}
Ejemplo n.º 8
0
bool CRTSPClient::OpenStream(char* url)
{
  LogDebug("CRTSPClient::OpenStream()");
  m_session=NULL;
	
  strcpy(m_url,url);
  // Open the URL, to get a SDP description: 
  char* sdpDescription= getSDPDescriptionFromURL(m_ourClient, url, ""/*username*/, ""/*password*/,""/*proxyServerName*/, 0/*proxyServerPortNum*/,1234/*desiredPortNum*/);
  if (sdpDescription == NULL) 
  {
    LogDebug("Failed to get a SDP description from URL %s %s",url ,m_env->getResultMsg() );
    shutdown();
    return false;
  }
  //LogDebug("Opened URL %s %s",url,sdpDescription);

  char* range=strstr(sdpDescription,"a=range:npt=");
  if (range!=NULL)
  {
    char *pStart = range+strlen("a=range:npt=");
    char *pEnd = strstr(range,"-") ;
    if (pEnd!=NULL)
    {
      pEnd++ ;
      double Start=atof(pStart) ;
      double End=atof(pEnd) ;

      LogDebug("rangestart:%f rangeend:%f", Start,End);
      m_duration=((End-Start)*1000.0);
    }
  }
  // Create a media session object from this SDP description:
  m_session = MediaSession::createNew(*m_env, sdpDescription);
  delete[] sdpDescription;
  if (m_session == NULL) 
  {
    LogDebug("Failed to create a MediaSession object from the SDP description:%s ",m_env->getResultMsg());
    shutdown();
    return false;
  } 
  else if (!m_session->hasSubsessions()) 
  {
    LogDebug("This session has no media subsessions");
    shutdown();
    return false;
  }

  // Then, setup the "RTPSource"s for the session:
  MediaSubsessionIterator iter(*m_session);
  MediaSubsession *subsession;
  Boolean madeProgress = False;
  char const* singleMediumToTest = singleMedium;
  while ((subsession = iter.next()) != NULL) 
  {
    // If we've asked to receive only a single medium, then check this now:
    if (singleMediumToTest != NULL) 
    {
      if (strcmp(subsession->mediumName(), singleMediumToTest) != 0) 
      {
        LogDebug("Ignoring %s %s %s" , subsession->mediumName(),subsession->codecName(),singleMedium);
        continue;
      } 
      else 
      {
        // Receive this subsession only
        singleMediumToTest = "xxxxx";
        // this hack ensures that we get only 1 subsession of this type
      }
    }
    if (desiredPortNum != 0) 
    {
      subsession->setClientPortNum(desiredPortNum);
      desiredPortNum += 2;
    }

    if (createReceivers) 
    {
      if (!subsession->initiate(simpleRTPoffsetArg)) 
      {
        LogDebug("Unable to create receiver for %s %s %s" ,subsession->mediumName(),subsession->codecName(),m_env->getResultMsg());
      } 
      else 
      {
        LogDebug("Created receiver for %s %s %d %d " ,subsession->mediumName(),subsession->codecName(),subsession->clientPortNum(),subsession->clientPortNum()+1 );
        madeProgress = True;

        if (subsession->rtpSource() != NULL) 
        {
          // Because we're saving the incoming data, rather than playing
          // it in real time, allow an especially large time threshold
          // (1 second) for reordering misordered incoming packets:
          
          int socketNum= subsession->rtpSource()->RTPgs()->socketNum();
          LogDebug("rtsp:increaseReceiveBufferTo to 2000000 for s:%d",socketNum);
          increaseReceiveBufferTo( *m_env, socketNum, 2000000 );

          unsigned const thresh = 1000000; // 1 second 
          subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);

          if (socketInputBufferSize > 0) 
          {
            // Set the RTP source's input buffer size as specified:
            int socketNum= subsession->rtpSource()->RTPgs()->socketNum();
            unsigned curBufferSize= getReceiveBufferSize(*m_env, socketNum);
            unsigned newBufferSize= setReceiveBufferTo(*m_env, socketNum, socketInputBufferSize);
            LogDebug( "Changed socket receive buffer size for the %s %s %d %d",
            subsession->mediumName(),subsession->codecName(),curBufferSize,newBufferSize);
          }
        }
      }
    } 
    else 
    {
      if (subsession->clientPortNum() == 0) 
      {
        LogDebug("No client port was specified for the %s %s",subsession->mediumName(),subsession->codecName());
      } 
      else 
      {	
        madeProgress = True;
      }
    }
  }
  if (!madeProgress) 
  {
    shutdown();
    return false;
  }
	
  // Perform additional 'setup' on each subsession, before playing them:
  if (!setupStreams())
  {
    return false;
  }

  // Create output files:
  // Create and start "FileSink"s for each subsession:
  madeProgress = False;
  iter.reset();
  while ((subsession = iter.next()) != NULL) 
  {
    if (subsession->readSource() == NULL) continue; // was not initiated
		
    CMemorySink* fileSink= CMemorySink::createNew(*m_env,m_buffer,fileSinkBufferSize);
    subsession->sink = fileSink;
    if (subsession->sink == NULL) 
    {
      LogDebug("Failed to create FileSink %s",m_env->getResultMsg());
      shutdown();
      return false;
    } 
    LogDebug("Created output sink:");;
    subsession->sink->startPlaying(*(subsession->readSource()),subsessionAfterPlaying,subsession);
				  
    // Also set a handler to be called if a RTCP "BYE" arrives
    // for this subsession:
    if (subsession->rtcpInstance() != NULL) 
    {
      subsession->rtcpInstance()->setByeHandler(subsessionByeHandler,subsession);
    }
    madeProgress = True;
  }

  return true;
}