How to pipe live video in real-time between Bambuser and AWS Elemental MediaLive

AWS Elemental offers a suite of broadcaster grade tools, both on-premise and cloud-based ones. Recently some of them were made available to all AWS customers via the regular AWS console using their standard pay-as-you-go approach. Elemental also have a large partner network where you will find a vast amount of solutions if you need server-side ad insertion, DRM, ready-made OTT experiences or anything else aimed at the professional broadcaster market.

Bambuser is a performant and cost-effective way of ingesting, storing and distributing live video from and to mobile phones, whether UGC, company-internal or any other form of content gathering.

If you are an Elemental customer already, or if you find some of their features appealing in your video production pipeline, and you simultaneously want to ingest vast amounts of user generated content from your app or website to source from in your Elemental productions, then using Bambuser and Elemental together might be a good idea.

Consider for example a funnel where 100:s or 1000:s of user-generated livestreams flow in to your Bambuser account daily. You can use filters, tagging, grouping and the segment exporter in Bambuser's content manager to find a handful of highlights that you want to use as part of your daily live production. Some of them might have occurred a while ago and can be replayed, some of them might be live light now. Regardless, using a Bambuser Live Output, they can be streamed to an AWS MediaLive Input and be part of the production, as a Cutaway, a PiP element or anything else supported by your MediaLive setup. For even more flexibility you can use several concurrent pairs of inputs and outputs.

The RTMP protocol has become a de-facto standard when piping video between internet services, whether output from Drones or Action Cameras or multi-camera field productions or ingest into CDN:s. It can also be used in between cloud services, which is what we will attempt here. RTMP can either be pushed from the source (sender-initiated, typical broadcaster behavior) to a public listener (an RTMP ingest server / endpoint) or fetched from a public url (recipient-initiated, typical player behavior). Below we will use the former approach in both directions.

Setting up a MediaLive channel with Bambuser as source

Let's look at a simple practical scenario: using Elemental to add a semi-transparent logo in the corner of our Bambuser stream.

  • Start a Bambuser live stream or pick an old one from your archive
  • Create a Bambuser realtime pipeline that feeds an AWS MediaLive channel using RTMP push
  • Add a scheduled action that overlays our logo onto the stream
  • Deliver the stream somewhere, for example you might loop it back to Bambuser using RTMP ingest

Creating the AWS MediaLive channel

In the AWS console, choose MediaLive.

If you can, make sure to use an AWS region on the same continent where you intend to ingest Bambuser content. At the time of writing, choosing Oregon (US users) or Ireland (EU users) should reduce latency and yield the best results.

Click Create Channel and give it a descriptive name. You can leave the rest of the form on the righthand side unchanged.

On the lefthand side, add an Input attachment, then after the righthand side updates, click Create input. Give your input a descriptive name, and choose RTMP push. This option will generate a static RTMP url that we can hand to Bambuser's stream forwarder.

Scroll down to Input security group, choose Create and enter the CIDR-value - which means "Allow access from all ip addresses". This setting allows us to restrict which ip addresses are able to provide media, but in this case we don't know the ip or even the ip range that Bambuser will use. Click Create input security group, then scroll down further.

In Input destinations we need to specify what the path and stream id should be in the RTMP url that MediaLive creates for us. These can take any arbitrary value you want.


Since we allow all ip:s and don't use RTMP's username/password feature, they are essentially a shared secret between our Bambuser environment and MediaLive: anyone with knowledge of them is able to ingest to our MediaLive channel. Ideally, use non-guessable values here.

MediaLive wants us to define two destinations. You can probably increase the reliability by sending two copies of the same stream using different ISP:s. For simplicity, let's define both but ignore one of them.

Click Create. When returned to the parent form, make sure to select the input, as it is not pre-selected for some odd reason.

Both inputs are now displayed as RTMP urls. Let's copy one of them to the clipboard and add it to Bambuser Dashboard's output configuration.

Creating an output

In Bambuser dashboard on the content page, click Add outbox on the righthand side and give it a descriptive name, perhaps AWS MediaLive #1 (since we might add more than one later) and click Save.

Then click Add RTMP output and enter most of RTMP url into the Ingest Endpoint field. Move the value after the last slash (should be the value we entered as Application instance earlier) over to the Stream id field (and don't include the last slash in either of the fields).

Our Bambuser output is now linked to our AWS MediaLive input! But none of them are active yet. If we drop a piece of content into the outbox and try to activate the forwarding, you will notice that it fails after a couple of seconds. This is due to the fact that we haven't finished creating our MediaLive channel yet, and it needs an output before it can start accepting content.

Adding a MediaLive output that returns the stream to Bambuser

Just like Bambuser's outboxes can forward to several destinations at once, AWS MediaLive can have multiple outputs of different kinds. We could use it to produce a multi-bitrate HLS stream on our CloudFront distribution, or we could forward the stream over RTMP to Akamai, or we could do whatever our OTT provider requires to present our end result correctly.

Bambuser has a web player and content manager that we're familiar with already: to keep things simple, let's try to feed MediaLive's modified stream back to Bambuser and see what happens!

On the lefthand side in our channel creation form, Click Add output group. We can choose to produce an HLS live stream a file on S3 and a few other things. Select RTMP push, then press Confirm.

Give the RTMP group a descriptive name, perhaps Output to Bambuser, then under RTMP outputs, click Settings.

In RTMP destination A we now need to enter a Bambuser RTMP ingest url. Head back to Bambuser dashboard and click Create > RTMP input on the content page, press Create RTMP input, then enter a descriptive name like Input A from MediaLive and press Generate RTMP credentials.

Then go back to MediaLive and enter Bambuser's url and key into the url and stream name fields respectively.

Again, MediaLive wants us to enter two destination RTMP urls for redundacy and this time there is probably no way to opt out: it won't let you enter the same value twice. In other words, repeat the process for RTMP destination B. MediaLive will only use one of them at a time and will alternate between them if the connection is lost and you choose to keep the retry behavior active.

Initiating the content loop

Finally, let's press Create channel in MediaLive and see what happens! If you accidentally skipped any of the steps (or if the MediaLive interface has changed since this guide was written), MediaLive will complain in a red box at the top, if not, wait a little while until the channel is created, then press Start and wait another minute or two until it is ready to accept content!

Finally, head back to Bambuser dashboard and add a video to your outbox.

Ingest tips

Any type of video should be fine: you can upload a pre-recorded file, use the Bambuser app, the web broadcaster or any other of the ingest options Bambuser supports.

You can even add multiple broadcasts to the outbox.

In case of archived videos, the outbox will cycle between all videos and restart from the top when the last one ends. In case of live videos, the outbox will stay on the topmost stream until the broadcaster ends the stream and then continue to the next one.

Then push the toggle button above the outbox into active mode. If your MediaLive channel is ready, another live stream should appear within a few seconds, tagged with the RTMP input name we chose. Pretty cool!

Now we have an idea of how the two systems can pass streams back and forth between each other, which is quite powerful - let's do something that's useful in practice too!

MediaLive can alter the stream that's flowing through the channel on-the-fly in various ways. The raw console UI can seem quite tedious, but it is probably a robust platform to build upon and one of the partners might have add-ons that provides smoother workflows.

Let's try something simple that's supported natively: adding a static semi-transparent logo in the corner of the video.

On the channel page in MediaLive, click the Schedule tab, then click Create and give our schedule action a descriptive name. Choose Fixed start type and enter a date a couple of minutes in the future. This is a bit cumbersome: a time in the past is rejected and if you choose a time in the future you have to wait... For some reason there is no way to choose "apply immediately", which perhaps suggests that actions are mainly intended to be created programmatically. Anyway, choose a good timestamp - note that it is in UTC! - then choose Static Image Activation. As Input location, enter a public url where your png file resides. One option is to upload the logo file to an S3 bucket and set the upload to publicly readable.

Further down we are given some positioning options. Let's use 50 as both x and y coordinates, to give us some margin relative to the top left corner. Using the top right corner would probably be more conventional and if you know the output resolution you can calculate the appropriate offset. Not sure if there is a way to specify the position in coordinates relative to the righthand side though, that would have been more convenient... You can also specify the desired width and height of the logo, in case your source png is large and you don't care to hand-craft an appropriately sized one.

Finally, double-check that your timestamp is still at least a few seconds in the future - in UTC time! - and click Create at the bottom.

On the next page you should see your action listed. Head back to Bambuser dashboard and wait until our selected time passes....

...and there we go! A professional-looking presentation!

The good news is, you do not have to go through this process every time. When you stop and re-start your channel, the logo will be re-applied even though the date is now in the past and predates the start time.

Shutting down

Remember to turn off both your Bambuser output and your MediaLive channel when you're done! Accidentally keeping them active 24/7 can get costly.

What's next?

Note also that you can automate Bambuser's RTMP out behaviors using Webhooks and the stream forwarding API.