springboot java 腾讯云vod上传视频 云点播

腾讯云点播(Video on Demand,VOD)基于腾讯多年技术积累与基础设施建设,为有音视频应用相关需求的客户提供包括音视频存储管理、音视频转码处理、音视频加速播放和音视频通信服务的一站式解决方案。

springboot java 腾讯云vod上传视频 云点播_第1张图片

腾讯云vod 开发文档
pom.xml

<!-- tencentcloud -->
<dependency>
    <groupId>com.tencentcloudapi</groupId>
    <artifactId>tencentcloud-sdk-java</artifactId>
    <version>3.1.2</version>
</dependency>

获取视频上传签名

@PostMapping("/getSignature")
@ApiOperation("获取视频上传签名")
public Result getVodSignature() {
    VodSignatureUtil sign = videoUtil.getVodSignature();
    String signature = null;
    try {
        signature = sign.getUploadSignature();
    } catch (Exception e) {
        e.printStackTrace();
        return Result.error(ResultEnum.SERVICE_UNAVAILABLE, "获取签名失败");
    }
    return Result.success(signature);
}

超级播放器获取视频播放签名

@GetMapping("/playSignature")
@ApiOperation("超级播放器获取视频播放签名")
public Result playSignature(@RequestParam("fileId") String fileId){
    return Result.success(videoUtil.videoToken(fileId));
}

腾讯云回调填值

@PostMapping("/callback")
@ApiOperation(value = "vod回调", hidden = true)
public void callback(@RequestBody String jsonObject){
    log.info("video callback log:" + jsonObject);
    JsonNode readTree = null;
    try {
        readTree = jsonMapper.readTree(jsonObject);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    String eventType = readTree.get("EventType").asText();
    if ("ProcedureStateChanged".equals(eventType)){
        try{
            JsonNode changeEvent = readTree.get("ProcedureStateChangeEvent");
            TencentVideoCastVo castVos = null;
            try {
                castVos = jsonMapper.readValue(changeEvent.toString(), TencentVideoCastVo.class);
            } catch (JsonProcessingException e) {
                log.error("callback json处理异常:{}" ,e.getMessage());
                throw new BusinessException(ResultEnum.SERVICE_UNAVAILABLE);
            }
            if (!"SUCCESS".equals(castVos.getMessage())){
                throw new BusinessException(ResultEnum.SERVICE_UNAVAILABLE.getCode(),"腾讯云点播转码出现问题,请及时解决。");
            }
            // 转码成功后将数据保存在数据库中
            log.info("=========转码成功后将数据保存在数据库中===================");
            //---
            // 将视频发布到微信小程序
            VodClient client = videoUtil.getVodClient();
            WeChatMiniProgramPublishRequest req = new WeChatMiniProgramPublishRequest();
            req.setFileId(castVos.getFileId());
            req.setSubAppId(tencentYunProperties.getVod().getAppId());
            // 选择转码后的视频发布到微信小程序
            req.setSourceDefinition(tencentYunProperties.getVod().getSourceDefinition());
            WeChatMiniProgramPublishResponse resp = client.WeChatMiniProgramPublish(req);
            log.info("log,视频发布微信小程序:{}",WeChatMiniProgramPublishResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {
            log.error(e.toString());
        }
    }
    // 视频发布到小程序 回调
    if ("WechatMiniProgramPublishComplete".equals(eventType)){
        JsonNode miniProgramPublishEvent = readTree.get("WechatMiniProgramPublishEvent");
        String fileId = miniProgramPublishEvent.get("FileId").asText();
        if ("SUCCESS".equals(miniProgramPublishEvent.get("Message").asText())){
            log.info("视频Id为:{} -->已发布到小程序",fileId);
        }
    }
}

工具类

package com.also.common.util;

import com.also.common.exception.BusinessException;
import com.also.common.properties.TencentYunProperties;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.cvm.v20170312.CvmClient;
import com.tencentcloudapi.cvm.v20170312.models.DescribeRegionsRequest;
import com.tencentcloudapi.cvm.v20170312.models.DescribeRegionsResponse;
import com.tencentcloudapi.vod.v20180717.VodClient;
import com.tencentcloudapi.vod.v20180717.models.DeleteMediaRequest;
import com.tencentcloudapi.vod.v20180717.models.DeleteMediaResponse;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.crypto.spec.SecretKeySpec;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author Joe
 */
@Component
@Slf4j
public class VideoUtil {

    @Resource
    private TencentYunProperties tencentYunProperties;

    private static Map<String, Object> JWT_HEADER = new HashMap<>();
    static {
        JWT_HEADER.put("typ", "JWT");
        JWT_HEADER.put("alg", "HS256");
    }

    /**
     * 获取视频上传签名
     * @return
     */
    public VodSignatureUtil getVodSignature(){
        VodSignatureUtil sign = new VodSignatureUtil();
        // 设置 App 的云 API 密钥
        sign.setSecretId(tencentYunProperties.getSecretId());
        sign.setSecretKey(tencentYunProperties.getSecretKey());
        sign.setVodSubAppId(tencentYunProperties.getVod().getAppId());
        sign.setCurrentTime(System.currentTimeMillis() / 1000);
        sign.setRandom(new Random().nextInt(Integer.MAX_VALUE));
        sign.setProcedure(tencentYunProperties.getVod().getProcedure());
        // 签名有效期:2天
        sign.setSignValidDuration(3600 * 24 * 2);
        return sign;
    }

    /**
     * vod视频播放token
     * @param fileId
     * @return
     */
    public String videoToken(String fileId) {
        LocalDateTime now = LocalDateTime.now();
        long expireTimeStamp = now.plusHours(24L).toEpochSecond(ZoneOffset.of("+8"));
        Map<String, Object> claims = new HashMap<>();
        claims.put("appId", tencentYunProperties.getVod().getAppId());
        claims.put("fileId", fileId);
        claims.put("currentTimeStamp", now.toEpochSecond(ZoneOffset.of("+8")));
        claims.put("expireTimeStamp", expireTimeStamp);
        claims.put("pcfg", "basicDrmPreset");

        Map<String, Object> urlAccessInfo = new HashMap<>();
        urlAccessInfo.put("t", Long.toHexString(expireTimeStamp));
        claims.put("urlAccessInfo", urlAccessInfo);

        // 加密生成jwt token
        return Jwts.builder()
                .setHeader(JWT_HEADER)
                .setClaims(claims)
                .setExpiration(new Date(expireTimeStamp * 1000))
                .signWith(SignatureAlgorithm.HS256, new SecretKeySpec(tencentYunProperties.getVod().getKey().getBytes(), 0, tencentYunProperties.getVod().getKey().getBytes().length, "HS256"))
                .compact();
    }

    public void uploadVideo(){
        try{
            Credential cred = new Credential(tencentYunProperties.getSecretId(), tencentYunProperties.getSecretKey());

            // 实例化一个http选项,可选的,没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("cvm.tencentcloudapi.com");
            // 实例化一个client选项,可选的,没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            // 实例化要请求产品的client对象,clientProfile是可选的
            CvmClient client = new CvmClient(cred, "", clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DescribeRegionsRequest req = new DescribeRegionsRequest();

            // 返回的resp是一个DescribeRegionsResponse的实例,与请求对象对应
            DescribeRegionsResponse resp = client.DescribeRegions(req);
            // 输出json格式的字符串回包
            log.info(DescribeRegionsResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {
            log.error(e.toString());
            throw new BusinessException(e.getMessage());
        }
    }

    public void removeTencentCloudVideo(String fileId) {
        try {
            VodClient client = getVodClient();
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DeleteMediaRequest req = new DeleteMediaRequest();
            req.setFileId(fileId);
            // 返回的resp是一个DeleteMediaResponse的实例,与请求对象对应
            DeleteMediaResponse resp = client.DeleteMedia(req);
            // 输出json格式的字符串回包
            log.info(DeleteMediaResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {
            log.error(e.toString());
            throw new BusinessException(e.getMessage());
        }
    }

    public VodClient getVodClient() {
        // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
        // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
        // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
        Credential cred = new Credential(tencentYunProperties.getSecretId(), tencentYunProperties.getSecretKey());
        // 实例化一个http选项,可选的,没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("vod.tencentcloudapi.com");
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        return new VodClient(cred, "", clientProfile);
    }


}

腾讯云vod签名

package com.also.common.util;


import sun.misc.BASE64Encoder;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

/**
 * @author Joe
 * @date 2023/08/03 10:42
 * 腾讯云vod签名
 * @see <a href="https://cloud.tencent.com/document/product/266/10638">官方示例 腾讯云vod上传视频签名生成</a>
 */
public class VodSignatureUtil {
    private String secretId;
    private String secretKey;
    private long currentTime;
    private int random;
    private int signValidDuration;
    private String procedure;
    private long vodSubAppId;

    /**
     * 签名算法
     */
    private static final String HMAC_ALGORITHM = "HmacSHA1";
    private static final String CONTENT_CHARSET = "UTF-8";

    public static byte[] byteMerger(byte[] byte1, byte[] byte2) {
        byte[] byte3 = new byte[byte1.length + byte2.length];
        System.arraycopy(byte1, 0, byte3, 0, byte1.length);
        System.arraycopy(byte2, 0, byte3, byte1.length, byte2.length);
        return byte3;
    }

    /**
     * 获取签名
     * @return strSign
     * @throws Exception
     */
    public String getUploadSignature() throws Exception {
        String strSign = "";
        String contextStr = "";

        // 生成原始参数字符串
        long endTime = (currentTime + signValidDuration);
        contextStr += "secretId=" + java.net.URLEncoder.encode(secretId, "utf8");
        contextStr += "¤tTimeStamp=" + currentTime;
        contextStr += "&expireTime=" + endTime;
        contextStr += "&random=" + random;
        contextStr += "&procedure=" + procedure;
        contextStr += "&vodSubAppId=" + vodSubAppId;
        try {
            Mac mac = Mac.getInstance(HMAC_ALGORITHM);
            SecretKeySpec secretKey = new SecretKeySpec(this.secretKey.getBytes(CONTENT_CHARSET), mac.getAlgorithm());
            mac.init(secretKey);

            byte[] hash = mac.doFinal(contextStr.getBytes(CONTENT_CHARSET));
            byte[] sigBuf = byteMerger(hash, contextStr.getBytes(StandardCharsets.UTF_8));
            strSign = base64Encode(sigBuf);
            strSign = strSign.replace(" ", "").replace("\n", "").replace("\r", "");
        } catch (Exception e) {
            throw e;
        }
        return strSign;
    }

    private String base64Encode(byte[] buffer) {
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(buffer);
    }

    public void setSecretId(String secretId) {
        this.secretId = secretId;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public void setCurrentTime(long currentTime) {
        this.currentTime = currentTime;
    }

    public void setRandom(int random) {
        this.random = random;
    }

    public String getProcedure() {
        return procedure;
    }

    public void setProcedure(String procedure) {
        this.procedure = procedure;
    }

    public void setSignValidDuration(int signValidDuration) {
        this.signValidDuration = signValidDuration;
    }

    public long getVodSubAppId() {
        return vodSubAppId;
    }

    public void setVodSubAppId(long vodSubAppId) {
        this.vodSubAppId = vodSubAppId;
    }
}

你可能感兴趣的:(java,spring,boot,腾讯云)