Saltar a la navegación

Guía de segmentos

Resumen

Los segmentos te permiten sincronizar diferentes clips de audio con distintos rangos de tiempo dentro de un solo video en una sola llamada API. Esto habilita lip sync de múltiples hablantes al permitirte asignar diferentes entradas de audio a diferentes partes de tu video. Con segments, puedes:

  • Aplicar lip sync de diferentes clips de audio a distintas partes de tu video
  • Usar una porción específica de una entrada de audio para hacer lipsync de un segmento con timing preciso
  • Usar tanto entradas de audio como de texto a voz para hacer lipsync de múltiples segmentos con distintos tipos de entrada en una sola generación

Conceptos básicos

Para usar la funcionalidad de segments, debes proporcionar un arreglo de nivel superior segments, con cada ítem definiendo un rango/segmento de tiempo de video, cada uno con su propia configuración de audio.

Segment

Cada ítem de segmento acepta las siguientes propiedades:

startTime
doubleRequired

Tiempo de inicio del segmento en segundos

endTime
doubleRequired

Tiempo de fin del segmento en segundos

audioInput
SegmentAudioInputRequired

Configuración de audio con refId y recorte opcional

optionsOverride
SegmentOptionsOverride

Sobrescribe las opciones de generación para este segmento específico

audioInput

Cada segmento requiere exactamente un audioInput. audioInput acepta las siguientes propiedades:

refId
stringRequired

ID de referencia de la entrada de audio/texto a voz que se usará para este segmento

startTime
double

Tiempo de inicio opcional (en segundos) para recortar el audio referenciado. Cuando se especifica, también debe proporcionarse endTime

endTime
double

Tiempo de fin opcional (en segundos) para recortar el audio referenciado. Cuando se especifica, también debe proporcionarse startTime

El audioInput especificado se usará para hacer lipsync del segmento de video entre startTime y endTime.

optionsOverride

Cada segmento puede sobrescribir opcionalmente las opciones de generación de nivel superior. Esto te permite aplicar distintos ajustes por segmento, incluyendo apuntar a diferentes hablantes.

Para videos de múltiples hablantes, usa active_speaker_detection para apuntar a una persona diferente en cada segmento. Consulta selección de hablante — API para ver todos los detalles sobre opciones de selección de hablante.

sync_mode
SyncMode

Sobrescribe el modo de sincronización para este segmento

temperature
double

Sobrescribe la expresividad (0-1) para este segmento

occlusion_detection_enabled
boolean

Sobrescribe la detección de oclusión para este segmento

active_speaker_detection
ActiveSpeaker

Sobrescribe active speaker detection para este segmento. Útil cuando diferentes segmentos tienen diferentes hablantes. Acepta las mismas opciones que active_speaker_detection de nivel superior:

  • auto_detect: detecta automáticamente y apunta al hablante activo
  • v3: usa ASD v3
  • frame_number + coordinates: especifica manualmente el hablante por frame y punto
  • bounding_boxes: proporciona bounding boxes por frame si tienes datos de detección
  • bounding_boxes_url: apunta a un archivo JSON externo que contiene bounding boxes (recomendado para videos largos para evitar payloads grandes)

Cómo funciona el timing y la duración de segmentos

Cuando el audio de un segmento y su ventana de video (endTime − startTime) tienen longitudes distintas, sync_mode decide cómo se resuelve el desajuste, y el modo que elijas cambia la duración efectiva de ese segmento en la salida:

sync_modeaudio más largo que la ventanaaudio más corto que la ventana
bounceel video rebota (avance y luego reversa) para cubrir el audiola ventana se recorta al audio
loopel video se repite para cubrir el audiola ventana se recorta al audio
cut_offla salida se recorta a la pista más corta (la ventana)la ventana se recorta al audio
silencereproduce el audio completo (video rellenado para cubrirlo)se reproduce la ventana completa; audio rellenado con silencio
remapel tiempo del video se estira para coincidir con el audiola ventana se recorta al audio

En resumen, la longitud efectiva de un segmento es cut_off → min(audio, ventana), silence → max(audio, ventana), y loop / bounce / remap → longitud del audio.

Las mismas reglas aplican a una generación de segmento único (sin segments), donde la “ventana” es todo el video. Un audio de 30 s en un video de 15 s con sync_mode: cut_off produce una salida de 15 s (recortada al video); silence / loop / bounce / remap producen una salida de ~30 s.

La salida puede ser más larga que tu video fuente

Cada segmento coloca su toma de audio en su propia ventana en la línea de tiempo, y cada ventana se expande para ajustarse a su audio (según el sync_mode anterior). Cuando hay huecos entre segmentos, esas ventanas expandidas desplazan el resto de la línea de tiempo, por lo que la salida puede ser más larga que el video fuente. Por ejemplo, dos segmentos [1s-3s] y [5s-8s] en un video de 10 s pueden producir una salida de ~16.8 s: cada ventana se estira para ajustarse a su toma de audio completa. Este comportamiento es esperado, no es un bug.

Para mantener la salida con la misma longitud que el video fuente, recorta cada toma de audio a su ventana con audioInput.startTime/endTime, de forma que la toma tenga exactamente la misma duración que la ventana y la ventana no se expanda:

{
"startTime": 1,
"endTime": 3,
"audioInput": { "refId": "audio_1", "startTime": 0, "endTime": 2 }
}

Aquí, el corte de audio de 2 segundos llena exactamente la ventana de 2 segundos, por lo que la línea de tiempo, y la duración de salida, se mantiene alineada con la fuente.

Ejemplos de uso de API

from sync import Sync
from sync.common import Audio, Video
sync = Sync()
response = sync.generations.create(
input=[
Video(url="https://assets.sync.so/docs/example-video.mp4"),
Audio(url="https://assets.sync.so/docs/example-audio.wav", ref_id="audio_1"),
],
model="lipsync-2",
segments=[
GenerationSegment(
start_time=2,
end_time=5,
audio_input=SegmentAudioInput(ref_id="audio_1"),
),
],
)

Múltiples segmentos con una sola entrada de audio

from sync import Sync
from sync.common import Audio, Video, TTS
sync = Sync()
response = sync.generations.create(
input=[
Video(url="https://assets.sync.so/docs/example-video.mp4"),
Audio(url="https://assets.sync.so/docs/example-audio.wav", ref_id="audio_1")
],
segments=[
{
"startTime": 2,
"endTime": 5,
"audioInput": {"refId": "audio_1", "startTime": 2, "endTime": 5}
},
{
"startTime": 6,
"endTime": 8,
"audioInput": {"refId": "audio_1", "startTime": 6, "endTime": 8}
}
],
model="lipsync-2"
)

Múltiples segmentos con múltiples audios

from sync import Sync
from sync.common import Audio, Video, TTS
sync = Sync()
response = sync.generations.create(
input=[
Video(url="https://assets.sync.so/docs/example-video.mp4"),
Audio(url="https://assets.sync.so/docs/example-audio.wav", ref_id="audio_1"),
Audio(url="https://assets.sync.so/docs/example-audio.wav", ref_id="audio_2")
],
segments=[
{
"startTime": 2,
"endTime": 5,
"audioInput": {"refId": "audio_1", "startTime": 2, "endTime": 5}
},
{
"startTime": 6,
"endTime": 8,
"audioInput": {"refId": "audio_2", "startTime": 6, "endTime": 8}
}
],
model="lipsync-2"
)

Segmentos con opciones por segmento

Usa optionsOverride para aplicar distintos ajustes de generación a cada segmento.

from sync import Sync
from sync.common import Audio, Video
sync = Sync()
response = sync.generations.create(
input=[
Video(url="https://assets.sync.so/docs/example-video.mp4"),
Audio(url="https://assets.sync.so/docs/audio1.wav", ref_id="audio_1"),
Audio(url="https://assets.sync.so/docs/audio2.wav", ref_id="audio_2")
],
segments=[
{
"startTime": 0,
"endTime": 5,
"audioInput": {"refId": "audio_1"},
"optionsOverride": {
"sync_mode": "loop",
"temperature": 0.3
}
},
{
"startTime": 5,
"endTime": 10,
"audioInput": {"refId": "audio_2"},
"optionsOverride": {
"sync_mode": "cut_off",
"temperature": 0.7
}
}
],
model="lipsync-2",
options={"sync_mode": "bounce"} # Default for segments without override
)

Apunta a distintos hablantes por segmento

Usa active_speaker_detection en optionsOverride para apuntar a distintos hablantes en cada segmento. Esto es útil cuando un video tiene varias personas y diferentes segmentos deben hacer lipsync con diferentes hablantes.

from sync import Sync
from sync.common import Audio, Video
sync = Sync()
response = sync.generations.create(
input=[
Video(url="https://assets.sync.so/docs/two-speakers.mp4"),
Audio(url="https://assets.sync.so/docs/speaker-a.wav", ref_id="audio_a"),
Audio(url="https://assets.sync.so/docs/speaker-b.wav", ref_id="audio_b")
],
segments=[
{
"startTime": 0,
"endTime": 5,
"audioInput": {"refId": "audio_a"},
"optionsOverride": {
"active_speaker_detection": {
"frame_number": 0,
"coordinates": [200, 300] # Point on speaker A's face
}
}
},
{
"startTime": 5,
"endTime": 10,
"audioInput": {"refId": "audio_b"},
"optionsOverride": {
"active_speaker_detection": {
"frame_number": 150,
"coordinates": [600, 300] # Point on speaker B's face
}
}
}
],
model="lipsync-2"
)

Consulta selección de hablante — API para detalles sobre opciones de active_speaker_detection.

Mejores prácticas

Planifica tus segmentos

  1. Mapea tu timeline: identifica segmentos de video y necesidades de audio correspondientes
  2. Prepara archivos de audio: garantiza calidad de audio y duración apropiada
  3. Prueba límites de segmento: verifica transiciones suaves entre segmentos

Preparación de audio

  • Usa calidad de audio consistente en todos los segmentos y en el audio del video.
  • Para mejores resultados, asegúrate de alinear correctamente el timing con los segmentos de video. Si la duración del segmento y la duración del audio correspondiente no coinciden, usa sync_mode para decidir cómo manejar el desajuste.

Solución de problemas

Errores comunes

Proporciona un arreglo segments de nivel superior cuando uses múltiples entradas de audio o texto.

# ❌ This will fail
response = sync.generations.create(
input=[
Video(url="video.mp4"),
Audio(url="audio1.wav"), # Multiple audio without segments
Audio(url="audio2.wav")
],
model="lipsync-2"
)
# ✅ This will work
response = sync.generations.create(
input=[
Video(url="video.mp4"),
Audio(url="audio1.wav", ref_id="a1"),
Audio(url="audio2.wav", ref_id="a2")
],
segments=[
{"start_time": 0, "end_time": 10, "audio_input": {"refId": "a1"}},
{"start_time": 10, "end_time": 20, "audio_input": {"refId": "a2"}}
],
model="lipsync-2"
)

Asegúrate de que todas las entradas de audio tengan valores url o assetId válidos y de que los valores refId referenciados existan en tus entradas de audio o texto.

# ❌ Missing refId reference
response = sync.generations.create(
input=[
Video(url="video.mp4"),
Audio(url="audio.wav", ref_id="audio1")
],
segments=[
{"start_time": 0, "end_time": 10, "audio_input": {"refId": "missing"}} # Wrong refId
],
model="lipsync-2"
)
# ✅ Correct refId reference
response = sync.generations.create(
input=[
Video(url="video.mp4"),
Audio(url="audio.wav", ref_id="audio1")
],
segments=[
{"start_time": 0, "end_time": 10, "audio_input": {"refId": "audio1"}} # Correct refId
],
model="lipsync-2"
)

Este error ocurre cuando al audio_input de un segmento le falta refId o refId está vacío. Cada segmento debe referenciar una entrada de audio o texto válida mediante su refId.

# ❌ Missing refId in segment
response = sync.generations.create(
input=[
Video(url="video.mp4"),
Audio(url="audio.wav", ref_id="audio1")
],
segments=[
{
"start_time": 0,
"end_time": 10,
"audio_input": {} # Missing refId
}
],
model="lipsync-2"
)
# ✅ Include refId in segment
response = sync.generations.create(
input=[
Video(url="video.mp4"),
Audio(url="audio.wav", ref_id="audio1")
],
segments=[
{
"start_time": 0,
"end_time": 10,
"audio_input": {"refId": "audio1"} # Valid refId
}
],
model="lipsync-2"
)

Este error ocurre cuando un segmento referencia un refId que no existe en tus entradas de audio o texto. Asegúrate de que todos los valores refId referenciados coincidan exactamente con los definidos en tus entradas.

# ❌ Segment references unknown refId
response = sync.generations.create(
input=[
Video(url="video.mp4"),
Audio(url="audio.wav", ref_id="audio1") # refId is "audio1"
],
segments=[
{
"start_time": 0,
"end_time": 10,
"audio_input": {"refId": "nonexistent"} # References unknown refId
}
],
model="lipsync-2"
)
# ✅ Segment references existing refId
response = sync.generations.create(
input=[
Video(url="video.mp4"),
Audio(url="audio.wav", ref_id="audio1") # refId is "audio1"
],
segments=[
{
"start_time": 0,
"end_time": 10,
"audio_input": {"refId": "audio1"} # References existing refId
}
],
model="lipsync-2"
)

El startTime de cada segmento debe ser menor o igual que su endTime. Se permiten segmentos de duración cero (cuando startTime es igual a endTime) para casos de uso como puntos de recorte de duración cero.

# ❌ Invalid: startTime greater than endTime
segments=[
{
"startTime": 10,
"endTime": 5, # endTime must be >= startTime
"audioInput": {"refId": "audio1"}
}
]
# ✅ Valid: startTime less than endTime
segments=[
{
"startTime": 0,
"endTime": 10,
"audioInput": {"refId": "audio1"}
}
]
# ✅ Valid: startTime equals endTime (zero-length segment)
segments=[
{
"startTime": 5,
"endTime": 5,
"audioInput": {"refId": "audio1"}
}
]

Cuando especificas límites de segmento usando frames en lugar de segundos, startFrame debe ser estrictamente menor que endFrame. A diferencia de los segmentos basados en tiempo, que permiten tiempos de inicio y fin iguales, los segmentos basados en frames requieren al menos un frame de diferencia.

# ❌ Invalid: startFrame greater than or equal to endFrame
segments=[
{
"startFrame": 100,
"endFrame": 0, # endFrame must be > startFrame
"audioInput": {"refId": "audio1"}
}
]
# ❌ Invalid: startFrame equals endFrame (not allowed for frames)
segments=[
{
"startFrame": 50,
"endFrame": 50, # endFrame must be > startFrame
"audioInput": {"refId": "audio1"}
}
]
# ✅ Valid: startFrame less than endFrame
segments=[
{
"startFrame": 0,
"endFrame": 100,
"audioInput": {"refId": "audio1"}
}
]

Cuando recortas audio dentro de un segmento, deben proporcionarse tanto startTime como endTime, y startTime debe ser menor o igual que endTime.

# ❌ Incomplete crop range
segments=[
{
"startTime": 0,
"endTime": 10,
"audioInput": {
"refId": "audio1",
"startTime": 5 # Missing endTime
}
}
]
# ❌ Invalid: startTime greater than endTime
segments=[
{
"startTime": 0,
"endTime": 10,
"audioInput": {
"refId": "audio1",
"startTime": 15,
"endTime": 5 # endTime must be >= startTime
}
}
]
# ✅ Valid: complete crop range with startTime <= endTime
segments=[
{
"startTime": 0,
"endTime": 10,
"audioInput": {
"refId": "audio1",
"startTime": 5,
"endTime": 15
}
}
]
# ✅ Valid: zero-duration crop point (startTime equals endTime)
segments=[
{
"startTime": 0,
"endTime": 10,
"audioInput": {
"refId": "audio1",
"startTime": 5,
"endTime": 5
}
}
]

Asegúrate de tener al menos una entrada de audio o texto con un refId válido al usar segments.

# ❌ This will fail - no audio or text inputs
response = sync.generations.create(
input=[
Video(url="https://example.com/video.mp4")
],
segments=[
{"start_time": 0, "end_time": 10, "audio_input": {"refId": "missing"}}
],
model="lipsync-2"
)
# ✅ This will work - includes text input
response = sync.generations.create(
input=[
Video(url="https://example.com/video.mp4"),
TTS(
provider={
"name": "elevenlabs",
"voiceId": "EXAVITQu4vr4xnSDxMaL",
"script": "Hello world"
},
ref_id="text1"
)
],
segments=[
{"start_time": 0, "end_time": 10, "audio_input": {"refId": "text1"}}
],
model="lipsync-2"
)

Recursos relacionados