Introduction to CasparCG's HTML producer

CasparCG is a free and open source playout server used to deliver high quality live television broadcasts. It supports data-driven templates for graphic overlays created with Adobe Flash and HTML websites. Although support for HTML based templates has been around for years, it’s neglected by many template creators who consider it less powerful and thus it’s difficult to find information and resources about HTML based templates.

This blog post series aims to be a comprehensive guide to CasparCG’s HTML producer: We will first have a look at what’s at hand. We will examine the current different CasparCG server versions and what they have under the hood. We will create a basic template and explore how to control it with AMCP commands to change and update the templates state and data.

We then have a look at how a production-ready template looks like and what needs to be considered in terms of dimensions and resolutions. We will also have a look at how we parse incoming data and introduce the webcg-framework, a drop-in script that takes care of AMCP command subscription and of the data parsing and processing and enables you to develop and debug templates.

Introduction

HTML templates are fully functional HTML websites and vice versa. You can play any HTML website with CasparCG’s HTML producer. The HTML producer uses the Chromium Embedded Framework (CEF) to render websites and mix them into the video channel. At the time of the first publication of this article, there were three different server versions: the latest stable in version 2.0.7 (December 2014), the latest official beta in version 2.1.0 Beta 2 (April 2017), both to find on the official download website and the latest release on GitHub in version 2.2.0 Beta (February 2018). The article has since been updated in December 2018 and January 2019 to include the latest version, currently 2.2.0 Stable.

All server versions come with a bundled CEF and thus the HTML producer works out of the box. The older two versions come with Chrome 33. Starting with version 2.2.0 the bundled CEF has been updated to version 63 as we can see in this comparison chart:

Release Date Version Chrome
2.0.7 2017-12-11 2.0.7.e9fc25a 33.0.1750.170
2.1.0 Beta 2 2017-04-13 2.1.0.3437 dc2e94b 33.0.1750.170
2.2.0 Beta 2018-02-28 2.2.0.3 f61e8975 63.0.3239.132
2.2.0 Beta 7 2018-09-01 2.2.0 8fab6484 63.0.3239.132
2.2.0 Stable 2018-12-29 2.2.0 66a9e3e2 63.0.3239.132

Chrome version 33.0.1750 was released in February 2014 1. This is rather dated in terms of web development. For example, CSS grid layout 2 or Array.prototype.find() 3 is not supported. Before we go into the details of the differences between the server versions, let’s get something on screen and play a basic template.

A basic template

An HTML template is a file that contains an HTML document. The most minimal and yet syntactically and semantically correct HTML document looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>basic-template</title>
</head>
<body>
  <div style="background-color: white;">
    <h1>basic-template.html</h1>    
  </div>
</body>
</html>

This HTML document, or website, displays a big, black text on a white background. Save this file in your server’s template folder as “basic-template.html” and you can play this template just like your Flash templates, for example by issuing these commands in your server’s console:

CG 1 ADD 0 "basic-template" 1 to load and play, and

CG 1 REMOVE 0 to remove the template.

The HTML producer can be invoked just like the Flash producer. You can use the offical CasparCG Client, issue AMCP template commands in the server’s console or use your custom client. There should be no difference in invoking them, since you must not provide a file extension when you load (add) a template. If there is a Flash template with the name “basic-template.ft”, it will take precedence and therefore the Flash producer is told to load (and play) the Flash template.

Handling AMCP commands

A fully functional HTML template should define functions that correspond to the AMCP template commands. The minimal set of required functions defined on the global window object are: play(), next(), stop() and update(). These are the functions that will be called by the HTML producer. If they are not present, you will see JavaScript error messages in your server’s console.

Here is a template that logs the function calls to the console and adds them to a list on screen. Additionally, a global error handler logs any given errors. The template also defines the functions remove() (commented) and action1(). We will discuss these two in the next section.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>debug-template</title>
</head>
<body>  
  <div style="background-color: white;">
    <h1>debug-template.html</h1>
    <ul></ul>
  </div>
  <script>  
  function play() {
    log('play()');
  }
    
  function stop() {
    log('stop()');
  }
  
  function next() {
    log('next()');
  }
  
  function update(data) {
    log('update() ' + typeof data + "  " + data);
  }
  
  // function remove() {
  //   log('remove()');
  // }
  
  function action1() {
    log('action1() ' + JSON.stringify(arguments));
  }
  
  window.onerror = function(msg) {
    log('error ' + msg);    
  }
  
  function log(s) {
    console.log(s)
    const li = document.createElement('li');
    li.innerText = s;
    document.body.querySelector('ul').appendChild(li);
  }
  
  log(window.location)
  log('Chrome: ' + window.navigator.userAgent.match(/Chrome\/([^ ]+)/)[1])
  log('window.caspar: ' + !!window.caspar)
  log('html.backgroundColor: ' + window.getComputedStyle(document.getElementsByTagName('html')[0]).backgroundColor)
  log('body.backgroundColor: ' + window.getComputedStyle(document.getElementsByTagName('body')[0]).backgroundColor)
  </script>
</body>
</html>

Save this template in your templates folder as “debug-template.html”. You should then be able to play the template by entering this command in your server’s console:

CG 1 ADD 0 "debug-template" 1

And later remove it with:

CG 1 REMOVE 0.

When you add (and play) this template, you should see something like this on screen:

  • file:///C:/Users/Reto/Desktop/CasparCG/templates/debug-template.html
  • Chrome: 63.0.3239.132
  • window.caspar: true
  • html.backgroundColor: rgba(0, 0, 0, 0)
  • body.backgroundColor: rgba(0, 0, 0, 0)
  • update() string
  • play()

AMCP template commands

In this section we are going to have a look at the AMCP template commands and examine the HTML producers behavior and the differences between the server versions 2.0.7, 2.1.0 Beta 2, 2.2.0 Beta 1 and 2.2.0 Beta 7.

A word about video_channel, layer and cg_layer

The CasparCG server can host one producer per video_channel and (video) layer. If you load a Flash template on the video_channel 1 and layer 20, and later you load a HTML template on the same video_channel and layer, the Flash producer and its templates will be unloaded and replaced with the HTML producer.

The Flash producer supports the parameter cg_layer and can play different templates on 10’000 distinct layers. The HTML producer does not support layers. This means that:

  1. If you want to play several HTML templates at the same time, each template has to be played on a different (video) layer, and
  2. The cg_layer parameter has no effect, thus you can
    CG 1-10 ADD 55 "html-template" 1 to add and play a template, and later
    CG 1-10 REMOVE 44 to remove the very same template.

CG ADD

Syntax: CG [video_channel:int]{-[layer:int]|-9999} ADD [cg_layer:int] [template:string] [play-on-load:0,1] {[data]}

The CG ADD command, according to the official documentation, “prepares a template for displaying. It won’t show until you call CG PLAY (unless you supply the play-on-load flag, 1 for true).”

As this description is true for the Flash producer, the HTML producer works differently: No matter whether you set the play-on-load flag, your HTML template is loaded, displayed and therefore visible if you don’t hide it with JavaScript and/or CSS. After loading the template, the HTML producer then calls the functions update() and/or play() according to the following specifications:

If you provide a data argument in server version 2.0.7, the function update() is called, otherwise it is not called. Starting from server version 2.1.0 Beta 2 the update() function is always called regardless whether you specify a data argument or not. In all server versions, after a possible call to update(), the play() function is called if you have set the play-on-load flag.

The format of the data argument has to follow strict specifications. These are explained in the CG UPDATE command description below.

Examples

Add a template to channel 1, layer 10, and play it:
CG 1-10 ADD 0 "folder/basic-template" 1

Add a template to channel 1, layer 0 (specific layer is omitted), but don’t play it:
CG 1 ADD 0 "folder/basic-template" 0

Add a template to channel 1, layer 0, and update with data previously stored with key “key1”, and play it:
CG 1 ADD 0 "folder/basic-template" 1 "key1"

Add a template to channel 1, layer 0, update with XML data, and play it:
CG 1 ADD 0 "folder/basic-template" 1 "<templateDate><componentData id=\"f0\"><data id=\"text\" value=\"https://www.indr.ch\"/></componentData></templateData>"

Version 2.1.0 Beta 2 and above: Add a template to channel 1, layer 0, update with JSON data, and play it:
CG 1 ADD 0 "folder/basic-template" 1 "{\"f0\":\"Reto\"}"

CG PLAY

Syntax: CG [video_channel:int]{-[layer:int]|-9999} PLAY [cg_layer:int]

The CG PLAY command “plays and displays the template in the specified layer.”. As noted in the previous section, the template is displayed (visible) after it has been loaded with CG ADD. The CG PLAY command tells the HTML producer the call the play() function.

The play() function is the ideal point where you start playing your template by starting intro animations and/or displaying it with JavaScript/CSS. Take a note that nothing prevents multiple calls of CG PLAY commands and subsequent calls to play().

Examples

CG 1 PLAY 0

CG STOP

Syntax: CG [video_channel:int]{-[layer:int]|-9999} STOP [cg_layer:int]

The CG STOP command “stops and removes the template from the specified layer. This is different from REMOVE in that the template gets a chance to animate out when it is stopped.”.

The HTML producer only calls the function stop(). It neither stops the execution of your template, hides it nor removes it.

The stop() function is the ideal point where you stop playing your template by starting outro animations and/or hiding it with JavaScript/CSS. Take a note that nothing prevents multiple calls of CG STOP commands and/or subsequent calls to stop().

Examples

CG 1 STOP 0

CG NEXT

Syntax: CG [video_channel:int]{-[layer:int]|-9999} NEXT [cg_layer:int]

The CG NEXT command “triggers a ‘continue’ in the template on the specified layer. This is used to control animations that has multiple discreet steps.”.

The HTML producer will call the next() function.

Examples

CG 1 NEXT 0

CG REMOVE

Syntax: CG [video_channel:int]{-[layer:int]|-9999} REMOVE [cg_layer:int]

The CG REMOVE command “removes a template from the specified layer.”.

What the HTML producer does depends on the server version. In version 2.0.7 the HTML template will be removed immediately. The same is true for version 2.1.0 Beta 2 unless a function remove() exists in your HTML template. If a function exists, the function is called but the template or the HTML producer is not removed. In version 2.2.0 Beta 1 and above, an existing function is called, but the template is never removed even if no function exists.

Examples

CG 1 REMOVE 0

CG UPDATE

Syntax: CG [video_channel:int]{-[layer:int]|-9999} UPDATE [cg_layer:int] [data:string]

The CG UPDATE command “sends new data to the template on specified layer. Data is either inline XML or a reference to a saved dataset.”.

The HTML producer will call the update() function with either the value provided for the parameter data or if a data store key with said value exists, the value that was previously stored with DATA STORE command is passed to the update() function.

The documentation says “inline XML”. The command accepts any string that starts with a less-than symbol “<“. The string is then passed to the HTML producer that calls the update() function with the value as a string.

Starting from server version 2.1.0 Beta 1, the producer accepts a string that starts with a curly bracket “{”. This can be used to pass a stringified JSON object (but not an array starting with a square bracket “[“) to the update() function. Be aware that the implemention doesn’t do any validation checks neither for the XML string nor for the JSON string. It simply checks for the first character to decide whether to lookup previously stored data store keys or not.

Examples

Update with an XML string:
CG 1 UPDATE 1 "<templateData><componentData id=\"f0\"><data id=\"text\" value=\"https://indr.ch/\"/></componentData></templateData>"

Update with the value stored with key “key1”:
CG 1 UPDATE 1 "key1"

Version 2.1.0 Beta 2 and above: Update with a JSON object string:
CG 1 UPDATE 1 "{\"f0\":123}"

CG INVOKE

Syntax: CG [video_channel:int]{-[layer:int]|-9999} INVOKE [cg_layer:int] [method:string]

The CG INVOKE command “invokes the given method on the template on the specified layer.”.

The HTML producer will call a global function with the name specfied as method. If method is a JavaScript function expression in the form of name() the function is called with the supplied parameters. If the function does not exist a normal Uncaught ReferenceError is thrown by the JavaScript runtime.

If you try to invoke a function called “remove”, the producer behaves differently depending on the server version: In version 2.1.0 Beta 2 and below the effect is the same as calling CG 1 REMOVE 0. In version 2.2.0 Beta 1 and above an existing remove() function is called. If the function does not exist no error is thrown.

Examples

Calls the function action1():
CG 1 INVOKE 1 "action1"

Calls the function action1('abc', 123):
CG 1 INVOKE 1 "action('abc', 123)"

CG INFO

The CG INFO command doesn’t seem to work with the HTML producer and always causes the JavaScript runtime to throw an Uncaught SyntaxError in version 2.0.7. CG INFO has no effect in version 2.1.0 Beta 2 and above.

Summary

This blog post covered all the basics you need to know to get started with CasparCG’s HTML producer. We had a look at how to load, play, update and stop a HTML template and discovered the traits and behaviors of the different server versions. There is two interesting and significant differences. One is that starting from 2.1.0 Beta 2 you can pass stringified JSON objects to the template. The second is that starting from 2.2.0 Beta 1 you have a more recent Chrome version under the hood.

In the next blog post we will have a look at how a production-ready template looks like. And we will introduce the webcg-framework, a drop-in script that has been used in production for more than a year. It let’s you conveniently register to AMCP commands and it automatically parses the incoming data to a JavaScript object. And on top of that, you can easily debug your templates with the lazy loaded webcg-devtools.

Join the discussion in the official CasparCG forum.

Appendix

User agent strings

CasparCG User agent string
2.0.7.e9fc25a Stable Release Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.170 Safari/537.36
2.1.0.3437 dc2e94b Beta 2 x64 Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.170 Safari/537.36
2.2.0.3 f61e8975 Beta 1 x64 Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
2.2.0 8fab6484 Beta 7 x64 Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
2.2.0 66a9e3e2 Stable x64 Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36

window.caspar property

CasparCG window.caspar
2.0.7.e9fc25a Stable Release undefined
2.1.0.3437 dc2e94b Beta 2 x64 undefined
2.2.0.3 f61e8975 Beta 1 x64 {}
2.2.0 8fab6484 Beta 7 x64 {}
2.2.0 66a9e3e2 Stable x64 {}