Copyright Protection Best Practices
1. Feature Overview
Polyv is committed to enhancing the security of video playback and protecting your video resources. Through its self-developed video copyright protection scheme (VRM) and proprietary encryption algorithms, Polyv can ensure the security of video files to the greatest extent possible. When integrating Polyv's PlaySafe video protection feature, it is recommended to refer to the best practices in this document to achieve optimal video security protection.
2. Overall Solution
Integrating the video encryption feature requires certain modifications on both your server side and client side. The following flowchart illustrates the overall workflow for playing encrypted videos:

The following sections describe each step in the flowchart in detail:
Your terminal requests a Token from your server
Before playing a video, your terminal (including Web, mobile App, PC player, etc.) should use the
vidof the video to be played and request a playback Token from your server through an interface you have developed internally. To enhance Token security, your interface should use the HTTPS protocol.Your server requests a Token from the Polyv server
Your server side should request the Token required for playing encrypted videos from the Polyv server via the Get Video Playback Credential interface.
- It is recommended to contact Polyv technical support to enable the IP Whitelist restriction feature. After setting up the whitelist, only the IP addresses you specify can obtain Tokens through this interface; other IPs will be unable to request Tokens from this interface.
The Polyv server returns the Token to your server
Upon receiving your request for the playback credential of a specific video, and after verifying no anomalies, the Polyv server will return a Token for playing the encrypted video to your server.
Your server returns the Token to your terminal
When your server receives the Token returned by Polyv, it needs to return this Token to the terminal. When returning the Token to the terminal, you should use your own defined encryption rules to encrypt the Token to prevent it from being leaked during network transmission.
Your terminal uses the VOD SDK to play the video
Before playing an encrypted video, you need to call the VOD SDK's interface and pass the Token obtained from your server. If you encrypted the Token on the server, you need to decrypt it on the terminal according to the corresponding rules before passing the actual Token to the VOD SDK.
The following sections explain the parts you need to modify and provide sample code for reference.
3. Server Side
Your server needs to focus on the "Interaction between Customer Server and Polyv Server" part shown in the diagram above.

On the server side, you should provide an interface that implements the functionality of requesting a Token for playing the corresponding video (specified by vid) from the Polyv server and returning it, so that your terminal can obtain the playback Token through the server. The specific functional points are as follows:
- Obtain interface request parameters: video
vid, userviewerId, and other parameters. - Request the Polyv server's Get Video Playback Credential interface. For mobile requests, the
viewerIdneeds to be Base64 encoded. - Parse the interface return value to obtain the Token.
- Encrypt the Token using your own defined encryption rules to prevent leakage.
- Return the encrypted Token to the client.
3.1 Sample Code
/**
* 获取点播加密视频的播放token
*/
@PostMapping("/getVodToken")
@ResponseBody
public ResponseVO getVodToken(@RequestBody GetTokenRequestVO tokenReq, HttpServletRequest request) throws IOException, NoSuchAlgorithmException {
// 请求参数处理
String videoId = tokenReq.getVideoId();
String viewerId = tokenReq.getViewerId();
if (StringUtils.isEmpty(videoId) || StringUtils.isEmpty(viewerId)) {
return ResponseVO.failure("argument is error");
}
Map<String, Object> args = new HashMap<>(16);
args.put("videoId", videoId);
args.put("viewerId", viewerId);
args.put("viewerIp", IPUtil.getIPAddress(request));
args.put("viewerName", tokenReq.getViewerName());
args.put("expires", tokenReq.getExpires());
args.put("disposable", tokenReq.getDisposable());
args.put("iswxa", tokenReq.getIswxa());
args.put("userId", USER_ID);
args.put("ts", System.currentTimeMillis());
// 去除空值参数
Map<String, String> params = args.entrySet()
.stream()
.filter(entry -> entry.getValue() != null)
.collect(
Collectors.toMap(Map.Entry::getKey, entry -> String.valueOf(entry.getValue()))
);
// 请求参数签名
params.put("sign", LiveSignUtil.getSign(params, SECRET_KEY));
// 向保利威服务器请求Token
TokenVO vo = RequestTokenService.requestTokenFromServer(params);
if (vo == null || vo.getCode() == null || vo.getCode() != HttpStatus.OK.value()) {
return ResponseVO.failure("请求数据失败");
} else {
// TODO 在返回Token前建议实现自己的加密逻辑,以免在网络传输过程中泄露Token
return ResponseVO.success(vo.getData());
}
}
The requestTokenFromServer method implements calling the Polyv server's Get Video Playback Credential interface to obtain the Token.
private const val API_URL = "http://hls.videocc.net/service/v1/token"
/**
* 向保利威服务器请求Token
* POST方式,Content-type: application/x-www-form-urlencoded
*/
fun requestTokenFromServer(params: Map<String, String>): TokenVO {
return httpClient.submitForm(
url = API_URL,
formParameters = Parameters.build {
params.forEach { (key, value) ->
append(key, value)
}
}
).bodyAsObject<TokenVO>()
}
More detailed code can be viewed at the Gitee address.
3.2 GetTokenRequestVO Parameter Description
| Parameter Name | Required | Type | Description |
|---|---|---|---|
| videoId | true | String | Video ID, e.g., e6b23c6f519c5906e54a13b8200d7bb0_e |
| viewerId | true | String | Viewer ID. Different viewers must use different IDs. For mobile requests, the viewerId must be Base64 encoded. |
| viewerIp | false | String | Viewer IP. If empty, the IP used to call the interface will be automatically obtained. |
| viewerName | false | String | Viewer name. |
| expires | false | Long | Token validity duration in seconds. Default is 10 minutes if empty. Maximum validity is 24 hours. |
| disposable | false | Boolean | Token validity type. Default is false.true: Token is valid for a single use (becomes invalid after one verification).false: Token can be verified multiple times within the validity period. |
| iswxa | false | Integer | Whether it is a WeChat Mini Program playback. Default is 0.1: Yes0: No |
| extraParams | false | String | Other custom parameters. |
3.3 TokenVO Parameter Description
| Parameter Name | Type | Description |
|---|---|---|
| token | String | Token value. |
| userId | String | Polyv VOD account ID. |
| appId | String | Account appId. |
| videoId | String | Video ID, e.g., e6b23c6f519c5906e54a13b8200d7bb0_e |
| viewerId | String | Viewer ID. |
| viewerIp | String | Viewer IP. |
| viewerName | String | Viewer name. |
| ttl | Long | Token validity duration in milliseconds. |
| disposable | Boolean | Token validity type.true: Token is valid for a single use (becomes invalid after one verification).false: Token can be verified multiple times within the validity period. |
| iswxa | Integer | Whether it is a WeChat Mini Program playback.1: Yes0: No |
| extraParams | String | Other custom parameters. |
| createdTime | Long | Token creation time, 13-digit millisecond timestamp. |
| expiredTime | Long | Token expiration time, 13-digit millisecond timestamp. |
4. Client Side
The client side needs to focus on the "Interaction between Customer Terminal and Customer Server" and "Interaction between Customer Terminal and Polyv VOD SDK" parts shown in the diagram above.

On the client side, you need to do the following:
Before playing a video, call the interface you developed on your server to obtain the playback Token for the corresponding video using the video
vid.Note: When mobile terminals (iOS and Android) request the playback Token from your server, the
viewerIdin the request parameters must be Base64 encoded.If you encrypted the Token on the server side, you need to decrypt the obtained Token first according to your custom rules.
Pass the decrypted Token through the API provided by the Polyv VOD SDK.
Steps 1 and 2 above belong to the "Interaction between Customer Terminal and Customer Server" and require your own development. They are not detailed here. The following sample code mainly demonstrates Step 3 – how to call the VOD SDK's API to pass the Token. This part belongs to the "Interaction between Customer Terminal and Polyv VOD SDK".
4.1 Web
For complete sample code, please refer to VOD JS SDK Play Encrypted Video.
var player = polyvPlayer({
wrap: '#player',
width: 800,
height: 533,
vid: '88083abbf5bcf1356e05d39666be527a_8',
playsafe:'81814fed-bdd0-4506-bec1-ebc8093148c5-hfevwsfxcsbcocx', // 通过 playsafe 传入 token
ts:'1568131545000',
sign:'88313661ba7ded642c7b557b0a364b4b'
});
4.2 iOS
For complete sample code, please refer to VOD iOS SDK 4. Video Playback section 4.1.2 External Playback Credential.
// 通过配置播放器的 requestCustomKeyTokenBlock 属性,播放器内部在开始播放加密视频时,将会自动执行该 block ,并使用 block 返回的 token 对加密视频进行解密。
self.player.requestCustomKeyTokenBlock = ^NSString *(NSString *vid) {
// 通过参数 vid,向客户自己的服务器请求 token
NSString *encodeToken = @"xxxxxxxx";
// 将服务器返回的 token 进行解密
NSString *decodeToken = @"yyyyyyyy";
return decodeToken;
};
// 通过 vid 获取在线播放视频模型
[PLVVodVideo requestVideoWithVid:vid completion:^(PLVVodVideo *video, NSError *error) {
// 播放视频
weakSelf.player.video = video;
}];
4.3 Android
4.3.1 Video Playback
For complete sample code, please refer to VOD Android SDK 4. Video Playback section 1.2 External Playback Credential.
videoView.setVideoTokenRequestListener(new IPLVVideoTokenRequestListener() {
@Override
public String onRequestToken(PolyvVideoVO videoVO, String viewerId, String viewerName, String viewerParam) {
// 返回外部获取的 token
return token;
}
});
// 通过vid播放视频
videoView.setVid(vid, bitrate, isMustFromLocal);
4.3.2 Video Download
For complete sample code, please refer to VOD Android SDK 5. Video Download.
downloader.setDownloaderTokenRequestListener(new IPLVDownloaderTokenRequestListener() {
@Override
public String onRequestToken(@NotNull String videoId, int bitRate) {
// 返回视频下载的token
return token;
}
});
4.4 C++ SDK
Code example for how the C++ SDK passes the Token and plays a video:
// 创建播放器对象,window为播放窗口句柄
auto player = PLVPlayerCreate(window);
// 播放前要先设置vid, videoPath为离线播放的视频存放地址,videoRate为视频的清晰度
PLVPlayerSetVideo(player, vid, videoPath, videoRate);
// 开始在线播放,token通过业务侧获取传入,seekMillisecond开始播放时想要seek的位置,sync是否同步(播放时会请求videoJson,同步时会阻塞等待请求结果,异步时通过回调通知结果)
PLVPlayerPlay(palyer, token, seekMillisecond, sync);
4.5 APICloud Platform
Code example for how APICloud calls the VOD SDK's API to pass the Token and play a video:
// 设置 播放外部播放 token
this.polyvVideo.setCustomVideoToken({token:""}, function (ret, err) {
});
// 通过 vid 播放在线视频
this.polyvVideo.setVid({
vid: ""
});
4.6 uniapp Platform
Code example for how uniapp calls the VOD SDK's API to pass the Token and play a video:
// 设置 播放外部播放 token
this.$refs.vod.setCustomVideoToken({token: ""},(ret) => {
})
// 通过 vid 播放在线视频
this.$refs.vod.setVid({
vid: "",
level: 0
},(ret) => {
})
