Liquidsoap – Multi-Bitrate DASH streaming configuration

This is an example of multi-bitrate DASH streaming configuration. In this example Liquidsoap will be configured to output three different MPEGTS video streams with various frame size, bitrates and one stereo audio MPEGTS stream all via  UDP.  This configuration can be used with the same setup as my previous blog post about setting up Liquidsoap MPEGTS DASH streaming. This example is using Liquidsoap v1.3.3.

Please note that this is more of a proof of concept than practical use. A hardware encoder plugin for Gstreamer would help.

Liquidsoap Configuration: MPEGTS via UDP for Multi-Bitrate DASH Streaming
set("log.stdout",true)
set("log.level",5)
set("gstreamer.debug_level",2)

set("frame.video.width",1280)
set("frame.video.height",720)
set("frame.video.samplerate",25)
set("gstreamer.add_borders", true)

input = single("/home/user/Videos/Test/test-1280x720-25fps.ogv")

#MPEGTS Output For DASH Streaming.
#You must start Shaka Packager first before starting Liquidsoap.

#Audio Channel. Port 5000
output.gstreamer.audio(
pipeline=
"audioconvert ! fdkaacenc bitrate=128000 ! queue ! mpegtsmux alignment=7 name=muxer ! queue ! udpsink host=127.0.0.1 port=5000
sync=true",
mksafe(input))

#Video Channels.
#360p Video at 600kbps. Port 5001
output.gstreamer.video(
pipeline=
"videoscale ! video/x-raw,width=480,height=360 ! videoconvert ! x264enc bitrate=600 key-int-max=72 pass=qual quantizer=20 tune
=zerolatency ! video/x-h264,profile=baseline ! queue ! mpegtsmux alignment=7 name=muxer ! queue ! udpsink host=127.0.0.1 port=5001 s
ync=true",
mksafe(input))

#480p Video at 1000kbps. Port 5002
output.gstreamer.video(
pipeline=
"videoscale ! video/x-raw,width=640,height=480 ! videoconvert ! x264enc bitrate=1000 key-int-max=72 pass=qual quantizer=20 tun
e=zerolatency ! video/x-h264,profile=main ! queue ! mpegtsmux alignment=7 name=muxer ! queue ! udpsink host=127.0.0.1 port=5002 sync
=true",
mksafe(input))

#720p Video at 3000kbps. Port 5003
output.gstreamer.video(
pipeline=
"videoscale ! video/x-raw,width=1280,height=720 ! videoconvert ! x264enc bitrate=3000 key-int-max=72 pass=qual quantizer=20 tu
ne=zerolatency ! video/x-h264,profile=main ! queue ! mpegtsmux alignment=7 name=muxer ! queue ! udpsink host=127.0.0.1 port=5003 syn
c=true",
mksafe(input))
Shaka Packager Command

The packager will take the UDP output from Liquidsoap and encapsulate it into the DASH format for playback via the Shaka Player or any other DASH player.

$packager \
'in=udp://127.0.0.1:5000?interface=127.0.0.1,stream=audio,init_segment=audio_init.mp4,segment_template=audio_$Number$.m4s' \
'in=udp://127.0.0.1:5001?interface=127.0.0.1,stream=video,init_segment=h264_360p_init.mp4,segment_template=h264_360p_$Number$.m4s' \
'in=udp://127.0.0.1:5002?interface=127.0.0.1,stream=video,init_segment=h264_480p_init.mp4,segment_template=h264_480p_$Number$.m4s' \
'in=udp://127.0.0.1:5003?interface=127.0.0.1,stream=video,init_segment=h264_720p_init.mp4,segment_template=h264_720p_$Number$.m4s' \
--temp_dir /home/user/tmp -mpd_output test_h264.mpd

That is pretty much all there is to it. You could add higher or lower frame size and bitrates if you wanted to. However, this configuration is pushing the limits of Liquidsoap.

Liquidsoap – Streaming DASH via UDP

So now that you have that magical UDP stream going, what to do with it? Why  not a DASH stream using the HTML5 Shaka Player? DASH is D)umb A)ss S)treaming H)ibbtyjibbty also known as the Hard Drive Killer. Cause you ain’t gunna be doing this on a mechanical drive for very long. Who thought the idea of creating millions of tiny files constantly was a good idea? We totally needed a new wheel worse than the one before it, right? I mean, who wants to install various different media players when you now can install various different browsers. Anyways, on to the show!

This is relatively straight forward with a lot of ambiguity.  The path of the stream is as follows; Liquidsoap output MPEGTS via UDP into Shaka Packager. Shaka Packager encapsulates the MPEGTS stream into a DASH stream for playback via a web server and HTML5 clients and other media players that support DASH (such as VLC).  You will want to download the Shaka Packager and Shaka Player.  This is a bit beyond the scope of this article oh how to get the Shaka Player compiled, but just trudge through it.

Liquidsoap Configuration

First part we need to configure Liquidsoap. This will be a basic configuration with the key parts being the output settings. Most notably and very important is that the Shaka Packager does not support the RTP container so it’s MPEGTS flat out.

set("log.stdout",true)
set("log.level",5)
set("gstreamer.debug_level",2)

set("frame.video.width",512)
set("frame.video.height",384)
set("frame.video.samplerate",25)
set("gstreamer.add_borders", true)

# The input file,
# any format supported by liquidsoap
input = single("/home/user/Videos/Test/video-720x576-25fps.ogv")

#MPEGTS via UDP Streaming (Shaka Packager doesn't support RTP container).
output.gstreamer.audio_video(
 video_pipeline=
 "videoconvert ! x264enc pass=qual quantizer=20 tune=zerolatency ! video/x-h264,profile=baseline ! queue ! muxer.",
 audio_pipeline=
 "audioconvert ! fdkaacenc bitrate=128000 ! queue ! muxer.",
 pipeline=
 "mpegtsmux alignment=7 name=muxer ! queue ! udpsink host=127.0.0.1 port=5000 sync=true",
 mksafe(input))

The Shaka Packager doesn’t support MPEGTS in RTP via UDP. If you encapsulate your MPEGTS stream via RTP you will get this error from packager.

[0522/093109:INFO:demuxer.cc(89)] Demuxer::Run() on file 'udp://127.0.0.1:5000?interface=127.0.0.1'.
[0522/093109:INFO:demuxer.cc(161)] Initialize Demuxer for file 'udp://127.0.0.1:5000?interface=127.0.0.1'.
[0522/093116:ERROR:demuxer.cc(207)] Not implemented reached in shaka::Status shaka::media::Demuxer::InitializeParser()
[0522/093116:ERROR:packager_main.cc(477)] Packaging Error: 4 (UNIMPLEMENTED): Container not supported.
Shaka Packager

The Shaka Packager is just a fairly simple program. I just downloaded the binaries and put them in my /home/user/bin/.

In this scenario and since we are using UDP as the transport, the Shaka Packager will need to be started first and listening for the MPEGTS stream packets BEFORE Liquidsoap starts. This is an important and key step in this.

For this example we will start the Shaka Packager program in the root web directory of our website the DASH manifest and media files will be created in this directory.

[/var/www/html/]$packager \
 'in=udp://127.0.0.1:5000interface=127.0.0.1,stream=audio,init_segment=audio_init.mp4,segment_template=audio_$Number$.m4s'  \ 'in=udp://127.0.0.1:5000interface=127.0.0.1,stream=video,init_segment=h264_384p_init.mp4,segment_template=h264_384p_$Number$.m4s' \
--mpd_output h264.mpd

The Shaka Packager is fairly straight forward. Since the Audio and Video is in a single stream we call both streams for our audio and video.  It will create all the necessary media files and the MPD manifest file in the current directory.  Once Shaka Packager is running it will just print out that it’s initialized the demuxer for input from the UDP stream.  It is now time to start Liquidsoap.

Once you start Liquidsoap, the Shaka Packager doesn’t announce anything so it is difficult to know that it is working.  With this current setup after about a minute or two the Shaka Packager will spit an error similar to this.

[0522/095415:WARNING:representation.cc(384)] Found a gap of size 343 > kRoundingErrorGrace (5). The new segment starts at 324900702 but the previous segment ends at 324900359.

If you get this error then you know it’s working. As long as the gap size doesn’t grow the stream should be good.

Shaka Player

So now that you got the stream files all going, you could point VLC to the http://localhost/h264.mpd file and VLC should be happy to play the DASH stream.  But now onto the Shaka Player. It is beyond the scope of me to tell you how to install it. But I feel you.

Following the basic guide for the Shaka Player, just copy the shaka-player.compiled.js script into the same directory as the media files. Then create a simple index.html file.

<!DOCTYPE html>
<html>
<head>
<!-- Shaka Player compiled library: -->
<script src="shaka-player.compiled.js"></script>
<!-- Your application source: -->
<script src="myapp.js"></script>
</head>
<body>
<video id="video" width="640" poster="//shaka-player-demo.appspot.com/assets/poster.jpg" controls autoplay></video>
</body>
</html>

Then you will want to create the myapp.js file which is essentially a kind of configuration and initialization file for the Shaka Player. This is the file that points to the DASH manifest (MPD) file that the Packager has created.

// myapp.js

var manifestUri = '//localhost/h264.mpd';

function initApp() {
// Install built-in polyfills to patch browser incompatibilities.
shaka.polyfill.installAll();

// Check to see if the browser supports the basic APIs Shaka needs.
if (shaka.Player.isBrowserSupported()) {
// Everything looks good!
initPlayer();
} else {
// This browser does not have the minimum set of APIs we need.
console.error('Browser not supported!');
}
}

function initPlayer() {
// Create a Player instance.
var video = document.getElementById('video');
var player = new shaka.Player(video);

// Attach player to the window to make it easy to access in the JS console.
window.player = player;

// Listen for error events.
player.addEventListener('error', onErrorEvent);

// Try to load a manifest.
// This is an asynchronous process.
player.load(manifestUri).then(function() {
// This runs if the asynchronous load is successful.
console.log('The video has now been loaded!');
}).catch(onError); // onError is executed if the asynchronous load fails.
}

function onErrorEvent(event) {
// Extract the shaka.util.Error object from the event.
onError(event.detail);
}

function onError(error) {
// Log the error.
console.error('Error code', error.code, 'object', error);
}

document.addEventListener('DOMContentLoaded', initApp);

You should now have a functioning DASH stream with Liquidsoap.  This is a basic example and can be expanded on with enough CPU resources and x264 hardware encoding via GStreamer.  The idea of DASH is to have multiple bit rates at various frame sizes so that you can cover a wide variety of client types and connectivity.  I haven’t tested this out, but you could start with a larger frame size setting in Liquidsoap then create multiple video outputs with the various frame sizes. You will only need one audio output.

Have fun!

Importing Video Tapes – DV Files and FFMPEG

I’ve been working on importing all my old VHS and 8mm video tapes into my computer.  It’s always been fairly straight forward process of importing the video, originally when it was composite video being inputted it was in the form of an Uncompressed AVI file.  And then you’d convert it over to whatever media format you wanted.  Long ago I had chosen the Real Media file format. It had multiple bit rate encoding in a single file. This was required due to the various connectivity speeds everyone had back then.  From 28k Dialup to 1mbit connections.  It worked really well and then the Real Media format was pushed out for more wide spread and open source accessible media file formats. This is what happened with most of all the video files I had online.  They were all in some obsolete format and there wasn’t anything that could convert the Real Media files.  Which in turn were low resolution already.

I had started importing my video tapes back in 2011 via Firewire port and the pass through option on my Sony video camera.  This worked really well and unfortunately that computer failed and the replacement one no longer had a Firewire port.  So, I finally picked up a Firewire port at the beginning of this month and began the process where I had left off.

When importing via Firewire the it creates DV files.  Back in 2011 one of my main things was for the Karvanek Conspiracy video files, I wanted to master them all in the new webm format, because I like to torture myself with bleeding edge technology and paint myself into a corner like I did with the Real Media.  This worked out great, but it was a fairly slow process of hand writing all the times for where to stop and start the webm encoding process.  I was using WinFF which is a Windows GUI for ffmpeg.  And I would do command line encoding using the latest version of ffmpeg at that time. Everything worked like a champ. Other than encoding in webm is insanely slow.

But, that is no longer the case now.  Trying WinFF and straight ffmpeg and any application that uses ffmpeg will now fail to encode DV video files that I am creating because the DV files will record tape drop outs and other events (like stopping and starting recording) as some sort of odd or error frame.  When ffmpeg detects these frames it will spit out a bunch of EOB errors and stop encoding. ffmpeg, WinFF, Xmedia Recode, Handbrake all succumb to this problem.  The only encoder I had installed on my computer was Microsoft Expression Encoder 3.  It was part of the whole Microsoft Expression suite as I use Expression Web to do HTML editing.  It is a real good encoder, it will do VC-1, H.264 and Smooth Streaming.  I’ve been encoding everything now in MP4 format and Expression Encoder 3 worked great, but it was slow. It would take an hour to encode 30 minutes of video.

I wasted a good day figuring out the problem with DV files and ffmpeg and realizing it was hopeless unless I wanted to patch the source code on a Linux box and do all my encoding on that.  Which seemed kind of retarded, wait, that is retarded.  This whole issue is retarded.  So I finally started looking into other encoder programs.  I found one that works like a champ with my DV files converting to MP4 and it will do WebM as well, but I haven’t tested it out yet.  It’s called Xilisoft Video Converter Ultimate.  It’s only about $50 at the time of this post. It’s worth the cost just in the time you will save searching total retarded non-sense.  The big surprise about this software is not that it worked converting the DV files, but it has code for both Nvidia and ATI graphics cards that will speed up MP4 encoding. The 30 minutes DV file that took an hour to convert using the old Expression Encoder 3, takes Video Converter Ultimate just about 5 minutes on my AMD A10 APU.  If you have a higher end graphics card I can imagine that time will go down considerably. So now my bottleneck is the actual importing of the video tapes and uploading them to You Tube.

The Super Fucking Ultra Shitty editor that comes with BlogEngine.Net refuses to allow me to enter a link over the Xilisoft name. You know, let’s make a blog application for Microsoft’s web server and go out of our way to make it not work with Internet Explorer.  So here is the manually typed in link; http://www.xilisoft.com/

 

 

Video Files – WebM Format

I started working on re-encoding the files as I had mentioned in a previous post.

I don’t have the best input device currently. I am using an old ADS VCD-USB device that is only compatile in Windows XP.  My laptop is still XP, so using that to encode the old VHS tapes.  I am encoding them first to WMV3 as Windows Movie Maker is the only program that seems to work properly encoding the live video on the laptop.  It’s old and slow.  From the WMV3 format I am converting them to the new open source WebM format for online.  I chose this format as, it’s similar, or an upgrade to the Theora video format that I have used previously. I wanted to use the open source format over the others.  I also know that it will be natively supported in the new versions of IE and Firefox.  It currently is supported in Chrome, so the videos will only work in Chrome.  And of course, since I am on the cutting dull edge of technology, I screw myself in the process.  I tried to install the WebM and Vorbis DirectShow plugins to test out Windows Media Player, but my WMP crashes after I install the Vorbis codecs.  So if you want to watch the Karvanek Conspiracy videos, you’ll need Chrome now.