Seedance 2.5 is live — 30-second cinematic video with native audio & real-person references
Python으로 동영상 고화질화: 배치 API 파이프라인과 실제 비용
2026/08/14

Python으로 동영상 고화질화: 배치 API 파이프라인과 실제 비용

Python으로 대량 동영상을 고화질화하는 80줄 배치 파이프라인. 요청 제한 예산, 사전 견적, 크래시 안전 재개 기능으로 초당 $0.002부터 시작합니다.

Python으로 동영상 고화질화를 실제 규모로 진행할 때, 문제는 API 호출 자체가 아닙니다. 클립 한 개는 POST와 폴링 루프로 20줄이면 됩니다. 문제는 100개 버전입니다. 요청 제한을 지키면서 폴링하기, 전송 전에 청구액을 알기, 클립 61에서 떨어진 배치를 재개할 때 1~60번 클립의 중복 과금을 피하기입니다.

이 가이드는 reAPI의 동영상 강화 엔드포인트로 이런 파이프라인을 구축합니다. Topaz Video Upscaler는 표준 티어에서 초당 $0.044, enhance-video-1.0은 초당 $0.002054부터 시작합니다[1][2]. 아래의 모든 수치와 계약 세부 사항은 2026년 8월의 모델 공식 페이지에서 가져온 것입니다. 도구 비교 버전(오픈 소스, 데스크톱, API)을 찾으신다면 별도 가이드 동영상 고화질화 수단 비교를 참고하세요.

TL;DR

  • API 계약은 배치용으로 설계됐습니다: 비동기 제출은 태스크 ID를 즉시 반환하고, 과금은 서버 감지 원본 동영상 초 단위이며, 실패 시 자동 환불되어 배치 중단으로 인한 중복 과금이 없습니다[1].
  • 유일한 제약은 초당 5개 요청입니다(폴링 포함)[1]. 4개 워커가 2.5초마다 폴링하면 약 초당 1.6개 요청으로 예산의 3분의 1 미만이며 제출할 여유가 있습니다.
  • 전송 전에 견적을 냅니다: 1분 클립 100개는 Topaz 표준으로 $264, enhance-video-1.0 표준 1080p로 $24.64입니다[1][2]. 티어 선택은 코드 최적화보다 10배 더 가치 있습니다.
  • 제출 시 태스크 ID를 디스크에 저장합니다. 재개는 무료입니다: 완료된 태스크는 이미 결제되었고 출력 URL은 유효합니다.
  • 전체 파이프라인은 약 80줄, 표준 라이브러리 더하기 requests만 있으면 됩니다.

API가 제공하는 배치용 계약

설계 전체를 결정하는 3가지 계약 조건이 있습니다. 모두 모델 공식 리퍼런스에서 나온 것입니다[1]:

제출은 비동기입니다. POST /api/v1/videos/generations{"id", "status": "processing"}을 즉시 반환하고 렌더링은 서버 쪽에서 진행되며 당신은 GET /api/v1/tasks/<id>statuscompleted 또는 failed가 될 때까지 폴링합니다. 배치는 당신이 추적하는 열린 태스크들의 집합이지 기다리는 큐가 아닙니다.

과금은 원본 동영상을 따릅니다. 플랫폼은 호스팅된 원본 동영상의 길이를 서버에서 감지하고 그 초 단위로 과금합니다. Topaz 고화질화는 표준 초당 $0.044 또는 최고 $0.077, enhance-video 표준 티어는 대상 해상도에 따라 초당 $0.002054~$0.016429입니다[1][2]. 비용이 영상 시간의 순수 함수이기 때문에 아래의 견적이 작동합니다.

실패는 자동 환불됩니다. 크레딧은 제출 시 예약되고 태스크 실패 시 전액 환불됩니다[1]. 클라이언트는 보상 로직이 필요 없으며 실패를 기록하고 재제출할지 결정하기만 합니다.

전송 전에 청구액을 견적합니다

중요한 입력은 길이뿐입니다. 클립이 로컬이면 ffprobe로 한 번에 읽습니다. 이미 호스팅되어 있으면 자신의 메타데이터에서 길이를 가져옵니다.

import subprocess, json

def probe_seconds(path: str) -> float:
    out = subprocess.run(
        ["ffprobe", "-v", "quiet", "-print_format", "json",
         "-show_format", path],
        capture_output=True, text=True, check=True,
    )
    return float(json.loads(out.stdout)["format"]["duration"])

RATES = {                     # $ per second of source, August 2026
    "topaz-standard": 0.044,
    "topaz-max": 0.077,
    "enhance-720p": 0.002054,
    "enhance-1080p": 0.004107,
    "enhance-4k": 0.016429,
}

def estimate(paths, rate_key):
    total = sum(probe_seconds(p) for p in paths)
    return total, total * RATES[rate_key]

1분 클립 100개의 계산 예:

티어요금100 × 60 s
enhance-video-1.0, 표준 720p$0.002054/s$12.32[2]
enhance-video-1.0, 표준 1080p$0.004107/s$24.64[2]
enhance-video-1.0, 표준 4K$0.016429/s$98.57[2]
Topaz Video Upscaler, 표준$0.044/s$264.00[1]
Topaz Video Upscaler, 최고$0.077/s$462.00[1]

최저 행과 최고 행의 37배 차이가 실제 최적화 표면입니다. Python을 아무리 조정해도 티어 선택만큼 청구액이 달라지지 않습니다. 선택 로직은 충분히 간단해서 규칙으로 인코딩할 수 있습니다(깨끗한 원본이면 해상도 업스케일로 강화 티어, 손상된 원본이면 세부 복구용 Topaz).

Python 80줄 배치 파이프라인

설계: 맨 처음에 모든 것을 제출(제출은 싸고 빠름), 태스크 맵을 디스크에 즉시 저장, 작은 워커 풀로 폴링합니다. 상태는 원본 URL을 키로 하는 단일 JSON 파일에 있습니다.

import json, pathlib, time
from concurrent.futures import ThreadPoolExecutor
import requests

API = "https://reapi.ai/api/v1"
HEADERS = {"Authorization": "Bearer rk_live_..."}
STATE = pathlib.Path("batch_state.json")
POLL_INTERVAL = 2.5   # 4 workers / 2.5s ≈ 1.6 req/s, well under the 5/s cap
WORKERS = 4

def load_state():
    return json.loads(STATE.read_text()) if STATE.exists() else {}

def save_state(state):
    STATE.write_text(json.dumps(state, indent=2))

def submit(video_url, state):
    if video_url in state:          # already submitted on a previous run
        return
    r = requests.post(f"{API}/videos/generations", headers=HEADERS, json={
        "model": "topaz-video-upscaler",
        "video_url": video_url,
        "upscale_factor": "2",
    }, timeout=30)
    r.raise_for_status()
    state[video_url] = {"task_id": r.json()["id"], "status": "processing"}
    save_state(state)               # persist before moving on

def poll_one(video_url, entry):
    while True:
        r = requests.get(f"{API}/tasks/{entry['task_id']}", headers=HEADERS)
        body = r.json()
        if body["status"] in ("completed", "failed"):
            return video_url, body
        time.sleep(POLL_INTERVAL)

def run(video_urls):
    state = load_state()
    for url in video_urls:
        submit(url, state)
        time.sleep(0.25)            # submits: 4/s, inside the budget

    open_items = [
        (u, e) for u, e in state.items() if e["status"] == "processing"
    ]
    with ThreadPoolExecutor(max_workers=WORKERS) as pool:
        for url, body in pool.map(lambda p: poll_one(*p), open_items):
            state[url]["status"] = body["status"]
            if body["status"] == "completed":
                state[url]["output"] = body["output"]
            else:
                state[url]["error"] = body.get("error")
            save_state(state)

    done = sum(1 for e in state.values() if e["status"] == "completed")
    failed = [u for u, e in state.items() if e["status"] == "failed"]
    print(f"{done} completed, {len(failed)} failed")
    for u in failed:
        print("FAILED:", u, state[u].get("error"))

run([
    "https://your-cdn.com/clip-001.mp4",
    "https://your-cdn.com/clip-002.mp4",
])

enhance-video-1.0 페이로드로 바꾸면 (upscale_factor 대신 tool_version, scene, resolution 사용) 다른 것은 변하지 않습니다[2]. 원본 URL은 공개 HTTPS 필수이며 base64 업로드는 플랫폼 전체에서 거부됩니다.

요청 제한 예산을 명시적으로 표시

플랫폼은 각 사용자를 초당 5개 요청으로 제한하며 폴링을 포함합니다[1]. 파이프라인의 사용량:

  • 제출: 제출 단계 중 초당 4개로 스로틀됨(단계는 짧음).
  • 폴링: 4개 워커 × 2.5초당 1개 요청 = 정상 상태에서 초당 1.6개 요청.
  • 여유: 초당 약 3.4개 요청 남음(다른 스크립트, 대시보드 또는 수동 curl 점검용).

WORKERS를 12로 올리되 2.5초 간격 유지하면 폴링만 초당 4.8개 요청이 되어 다른 것이 API를 건드리면 429 에러가 시작됩니다. 워커 증가는 렌더링 속도를 높이지 않습니다. 렌더링은 서버 쪽입니다. 워커는 완료 감지만 빠르게 하고 2.5초 지연은 비용이 없습니다.

중복 과금 없이 실패 처리

플랫폼의 실패 계약이 무거운 것을 들어올립니다: 실패한 태스크는 예약 크레딧을 자동 전액 환불합니다[1]. 파이프라인의 작업은 간부 기록으로 줄어듭니다:

  1. 실패를 기록합니다. 에러 객체(code, message, request_id 포함)와 함께(에러 코드 참조는 API 문서에 있습니다[3]).
  2. 무작정 재제출하지 마세요. 원본 URL이 404인 클립은 같은 비용(0)으로 다시 실패합니다. 그러나 재시도 폭주는 요청 예산을 태웁니다. 입력을 고쳐서 스크립트를 다시 실행하세요. 상태 파일은 완료된 것을 건너뜁니다.
  3. 재개를 신뢰하세요. 완료된 항목은 출력 URL을 유지합니다. CDN 재호스트 파일을 가리키며 만료되지 않습니다[1]. 클립 61에서 중단된 배치는 60개의 지불된 결과를 그대로 재개하고 나머지만 미결입니다.

FAQ

Python으로 동영상 고화질화를 무료로 할 수 있나요?

호스팅된 API로는 불가능합니다. 렌더링은 누군가의 GPU 시간입니다. 무료 경로는 자신의 GPU에서 video2x나 Real-ESRGAN 같은 오픈소스 고화질화 도구를 실행하는 것입니다. 하드웨어와 수고를 돈으로 교환합니다(도구 비교에서 다룹니다). API 경로는 원본 초당 $0.002054부터 시작하며 가입 크레딧이 처음 테스트를 지원합니다[2].

병렬로 몇 개 클립을 처리할 수 있나요?

원하는 만큼 제출하세요. 제약은 요청 속도이지 열린 태스크 수가 아닙니다. 총 요청 처리량(제출 + 폴링)을 초당 5개 미만으로 유지하세요[1]. 4개 폴링 워커가 2.5초 간격은 편안한 정상 상태입니다.

100개 동영상 처리 비용은 얼마인가요?

길이에 따라 결정됩니다. 클립당 1분: $12.32(enhance-video 720p)부터 $462(Topaz 최고)까지입니다[1][2]. 실제 길이로 견적을 실행한 후 제출하세요. 4줄의 ffprobe입니다.

스크립트 충돌 후 배치를 재개할 수 있나요?

태스크 ID가 제출 시 저장되었다면 예. 완료된 태스크는 완료 상태를 유지하고 지불되었으며 출력 URL은 유효합니다. 실패한 태스크는 이미 환불되었습니다[1]. 위의 상태 파일 패턴은 재개를 복구 기능이 아닌 기본 동작으로 만듭니다.

배치 작업에서 4K로 고화질화해야 하나요?

출력 화면이 요구할 때만. 4K 티어는 enhance-video에서 720p 티어의 8배 비용입니다[2]. 소셜 피드는 어차피 재압축합니다. 일반적인 패턴은 모든 것을 1080p로 일괄 처리하고 히로 클립 몇 개만 4K로 재실행하는 것입니다.

플랫폼이 과금할 원본 길이를 어떻게 아나요?

플랫폼은 호스팅 파일을 서버에서 감지하고 실제 길이로 과금합니다[1]. 같은 파일에서 로컬 ffprobe는 같은 숫자를 줍니다. 차이는 호스팅 버전이 로컬 버전과 다르다는 뜻으로 100개 제출 전에 잡을 가치가 있습니다.

첫 배치를 실행합니다

100개가 아니라 3개로 시작하세요: 깨끗한 것 1개, 손상된 것 1개, 긴 것 1개. 그 실행은 상태 파일을 검증하고 클립당 실제 비용 대 견적을 표시하며 제출 전 입력 문제를 드러냅니다. 그 후 스크립트를 전체 목록으로 향하게 하고 환불 계약과 상태 파일이 무엇이든 흡수하도록 놔두세요. Python으로 하는 요점은 Python으로 두 번째 실행, 명령은 단순히 스크립트를 다시 실행하는 것이고 두 번째 실행은 첫 번째가 완료하지 못한 부분만 지불한다는 것입니다.

References

  1. reAPI. Topaz Video Upscaler — model page: live pricing, task lifecycle, rate limits. Retrieved August 2026 from reapi.ai/models/topaz-video-upscaler
  2. reAPI. Enhance Video 1.0 — model page: live per-second tier pricing. Retrieved August 2026 from reapi.ai/models/enhance-video-1-0
  3. reAPI. API error codes reference. Retrieved August 2026 from reapi.ai/docs/api/errors

Further reading