⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 playcommon.cpp

📁 Live media server used to transfer mpeg or other video/audio media
💻 CPP
📖 第 1 页 / 共 4 页
字号:
      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 'R': { // inject received data into a RTSP server      destRTSPURL = argv[2];      ++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 (destRTSPURL != NULL && (!createReceivers || outputCompositeFile)) {    *env << "The -R flag cannot be used with -r, -q, or -i!\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 (endTimeSlop < 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.    endTimeSlop = qosMeasurementIntervalMS > 0 ? 0.0 : 5.0;  }  char* url = argv[1];  // 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);    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);		  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 {      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 if (destRTSPURL != NULL) {      // Announce the session into a (separate) RTSP server,      // and create one or more "RTPTranslator"s to tie the source      // and destination together:      if (setupDestinationRTSPServer()) {		  *env << "Set up destination RTSP session for \"" << destRTSPURL << "\"\n";      } else {		  *env << "Failed to set up destination RTSP session for \"" << destRTSPURL			  << "\": " << env->getResultMsg() << "\n";		shutdown();      }    } 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 {	  // 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;	  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -