Invitez et gagnez

Fonctionnement des récompenses

Partagez votre lien. Lorsqu’un ami s’inscrit avec ce lien et recharge son solde, vous recevez la récompense affichée sur ses recharges ultérieures.

Comment vérifier une vidéo après augmentation de la fréquence d’images dans Runway

Flux complet depuis la préparation et l’upload d’une vidéo locale jusqu’à enhance_frame_rate, au suivi de tâche, à la sauvegarde et aux contrôles FPS et audio.

Sommaire
Comment vérifier une vidéo après augmentation de la fréquence d’images dans Runway

Vous pouvez avoir une vidéo locale finalisée sans disposer encore de la sortie Runway à la nouvelle fréquence. Avant la recette, il faut préparer et téléverser le fichier, envoyer targetFramerate, attendre la tâche et enregistrer le résultat. Ce guide couvre toute cette chaîne REST, puis vérifie la cadence, les artefacts de mouvement, les coupes et la synchronisation audio.

Runway a ajouté enhance_frame_rate à Runway Dev le 17 septembre 2026. L’opération utilise le video upscale endpoint et accepte 24, 25, 30, 48, 50, 60, 120, 23_98 (23,98 fps), 29_97 (29,97 fps) et 59_94 (59,94 fps) ; chaque entrée est limitée à 300 secondes et la note de lancement indique 1 credit pour 2 secondes.

N’acceptez pas le résultat uniquement parce qu’il paraît plus fluide. Choisissez d’abord la cadence exacte exigée par la destination, puis contrôlez métadonnées, mouvements à risque, coupes et synchronisation au début, au milieu et à la fin, avant de tester sur la timeline et la plateforme réelles.

Choisissez d’abord la cadence de livraison ; arrêtez-vous sans spécification exacte

Choisissez la valeur exacte dans la timeline, les exigences du diffuseur, de la plateforme publicitaire ou du client avant tout envoi. 29_97 et 30, comme 59_94 et 60, semblent proches, mais une substitution incorrecte peut imposer un nouveau transcodage ou retraitement en long format, diffusion ou projet multi-source.

CibleMotif habituel du choixÀ confirmer avant livraison
23_98 / 24La timeline ou le client exige une cadence cinémaS’il faut exactement 23,98 plutôt que 24 entier
25 / 50Chaîne de production 25/50 fps ou norme régionaleTimeline, sous-titres, audio et autres plans utilisent la même cadence
29_97 / 30Le système de destination nomme explicitement l’une des deuxNe pas remplacer l’une par l’autre sans validation
59_94 / 60Contenu très mobile ou plateforme exigeant une fréquence élevéeUne lecture plus fluide ne restaure pas nécessairement les détails perdus
48 / 120Timeline particulière, ralenti ou livraison à fréquence élevéeÀ utiliser seulement si la destination l’exige ; plus élevé n’est pas toujours meilleur

Si le brief dit seulement « rendre la vidéo plus fluide », demandez la spécification finale. Sinon, vous pouvez produire un fichier valide à 60 fps qui ne convient toujours pas à une timeline de 59,94 fps.

Conservez la référence source pour retrouver l’origine d’un défaut

Notez la fréquence, la durée, le codec et les pistes audio de la source avant traitement. Sans cette référence, il devient difficile d’attribuer une piste manquante, une durée modifiée ou une fin figée à la source, à la sortie Runway ou à un transcodage ultérieur.

  1. Nom du fichier, durée, dimensions, codec et fréquence d’origine.
  2. Si la source est à fréquence constante (CFR) ou variable (VFR).
  3. Nombre de pistes audio, sample rate, canaux et durée approximative.
  4. Fréquence cible et origine de l’exigence, par exemple « le client exige 59_94 ».
  5. Trois à cinq timecodes à risque : panoramiques rapides, mains, lignes fines, bords d’occlusion, flashes, transitions, sous-titres ou UI.
  6. Au moins trois repères de synchronisation près du début, du milieu et de la fin.

Cette référence évite de réduire le contrôle à « c’est plus fluide » alors qu’un changement de durée, une piste manquante ou une incompatibilité de livraison passe inaperçu.

Vérifiez d’abord que la vidéo locale peut entrer dans ce flux

Contrôlez format, durée et taille avant l’appel API. Une entrée enhance_frame_rate ne peut pas dépasser 300 secondes, et un upload éphémère doit faire entre 512 octets et 200 MB. Privilégiez un conteneur et un codec pris en charge, par exemple MP4 avec H.264, H.265 ou AV1, et découpez les programmes plus longs sur des coupes naturelles.

Si la vidéo est déjà dans un stockage objet, son URL HTTPS peut être fournie directement dans videoUri. Elle doit utiliser un domaine et non une IP, accepter HEAD, retourner des en-têtes Content-Type et Content-Length corrects et ne pas dépendre de redirections ; la limite vidéo par URL est de 32 MB. Pour un master local classique, l’upload éphémère évite ces contraintes d’hébergement.

Vérifiez aussi que le compte possède des credits achetés. La note indique 1 credit pour 2 secondes, sans préciser l’arrondi des fractions ; conservez donc estimatedCost à l’envoi et le cost final de la tâche.

Utilisez ce script pour téléverser, envoyer, attendre et télécharger

Cet exemple REST garde toutes les étapes importantes visibles. Il demande la clé sans l’afficher, contrôle durée et taille, crée un upload éphémère, transfère le fichier, soumet la tâche, interroge toutes les cinq secondes et télécharge la sortie réussie.

Installez la dépendance Python et vérifiez que ffprobe est disponible :

python3 -m pip install requests

Enregistrez le code suivant dans 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()

Exemple pour convertir input.mp4 en 60 fps et enregistrer output-60fps.mp4 :

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

Saisissez la clé seulement lorsque RUNWAYML_API_SECRET: apparaît. Elle n’est ni affichée ni ajoutée à l’historique du shell, et le script ne l’écrit pas sur disque. Si la variable d’environnement existe déjà de façon sûre, elle est utilisée.

Comprenez les trois étapes API du script

La génération n’est terminée qu’après la réussite des trois étapes. Les noms sont sensibles à la casse : le JSON REST doit utiliser videoUri et targetFramerate.

ÉtapeRequêteContenu requisSignal de réussite
Initialiser l’uploadPOST https://api.dev.runwayml.com/v1/uploadsfilename, type: "ephemeral"Retour de uploadUrl, fields, runwayUri
Soumettre l’améliorationPOST https://api.dev.runwayml.com/v1/video_upscalemodel: "enhance_frame_rate", videoUri, targetFramerateRetour de l’id et de estimatedCost
Lire la tâcheGET https://api.dev.runwayml.com/v1/tasks/{id}ID dans le cheminstatus: "SUCCEEDED" et output non vide

Après l’initialisation, envoyez un POST multipart à uploadUrl, conservez toutes les valeurs de fields et joignez la vidéo sous le champ file. runwayUri n’est utilisable qu’après ce transfert réussi et reste valable 24 heures.

Téléchargez et conservez le résultat dès le succès

Continuez à attendre avec PENDING, THROTTLED ou RUNNING ; Runway indique de ne pas attendre plus d’une mise à jour de la même tâche en moins de cinq secondes. Ne lisez output[0] qu’avec SUCCEEDED. FAILED et CANCELLED sont des états terminaux en échec.

Les URLs de sortie expirent généralement sous 24–48 heures. Téléchargez aussitôt le fichier dans votre stockage persistant et ne livrez pas l’URL temporaire. Si elle a expiré, relisez d’abord la même tâche pour obtenir une nouvelle URL au lieu de payer immédiatement une nouvelle génération. Le téléchargement valide seulement l’exécution API ; les contrôles ci-dessous restent obligatoires.

Traitez chaque erreur selon sa catégorie

Si le POST multipart vers uploadUrl échoue, ne réutilisez pas cet upload signé : rappelez /v1/uploads. Pour 400, 401, 404 ou 405, corrigez entrée, clé, ressource ou méthode. Le script ne réessaie que 429, 502, 503 et 504 avec backoff exponentiel et jitter.

Quand la tâche est FAILED, conservez failure, failureCode et cost : ne réessayez pas SAFETY.* ; corrigez le média avant de renvoyer ASSET.INVALID ; examinez l’entrée avant INTERNAL.BAD_OUTPUT.* ; attendez avant de réessayer INPUT_PREPROCESSING.INTERNAL, INTERNAL, un code absent ou THIRD_PARTY.UNAVAILABLE. N’exécutez jamais la même requête en boucle infinie.

Étape 1 : utilisez ffprobe pour confirmer que le fichier atteint la cible

Utilisez ffprobe pour vérifier fréquence moyenne, time base, nombre réel d’images, durée et pistes audio avant de juger l’image. Une seule étiquette FPS dans le système ou le lecteur ne suffit pas à accepter le fichier.

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

Vérifiez que :

  • avg_frame_rate correspond à la cible ou à une représentation rationnelle équivalente.
  • r_frame_rate et avg_frame_rate ne sont pas en conflit inexpliqué ; un écart important nécessite une investigation VFR.
  • Pour un fichier proche du CFR, nb_read_frames est raisonnablement proche de la durée multipliée par le fps cible.
  • La durée de sortie correspond à la source, sans fin tronquée ni queue figée ajoutée.
  • Les dimensions, le codec et les pistes audio répondent à la spécification de livraison.
  • La durée audio ne diffère pas de manière inattendue de la durée vidéo.

Pour 29,97 et 59,94, les outils affichent souvent 30000/1001 et 60000/1001. Cette représentation fractionnaire n’est pas une erreur.

Étape 2 : contrôlez d’abord les plans les plus risqués

Commencez par les mouvements rapides, bords d’occlusion, petits textes et points de coupe, car ils révèlent vite les défauts d’interpolation. Contrôlez les scènes suivantes à 100 %, image par image ou au ralenti :

  • panoramiques rapides, travellings et objets rapides ;
  • mains, doigts, cheveux, montures de lunettes et lèvres ;
  • grilles, stores, maillages, petits textes et fines lignes d’UI ;
  • objets de premier plan qui traversent ou révèlent les bords du fond ;
  • eau, fumée, particules, feuilles et textures à haute fréquence ;
  • flashes, coupes franches, fondus et images autour d’un changement de plan.

Recherchez des défauts reproductibles plutôt qu’une impression vague de netteté : doubles contours, ghosting, bords tordus, objets disparaissant pendant une image, texture pulsante, membres déformés, images mélangées sur une coupe ou tremblement d’un texte statique.

Pour chaque problème, notez le timecode exact, la fréquence cible et les extraits source et résultat. Vous pourrez ainsi distinguer un défaut déjà présent d’un problème nouveau ou d’une différence de décodage.

Étape 3 : vérifiez la synchro au début, au milieu et à la fin

Une synchronisation correcte au début ne prouve pas que tout le fichier l’est ; vérifiez début, milieu et fin pour distinguer un décalage fixe d’une dérive progressive. Suivez cet ordre :

  1. Trouvez un repère clair au début : claquement, consonne occlusive, impact, atterrissage ou coupe visuelle.
  2. Répétez le contrôle au milieu et à la fin.
  3. Un décalage similaire aux trois endroits suggère un retard fixe.
  4. Une erreur qui augmente vers la fin indique plutôt un problème de durée, de time base ou d’interprétation de la fréquence.
  5. Pour le lip sync, contrôlez le début, le milieu et la fin d’une phrase continue, pas une seule syllabe.

La note de lancement ne décrit pas le traitement de l’audio. Ne supposez donc pas que la piste est toujours conservée à l’identique ou automatiquement synchronisée : jugez le fichier livré.

Étape 4 : retestez dans la timeline et la plateforme réelles

Testez toujours le fichier dans la timeline de montage et la plateforme finales, car un NLE ou un second transcodage peut réinterpréter la cadence, modifier la vitesse ou perdre une piste. Effectuez au moins ces deux contrôles :

  • Placez le fichier sur la timeline prévue et vérifiez que le NLE ne le réinterprète pas, ne modifie pas sa vitesse et ne perd pas de piste.
  • Testez-le sur la plateforme ou l’appareil final et vérifiez qu’un second transcodage n’a pas modifié cadence, sous-titres ou synchronisation.

Si la plateforme transcode de nouveau, conservez la sortie Runway et la version de la plateforme. Inspectez-les séparément avant d’attribuer un défaut au fichier amont.

Utilisez ce tableau pour accepter, retraiter ou conserver un segment source

Acceptez le fichier seulement si tous les points critiques respectent la spécification. Si un seul plan échoue, retraitez ce segment ou conservez la source avant de relancer tout le programme.

ContrôleCondition de réussiteAction en cas d’échec
Fréquence cibleCadence exacte ; 29,97/59,94 ne sont pas étiquetés 30/60Corriger la cible ou l’interprétation de la timeline
Durée et imagesDurée identique ; en CFR, nombre proche de l’estimationExaminer VFR, troncature, queue figée et time base
Dimensions et codecConformes à l’éditeur ou au canalRéencapsuler ou transcoder selon la spécification
Mouvement rapidePas de double image, déformation ou disparition inacceptableMarquer les timecodes ; essayer une autre cible ou conserver le plan source
Coupes et flashesPas d’images mélangées, répétées ou de clignotement anormalDécouper sur une coupe naturelle, retraiter et contrôler le raccord
Texte et UIGlyphes, lignes fines et overlays statiques restent stablesRéappliquer les éléments graphiques en postproduction
SynchronisationAucun décalage ni dérive visible au début, milieu et finComparer durées/time base, puis réaligner ou transcoder
IntégritéDécodage complet, fin intacte et toutes les pistes présentesRetélécharger, réencapsuler ou relancer la tâche

Ne passez pas de 60 à 120 fps dans ces cas

Restez à la fréquence la plus basse qui satisfait la livraison lorsque 120 fps n’ajoute que du volume et du traitement aval. N’augmentez pas la fréquence dans les cas suivants :

  • la destination ne demande que 24, 25, 29,97 ou 30 fps ;
  • la source contient déjà beaucoup de ghosting, de blocs de compression ou de motion blur ;
  • les sous-titres, l’UI ou les lignes fines deviennent moins stables ;
  • un problème de synchronisation reste inexpliqué ;
  • la plateforme finale imposera un transcodage à fréquence inférieure ;
  • aucun bénéfice visible n’apparaît, mais stockage, décodage ou transcodage aval augmentent.

La fréquence d’images est un paramètre de livraison, pas une note de qualité indépendante. Le critère est « respecte la cadence requise sans nouveau défaut inacceptable », pas « affiche le plus grand nombre ».

Terminez la livraison en dix étapes

L’ordre avec le moins de reprise est spécification et référence, upload et envoi, attente et stockage, puis validation technique, visuelle et réelle.

  1. Choisissez le targetFramerate exact selon la destination.
  2. Enregistrez cadence, durée, audio et timecodes à risque avec ffprobe, et confirmez un maximum de 300 secondes.
  3. Pour un fichier local, appelez POST /v1/uploads et conservez uploadUrl, fields, runwayUri.
  4. Envoyez le formulaire multipart à uploadUrl ; demandez un nouvel upload en cas d’échec.
  5. Appelez POST /v1/video_upscale avec model, videoUri, targetFramerate.
  6. Conservez l’id de tâche et estimatedCost.
  7. Appelez GET /v1/tasks/{id} toutes les cinq secondes jusqu’à un état terminal.
  8. Avec SUCCEEDED, téléchargez et stockez output ; traitez FAILED ou CANCELLED par type d’erreur.
  9. Vérifiez cadence réelle, durée, artefacts, coupes et audio avec ffprobe et un examen image par image.
  10. Testez dans la timeline et sur la plateforme réelles avant livraison.

Références officielles : Models, Inputs, Uploads, Video upscale API Reference, Task API Reference, Outputs, HTTP errors, Task failures et API Changelog. Champs et étapes vérifiés le 26 septembre 2026.

Prêt à optimiser votre workflow LLM ?

Connectez vos modèles via une API unique, gérez les clés et maîtrisez vos dépenses d’IA.

Commencer gratuitement