[Live-devel] patch for rtspclient to support speed header

Anon Sricharoenchai anon.hui at gmail.com
Thu Jun 25 04:35:12 PDT 2009


Hi,

rtspclient should support "Speed: " header.
It is easy to implement.
The attached file is the patch for this.

Thank you,
Anon.
-------------- next part --------------
diff -urN liblivemedia-2008.07.25.orig/liveMedia/MediaSession.cpp liblivemedia-2008.07.25.develop/liveMedia/MediaSession.cpp
--- liblivemedia-2008.07.25.orig/liveMedia/MediaSession.cpp	2008-07-25 07:40:05.000000000 +0700
+++ liblivemedia-2008.07.25.develop/liveMedia/MediaSession.cpp	2009-06-25 14:44:39.000000000 +0700
@@ -63,7 +63,7 @@
   : Medium(env),
     fSubsessionsHead(NULL), fSubsessionsTail(NULL),
     fConnectionEndpointName(NULL), fMaxPlayStartTime(0.0f), fMaxPlayEndTime(0.0f),
-    fScale(1.0f), fMediaSessionType(NULL), fSessionName(NULL), fSessionDescription(NULL),
+    fSpeed(1.0f), fScale(1.0f), fMediaSessionType(NULL), fSessionName(NULL), fSessionDescription(NULL),
     fControlPath(NULL) {
 #ifdef SUPPORT_REAL_RTSP
   RealInitSDPAttributes(this);
@@ -549,7 +549,7 @@
     fCpresent(False), fRandomaccessindication(False),
     fConfig(NULL), fMode(NULL), fSpropParameterSets(NULL),
     fPlayStartTime(0.0), fPlayEndTime(0.0),
-    fVideoWidth(0), fVideoHeight(0), fVideoFPS(0), fNumChannels(1), fScale(1.0f), fNPT_PTS_Offset(0.0f),
+    fVideoWidth(0), fVideoHeight(0), fVideoFPS(0), fNumChannels(1), fSpeed(1.0f), fScale(1.0f), fNPT_PTS_Offset(0.0f),
     fRTPSocket(NULL), fRTCPSocket(NULL),
     fRTPSource(NULL), fRTCPInstance(NULL), fReadSource(NULL) {
   rtpInfo.seqNum = 0; rtpInfo.timestamp = 0; rtpInfo.infoIsNew = False;
diff -urN liblivemedia-2008.07.25.orig/liveMedia/RTSPClient.cpp liblivemedia-2008.07.25.develop/liveMedia/RTSPClient.cpp
--- liblivemedia-2008.07.25.orig/liveMedia/RTSPClient.cpp	2008-07-25 07:40:05.000000000 +0700
+++ liblivemedia-2008.07.25.develop/liveMedia/RTSPClient.cpp	2009-06-25 18:16:08.000000000 +0700
@@ -1011,6 +1011,28 @@
   return False;
 }
 
+static char* createSpeedString(float speed, float currentSpeed) {
+  char buf[100];
+  if (speed == 1.0f && currentSpeed == 1.0f) {
+    // This is the default value; we don't need a "Speed:" header:
+    buf[0] = '\0';
+  } else {
+    Locale("C", LC_NUMERIC);
+    // Eventhough the default decimal-point is 6, but there's no limit on big
+    // value.
+    // While this may not be injected by streaming server.
+    // But the client application may be injected in some situation, for
+    // example,
+    // * One may write some web application that accept the query,
+    //   "rtsp-proxy.cgi?speed=2.0&url=...".  rtsp-proxy.cgi may call
+    //   this rtsp client library with arbitrary speed value, without knowing
+    //   what range of value is safe.
+    snprintf(buf, sizeof(buf)/sizeof(buf[0]), "Speed: %f\r\n", speed);
+  }
+
+  return strDup(buf);
+}
+      
 static char* createScaleString(float scale, float currentScale) {
   char buf[100];
   if (scale == 1.0f && currentScale == 1.0f) {
@@ -1045,7 +1067,8 @@
 static char const* NoSessionErr = "No RTSP session is currently in progress\n";
 
 Boolean RTSPClient::playMediaSession(MediaSession& session,
-				     float start, float end, float scale) {
+				     float start, float end,
+				     float scale, float speed) {
 #ifdef SUPPORT_REAL_RTSP
   if (session.isRealNetworksRDT) {
     // This is a RealNetworks stream; set the "Subscribe" parameter before proceeding:
@@ -1067,6 +1090,8 @@
     // First, construct an authenticator string:
     char* authenticatorStr
       = createAuthenticatorString(&fCurrentAuthenticator, "PLAY", fBaseURL);
+    // And then a "Speed:" string:
+    char* speedStr = createSpeedString(speed, session.speed());
     // And then a "Scale:" string:
     char* scaleStr = createScaleString(scale, session.scale());
     // And then a "Range:" string:
@@ -1080,6 +1105,7 @@
       "%s"
       "%s"
       "%s"
+      "%s"
       "\r\n";
 
     char const* sessURL = sessionURL(session);
@@ -1087,6 +1113,7 @@
       + strlen(sessURL)
       + 20 /* max int len */
       + strlen(fLastSessionId)
+      + strlen(speedStr)
       + strlen(scaleStr)
       + strlen(rangeStr)
       + strlen(authenticatorStr)
@@ -1096,10 +1123,12 @@
 	    sessURL,
 	    ++fCSeq,
 	    fLastSessionId,
+	    speedStr,
 	    scaleStr,
 	    rangeStr,
 	    authenticatorStr,
 	    fUserAgentHeaderStr);
+    delete[] speedStr;
     delete[] scaleStr;
     delete[] rangeStr;
     delete[] authenticatorStr;
@@ -1119,6 +1148,7 @@
 
       nextLineStart = getLine(lineStart);
 
+      if (parseSpeedHeader(lineStart, session.speed())) continue;
       if (parseScaleHeader(lineStart, session.scale())) continue;
       if (parseRangeHeader(lineStart, session.playStartTime(), session.playEndTime())) continue;
 
@@ -1153,7 +1183,8 @@
 }
 
 Boolean RTSPClient::playMediaSubsession(MediaSubsession& subsession,
-					float start, float end, float scale,
+					float start, float end,
+					float scale, float speed,
 					Boolean hackForDSS) {
   char* cmd = NULL;
   do {
@@ -1168,6 +1199,8 @@
     // First, construct an authenticator string:
     char* authenticatorStr
       = createAuthenticatorString(&fCurrentAuthenticator, "PLAY", fBaseURL);
+    // And then a "Speed:" string:
+    char* speedStr = createSpeedString(speed, subsession.speed());
     // And then a "Scale:" string:
     char* scaleStr = createScaleString(scale, subsession.scale());
     // And then a "Range:" string:
@@ -1181,6 +1214,7 @@
       "%s"
       "%s"
       "%s"
+      "%s"
       "\r\n";
 
     char const *prefix, *separator, *suffix;
@@ -1197,6 +1231,7 @@
       + strlen(prefix) + strlen(separator) + strlen(suffix)
       + 20 /* max int len */
       + strlen(subsession.sessionId)
+      + strlen(speedStr)
       + strlen(scaleStr)
       + strlen(rangeStr)
       + strlen(authenticatorStr)
@@ -1206,10 +1241,12 @@
 	    prefix, separator, suffix,
 	    ++fCSeq,
 	    subsession.sessionId,
+	    speedStr,
 	    scaleStr,
 	    rangeStr,
 	    authenticatorStr,
 	    fUserAgentHeaderStr);
+    delete[] speedStr;
     delete[] scaleStr;
     delete[] rangeStr;
     delete[] authenticatorStr;
@@ -1229,6 +1266,7 @@
 
       nextLineStart = getLine(lineStart);
 
+      if (parseSpeedHeader(lineStart, subsession.speed())) continue;
       if (parseScaleHeader(lineStart, subsession.scale())) continue;
       if (parseRangeHeader(lineStart, subsession._playStartTime(), subsession._playEndTime())) continue;
 
@@ -2302,6 +2340,14 @@
   return True;
 }
 
+Boolean RTSPClient::parseSpeedHeader(char const* line, float& speed) {
+  if (_strncasecmp(line, "Speed: ", 7) != 0) return False;
+  line += 7;
+
+  Locale("C", LC_NUMERIC);
+  return sscanf(line, "%f", &speed) == 1;
+}
+
 Boolean RTSPClient::parseScaleHeader(char const* line, float& scale) {
   if (_strncasecmp(line, "Scale: ", 7) != 0) return False;
   line += 7;
diff -urN liblivemedia-2008.07.25.orig/liveMedia/include/MediaSession.hh liblivemedia-2008.07.25.develop/liveMedia/include/MediaSession.hh
--- liblivemedia-2008.07.25.orig/liveMedia/include/MediaSession.hh	2008-07-25 07:40:05.000000000 +0700
+++ liblivemedia-2008.07.25.develop/liveMedia/include/MediaSession.hh	2009-06-25 14:33:33.000000000 +0700
@@ -44,6 +44,7 @@
   char* connectionEndpointName() const { return fConnectionEndpointName; }
   char const* CNAME() const { return fCNAME; }
   struct in_addr const& sourceFilterAddr() const { return fSourceFilterAddr; }
+  float& speed() { return fSpeed; }
   float& scale() { return fScale; }
   char* mediaSessionType() const { return fMediaSessionType; }
   char* sessionName() const { return fSessionName; }
@@ -103,6 +104,7 @@
   float fMaxPlayStartTime;
   float fMaxPlayEndTime;
   struct in_addr fSourceFilterAddr; // used for SSM
+  float fSpeed; // set from a RTSP "Speed:" header
   float fScale; // set from a RTSP "Scale:" header
   char* fMediaSessionType; // holds a=type value
   char* fSessionName; // holds s=<session name> value
@@ -143,6 +145,7 @@
   unsigned short videoHeight() const { return fVideoHeight; }
   unsigned videoFPS() const { return fVideoFPS; }
   unsigned numChannels() const { return fNumChannels; }
+  float& speed() { return fSpeed; }
   float& scale() { return fScale; }
 
   RTPSource* rtpSource() { return fRTPSource; }
@@ -293,6 +296,7 @@
      // frame rate (set by an optional "a=framerate: <fps>" or "a=x-framerate: <fps>" line)
   unsigned fNumChannels;
      // optionally set by "a=rtpmap:" lines for audio sessions.  Default: 1
+  float fSpeed; // set from a RTSP "Speed:" header
   float fScale; // set from a RTSP "Scale:" header
   double fNPT_PTS_Offset; // set by "getNormalPlayTime()"; add this to a PTS to get NPT
 
diff -urN liblivemedia-2008.07.25.orig/liveMedia/include/RTSPClient.hh liblivemedia-2008.07.25.develop/liveMedia/include/RTSPClient.hh
--- liblivemedia-2008.07.25.orig/liveMedia/include/RTSPClient.hh	2008-07-25 07:40:05.000000000 +0700
+++ liblivemedia-2008.07.25.develop/liveMedia/include/RTSPClient.hh	2009-06-25 14:30:49.000000000 +0700
@@ -90,13 +90,13 @@
 
   Boolean playMediaSession(MediaSession& session,
 			   float start = 0.0f, float end = -1.0f,
-			   float scale = 1.0f);
+			   float scale = 1.0f, float speed = 1.0f);
       // Issues an aggregate RTSP "PLAY" command on "session".
       // Returns True iff this command succeeds
       // (Note: start=-1 means 'resume'; end=-1 means 'play to end')
   Boolean playMediaSubsession(MediaSubsession& subsession,
 			      float start = 0.0f, float end = -1.0f,
-			      float scale = 1.0f,
+			      float scale = 1.0f, float speed = 1.0f,
 			      Boolean hackForDSS = False);
       // Issues a RTSP "PLAY" command on "subsession".
       // Returns True iff this command succeeds
@@ -184,6 +184,7 @@
 				 unsigned char& rtpChannelId,
 				 unsigned char& rtcpChannelId);
   Boolean parseRTPInfoHeader(char*& line, u_int16_t& seqNum, u_int32_t& timestamp);
+  Boolean parseSpeedHeader(char const* line, float& speed);
   Boolean parseScaleHeader(char const* line, float& scale);
   Boolean parseGetParameterHeader(char const* line, 
                                   const char* param,
diff -urN liblivemedia-2008.07.25.orig/testProgs/openRTSP.cpp liblivemedia-2008.07.25.develop/testProgs/openRTSP.cpp
--- liblivemedia-2008.07.25.orig/testProgs/openRTSP.cpp	2008-07-25 07:40:05.000000000 +0700
+++ liblivemedia-2008.07.25.develop/testProgs/openRTSP.cpp	2009-06-25 14:54:18.000000000 +0700
@@ -60,7 +60,7 @@
 
 Boolean clientStartPlayingSession(Medium* client,
 				  MediaSession* session) {
-  extern double initialSeekTime, duration, scale;
+  extern double initialSeekTime, duration, scale, speed;
   double endTime = initialSeekTime;
   if (scale > 0) {
     if (duration <= 0) endTime = -1.0f;
@@ -72,7 +72,7 @@
 
   if (client == NULL || session == NULL) return False;
   RTSPClient* rtspClient = (RTSPClient*)client;
-  return rtspClient->playMediaSession(*session, (float)initialSeekTime, (float)endTime, (float)scale);
+  return rtspClient->playMediaSession(*session, (float)initialSeekTime, (float)endTime, (float)scale, (float)speed);
 }
 
 Boolean clientTearDownSession(Medium* client,
diff -urN liblivemedia-2008.07.25.orig/testProgs/playCommon.cpp liblivemedia-2008.07.25.develop/testProgs/playCommon.cpp
--- liblivemedia-2008.07.25.orig/testProgs/playCommon.cpp	2008-07-25 07:40:05.000000000 +0700
+++ liblivemedia-2008.07.25.develop/testProgs/playCommon.cpp	2009-06-25 14:53:53.000000000 +0700
@@ -68,6 +68,7 @@
 double durationSlop = -1.0; // extra seconds to play at the end
 double initialSeekTime = 0.0f;
 double scale = 1.0f;
+double speed = 1.0f;
 unsigned interPacketGapMaxTime = 0;
 unsigned totNumPacketsReceived = ~0; // used if checking inter-packet gaps
 Boolean playContinuously = False;
@@ -108,7 +109,7 @@
        << " [-u <username> <password>"
 	   << (allowProxyServers ? " [<proxy-server> [<proxy-server-port>]]" : "")
        << "]" << (supportCodecSelection ? " [-A <audio-codec-rtp-payload-format-code>|-M <mime-subtype-name>]" : "")
-       << " [-s <initial-seek-time>] [-z <scale>]"
+       << " [-s <initial-seek-time>] [-z <scale>] [-Z <bandwidth-scale>]"
        << " [-w <width> -h <height>] [-f <frames-per-second>] [-y] [-H] [-Q [<measurement-interval>]] [-F <filename-prefix>] [-b <file-sink-buffer-size>] [-B <input-socket-buffer-size>] [-I <input-interface-ip-address>] [-m] <url> (or " << progName << " -o [-V] <url>)\n";
   //##### Add "-R <dest-rtsp-url>" #####
   shutdown();
@@ -429,6 +430,16 @@
       break;
     }
 
+    case 'Z': { // speed (trick play)
+      float arg;
+      if (sscanf(argv[2], "%g", &arg) != 1 || arg == 0.0f) {
+	usage();
+      }
+      speed = arg;
+      ++argv; --argc;
+      break;
+    }
+
     default: {
       usage();
       break;


More information about the live-devel mailing list