ffmpeg for pseudo live with protected publish stream

Hello,

I try to use ffmpeg to stream a file to a live stream like this

ffmpeg -i mytestfile.flv -re -sameq -acodec copy -vcodec copy -f flv rtmp://localhost/live/myStream.sdp

I protected live-Application publishing with login and pass like it is described in the media security addon. With flash media encoder it works fine, but i cant connect with ffmpeg to the publishing interface - i tried many combinations for command line options but nothing works.

Please help - how can ffmpeg authentificate to wowza?

Best regards

I suspect that ffmpeg does not have the authentication method build in.

You could just get Wowza to stream out the file as if it were live, using the Stream Class ?

See here for how to

https://www.wowza.com/docs/how-to-do-basic-server-side-publishing-with-stream-class-streams

Shamrock

Rowland,

How is security configured? ModuleRTMPAuthenticate with secureTokenSharedSecret Property?

It might work with ModuleSecureToken and secureTokenSharedSecret Property.

I think you could use SecureURLParams to secure publishing in this case. See the doc in the old version (for Wowza 1.7) of MediaSecurity:

https://www.wowza.com/downloads/forums/mediasecurity/MediaSecurity.zip

Richard

You can use ModuleSecureURLParams with ffmpeg:

https://www.wowza.com/docs/how-to-secure-publishing-from-an-rtmp-encoder-that-does-not-support-authentication-modulesecureurlparams

There are links to pre-built ffmpeg that will work:

https://www.wowza.com/docs/how-to-use-ffmpeg-with-wowza-media-server-mpeg-ts)

Richard

I don’t know. I found this comment:

http://lists.mplayerhq.hu/pipermail/rtmpdump/2010-June/000983.html

SecureURLParams is a pretty good alternative. It is the method for publishing security in Wowza 1x

Richard

I would give it to you if I knew what it was. I wish I did, assuming it was easy which is what I like about those pre-built ffmpeg builds.

Richard

Due to things like network latency, client-side buffering, and a number of other challenges it’s virtually impossible to have streaming clients getting the exact same video frames at exactly the same time, but they’ll usually be pretty close (within a minute or so of each other).

You may want to try a live-lowlatency application type if you need them to be in closer sync.

-Ian

There is no simple way to Sync clients as they will buffer differently so never be 100% synced.

Shamrock

Steve, we can confirm it all works once the command line is quoted. As follows:

ffmpeg -i <INPUTFILE> -vcodec libx264 -re -vpre medium -acodec libfaac -ab 64k -f flv "<PUBLISH PATH>  flashver=FMLE/3.0\20(compatible;)FMSc/1.0\29 pubUser=<USERNAME> pubPasswd=<PASSWORD>"

Cheers,

Rajiv

librtmp does not contain any authentication methods. The easier way it to use RTSP. This way you can use authentication in the URL as such rtsp://:@. If you require using RTMP then you will need to patch librtmp, recompile it and then rebuild ffmpeg.

Here is the patch that I used. You will need to do some manual patching if you apply this to the current release.

Index: librtmp/rtmp.c
===================================================================
--- librtmp/rtmp.c	(revision 513)
+++ librtmp/rtmp.c	(working copy)
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#include <time.h>
 
 #include "rtmp_sys.h"
 #include "log.h"
@@ -34,11 +35,18 @@
 #ifdef CRYPTO
 #ifdef USE_POLARSSL
 #include <polarssl/havege.h>
+#include <polarssl/md5.h>
+#include <polarssl/base64.h>
+#define MD5_DIGEST_LENGTH 16
 #elif defined(USE_GNUTLS)
 #include <gnutls/gnutls.h>
+#include <gnutls/openssl.h>
 #else	/* USE_OPENSSL */
 #include <openssl/ssl.h>
 #include <openssl/rc4.h>
+#include <openssl/md5.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
 #endif
 TLS_CTX RTMP_TLS_ctx;
 #endif
@@ -491,6 +499,10 @@
   	"Buffer time in milliseconds" },
   { AVC("timeout"),   OFF(Link.timeout),       OPT_INT, 0,
   	"Session timeout in seconds" },
+  { AVC("pubUser"),   OFF(Link.pubUser),     OPT_STR, 0,
+      "Publisher username" },
+  { AVC("pubPasswd"),   OFF(Link.pubPasswd), OPT_STR, 0,
+      "Publisher password" },
   { {NULL,0}, 0, 0}
 };
 
@@ -2221,6 +2233,241 @@
   free(vals);
 }
 
+
+#ifdef CRYPTO
+static int
+b64enc(const unsigned char *input, int length, char *output, int maxsize)
+{
+#ifdef USE_POLARSSL
+  int buf_size = maxsize;
+  if(base64_encode((unsigned char *) output, &buf_size, input, length) == 0)
+    {
+      output[buf_size] = '\0';
+      return 1;
+    }
+  else
+    {
+      RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
+      return 0;
+    }
+#elif defined(USE_GNUTLS)
+    //TODO: gnutls have SRP-base64 encoder, use it if possible
+  static const char b64str[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  while (length && maxsize)
+    {
+      *output++ = b64str[(input[0] >> 2) & 0x3f];
+      if (!--maxsize)
+          break;
+      *output++ = b64str[((input[0] << 4) + (--length ? input[1] >> 4 : 0)) & 0x3f];
+      if (!--maxsize)
+          break;
+      *output++ = (length ? b64str[((input[1] << 2) + (--length ? input[2] >> 6 : 0)) & 0x3f] : '=');
+      if (!--maxsize)
+          break;
+      *output++ = length ? b64str[input[2] & 0x3f] : '=';
+      if (!--maxsize)
+          break;
+      if (length)
+          length--;
+      if (length)
+          input += 3;
+    }
+  if (maxsize)
+      *output = '\0';
+#else   /* USE_OPENSSL */
+  BIO *bmem, *b64;
+  BUF_MEM *bptr;
+
+  b64 = BIO_new(BIO_f_base64());
+  bmem = BIO_new(BIO_s_mem());
+  b64 = BIO_push(b64, bmem);
+  BIO_write(b64, input, length);
+  if (BIO_flush(b64) == 1)
+    {
+      BIO_get_mem_ptr(b64, &bptr);
+      memcpy(output, bptr->data, bptr->length-1);
+      output[bptr->length-1] = '\0';
+    }
+  else
+    {
+      RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
+      return 0;
+    }
+  BIO_free_all(b64);
+#endif
+  return 1;
+}
+
+#ifdef USE_POLARSSL
+#define md5sum(x,y,z)  md5(x,y,z);
+#else
+#define md5sum(x,y,z)  MD5(x,y,z);
+#endif
+
+static const AVal av_authmod_adboe = AVC("authmod=adobe");
+
+static int
+PublisherAuth(RTMP *r, AVal *description)
+{
+  char *token_in = NULL;
+  char *ptr;
+  unsigned char md5sum_val[MD5_DIGEST_LENGTH+1];
+  int challenge2_data;
+#define RESPONSE_LEN 32
+#define CHALLENGE2_LEN 16
+#define SALTED2_LEN (32+8+8+8)
+  char response[RESPONSE_LEN];
+  char challenge2[CHALLENGE2_LEN];
+  char salted2[SALTED2_LEN];
+  AVal pubToken;
+
+  if (strstr(description->av_val, av_authmod_adboe.av_val) != NULL)
+    {
+      if(strstr(description->av_val, "code=403 need auth") != NULL)
+        {
+            if (strstr(r->Link.app.av_val, av_authmod_adboe.av_val) != NULL) {
+              RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+              return 0;
+            } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) {
+              pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_adboe.av_len + 8);
+              pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
+                      av_authmod_adboe.av_val,
+                      r->Link.pubUser.av_val);
+              RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
+              r->Link.pFlags |= RTMP_PUB_NAME;
+            } else {
+              RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+              return 0;
+            }
+        }
+      else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
+        {
+          ptr = strdup(token_in);
+          char *par, *val = NULL;
+          char *user = NULL;
+          char *salt = NULL;
+          char *opaque = NULL;
+          char *salted1;
+
+          while (ptr)
+            {
+              par = ptr;
+              ptr = strchr(par, '&');
+              if(ptr)
+                  *ptr++ = '\0';
+
+              val =  strchr(par, '=');
+              if(val)
+                  *val++ = '\0';
+
+              if (strcmp(par, "user") == 0){
+                  user = val;
+              } else if (strcmp(par, "salt") == 0){
+                  salt = val;
+              } else if (strcmp(par, "opaque") == 0){
+                  opaque = val;
+              }
+
+              RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
+            }
+
+            /* hash1 = base64enc(md5(user + _aodbeAuthSalt + password)) */
+            salted1 = malloc(strlen(user)+strlen(salt)+r->Link.pubPasswd.av_len+1);
+            strcpy(salted1, user);
+            strcat(salted1, salt);
+            strcat(salted1, r->Link.pubPasswd.av_val);
+            md5sum((unsigned char*) salted1, strlen(salted1), md5sum_val);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s) =>", __FUNCTION__, salted1);
+            free(salted1);
+
+            RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
+
+            b64enc(md5sum_val, MD5_DIGEST_LENGTH, salted2, SALTED2_LEN);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_1) = %s", __FUNCTION__, salted2);
+
+            srand( time(NULL) );
+            challenge2_data = rand();
+
+            b64enc((unsigned char *) &challenge2_data, sizeof(int), challenge2, CHALLENGE2_LEN);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, b64(%d) = %s", __FUNCTION__, challenge2_data, challenge2);
+
+            /* response = base64enc(md5(hash1 + opaque + challenge2)) */
+            strcat(salted2, opaque);
+            strcat(salted2, challenge2);
+
+            md5sum((unsigned char*) salted2, strlen(salted2), md5sum_val);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s) =>", __FUNCTION__, salted2);
+            RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
+
+            b64enc(md5sum_val, MD5_DIGEST_LENGTH, response, RESPONSE_LEN);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_2) = %s", __FUNCTION__, response);
+
+            /* have all hashes, create auth token for the end of app */
+            pubToken.av_val = malloc(32 + strlen(challenge2) + strlen(response) + strlen(opaque));
+            pubToken.av_len = sprintf(pubToken.av_val,
+                    "&challenge=%s&response=%s&opaque=%s",
+                    challenge2,
+                    response,
+                    opaque);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
+            free(ptr);
+            r->Link.pFlags |= RTMP_PUB_RESP|RTMP_PUB_CLATE;
+        }
+      else if(strstr(description->av_val, "?reason=authfailed") != NULL)
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: wrong password", __FUNCTION__);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+      else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+      else
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
+                  __FUNCTION__, description->av_val);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+
+      ptr = malloc(r->Link.app.av_len + pubToken.av_len);
+      strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
+      strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
+      r->Link.app.av_len += pubToken.av_len;
+      if(r->Link.pFlags & RTMP_PUB_ALLOC)
+          free(r->Link.app.av_val);
+      r->Link.app.av_val = ptr;
+
+      ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
+      strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
+      strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
+      r->Link.tcUrl.av_len += pubToken.av_len;
+      if(r->Link.pFlags & RTMP_PUB_ALLOC)
+          free(r->Link.tcUrl.av_val);
+      r->Link.tcUrl.av_val = ptr;
+
+      free(pubToken.av_val);
+      r->Link.pFlags |= RTMP_PUB_ALLOC;
+
+      RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
+              r->Link.app.av_len, r->Link.app.av_val,
+              r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
+              r->Link.playpath.av_val);
+    }
+  else
+    {
+      return 0;
+    }
+  return 1;
+}
+#endif
+
+
 SAVC(onBWDone);
 SAVC(onFCSubscribe);
 SAVC(onFCUnsubscribe);
@@ -2230,6 +2477,7 @@
 SAVC(close);
 SAVC(code);
 SAVC(level);
+SAVC(description);
 SAVC(onStatus);
 SAVC(playlist_ready);
 static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
@@ -2246,6 +2494,8 @@
 static const AVal av_NetStream_Play_UnpublishNotify =
 AVC("NetStream.Play.UnpublishNotify");
 static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
+static const AVal av_NetConnection_Connect_Rejected =
+AVC("NetConnection.Connect.Rejected");
 
 /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
 static int
@@ -2383,12 +2633,72 @@
     }
   else if (AVMATCH(&method, &av__error))
     {
+#ifdef CRYPTO
+      AVal methodInvoked = {0};
+      int i;
+
+      if (r->Link.protocol & RTMP_FEATURE_WRITE)
+        {
+          for (i=0; i<r->m_numCalls; i++)
+            {
+              if (r->m_methodCalls[i].num == txn)
+                {
+                  methodInvoked = r->m_methodCalls[i].name;
+                  AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
+                  break;
+                }
+            }
+          if (!methodInvoked.av_val)
+            {
+              RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %d without matching request",
+                    __FUNCTION__, txn);
+              goto leave;
+            }
+
+          RTMP_Log(RTMP_LOGDEBUG, "%s, received error for method call <%s>", __FUNCTION__,
+          methodInvoked.av_val);
+
+          if (AVMATCH(&methodInvoked, &av_connect))
+            {
+              AMFObject obj2;
+              AVal code, level, description;
+              AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
+              AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
+              AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
+              AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description);
+              RTMP_Log(RTMP_LOGDEBUG, "%s, error description: %s", __FUNCTION__, description.av_val);
+              /* if PublisherAuth returns 1, then reconnect */
+              PublisherAuth(r, &description);
+            }
+        }
+      else
+        {
+          RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
+        }
+#else
       RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
+#endif
     }
   else if (AVMATCH(&method, &av_close))
     {
       RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
       RTMP_Close(r);
+#ifdef CRYPTO
+      if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
+              !(r->Link.pFlags & RTMP_PUB_CLEAN) &&
+              (  !(r->Link.pFlags & RTMP_PUB_NAME) ||
+                 !(r->Link.pFlags & RTMP_PUB_RESP) ||
+                 (r->Link.pFlags & RTMP_PUB_CLATE) ) )
+        {
+          /* clean later */
+          if(r->Link.pFlags & RTMP_PUB_CLATE)
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+          RTMP_Log(RTMP_LOGERROR, "authenticating publisher");
+
+          if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0))
+              goto leave;
+       }
+#endif
     }
   else if (AVMATCH(&method, &av_onStatus))
     {
@@ -3419,10 +3729,21 @@
   r->m_resplen = 0;
   r->m_unackd = 0;
 
-  free(r->Link.playpath0.av_val);
-  r->Link.playpath0.av_val = NULL;
-
 #ifdef CRYPTO
+  if (!(r->Link.protocol & RTMP_FEATURE_WRITE) || (r->Link.pFlags & RTMP_PUB_CLEAN))
+    {
+      free(r->Link.playpath0.av_val);
+      r->Link.playpath0.av_val = NULL;
+    }
+  if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
+      (r->Link.pFlags & RTMP_PUB_CLEAN) &&
+      (r->Link.pFlags & RTMP_PUB_ALLOC))
+    {
+      free(r->Link.app.av_val);
+      r->Link.app.av_val = NULL;
+      free(r->Link.tcUrl.av_val);
+      r->Link.tcUrl.av_val = NULL;
+    }
   if (r->Link.dh)
     {
       MDH_free(r->Link.dh);
@@ -3438,6 +3759,9 @@
       RC4_free(r->Link.rc4keyOut);
       r->Link.rc4keyOut = NULL;
     }
+#else
+  free(r->Link.playpath0.av_val);
+  r->Link.playpath0.av_val = NULL;
 #endif
 }
 
Index: librtmp/rtmp.h
===================================================================
--- librtmp/rtmp.h	(revision 513)
+++ librtmp/rtmp.h	(working copy)
@@ -136,6 +136,8 @@
     AVal flashVer;
     AVal subscribepath;
     AVal token;
+    AVal pubUser;
+    AVal pubPasswd;
     AMFObject extras;
     int edepth;
 
@@ -154,6 +156,13 @@
     int protocol;
     int timeout;		/* connection timeout in seconds */
 
+#define RTMP_PUB_NAME   0x0001  /* send login to server */
+#define RTMP_PUB_RESP   0x0002  /* send salted password hash */
+#define RTMP_PUB_ALLOC  0x0004  /* allocated data for new tcUrl & app */
+#define RTMP_PUB_CLEAN  0x0008  /* need to free allocated data for newer tcUrl & app at exit */
+#define RTMP_PUB_CLATE  0x0010  /* late clean tcUrl & app at exit */
+    int pFlags;
+
     unsigned short socksport;
     unsigned short port;
 
Index: librtmp/Makefile
===================================================================
--- librtmp/Makefile	(revision 513)
+++ librtmp/Makefile	(working copy)
@@ -14,7 +14,7 @@
 DEF_=-DNO_CRYPTO
 REQ_GNUTLS=gnutls
 REQ_OPENSSL=libssl,libcrypto
-LIB_GNUTLS=-lgnutls -lgcrypt
+LIB_GNUTLS=-lgnutls -lgcrypt -lgnutls-openssl
 LIB_OPENSSL=-lssl -lcrypto
 LIB_POLARSSL=-lpolarssl
 CRYPTO_LIB=$(LIB_$(CRYPTO))
Index: Makefile
===================================================================
--- Makefile	(revision 513)
+++ Makefile	(working copy)
@@ -11,7 +11,7 @@
 CRYPTO=OPENSSL
 #CRYPTO=POLARSSL
 #CRYPTO=GNUTLS
-LIB_GNUTLS=-lgnutls -lgcrypt
+LIB_GNUTLS=-lgnutls -lgcrypt -lgnutls-openssl
 LIB_OPENSSL=-lssl -lcrypto
 LIB_POLARSSL=-lpolarssl
 CRYPTO_LIB=$(LIB_$(CRYPTO))

My password example in my previous post was for RTSP. I am going to assume that WMS has the proper security module installed.

For RTMP you need to use a URL like this.

rtmp://192.168.1.50:1935/live/test flashver=FMLE/3.0\20(compatible;\20FMSc/1.0) pubUser=user pubPasswd=password

In my code this URL gets passed to av_guess_format and then url_fopen. I assume FFmpeg does this as well, so it should work from the command line.

The patch I posted is somewhat broken. Essentially it has an infinite recursion in it. This occurs if you specify an invalid WMS application. Here is the issue.

else if (AVMATCH(&method, &av_close))
     {
       RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
       RTMP_Close(r);
+#ifdef CRYPTO
+      if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
+              !(r->Link.pFlags & RTMP_PUB_CLEAN) &&
+              (  !(r->Link.pFlags & RTMP_PUB_NAME) ||
+                 !(r->Link.pFlags & RTMP_PUB_RESP) ||
+                 (r->Link.pFlags & RTMP_PUB_CLATE) ) )
+        {
+          /* clean later */
+          if(r->Link.pFlags & RTMP_PUB_CLATE)
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+          RTMP_Log(RTMP_LOGERROR, "authenticating publisher");
+
+          if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0))
+              goto leave;
+       }
+#endif

The above is wrong.

I have not put together a proper diff patch, but here is how I fixed this issue. Find this in rtmp.c

/* if PublisherAuth returns 1, then reconnect */
PublisherAuth(r, &description);

Use this instead of PublisherAuth

if (PublisherAuth(r, &description)) {
    
    RTMP_Log(RTMP_LOGERROR, "RTMP Server Requested Auth");
    RTMP_Close(r);
  
     if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
        !(r->Link.pFlags & RTMP_PUB_CLEAN) &&
        (  !(r->Link.pFlags & RTMP_PUB_NAME) ||
         !(r->Link.pFlags & RTMP_PUB_RESP) ||
         (r->Link.pFlags & RTMP_PUB_CLATE) ) )
     {
        /* clean later */
        if(r->Link.pFlags & RTMP_PUB_CLATE)
            r->Link.pFlags |= RTMP_PUB_CLEAN;
        RTMP_Log(RTMP_LOGERROR, "Authenticating User");
        
        if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0))
            goto leave;
     }
}

Don’t forget to remove the bad code.

If you are having problems then setup FFmpeg with debug output. LIBRTMP will allso debug to the console.

I am only using ModuleRTMPAuthenticate

Hey Rajiv could you post or PM the patch which you used for librtmp?

Thanks!

—Jeff

Could you post or PM a corrected patch for librtmp?

Thanks,

—Jeff

Thanks for your reply. I tried https://www.wowza.com/docs/how-to-schedule-streaming-with-wowza-streaming-engine-streampublisher what seems to be the same like your posted stuff. Hereby my problem is that the clients are on the same playlist especially the same file but the are no synced to the same position of the video when connection - so that is no real broadcasting. Is it possibly to sync the clients?

I was wondering about because trying before the solution with ffmpeg and an (unportected) stream it seems to works better then the this solution now (nearly no latency between different players on different test hosts).

I have searched this forum up for any broadcasting solution. Isn’t there any final solution for managing wowza server side to play files and on demand switch to a live signal/show. E.g. with a nice gui :slight_smile:

Is there experience with synpase products?

Hi Steve,

Thanks for creating the patch!

Successfully compiled librtmp and ffmpeg with your patch, however, when hitting a secured wowza server with the username/password in the URL I get the following error:

RTMP_Connect0, failed to connect socket. 111 (Connection refused)

: Operation not permitted

Am I missing anything here or I’ve done something wrong?

Cheers,

Rowland

Hello,

I’m also looking for a patch for ffmpeg to stream a file through a protected stream in wowza.

Please send me the patched version too if possible.

Thank you so much in advance.

Thanks Richard, but the second link you mentioned provides links to ffmpeg binaries that don’t support authentication right?

I’m looking for an ffmpeg binary that supports RTMP authentication

Richard,that requires further customization on the player side. We’re currently using strobe media playback and it could get more complex if we go that way.

It would be nice if you could provide a link to a compiled version of FFMPEG that includes the above patch.

Thank you.