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

📄 mediasession.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/**********This library is free software; you can redistribute it and/or modify it underthe terms of the GNU Lesser General Public License as published by theFree Software Foundation; either version 2.1 of the License, or (at youroption) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)This library is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License formore details.You should have received a copy of the GNU Lesser General Public Licensealong with this library; if not, write to the Free Software Foundation, Inc.,59 Temple Place, Suite 330, Boston, MA  02111-1307  USA**********/// "liveMedia"// Copyright (c) 1996-2004 Live Networks, Inc.  All rights reserved.// A data structure that represents a session that consists of// potentially multiple (audio and/or video) sub-sessions// Implementation#include "liveMedia.hh"#ifdef SUPPORT_REAL_RTSP#include "../RealRTSP/include/RealRTSP.hh"#endif#include "GroupsockHelper.hh"#include <ctype.h>////////// MediaSession //////////MediaSession* MediaSession::createNew(UsageEnvironment& env,				      char const* sdpDescription) {  MediaSession* newSession = new MediaSession(env);  if (newSession != NULL) {    if (!newSession->initializeWithSDP(sdpDescription)) {      delete newSession;      return NULL;    }  }  return newSession;}Boolean MediaSession::lookupByName(UsageEnvironment& env,				   char const* instanceName,				   MediaSession*& resultSession) {  resultSession = NULL; // unless we succeed  Medium* medium;  if (!Medium::lookupByName(env, instanceName, medium)) return False;  if (!medium->isMediaSession()) {    env.setResultMsg(instanceName, " is not a 'MediaSession' object");    return False;  }  resultSession = (MediaSession*)medium;  return True;}MediaSession::MediaSession(UsageEnvironment& env)  : Medium(env),    fSubsessionsHead(NULL), fSubsessionsTail(NULL),    fConnectionEndpointName(NULL), fMaxPlayEndTime(0.0f), fScale(1.0f) {#ifdef SUPPORT_REAL_RTSP  RealInitSDPAttributes(this);#endif  fSourceFilterAddr.s_addr = 0;  // Get our host name, and use this for the RTCP CNAME:  const unsigned maxCNAMElen = 100;  char CNAME[maxCNAMElen+1];#ifndef CRIS  gethostname((char*)CNAME, maxCNAMElen);#else  // "gethostname()" isn't defined for this platform  sprintf(CNAME, "unknown host %d", (unsigned)(our_random()*0x7FFFFFFF));#endif  CNAME[maxCNAMElen] = '\0'; // just in case  fCNAME = strDup(CNAME);}MediaSession::~MediaSession() {  delete fSubsessionsHead;  delete[] fCNAME;  delete[] fConnectionEndpointName;#ifdef SUPPORT_REAL_RTSP  RealReclaimSDPAttributes(this);#endif}Boolean MediaSession::isMediaSession() const {  return True;}Boolean MediaSession::initializeWithSDP(char const* sdpDescription) {  if (sdpDescription == NULL) return False;  // Begin by processing all SDP lines until we see the first "m="  char const* sdpLine = sdpDescription;  char const* nextSDPLine;  while (1) {    if (!parseSDPLine(sdpLine, nextSDPLine)) return False;    //##### We should really check for:     // - "a=control:" attributes (to set the URL for aggregate control)    // - the correct SDP version (v=0)    if (sdpLine[0] == 'm') break;    sdpLine = nextSDPLine;    if (sdpLine == NULL) break; // there are no m= lines at all     // Check for various special SDP lines that we understand:    if (parseSDPLine_c(sdpLine)) continue;    if (parseSDPAttribute_range(sdpLine)) continue;    if (parseSDPAttribute_source_filter(sdpLine)) continue;#ifdef SUPPORT_REAL_RTSP    if (RealParseSDPAttributes(this, sdpLine)) continue;#endif  }      while (sdpLine != NULL) {    // We have a "m=" line, representing a new sub-session:    MediaSubsession* subsession = new MediaSubsession(*this);    if (subsession == NULL) {      envir().setResultMsg("Unable to create new MediaSubsession");      return False;    }    // Parse the line as "m=<medium_name> <client_portNum> RTP/AVP <fmt>"    // or "m=<medium_name> <client_portNum>/<num_ports> RTP/AVP <fmt>"    // (Should we be checking for >1 payload format number here?)#####    char* mediumName = strDupSize(sdpLine); // ensures we have enough space    char* protocolName = NULL;    unsigned payloadFormat;    if ((sscanf(sdpLine, "m=%s %hu RTP/AVP %u",		mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 ||	 sscanf(sdpLine, "m=%s %hu/%*u RTP/AVP %u",		mediumName, &subsession->fClientPortNum, &payloadFormat) == 3)	&& payloadFormat <= 127) {      protocolName = "RTP";    } else if ((sscanf(sdpLine, "m=%s %hu UDP %u",		       mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 ||		sscanf(sdpLine, "m=%s %hu udp %u",		       mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 ||		sscanf(sdpLine, "m=%s %hu RAW/RAW/UDP %u",		       mediumName, &subsession->fClientPortNum, &payloadFormat) == 3)	       && payloadFormat <= 127) {      // This is a RAW UDP source      protocolName = "UDP";    } else {      // This "m=" line is bad; output an error message saying so:      char* sdpLineStr;      if (nextSDPLine == NULL) {	sdpLineStr = (char*)sdpLine;      } else {	sdpLineStr = strDup(sdpLine);	sdpLineStr[nextSDPLine-sdpLine] = '\0';      }      envir() << "Bad SDP \"m=\" line: " <<  sdpLineStr << "\n";      if (sdpLineStr != (char*)sdpLine) delete[] sdpLineStr;      delete[] mediumName;      delete subsession;      // Skip the following SDP lines, up until the next "m=":      while (1) {	sdpLine = nextSDPLine;	if (sdpLine == NULL) break; // we've reached the end	if (!parseSDPLine(sdpLine, nextSDPLine)) return False;	if (sdpLine[0] == 'm') break; // we've reached the next subsession      }      continue;    }    // Insert this subsession at the end of the list:    if (fSubsessionsTail == NULL) {      fSubsessionsHead = fSubsessionsTail = subsession;    } else {      fSubsessionsTail->setNext(subsession);      fSubsessionsTail = subsession;    }    subsession->serverPortNum = subsession->fClientPortNum; // by default    char const* mStart = sdpLine;    subsession->fSavedSDPLines = strDup(mStart);    subsession->fMediumName = strDup(mediumName);    delete[] mediumName;    subsession->fProtocolName = strDup(protocolName);    subsession->fRTPPayloadFormat = payloadFormat;    // Process the following SDP lines, up until the next "m=":    while (1) {      sdpLine = nextSDPLine;      if (sdpLine == NULL) break; // we've reached the end      if (!parseSDPLine(sdpLine, nextSDPLine)) return False;      if (sdpLine[0] == 'm') break; // we've reached the next subsession      // Check for various special SDP lines that we understand:      if (subsession->parseSDPLine_c(sdpLine)) continue;      if (subsession->parseSDPAttribute_rtpmap(sdpLine)) continue;      if (subsession->parseSDPAttribute_control(sdpLine)) continue;      if (subsession->parseSDPAttribute_range(sdpLine)) continue;      if (subsession->parseSDPAttribute_fmtp(sdpLine)) continue;      if (subsession->parseSDPAttribute_source_filter(sdpLine)) continue;      if (subsession->parseSDPAttribute_x_mct_slap(sdpLine)) continue;      if (subsession->parseSDPAttribute_x_dimensions(sdpLine)) continue;      if (subsession->parseSDPAttribute_x_framerate(sdpLine)) continue;#ifdef SUPPORT_REAL_RTSP      if (RealParseSDPAttributes(subsession, sdpLine)) continue;#endif      // (Later, check for malformed lines, and other valid SDP lines#####)    }    if (sdpLine != NULL) subsession->fSavedSDPLines[sdpLine-mStart] = '\0';    // If we don't yet know the codec name, try looking it up from the    // list of static payload types:    if (subsession->fCodecName == NULL) {      subsession->fCodecName	= lookupPayloadFormat(subsession->fRTPPayloadFormat,			      subsession->fRTPTimestampFrequency,			      subsession->fNumChannels);      if (subsession->fCodecName == NULL) {	char typeStr[20];	sprintf(typeStr, "%d", subsession->fRTPPayloadFormat);	envir().setResultMsg("Unknown codec name for RTP payload type ",			     typeStr);	return False;      }    }    // If we don't yet know this subsession's RTP timestamp frequency    // (because it uses a dynamic payload type and the corresponding    // SDP "rtpmap" attribute erroneously didn't specify it),    // then guess it now:    if (subsession->fRTPTimestampFrequency == 0) {      subsession->fRTPTimestampFrequency	= guessRTPTimestampFrequency(subsession->fMediumName,				     subsession->fCodecName);    }  }  return True;}Boolean MediaSession::parseSDPLine(char const* inputLine,				   char const*& nextLine){  // Begin by finding the start of the next line (if any):  nextLine = NULL;  for (char const* ptr = inputLine; *ptr != '\0'; ++ptr) {    if (*ptr == '\r' || *ptr == '\n') {      // We found the end of the line      ++ptr;      while (*ptr == '\r' || *ptr == '\n') ++ptr;      nextLine = ptr;      if (nextLine[0] == '\0') nextLine = NULL; // special case for end      break;    }  }  // Then, check that this line is a SDP line of the form <char>=<etc>  // (However, we also accept blank lines in the input.)  if (inputLine[0] == '\r' || inputLine[0] == '\n') return True;  if (strlen(inputLine) < 2 || inputLine[1] != '='      || inputLine[0] < 'a' || inputLine[0] > 'z') {    envir().setResultMsg("Invalid SDP line: ", inputLine);    return False;  }  return True;}static char* parseCLine(char const* sdpLine) {  char* resultStr = NULL;  char* buffer = strDupSize(sdpLine); // ensures we have enough space  if (sscanf(sdpLine, "c=IN IP4 %[^/ ]", buffer) == 1) {    // Later, handle the optional /<ttl> and /<numAddresses> #####    resultStr = strDup(buffer);  }  delete[] buffer;  return resultStr;}Boolean MediaSession::parseSDPLine_c(char const* sdpLine) {  // Check for "c=IN IP4 <connection-endpoint>"  // or "c=IN IP4 <connection-endpoint>/<ttl+numAddresses>"  // (Later, do something with <ttl+numAddresses> also #####)  char* connectionEndpointName = parseCLine(sdpLine);  if (connectionEndpointName != NULL) {    delete[] fConnectionEndpointName;    fConnectionEndpointName = connectionEndpointName;    return True;  }  return False;}static Boolean parseRangeAttribute(char const* sdpLine, float& endTime) {  return sscanf(sdpLine, "a=range: npt = %*g - %g", &endTime) == 1;}Boolean MediaSession::parseSDPAttribute_range(char const* sdpLine) {  // Check for a "a=range:npt=<startTime>-<endTime>" line:  // (Later handle other kinds of "a=range" attributes also???#####)  Boolean parseSuccess = False;  float playEndTime;  if (parseRangeAttribute(sdpLine, playEndTime)) {    parseSuccess = True;    if (playEndTime > fMaxPlayEndTime) {      fMaxPlayEndTime = playEndTime;    }  }  return parseSuccess;}static Boolean parseSourceFilterAttribute(char const* sdpLine,					  struct in_addr& sourceAddr) {  // Check for a "a=source-filter:incl IN IP4 <something> <source>" line.  // Note: At present, we don't check that <something> really matches  // one of our multicast addresses.  We also don't support more than  // one <source> #####  Boolean result = False; // until we succeed   char* sourceName = strDupSize(sdpLine); // ensures we have enough space  do {    if (sscanf(sdpLine, "a=source-filter: incl IN IP4 %*s %s",	       sourceName) != 1) break;    // Now, convert this name to an address, if we can:    NetAddressList addresses(sourceName);    if (addresses.numAddresses() == 0) break;    netAddressBits sourceAddrBits      = *(netAddressBits*)(addresses.firstAddress()->data());    if (sourceAddrBits == 0) break;    sourceAddr.s_addr = sourceAddrBits;    result = True;  } while (0);  delete[] sourceName;  return result;}Boolean MediaSession::parseSDPAttribute_source_filter(char const* sdpLine) {  return parseSourceFilterAttribute(sdpLine, fSourceFilterAddr);}char* MediaSession::lookupPayloadFormat(unsigned char rtpPayloadType,					unsigned& freq, unsigned& nCh) {  // Look up the codec name and timestamp frequency for known (static)  // RTP payload formats.  char* temp = NULL;  switch (rtpPayloadType) {  case 0: {temp = "PCMU"; freq = 8000; nCh = 1; break;}  case 2: {temp = "G726-32"; freq = 8000; nCh = 1; break;}  case 3: {temp = "GSM"; freq = 8000; nCh = 1; break;}  case 4: {temp = "G723"; freq = 8000; nCh = 1; break;}  case 5: {temp = "DVI4"; freq = 8000; nCh = 1; break;}  case 6: {temp = "DVI4"; freq = 16000; nCh = 1; break;}  case 7: {temp = "LPC"; freq = 8000; nCh = 1; break;}  case 8: {temp = "PCMA"; freq = 8000; nCh = 1; break;}  case 9: {temp = "G722"; freq = 8000; nCh = 1; break;}  case 10: {temp = "L16"; freq = 44100; nCh = 2; break;}  case 11: {temp = "L16"; freq = 44100; nCh = 1; break;}  case 12: {temp = "QCELP"; freq = 8000; nCh = 1; break;}  case 14: {temp = "MPA"; freq = 90000; nCh = 1; break;}    // 'number of channels' is actually encoded in the media stream  case 15: {temp = "G728"; freq = 8000; nCh = 1; break;}  case 16: {temp = "DVI4"; freq = 11025; nCh = 1; break;}  case 17: {temp = "DVI4"; freq = 22050; nCh = 1; break;}  case 18: {temp = "G729"; freq = 8000; nCh = 1; break;}  case 25: {temp = "CELB"; freq = 90000; nCh = 1; break;}

⌨️ 快捷键说明

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