Seguir un job y obtener sus resultados
GET /v1/jobs/{id}Mientras el job corre, el progreso se actualiza en cada petición. En vez de consultar una y otra vez, escucha los webhooks: job.succeeded, job.failed y job.canceled traen el job tal como lo muestra esta petición.
queued → processing → succeeded | failed | canceled
Un job espera en queued mientras tu organización ya tiene en marcha tantos jobs como permite su plan (max_concurrent_jobs); empieza en cuanto uno termina. progress (0–100) es el del job entero.
tasks lista todo lo que se está produciendo, cada cosa con su status (pending, running, done, stopped), progress (0–100, o null mientras corre sin un porcentaje medible) y tiempos:
type |
|
|---|---|
import |
La copia desde input.url, con bytes y total_bytes. |
upload |
Una subida progresiva que va llegando, con bytes y total_bytes. |
analysis |
La lectura de la fuente. |
video |
Una por calidad (resolution). Las calidades avanzan juntas, porque se codifican de los mismos fotogramas. |
audio |
Una por idioma: track, language, name y mode: copy (se reutiliza el audio de la fuente, sin pérdida) o encode. |
subtitles |
count pistas. |
mp4, mp3, poster, storyboard |
Cada entregable. |
streaming |
Los manifiestos HLS y DASH (formats). |
Tiempos
Sección titulada «Tiempos»| Campo | |
|---|---|
queued_seconds |
La espera por hueco en tu plan. |
import_seconds |
La copia desde input.url, si el job tenía una. |
processing_seconds |
Desde el inicio del análisis hasta que los resultados están listos, sin la cola ni la subida. Si el video se procesó mientras llegaba, cuenta desde el final de la subida o la copia: es la espera una vez está el archivo. |
speed |
Segundos de video por segundo de proceso: 33,5 es 33,5× tiempo real. |
stages |
analysis_seconds, encoding_seconds, assembly_seconds. |
timeline |
Cuándo empezó y terminó cada etapa (created_at, dispatched_at, import_started_at, imported_at, analysis_started_at, analyzed_at, encoded_at, completed_at), para dibujarlas en un mismo eje. |
Resultados
Sección titulada «Resultados»"outputs": { "streaming": { "hls_url": "https://…/master.m3u8", "dash_url": "https://…/manifest.mpd", "variants": [{ "resolution": "1080p", "width": 1920, "height": 1080, "size_bytes": 612345678 }], "size_bytes": 640123456, "audio_size_bytes": 27000000 }, "mp4": [{ "resolution": "720p", "width": 1280, "height": 720, "url": "https://…", "size_bytes": 301234567 }], "mp3": { "url": "https://…", "size_bytes": 57600000 }, "posters": [{ "url": "https://…", "size_bytes": 84512 }], "storyboard": { "image_url": "https://…/sprite-1-000.jpg", "image_urls": ["…"], "vtt_url": "https://…/storyboard.vtt", "size_bytes": 1203344 }, "audio_tracks": [{ "language": "spa", "name": "Español", "default": true }], "subtitles": [{ "language": "spa", "name": "Español (forzados)", "forced": true, "url": "https://…/subtitles-0.vtt" }], "quality": { "metric": "vmaf", "model": "vmaf_v0.6.1", "sampled_seconds": 96, "variants": [{ "resolution": "1080p", "vmaf": 95.8, "vmaf_min": 93.1 }] }, "total_size_bytes": 999123456, "source_size_bytes": 4812345678}width y height son lo que salió, tras fit y la rotación. Un storyboard largo se divide en varias imágenes (hojas de 10 filas); image_url es la primera, image_urls todas, y el WebVTT asocia cada momento a su miniatura.
Tamaños
Sección titulada «Tamaños»Cada resultado tiene size_bytes, lo que pesa publicado. En streaming, size_bytes es la carpeta entera: HLS y DASH comparten segmentos, así que cuentan una vez; el de cada variante es su video, y audio_size_bytes es el audio que comparten todas. total_size_bytes es todo lo publicado del job; source_size_bytes, la fuente.
Calidad (VMAF)
Sección titulada «Calidad (VMAF)»Con quality_metrics: true, outputs.quality puntúa cómo se ve cada variante frente a la fuente, de 0 a 100, en muestras repartidas por el video (el video entero si es corto): vmaf es la media de las muestras y vmaf_min, la más débil. Desde 93 aproximadamente la diferencia apenas se ve; 80–93 es buena; por debajo de 60, pobre. Se compara a 1080p (o al tamaño de la fuente, si es menor) con el modelo estándar vmaf_v0.6.1. Las variantes con marca de agua no se puntúan, porque la marca contaría como defecto. Sin quality_metrics vale null.
Otros campos
Sección titulada «Otros campos»source: qué es la fuente (duración, tamaño, frecuencia de fotogramas, bitrate, códecs,audio_tracks,subtitle_tracks).adjustments: correcciones aplicadas para que los resultados se reproduzcan en todas partes:deinterlaced,frame_rate_normalizedyframe_rate_capped(confromyto),rotation_applied(degrees),anamorphic_corrected,hdr_tone_mapped.skipped: calidades omitidas por ser mayores que la fuente (on_upscale: "skip").skipped_tracks: pistas pedidas que no salieron:not_found(una opcional),image_subtitles,too_many.request: los ajustes con los que se creó el job, con los valores por defecto aplicados: de ahí parte un reintento.billed_minutes: los minutos facturados del job por categoría, cuando terminó bien (solo enGET /v1/jobs/{id}).
Cuando un job falla
Sección titulada «Cuando un job falla»error dice de quién es el problema y si volver a intentarlo puede servir:
"error": { "code": "unreadable_source", "category": "source", "retryable": false, "message": "…" }code |
category |
retryable |
Qué pasó, qué hacer |
|---|---|---|---|
unsupported_source |
source |
no | El archivo no puede dar lo pedido: sin audio y se pidió MP3, menor que una calidad con on_upscale: "fail", una pista obligatoria que no existe, un video no admitido. Cambia la petición o el archivo. |
unreadable_source |
source |
no | El archivo está dañado, incompleto (un MP4 sin su índice, cortado a mitad de subida) o no es audio ni video. Súbelo de nuevo, completo. |
source_import_failed |
source |
sí | No se pudo copiar desde input.url (HTTP 4xx o 5xx, tiempo agotado, demasiado grande…). Revisa la URL y reintenta. |
upload_incomplete |
source |
no | Una subida progresiva dejó de llegar durante 30 minutos. Sube el archivo de nuevo. |
validation_error |
request |
no | Los ajustes no sirven para este archivo (una marca de agua que no se puede descargar, por ejemplo). Corrígelos. |
timeout, launch_failed |
internal |
sí | Nuestro y pasajero: reintenta. |
processing_error |
internal |
no | Nuestro: ya lo estamos revisando. El mensaje es genérico a propósito. |
Los fallos momentáneos (red, capacidad) se reintentan dentro del job y nunca llegan a failed.
Reintentar, cancelar, borrar
Sección titulada «Reintentar, cancelar, borrar»POST /v1/jobs/{id}/retryPOST /v1/jobs/{id}/cancelDELETE /v1/jobs/{id}- Reintentar crea un job nuevo desde la misma fuente (sin subirla otra vez) con los mismos ajustes, salvo los que vengan en el cuerpo:
outputs,audio,subtitles,on_upscale,quality_metrics,webhook_url,metadataeinput.clip(nullpara el video entero). También sirve para hacer una variación de un job terminado. Elretry_ofdel job nuevo apunta al original. Las fuentes se guardan 7 días: después, una traída de una URL se copia de nuevo desde ella, y una subida responde409(súbela de nuevo). - Cancelar detiene un job en cola o en marcha.
- Borrar elimina los archivos de un job terminado. El job sigue en la lista, con
deleted: true, para tu historial y tu facturación.
Listar jobs
Sección titulada «Listar jobs»GET /v1/jobs?status=processing&limit=20Del más nuevo al más antiguo. Pasa el next_cursor de la página como cursor para la siguiente; en la última vale null. Las páginas se mantienen coherentes aunque lleguen jobs nuevos.