Java SDK 使用教程

视频翻译 Java SDK 完整使用教程:按业务流程讲解项目创建、视频上传、翻译轮询、字幕处理、成品下载与日常管理,附方法速查表与常见问题

开始前请确认已完成 SDK 安装并创建了客户端,见 Java SDK 下载。

为简洁,本文示例统一省略 isSuccess() 结果判断模板,实际使用时请按 通用调用模式 补全。

完整业务流程总览

创建项目
   ↓
取上传凭证 ──→ COS 直传视频文件 ──→ 上传完成回调
   ↓
视频入库
   ↓
设置字幕区域(翻译前的最后一步,指定原字幕位置,
   供擦除阶段精准识别与擦除原字幕)
   ↓
开始翻译(计费)
   ↓
轮询翻译进度(擦除 → 校准 → 翻译 → 压制 四阶段)
   ↓
校对/编辑字幕(可选)
   ↓
下载成片 / 获取字幕

创建项目

翻译任务以"项目"为单位,创建时指定源语言与目标语言(语言创建后不可修改)。

import com.jiyou.base.sdk.request.ProjectAddRequest;
import com.jiyou.base.sdk.response.ProjectAddResponse;

// name: 项目名称;sourceLanguage: 源语言;targetLanguage: 目标语言(多个用逗号分隔);
// fontSize: 字号,0 表示自动计算,可传 null
ProjectAddRequest request = new ProjectAddRequest("我的短剧", "Simplified Chinese", "English", 0);
ProjectAddResponse response = client.execute(request, ProjectAddResponse.class);

支持的语言代码(注意:使用英文全称):

语言代码
简体中文Simplified Chinese
繁体中文Traditional Chinese
英语English
日语Japanese
韩语Korean
越南语Vietnamese
泰语Thai
西班牙语Spanish
葡萄牙语Portuguese
俄语Russian

上传视频

视频文件由调用方直接上传至腾讯云 COS 对象存储,SDK 负责凭证申请与上传完成后的回调确认,支持两种模式:

模式上传执行方调用方后端是否需要 cos_api适用场景
模式一:后端上传调用方 Java 后端需要后端读取本地/服务器文件上传
模式二:前端直传(推荐)调用方前端不需要Web 应用,后端只做凭证中转

两种模式的第一步(取凭证)和第三步(完成回调)完全相同,仅第二步(文件上传)的执行方不同。

第一步:获取 COS 直传临时凭证(两种模式相同)

import com.jiyou.base.sdk.model.CosUploadCredentialsModel;
import com.jiyou.base.sdk.request.VideoUploadCredentialsRequest;
import com.jiyou.base.sdk.response.VideoUploadCredentialsResponse;

VideoUploadCredentialsRequest request = new VideoUploadCredentialsRequest("projectId");
VideoUploadCredentialsResponse response = client.execute(request, VideoUploadCredentialsResponse.class);

CosUploadCredentialsModel sts = response.getData();

凭证字段说明:

字段说明
fileId后端预生成的文件 id,回调时需回传
bucket / region / key上传的 COS 目标位置(不可修改)
tmpSecretId / tmpSecretKey / sessionToken临时密钥(有效期约 2 小时,仅可上传到指定位置)
startTime / expiredTime密钥生效/失效时间戳(秒)
maxSizeBytes当前等级允许的单文件大小上限(字节),上传前请校验文件大小

第二步(模式一):后端使用 COS Java SDK 分片上传

import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicSessionCredentials;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;

// 使用临时密钥三元组(sessionToken 必传)
BasicSessionCredentials cred = new BasicSessionCredentials(
        sts.getTmpSecretId(), sts.getTmpSecretKey(), sts.getSessionToken());
ClientConfig config = new ClientConfig(new Region(sts.getRegion()));
TransferManager tm = new TransferManager(new com.qcloud.cos.COSClient(cred, config));

// 上传到凭证指定的 bucket + key(不可修改目标位置)
File localFile = new File("/path/to/video.mp4");
Upload upload = tm.upload(sts.getBucket(), sts.getKey(), localFile);
upload.waitForUploadResult();  // 大文件自动分片并发上传
tm.shutdownNow();

第二步(模式二):下发凭证给前端直传(后端无需 cos_api)

后端将第一步获取的凭证经自己的接口下发给前端,由前端直传 COS。

后端接口(示意)——取凭证并下发:

// 调用方后端自己的 Controller 方法,内部使用 SDK 取凭证后返回给前端
public CosUploadCredentialsModel getUploadCredentials(String projectId) {
    VideoUploadCredentialsRequest request = new VideoUploadCredentialsRequest(projectId);
    VideoUploadCredentialsResponse response = client.execute(request, VideoUploadCredentialsResponse.class);
    return response.getData();  // 前端拿到 fileId/密钥三元组/bucket/region/key/maxSizeBytes
}

前端直传(JavaScript,需引入 cos-js-sdk-v5):

import COS from 'cos-js-sdk-v5'

const sts = await api.getUploadCredentials(projectId)  // 调用方自己的后端接口

// 上传前校验文件大小
if (file.size > sts.maxSizeBytes) {
  throw new Error(`文件大小超过等级限制(最大 ${Math.round(sts.maxSizeBytes / 1024 / 1024)}MB)`)
}

// 上传前计算文件 sha256(回调时需要,Web Crypto API)
const sha256 = await calcFileSha256(file)

// 使用临时密钥三元组直传(密钥有效期内无需续签)
const cos = new COS({
  getAuthorization(options, callback) {
    callback({
      TmpSecretId: sts.tmpSecretId,
      TmpSecretKey: sts.tmpSecretKey,
      SecurityToken: sts.sessionToken,
      StartTime: sts.startTime,
      ExpiredTime: sts.expiredTime,
    })
  },
})

// 分片上传到凭证指定的 bucket + key(不可修改目标位置)
await new Promise((resolve, reject) => {
  cos.sliceUploadFile({
    Bucket: sts.bucket,
    Region: sts.region,
    Key: sts.key,
    Body: file,
    SliceSize: 1024 * 1024,
    onProgress: (p) => console.log(`进度:${Math.round((p.percent || 0) * 100)}%`),
  }, err => (err ? reject(err) : resolve()))
})

// 上传完成,将 fileId/sha256/fileName 回传给调用方后端,由后端执行第三步回调
await api.notifyUploadComplete({ fileId: sts.fileId, sha256, fileName: file.name })

安全注意:

  • appId/appSecret 仅保存在调用方后端用于请求签名,绝不能下发到前端
  • 上传凭证是临时密钥(有效期约 2 小时,仅可上传到指定位置),仍建议通过鉴权后的接口下发

第三步:上传完成回调(两种模式相同)

文件上传完成后回调,平台会校验文件并完成入库登记。

import com.jiyou.base.sdk.model.VideoUploadResultModel;
import com.jiyou.base.sdk.request.VideoUploadCompleteRequest;
import com.jiyou.base.sdk.response.VideoUploadCompleteResponse;

// fileId: 第一步凭证中的 fileId;sha256: 文件 sha256(模式二由前端计算回传,必填);
// fileName: 文件名(请勿包含逗号)
VideoUploadCompleteRequest request =
        new VideoUploadCompleteRequest(sts.getFileId(), "projectId", sha256, "video.mp4");
VideoUploadCompleteResponse response = client.execute(request, VideoUploadCompleteResponse.class);

VideoUploadResultModel result = response.getData();
String sourceFileId = result.getFileId();      // 源视频文件id(入库时使用)
String previewFileId = result.getPreviewFileId(); // 360P预览视频文件id

每个视频文件(含预览视频,如有)都要独立走一遍这三步。

视频入库

文件上传完成后,将文件 id 批量登记到项目下。

import java.util.Arrays;
import com.jiyou.base.sdk.request.VideoAddRequest;
import com.jiyou.base.sdk.response.VideoAddResponse;

// fileIds: 源视频文件id列表(必填);后三个列表可传 null,
// 但如果传了则数量必须与 fileIds 一致
VideoAddRequest request = new VideoAddRequest("projectId",
        Arrays.asList("fileId1", "fileId2"),   // fileIds
        null,                                    // previewFileIds:360P预览视频
        Arrays.asList("sha256_1", "sha256_2"),   // fileSha256s
        Arrays.asList("第01集.mp4", "第02集.mp4")); // fileNames
VideoAddResponse response = client.execute(request, VideoAddResponse.class);

注意:

  • 各列表参数数量必须一致,文件名请勿包含逗号(列表按逗号拼接传输,含逗号会错位)
  • 入库后系统按"源语言 + 目标语言"自动拆分为多条视频记录(每目标语言一条)

设置字幕区域(翻译前的最后一步)

指定原字幕在画面中的位置,供擦除(erase)阶段精准识别与擦除原字幕。应在开始翻译之前设置;不设置则擦除效果无法保证。

import java.util.Arrays;
import com.jiyou.base.sdk.request.VideoSubtitleRegionSaveRequest;
import com.jiyou.base.sdk.response.VideoSubtitleRegionSaveResponse;

// ids: 视频id列表;regions: 字幕区域JSON串(0-1 相对坐标,可多个区域)
VideoSubtitleRegionSaveRequest request = new VideoSubtitleRegionSaveRequest(
        Arrays.asList("videoId1", "videoId2"),
        "[{\"x\":0.1,\"y\":0.80,\"width\":0.8,\"height\":0.12}]");
VideoSubtitleRegionSaveResponse response = client.execute(request, VideoSubtitleRegionSaveResponse.class);

regions 坐标说明(相对视频画面,取值 0-1):

字段含义
x / y区域左上角坐标(占画面宽/高的比例)
width / height区域宽/高(占画面宽/高的比例)

示例 [{"x":0.1,"y":0.80,"width":0.8,"height":0.12}] 表示画面底部 10%~90% 宽、80%~92% 高的矩形区域(典型底部字幕位置)。

开始翻译

import com.jiyou.base.sdk.request.VideoTranslateRequest;
import com.jiyou.base.sdk.response.VideoTranslateResponse;

// projectId: 项目id;ids: 视频id列表,传 null 表示翻译项目下全部未翻译视频
VideoTranslateRequest request = new VideoTranslateRequest("projectId", null);
VideoTranslateResponse response = client.execute(request, VideoTranslateResponse.class);

计费规则(重要):

  • 开始翻译时,未付费视频会自动扣费(余额不足则整个请求失败)
  • 单价按视频时长(分钟)计算,接口抛出的错误信息会包含失败原因

轮询翻译进度

翻译分四个阶段依次执行:擦除(erase)→ 校准(review)→ 翻译(translate)→ 压制(embed)。通过视频列表接口轮询各阶段状态。

import com.jiyou.base.sdk.model.PageModel;
import com.jiyou.base.sdk.model.ProjectVideoModel;
import com.jiyou.base.sdk.request.VideoListRequest;
import com.jiyou.base.sdk.response.VideoListResponse;

// dataEqual 为精确过滤条件 JSON 串:按项目查询
VideoListRequest request = new VideoListRequest(1, 100, "{\"projectId\":\"xxx\"}", null, null, null);
VideoListResponse response = client.execute(request, VideoListResponse.class);

PageModel<ProjectVideoModel> page = response.getData();
for (ProjectVideoModel video : page.getRecords()) {
    String eraseStatus = video.getEraseStatus();         // 擦除状态
    String reviewStatus = video.getReviewStatus();       // 校准状态
    String translateStatus = video.getTranslateStatus(); // 翻译状态
    String embedStatus = video.getEmbedStatus();         // 压制状态
}

状态字段取值:

取值含义
init未开始
queue队列中
ing处理中
success成功
fail失败

四个状态均为 success 时翻译全部完成;任一为 fail 时可调用重试接口(见 失败处理)。

字幕处理

校准(review)阶段完成后可获取源字幕并人工校对;翻译(translate)完成后可获取译文字幕。

获取源字幕(返回 SRT 格式文本):

import com.jiyou.base.sdk.request.VideoGetSrtRequest;
import com.jiyou.base.sdk.response.VideoGetSrtResponse;

VideoGetSrtRequest request = new VideoGetSrtRequest("videoId");
VideoGetSrtResponse response = client.execute(request, VideoGetSrtResponse.class);
String srtText = response.getData();

获取翻译后字幕:

import com.jiyou.base.sdk.request.VideoGetTranslateSrtRequest;
import com.jiyou.base.sdk.response.VideoGetTranslateSrtResponse;

VideoGetTranslateSrtRequest request = new VideoGetTranslateSrtRequest("videoId");
VideoGetTranslateSrtResponse response = client.execute(request, VideoGetTranslateSrtResponse.class);
String srtText = response.getData();

更新源字幕(SRT 全文覆盖):

import com.jiyou.base.sdk.request.VideoUpdateSourceSrtRequest;
import com.jiyou.base.sdk.response.VideoUpdateSourceSrtResponse;

VideoUpdateSourceSrtRequest request = new VideoUpdateSourceSrtRequest("videoId", srtText);
VideoUpdateSourceSrtResponse response = client.execute(request, VideoUpdateSourceSrtResponse.class);

更新翻译后字幕(SRT 全文覆盖):

import com.jiyou.base.sdk.request.VideoUpdateTranslateSrtRequest;
import com.jiyou.base.sdk.response.VideoUpdateTranslateSrtResponse;

VideoUpdateTranslateSrtRequest request = new VideoUpdateTranslateSrtRequest("videoId", srtText);
VideoUpdateTranslateSrtResponse response = client.execute(request, VideoUpdateTranslateSrtResponse.class);

编辑字幕后如需重新压制,可调用重试接口并指定 fromStage = "embed"(见 失败处理)。

失败处理

重试(从指定阶段开始,该阶段及之后的阶段重新执行):

import java.util.Arrays;
import com.jiyou.base.sdk.request.VideoRetryRequest;
import com.jiyou.base.sdk.response.VideoRetryResponse;

// fromStage: erase/review/translate/embed,传 null 默认 erase
VideoRetryRequest request = new VideoRetryRequest("projectId",
        Arrays.asList("videoId1"), "translate");
VideoRetryResponse response = client.execute(request, VideoRetryResponse.class);

fromStage 取值说明:

取值从哪个阶段重试
erase全流程重试(清空全部产物)
review从校准开始(保留擦除产物)
translate从翻译开始(保留擦除+校准产物)
embed从压制开始(保留前三阶段产物)

重试扣费规则:未付费视频首次重试会扣费;超过免费重试次数的全成功视频重新扣费。

批量重试注意:多个视频按总价一次扣费,余额不足时整体失败、不会部分扣费。如需部分成功,请循环单视频调用。

取消翻译(仅取消队列中尚未开始的):

import com.jiyou.base.sdk.request.VideoCancelTranslateRequest;
import com.jiyou.base.sdk.response.VideoCancelTranslateResponse;

VideoCancelTranslateRequest request = new VideoCancelTranslateRequest("projectId", null);
VideoCancelTranslateResponse response = client.execute(request, VideoCancelTranslateResponse.class);

下载

单文件下载(源视频或成片均可,返回签名下载地址):

import com.jiyou.base.sdk.request.FileSignRequest;
import com.jiyou.base.sdk.response.FileSignResponse;

// fileId: 源视频传 sourceFileId,成片传 embedFileId
FileSignRequest request = new FileSignRequest("embedFileId");
FileSignResponse response = client.execute(request, FileSignResponse.class);
String downloadUrl = response.getData().getUrl();

整剧打包下载(要求项目下视频全部翻译成功):

import com.jiyou.base.sdk.request.ProjectDownloadEoRequest;
import com.jiyou.base.sdk.response.ProjectDownloadEoResponse;

ProjectDownloadEoRequest request = new ProjectDownloadEoRequest("projectId");
ProjectDownloadEoResponse response = client.execute(request, ProjectDownloadEoResponse.class);

// state=packaging 打包中,需间隔轮询;state=success 后用 url 下载
String state = response.getData().getState();
String url = response.getData().getUrl();

日常管理

项目列表(分页查询):

import com.jiyou.base.sdk.request.ProjectListRequest;
import com.jiyou.base.sdk.response.ProjectListResponse;

// page 从 1 开始;dataEqual/dataLike/dataRange 为过滤条件 JSON 串(如 {"name":"xx"})
ProjectListRequest request = new ProjectListRequest(1, 10, null, null, null, null, null);
ProjectListResponse response = client.execute(request, ProjectListResponse.class);
response.getData().getRecords(); // List<ProjectModel>
response.getData().getTotal();   // 总数

编辑项目(名称与字号,语言不可改):

import com.jiyou.base.sdk.request.ProjectEditRequest;
import com.jiyou.base.sdk.response.ProjectEditResponse;

ProjectEditRequest request = new ProjectEditRequest("projectId", "新名称", 0);
ProjectEditResponse response = client.execute(request, ProjectEditResponse.class);

删除项目(级联删除项目下所有视频):

import java.util.Arrays;
import com.jiyou.base.sdk.request.ProjectDelRequest;
import com.jiyou.base.sdk.response.ProjectDelResponse;

ProjectDelRequest request = new ProjectDelRequest(Arrays.asList("projectId1"));
ProjectDelResponse response = client.execute(request, ProjectDelResponse.class);

重命名视频:

import com.jiyou.base.sdk.request.VideoEditRequest;
import com.jiyou.base.sdk.response.VideoEditResponse;

VideoEditRequest request = new VideoEditRequest("videoId", "新文件名.mp4");
VideoEditResponse response = client.execute(request, VideoEditResponse.class);

删除视频:

import java.util.Arrays;
import com.jiyou.base.sdk.request.VideoDelRequest;
import com.jiyou.base.sdk.response.VideoDelResponse;

VideoDelRequest request = new VideoDelRequest(Arrays.asList("videoId1"));
VideoDelResponse response = client.execute(request, VideoDelResponse.class);

方法速查表

#方法接口构造参数data 类型
1ProjectAddRequest/project/add.html(name, sourceLanguage, targetLanguage, fontSize)Void
2ProjectListRequest/project/data.html(page, limit, dataEqual, dataLike, dataRange, sort, order)PageModel<ProjectModel>
3ProjectEditRequest/project/edit.html(id, name, fontSize)Void
4ProjectDelRequest/project/del.html(ids)Void
5VideoUploadCredentialsRequest/project/video/uploadCredentials.html(projectId)CosUploadCredentialsModel
6VideoUploadCompleteRequest/project/video/uploadComplete.html(fileId, projectId, sha256, fileName)VideoUploadResultModel
7VideoAddRequest/project/video/add.html(projectId, fileIds, previewFileIds, fileSha256s, fileNames)Void
8VideoListRequest/project/video/data.html(page, limit, dataEqual, dataLike, sort, order)PageModel<ProjectVideoModel>
9VideoEditRequest/project/video/edit.html(id, sourceFileName)Void
10VideoDelRequest/project/video/del.html(ids)Void
11VideoTranslateRequest/project/video/translate.html(projectId, ids)Void
12VideoCancelTranslateRequest/project/video/cancelTranslate.html(projectId, ids)Void
13VideoRetryRequest/project/video/retry.html(projectId, ids, fromStage)Void
14VideoGetSrtRequest/project/video/getSrt.html(id)String
15VideoGetTranslateSrtRequest/project/video/getTranslateSrt.html(id)String
16VideoUpdateSourceSrtRequest/project/video/updateSourceSrt.html(id, sourceText)Void
17VideoUpdateTranslateSrtRequest/project/video/updateTranslateSrt.html(id, translateText)Void
18VideoSubtitleRegionSaveRequest/project/video/subtitleRegion/save.html(ids, regions)Void
19ProjectDownloadEoRequest/project/downloadEo.html(projectId)DownloadEoModel
20FileSignRequest/file/signFile.html(fileId)FileSignModel

每个方法均与同名 Response 配对使用:client.execute(request, XxxResponse.class)。各参数是否可空详见 SDK 源码包中对应 Request 类的 Javadoc(Maven 中央仓库同时发布了 sources 包)。

主要数据模型:

模型关键字段
ProjectModelid、name、sourceLanguage、targetLanguage、subtitleRegions、videoTotalCount
ProjectVideoModelid、sourceFileName、targetLanguage、duration、eraseStatus/reviewStatus/translateStatus/embedStatus(四阶段状态)、price(分)、isPaid、retryCount、embedFileId(成片文件id)、subtitleRegions
PageModel<T>records、total、size、current、pages
DownloadEoModelstate(packaging/success)、url
FileSignModelurl

常见问题

1. 参数校验在哪里?

SDK 不做客户端校验。必填参数缺失时后端返回明确的错误信息(response.isSuccess() 为 false,错误信息见 response.getMsg())。

2. 列表参数(ids/fileIds/fileNames 等)如何传输?

Java List 在 SDK 内按逗号拼接为字符串传输。因此文件名等参数值不能包含逗号,否则后端解析数量错位。

3. 过滤条件(dataEqual 等)怎么写?

传 JSON 字符串原样,如 "{\"projectId\":\"xxx\"}"(按项目过滤视频)、"{\"name\":\"关键词\"}"(配合 dataLike 模糊查询)。

4. 分页数据怎么取?

列表接口的 data 是 PageModel(分页结构),取数据用 response.getData().getRecords(),不是 List 本身。

5. 上传必须在两个小时内完成吗?

COS 临时凭证有效期约 2 小时。超时未完成上传,重新调用 VideoUploadCredentialsRequest 获取新凭证即可(凭证与 fileId 绑定,重复获取新凭证不影响)。前端直传模式下凭证在前端使用,超时重取凭证的逻辑应放在前端。

6. 翻译费用如何计算?

按视频时长(分钟)计费,开始翻译与重试时自动扣费。视频列表返回的 price 字段为单条视频费用(单位:分)。

7. 各接口的 HTTP 参数定义在哪里?

本文方法速查表中"接口"列对应各 HTTP API 文档(项目管理、视频上传、视频翻译任务、字幕处理、成品下载),参数语义与 Request 构造参数一一对应。