Invita y gana

Cómo funcionan las recompensas

Comparte tu enlace. Cuando un amigo se registre con él y recargue saldo, recibirás la recompensa indicada por sus recargas posteriores.

Cómo verificar un video tras aumentar la tasa de fotogramas en Runway

Flujo completo desde preparar y subir un video local hasta enviar enhance_frame_rate, consultar la tarea, guardar la salida y verificar FPS, artefactos y audio.

Índice
Cómo verificar un video tras aumentar la tasa de fotogramas en Runway

Puede que tengas un video local terminado, pero todavía no una salida de Runway con la nueva tasa de fotogramas. Antes de verificar la entrega debes preparar y subir el archivo, enviar targetFramerate, esperar la tarea y guardar el resultado. Esta guía cubre todo ese flujo REST y después comprueba FPS, artefactos de movimiento, cortes y sincronía de audio.

Runway incorporó enhance_frame_rate a Runway Dev el 17 de septiembre de 2026. La operación utiliza el video upscale endpoint y acepta 24, 25, 30, 48, 50, 60, 120, 23_98 (23,98 fps), 29_97 (29,97 fps) y 59_94 (59,94 fps); cada entrada está limitada a 300 segundos y la nota de lanzamiento indica 1 credit por cada 2 segundos.

No apruebes el resultado solo porque se ve más fluido. Elige primero la cadencia exacta del destino, después revisa metadatos, movimientos de riesgo, cortes y sincronía al principio, en el centro y al final, y termina probando el archivo en la línea de tiempo y plataforma reales.

Elige primero la cadencia de entrega; detente si no hay una especificación exacta

Elige el valor exacto de la línea de tiempo, el broadcaster, la plataforma publicitaria o la especificación del cliente antes de enviar nada. 29_97 y 30, igual que 59_94 y 60, parecen casi iguales, pero una sustitución incorrecta puede obligarte a transcodificar de nuevo o repetir el proceso en trabajos largos, broadcast y proyectos con fuentes mixtas.

ObjetivoMotivo habitual para elegirloConfirma antes de entregar
23_98 / 24La línea de tiempo o el cliente exige una cadencia cinematográficaSi se requiere exactamente 23,98 y no 24 entero
25 / 50Flujo de producción a 25/50 fps o especificación regionalQue línea de tiempo, subtítulos, audio y demás material usen la misma cadencia
29_97 / 30El sistema de destino nombra explícitamente uno de los dosNo sustituir uno por otro sin aprobación
59_94 / 60Contenido con mucho movimiento o una plataforma que pide alta tasaUna reproducción más fluida no significa recuperar detalle perdido
48 / 120Línea de tiempo específica, cámara lenta o entrega de alta tasaUsarlo solo si el destino lo exige; un número mayor no es siempre mejor

Si el encargo solo dice “hazlo más fluido”, pide la especificación final. De lo contrario, puedes crear un archivo válido a 60 fps que no encaje correctamente en una línea de tiempo de 59,94 fps.

Guarda la línea base para poder localizar cualquier fallo

Registra antes del proceso la tasa, duración, códec y pistas de audio del original. Sin esa referencia será difícil saber si una pista perdida, una duración distinta o una cola congelada provienen del original, de la salida de Runway o de una transcodificación posterior.

  1. Nombre del archivo, duración, dimensiones, códec y tasa original.
  2. Si la fuente usa tasa constante (CFR) o variable (VFR).
  3. Número de pistas de audio, sample rate, canales y duración aproximada.
  4. Tasa objetivo y origen del requisito, por ejemplo: “el cliente exige 59_94”.
  5. De tres a cinco timecodes de riesgo: paneos rápidos, manos, líneas finas, bordes de oclusión, destellos, transiciones, subtítulos o UI.
  6. Al menos tres anclas de sincronización cerca del inicio, centro y final.

Esta línea base evita que la revisión se reduzca a “se ve más fluido” mientras pasan inadvertidos un cambio de duración, una pista perdida o una incompatibilidad de entrega.

Confirma primero que el video local puede entrar en el flujo

Comprueba formato, duración y tamaño antes de llamar a la API. Una entrada de enhance_frame_rate no puede superar 300 segundos y una carga efímera debe ocupar entre 512 bytes y 200 MB. Prioriza contenedores y códecs compatibles, como MP4 con H.264, H.265 o AV1, y divide una pieza más larga en cortes naturales.

Si el video ya está en almacenamiento de objetos, puedes pasar su URL HTTPS directamente como videoUri. La URL debe usar un dominio, no una IP, admitir HEAD, devolver Content-Type y Content-Length válidos y no depender de redirecciones; el límite de video por URL es 32 MB. Para un máster local normal, la carga efímera evita esos requisitos de alojamiento.

Confirma también que la cuenta tenga credits comprados. La nota de lanzamiento indica 1 credit por 2 segundos, pero no explica el redondeo de fracciones, por lo que conviene guardar estimatedCost al enviar y el cost final de la tarea.

Usa este script para subir, enviar, esperar y descargar

El ejemplo usa REST y deja visibles todos los pasos críticos. Solicita la API Key sin mostrarla, valida duración y tamaño, crea una carga efímera, transfiere el archivo, envía la tarea, consulta cada cinco segundos y descarga la salida correcta.

Instala la dependencia de Python y comprueba que ffprobe esté disponible:

python3 -m pip install requests

Guarda lo siguiente como runway_fps.py:

from __future__ import annotations

import getpass, json, os, random, subprocess, sys, time
from pathlib import Path
import requests

API = "https://api.dev.runwayml.com"
FPS = {"24", "25", "30", "48", "50", "60", "120", "23_98", "29_97", "59_94"}
RETRYABLE = {429, 502, 503, 504}


def api(session, method, path, body=None):
    for attempt in range(6):
        response = session.request(method, API + path, json=body, timeout=60)
        if response.status_code < 400:
            return response
        if response.status_code in RETRYABLE and attempt < 5:
            time.sleep((2**attempt) * (1 + random.random() * 0.5))
            continue
        raise RuntimeError(f"HTTP {response.status_code}: {response.text}")
    raise RuntimeError("RETRY_LIMIT_REACHED")


def main():
    if len(sys.argv) not in {3, 4}:
        raise SystemExit("python runway_fps.py INPUT_VIDEO TARGET_FPS [OUTPUT_VIDEO]")

    source = Path(sys.argv[1])
    target = sys.argv[2]
    output = Path(sys.argv[3]) if len(sys.argv) == 4 else Path(f"runway-{target}fps.mp4")

    if target not in FPS:
        raise SystemExit(f"UNSUPPORTED_TARGET_FRAMERATE: {target}")
    if not source.is_file():
        raise SystemExit(f"INPUT_NOT_FOUND: {source}")
    if not 512 <= source.stat().st_size <= 200 * 1024 * 1024:
        raise SystemExit(f"INVALID_UPLOAD_SIZE_BYTES: {source.stat().st_size}")

    duration = float(subprocess.run(
        ["ffprobe", "-v", "error", "-show_entries", "format=duration",
         "-of", "default=noprint_wrappers=1:nokey=1", str(source)],
        check=True, capture_output=True, text=True,
    ).stdout.strip())
    if not 0 < duration <= 300:
        raise SystemExit(f"INVALID_DURATION_SECONDS: {duration}")

    key = os.getenv("RUNWAYML_API_SECRET") or getpass.getpass("RUNWAYML_API_SECRET: ")
    session = requests.Session()
    session.headers.update({
        "Authorization": f"Bearer {key}",
        "X-Runway-Version": "2024-11-06",
        "Content-Type": "application/json",
    })

    upload_init = api(session, "POST", "/v1/uploads", {
        "filename": source.name,
        "type": "ephemeral",
    }).json()
    with source.open("rb") as handle:
        upload = requests.post(
            upload_init["uploadUrl"],
            data=upload_init["fields"],
            files={"file": (source.name, handle)},
            timeout=300,
        )
    if upload.status_code >= 400:
        raise RuntimeError(
            f"UPLOAD_FAILED_REQUEST_NEW_UPLOAD: HTTP {upload.status_code}: {upload.text}"
        )

    created = api(session, "POST", "/v1/video_upscale", {
        "model": "enhance_frame_rate",
        "videoUri": upload_init["runwayUri"],
        "targetFramerate": target,
    }).json()
    task_id = created["id"]
    print(json.dumps({"id": task_id, "estimatedCost": created.get("estimatedCost")}, indent=2))

    while True:
        task = api(session, "GET", f"/v1/tasks/{task_id}").json()
        status = task["status"]
        if status in {"PENDING", "THROTTLED", "RUNNING"}:
            time.sleep(5)
            continue
        if status == "SUCCEEDED":
            urls = task.get("output") or []
            if not urls:
                raise RuntimeError("SUCCEEDED_WITHOUT_OUTPUT")
            with requests.get(urls[0], stream=True, timeout=300) as download:
                download.raise_for_status()
                with output.open("wb") as saved:
                    for chunk in download.iter_content(1024 * 1024):
                        if chunk:
                            saved.write(chunk)
            break
        if status == "FAILED":
            raise RuntimeError(json.dumps({
                "status": status,
                "failure": task.get("failure"),
                "failureCode": task.get("failureCode"),
                "cost": task.get("cost"),
            }, ensure_ascii=False))
        if status == "CANCELLED":
            raise RuntimeError(json.dumps({"status": status, "cost": task.get("cost")}))
        raise RuntimeError(f"UNKNOWN_TASK_STATUS: {status}")

    subprocess.run([
        "ffprobe", "-v", "error", "-show_entries",
        "stream=codec_name,width,height,r_frame_rate,avg_frame_rate,time_base,duration:format=duration",
        "-of", "json", str(output),
    ], check=True)
    print(output.resolve())


if __name__ == "__main__":
    main()

Ejemplo para convertir input.mp4 a 60 fps y guardar output-60fps.mp4:

python3 runway_fps.py input.mp4 60 output-60fps.mp4

Introduce la clave solo cuando aparezca RUNWAYML_API_SECRET:. El valor no se muestra ni entra en el historial del shell, y el script no lo escribe en disco. Si la variable de entorno ya está configurada de forma segura, se usa directamente.

Entiende las tres etapas de API del script

La generación solo termina cuando las tres etapas tienen éxito. Los nombres distinguen mayúsculas y minúsculas: el JSON REST debe usar videoUri y targetFramerate.

EtapaSolicitudContenido obligatorioSeñal de éxito
Inicializar cargaPOST https://api.dev.runwayml.com/v1/uploadsfilename, type: "ephemeral"Devuelve uploadUrl, fields, runwayUri
Enviar mejoraPOST https://api.dev.runwayml.com/v1/video_upscalemodel: "enhance_frame_rate", videoUri, targetFramerateDevuelve id y estimatedCost
Consultar tareaGET https://api.dev.runwayml.com/v1/tasks/{id}ID en la rutastatus: "SUCCEEDED" y output no vacío

Después de inicializar, envía un POST multipart a uploadUrl, conserva todos los valores de fields y adjunta el video con el nombre de campo file. runwayUri solo queda listo después de esa transferencia; caduca a las 24 horas.

Descarga y guarda el resultado en cuanto tenga éxito

Sigue esperando con PENDING, THROTTLED o RUNNING; Runway indica que no debe esperarse más de una actualización de la misma tarea cada cinco segundos. Lee output[0] solo con SUCCEEDED. FAILED y CANCELLED son estados terminales no válidos.

Las URLs de salida suelen caducar en 24–48 horas. Descarga el archivo enseguida a almacenamiento persistente y no entregues la URL temporal al usuario final. Si caduca, vuelve a consultar la misma tarea para obtener otra URL antes de pagar por una nueva generación. Descargar correctamente solo confirma el trabajo de API; aún faltan las comprobaciones siguientes.

Trata cada fallo según su tipo

Si falla el POST multipart a uploadUrl, no reutilices esa carga firmada: vuelve a llamar a /v1/uploads. Para 400, 401, 404 o 405, corrige entrada, clave, recurso o método. El script solo reintenta 429, 502, 503 y 504 con espera exponencial y jitter.

Cuando la tarea esté FAILED, guarda failure, failureCode y cost: no reintentes SAFETY.*; corrige el medio antes de reenviar ASSET.INVALID; revisa la entrada antes de repetir INTERNAL.BAD_OUTPUT.*; espera antes de reintentar INPUT_PREPROCESSING.INTERNAL, INTERNAL, un código ausente o THIRD_PARTY.UNAVAILABLE. No repitas indefinidamente la misma solicitud.

Paso 1: usa ffprobe para confirmar que el archivo cumple el objetivo

Usa ffprobe para verificar tasa media, time base, recuento real, duración y pistas de audio antes de juzgar la imagen. Una sola etiqueta FPS del sistema operativo o del reproductor no basta para aceptar el archivo.

ffprobe -v error -select_streams v:0 \
  -show_entries stream=codec_name,width,height,r_frame_rate,avg_frame_rate,time_base,duration \
  -of json output.mp4
ffprobe -v error -select_streams v:0 -count_frames \
  -show_entries stream=nb_read_frames,avg_frame_rate,r_frame_rate,duration \
  -of json output.mp4
ffprobe -v error \
  -show_entries format=duration:stream=index,codec_type,codec_name,sample_rate,channels,duration \
  -of json output.mp4

Comprueba:

  • avg_frame_rate coincide con el objetivo o con una representación racional equivalente.
  • r_frame_rate y avg_frame_rate no presentan un conflicto sin explicación; una diferencia grande requiere investigar VFR.
  • En un archivo cercano a CFR, nb_read_frames se aproxima a duración multiplicada por fps objetivo.
  • La duración de salida coincide con la fuente, sin recorte al final ni cola congelada añadida.
  • Dimensiones, códec y pistas de audio cumplen la especificación de entrega.
  • La duración del audio no difiere de forma inesperada de la del video.

Para 29,97 y 59,94, es normal ver fracciones como 30000/1001 y 60000/1001. La representación fraccionaria no es un fallo.

Paso 2: revisa primero los planos con mayor riesgo

Empieza por movimiento rápido, bordes de oclusión, texto fino y puntos de corte, porque ahí aparecen antes los fallos de interpolación. Revisa lo siguiente al 100 %, fotograma a fotograma o a velocidad reducida:

  • paneos, seguimientos y objetos rápidos;
  • manos, dedos, pelo, monturas de gafas y labios;
  • rejas, persianas, cuadrículas, texto pequeño y líneas finas de UI;
  • objetos en primer plano que cruzan o descubren bordes del fondo;
  • agua, humo, partículas, hojas y texturas de alta frecuencia;
  • destellos, cortes duros, disolvencias y fotogramas alrededor de un cambio de plano.

Busca defectos reproducibles, no una impresión vaga de nitidez: contornos dobles, ghosting, bordes deformados, objetos que desaparecen durante un fotograma, textura pulsante, extremidades deformadas, fotogramas mezclados en un corte o vibración de texto estático.

Cuando encuentres un problema, registra el timecode exacto, la tasa objetivo y los fragmentos de origen y salida. Así podrás separar un defecto preexistente de uno nuevo o de una diferencia del decodificador.

Paso 3: comprueba la sincronía al principio, en el centro y al final

Que el principio esté sincronizado no demuestra que toda la pieza lo esté; revisa principio, centro y final para distinguir un desplazamiento fijo de una deriva progresiva. Sigue este orden:

  1. Busca una ancla clara al principio: una palmada, una consonante explosiva, un impacto, un aterrizaje o un corte visual.
  2. Repite la comprobación en el centro y al final.
  3. Un desplazamiento similar en los tres puntos sugiere un retraso fijo.
  4. Un error que crece hacia el final apunta a duración, time base o interpretación de la tasa.
  5. Para lip sync, revisa principio, centro y final de una frase continua, no una sola sílaba.

La nota de lanzamiento no describe el tratamiento del audio. No supongas que la pista siempre se conserva sin cambios ni que queda sincronizada automáticamente: evalúa el archivo entregado.

Paso 4: vuelve a probar en la línea de tiempo y plataforma reales

Prueba siempre el archivo en la línea de tiempo y plataforma finales, porque un NLE o una segunda transcodificación pueden reinterpretar la cadencia, cambiar la velocidad o perder una pista. Haz al menos estas dos comprobaciones:

  • Colócalo en la línea de tiempo prevista y confirma que el NLE no lo reinterpreta, cambia su velocidad ni pierde una pista.
  • Pruébalo en la plataforma o dispositivo final y confirma que una segunda transcodificación no altera cadencia, subtítulos o sincronía.

Si la plataforma vuelve a transcodificar, conserva tanto la salida de Runway como la versión de la plataforma. Inspecciónalas por separado antes de atribuir el problema al archivo anterior.

Usa esta tabla para aprobar, rehacer o conservar un fragmento original

Aprueba el archivo solo cuando todos los puntos críticos cumplan la especificación. Si falla un solo plano, rehace ese segmento o conserva el original antes de volver a procesar toda la pieza.

ComprobaciónCondición de aprobadoAcción si falla
Tasa objetivoCadencia exacta; 29,97/59,94 no se etiquetan como 30/60Corregir el objetivo o la interpretación de la línea de tiempo
Duración y fotogramasDuración igual a la fuente; en CFR el recuento se acerca al esperadoInvestigar VFR, truncado, cola congelada y time base
Dimensiones y códecCumplen los requisitos del editor o canalReempaquetar o transcodificar según la especificación
Movimiento rápidoSin dobles imágenes, deformación o desapariciones inaceptablesMarcar timecodes; probar otro objetivo o conservar el fragmento original
Cortes y destellosSin fotogramas mezclados, repetidos ni parpadeos anómalosDividir en un corte natural, reprocesar y revisar la unión
Texto y UIGlifos, líneas finas y overlays estáticos permanecen establesVolver a aplicar los gráficos en posproducción
Sincronía de audioSin desplazamiento ni deriva visibles en inicio, centro y finalComparar duraciones/time base y después realinear o transcodificar
IntegridadDecodificación completa, final intacto y todas las pistas presentesDescargar de nuevo, reempaquetar o repetir la tarea

No pases de 60 a 120 fps en estos casos

Quédate en la tasa más baja que cumpla la entrega cuando 120 fps solo añada tamaño y trabajo posterior. No aumentes la tasa en los siguientes casos:

  • el destino solo exige 24, 25, 29,97 o 30 fps;
  • la fuente ya tiene ghosting, bloques de compresión o motion blur fuertes;
  • subtítulos, UI o líneas finas se vuelven menos estables;
  • todavía no se ha explicado un problema de sincronía;
  • la plataforma final forzará una transcodificación a menor tasa;
  • no hay beneficio visible, pero aumentan almacenamiento, decodificación o transcodificación posterior.

La tasa de fotogramas es un parámetro de entrega, no una puntuación de calidad aislada. El criterio es “cumple la cadencia requerida sin defectos nuevos inaceptables”, no “tiene el número más alto”.

Completa la entrega en diez pasos

El orden con menos retrabajo es especificación y referencia, carga y envío, espera y almacenamiento, y después revisión técnica, visual y real.

  1. Elige el targetFramerate exacto según el destino.
  2. Guarda tasa, duración, audio y timecodes de riesgo con ffprobe; confirma un máximo de 300 segundos.
  3. Para un archivo local, llama a POST /v1/uploads y conserva uploadUrl, fields, runwayUri.
  4. Envía el formulario multipart a uploadUrl; pide una carga nueva si falla.
  5. Llama a POST /v1/video_upscale con model, videoUri, targetFramerate.
  6. Guarda el id de tarea y estimatedCost.
  7. Consulta GET /v1/tasks/{id} cada cinco segundos hasta un estado terminal.
  8. Con SUCCEEDED, descarga y conserva output; trata FAILED o CANCELLED por tipo de error.
  9. Verifica cadencia real, duración, artefactos, cortes y audio con ffprobe y revisión fotograma a fotograma.
  10. Prueba en la línea de tiempo y plataforma finales antes de entregar.

Referencias oficiales: Models, Inputs, Uploads, Video upscale API Reference, Task API Reference, Outputs, HTTP errors, Task failures y API Changelog. Campos y pasos verificados el 26 de septiembre de 2026.

¿Quieres optimizar tu flujo de trabajo con LLM?

Conecta modelos mediante una API, gestiona claves y controla el gasto en IA.

Empezar gratis