The NexGuard library forensic watermarking tool Quickmark embeds a unique, invisible serial number onto video/audio content.

The minimum Android API for using the watermarking feature is 21 (Lollipop 5.0).
Watermark requires Android System Webview Version 42 or higher to be installed on the device.
Having any UI element rendered over the OTVVideoView  may prevent the watermark from working properly.


A working watermark requires the following parameters to work correctly:

  • A context to call OTVWatermark constructor
  • A valid OTVVideoView to bind the watermark to
  • A valid customer/system generated token of type String
  • A valid URL of type String
  • A valid Tenant name of type String

The last optional value is to set the ApiKey which is also of type String; this parameter is not mandatory. If these values available, a working QuickMarkView can be created.
The core class of the watermarking function is Watermark. Its purpose is to take the above parameters passed by the user to create a new object of the QuickMarkView class and bind it to the provided OTVVideoView before starting the watermark playback. The class is also responsible for handling error message events and starting and stopping the QuickMarkView whenever video is played or paused.

Currently, the only cases that trigger an error are:

  • Null tenant value
  • Null token value
  • Null server URL value
  • No server response
  • A URL shorter than four characters

In particular, the following errors do not get thrown (errors are silently ignored):

  • Invalid URL string
  • Incorrect token value


The Quickmark library (current version 1.1.5) is embedded within the SDK .aar library: there is no need to include or import additional libraries to your project.

Example code

Attaching a watermark is quite simple if you have the five parameters above. Since OTVVideoView is required to bind and unbind the QuickMarkView, we recommend you tie the watermark lifecycle to the OTVVideoView lifecycle. A simple example of implementing the watermark feature is shown below.

Create/bind watermark

import nagra.otv.sdk.OTVLog;
import nagra.otv.sdk.OTVSDK;
import nagra.otv.sdk.OTVVideoView;
import nagra.otv.sdk.Watermarking.Watermark;
import nagra.otv.sdk.Watermarking.WatermarkErrorId;
import nagra.otv.sdk.Watermarking.WatermarkErrorListener;
import nagra.otv.sdk.Watermarking.WatermarkMessageListener;
    private static String TAG = "Watermarking";

    private static String TOKEN      = "TOKEN";
    private static String API_KEY    = "API_KEY";
    private static String TENANT_ID  = "TENANT_ID";
    private static String SERVER_URL = "SERVER_URL";

    private OTVideoView mVideoView = null;
    private Watermark mWatermark

    // your function that creates/initialises your video view.
    // Once the video view is setup you can call watermark to bind it to the player
    private void initVideoView() {
        // The OTVSDK.load() method must be called before the SDK can be used
        // You may wish to do this in an application class
        // OTVSDK expects to find the player licence as an opy_licence in the res/raw directory
        mVideoView = (OTVVideoView) xView.findViewById(;
        //some video view initialising code

    private void startWatermark() {
        mWatermark = new Watermark(getContext());

    *Create a watermark error listener to react to server watermark responses
    private WatermarkErrorListener mErrorListener = new WatermarkErrorListener() {
        public void onError(WatermarkErrorId watermarkErrorId, String s) {
            switch (watermarkErrorId) {
            case INVALID_TOKEN:
            case INVALID_URL:
            case INVALID_SERVER_ANSWER:
            case CANNOT_CONTACT_SERVER:
            case NO_ERROR:

    private WatermarkMessageListener mMessageListener = new WatermarkMessageListener() {
        public void onMessage(String s) {
            OTVLog.d(TAG, "watermark message: " + s);

All mWatermark configuration must be set prior to the binding call.

Destroy/unbind watermark

Assuming that the watermark has been constructed as referenced above then the code below should be run when the OTVVideoView is being destroyed to keep the watermark lifecycle matching with the video lifecycle.

    private void destroyVideoView() {
      //some video view destruction code
      mWatermark = null;

    * stop the watermark view and remove all listeners then unbind the OTVVideoView.
    private void stopWatermark(){
      if(mWatermark != null && mWatermark.boundPlayer() == mVideoView) {