# ffmpeg for pseudo live with protected publish stream

**URL:** <https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046>\
**Category:** Wowza Streaming Engine\
**Created:** [January 27, 2011, 6:37pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046 "2011-01-27T18:37:27Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![t\_f](https://avatars.discourse-cdn.com/v4/letter/t/ce7236/32.png) [@t\_f](https://community.wowza.com/u/t_f)\
**Post date:** [January 27, 2011, 6:37pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/1 "2011-01-27T18:37:27Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Andrew\_Kennedy](https://avatars.discourse-cdn.com/v4/letter/a/ecb155/32.png) [@Andrew\_Kennedy](https://community.wowza.com/u/Andrew_Kennedy)\
**Post date:** [January 28, 2011, 2:53am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/2 "2011-01-28T02:53:42Z")

</div>

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](https://www.wowza.com/docs/how-to-do-basic-server-side-publishing-with-stream-class-streams)

Shamrock

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [February 16, 2011, 3:53pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/3 "2011-02-16T15:53:05Z")

</div>

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](https://www.wowza.com/downloads/forums/mediasecurity/MediaSecurity.zip)

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [May 16, 2011, 3:39pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/4 "2011-05-16T15:39:00Z")

</div>

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](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](https://www.wowza.com/docs/how-to-use-ffmpeg-with-wowza-media-server-mpeg-ts))

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [May 17, 2011, 12:54pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/5 "2011-05-17T12:54:53Z")

</div>

I don’t know. I found this comment:

[http://lists.mplayerhq.hu/pipermail/rtmpdump/2010-June/000983.html](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

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [May 17, 2011, 8:57pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/6 "2011-05-17T20:57:14Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Ian\_Beyer](https://avatars.discourse-cdn.com/v4/letter/i/e99b99/32.png) [@Ian\_Beyer](https://community.wowza.com/u/Ian_Beyer)\
**Post date:** [January 28, 2011, 11:11am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/7 "2011-01-28T11:11:01Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Andrew\_Kennedy](https://avatars.discourse-cdn.com/v4/letter/a/ecb155/32.png) [@Andrew\_Kennedy](https://community.wowza.com/u/Andrew_Kennedy)\
**Post date:** [January 28, 2011, 9:15am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/8 "2011-01-28T09:15:05Z")

</div>

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

Shamrock

---

<div class="post-metadata">

**Author:** ![Rajiv\_Trehan](https://avatars.discourse-cdn.com/v4/letter/r/a88e4f/32.png) [@Rajiv\_Trehan](https://community.wowza.com/u/Rajiv_Trehan)\
**Post date:** [February 23, 2011, 4:14pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/9 "2011-02-23T16:14:04Z")

</div>

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

```auto
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

---

<div class="post-metadata">

**Author:** ![Steve\_McFarlin](https://avatars.discourse-cdn.com/v4/letter/s/aca169/32.png) [@Steve\_McFarlin](https://community.wowza.com/u/Steve_McFarlin)\
**Post date:** [January 29, 2011, 9:56pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/10 "2011-01-29T21:56:05Z")

</div>

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.

```auto
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))

```

---

<div class="post-metadata">

**Author:** ![Steve\_McFarlin](https://avatars.discourse-cdn.com/v4/letter/s/aca169/32.png) [@Steve\_McFarlin](https://community.wowza.com/u/Steve_McFarlin)\
**Post date:** [February 17, 2011, 1:42pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/11 "2011-02-17T13:42:15Z")

</div>

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.

```auto
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.

```auto
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

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

```

Use this instead of PublisherAuth

```auto
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.

---

<div class="post-metadata">

**Author:** ![Steve\_McFarlin](https://avatars.discourse-cdn.com/v4/letter/s/aca169/32.png) [@Steve\_McFarlin](https://community.wowza.com/u/Steve_McFarlin)\
**Post date:** [February 17, 2011, 1:56pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/12 "2011-02-17T13:56:28Z")

</div>

I am only using ModuleRTMPAuthenticate

---

<div class="post-metadata">

**Author:** ![jeff\_stagg](https://avatars.discourse-cdn.com/v4/letter/j/5f9b8f/32.png) [@jeff\_stagg](https://community.wowza.com/u/jeff_stagg)\
**Post date:** [April 6, 2011, 8:47am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/13 "2011-04-06T08:47:36Z")

</div>

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

Thanks!

—Jeff

---

<div class="post-metadata">

**Author:** ![jeff\_stagg](https://avatars.discourse-cdn.com/v4/letter/j/5f9b8f/32.png) [@jeff\_stagg](https://community.wowza.com/u/jeff_stagg)\
**Post date:** [April 6, 2011, 8:48am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/14 "2011-04-06T08:48:41Z")

</div>

Could you post or PM a corrected patch for librtmp?

Thanks,

—Jeff

---

<div class="post-metadata">

**Author:** ![t\_f](https://avatars.discourse-cdn.com/v4/letter/t/ce7236/32.png) [@t\_f](https://community.wowza.com/u/t_f)\
**Post date:** [January 28, 2011, 9:01am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/15 "2011-01-28T09:01:19Z")

</div>

Thanks for your reply. I tried [https://www.wowza.com/docs/how-to-schedule-streaming-with-wowza-streaming-engine-streampublisher](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?

---

<div class="post-metadata">

**Author:** ![t\_f](https://avatars.discourse-cdn.com/v4/letter/t/ce7236/32.png) [@t\_f](https://community.wowza.com/u/t_f)\
**Post date:** [January 28, 2011, 9:28am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/16 "2011-01-28T09:28:24Z")

</div>

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 🙂

Is there experience with synpase products?

---

<div class="post-metadata">

**Author:** ![Rowland\_Watkins](https://avatars.discourse-cdn.com/v4/letter/r/d78d45/32.png) [@Rowland\_Watkins](https://community.wowza.com/u/Rowland_Watkins)\
**Post date:** [February 16, 2011, 5:49pm UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/17 "2011-02-16T17:49:42Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Sayne\_Josh](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@Sayne\_Josh](https://community.wowza.com/u/Sayne_Josh)\
**Post date:** [May 16, 2011, 1:44am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/18 "2011-05-16T01:44:59Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Sayne\_Josh](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@Sayne\_Josh](https://community.wowza.com/u/Sayne_Josh)\
**Post date:** [May 17, 2011, 4:46am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/19 "2011-05-17T04:46:09Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Sayne\_Josh](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@Sayne\_Josh](https://community.wowza.com/u/Sayne_Josh)\
**Post date:** [May 17, 2011, 8:00am UTC](https://community.wowza.com/t/ffmpeg-for-pseudo-live-with-protected-publish-stream/36046/20 "2011-05-17T08:00:07Z")

</div>

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.
