> ## Documentation Index
> Fetch the complete documentation index at: https://docs.laozhang.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 视频理解 API：用 Gemini 分析 MP4 视频的画面与音频

> 在老张API用 Gemini 模型解析完整 MP4 视频：画面时序与音轨同时理解，附本地上传、视频链接、章节时间戳、结构化 JSON、片段截取、抽帧率、多视频对比与 OpenAI SDK 调用示例。

视频理解让 Gemini 模型直接读取完整的 MP4，同时理解画面时序和音轨，用于生成章节与摘要、转写解说、检索某一时刻的内容或对比多个视频。直接上传视频文件即可，不需要先在本地抽帧转图片。

| 项目     | 内容                                                                                                      |
| ------ | ------------------------------------------------------------------------------------------------------- |
| 端点     | `POST https://api.laozhang.ai/v1beta/models/{模型}:generateContent`（[Gemini 原生接口](/api-reference/gemini)） |
| 视频来源   | 本地文件用 `inlineData` 内联；公网直链或公开 YouTube 视频用 `fileData`                                                    |
| 计费     | 画面与音轨都换算为输入 token，按模型单价计费，见[模型与价格总表](/models)                                                           |
| 本页示例模型 | `gemini-3.8-flash`                                                                                      |

## 选择模型

视频输入只有 Gemini 模型支持，GPT-6、GPT-5.6 等 OpenAI 模型不接受视频。以下模型都在 `default` 分组按量计费：

| 模型 ID                                     | 适合                    |
| ----------------------------------------- | --------------------- |
| `gemini-3.8-flash`                        | 默认选择，速度快，适合大多数视频分析    |
| `gemini-3.7-flash`                        | 与 3.8 Flash 相近的通用视频分析 |
| `gemini-3.1-pro-preview`、`gemini-2.5-pro` | 需要更强推理的复杂视频，单价更高      |
| `gemini-3.5-flash-lite`                   | 单价最低，适合批量摘要和分类        |

## 准备密钥和 SDK

在[令牌管理](https://api.laozhang.ai/token)创建 API Key，计费模式选择按量优先（推荐）或按量计费，然后写入环境变量。Python 示例使用 Google Gen AI SDK：

```bash theme={null}
export LAOZHANG_API_KEY="替换为你的老张API密钥"
python -m pip install google-genai
```

老张API不提供 Google File API（`/upload/v1beta/files`），SDK 的 `client.files.upload()` 不可用。本地视频按下文用 `inlineData` 放进请求，已有公网地址的视频用 `fileData` 传链接。

## 快速开始：上传本地视频

以下示例读取当前目录中的 `input.mp4`，让模型按时间顺序描述画面并转写语音：

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    import os
    from pathlib import Path
    from google import genai
    from google.genai import types

    client = genai.Client(
        api_key=os.environ["LAOZHANG_API_KEY"],
        http_options={
            "base_url": "https://api.laozhang.ai",
            "api_version": "v1beta",
            "timeout": 300_000,
        },
    )
    video = types.Part.from_bytes(
        data=Path("input.mp4").read_bytes(),
        mime_type="video/mp4",
    )
    response = client.models.generate_content(
        model="gemini-3.8-flash",
        contents=[video, "按时间顺序描述视频画面，并转写音频中的对话。"],
    )
    print(response.text)
    ```
  </Tab>

  <Tab title="cURL">
    Base64 视频太长，不适合直接写在命令行里。先用 Python 标准库生成请求文件：

    ```python theme={null}
    import base64
    import json
    from pathlib import Path

    request = {
        "contents": [{
            "role": "user",
            "parts": [
                {"inlineData": {
                    "mimeType": "video/mp4",
                    "data": base64.b64encode(
                        Path("input.mp4").read_bytes()
                    ).decode("ascii"),
                }},
                {"text": "按时间顺序描述视频画面，并转写音频中的对话。"},
            ],
        }],
    }
    Path("video-request.json").write_text(
        json.dumps(request, ensure_ascii=False), encoding="utf-8"
    )
    ```

    再发送请求文件：

    ```bash theme={null}
    curl --fail-with-body --max-time 300 \
      "https://api.laozhang.ai/v1beta/models/gemini-3.8-flash:generateContent" \
      -H "Authorization: Bearer $LAOZHANG_API_KEY" \
      -H "Content-Type: application/json" \
      --data-binary @video-request.json
    ```
  </Tab>
</Tabs>

回答在 `candidates[].content.parts` 的 `text` 中，SDK 用 `response.text` 读取。

使用内联视频时注意：

* `mimeType` 写文件的实际类型，MP4 为 `video/mp4`；`data` 只放 Base64 字符串，不带 `data:` 前缀。
* Base64 编码后请求体约为原文件的 4/3，视频越大上传越久，超时时间要留足。
* 大文件或已经托管在公网的视频，改用[视频链接](#分析视频链接)可以省去上传。

以下案例都复用上面创建的 `client`，本地视频统一为 `input.mp4`。

## 案例：按时间戳拆分章节

在提示词里写明时间格式和每章要包含的字段，模型会结合画面切换和语音内容划分章节：

```python theme={null}
video = types.Part.from_bytes(
    data=Path("input.mp4").read_bytes(), mime_type="video/mp4"
)
response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[
        video,
        "把视频按内容分成章节。每章给出起止时间（MM:SS）、画面上的标题和这一段语音的中文摘要。",
    ],
)
print(response.text)
```

回答类似：

```text theme={null}
1. 00:00 - 00:06  标题：INTRO    摘要：欢迎进入产品导览。
2. 00:06 - 00:12  标题：PRICING  摘要：入门套餐每月 29 美元。
3. 00:12 - 00:18  标题：DEMO     摘要：演示上传文件并运行第一个任务。
```

画面与声音按时间对齐，所以模型能指出「某段画面出现时说了什么」。标注的时间可能与实际切换点相差约 1 秒，需要精确到秒时见[时间戳准确吗](#时间戳准确吗？)。

## 案例：输出结构化 JSON

要把结果写入数据库或字幕系统，在 `config` 中指定 `response_mime_type` 和 `response_schema`，模型会返回符合结构的 JSON，SDK 用 `response.parsed` 得到对象：

```python theme={null}
from pydantic import BaseModel

class Chapter(BaseModel):
    start: str
    end: str
    title: str
    summary: str

video = types.Part.from_bytes(
    data=Path("input.mp4").read_bytes(), mime_type="video/mp4"
)
response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[video, "按章节列出视频内容，时间用 MM:SS。"],
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=list[Chapter],
    ),
)
for chapter in response.parsed:
    print(chapter.start, chapter.end, chapter.title, chapter.summary)
```

用 REST 请求时，把同样的设置写进 `generationConfig`：

```json theme={null}
"generationConfig": {
  "responseMimeType": "application/json",
  "responseSchema": {
    "type": "ARRAY",
    "items": {
      "type": "OBJECT",
      "properties": {
        "start": {"type": "STRING"},
        "end": {"type": "STRING"},
        "title": {"type": "STRING"},
        "summary": {"type": "STRING"}
      },
      "required": ["start", "end", "title", "summary"]
    }
  }
}
```

## 案例：只分析其中一段

用 `videoMetadata` 的 `startOffset` 和 `endOffset` 截取片段，模型只处理这一段，用量按片段时长计算。长视频里只关心某几分钟时，这比上传整段更省：

```python theme={null}
clip = types.Part(
    inline_data=types.Blob(
        data=Path("input.mp4").read_bytes(), mime_type="video/mp4"
    ),
    video_metadata=types.VideoMetadata(start_offset="12s", end_offset="18s"),
)
response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[clip, "这一段画面上显示什么？语音说了什么？"],
)
print(response.text)
```

REST 请求中，`videoMetadata` 与 `inlineData` 或 `fileData` 写在同一个 part 里：

```json theme={null}
{
  "inlineData": {"mimeType": "video/mp4", "data": "<Base64 数据>"},
  "videoMetadata": {"startOffset": "12s", "endOffset": "18s"}
}
```

只想问某一时刻时，也可以不截取，直接在提示词中写时间，例如「00:14 时画面上显示什么？」。

## 分析视频链接

视频已有公网地址时，用 `fileData` 传链接，由服务端下载，省去 Base64 上传。以下示例分析一个公开 YouTube 视频的前 60 秒：

<Tabs>
  <Tab title="Python SDK">
    ```python theme={null}
    video = types.Part(
        file_data=types.FileData(
            file_uri="https://www.youtube.com/watch?v=9hE5-98ZeCg",
            mime_type="video/mp4",
        ),
        video_metadata=types.VideoMetadata(start_offset="0s", end_offset="60s"),
    )
    response = client.models.generate_content(
        model="gemini-3.8-flash",
        contents=[video, "按时间顺序概括这段视频的画面和讲解内容。"],
    )
    print(response.text)
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl --fail-with-body --max-time 300 \
      "https://api.laozhang.ai/v1beta/models/gemini-3.8-flash:generateContent" \
      -H "Authorization: Bearer $LAOZHANG_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "contents": [{
          "role": "user",
          "parts": [
            {
              "fileData": {
                "fileUri": "https://www.youtube.com/watch?v=9hE5-98ZeCg",
                "mimeType": "video/mp4"
              },
              "videoMetadata": {"startOffset": "0s", "endOffset": "60s"}
            },
            {"text": "按时间顺序概括这段视频的画面和讲解内容。"}
          ]
        }]
      }'
    ```
  </Tab>
</Tabs>

链接的要求：

* 可以是公开的 YouTube 视频，也可以是 MP4 直链。
* 必须无需登录、Cookie 或签名即可下载，服务端拉取失败时返回 400 `Cannot fetch content from the provided URL`。
* 私有存储中的视频，先生成可公开访问的临时链接，或下载后用 `inlineData` 上传。

## 案例：一次对比多个视频

在同一条消息里依次放入多个视频 part，并在提示词中说明顺序：

```python theme={null}
first = types.Part.from_bytes(data=Path("a.mp4").read_bytes(), mime_type="video/mp4")
second = types.Part.from_bytes(data=Path("b.mp4").read_bytes(), mime_type="video/mp4")
response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[first, second, "第一个视频和第二个视频分别讲了什么？列出两者的主要差异。"],
)
print(response.text)
```

每个视频的 token 分别计算，总用量是各视频之和。

## 控制抽帧率和用量

模型默认每秒抽取 1 帧画面，音轨完整处理。用 `videoMetadata.fps` 可以调整抽帧率：

* 画面变化慢的视频，例如讲座、录屏，设为 `0.5` 等更低的值，画面 token 大约按比例减少。
* 动作快、需要捕捉短暂画面的视频，设为 `2` 等更高的值，画面 token 大约按比例增加。
* 音频 token 不受 `fps` 影响。

```python theme={null}
video = types.Part(
    inline_data=types.Blob(
        data=Path("input.mp4").read_bytes(), mime_type="video/mp4"
    ),
    video_metadata=types.VideoMetadata(fps=0.5),
)
```

`fps` 可以与 `startOffset`、`endOffset` 写在同一个 `videoMetadata` 中。

## 流式输出

长视频的回答较长时，可以边生成边显示。SDK 用 `generate_content_stream`，REST 把方法换成 `streamGenerateContent` 并加上 `?alt=sse`：

```python theme={null}
video = types.Part.from_bytes(
    data=Path("input.mp4").read_bytes(), mime_type="video/mp4"
)
for chunk in client.models.generate_content_stream(
    model="gemini-3.8-flash",
    contents=[video, "按时间顺序总结这个视频。"],
):
    print(chunk.text or "", end="", flush=True)
print()
```

流式过程中 SDK 可能打印 `is not a valid FinishReason` 警告，不影响输出内容。

## 用 OpenAI SDK 调用

已经基于 OpenAI SDK 开发的应用，可以在 Chat Completions 中用 `video_url` 内容块传视频，只接受 Base64 data URL：

```python theme={null}
import base64
import os
from pathlib import Path
from openai import OpenAI

video_data = base64.b64encode(Path("input.mp4").read_bytes()).decode("ascii")

client = OpenAI(
    api_key=os.environ["LAOZHANG_API_KEY"],
    base_url="https://api.laozhang.ai/v1",
    timeout=300.0,
    max_retries=0,
)
response = client.chat.completions.create(
    model="gemini-3.8-flash",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "按时间顺序描述视频画面，并转写音频中的对话。"},
            {"type": "video_url", "video_url": {"url": f"data:video/mp4;base64,{video_data}"}},
        ],
    }],
)
print(response.choices[0].message.content)
```

这种写法有以下限制：

* 需要 `pip install openai`，`model` 只能用 Gemini 模型。
* `video_url` 里传公网链接，或用 `file` 内容块传视频，视频会被忽略，模型可能在没看到视频的情况下作答。
* 不支持视频链接、片段截取和 `fps`；需要这些功能时使用原生接口。
* 响应 `usage` 中的 `video_tokens` 大于 0，说明视频已被读取。

## 读取用量与计费

原生接口的 `usageMetadata.promptTokensDetails` 分别列出画面与音轨的 token：

```json theme={null}
"promptTokensDetails": [
  {"modality": "VIDEO", "tokenCount": 1980},
  {"modality": "AUDIO", "tokenCount": 750},
  {"modality": "TEXT", "tokenCount": 30}
]
```

两者都按输入 token 计费。要降低用量，可以截取片段、降低 `fps`，或换用单价更低的模型。每次请求的实际费用以[调用日志](/faq/call-logs)为准。

## 错误处理

| 现象                                                | 处理                                                      |
| ------------------------------------------------- | ------------------------------------------------------- |
| 400，提示 Cannot fetch content from the provided URL | 链接无法直接下载，换成公开直链，或改用 `inlineData`                        |
| 上传文件时返回网页或 404                                    | 不提供 File API，改用 `inlineData` 或 `fileData` 链接            |
| 返回 200，但回答与视频无关                                   | 检查用量中是否有 `VIDEO`；OpenAI 格式下确认用的是 `video_url` 和 data URL |
| 请求超时                                              | 视频较大时延长客户端超时，或截取片段、改用视频链接；重试前先查看[调用日志](/faq/call-logs)  |
| 400 或 500，提示 `video_url` 无效                       | 确认模型是 Gemini 模型，OpenAI 模型不接受视频                          |

## 常见问题

### 可以直接上传完整 MP4 吗？

可以。把整个 MP4 编码为 Base64 放进 `inlineData`，模型会同时理解画面时序和音轨，不需要预先抽帧转图片。视频已有公网地址时，用 `fileData` 传链接更省上传时间。

### 哪些模型支持视频理解？

以下模型都支持：

* `gemini-3.8-flash`、`gemini-3.7-flash`
* `gemini-3.5-flash-lite`
* `gemini-3.1-pro-preview`、`gemini-2.5-pro`

使用其他 Gemini 模型前，先发送一个短视频，检查用量中是否出现 `VIDEO`。

### 模型能听到视频里的声音吗？

能。音轨会和画面一起处理，可以转写对白、总结解说，也能回答「这段画面出现时说了什么」这类需要音画对齐的问题。用量中的 `AUDIO` 就是音轨占用的 token。

### 时间戳准确吗？

章节顺序和内容可靠，但各模型标注的起止时间都可能与实际切换点相差约 1 秒。需要逐秒核对时：

* 用 `startOffset` 和 `endOffset` 截取相关片段再问一次；
* 提高 `fps`，让模型看到更密的画面；
* 用 `whisper-1` 生成带时间戳的字幕，按语音时间核对，见[生成字幕和时间戳](/api-capabilities/audio-transcription#生成字幕和时间戳)。

### 视频有大小或时长限制吗？

内联视频会让请求体增大约三分之一，文件越大上传越慢、越容易超时。大文件建议用 `fileData` 传公网链接，长视频可以用 `startOffset`、`endOffset` 分段处理。

### 支持 Google File API 吗？

不支持，以下写法都不可用：

* `/upload/v1beta/files` 上传接口；
* `files/...` 形式的文件引用；
* SDK 的 `client.files.upload()`。

本地视频用 `inlineData`，公网视频用 `fileData`。

### 能生成视频吗？

本页只负责理解已有视频。生成视频可使用 [Wan 2.7](/api-capabilities/wan-video-generation) 或 [Seedance 2.0](/api-capabilities/seedance2-video-generation)。

## 相关文档

* [Gemini 协议](/api-reference/gemini)
* [图片理解 API](/api-capabilities/vision-understanding)
* [音频转录与语音生成](/api-capabilities/audio-transcription)
* [Google 视频理解文档](https://ai.google.dev/gemini-api/docs/video-understanding)
* [模型与价格总表](/models)
* [调用日志](/faq/call-logs)
