Polyv Help Center

Help Center

Playing Encrypted Videos

Updated: 2026-05-22 22:24:15

Polyv video encryption uses a proprietary encryption algorithm, providing an integrated video security solution that includes encrypted transcoding, secure transmission, and decryption playback. By applying high-strength encryption to the video data itself, even if the video file is downloaded locally, it cannot be directly played or distributed, effectively preventing video leaks and piracy. For more details, see: Video Encryption.

To facilitate rapid integration for developers, the decryption and playback logic is encapsulated within the player. Compared to playing regular videos, developers only need to pass an additional playback credential parameter to the player to enable encrypted video playback.

Development Guide

Encrypted videos must be played using the playback credential method. The player supports the following playback credential parameters. Please pass the corresponding parameter based on your integration method. For new integrations, it is recommended to use playsafe or playsafeUrl.

Name Type Description
playsafe String/Function Recommended authorization credential for playing encrypted videos, suitable for PC Web and mobile H5. The business server obtains the token via the Create Playsafe Token API and returns it to the player. Supports passing the token directly or dynamically obtaining it via a Function.
playsafeUrl String The API URL for obtaining the playback credential for encrypted videos, suitable for PC Web and mobile H5 (mutually exclusive with the playsafe parameter). For new integrations, it is recommended to use playsafeUrl or the playsafe Function, where the business server returns the token in real-time.
ts Number Compatibility parameter for playing encrypted videos on mobile H5, representing a 13-digit millisecond timestamp. This parameter is still valid but is no longer the recommended integration method.
sign String Compatibility signature for playing encrypted videos on mobile H5. The generation rule is to concatenate the values of the VOD account's secretkey, vid, and ts in order, then perform an MD5 calculation. It is generated by the business server and returned to the player. This parameter is still valid but is no longer the recommended integration method.
Note: The sign signature does not need to be converted to uppercase.
Signature example:
If the secretkey is abc, the vid is 123, and the ts is 1672829071000, then the sign is md5("abc1231672829071000")

Note: For new integrations, it is recommended to uniformly use playsafe or playsafeUrl for both PC Web and mobile H5 to obtain the playback token. The ts and sign parameters are still usable, mainly for historical compatibility, but are no longer recommended.

Player Code Example:

<div id="player"></div>
<script src="//player.polyv.net/resp/vod-player/latest/player.js"></script>
<script>
var player = polyvPlayer({
    wrap: '#player',
    width: 800,
    height: 533,
    vid: '88083abbf5bcf1356e05d39666be527a_8',
    // 推荐:传入业务方服务端获取到的 playsafe token,PC Web 和移动端 H5 均可使用
    playsafe: '81814fed-bdd0-4506-bec1-ebc8093148c5-hfevwsfxcsbcocx'
    // 如需通过业务方自定义接口动态获取播放凭证,可将 playsafe 替换为:
    // playsafeUrl: 'https://myDomain.com/token'
});

// 切换加密视频时,需要重新获取播放凭证。如果初始化播放器时使用了 playsafeUrl 参数,则播放器会自动获取新的凭证,无需传 playsafe 参数。
player.changeVid({
  vid: '88083abbf5bcf1356e05d39666be527a_9', // 需要切换的视频 vid
  playsafe: '81814fed-bdd0-4506-bec1-ebc8093148c6-hfevwsfxcsbcocx' // 新获取的 playsafe token
});
</script>

Before playing an encrypted video on a web page, you need to first access the business server's authorization verification API (you can add your own business authorization logic here, such as checking login status or course purchase; HTTPS is recommended). If the business allows playback, obtain the playback credential via the Create Playsafe Token API and return it to the web player. For new integrations, it is recommended to uniformly use Playsafe Token for both PC Web and mobile H5. The legacy ts and sign methods for mobile H5 are still valid but are mainly for historical compatibility and are no longer the recommended integration method.

Server-side Code Example for Generating Playback Credentials:

PHP Code:

// 接口中应附带自有业务的授权验证逻辑,如判断是否登录、是否购买课程等

// 以下为生成播放凭证的代码示例
function get_client_ip() {
  if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
    $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
  } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
      $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
  } else {
      $ipaddress = $_SERVER['REMOTE_ADDR'];
  }
    return $ipaddress;
}

$userid = 'your userid';       // 保利威点播账号的 userid
$secretkey = 'your secretkey';     // 保利威点播账号的secretkey
$videoId = '88083abbf5bcf1356e05d39666be527a_8';  // 视频id
$ts = time() * 1000;      // 时间戳
$viewerIp = get_client_ip();  // 观众ip
$viewerId = '12345';      // 观众id
$viewerName = 'testUser';  // 观众昵称, 若值为中文需要urlencode('张三')
$extraParams = 'HTML5';  // 自定义扩展参数
$disposable = 'false'; // true 表示 token 仅一次有效。false 则表示在有效期内可以多次验证。默认为 false。

/* 将参数 userid、videoId、ts、viewerIp、viewerId、viewerName、extraParams、disposable 按照 ASCII 升序 key + value + key + value ... + value 拼接
*/
$concated =  'disposable'.$disposable.'extraParams'.$extraParams.'ts'.$ts.'userid'.$userid.'videoId'.$videoId.'viewerId'.$viewerId.'viewerIp'.$viewerIp.'viewerName'.$viewerName;
// 首尾加上secretkey值
$plain = $secretkey.$concated.$secretkey;
// 取大写MD5
$sign = strtoupper(md5($plain));

// 然后将下列参数用post请求  https://hls.videocc.net/service/v1/token 获取 token
$url = 'https://hls.videocc.net/service/v1/token';
$data = array('userid' => $userid, 'videoId' => $videoId, 'ts' => $ts, 'viewerIp' => $viewerIp, 'viewerName' => $viewerName, 'extraParams' => $extraParams, 'viewerId' => $viewerId, 'disposable' => $disposable, 'sign' => $sign);
$options = array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded",
        'method'  => 'POST',
        'content' => http_build_query($data)
    )
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);

// 获取接口返回结果中的token值, 并传给播放器播放加密视频
$token = json_decode($result)->data->token;
echo $token;

Java SpringMvc Code:

@ResponseBody
@RequestMapping("/playerSafe")
public String playerSafe(HttpServletRequest request) {
    String userid = "your userid";       // 保利威点播账号的 userid
    String secretkey = "your secretkey";     // 保利威点播账号的secretkey
    String videoId = "88083abbf5bcf1356e05d39666be527a_8";  // 视频id
    long ts = System.currentTimeMillis();      // 时间戳
    String viewerIp = getClientIp(request);  // 观众ip
    String viewerId = "12345";      // 观众id
    String viewerName = "testUser";  // 观众昵称, 若值为中文需要urlencode('张三')
    String extraParams = "HTML5";  // 自定义扩展参数
    boolean disposable = false; // true 表示 token 仅一次有效。false 则表示在有效期内可以多次验证。默认为 false。

    /* 将参数 userid、videoId、ts、viewerIp、viewerId、viewerName、extraParams、disposable 按照 ASCII 升序 key + value + key + value ... + value 拼接
     */
    String concated = "disposable" + disposable + "extraParams" + extraParams + "ts" + ts + "userid" + userid + "videoId" + videoId + "viewerId" + viewerId + "viewerIp" + viewerIp + "viewerName" + viewerName;
    // 首尾加上secretkey值
    String plain = secretkey + concated + secretkey;
    // 取大写MD5,可自行选择md5库
    String sign = md5Hex(plain).toUpperCase();

    // 然后将下列参数用post请求  https://hls.videocc.net/service/v1/token 获取 token
    String url = "https://hls.videocc.net/service/v1/token";

    Map<String, String> params = new HashMap<>();
    params.put("userid", userid);
    params.put("videoId", videoId);
    params.put("ts", String.valueOf(ts));
    params.put("viewerIp", viewerIp);
    params.put("viewerName", viewerName);
    params.put("extraParams", extraParams);
    params.put("viewerId", viewerId);
    params.put("disposable", String.valueOf(disposable));
    params.put("sign", sign);
    // 可自行选择http客户端
    String response = HttpClientUtil.getInstance().sendHttpPost(url, params);

    try {
        //解析json
        ObjectMapper objectMapper = new ObjectMapper();
        TokenResponse tokenResponse = objectMapper.readValue(response, TokenResponse.class);
        // 响应代码,200为成功,403为ts过期或签名错误,400为参数错误(例如缺少 userid 或 videoId)
        if (tokenResponse.getCode() == 200) {
            Map data = (Map) tokenResponse.getData();
            return data.get("token").toString();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "";
}
static class TokenResponse {
    int code;
    String status;
    String message;
    Object data;
    //省略getter、setter...
}
public String getClientIp(HttpServletRequest request) {
    String ip = request.getHeader("x-forwarded-for");
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getRemoteAddr();
    }
    return ip;
}

If the player uses the playsafeUrl parameter, the output must be in JSON format:

PHP Code

// 已省略获取token的代码...
$token = json_decode($result)->data->token;
$code = json_decode($result)->code; // 响应代码,200为成功,403为ts过期或签名错误,400为参数错误(例如缺少 userid 或 videoId)
$message=json_decode($result)->message;
$status=json_decode($result)->status;
if($code == 200){
    $array = Array("code"=>$code,'status'=>$status,'message'=>$message,"data"=>$token);
}else{
    $array = Array("code"=>$code,'status'=>$status,'message'=>$message,"data"=>json_decode($result)->data);
}
$Json = json_encode($array);
echo $Json; //输出json

Java SpringMvc Code

@ResponseBody
@RequestMapping("/playerSafeUrl")
public Map<String, Object> playerSafeUrl(HttpServletRequest request) {
    // 已省略获取token的代码...
    Map<String, Object> resultMap = new LinkedHashMap<>();
    try {
        //解析json
        ObjectMapper objectMapper = new ObjectMapper();
        TokenResponse tokenResponse = objectMapper.readValue(response, TokenResponse.class);
        resultMap.put("code", tokenResponse.getCode());
        resultMap.put("status", tokenResponse.getStatus());
        resultMap.put("message", tokenResponse.getMessage());
        // 响应代码,200为成功,403为ts过期或签名错误,400为参数错误(例如缺少 userid 或 videoId)
        if (tokenResponse.getCode() == 200) {
            Map data = (Map) tokenResponse.getData();
            resultMap.put("data", data.get("token"));
        } else {
            resultMap.put("data", tokenResponse.getData());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return resultMap;
}

playsafeUrl Return Result Example:

Request Successful:

{
    "code": 200,
    "status": "success",
    "message": "",
    "data": "973d7731803940a1b14fdc93941f493c"
}

Request Failed (Signature Error):

{
    "code": 403,
    "status": "error",
    "message": "sign_invalid",
    "data": "sign parameter invalid."
}

The playsafeUrl may encounter cross-origin issues. For solutions, please refer to: Cross-Origin Access Settings.

Legacy Mobile H5 Compatibility Method Using ts + sign

For legacy mobile H5 playing web encrypted videos, you can also return the sign and ts parameters to the player. This method is still valid and existing services can continue to use it. For new integrations, it is recommended to use playsafe or playsafeUrl to obtain the playback token.

// php
$vid = "88083abbf5bcf1356e05d39666be527a_8"; // 视频vid
$secretkey= "your secretkey"; // 保利威点播账号的secretkey
$ts=time()*1000;  // 10位的秒级时间戳,后面加多3个0,最后为13位的数值
$sign = md5($secretkey.$vid.$ts); 
联系客服,在线咨询