Gemini API 동영상 이해하기

Gemini API 동영상 이해하기 (Video Understanding)

Gemini 모델은 동영상을 처리할 수 있어요. 과거에는 도메인 특화 모델이 필요했을 많은 최첨단 개발자 사용 사례를 가능하게 합니다. Gemini의 비전 기능 중 일부는 동영상을 설명·분할·정보 추출하고, 동영상 내용에 관한 질문에 답하고, 동영상 안의 특정 타임스탬프를 참조하는 능력을 포함해요.

출처: 문서

본문

동영상 생성에 대해 배우려면 Gemini Omni Flash 가이드를 참고하세요.

Gemini에 동영상을 입력으로 제공하는 방법은 다음과 같아요.

입력 방법 최대 크기 권장 사용 사례
File API 20GB (유료) / 2GB (무료) 대용량 파일(100MB+), 긴 동영상(10분+), 재사용 파일.
Cloud Storage 등록 2GB (파일당, 저장 한도 없음) 대용량 파일(100MB+), 긴 동영상(10분+), 영구·재사용 파일.
인라인 데이터 < 100MB 작은 파일(<100MB), 짧은 길이(<1분), 일회성 입력.
YouTube URL 해당 없음 공개 YouTube 동영상.

참고: File API가 대부분의 사용 사례, 특히 100MB보다 큰 파일이나 여러 요청에 걸쳐 파일을 재사용하려 할 때 권장됩니다.

외부 URL이나 Google Cloud에 저장된 파일 같은 다른 파일 입력 방법은 File input methods 가이드를 참고하세요.

동영상 파일 업로드

아래 코드는 샘플 동영상을 다운로드해 Files API로 업로드하고, 처리될 때까지 기다린 뒤, 업로드된 파일 참조를 사용해 동영상을 요약해요.

from google import genai

client = genai.Client()

myfile = client.files.upload(file="path/to/sample.mp4")

response = client.models.generate_content(
    model="gemini-3.8-flash", contents=[myfile, "Summarize this video. Then create a quiz with an answer key based on the information in this video."]
)

print(response.text)
import {
  GoogleGenAI,
  createUserContent,
  createPartFromUri,
} from "@google/genai";

const ai = new GoogleGenAI({});

async function main() {
  const myfile = await ai.files.upload({
    file: "path/to/sample.mp4",
    config: { mimeType: "video/mp4" },
  });

  const response = await ai.models.generateContent({
    model: "gemini-3.8-flash",
    contents: createUserContent([
      createPartFromUri(myfile.uri, myfile.mimeType),
      "Summarize this video. Then create a quiz with an answer key based on the information in this video.",
    ]),
  });
  console.log(response.text);
}

await main();
uploadedFile, _ := client.Files.UploadFromPath(ctx, "path/to/sample.mp4", nil)

parts := []*genai.Part{
    genai.NewPartFromText("Summarize this video. Then create a quiz with an answer key based on the information in this video."),
    genai.NewPartFromURI(uploadedFile.URI, uploadedFile.MIMEType),
}

contents := []*genai.Content{
    genai.NewContentFromParts(parts, genai.RoleUser),
}

result, _ := client.Models.GenerateContent(
    ctx,
    "gemini-3.8-flash",
    contents,
    nil,
)

fmt.Println(result.Text())
VIDEO_PATH="path/to/sample.mp4"
MIME_TYPE=$(file -b --mime-type "${VIDEO_PATH}")
NUM_BYTES=$(wc -c < "${VIDEO_PATH}")
DISPLAY_NAME=VIDEO

tmp_header_file=upload-header.tmp

echo "Starting file upload..."
curl "https://generativelanguage.googleapis.com/upload/v1beta/files" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -D ${tmp_header_file} \
  -H "X-Goog-Upload-Protocol: resumable" \
  -H "X-Goog-Upload-Command: start" \
  -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \
  -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \
  -H "Content-Type: application/json" \
  -d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null

upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")
rm "${tmp_header_file}"

echo "Uploading video data..."
curl "${upload_url}" \
  -H "Content-Length: ${NUM_BYTES}" \
  -H "X-Goog-Upload-Offset: 0" \
  -H "X-Goog-Upload-Command: upload, finalize" \
  --data-binary "@${VIDEO_PATH}" 2> /dev/null > file_info.json

file_uri=$(jq -r ".file.uri" file_info.json)
echo file_uri=$file_uri

echo "File uploaded successfully. File URI: ${file_uri}"

# --- 3. Generate content using the uploaded video file ---
echo "Generating content from video..."
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
          {"file_data":{"mime_type": "'"${MIME_TYPE}"'", "file_uri": "'"${file_uri}"'"}},
          {"text": "Summarize this video. Then create a quiz with an answer key based on the information in this video."}]
        }]
      }' 2> /dev/null > response.json

jq -r ".candidates[].content.parts[].text" response.json

토큰 효율과 성능을 최적화하려면 에이전틱 동영상 처리를 고려해 보세요.

전체 요청 크기(파일, 텍스트 프롬프트, 시스템 지시 포함)가 20MB보다 크거나, 동영상 길이가 상당하거나, 같은 동영상을 여러 프롬프트에서 사용하려 한다면 항상 Files API를 사용하세요. File API는 동영상 파일 형식을 직접 받아들여요.

미디어 파일 다루는 방법은 Files API에서 더 배울 수 있어요.

동영상 데이터 인라인 전달

File API로 동영상 파일을 업로드하는 대신, 더 작은 동영상을 generateContent 요청에 직접 전달할 수 있어요. 전체 요청 크기가 20MB 미만인 더 짧은 동영상에 적합해요.

인라인 동영상 데이터 예시:

from google import genai
from google.genai import types

# Only for videos of size <20Mb
video_file_name = "/path/to/your/video.mp4"
video_bytes = open(video_file_name, 'rb').read()

client = genai.Client()
response = client.models.generate_content(
    model='gemini-3.8-flash',
    contents=types.Content(
        parts=[
            types.Part(
                inline_data=types.Blob(data=video_bytes, mime_type='video/mp4')
            ),
            types.Part(text='Please summarize the video in 3 sentences.')
        ]
    )
)
print(response.text)
import { GoogleGenAI } from "@google/genai";
import * as fs from "node:fs";

const ai = new GoogleGenAI({});
const base64VideoFile = fs.readFileSync("path/to/small-sample.mp4", {
  encoding: "base64",
});

const contents = [
  {
    inlineData: {
      mimeType: "video/mp4",
      data: base64VideoFile,
    },
  },
  { text: "Please summarize the video in 3 sentences." }
];

const response = await ai.models.generateContent({
  model: "gemini-3.8-flash",
  contents: contents,
});
console.log(response.text);
VIDEO_PATH=/path/to/your/video.mp4

if [[ "$(base64 --version 2>&1)" = *"FreeBSD"* ]]; then
  B64FLAGS="--input"
else
  B64FLAGS="-w0"
fi

curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
            {
              "inline_data": {
                "mime_type":"video/mp4",
                "data": "'$(base64 $B64FLAGS $VIDEO_PATH)'"
              }
            },
            {"text": "Please summarize the video in 3 sentences."}
        ]
      }]
    }' 2> /dev/null

참고: Argument list too long 오류가 나면 파일의 base64 인코딩이 curl 명령줄에 너무 길 수 있어요. 더 큰 파일에는 File API 방법을 사용하세요.

YouTube URL 전달

프리뷰: YouTube URL 기능은 프리뷰 상태이며 무료로 제공돼요. 가격과 속도 제한은 변경될 수 있습니다.

YouTube URL을 요청의 일부로 Gemini API에 직접 전달할 수 있어요.

from google import genai
from google.genai import types

client = genai.Client()
response = client.models.generate_content(
    model='gemini-3.8-flash',
    contents=types.Content(
        parts=[
            types.Part(
                file_data=types.FileData(file_uri='https://www.youtube.com/watch?v=9hE5-98ZeCg')
            ),
            types.Part(text='Please summarize the video in 3 sentences.')
        ]
    )
)
print(response.text)
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({});

const contents = [
  {
    fileData: {
      fileUri: "https://www.youtube.com/watch?v=9hE5-98ZeCg",
    },
  },
  { text: "Please summarize the video in 3 sentences." }
];

const response = await ai.models.generateContent({
  model: "gemini-3.8-flash",
  contents: contents,
});
console.log(response.text);
package main

import (
  "context"
  "fmt"
  "os"
  "google.golang.org/genai"
)

func main() {
  ctx := context.Background()
  client, err := genai.NewClient(ctx, nil)
  if err != nil {
      log.Fatal(err)
  }

  parts := []*genai.Part{
      genai.NewPartFromText("Please summarize the video in 3 sentences."),
      genai.NewPartFromURI("https://www.youtube.com/watch?v=9hE5-98ZeCg","video/mp4"),
  }

  contents := []*genai.Content{
      genai.NewContentFromParts(parts, genai.RoleUser),
  }

  result, _ := client.Models.GenerateContent(
      ctx,
      "gemini-3.8-flash",
      contents,
      nil,
  )

  fmt.Println(result.Text())
}
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
            {"text": "Please summarize the video in 3 sentences."},
            {
              "file_data": {
                "file_uri": "https://www.youtube.com/watch?v=9hE5-98ZeCg"
              }
            }
        ]
      }]
    }' 2> /dev/null

제한 사항:

  • 무료 계층에서는 하루에 8시간 이상의 YouTube 동영상을 업로드할 수 없어요.
  • 유료 계층에서는 동영상 길이에 따른 제한이 없어요.
  • Gemini 2.5 이전 모델에서는 요청당 1개 동영상만 업로드할 수 있어요. Gemini 2.5 이상 모델에서는 요청당 최대 10개 동영상을 업로드할 수 있어요.
  • 공개 동영상만 업로드할 수 있어요(비공개·숨김 동영상은 안 됨).

에이전틱 동영상 이해 (Agentic video understanding)

기본적으로 동영상 입력은 정적 처리를 사용해요(1 FPS로 프레임 추출). Gemini 3.8 Flash, 3.7 Flash, 3.6 Flash, 3.5 Flash Lite 모델은 에이전틱 동영상 이해도 지원하는데, 모델이 동영상 타임라인을 동적으로 탐색하고, 프롬프트에 따라 전사본을 선택적으로 검사하고, 프레임 속도와 해상도를 그때그때 적응적으로 조정합니다.

모드 설명 지원 모델
정적 (Static) (기본값) 고정 속도(1 FPS)로 프레임을 추출해 한 번에 컨텍스트에 배치. 짧은 클립에 잘 맞음. 모든 Gemini 모델
에이전틱 (Agentic) 모델이 동영상 타임라인을 동적으로 탐색하며 프롬프트에 기반해 필요한 콘텐츠만 로드. 긴 콘텐츠에서 최대 88% 토큰 효율, 약 7% 높은 품질. Gemini 3.8 Flash, 3.7 Flash, 3.6 Flash, 3.5 Flash Lite

처리 모드 선택

일반 지침으로, 특히 응답 품질이나 토큰 효율을 최적화할 때 에이전틱 모드로 시작하세요.

  • 에이전틱 (Agentic): 긴 형식 동영상이나 특정 순간을 대상으로 하는 쿼리. 모델이 타임라인을 동적으로 탐색해 컨텍스트 윈도우를 채우지 않고 맥락상 관련 있는 정보를 타겟팅해요.
  • 정적 (Static): 짧은 클립(5분 미만)의 지연 시간에 민감한 쿼리, 또는 전체 클립에 걸쳐 프레임 수준 정밀도가 필요한 경우.

참고: 에이전틱 처리가 더 오래 걸리는 긴 동영상이나 복잡한 프롬프트에서는 스트리밍(client.models.generate_content_stream)을 사용하세요. 이렇게 하면 연결을 활성 상태로 유지하고 중간 추론 단계를 표시하며 연결·인증 타임아웃을 피할 수 있어요.

처리 모드 설정

import time
from google import genai
from google.genai import types

client = genai.Client()

video_file = client.files.upload(file="path/to/lecture.mp4")

while video_file.state.name == "PROCESSING":
    time.sleep(2)
    video_file = client.files.get(name=video_file.name)

response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[
        types.Part.from_uri(
            file_uri=video_file.uri,
            mime_type=video_file.mime_type,
            media_processing="AGENTIC",
        ),
        "What are the three main arguments presented?",
    ],
)
print(response.text)
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({});

let videoFile = await ai.files.upload({
  file: "path/to/lecture.mp4",
  config: { mimeType: "video/mp4" },
});

while (videoFile.state === "PROCESSING") {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  videoFile = await ai.files.get({ name: videoFile.name });
}

const response = await ai.models.generateContent({
  model: "gemini-3.8-flash",
  contents: [
    {
      role: "user",
      parts: [
        {
          fileData: {
            fileUri: videoFile.uri,
            mimeType: videoFile.mimeType,
          },
          mediaProcessing: "AGENTIC",
        },
        { text: "What are the three main arguments presented?" },
      ],
    },
  ],
});
console.log(response.text);
uploadedFile, _ := client.Files.UploadFromPath(ctx, "path/to/lecture.mp4", nil)
parts := []*genai.Part{
    {
        FileData: &genai.FileData{
            FileURI:  uploadedFile.URI,
            MIMEType: uploadedFile.MIMEType,
        },
        MediaProcessing: genai.MediaProcessingAgentic,
    },
    genai.NewPartFromText("What are the three main arguments presented?"),
}
contents := []*genai.Content{
    genai.NewContentFromParts(parts, genai.RoleUser),
}
result, _ := client.Models.GenerateContent(
    ctx,
    "gemini-3.8-flash",
    contents,
    nil,
)
fmt.Println(result.Text())
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent?key=$GEMINI_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "contents": [{
      "parts": [
        {
          "file_data": {
            "file_uri": "'${file_uri}'",
            "mime_type": "video/mp4"
          },
          "media_processing": "AGENTIC"
        },
        {"text": "What are the three main arguments presented?"}
      ]
    }]
  }'

참고: 에이전틱 처리가 사용됐는지 확인하려면 response.candidates[0].content.parts를 검사하세요. MEDIA_PROCESSING 도구 유형의 tool_call과 tool_response 부분이 있으면 모델이 동영상을 동적으로 탐색했다는 뜻이에요.

참고: 다른 서버측 도구(Google Search나 URL 컨텍스트 같은)와 달리, 에이전틱 동영상은 도구 호출과 결과를 반환·스트리밍하려고 ToolConfig에서 include_server_side_tool_invocations=True를 설정할 필요가 없어요. 어떤 입력 부분에 media_processing="AGENTIC"가 설정되면 동영상 탐색용 tool_call과 tool_response 부분은 자동으로 반환돼요.

응답 구조

에이전틱 처리가 활성화되면 응답에 내부 탐색 추적을 드러내는 추가 부분이 포함돼요.

  • tool_call 부분 (tool_type: "MEDIA_PROCESSING"): 모델이 동영상 세그먼트나 오디오 전사본을 요청할 때마다 생성.
  • tool_response 부분 (tool_type: "MEDIA_PROCESSING"): 각 로드 작업의 결과.

이 부분들을 수동으로 처리하거나 답할 필요는 없어요. 전체 응답을 대화 히스토리로 다시 전달하면 자동으로 처리됩니다.

ThinkingConfig에서 include_thoughts=True를 설정하면 추론 단계가 도구 호출·응답 쌍과 섞인 thought: true 부분으로 나타나요. 생각을 끄면 생각 텍스트는 생략되지만 도구 부분은 여전히 존재해요.

아래 예시는 도구 호출과 응답 부분이 섞인 응답 페이로드를 보여줘요.

{
  "candidates": [
    {
      "content": {
        "role": "model",
        "parts": [
          {
            "thought": true,
            "text": "Inspecting transcript for key discussion topics..."
          },
          {
            "thought_signature": "sig_A",
            "tool_call": {
              "tool_type": "MEDIA_PROCESSING"
            }
          },
          {
            "thought_signature": "sig_B",
            "tool_response": {
              "tool_type": "MEDIA_PROCESSING"
            }
          },
          {
            "thought": true,
            "text": "Loading visual frames to verify slide content..."
          },
          {
            "thought_signature": "sig_C",
            "tool_call": {
              "tool_type": "MEDIA_PROCESSING"
            }
          },
          {
            "thought_signature": "sig_D",
            "tool_response": {
              "tool_type": "MEDIA_PROCESSING"
            }
          },
          {
            "thought": true,
            "text": "Synthesizing answer from gathered evidence..."
          },
          {
            "text": "The three main arguments presented in the lecture are...",
            "thought_signature": "sig_E"
          }
        ]
      }
    }
  ]
}

동영상 간 처리 모드 섞기

같은 요청에서 각 동영상 Part에 서로 다른 처리 모드를 설정할 수 있어요.

from google import genai
from google.genai import types

client = genai.Client()

lecture = client.files.upload(file="path/to/long-lecture.mp4")
experiment = client.files.upload(file="path/to/short-experiment.mp4")

response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[
        types.Part.from_uri(
            file_uri=lecture.uri,
            mime_type=lecture.mime_type,
            media_processing="AGENTIC",  # Use agentic video understanding
        ),
        types.Part.from_uri(
            file_uri=experiment.uri,
            mime_type=experiment.mime_type,
            media_processing="STATIC",  # Use static processing
        ),
        "Compare the lecture content with the experiment results.",
    ],
)
print(response.text)
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({});

const lecture = await ai.files.upload({
  file: "path/to/long-lecture.mp4",
  config: { mimeType: "video/mp4" },
});
const experiment = await ai.files.upload({
  file: "path/to/short-experiment.mp4",
  config: { mimeType: "video/mp4" },
});

const response = await ai.models.generateContent({
  model: "gemini-3.8-flash",
  contents: [
    {
      role: "user",
      parts: [
        {
          fileData: {
            fileUri: lecture.uri,
            mimeType: lecture.mimeType,
          },
          mediaProcessing: "AGENTIC", // Use agentic video understanding
        },
        {
          fileData: {
            fileUri: experiment.uri,
            mimeType: experiment.mimeType,
          },
          mediaProcessing: "STATIC", // Use static processing
        },
        { text: "Compare the lecture content with the experiment results." },
      ],
    },
  ],
});
console.log(response.text);
lecturePart := &genai.Part{
    FileData: &genai.FileData{
        FileURI:  lectureFile.URI,
        MIMEType: lectureFile.MIMEType,
    },
    MediaProcessing: genai.MediaProcessingAgentic, // Use agentic
}
experimentPart := &genai.Part{
    FileData: &genai.FileData{
        FileURI:  experimentFile.URI,
        MIMEType: experimentFile.MIMEType,
    },
    MediaProcessing: genai.MediaProcessingStatic, // Use static
}
parts := []*genai.Part{
    lecturePart,
    experimentPart,
    genai.NewPartFromText("Compare the lecture content with the experiment results."),
}
contents := []*genai.Content{
    genai.NewContentFromParts(parts, genai.RoleUser),
}
result, _ := client.Models.GenerateContent(ctx, "gemini-3.8-flash", contents, nil)
fmt.Println(result.Text())
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent?key=$GEMINI_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "contents": [{
      "parts": [
        {
          "file_data": {
            "file_uri": "'${lecture_uri}'",
            "mime_type": "video/mp4"
          },
          "media_processing": "AGENTIC"
        },
        {
          "file_data": {
            "file_uri": "'${experiment_uri}'",
            "mime_type": "video/mp4"
          },
          "media_processing": "STATIC"
        },
        {"text": "Compare the lecture content with the experiment results."}
      ]
    }]
  }'

긴 동영상에 컨텍스트 캐싱 사용

10분보다 긴 동영상이나 같은 동영상 파일에 여러 요청을 할 계획이라면 컨텍스트 캐싱으로 비용을 줄이고 지연 시간을 개선하세요. 컨텍스트 캐싱을 사용하면 동영상을 한 번만 처리하고 이후 쿼리에서 토큰을 재사용할 수 있어, 채팅 세션이나 긴 형식 콘텐츠의 반복 분석에 이상적이에요.

콘텐츠에서 타임스탬프 참조

MM:SS 형식의 타임스탬프로 동영상 안의 특정 시점에 대해 질문할 수 있어요.

response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[
        myfile,
        "What are the examples given at 00:05 and 00:10 supposed to show us?",
    ],
)
print(response.text)
const response = await ai.models.generateContent({
  model: "gemini-3.8-flash",
  contents: [
    myfile,
    "What are the examples given at 00:05 and 00:10 supposed to show us?",
  ],
});
console.log(response.text);
parts := []*genai.Part{
    genai.NewPartFromURI(uploadedFile.URI, uploadedFile.MIMEType),
    genai.NewPartFromText("What are the examples given at 00:05 and 00:10 supposed to show us?"),
}

result, _ := client.Models.GenerateContent(
    ctx,
    "gemini-3.8-flash",
    []*genai.Content{genai.NewContentFromParts(parts, genai.RoleUser)},
    nil,
)
fmt.Println(result.Text())
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
          {"file_data": {"file_uri": "'"${file_uri}"'", "mime_type": "'"${MIME_TYPE}"'"}},
          {"text": "What are the examples given at 00:05 and 00:10 supposed to show us?"}
        ]
      }]
    }' 2> /dev/null

동영상에서 상세 인사이트 추출

Gemini 모델은 오디오와 시각적 스트림 모두의 정보를 처리해 동영상 콘텐츠를 이해하는 강력한 능력을 제공해요. 동영상에서 무슨 일이 일어나는지에 대한 설명 생성과 콘텐츠에 대한 질문 응답을 포함해 풍부한 세부 사항을 추출할 수 있습니다.

시각적 설명을 위해 모델은 동영상을 초당 1프레임(FPS) 비율로 샘플링해요. 이 기본 샘플링 비율은 대부분의 콘텐츠에 잘 맞지만, 빠른 움직임이나 빠른 장면 전환이 있는 동영상에서는 세부 사항을 놓칠 수 있음에 유의하세요. 이런 고움직임 콘텐츠에는 커스텀 프레임 속도 설정을 고려해 보세요.

response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[
        myfile,
        "Describe the key events in this video, providing both audio and visual details. Include timestamps for salient moments.",
    ],
)
print(response.text)
const response = await ai.models.generateContent({
  model: "gemini-3.8-flash",
  contents: [
    myfile,
    "Describe the key events in this video, providing both audio and visual details. Include timestamps for salient moments.",
  ],
});
console.log(response.text);
parts := []*genai.Part{
    genai.NewPartFromURI(uploadedFile.URI, uploadedFile.MIMEType),
    genai.NewPartFromText("Describe the key events in this video, providing both audio and visual details. " +
        "Include timestamps for salient moments."),
}

result, _ := client.Models.GenerateContent(
    ctx,
    "gemini-3.8-flash",
    []*genai.Content{genai.NewContentFromParts(parts, genai.RoleUser)},
    nil,
)
fmt.Println(result.Text())
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:generateContent" \
    -H "x-goog-api-key: $GEMINI_API_KEY" \
    -H 'Content-Type: application/json' \
    -X POST \
    -d '{
      "contents": [{
        "parts":[
          {"file_data": {"file_uri": "'"${file_uri}"'", "mime_type": "'"${MIME_TYPE}"'"}},
          {"text": "Describe the key events in this video, providing both audio and visual details. Include timestamps for salient moments."}
        ]
      }]
    }' 2> /dev/null

동영상 처리 커스터마이즈

클리핑 간격을 설정하거나 커스텀 프레임 속도 샘플링을 제공해 Gemini API에서 동영상 처리를 커스터마이즈할 수 있어요. 이 커스터마이즈 옵션은 "static" 모드로 동영상을 처리할 때만 지원됩니다.

클리핑 간격 설정

videoMetadata에 시작·끝 오프셋을 지정해 동영상을 클립할 수 있어요.

from google import genai
from google.genai import types

client = genai.Client()
response = client.models.generate_content(
    model='models/gemini-3.8-flash',
    contents=types.Content(
        parts=[
            types.Part(
                file_data=types.FileData(file_uri='https://www.youtube.com/watch?v=XEzRZ35urlk'),
                video_metadata=types.VideoMetadata(
                    start_offset='1250s',
                    end_offset='1570s'
                )
            ),
            types.Part(text='Please summarize the video in 3 sentences.')
        ]
    )
)
import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI({});
const model = 'gemini-3.8-flash';

async function main() {
const contents = [
  {
    role: 'user',
    parts: [
      {
        fileData: {
          fileUri: 'https://www.youtube.com/watch?v=9hE5-98ZeCg',
          mimeType: 'video/*',
        },
        videoMetadata: {
          startOffset: '40s',
          endOffset: '80s',
        }
      },
      {
        text: 'Please summarize the video in 3 sentences.',
      },
    ],
  },
];

const response = await ai.models.generateContent({
  model,
  contents,
});

console.log(response.text)

}

await main();

커스텀 프레임 속도 설정

videoMetadata에 fps 인자를 전달해 커스텀 프레임 속도 샘플링을 설정할 수 있어요.

from google import genai
from google.genai import types

# Only for videos of size <20Mb
video_file_name = "/path/to/your/video.mp4"
video_bytes = open(video_file_name, 'rb').read()

client = genai.Client()
response = client.models.generate_content(
    model='models/gemini-3.8-flash',
    contents=types.Content(
        parts=[
            types.Part(
                inline_data=types.Blob(
                    data=video_bytes,
                    mime_type='video/mp4'),
                video_metadata=types.VideoMetadata(fps=5)
            ),
            types.Part(text='Please summarize the video in 3 sentences.')
        ]
    )
)
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({});

const myfile = await ai.files.upload({
  file: "path/to/sample.mp4",
  mimeType: "video/mp4",
});

const response = await ai.models.generateContent({
  model: "gemini-3.8-flash",
  contents: [
    {
      fileData: {
        fileUri: myfile.uri,
        mimeType: myfile.mimeType,
      },
      videoMetadata: {
        fps: 5,
      },
    },
    "Please summarize the video in 3 sentences.",
  ],
});

console.log(response.text);

기본적으로 동영상에서 초당 1프레임(FPS)이 샘플링돼요. 긴 동영상에는 낮은 FPS(< 1)를 설정하고 싶을 수 있어요. 이는 대부분 정적인 동영상(예: 강의)에 특히 유용해요. 빠른 동작 이해나 고속 움직임 추적 같은 세밀한 시간 분석이 필요한 동영상에는 더 높은 FPS를 사용하세요.

지원 동영상 형식

Gemini는 다음 동영상 형식 MIME 타입을 지원해요.

  • video/mp4
  • video/mpeg
  • video/quicktime
  • video/avi
  • video/x-flv
  • video/mpg
  • video/webm
  • video/wmv
  • video/3gpp

동영상에 대한 기술적 세부 사항

  • 지원 모델과 컨텍스트: 모든 Gemini 모델이 동영상 데이터를 처리할 수 있어요.
    • 1M 컨텍스트 윈도우가 있는 모델은 기본적으로(저 미디어 해상도) 최대 3시간 길이의 동영상, 또는 고 미디어 해상도에서 최대 1시간 길이의 동영상을 처리할 수 있어요.
  • 처리 모드: Gemini 3.8 Flash, 3.7 Flash, 3.6 Flash, 3.5 Flash Lite와 이후 모델은 두 가지 동영상 처리 모드를 지원해요.
    • 정적 (Static): 1 FPS로 프레임을 추출해 컨텍스트에 배치(모든 모델의 기본값). 오디오는 1Kbps(단일 채널)로 처리. 매초 타임스탬프 추가. 짧은 클립이나 모든 프레임이 중요할 때(프레임별 검사)에 최적. 빠른 동작 시퀀스는 1 FPS 샘플링으로 인해 세부 사항이 손실될 수 있음에 유의.
    • 에이전틱 (Agentic): 모델이 동영상을 동적으로 탐색하며 전사본·프레임·오디오를 요청 시 로드. 긴 콘텐츠에서 최대 88% 적은 토큰을 사용하지만, 생성이 시작되기 전 내부 추론·도구 왕복으로 인해 짧은 클립(<5분)에서 TTFT(Time to First Token)가 약간 늘 수 있어요. 응답은 턴 전반의 추론 컨텍스트 보존을 위해 MEDIA_PROCESSING 도구 호출·응답 부분을 포함해요. 토큰 비용과 응답 품질 최적화에 긴 형식 동영상에 최적. Gemini 3.8 Flash, 3.7 Flash, 3.6 Flash, 3.5 Flash Lite에서 지원.
  • 토큰 계산 (정적 모드): 동영상 1초는 다음과 같이 토큰화돼요.
    • 개별 프레임(1 FPS로 샘플링):
      • media_resolution이 low면 프레임당 66토큰으로 토큰화.
      • 그 외에는 프레임당 258토큰으로 토큰화.
    • 오디오: 초당 32토큰.
    • 메타데이터도 포함.
    • 총합: 기본(저) 미디어 해상도에서 동영상 1초당 약 100토큰, 고 미디어 해상도에서 동영상 1초당 약 300토큰.
  • 토큰 계산 (에이전틱 모드): 토큰 사용량은 콘텐츠 복잡도와 모델의 탐색 전략에 따라 달라져요. 동영상 탐색 중 생성된 탐색 추론 토큰은 thinking 토큰(thoughts_token_count)으로 계산되고, 요청 시 로드된 프레임·오디오·전사본은 도구 프롬프트 토큰(tool_use_prompt_token_count)으로 계산돼요. 에이전틱 처리는 모델이 프롬프트에 답하는 데 필요한 전사본·프레임·오디오만 로드하기 때문에 긴 콘텐츠에서 정적 처리보다 보통 최대 88% 적은 총 토큰을 사용해요(tokens 가이드 참고).
  • 미디어 해상도: Gemini 3는 media_resolution 파라미터로 멀티모달 비전 처리에 대한 세밀한 제어를 도입했어요. media_resolution 파라미터는 입력 이미지나 동영상 프레임당 할당되는 최대 토큰 수를 결정해요. 더 높은 해상도는 미세한 텍스트를 읽거나 작은 세부 사항을 식별하는 모델의 능력을 개선하지만 토큰 사용량과 지연 시간을 늘려요. media_resolution과 media_processing 파라미터는 독립적이에요. 같은 동영상 Part에 둘 다 설정할 수 있어요.

토큰 계산에 대한 자세한 내용은 tokens 가이드를 참고하세요.

  • 타임스탬프 형식: 프롬프트에서 동영상의 특정 순간을 참조할 때는 MM:SS 형식(예: 1분 15초는 01:15)을 사용하세요.
  • 프롬프트 배치: 텍스트와 단일 동영상을 결합한다면 contents 배열에서 텍스트 프롬프트를 동영상 part 다음에 두세요.
  • 긴 요청의 타임아웃: 확장 처리 시간이나 복잡한 다단계 추론이 필요한 동영상에는 스트리밍(client.models.generate_content_stream)을 사용하세요. 고부하에서 백엔드 재시도를 겪는 동기·비스트리밍 요청은 연결이나 인증 토큰 유효 시간을 초과해 예상 밖의 401 Unauthorized 또는 타임아웃 오류가 표시될 수 있어요. 스트리밍은 연결을 활성 상태로 유지하고 중간 추론·도구 호출 진행을 표시해요.

다음 단계

  • Media resolution: 품질과 토큰 사용을 균형 잡도록 동영상 프레임 해상도 제어.
  • Tokens: 정적·에이전틱 처리 모드에서 동영상 콘텐츠가 토큰화되는 방식을 이해.
  • System instructions: 시스템 지시로 특정 요구·사용 사례에 맞게 모델 동작 조종.
  • Files API: Gemini에 사용할 파일 업로드·관리에 대해 더 배우기.
  • File prompting strategies: Gemini API는 텍스트, 이미지, 오디오, 동영상 데이터(멀티모달 프롬프팅)로 프롬프트하는 것을 지원.
  • Safety guidance: 가끔 생성형 AI 모델이 부정확·편향·공격적인 출력 같은 예상 밖의 결과를 만들 수 있음. 후처리와 인간 평가가 이런 출력의 피해 위험을 줄이는 데 필수적.

더 알아보기 (Learn more)

동영상 이해는 텍스트·오디오·비전을 한 번에 다루는 Gemini의 강점이에요. 긴 동영상에는 에이전틱 처리 모드가 토큰을 크게 아끼고, 짧은 클립이나 프레임 정밀도가 필요하면 정적 모드가 어울려요. 미디어 해상도와 토큰 이해는 해당 가이드에서, 동영상 생성은 omni 가이드를 이어서 보면 좋아요.