保利威文档中心

幫助中心

播放加密影片

更新時間:2026-05-22 22:24:15

保利威影片加密採用私有的加密演算法,提供包含加密轉碼、安全傳輸、解密播放等一體化的影片安全方案。透過對影片資料本身進行高強度的加密,影片檔案即使被下載到本地也無法直接播放和傳播,可有效防止影片外洩和盜版問題,詳見:影片加密

為了方便開發者快速整合,我們將解密播放相關邏輯都封裝到了播放器內部,與播放一般影片相比,在播放器端,開發者只需多傳入播放憑證參數即可實現加密影片的播放。

開發指引

加密影片需使用播放憑證方式進行播放。播放器支援以下播放憑證參數,請根據接入方式傳遞對應參數。新接入建議使用 playsafe 或 playsafeUrl。

名稱 類型 說明
playsafe String/Function 播放加密影片推薦使用的授權憑證,適用於 PC Web 和行動端 H5。業務方伺服端透過建立 Playsafe Token介面取得並回傳給播放器。支援直接傳入 token,也支援透過 Function 方式動態取得 token。
playsafeUrl String 取得播放加密影片憑證的介面 URL,適用於 PC Web 和行動端 H5(**與 playsafe 參數二選一**)。新接入建議優先使用 playsafeUrl 或 playsafe Function,由業務方伺服端即時回傳 token。
ts Number 行動端 H5 播放加密影片的相容參數,表示 13 位毫秒級時間戳記。該參數仍然有效,但不再作為推薦接入方式。
sign String 行動端 H5 播放加密影片的相容簽名,產生規則為點播帳號的 secretkey、vid、ts 的值依序拼接後進行 md5 計算,由業務方伺服端產生並回傳給播放器。該參數仍然有效,但不再作為推薦接入方式。
註:sign 簽名不需要轉大寫。
簽名範例:
若 secretkey 為 abc,vid 為 123,ts 為 1672829071000,此時 sign 為 md5("abc1231672829071000")

註:新接入建議 PC Web 和行動端 H5 統一使用 playsafe 或 playsafeUrl 取得播放 token。ts、sign 仍可用,主要用於歷史相容,不再推薦使用。

播放器程式碼範例:

<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>

Web 頁面播放加密影片前,需要先存取業務方自己的伺服端授權驗證介面(可以在這裡加上自有業務的授權驗證邏輯,例如是否登入、是否購買課程等,建議使用 HTTPS)。如果業務上允許播放,則透過建立 Playsafe Token介面取得播放憑證,並回傳給 Web 端播放器。新接入建議 PC Web 和行動端 H5 都統一使用 Playsafe Token。舊版行動端 H5 的 ts、sign 方式仍然有效,但主要用於歷史相容,不再作為推薦接入方式。

伺服端產生播放憑證程式碼範例:

PHP 程式碼:

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

// 以下为生成播放凭证的代码示例
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 程式碼:

@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;
}

如果播放器使用 playsafeUrl 參數的方式,則需輸出 json 格式:

PHP 程式碼

// 已省略获取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 程式碼

@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 回傳結果範例:

請求成功:

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

請求失敗(簽名錯誤):

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

playsafeUrl 可能存在跨域問題,解決方案請參考:跨域存取設定

舊版行動端 H5 的 ts + sign 相容方式

舊版行動端 H5 播放 Web 加密影片時,也可以回傳 sign 和 ts 參數給播放器。該方式目前仍然有效,存量業務可以繼續使用;新接入建議使用 playsafe 或 playsafeUrl 取得播放 token。

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