Java:将视频上传到腾讯云并通过腾讯云点播播放

功能需求:

传入一个videoFile也就是视频字节流,返回腾讯云点播的视频保存url

需要在腾讯云中寻找的配置信息:

导入的依赖:

java 复制代码
<!--腾讯云点播-->
        <dependency>
            <groupId>com.tencentcloudapi</groupId>
            <artifactId>tencentcloud-sdk-java</artifactId>
            <version>4.0.11</version>
        </dependency>
        <!--腾讯云cos-->
        <dependency>
            <groupId>com.qcloud</groupId>
            <artifactId>cos_api</artifactId>
            <version>5.6.54</version>
        </dependency>

大体分为两步:

1.将视频上传到腾讯云

我们借助腾讯云依赖提供的cos客户端,将腾讯云的id,秘钥等配置信息传入,再将文件信息配置到cos客户端,发送请求,生成这个视频的访问路径

2.腾讯云点播保存腾讯云中我们刚刚上传的视频并返回一个播放改视频的url

同理,借助VOD客户端上传对应视频

全部源代码

java 复制代码
package net.mingsoft.cms.biz.impl;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.region.Region;
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.vod.v20180717.VodClient;
import com.tencentcloudapi.vod.v20180717.models.*;
import net.mingsoft.base.biz.impl.BaseBizImpl;
import net.mingsoft.base.dao.IBaseDao;
import net.mingsoft.cms.biz.IVideoBiz;
import net.mingsoft.cms.dao.IVideoDao;
import net.mingsoft.cms.entity.VideoEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

/**
 * 视频管理服务实现类(集成COS上传与云点播同步)
 * 提供视频上传到腾讯云COS并同步到云点播服务功能
 */
@Service("cmsVideoBizImpl")
public class VideoBizImpl extends BaseBizImpl<IVideoDao, VideoEntity> implements IVideoBiz {
    private static final Logger log = LoggerFactory.getLogger(VideoBizImpl.class);

    // 腾讯云配置信息 - 需要从配置文件或环境变量中获取
    private static final String SECRET_ID = "YOUR_TENCENT_CLOUD_SECRET_ID";
    private static final String SECRET_KEY = "YOUR_TENCENT_CLOUD_SECRET_KEY";
    private static final String BUCKET_NAME = "your-bucket-name";
    private static final String BUCKET_REGION = "ap-region-1";
    private static final String COS_DOMAIN = "your-bucket.cos.ap-region-1.myqcloud.com";

    // 云点播配置
    private static final String VOD_REGION = "ap-region-1";
    private static final Long VOD_SUB_APP_ID = 1000000L;

    /**
     * 上传视频文件到腾讯云并同步到云点播
     * @param videoFile 视频文件
     * @return 云点播播放URL
     * @throws IOException 文件读取异常
     */
    @Override
    public String uploadVideo(MultipartFile videoFile) throws IOException {
        // 1. 初始化COS客户端
        COSCredentials cosCred = new BasicCOSCredentials(SECRET_ID, SECRET_KEY);
        ClientConfig clientConfig = new ClientConfig(new Region(BUCKET_REGION));
        clientConfig.setHttpProtocol(HttpProtocol.https);
        
        try (COSClient cosClient = new COSClient(cosCred, clientConfig)) {
            // 2. 处理文件信息
            String originalFilename = videoFile.getOriginalFilename();
            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            // 添加目录前缀便于管理
            String newFileName = "videos/" + UUID.randomUUID() + fileExtension;
            
            // 3. 上传文件到COS
            try (InputStream inputStream = videoFile.getInputStream()) {
                ObjectMetadata metadata = new ObjectMetadata();
                metadata.setContentLength(videoFile.getSize());
                metadata.setContentType(videoFile.getContentType());
                
                PutObjectRequest putObjectRequest = new PutObjectRequest(
                        BUCKET_NAME,
                        newFileName,
                        inputStream,
                        metadata
                );
                cosClient.putObject(putObjectRequest);
            }
            
            log.info("视频已成功上传到COS,路径:{}", newFileName);
            
            // 4. 生成COS访问URL
            String cosUrl = "https://" + COS_DOMAIN + "/" + newFileName;
            
            // 5. 同步到云点播并获取播放链接
            String playUrl = syncToVod(cosUrl, originalFilename);
            log.info("视频已成功同步到云点播,播放URL: {}", playUrl);
            
            return playUrl;

        } catch (TencentCloudSDKException e) {
            log.error("云点播API调用失败", e);
            throw new RuntimeException("视频处理失败:" + e.getMessage());
        }
    }

    /**
     * 将COS视频同步到云点播并获取播放链接
     * @param cosUrl COS视频URL
     * @param originalFilename 原始文件名
     * @return 云点播播放URL
     */
    private String syncToVod(String cosUrl, String originalFilename) throws TencentCloudSDKException {
        // 1. 初始化VOD客户端
        Credential cred = new Credential(SECRET_ID, SECRET_KEY);
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("vod.tencentcloudapi.com");
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        
        try (VodClient vodClient = new VodClient(cred, VOD_REGION, clientProfile)) {
            // 2. 拉取上传到云点播
            PullUploadRequest pullRequest = new PullUploadRequest();
            pullRequest.setMediaUrl(cosUrl);
            pullRequest.setMediaName(originalFilename);
            pullRequest.setSubAppId(VOD_SUB_APP_ID);
            
            log.info("开始拉取上传视频到云点播,COS URL: {}", cosUrl);
            
            // 3. 执行拉取上传
            PullUploadResponse pullResponse = vodClient.PullUpload(pullRequest);
            String taskId = pullResponse.getTaskId();
            log.info("云点播拉取上传任务已创建,任务ID: {}", taskId);
            
            // 4. 等待任务完成并获取文件ID
            String fileId = waitForTaskCompletion(vodClient, taskId);

            if (fileId == null) {
                throw new RuntimeException("云点播任务处理超时或失败");
            }

            log.info("视频已成功同步到云点播,文件ID: {}", fileId);

            // 5. 获取播放URL
            return getPlayUrl(vodClient, fileId);
        }
    }

    /**
     * 等待云点播任务完成
     */
    private String waitForTaskCompletion(VodClient vodClient, String taskId) throws TencentCloudSDKException {
        int maxRetries = 30; // 最大重试次数
        int retryInterval = 2000; // 重试间隔2秒

        for (int i = 0; i < maxRetries; i++) {
            try {
                Thread.sleep(retryInterval);

                DescribeTaskDetailRequest taskRequest = new DescribeTaskDetailRequest();
                taskRequest.setTaskId(taskId);
                taskRequest.setSubAppId(VOD_SUB_APP_ID);

                DescribeTaskDetailResponse taskResponse = vodClient.DescribeTaskDetail(taskRequest);
                String status = taskResponse.getStatus();

                if ("FINISH".equals(status)) {
                    PullUploadTask pullUploadTask = taskResponse.getPullUploadTask();
                    if (pullUploadTask != null) {
                        return pullUploadTask.getFileId();
                    } else {
                        throw new RuntimeException("无法获取PullUploadTask信息");
                    }
                } else if ("FAIL".equals(status)) {
                    throw new RuntimeException("云点播任务处理失败");
                }

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("任务等待被中断", e);
            }
        }

        throw new RuntimeException("云点播任务处理超时");
    }

    /**
     * 获取视频播放URL
     */
    private String getPlayUrl(VodClient vodClient, String fileId) throws TencentCloudSDKException {
        DescribeMediaInfosRequest mediaRequest = new DescribeMediaInfosRequest();
        mediaRequest.setFileIds(new String[]{fileId});
        mediaRequest.setSubAppId(VOD_SUB_APP_ID);

        DescribeMediaInfosResponse mediaResponse = vodClient.DescribeMediaInfos(mediaRequest);

        if (mediaResponse.getMediaInfoSet() == null || mediaResponse.getMediaInfoSet().length == 0) {
            throw new RuntimeException("未找到视频信息,文件ID: " + fileId);
        }

        MediaInfo mediaInfo = mediaResponse.getMediaInfoSet()[0];
        return mediaInfo.getBasicInfo().getMediaUrl();
    }

    /**
     * 获取转码后的播放URL(可选)
     */
    private String getTranscodePlayUrl(VodClient vodClient, String fileId) throws TencentCloudSDKException {
        DescribeMediaInfosRequest mediaRequest = new DescribeMediaInfosRequest();
        mediaRequest.setFileIds(new String[]{fileId});
        mediaRequest.setSubAppId(VOD_SUB_APP_ID);

        DescribeMediaInfosResponse mediaResponse = vodClient.DescribeMediaInfos(mediaRequest);
        return mediaResponse.getMediaInfoSet()[0].getBasicInfo().getMediaUrl();
    }

    @Override
    protected IBaseDao<VideoEntity> getDao() {
        return null;
    }
}
相关推荐
猿究院--冯磊2 分钟前
JVM垃圾收集器
java·jvm·算法
天天摸鱼的java工程师7 分钟前
Go 语言未来会取代 Java 吗?
java·后端
掉鱼的猫21 分钟前
Solon AI & MCP v3.5.0 发布(智能体应用开发框架)
java·mcp
野犬寒鸦25 分钟前
力扣hot100:最大子数组和的两种高效方法:前缀和与Kadane算法(53)
java·后端·算法
AAA修煤气灶刘哥29 分钟前
《从 0 到 1 上手:RBAC+SpringSecurity 权限管理教程》
java·后端·安全
肉夹馍不加青椒1 小时前
第三十三天(信号量)
java·c语言·算法
现在,此刻1 小时前
面试题储备-MQ篇 2-说说你对RocketMQ的理解
java·rocketmq·java-rocketmq
诗句藏于尽头2 小时前
更改jar素材后打包
java·jar
SimonKing2 小时前
开源新锐:SQL玩转搜索引擎?Manticore颠覆你的认知
java·后端·程序员
中国lanwp2 小时前
Jenkins Pipeline中参数化构建
java·jenkins