Decoder Integration Layer for Web (DIL.js)
Introduction
This section provides an overview of the LCEVC decoding components for Web, included as part of the V-Nova LCEVC SDK, and provides instructions on how to integrate them into different HTML5 players.
LCEVC-enhanced HTML5 pipeline
As shown in Figure 1, the main change in the video pipeline due to enabling LCEVC decoding is to hide the original video tag region and then play back video on a new canvas region. This new canvas region and passing the MSE SourceBuffers into the LcevcDil.js module are the main requirements of the modified video pipeline. The following sections provide further detail on these aspects as well as integration with web based video players.
The HTML5 decoding takes the following inputs:
Video segment as an MSE SourceBuffer that is also fed to the HTML Video Element;
Video element for the base decoded video picture;
A div element as destination for subtitles;
Canvas element as destination for the LCEVC-enhanced decoded video.
By using the requestAnimationFrame API, the LCEVC-enhanced decoder extracts each video frame from the video element and renders the LCEVC-enhanced output frame on the given canvas element.
Since subtitles (e.g WebVTT) are typically rendered by the browser on the video tag, there is currently no way for the LCEVC decoder to extract that region and move it to the canvas. As a result, the solution currently offered by the decoder is to render the cues via simple, yet customizable, div rendering on top of the canvas element.
Supported browsers and platforms
The following capabilities are required in order to integrate V-Nova LCEVC HTML5 playback:
WebGL 1.0 with FrameBuffer capability. This is almost universal among current browsers and systems.
WebWorkers / WebAssembly.
WebAudio with Delay node functionality.
Typical steps taken to verify browser type and feature required including example code are described below:
Step 1: Detect the supported browser and browser version.
The supported browser and versions for Windows:
Chrome (version ≥ 57)
Firefox (version ≥ 52)
Edge (version ≥ 16)
The supported browser and versions for MacOS:
Chrome (version ≥ 57)
Firefox (version ≥ 52)
Safari (version ≥ 11)
Browsers tested on Ubuntu 18.04 LTS:
Chrome version 92.0.4515.131
Firefox version 94.0
Sample code:
Step 2: Detect the OS.
It is advised that the supported browser for the respective OS is used, as specified in Step 1.
Step 3: Check that WebGL 1.0 is available.
Create a canvas element. Note that the canvas is not added to the document itself, so it is never displayed in the browser window.
Step 4: Check if the browser supports/does not support WebWorkers.
Step 5: If all of the preceding requirements(steps) are satisfied, then proceed to the video playback. Otherwise, display an alert message to the user.
Components
The HTML5 delivery for the LCEVC SDK consists of the following sets of Javascript and Web Assembly files specific to decoding LCEVC-enhanced streams:
liblcevc_dpi.wasm: V-Nova LCEVC WebAssembly decoder library.
lcevc_dil.min.js: V-Nova LCEVC JavaScript player.
lcevc_dil_patch_xyz.js: V-Nova LCEVC JavaScript functions that are used in conjunction with the specific player being used e.g. lcevc_dil_patch_shaka.js
dil.js integration guide
This section outlines the steps and considerations needed to integrate dil.js with any HTML5 player based on Media Source Extensions (MSE), and how to write your own patch file. The examples given here refer to hls.js but the principles are consistent for other players.
Overview
The general concept is that the base layer of the video (the image of the frame) is provided by the browser's native video tag, while the LCEVC enhancement data is provided by extra data stored in the video stream. The supplied LCEVC library decodes these enhancements into a texture, then using WebGL, composites this texture on top of the original video image to create the final improved frame.
It is essential that the timestamp of the metadata exactly matches the timestamp of the video image, which can be achieved using JavaScript, as they are provided in different ways by the browser.
Each video player is coded differently. With some (such as hls.js) it may be possible just to hotwire global JavaScript properties and functions, and provide the integration through a patch script. With others the only option may be to compile from source, and bundle an entire version of the library.
The steps taken in hls.js serve as an example and starting point to adding LCEVC support to the video technology you wish to target. Please refer to the file lcevc_patch_hls.js when reading this as it includes the methods in that player which must be overidden to invoke LCEVC-enhancement decoding and equivalent methods should be identified in the player you are using.
1. Opening and Closing LCEVC
The recommended way to initialise the LCEVC object is through an attachLcevc
function that should be called directly after the player has been created.
A reference is passed to the canvas (where the frames will be rendered in WebGL) along with the configuration options (some of which can not be modified after creation).
The function is defined inside the patch file as an extension of the hls.js prototype. By listening to the MEDIA_ATTACHING and MEDIA_DETACHING events, the player is able to create an instance of the LCEVC object in memory and remove it from memory when the player closes, seamlessly, without the host page needing any extra script.
2. Appending Buffer Data
The main job of any video stream player is to parse the manifest file (m3u8) and manage the network, so that the correct video byte data is downloaded from the server and attached to the video player at the right time.
Each of the video technologies mentioned; hls.js, Video.js and Shaka contain a function which appends incoming byte data to a MediaSource Buffer object. At this point video data should be intercepted and a copy of the data also passed to the LCEVC decoder.
NOTE: The LCEVC function “lcevc.appendBuffer” passes the arrayBuffer to a WebWorker which demuxes and decodes it, then stores the extracted LCEVC header packets.
3. Maintaining the Profile Level and PTS Drift
An adaptive bitrate video stream can be composed of video segments with different bitrates (to accommodate changing network conditions) that are concatenated to create a seamless playback inside a single video tag. Because these segments might have slightly different start and end timestamps it is possible for the residual metadata to become misaligned with the base video layer.
Every event of the video player that indicates that the PTS offset has changed when parsing a new fragment. Sometimes they come with extra information like type of fragment, level and drift time. This extra data helps LCEVC with the synchronisation of the residuals.
In hls.js the following event is used:
Whenever the player indicates that the network has changed and so the settings of the video profile the store of LCEVC residuals (collected from metadata) must be flushed. This means whenever a level switch occurs, or the coder changes video source.
In hls.js the following events are used:
API
The interface between the webpage script and the LCEVC-enhanced player is maintained by a simple API using the following properties, methods, and events.
Configurations options
Configurations parameters can be provided to lcevc_dil.min.js to create an lcevcDil
object.
renderAtDisplaySize
Use the display size instead of the video size when rendering. Useful when the display size is lower than the video size. For example, if the video is 1080p but the player size is 720p, it will render at 720p.
Default: True
logLevel
Set the lcevc log level. Depending on the level specified, different levels of message feedback detail will be printed in the console.
Default: LcevcDil.LogLevel.NONE
Dynamic Performance Scaling
Enable or disable dynamic performance scaling. Dynamic performance scaling monitors playback to ensure that the number of frames being dropped due to constrained system resources hasn't reached an unacceptable level. If the decoding system is struggling, LCEVC decoding will be temporarily paused with the video just displaying the base video decode.
Default: True
playerControls
Enables a simple player controller with some customisation options. It is used to debug the actions of a player controller. Also, it give some info about the stream like video size, selected profile, frame rate and timestamp. It can be configured with the following parameters:
enabled:
True
to enable it, otherwiseFalse
.position: CSS style position of the controls.
offsetY: Vertical position offset of the controls.
offsetX: Horizontal position offset of the controls.
colorPlayed: Hex color of the played time bar.
colorBuffered: Hex color of the buffered video.
fullscreenElement:
HTMLElement
of the player.
Default: null
Version control
LcevcDil.DIL_BUILD_DATE
Returns the build date.
Log level API
LcevcDil.LogLevel
Log level enumerate:
NONE: 0.
ERROR: 1.
WARNING: 2.
INFO: 3.
DEBUG: 4.
VERBOSE: 5.
LcevcDil API
LcevcDil(video, canvas, configOptions)
Construct a new lcevc object using the HTMLVideoElement
of the video, HTMLCanvasElement
of the display canvas and the lcevc configuration options
.
LcevcDil.video get
Return the HTMLVideoElement
used for the video.
LcevcDil.isFullscreen get
Return True
if the video is fullscreen, otherwise False
.
LcevcDil.isLive get
Return True
if the video is live, otherwise False
.
LcevcDil.isPerformanceScalingEnabled get
Return True
if dynamic performance scaling is enabled, otherwise False
.
LcevcDil.enablePerformanceScaling(value)
Enable or disable the dynamic performance scaling.
LcevcDil.isPerformanceScalingActive get
Return True
if the performance scaling is active, otherwise False
.
LcevcDil.isLcevcEnabled get
Return True
if lcevc data is enabled, otherwise False
.
LcevcDil.lcevcDataDetected get
Return True
if lcevc data is detected in the video, otherwise False
.
LcevcDil.frameWidth get
Return the width size of the displayed frame.
LcevcDil.frameHeight get
Return the height size of the displayed frame.
LcevcDil.currentLevel get
Return the number value of the current level.
LcevcDil.firstLcevcSegmentLoaded get
Return True
if a segment with lcevc has been loaded, otherwise False
.
LcevcDil.aspectRatio get
Returns the value of the aspect ratio of the video.
LcevcDil.frameRate get
Returns the frame rate of the video.
LcevcDil.getConfigOption(option)
Get the value of the option
of the lcevc configuration.
LcevcDil.setConfigOption(option, value)
Set the option
with the value
to the lcevc configuration.
LcevcDil.logLevel get/set
Get or set the log level to the given Lcevc.LogLevel
(default NONE).
LcevcDil.profileIn get
Get the input color profile.
LcevcDil.setProfileIn(profileName)
Set the input color profile to the given profile name.
LcevcDil.profileOut get
Get the output color profile.
LcevcDil.setProfileOut(profileName)
Set the output color profile to the given profile name.
LcevcDil.onFullscreen(enable)
Tell LcevcDil that the player has trigger a fullscreen event.
LcevcDil.clearTemporal()
Clears the lcevc temporal buffer. This will remove the current residuals and should only be used when moving or seeking in the video or when changing the profile.
LcevcDil.setCurrentLevel(level)
Notifies lcevc that a level loaded event has been triggered passing the new level
. This ensures that LCEVC data is managed correctly upon loading a new level.
LcevcDil.setLevelSwitching(level)
Notifies lcevc that a level switching event has been triggered passing the new level
. This ensures that LCEVC data is managed correctly on the transition between levels.
LcevcDil.appendBuffer(data, type, level, start, end)
Integration function only.
Receives video buffer data and sends it to the worker to detect and extract lcevc data. The arguments are:
data: The video buffer data.
type: The type of the data, can be
'video'
,'audio'
or'audiovideo'
.level: The current ABR profile/rendition/level ID of the data.
start (optional): The start time of the buffer.
end (optional): The end time of the buffer.
LcevcDil.flushBuffer(startTime, endTime)
Flush the residual and drift data of the given interval of time in milliseconds.
LcevcDil.resetBuffer()
Reset the internal buffers. This should only be used when changing the video. Calling this during playback may lead to unexpected behaviour.
LcevcDil.newPts(start, end, type, level, drift)
Integration function only.
Instructs lcevc that new information has been updated after parsing a fragment.
The type, level and drift are optional, but providing them helps lcevc to maintain correct synchronisation between the base video and decoded enhancement layers.
start: The start time in milliseconds of the fragment.
end: The end time in milliseconds of the fragment.
type: Type of the fragment, can be
'video'
or'audio'
.level: The level of the parsed fragment.
drift: The drift amount of time.
LcevcDil.displayError(message)
Prints an error message in the canvas where the video is displayed.
LcevcDil.clearError()
Clears the error message of the canvas if any.
LcevcDil.close()
Closes lcevc and releases memory in use. This should only be used when changing the video. Calling this during playback may lead to unexpected behaviour.
Events API
LcevcDil.on(type, listener)
Attach an event listener of Lcevc.Events
type to lcevc.
LcevcDil.off(type, listener)
Remove the event listener of the given Lcevc.Events
type.
Runtime events
LcevcDil.Events.PERFORMANCE_DROPPED
Occurs when Dynamic Performance Scaling is enabled, and GPU system resources are heavily constrained.
LcevcDil.Events.PERFORMANCE_RESTORED
Occurs after a PERFORMANCE_DROPPED event, when the GPU is able to run at optimal speed again. LCEVC enhancement decoding has been restored.
Last updated