예제 #1
0
int main(int argc, char** argv)
{
  // Begin by setting up our usage environment:
  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
  env = BasicUsageEnvironment::createNew(*scheduler);

  progName = APP_NAME;
  username = SIP_USERNAME;
  password = SIP_PASSWORD;

  gettimeofday(&startTime, NULL);

#ifdef USE_SIGNALS
  // Allow ourselves to be shut down gracefully by a SIGHUP or a SIGUSR1:
  signal(SIGHUP, signalHandlerShutdown);
  signal(SIGUSR1, signalHandlerShutdown);
#endif

  unsigned short desiredPortNum = 0;

//// unfortunately we can't use getopt() here, as Windoze doesn't have it
//while (argc > 2) {
//  char* const opt = argv[1];
//  if (opt[0] != '-') usage();
//  switch (opt[1]) {
//
//    case 'p': { // specify start port number
//      int portArg;
//      if (sscanf(argv[2], "%d", &portArg) != 1) {
//        usage();
//      }
//      if ((portArg <= 0) || (portArg >= 65536) || (portArg&1)) {
//        *env << "bad port number: " << portArg
//             << " (must be even, and in the range (0,65536))\n";
//        usage();
//      }
//      desiredPortNum = (unsigned short)portArg;
//      ++argv; --argc;
//      break;
//    }
//
//    case 'r': { // do not receive data (instead, just 'play' the stream(s))
//      createReceivers = False;
//      break;
//    }
//
//    case 'q': { // output a QuickTime file (to stdout)
//      outputQuickTimeFile = True;
//      break;
//    }
//
//    case '4': { // output a 'mp4'-format file (to stdout)
//      outputQuickTimeFile = True;
//      generateMP4Format = True;
//      break;
//    }
//
//    case 'i': { // output an AVI file (to stdout)
//      outputAVIFile = True;
//      break;
//    }
//
//    case 'I': { // specify input interface...
//      NetAddressList addresses(argv[2]);
//      if (addresses.numAddresses() == 0) {
//        *env << "Failed to find network address for \"" << argv[2] << "\"";
//        break;
//      }
//      ReceivingInterfaceAddr = *(unsigned*)(addresses.firstAddress()->data());
//      ++argv; --argc;
//      break;
//    }
//
//    case 'a': { // receive/record an audio stream only
//      audioOnly = True;
//      singleMedium = "audio";
//      break;
//    }
//
//    case 'v': { // receive/record a video stream only
//      videoOnly = True;
//      singleMedium = "video";
//      break;
//    }
//
//    case 'V': { // disable verbose output
//      verbosityLevel = 0;
//      break;
//    }
//
//    case 'd': { // specify duration, or how much to delay after end time
//      float arg;
//      if (sscanf(argv[2], "%g", &arg) != 1) {
//        usage();
//      }
//      if (argv[2][0] == '-') { // not "arg<0", in case argv[2] was "-0"
//        // a 'negative' argument was specified; use this for "durationSlop":
//        duration = 0; // use whatever's in the SDP
//        durationSlop = -arg;
//      } else {
//        duration = arg;
//        durationSlop = 0;
//      }
//      ++argv; --argc;
//      break;
//    }
//
//    case 'D': { // specify maximum number of seconds to wait for packets:
//      if (sscanf(argv[2], "%u", &interPacketGapMaxTime) != 1) {
//        usage();
//      }
//      ++argv; --argc;
//      break;
//    }
//
//    case 'c': { // play continuously
//      playContinuously = True;
//      break;
//    }
//
//    case 'S': { // specify an offset to use with "SimpleRTPSource"s
//      if (sscanf(argv[2], "%d", &simpleRTPoffsetArg) != 1) {
//        usage();
//      }
//      if (simpleRTPoffsetArg < 0) {
//        *env << "offset argument to \"-S\" must be >= 0\n";
//        usage();
//      }
//      ++argv; --argc;
//      break;
//    }
//
//    case 'O': { // Don't send an "OPTIONS" request before "DESCRIBE"
//      sendOptionsRequest = False;
//      break;
//    }
//
//    case 'o': { // Send only the "OPTIONS" request to the server
//      sendOptionsRequestOnly = True;
//      break;
//    }
//
//    case 'm': { // output multiple files - one for each frame
//      oneFilePerFrame = True;
//      break;
//    }
//
//    case 'n': { // notify the user when the first data packet arrives
//      notifyOnPacketArrival = True;
//      break;
//    }
//
//    case 't': {
//      // stream RTP and RTCP over the TCP 'control' connection
//      if (controlConnectionUsesTCP) {
//        streamUsingTCP = True;
//      } else {
//        usage();
//      }
//      break;
//    }
//
//    case 'T': {
//      // stream RTP and RTCP over a HTTP connection
//      if (controlConnectionUsesTCP) {
//        if (argc > 3 && argv[2][0] != '-') {
//          // The next argument is the HTTP server port number:
//          if (sscanf(argv[2], "%hu", &tunnelOverHTTPPortNum) == 1
//              && tunnelOverHTTPPortNum > 0) {
//            ++argv; --argc;
//            break;
//          }
//        }
//      }
//
//      // If we get here, the option was specified incorrectly:
//      usage();
//      break;
//    }
//
//    case 'u': { // specify a username and password
//      username = argv[2];
//      password = argv[3];
//      argv+=2; argc-=2;
//      if (allowProxyServers && argc > 3 && argv[2][0] != '-') {
//        // The next argument is the name of a proxy server:
//        proxyServerName = argv[2];
//        ++argv; --argc;
//
//        if (argc > 3 && argv[2][0] != '-') {
//          // The next argument is the proxy server port number:
//          if (sscanf(argv[2], "%hu", &proxyServerPortNum) != 1) {
//            usage();
//          }
//          ++argv; --argc;
//        }
//      }
//      break;
//    }
//
//    case 'A': { // specify a desired audio RTP payload format
//      unsigned formatArg;
//      if (sscanf(argv[2], "%u", &formatArg) != 1 || formatArg >= 96) {
//        usage();
//      }
//      desiredAudioRTPPayloadFormat = (unsigned char)formatArg;
//      ++argv; --argc;
//      break;
//    }
//
//    case 'M': { // specify a MIME subtype for a dynamic RTP payload type
//      mimeSubtype = argv[2];
//      if (desiredAudioRTPPayloadFormat==0) desiredAudioRTPPayloadFormat = 96;
//      ++argv; --argc;
//      break;
//    }
//
//    case 'w': {
//      // specify a width (pixels) for an output QuickTime or AVI movie
//      if (sscanf(argv[2], "%hu", &movieWidth) != 1) {
//        usage();
//      }
//      movieWidthOptionSet = True;
//      ++argv; --argc;
//      break;
//    }
//
//    case 'h': {
//      // specify a height (pixels) for an output QuickTime or AVI movie
//      if (sscanf(argv[2], "%hu", &movieHeight) != 1) {
//        usage();
//      }
//      movieHeightOptionSet = True;
//      ++argv; --argc;
//      break;
//    }
//
//    case 'f': {
//      // specify a frame rate (per second) for an output QT or AVI movie
//      if (sscanf(argv[2], "%u", &movieFPS) != 1) {
//        usage();
//      }
//      movieFPSOptionSet = True;
//      ++argv; --argc;
//      break;
//    }
//
//    case 'F': { // specify a prefix for the audio and video output files
//      fileNamePrefix = argv[2];
//      ++argv; --argc;
//      break;
//    }
//
//    case 'b': { // specify the size of buffers for "FileSink"s
//      if (sscanf(argv[2], "%u", &fileSinkBufferSize) != 1) {
//        usage();
//      }
//      ++argv; --argc;
//      break;
//    }
//
//    case 'B': { // specify the size of input socket buffers
//      if (sscanf(argv[2], "%u", &socketInputBufferSize) != 1) {
//        usage();
//      }
//      ++argv; --argc;
//      break;
//    }
//
//    // Note: The following option is deprecated, and may someday be removed:
//    case 'l': { // try to compensate for packet loss by repeating frames
//      packetLossCompensate = True;
//      break;
//    }
//
//    case 'y': { // synchronize audio and video streams
//      syncStreams = True;
//      break;
//    }
//
//    case 'H': { // generate hint tracks (as well as the regular data tracks)
//      generateHintTracks = True;
//      break;
//    }
//
//    case 'Q': { // output QOS measurements
//      qosMeasurementIntervalMS = 1000; // default: 1 second
//
//      if (argc > 3 && argv[2][0] != '-') {
//        // The next argument is the measurement interval,
//        // in multiples of 100 ms
//        if (sscanf(argv[2], "%u", &qosMeasurementIntervalMS) != 1) {
//          usage();
//        }
//        qosMeasurementIntervalMS *= 100;
//        ++argv; --argc;
//      }
//      break;
//    }
//
//    case 's': { // specify initial seek time (trick play)
//      double arg;
//      if (sscanf(argv[2], "%lg", &arg) != 1 || arg < 0) {
//        usage();
//      }
//      initialSeekTime = arg;
//      ++argv; --argc;
//      break;
//    }
//
//    case 'z': { // scale (trick play)
//      float arg;
//      if (sscanf(argv[2], "%g", &arg) != 1 || arg == 0.0f) {
//        usage();
//      }
//      scale = arg;
//      ++argv; --argc;
//      break;
//    }
//
//    default: {
//      usage();
//      break;
//    }
//  }
//
//  ++argv; --argc;
//}
//if (argc != 2) usage();
//if (outputQuickTimeFile && outputAVIFile) {
//  *env << "The -i and -q (or -4) flags cannot both be used!\n";
//  usage();
//}
//Boolean outputCompositeFile = outputQuickTimeFile || outputAVIFile;
//if (!createReceivers && outputCompositeFile) {
//  *env << "The -r and -q (or -4 or -i) flags cannot both be used!\n";
//  usage();
//}
//if (outputCompositeFile && !movieWidthOptionSet) {
//  *env << "Warning: The -q, -4 or -i option was used, but not -w.  Assuming a video width of "
//      << movieWidth << " pixels\n";
//}
//if (outputCompositeFile && !movieHeightOptionSet) {
//  *env << "Warning: The -q, -4 or -i option was used, but not -h.  Assuming a video height of "
//      << movieHeight << " pixels\n";
//}
//if (outputCompositeFile && !movieFPSOptionSet) {
//  *env << "Warning: The -q, -4 or -i option was used, but not -f.  Assuming a video frame rate of "
//      << movieFPS << " frames-per-second\n";
//}
//if (audioOnly && videoOnly) {
//  *env << "The -a and -v flags cannot both be used!\n";
//  usage();
//}
//if (sendOptionsRequestOnly && !sendOptionsRequest) {
//  *env << "The -o and -O flags cannot both be used!\n";
//  usage();
//}
//if (tunnelOverHTTPPortNum > 0) {
//  if (streamUsingTCP) {
//    *env << "The -t and -T flags cannot both be used!\n";
//    usage();
//  } else {
//    streamUsingTCP = True;
//  }
//}
//if (!createReceivers && notifyOnPacketArrival) {
//  *env << "Warning: Because we're not receiving stream data, the -n flag has no effect\n";
//}
//if (durationSlop < 0) {
//  // This parameter wasn't set, so use a default value.
//  // If we're measuring QOS stats, then don't add any slop, to avoid
//  // having 'empty' measurement intervals at the end.
//  durationSlop = qosMeasurementIntervalMS > 0 ? 0.0 : 5.0;
//}

  char* url = SIP_URL;

  // Create our client object:
  ourClient = createClient(*env, verbosityLevel, progName);
  if (ourClient == NULL) {
    *env << "Failed to create " << clientProtocolName
        << " client: " << env->getResultMsg() << "\n";
    shutdown();
  }

  if (sendOptionsRequest) {
    // Begin by sending an "OPTIONS" command:
    char* optionsResponse
    = getOptionsResponse(ourClient, url, username, password);
    if (sendOptionsRequestOnly) {
      if (optionsResponse == NULL) {
        *env << clientProtocolName << " \"OPTIONS\" request failed: "
            << env->getResultMsg() << "\n";
      } else {
        *env << clientProtocolName << " \"OPTIONS\" request returned: "
            << optionsResponse << "\n";
      }
      shutdown();
    }
    delete[] optionsResponse;
  }

  // Open the URL, to get a SDP description:
  char* sdpDescription
  = getSDPDescriptionFromURL(ourClient, url, username, password,
                             proxyServerName, proxyServerPortNum,
                             desiredPortNum);
  if (sdpDescription == NULL) {
    *env << "Failed to get a SDP description from URL \"" << url
        << "\": " << env->getResultMsg() << "\n";
    shutdown();
  }

  *env << "Opened URL \"" << url
      << "\", returning a SDP description:\n" << sdpDescription << "\n";

//  // Create a media session object from this SDP description:
//  session = MediaSession::createNew(*env, sdpDescription);
//  delete[] sdpDescription;
//  if (session == NULL) {
//    *env << "Failed to create a MediaSession object from the SDP description: "
//         << env->getResultMsg() << "\n";
//    shutdown();
//  } else if (!session->hasSubsessions()) {
//    *env << "This session has no media subsessions (i.e., \"m=\" lines)\n";
//    shutdown();
//  }
//
//  // Then, setup the "RTPSource"s for the session:
//  MediaSubsessionIterator iter(*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) {
//        *env << "Ignoring \"" << subsession->mediumName()
//             << "/" << subsession->codecName()
//             << "\" subsession, because we've asked to receive a single "
//             << singleMedium
//             << " session only\n";
//        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)) {
//        *env << "Unable to create receiver for \"" << subsession->mediumName()
//                     << "/" << subsession->codecName()
//                     << "\" subsession: " << env->getResultMsg() << "\n";
//      } else {
//        *env << "Created receiver for \"" << subsession->mediumName()
//             << "/" << subsession->codecName()
//             << "\" subsession (client ports " << subsession->clientPortNum()
//             << "-" << subsession->clientPortNum()+1 << ")\n";
//        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:
//          unsigned const thresh = 1000000; // 1 second
//          subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
//
//          // Set the RTP source's OS socket buffer size as appropriate - either if we were explicitly asked (using -B),
//          // or if the desired FileSink buffer size happens to be larger than the current OS socket buffer size.
//          // (The latter case is a heuristic, on the assumption that if the user asked for a large FileSink buffer size,
//          // then the input data rate may be large enough to justify increasing the OS socket buffer size also.)
//          int socketNum = subsession->rtpSource()->RTPgs()->socketNum();
//          unsigned curBufferSize = getReceiveBufferSize(*env, socketNum);
//          if (socketInputBufferSize > 0 ||
//              fileSinkBufferSize > curBufferSize) {
//            unsigned newBufferSize = ((socketInputBufferSize) > 0 ?
//                                      socketInputBufferSize :
//                                      fileSinkBufferSize);
//            newBufferSize = setReceiveBufferTo(*env, socketNum, newBufferSize);
//            if (socketInputBufferSize > 0) { // The user explicitly asked for the new socket buffer size; announce it:
//              *env << "Changed socket receive buffer size for the \""
//                   << subsession->mediumName()
//                   << "/" << subsession->codecName()
//                   << "\" subsession from "
//                   << curBufferSize << " to "
//                   << newBufferSize << " bytes\n";
//            }
//          }
//        }
//      }
//    } else {
//      if (subsession->clientPortNum() == 0) {
//        *env << "No client port was specified for the \""
//             << subsession->mediumName()
//             << "/" << subsession->codecName()
//             << "\" subsession.  (Try adding the \"-p <portNum>\" option.)\n";
//      } else {
//        madeProgress = True;
//      }
//    }
//  }
//  if (!madeProgress) shutdown();
//
//  // Perform additional 'setup' on each subsession, before playing them:
//  setupStreams();
//
//  // Create output files:
//  if (createReceivers) {
//    if (outputQuickTimeFile) {
//      // Create a "QuickTimeFileSink", to write to 'stdout':
//      qtOut = QuickTimeFileSink::createNew(*env, *session, "stdout",
//                                           fileSinkBufferSize,
//                                           movieWidth, movieHeight,
//                                           movieFPS,
//                                           packetLossCompensate,
//                                           syncStreams,
//                                           generateHintTracks,
//                                           generateMP4Format);
//      if (qtOut == NULL) {
//        *env << "Failed to create QuickTime file sink for stdout: "
//             << env->getResultMsg();
//        shutdown();
//      }
//
//      qtOut->startPlaying(sessionAfterPlaying, NULL);
//    } else if (outputAVIFile) {
//      // Create an "AVIFileSink", to write to 'stdout':
//      aviOut = AVIFileSink::createNew(*env, *session, "stdout",
//                                      fileSinkBufferSize,
//                                      movieWidth, movieHeight,
//                                      movieFPS,
//                                      packetLossCompensate);
//      if (aviOut == NULL) {
//        *env << "Failed to create AVI file sink for stdout: "
//             << env->getResultMsg();
//        shutdown();
//      }
//
//      aviOut->startPlaying(sessionAfterPlaying, NULL);
//#ifdef SUPPORT_REAL_RTSP
//    } else if (session->isRealNetworksRDT) {
//      // For RealNetworks' sessions, we create a single output file,
//      // named "output.rm".
//      char outFileName[1000];
//      if (singleMedium == NULL) {
//        snprintf(outFileName, sizeof(outFileName),
//                 "%soutput.rm", fileNamePrefix);
//      } else {
//        // output to 'stdout' as normal, even though we actually output all media
//        sprintf(outFileName, "stdout");
//      }
//      FileSink* fileSink = FileSink::createNew(*env, outFileName,
//                                               fileSinkBufferSize,
//                                               oneFilePerFrame);
//
//      // The output file needs to begin with a special 'RMFF' header,
//      // in order for it to be usable.  Write this header first:
//      unsigned headerSize;
//      unsigned char* headerData = RealGenerateRMFFHeader(session, headerSize);
//      struct timeval timeNow;
//      gettimeofday(&timeNow, NULL);
//      fileSink->addData(headerData, headerSize, timeNow);
//      delete[] headerData;
//
//      // Start playing the output file from the first subsession.
//      // (Hack: Because all subsessions' data is actually multiplexed on the
//      // single RTSP TCP connection, playing from one subsession is sufficient.)
//      iter.reset();
//      madeProgress = False;
//      while ((subsession = iter.next()) != NULL) {
//        if (subsession->readSource() == NULL) continue; // was not initiated
//
//        fileSink->startPlaying(*(subsession->readSource()),
//                               subsessionAfterPlaying, subsession);
//        madeProgress = True;
//        break; // play from one subsession only
//      }
//      if (!madeProgress) shutdown();
//#endif
//    } else {
//      // 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
//
//        // Create an output file for each desired stream:
//        char outFileName[1000];
//        if (singleMedium == NULL) {
//          // Output file name is
//          // "<filename-prefix><medium_name>-<codec_name>-<counter>"
//          static unsigned streamCounter = 0;
//          snprintf(outFileName, sizeof outFileName, "%s%s-%s-%d",
//                   fileNamePrefix, subsession->mediumName(),
//                   subsession->codecName(), ++streamCounter);
//        } else {
//          sprintf(outFileName, "stdout");
//        }
//        FileSink* fileSink;
//        if (strcmp(subsession->mediumName(), "audio") == 0 &&
//            (strcmp(subsession->codecName(), "AMR") == 0 ||
//                strcmp(subsession->codecName(), "AMR-WB") == 0)) {
//          // For AMR audio streams, we use a special sink that inserts AMR frame hdrs:
//          fileSink = AMRAudioFileSink::createNew(*env, outFileName,
//                                                 fileSinkBufferSize,
//                                                 oneFilePerFrame);
//        } else if (strcmp(subsession->mediumName(), "video") == 0 &&
//            (strcmp(subsession->codecName(), "H264") == 0)) {
//          // For H.264 video stream, we use a special sink that insert start_codes:
//          fileSink = H264VideoFileSink::createNew(*env, outFileName,
//                                                  fileSinkBufferSize,
//                                                  oneFilePerFrame);
//        } else {
//          // Normal case:
//          fileSink = FileSink::createNew(*env, outFileName,
//                                         fileSinkBufferSize,
//                                         oneFilePerFrame);
//        }
//        subsession->sink = fileSink;
//        if (subsession->sink == NULL) {
//          *env << "Failed to create FileSink for \"" << outFileName
//              << "\": " << env->getResultMsg() << "\n";
//        } else {
//          if (singleMedium == NULL) {
//            *env << "Created output file: \"" << outFileName << "\"\n";
//          } else {
//            *env << "Outputting data from the \"" << subsession->mediumName()
//                                << "/" << subsession->codecName()
//                                << "\" subsession to 'stdout'\n";
//          }
//
//          if (strcmp(subsession->mediumName(), "video") == 0 &&
//              strcmp(subsession->codecName(), "MP4V-ES") == 0 &&
//              subsession->fmtp_config() != NULL) {
//            // For MPEG-4 video RTP streams, the 'config' information
//            // from the SDP description contains useful VOL etc. headers.
//            // Insert this data at the front of the output file:
//            unsigned configLen;
//            unsigned char* configData
//            = parseGeneralConfigStr(subsession->fmtp_config(), configLen);
//            struct timeval timeNow;
//            gettimeofday(&timeNow, NULL);
//            fileSink->addData(configData, configLen, timeNow);
//            delete[] configData;
//          }
//
//          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;
//        }
//      }
//      if (!madeProgress) shutdown();
//    }
//  }
//
//  // Finally, start playing each subsession, to start the data flow:
//
//  startPlayingStreams();
//
//  env->taskScheduler().doEventLoop(); // does not return

  return 0; // only to prevent compiler warning
}
예제 #2
0
int CMediaNet::MediaNet_Thread( void * pThisVoid )
{
	CMediaNet *pThis = ( CMediaNet* )pThisVoid;

	do 
	{
		// 开始初始化.
		pThis->SetRtspStatus( RTSPStatus_Init );

		// Begin by setting up our usage environment:
		TaskScheduler* scheduler = BasicTaskScheduler::createNew();
		env = BasicUsageEnvironment::createNew(*scheduler);

		progName = "M_CU";

		string strUrl = pThis->m_strRTSPUrlA;

		gettimeofday(&startTime, NULL);

		unsigned short desiredPortNum = 0;

		// unfortunately we can't use getopt() here, as Windoze doesn't have it

		// Create our client object:
		ourClient = createClient(*env, verbosityLevel, progName);
		if (ourClient == NULL) 
		{
			*env << "Failed to create " << clientProtocolName
				<< " client: " << env->getResultMsg() << "\n";

			pThis->SetRtspStatus( RTSPStatus_Error_Connect_Srv );
			break;
		}

		// 开始获取Opition.
		pThis->SetRtspStatus( RTSPStatus_Opitiion );
		// Begin by sending an "OPTIONS" command:
		char* optionsResponse
			= getOptionsResponse(ourClient, pThis->m_strRTSPUrlA.c_str(), username, password);

		if (optionsResponse == NULL) 
		{
			*env << clientProtocolName << " \"OPTIONS\" request failed: "
				<< env->getResultMsg() << "\n";

			pThis->SetRtspStatus( RTSPStatus_Error_Connect_Srv );
			break;
		} 
		else 
		{
			*env << clientProtocolName << " \"OPTIONS\" request returned: "
				<< optionsResponse << "\n";
		}
		if( optionsResponse )
		{
			delete[] optionsResponse;
		}
			

		// 开始获取Description.
		// Open the URL, to get a SDP description:
		pThis->SetRtspStatus( RTSPStatus_Description );
		char* sdpDescription
			= getSDPDescriptionFromURL(ourClient, pThis->m_strRTSPUrlA.c_str(), username, password,
			proxyServerName, proxyServerPortNum,
			desiredPortNum);
		if (sdpDescription == NULL) 
		{
			*env << "Failed to get a SDP description from URL \"" << pThis->m_strRTSPUrlA.c_str()
				<< "\": " << env->getResultMsg() << "\n";
			pThis->SetRtspStatus( RTSPStatus_Error_Connect_Srv );
			break;
		}

		*env << "Opened URL \"" << pThis->m_strRTSPUrlA.c_str()
			<< "\", returning a SDP description:\n" << sdpDescription << "\n";

		// Create a media session object from this SDP description:
		session = MediaSession::createNew(*env, sdpDescription);
		delete[] sdpDescription;
		if (session == NULL) 
		{
			*env << "Failed to create a MediaSession object from the SDP description: " << env->getResultMsg() << "\n";
			pThis->SetRtspStatus( RTSPStatus_Error_Connect_Srv );
			break;
		} 
		else if (!session->hasSubsessions()) 
		{
			*env << "This session has no media subsessions (i.e., \"m=\" lines)\n";
			pThis->SetRtspStatus( RTSPStatus_Error_Connect_Srv );
			break;
		}

		// Then, setup the "RTPSource"s for the session:
		MediaSubsessionIterator iter(*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) 
				{
					*env << "Ignoring \"" << subsession->mediumName()
						<< "/" << subsession->codecName()
						<< "\" subsession, because we've asked to receive a single " << singleMedium
						<< " session only\n";
					continue;
				} 
				else 
				{
					// Receive this subsession only
					singleMediumToTest = "xxxxx";
					// this hack ensures that we get only 1 subsession of this type
				}
			}

			desiredPortNum = 0;
			if (desiredPortNum != 0) 
			{
				subsession->setClientPortNum(desiredPortNum);
				desiredPortNum += 2;
			}

			if (true) 
			{
				if (!subsession->initiate(simpleRTPoffsetArg)) 
				{
					*env << "Unable to create receiver for \"" << subsession->mediumName()
						<< "/" << subsession->codecName()
						<< "\" subsession: " << env->getResultMsg() << "\n";
				} 
				else 
				{
					*env << "Created receiver for \"" << subsession->mediumName()
						<< "/" << subsession->codecName()
						<< "\" subsession (client ports " << subsession->clientPortNum()
						<< "-" << subsession->clientPortNum()+1 << ")\n";
					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:
						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(*env, socketNum);
							unsigned newBufferSize
								= setReceiveBufferTo(*env, socketNum, socketInputBufferSize);
							*env << "Changed socket receive buffer size for the \""
								<< subsession->mediumName()
								<< "/" << subsession->codecName()
								<< "\" subsession from "
								<< curBufferSize << " to "
								<< newBufferSize << " bytes\n";
						}
					}
				}
			} 
			else 
			{
				mcu::tlog << _T( "Use port: " ) << (int)subsession->clientPortNum() << endl;
				if (subsession->clientPortNum() == 0) 
				{
					*env << "No client port was specified for the \""
						<< subsession->mediumName()
						<< "/" << subsession->codecName()
						<< "\" subsession.  (Try adding the \"-p <portNum>\" option.)\n";
				} 
				else 
				{
					madeProgress = True;
				}
			}
		}
		if (!madeProgress) 
			break;

		// Perform additional 'setup' on each subsession, before playing them:
		pThis->SetRtspStatus( RTSPStatus_Setup );
		unsigned nResponseCode = NULL;
		BOOL bSetupSuccess = setupStreams( &nResponseCode );
		if ( !bSetupSuccess )
		{
			// setup失败!
			if ( RTSPResp_Error_Server_Full == nResponseCode )
			{
				pThis->SetRtspStatus( RTSPStatus_Error_Server_Full );
			}
			else
			{
				pThis->SetRtspStatus( RTSPStatus_Idle );
			}
			break;
		}
		// Create output files:
		
		if ( true  ) 
		{
				// 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

					MediaSink *pDecodeSink = 0;
					if (strcmp(subsession->mediumName(), "video") == 0 )
					{
						int nBandWidth = subsession->GetBandWidth();

						if ( strcmp(subsession->codecName(), "MP4V-ES") == 0 )
						{
							CMpeg4StreamDecodeSink *pMsds = CMpeg4StreamDecodeSink::CreateNew( *env, 20000, nBandWidth );
							 pDecodeSink = pMsds;
							
						}
						else if ( strcmp( subsession->codecName(), "H264" ) == 0 )
						{
							 CH264StreamDecodeSink *pHsds = CH264StreamDecodeSink::CreateNew( *env, 20000, nBandWidth );
							 pDecodeSink = pHsds;
						}
						else
						{
							continue;
						}
					}				

					subsession->sink = pDecodeSink;
					if (subsession->sink == NULL) 
					{
						*env << "Failed to create CH264StreamDecodeSink \""  << "\n";
					} 


					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);
					}

					// 发送NAT探测包。
					unsigned char temp[112] = {0};
					temp[0] = 0x80;
					subsession->rtpSource()->RTPgs()->output( *env, 0,temp, 112 );

					madeProgress = True;
				}
			}


		// Finally, start playing each subsession, to start the data flow:
		pThis->SetRtspStatus( RTSPStatus_Play );
		startPlayingStreams();


		pThis->SetRtspStatus( RTSPStatus_Running );
		// 传入结束标志指针。 
		env->taskScheduler().doEventLoop( &pThis->m_runFlag ); 

		pThis->SetRtspStatus( RTSPStatus_Idle );

	} while(0);	

	return 0;
}
예제 #3
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;
}