Polyv Help Center

Help Center

Authorized Playback and Watermark

Updated: 2024-04-22 19:18:32

Screen recording is one of the most difficult video piracy methods to prevent. The anti-recording watermark feature provided by the Polyv player displays text content (usually the viewer's identity ID) irregularly scrolling across the video to deter pirates, thereby protecting video copyright.

Additionally, on the user's website, besides verifying whether a viewer has permission to access the video playback page through login information (cookies), the Polyv player can also verify whether a viewer has permission to play a specific video, thus achieving dual verification of viewer permissions.

Video introduction of the anti-recording watermark: Anti-Recording Tool – Watermark (Video).

Implementation Flow

image-20200831160621474

Implementation Steps

1. Management Console Settings

  1. Log in to the Cloud Video on Demand management console, click 【Settings】【Video Settings】 to enter the video settings page.

  2. In the Authorized Playback and Anti-Recording Watermark Interface settings section, fill in the business party's interface service URL. image-20200831161317380

When the player requests the authorization interface, it will automatically adapt to the following situations:

  1. When a complete URL is filled in, the player will request it directly, e.g., http://mywebsite.com/interface/validate。
  2. When an interface address without a protocol header is filled in, the player will automatically complete it based on the request protocol of the current page. For example, if //mywebsite.com/interface/validate is filled in and the current page uses the https protocol, the actual request will be: https://mywebsite.com/interface/validate。
  3. When an interface address without a protocol header and HOST is filled in, the player will automatically complete it based on the request protocol and HOST of the current page. For example, if /interface/validate or interface/validate is filled in, and the current page's domain is mywebsite2.com using the http protocol, the actual request will be: http://mywebsite2.com/interface/validate。

2. Business Party Server-Side Implementation

1. Player Request

After setting the authorization playback and watermark interface in the management console, the Polyv player will first request the interface set in the background when playing a video. The request method is GET, and it will include the four parameters: vid, code, t, and callback. For example: https://www.mywebsite.com/validate?vid=e2e84a73837363106d8d257f60e55c4c_e&code=&t=1457938821973&callback=polyvObject16209048491895664483_1457938783908&_=1457938784101。

Where code is a parameter in the player embed code, and its value can be customized; t is a random number generated by the player. Example player embed code:

<script src='https://player.polyv.net/script/player.js'></script>
<div id='player'></div>
<script>
var player = polyvPlayer({
    wrap: '#player',
    width: 800,
    height: 533,
    vid: '88083abbf5bcf1356e05d39666be527a_8',
    code: 'myCodeValue'  // 用户可自定义参数值,也可以不设置此参数,那么在请求接口时该参数值为空。参数值为中文时需要做base64URLSafe。
});
</script>

Since the H5 player requests the user's interface via Ajax, it requires cross-origin requests, hence the callback parameter is needed. The Flash player achieves cross-origin through a cross-domain file, so it does not need the callback parameter and only submits the three parameters vid, code, and t when requesting the interface. For Flash player cross-origin implementation, please refer to Cross-Origin Access Settings.

2. Server-Side Interface Implementation

If the business party's server-side interface only needs to implement authorization verification functionality, it only needs to return the three parameters status, username, and sign to the player for verification.

PHP example for server-side implementation:

// validate.php
<?php
$username = "elvis"; // 用户昵称, 若值为中文需要urlencode('张三'),可从session获取
$secretkey = "secretkey"; // 登录保利威管理后台,点击 【设置】 → 【API接口】获取
$vid=$_GET["vid"];
$t = $_GET["t"];
$code = $_GET["code"];

if($username=="elvis"){
  $status = 1; // 业务方可自定义授权验证逻辑
}else {
  $status = 2;
}
if(!empty($_GET["callback"])){
  $callback = $_GET["callback"];
}else{
  $callback = '';
}

$sign=md5("vid=$vid&secretkey=$secretkey&username=$username&code=$code&status=$status&t=$t");
$array=Array("status"=>$status,"username"=>$username,"sign"=>$sign);
$Json = json_encode($array);

if($callback!=''){ //PC H5播放器会提交callback参数
  echo $callback."(".$Json.")";
} else{ //Flash播放器不提交callback参数
  echo "(".$Json.")";
}
?>

Java SpringMvc example:

@ResponseBody
@RequestMapping("/player-auth")
public String playerAuth(String vid, long t, String code, String callback) {
    String username = "elvis";
    String secretKey = "secretkey";
    int status;

    // 业务方可自定义授权验证逻辑
    if ("elvis".equals(username)) {
        status = 1;
    } else {
        status = 2;
    }

    // md5签名,自行选择md5库
    String plain = "vid=" + vid + "&secretkey=" + secretKey + "&username=" + username + "&code=" + code + "&status=" + status + "&t=" + t;
    String sign = md5Hex(plain);

    Map<String, Object> resultMap = new HashMap<>();
    resultMap.put("username", username);
    resultMap.put("status", status);
    resultMap.put("sign", sign);

    // json序列化
    ObjectMapper objectMapper = new ObjectMapper();
    String resultJson = "";
    try {
        resultJson = objectMapper.writeValueAsString(resultMap);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }

    if (callback != null && !"".equals(callback)) {
        return callback + "(" + resultJson + ")";
    } else {
        return resultJson;
    }
}

Where the calculation rule for sign is: concatenate vid, secretkey, username, code, status, t parameters and perform MD5 calculation:

Plain ="vid=" + vid + "&secretkey=" + secretKey + "&username=" + username + "&code=" + code + "&status=" +status + "&t=" + t
sign = MD5.hash(Plain);

Example interface response:

  polyvObject16208229674372271079_1478765178186({
  "status":1,
  "username":"elvis",
  "sign":"1cca74bd55c6076091ed84807065e5b7"
  })
// 不提交callback参数时
{
  "status":1,
  "username":"elvis",
  "sign":"2c2bfb00314da7d768d50a7d1e93bd9f"
}

If, in addition to authorization verification, the watermark functionality is also required, the interface needs to return parameters related to the watermark.

PHP example for server-side implementation:

// validate.php
<?php
$username = "elvis"; // 用户昵称, 若值为中文需要urlencode('张三'),可从session获取
$secretkey = "secretkey"; // 登录保利威管理后台,点击 【设置】 → 【API接口】获取
$vid=$_GET["vid"];
$t = $_GET["t"];
$code = $_GET["code"];
$fontSize="40";
$fontColor="0xFFE900";
$speed="200";
$filter="on";
$setting="3";
$alpha="1";
$filterAlpha="1";
$filterColor="0x3914AF";
$blurX="2";
$blurY="2";
$tweenTime="1";
$interval="5";
$lifeTime="3";
$strength="4";
$show="on";
$msg="Errormessage!";

if($username=="elvis"){ // 业务方可自定义授权验证逻辑
 $status = 1;
}else {
 $status = 2;
}

if(!empty($_GET["callback"])){
 $callback = $_GET["callback"];
}else{
 $callback = '';
}

$sign=md5("vid=$vid&secretkey=$secretkey&username=$username&code=$code&status=$status&t=$t&msg=$msg&fontSize=$fontSize&fontColor=$fontColor&speed=$speed&filter=$filter&setting=$setting&alpha=$alpha&filterAlpha=$filterAlpha&filterColor=$filterColor&blurX=$blurX&blurY=$blurY&interval=$interval&lifeTime=$lifeTime&tweenTime=$tweenTime&strength=$strength&show=$show");
$array = Array("status"=>$status,"username"=>$username,"sign"=>$sign,"msg"=>$msg,"fontSize"=>$fontSize,"fontColor"=>$fontColor,"speed"=>$speed,"filter"=>$filter,"setting"=>$setting,"alpha"=>$alpha,"filterAlpha"=>$filterAlpha,"filterColor"=>$filterColor,"blurX"=>$blurX,"blurY"=>$blurY,"tweenTime"=>$tweenTime,"interval"=>$interval,"lifeTime"=>$lifeTime,"strength"=>$strength,"show"=>$show,);
$Json = json_encode($array);

if($callback!=''){
 echo $callback."(".$Json.")";
} else{
 echo $Json;
}
?>

Java SpringMvc example:

@ResponseBody
@RequestMapping("/player-auth-marquee")
public String playerAuthMarquee(String vid, long t, String code, String callback) {
    String username = "suki";
    String secretKey = "AiDQw1mAmi";
    String fontSize = "40", fontColor = "0xFFE900", speed = "200",
            filter = "on", setting = "3", alpha = "1", filterAlpha = "1",
            filterColor = "0x3914AF", blurX = "2", blurY = "2", tweenTime = "1",
            interval = "5", lifeTime = "3", strength = "4", show = "on", msg = "Errormessage!";
    int status;

    // 业务方可自定义授权验证逻辑
    if ("suki".equals(username)) {
        status = 1;
    } else {
        status = 2;
    }

    code = code == null?"":code;

    // md5签名,自行选择md5库
    String plain = "vid=" + vid + "&secretkey=" + secretKey + "&username=" + username + "&code=" + code + "&status=" + status + "&t=" + t +
            "&msg=" + msg + "&fontSize=" + fontSize + "&fontColor=" + fontColor + "&speed=" + speed + "&filter=" + filter + "&setting=" + setting +
            "&alpha=" + alpha + "&filterAlpha=" + filterAlpha + "&filterColor=" + filterColor + "&blurX=" + blurX + "&blurY=" + blurY +
            "&interval=" + interval + "&lifeTime=" + lifeTime + "&tweenTime=" + tweenTime + "&strength=" + strength + "&show=" + show;
    String sign = md5Hex(plain);

    Map<String, Object> resultMap = new HashMap<>();
    resultMap.put("username", username);
    resultMap.put("status", status);
    resultMap.put("sign", sign);
    resultMap.put("msg", msg);
    resultMap.put("fontSize", fontSize);
    resultMap.put("fontColor", fontColor);
    resultMap.put("speed", speed);
    resultMap.put("filter", filter);
    resultMap.put("setting", setting);
    resultMap.put("alpha", alpha);
    resultMap.put("filterAlpha", filterAlpha);
    resultMap.put("filterColor", filterColor);
    resultMap.put("blurX", blurX);
    resultMap.put("blurY", blurY);
    resultMap.put("tweenTime", tweenTime);
    resultMap.put("interval", interval);
    resultMap.put("lifeTime", lifeTime);
    resultMap.put("strength", strength);
    resultMap.put("show", show);

    // json序列化,可自行选择json序列化库
    ObjectMapper objectMapper = new ObjectMapper();
    String resultJson = "";
    try {
        resultJson = objectMapper.writeValueAsString(resultMap);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }

    if (callback != null && !"".equals(callback)) {
        return callback + "(" + resultJson + ")";
    } else {
        return resultJson;
    }
}

Where the calculation rule for sign is (parameters must be concatenated in the order shown in the example):

Plain = "vid=" + vid + "&secretkey=" + secretKey + "&username=" + username + "&code=" + code + "&status=" + status + "&t=" + t +
"&msg=" + msg + "&fontSize=" + fontSize + "&fontColor=" + fontColor + "&speed=" + speed +"&filter=" +filter + "&setting=" + setting +
"&alpha=" + alpha + "&filterAlpha=" + filterAlpha  + "&filterColor=" + filterColor + "&blurX=" + blurX + "&blurY=" + blurY +
"&interval=" + interval + "&lifeTime=" + lifeTime + "&tweenTime=" + tweenTime + "&strength=" + strength + "&show=" +show;
sign = MD5.hash(Plain);

For example: When vid="8f8482aaab11dd5f45f183a9192a04c5_8",secretkey="AiDQw1mAmi",username="suki",code="abc",status="1",t="143020010115550947",msg="Errormessage!",fontSize="40",fontColor="0xFFE900",speed="200",filter="on",setting="3",alpha="1",filterAlpha="1",filterColor="0x3914AF",blurX="2",blurY="2",interval="5",lifeTime="3",tweenTime="1",strength="4",show="on" the string concatenated for MD5 calculation is: vid=8f8482aaab11dd5f45f183a9192a04c5_8&secretkey=AiDQw1mAmi&username=suki&code=abc&status=1&t=143020010115550947&msg=Errormessage!&fontSize=40&fontColor=0xFFE900&speed=200&filter=on&setting=3&alpha=1&filterAlpha=1&filterColor=0x3914AF&blurX=2&blurY=2&interval=5&lifeTime=3&tweenTime=1&strength=4&show=on Then the sign is the 32-character lowercase MD5 value: 3b07f56f29b7fd728bf20020442338e7

Example interface response:

{
  "status":1,
  "username":"elvis",
  "sign":"6ab63590797e513d1b6c46b407413478",
  "msg":"Errormessage!",
  "fontSize":"40",
  "fontColor":"0xFFE900",
  "speed":"200",
  "filter":"on",
  "setting":"3",
  "alpha":"1",
  "filterAlpha":"1",
  "filterColor":"0x3914AF",
  "blurX":"2",
  "blurY":"2",
  "tweenTime":"1",
  "interval":"5",
  "lifeTime":"3",
  "strength":"4",
  "show":"on"
}

3. Interface Return Parameter Description

Parameter Type Required Default Description
status Integer Yes / Whether playback is allowed: 1 Allow 2 Deny
username String Yes / Viewer name, also used as the text content displayed in the watermark
sign String Yes / Interface signature, used to verify if the returned content has been tampered with
show String Yes off When the parameter value is "on", the watermark is displayed; default is off
setting Integer Yes 1 Watermark scrolling style: 1 Scroll from right to left 2 Flash at random positions 3 Flash scroll from right to left
speed Integer Yes 200 Time required for the watermark text to move from right to left, unit: 1/10 second, only effective for setting(1, 3)
lifeTime Integer Yes 3 Watermark text display time, unit: seconds, only effective for setting(2)
interval Integer Yes 5 Watermark text hidden interval time, unit: seconds, only effective for setting(2, 3)
tweenTime Integer Yes 1 Watermark text fade in/out time, unit: seconds (Deprecated)
fontSize Integer Yes 30 Font size of the watermark text
fontColor String Yes 0x000000 Watermark text color, represented in hexadecimal color value, e.g., 0xFF0000, default is black
alpha Float Yes 1 Watermark text transparency, range 0.01~1, parameter value cannot be less than 0.01
filter String Yes off Whether the watermark text has an outline, on outline off no outline
filterAlpha Float Yes 1 Text outline transparency, range 0~1
filterColor String Yes 0x000000 Text outline color, represented in hexadecimal color value, e.g., 0xFF0000, default is black
strength Integer Yes 4 Outline strength, range 0~255
blurX Integer Yes 2 Outline horizontal blur amount, range 0~255
blurY Integer Yes 2 Outline vertical blur amount, range 0~255
msg String Yes / Custom error message
  • setting(1): Watermark scrolls from right to left, completes scrolling in speed/10 seconds, then waits 2 seconds before the next scroll
  • setting(2): Watermark alternately displays and hides at random positions, displays for lifeTime seconds each time, then hides for interval seconds, then the next cycle begins
  • setting(3): Watermark scrolls from right to left, completes scrolling in speed/10 seconds, waits speed/10 + interval seconds before the next scroll, hides every 3 seconds during scrolling, and displays after 3 seconds of hiding
  1. When the interface is only used for authorization verification, only the three parameters status, username, and sign need to be returned; watermark-related parameters can be omitted.
  2. Please ensure the interface returns data in utf-8 encoding. Note that the status parameter is an integer type, not a string type.
  3. Currently, the watermark feature is not supported on mobile H5 players (1.0 does not support it; it is recommended to use 2.0).
  4. Please try not to modify the player style or the <video> tag.
联系客服,在线咨询