# AI 漫剧转绘

> 把真人 / 实拍视频整体转绘为漫画风格成片。5 步链路：上传 → 查上传 → 提交转绘 → 轮询结果 → 取播放地址。兼容火山云 VOD 官方格式。

AI 漫剧转绘把真人 / 实拍视频整体转绘为**漫画风格**成片，保留原片运动与构图，适合短剧漫改、二创内容、动漫营销素材等场景。支持 `480p` / `720p` / `1080p` 输出与自定义转绘风格。

调用链路与火山官方 VOD 完全一致，共 5 步：

<Steps>
  <Step title="提交源视频（UploadMediaByUrl）">
    提交源视频公网链接，返回上传作业 `JobId`。
  </Step>
  <Step title="查询上传（QueryUploadTaskInfo）">
    用 `JobId` 查询，返回媒资 `Vid`。
  </Step>
  <Step title="提交转绘任务（AsyncVCreativeTask）">
    用 `vid://<Vid>` 提交转绘，返回任务 ID `VCreativeId`。
  </Step>
  <Step title="轮询任务结果（GetVCreativeTaskResult）">
    轮询直至 `Status` 为 `success`，从 `OutputJson` 拿到成片 `Vid`。
  </Step>
  <Step title="获取播放地址（GetPlayInfo）">
    用成片 `Vid` 换取播放地址，尽快下载（临时链接约 2 小时失效）。
  </Step>
</Steps>

鉴权与统一响应结构见 [VOD 接入说明](/video-processing/vod/overview)。以下 `Result` 均指成功响应中的 `Result` 对象。

---

## 步骤 1 · 提交源视频

```
POST /api/vod?Action=UploadMediaByUrl&Version=2020-08-01
```

### 请求体

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `SpaceName` | string | 否 | 空间名（兼容保留，可不传） |
| `URLSets` | array | 是 | 上传项数组，当前每次处理第一条 |
| `URLSets[].SourceUrl` | string | 是 | 源视频公网链接（`http(s)`，最长 1024 字符） |
| `URLSets[].FileExtension` | string | 否 | 文件扩展名（兼容保留） |
| `URLSets[].CallbackArgs` | string | 否 | 回调透传参数（兼容保留） |

```json
{
  "URLSets": [
    { "SourceUrl": "https://example.com/comic-source.mp4" }
  ]
}
```

### 响应 `Result`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `Data` | array | 上传作业数组 |
| `Data[].JobId` | string | 上传作业 ID（用于步骤 2） |
| `Data[].SourceUrl` | string | 回显源链接 |

```json
{
  "Result": {
    "Data": [
      { "JobId": "lrv1_xxxx.yyyy", "SourceUrl": "https://example.com/comic-source.mp4" }
    ]
  }
}
```

---

## 步骤 2 · 查询上传

```
GET /api/vod?Action=QueryUploadTaskInfo&Version=2020-08-01&JobIds={JobId}
```

### Query 参数

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `JobIds` | 是 | 步骤 1 返回的上传作业 ID（支持逗号分隔，当前每次处理第一个） |

### 响应 `Result`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `MediaInfoList` | array | 媒资信息列表 |
| `MediaInfoList[].JobId` | string | 回显作业 ID |
| `MediaInfoList[].SourceUrl` | string | 回显源链接 |
| `MediaInfoList[].State` | string | 上传状态，`Success` 表示可用 |
| `MediaInfoList[].Vid` | string | 媒资 `Vid`（用于步骤 3） |
| `NotExistJobIds` | array | 未识别的作业 ID |

```json
{
  "Result": {
    "MediaInfoList": [
      {
        "JobId": "lrv1_xxxx.yyyy",
        "SourceUrl": "https://example.com/comic-source.mp4",
        "State": "Success",
        "Vid": "lrv1_aaaa.bbbb"
      }
    ],
    "NotExistJobIds": []
  }
}
```

---

## 步骤 3 · 提交转绘任务

```
POST /api/vod?Action=AsyncVCreativeTask&Version=2018-01-01
```

<Note>
计费按**实际用量后付费**：任务成功后按实际输出时长与分辨率档位计费；任务失败**不收费**。
</Note>

### 请求体

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `Uploader` | string | 否 | 上传者标识（兼容保留） |
| `Scene` | string | 否 | 场景标识，漫剧转绘为 `videostyletrans`（兼容保留，可不传） |
| `CallbackArgs` | string | 否 | 回调透传参数（兼容保留） |
| `ParamObj` | object | 是 | 转绘参数 |
| `ParamObj.input` | string | 是 | 输入媒资，必须形如 `vid://<Vid>`（步骤 2 返回的 Vid） |
| `ParamObj.resolution` | string | 是 | 输出分辨率档位：`480p` / `720p` / `1080p` |
| `ParamObj.style` | string | 否 | 转绘风格描述（最长 100 字符；留空使用默认风格） |

```json
{
  "Scene": "videostyletrans",
  "ParamObj": {
    "input": "vid://lrv1_aaaa.bbbb",
    "resolution": "1080p",
    "style": "manga"
  }
}
```

### 响应 `Result`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `VCreativeId` | string | 转绘任务 ID（用于步骤 4） |
| `Code` | int | 固定 `0` |
| `BaseResp.StatusCode` | int | 固定 `0` |
| `BaseResp.StatusMessage` | string | 固定 `success` |

```json
{
  "Result": {
    "VCreativeId": "vg_7a6d4f30",
    "Code": 0,
    "BaseResp": { "StatusCode": 0, "StatusMessage": "success" }
  }
}
```

---

## 步骤 4 · 轮询任务结果

```
GET /api/vod?Action=GetVCreativeTaskResult&Version=2018-01-01&VCreativeId={VCreativeId}
```

建议每 10–30 秒轮询一次（转绘耗时随视频时长与分辨率变化，通常为分钟级）。

### Query 参数

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `VCreativeId` | 是 | 步骤 3 返回的任务 ID |

### 响应 `Result`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `Scene` | string | 固定 `videostyletrans` |
| `VCreativeId` | string | 回显任务 ID |
| `ParamObj` | string | **JSON 字符串**，回显提交参数 |
| `Status` | string | 任务状态：`start`（进行中）/ `success`（成功）/ `failed_run`（失败） |
| `OutputJson` | string | **JSON 字符串**。成功时为 `{"vid":"<成片 Vid>"}`；进行中 / 失败为空串 |

```json
{
  "Result": {
    "Scene": "videostyletrans",
    "VCreativeId": "vg_7a6d4f30",
    "ParamObj": "{\"input\":\"vid://lrv1_aaaa.bbbb\",\"resolution\":\"1080p\",\"style\":\"manga\"}",
    "Status": "success",
    "OutputJson": "{\"vid\":\"lrv1_cccc.dddd\"}"
  }
}
```

<Note>
`ParamObj` 与 `OutputJson` 是**序列化后的 JSON 字符串**（与官方一致），需要再做一次 JSON 解析。任务失败（`failed_run`）**不收费**。
</Note>

---

## 步骤 5 · 获取播放地址

```
GET /api/vod?Action=GetPlayInfo&Version=2020-08-01&Vid={成片Vid}
```

### Query 参数

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `Vid` | 是 | 步骤 4 `OutputJson` 中的成片 `Vid` |

### 响应 `Result`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `Vid` | string | 回显成片 Vid |
| `Status` | int | `10` 表示已就绪可播 |
| `FileType` | string | 固定 `video` |
| `TotalCount` | int | 播放信息条数 |
| `Duration` | number | 成片时长（秒） |
| `PlayInfoList` | array | 播放信息列表 |

**`PlayInfoList[]` 元素**：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `MainPlayUrl` | string | 成片播放 / 下载地址（**临时链接，约 2 小时后失效**） |
| `FileType` | string | 固定 `video` |
| `Format` | string | 封装格式，如 `mp4` |
| `Width` | int | 成片宽（像素） |
| `Height` | int | 成片高（像素） |
| `Codec` | string | 视频编码，如 `H264`（可选，视素材而定） |
| `Bitrate` | int | 码率（bps）（可选） |
| `Size` | number | 文件大小（字节）（可选） |
| `Md5` | string | 文件 MD5（可选） |
| `Definition` | string | 清晰度档位，如 `1080p`（可选） |
| `Quality` | string | 画质标记，如 `normal`（可选） |

```json
{
  "Result": {
    "Vid": "lrv1_cccc.dddd",
    "Status": 10,
    "FileType": "video",
    "TotalCount": 1,
    "Duration": 12.5,
    "PlayInfoList": [
      {
        "MainPlayUrl": "https://…/out.mp4?…",
        "FileType": "video",
        "Format": "mp4",
        "Width": 1920,
        "Height": 1080,
        "Codec": "H264",
        "Bitrate": 2500000,
        "Size": 9437184,
        "Md5": "d41d8cd98f00b204e9800998ecf8427e",
        "Definition": "1080p",
        "Quality": "normal"
      }
    ]
  }
}
```

<Warning>
- `MainPlayUrl` 为**临时链接**，约 **2 小时**后失效，请尽快下载并转存到你自己的存储。
- 任务未成功或成片尚未就绪时，返回 HTTP 404 + `Error.Code = ResourceNotFound`，稍后重试即可。
</Warning>

---

## 端到端调用示例

使用火山官方 VOD SDK（把接入域名指向 `api.looprouter.com`、填入控制台获取的 AK/SK）依次调用：

```text 调用顺序
# 1) 提交源视频 → JobId
POST /api/vod?Action=UploadMediaByUrl&Version=2020-08-01
     body: { "URLSets": [ { "SourceUrl": "https://…/src.mp4" } ] }
  -> Result.Data[0].JobId

# 2) 查询上传 → Vid
GET  /api/vod?Action=QueryUploadTaskInfo&Version=2020-08-01&JobIds=<JobId>
  -> Result.MediaInfoList[0].Vid

# 3) 提交转绘 → VCreativeId（开始计费）
POST /api/vod?Action=AsyncVCreativeTask&Version=2018-01-01
     body: { "ParamObj": { "input": "vid://<Vid>", "resolution": "1080p", "style": "manga" } }
  -> Result.VCreativeId

# 4) 轮询直到 Status=success → 成片 Vid
GET  /api/vod?Action=GetVCreativeTaskResult&Version=2018-01-01&VCreativeId=<VCreativeId>
  -> JSON.parse(Result.OutputJson).vid

# 5) 获取播放地址（尽快下载，约 2 小时失效）
GET  /api/vod?Action=GetPlayInfo&Version=2020-08-01&Vid=<成片Vid>
  -> Result.PlayInfoList[0].MainPlayUrl
```
