# Reproducción de video

Hay tres formas diferentes de mostrar un video en una Scene:

* Subir un archivo de video como parte del contenido de la Scene
* Transmitir el video desde una fuente externa
* Transmitir en vivo a través de Decentraland cast

{% hint style="info" %}
**💡 Consejo**: En el [Scene Editor en Creator Hub](/creator/content-creator-es/scene-editor/comenzar/about-editor.md), puedes usar un **Video Player** [Smart Item](/creator/content-creator-es/scene-editor/interactividad/smart-items.md) para una forma sin código de lograr esto.
{% endhint %}

En todos los casos, necesitarás:

* Una entity con un [forma primitiva](/creator/content-creator-es/scenes-sdk7/esenciales-de-contenido-3d/shape-components.md) como un plano, un cubo o incluso un cono.
* A [material](/creator/content-creator-es/scenes-sdk7/esenciales-de-contenido-3d/materials.md) con un `VideoTexture` asignado a su texture
* A `VideoPlayer` component para controlar el estado del video.

## Consideraciones de rendimiento

Ten en cuenta que transmitir video exige un esfuerzo significativo de la máquina del jugador. Se recomienda evitar reproducir más de un video a la vez.

Si se están reproduciendo demasiados videos al mismo tiempo en tu scene, algunos serán pausados por el engine. La prioridad para pausar una pantalla se determina en función de varios factores, incluida la proximidad al jugador, el tamaño y si la pantalla está dentro del campo de visión del jugador. El número máximo de videos simultáneos depende de los ajustes de calidad del jugador.

* Bajo: 1
* Medio: 5
* Alto: 10

También recomendamos empezar a reproducir el video cuando el player esté cerca o realice una acción para hacerlo. Empezar a reproducir un video cuando tu scene se carga lejos en el horizonte afectará innecesariamente al rendimiento mientras los players visitan scenes vecinas.

Evita también transmitir videos en una resolución muy alta. No uses nada por encima de *HD*.

También es ideal reproducir videos en materiales Basic (unlit), para reducir la carga de rendimiento, como ocurre en todos los fragmentos de ejemplo de abajo.

## Mostrar un video

Las siguientes instrucciones se aplican a las tres opciones de mostrar video:

1. Crea una entity que sirva como pantalla de video. Dale a esta entity un `MeshRenderer` component para que tenga una forma visible.
2. Crea un `VideoPlayer` component, ya sea haciendo referencia a una URL de streaming o a una ruta a un archivo de video. Aquí también puedes configurar el `playing` estado y su volumen. Este component puede asignarse a la entity de la pantalla de video o a cualquier otra entity de la scene.
3. Crea un `VideoTexture` object, y en su `videoPlayerEntity` property asigna la entity que posee el `VideoPlayer` componente.
4. Crea un `Material`, asígnalo a la entity de la pantalla, y establece su `texture` a las `VideoTexture` que creaste.

Este ejemplo usa un video almacenado localmente en una `/videos` carpeta en el proyecto de la scene:

```ts
// #1
const screen = engine.addEntity()
MeshRenderer.setPlane(screen)
Transform.create(screen, { position: { x: 4, y: 1, z: 4 } })

// #2
VideoPlayer.create(screen, {
	src: 'videos/myVideo.mp4',
	playing: true,
})

// #3
const videoTexture = Material.Texture.Video({ videoPlayerEntity: screen })

// #4
Material.setBasicMaterial(screen, {
	texture: videoTexture,
})
```

Para usar un video desde una URL de streaming externa, cambia el paso 2 para que el `src` propiedad en el `VideoPlayer` component haga referencia a la URL de streaming.

```ts
// #2
VideoPlayer.create(screen, {
	src: 'https://player.vimeo.com/external/552481870.m3u8?s=c312c8533f97e808fccc92b0510b085c8122a875',
	playing: true,
})
```

Consulta [Transmitir usando Decentraland cast](#streaming-using-decentraland-cast) para obtener detalles sobre cómo usar este tercer método alternativo.

## About External Streaming

La fuente del streaming debe ser una URL *https* (las URL*http* Las URLs no son compatibles).

Deberías poder pegar una URL que apunte a un video de la mayoría de los sitios populares de streaming de video. Ten en cuenta los términos de servicio de estas plataformas.

Para transmitir desde un archivo de video que tengas en tu máquina local, la forma más sencilla es subir este video a un Google Drive público y pegar el enlace.

Otra opción es usar un proveedor de hosting gestionado como [Vimeo](https://vimeo.com/) , [Livepeer Studio](https://livepeer.studio/) o [Serraform](https://serraform.gitbook.io/streaming-docs/guides/decentraland-playback) donde pagas una tarifa al proveedor para que gestione toda la infraestructura de streaming.

La forma más potente es configurar tu propio servidor, usando software gratuito pero pagando el hosting en una plataforma como [Digital Ocean](https://try.digitalocean.com/developerbrand/?_campaign=emea_brand_kw_en_cpc&_adgroup=digitalocean_exact_exact&_keyword=digitalocean&_device=c&_adposition=&_content=conversion&_medium=cpc&_source=bing\&msclkid=160bfc160a2a1bab9bbf9933594bd9c5\&utm_source=bing\&utm_medium=cpc\&utm_campaign=emea_brand_kw_en_cpc\&utm_term=digitalocean\&utm_content=DigitalOcean%20Exact_Exact) o [Cloudflare](https://www.cloudflare.com/products/cloudflare-stream/). Puedes desplegar algo como un [Node Media Server](https://github.com/illuspas/Node-Media-Server), que proporciona la mayor parte de lo que necesitas listo para usar.

Todas estas opciones tienen ventajas y desventajas para distintos escenarios. Debes evaluar qué es lo mejor para ti teniendo en cuenta tus necesidades, habilidades técnicas y presupuesto.

## Setting up OBS for successful streaming

[OBS](https://obsproject.com/) es una herramienta popular y gratuita para gestionar tus streams.

Ya sea que uses la stream key de un venue o tu propio servidor RTMP, tus ajustes en OBS son importantes para el éxito de tu stream. Debes buscar una conexión sólida y consistente.

### Configuración simple de OBS

Se recomienda la siguiente configuración simple:

* Bitrate 2500kbps (funcionará con todos los venues de Decentraland)
* Bitrate de audio 160kbps
* Preset del codificador de video: Hardware NVENC
* Codificador de audio AAC
* Resolución más amplia: 720 (cualquier valor mayor causa problemas en DCL)
* Tasa de frames 30fps

{% hint style="warning" %}
**📔 Nota**: Asegúrate de desactivar Multitrack streaming en OBS. Puedes encontrarlo en Settings > Stream.
{% endhint %}

### Consejos para nuevos streamers

* Las pruebas de sonido tempranas son esenciales para probar tu configuración con el venue.
* Pequeños errores, como un dígito incorrecto en la stream key, son lo más probable para arruinar el stream.
* No superes la resolución 720 ni un bitrate de 2500 kbps.

## Live streaming

Puedes hacer livestream desde tu cámara o compartir tu pantalla usando la [Live streaming](/creator/content-creator-es/scene-editor/operar-en-vivo/live-streaming.md) funcionalidad del [Admin tools](/creator/content-creator-es/scene-editor/operar-en-vivo/scene-admin.md) smart item.

Este método de streaming usa la misma arquitectura de comms utilizada para las comunicaciones en vivo entre jugadores. Es fácil de configurar y tiene mucha menos demora que transmitir desde fuentes externas.

1. Añade un [Admin tools](/creator/content-creator-es/scene-editor/operar-en-vivo/scene-admin.md) smart item a tu scene, así como un [Reproductor de video](/creator/content-creator-es/scene-editor/interactividad/video-screen.md) smart item.
2. Publica tu scene, ya sea en un World o en Genesis City.
3. Entra en la scene como jugador con permiso para usar las Admin tools.
4. Abre la consola de Admin, selecciona la pestaña **Video** después selecciona la **Live** funcionalidad y haz clic en el **Get Stream Key** .
5. Copia la **Server URL** y *Streaming key*\* a tu software de streaming (por ejemplo OBS).
6. Presiona la tecla **Activa el botón** para iniciar el streaming.

En lugar de añadir un smart item Video player a tu scene, también puedes usar la URL `livekit-video://current-stream` como fuente de video para reproducir el stream en tu scene. Aun así, necesitarás las Admin tools para obtener la stream key.

```ts
// #1
const screen = engine.addEntity()
MeshRenderer.setPlane(screen)
Transform.create(screen, { position: { x: 4, y: 1, z: 4 } })

// #2
VideoPlayer.create(screen, {
	src: `livekit-video://current-stream`,
	playing: true,
})

// #3
const videoTexture = Material.Texture.Video({ videoPlayerEntity: screen })

// #4
Material.setBasicMaterial(screen, {
	texture: videoTexture,
})
```

## Materiales de video

La mayoría de las veces, querrás reproducir videos en un [material Basic](/creator/content-creator-es/scenes-sdk7/esenciales-de-contenido-3d/materials.md#unlit-materials)sin iluminación, en lugar de un material PBR. Esto da como resultado una imagen mucho más brillante y nítida y es mejor para el rendimiento.

```ts
Material.setBasicMaterial(screen, {
	texture: videoTexture,
})
```

Por lo general se recomienda reproducir videos en materiales Basic unlit, ya que esto mejora el rendimiento. Sin embargo, si quieres proyectar un video sobre un material PBR, ten en cuenta que las propiedades predeterminadas hacen que el video se vea bastante opaco. Puedes mejorarlo modificando otras propiedades del material. Aquí tienes algunos ajustes recomendados para hacer que el video resalte más:

```ts
Material.setPbrMaterial(screen, {
	texture: videoTexture,
	roughness: 1.0,
	specularIntensity: 0,
	metallic: 0,
	emissiveTexture: videoTexture,
	emissiveIntensity: 0.6,
	emissiveColor: Color3.White(),
})
```

{% hint style="info" %}
**💡 Consejo**: Como el video es una texture que se añade a un material, también puedes experimentar con otras propiedades de los materials, como teñirlo con un color o añadir otras capas de texture, por ejemplo para producir un efecto de pantalla sucia.

Consulta [materials](/creator/content-creator-es/scenes-sdk7/esenciales-de-contenido-3d/materials.md) para más detalles.
{% endhint %}

## Acerca de los archivos de video

Se admiten los siguientes formatos de archivo:

* *.mp4*
* *.ogg*
* *.webm*

Ten en cuenta que un archivo de video aumenta el tamaño total de la scene, lo que hace que la scene tarde más en descargarse para los players que entren en tu scene. El tamaño del video también podría hacer que superes el [limitaciones de la scene](/creator/content-creator-es/scenes-sdk7/optimizacion/scene-limitations.md), ya que tienes un máximo de 15 MB por parcel para usar. Recomendamos comprimir el video tanto como sea posible, para que sea menos problemático.

También recomendamos empezar a reproducir el video cuando el jugador esté cerca o realice una acción que lo active. Empezar a reproducir un video cuando tu scene se carga lejos en el horizonte afectará innecesariamente al rendimiento mientras los jugadores visitan scenes vecinas.

## Iniciar, pausar y detener un video

Para empezar a reproducir el video o pausarlo, establece el `playing` propiedad en *true* o *false*. Si `playing` se establece en false, el video se pausa en el último frame mostrado.

Puedes hacer que una pantalla sea activable agregándole un pointer event como se muestra abajo:

```ts
pointerEventsSystem.onPointerDown(
	{
		entity: screen,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Reproducir/Pausar' },
	},
	function () {
		const videoPlayer = VideoPlayer.getMutable(screen)
		videoPlayer.playing = !videoPlayer.playing
	}
)
```

Para detener el video y devolverlo al primer frame, establece la `posición` property en 0. En el siguiente ejemplo, hacer clic en el video lo detiene.

```ts
pointerEventsSystem.onPointerDown(
	{
		entity: screen,
		opts: { button: InputAction.IA_POINTER, hoverText: 'DETENER' },
	},
	function () {
		const videoPlayer = VideoPlayer.getMutable(screen)
		videoPlayer.playing = false
		videoPlayer.position = 0
	}
)
```

## Configurar el video player

Las siguientes propiedades opcionales están disponibles para establecer en el `VideoPlayer` componente:

* `playing`: Determina si el video se está reproduciendo actualmente. Si es false, el video está en pausa.

{% hint style="warning" %}
**📔 Nota**: Solo puede haber un `VideoPlayer` component activo a la vez en cada scene.
{% endhint %}

* `playbackRate`: Cambia la velocidad a la que se reproduce el video. *1* de forma predeterminada.
* `volume`: Te permite cambiar el volumen del audio. *1* de forma predeterminada.
* `posición`: Te permite establecer una posición inicial diferente en el video. Se expresa en segundos después del comienzo original del video. *-1* por defecto, lo que hace que empiece al inicio real del video.
* `loop`: Booleano que determina si el video se reproduce continuamente en un loop o si se detiene después de reproducirse una vez. *false* de forma predeterminada.

## Reproducir múltiples videos

Para evitar problemas de rendimiento, cada scene solo puede reproducir una texture de video a la vez. Sin embargo, una scene puede reproducir múltiples copias de la misma texture de video en varias pantallas diferentes. Esto no está restringido, ya que afecta al rendimiento considerablemente menos que reproducir videos separados. Para reproducir el mismo video en múltiples entities, simplemente asigna la misma instancia del objeto de texture de video a los `Material` components de cada entity de pantalla.

```ts
// #1
const screen1 = engine.addEntity()
MeshRenderer.setPlane(screen1)
Transform.create(screen1, { position: { x: 4, y: 1, z: 4 } })

const screen2 = engine.addEntity()
MeshRenderer.setPlane(screen2)
Transform.create(screen2, { position: { x: 6, y: 1, z: 4 } })

// #2
VideoPlayer.create(screen1, {
	src: 'https://player.vimeo.com/external/552481870.m3u8?s=c312c8533f97e808fccc92b0510b085c8122a875',
	playing: true,
})

// #3
const videoTexture = Material.Texture.Video({ videoPlayerEntity: screen1 })

// #4
Material.setBasicMaterial(screen1, {
	texture: videoTexture,
})

Material.setBasicMaterial(screen2, {
	texture: videoTexture,
})
```

Ten en cuenta que en el ejemplo anterior, solo es necesario crear un `VideoPlayer` component, que controla el estado de ambas pantallas de video. En este caso, el component se asigna a la entity `screen1` entity, pero también podría asignarse a cualquier otra entity de la scene, no necesariamente a una de las pantallas.

## Eventos de video

Gestiona fácilmente los cambios de estado en un video, para responder cuando un video empieza a reproducirse, se pausa, etc. Esto puede usarse, por ejemplo, para reproducir animaciones en perfecta sincronía con un video, asegurando que empiecen al mismo tiempo que el video.

Usa `videoEventsSystem.registerVideoEventsEntity` para definir una función que se ejecuta cada vez que cambia el estado del video asignado a una entity. Cada vez que cambie el estado, tu función puede comprobar el nuevo estado y responder en consecuencia.

```ts
import {
	engine,
	Entity,
	VideoPlayer,
	videoEventsSystem,
	VideoState,
} from '@dcl/sdk/ecs'

// ... Crea videoPlayerEntity con el component VideoPlayer, Transform, MeshRenderer.setPlane(), etc. ...

videoEventsSystem.registerVideoEventsEntity(
	videoPlayerEntity,
	function (videoEvent) {
		console.log(
			'video event - state: ' +
				videoEvent.state +
				'\ncurrent offset:' +
				videoEvent.currentOffset +
				'\nvideo length:' +
				videoEvent.videoLength
		)

		switch (videoEvent.state) {
			case VideoState.VS_READY:
				console.log('video event - video is READY')
				break
			case VideoState.VS_NONE:
				console.log('video event - video is in NO STATE')
				break
			case VideoState.VS_ERROR:
				console.log('video event - video ERROR')
				break
			case VideoState.VS_SEEKING:
				console.log('video event - video is SEEKING')
				break
			case VideoState.VS_LOADING:
				console.log('video event - video is LOADING')
				break
			case VideoState.VS_BUFFERING:
				console.log('video event - video is BUFFERING')
				break
			case VideoState.VS_PLAYING:
				console.log('video event - video started PLAYING')
				break
			case VideoState.VS_PAUSED:
				console.log('video event - video is PAUSED')
				break
		}
	}
)
```

El objeto videoEvent pasado como entrada para la función contiene las siguientes propiedades:

* `currentOffset` (*number*): El valor actual de la property `posición` en el video. Este valor muestra los segundos después del comienzo original del video. *-1* por defecto, si el video aún no ha empezado a reproducirse.
* `state`: El nuevo estado del video, expresado como un valor del `VideoState` enum. Este enum puede contener los siguientes valores posibles:
  * `VideoState.VS_READY`
  * `VideoState.VS_NONE`
  * `VideoState.VS_ERROR`
  * `VideoState.VS_SEEKING`
  * `VideoState.VS_LOADING`
  * `VideoState.VS_BUFFERING`
  * `VideoState.VS_PLAYING`
  * `VideoState.VS_PAUSED`
* `videoLength` (*number* ): La duración en segundos de todo el video. *-1* si la duración es desconocida.
* `timeStamp` ( *number*): Un *lamport* timestamp que se incrementa cada vez que el video cambia de estado.
* `tickNumber` (*number*): El momento en que ocurrió el evento, expresado como el conteo de ticks desde que la scene comenzó a ejecutarse.

### Último evento de video

Consulta el último cambio de estado de un video usando `videoEventsSystem.getVideoState()`. Esta función siempre devuelve el último valor de `VideoEvent` para el video.

```ts
function mySystem() {
	const latestVideoEvent = videoEventsSystem.getVideoState(videoPlayerEntity)
	if (!latestVideoEvent) return

	console.log(`state: ${latestVideoEvent.state}
    \ncurrentOffset: ${latestVideoEvent.currentOffset}
    \nvideoLength: ${latestVideoEvent.videoLength}`)
}
```

## Máscaras alpha en videos

Un truco ingenioso para tener pantallas de video no rectangulares es aplicar una texture alpha encima de un plano. Puedes recortar parte del plano en la forma que quieras.

Usa la siguiente imagen para recortar tu video en una forma circular, con esquinas transparentes.

![](/files/4e00882f1e9b6519900e0f2898efbe9daf5b2d5e)

```ts
const videoTexture = Material.Texture.Video({
	videoPlayerEntity: screen,
})
const alphaMask = Material.Texture.Common({
	src: 'assets/scene/circle_mask.png',
	wrapMode: TextureWrapMode.TWM_MIRROR,
})

Material.setBasicMaterial(screen, {
	texture: videoTexture,
	alphaTexture: alphaMask,
})
```

![](/files/8f378d68ea244dd7498ffbed72b691b89ec54552)

{% hint style="warning" %}
**📔 Nota**: En versiones anteriores, la property `alphaTexture` solo estaba presente en materiales PBR. Actualmente, solo funciona en materiales básicos.
{% endhint %}

## Reproducir un video en un modelo glTF

Puedes reproducir un video en un *glTF* modelo usando el [GltfNodeModifiers](/creator/content-creator-es/scenes-sdk7/esenciales-de-contenido-3d/materials.md#modify-gltf-materials) component. Consulta [Modificar materiales glTF](/creator/content-creator-es/scenes-sdk7/esenciales-de-contenido-3d/materials.md#modify-gltf-materials) para más detalles.

Esto te permite reproducir tus videos en cualquier forma, no solo en planos. Por ejemplo, puedes reproducir videos en una pantalla curva, o incluso en todo el cuerpo de un NPC.

```ts
const myEntity = engine.addEntity()

GltfContainer.create(myEntity, {
	src: 'models/myModel.glb',
})

Transform.create(myEntity, {
	position: Vector3.create(4, 0, 4),
})

VideoPlayer.create(myEntity, {
	src: 'https://player.vimeo.com/external/552481870.m3u8?s=c312c8533f97e808fccc92b0510b085c8122a875',
	playing: true,
})

GltfNodeModifiers.create(myEntity, {
	modifiers: [
		{
			path: '',
			material: {
				material: {
					$case: 'pbr',
					pbr: {
						texture: Material.Texture.Video({
							videoPlayerEntity: myEntity,
						}),
					},
				},
			},
		},
	],
})
```

La asignación del video seguirá el mapeo UV original que usa el modelo. Esto significa que si el modelo tiene una texture que está mapeada a una parte específica del modelo, el video se mapeará a esa misma parte.

También puedes usar la `GltfNodeModifiers` component para reproducir un video solo en una mesh específica dentro del modelo. Por ejemplo, puedes reproducirlo en una pared específica de un edificio, aunque el modelo abarque todo el edificio. Ver [Modificar materiales glTF](/creator/content-creator-es/scenes-sdk7/esenciales-de-contenido-3d/materials.md#modify-gltf-materials) para más detalles.

## Audio espacial

De forma predeterminada, el video de un `VideoPlayer` component es global, lo que significa que se escuchará a un volumen constante en toda tu scene. Si un jugador sale de la scene, no escuchará la transmisión en absoluto.

Para hacer que el audio sea espacial, establece el `spatial` propiedad en *true*.

```ts
VideoPlayer.create(entity, {
	src: 'https://player.vimeo.com/progressive_redirect/playback/1145666916/rendition/540p/file.mp4%20%28540p%29.mp4?loc=external&signature=db1cd6946851313cb8f7be60d1f6c30af0902bcc46fdae0ba2a06e5fdf44c329',
	playing: true,
	spatial: true,
})
```

Ahora el video se escuchará desde la posición de la entity que posee el `VideoPlayer` component, y sonará más fuerte a medida que el jugador se acerque.

Controla el audio espacial con las siguientes propiedades:

* `spatialMinDistance`: La distancia mínima a la que el audio se vuelve espacial. Si el jugador está más cerca, el audio se escuchará a volumen completo. *0* de forma predeterminada.
* `spatialMaxDistance`: La distancia máxima a la que se oye el audio. Si el jugador está más lejos, el audio se escuchará a volumen 0. *60* por defecto

```ts
const videoPlayerEntity = engine.addEntity()

Transform.create(videoPlayerEntity, {
	position: Vector3.create(8, 2, 8),
})

VideoPlayer.create(videoPlayerEntity, {
	src: 'https://player.vimeo.com/progressive_redirect/playback/1145666916/rendition/540p/file.mp4%20%28540p%29.mp4?loc=external&signature=db1cd6946851313cb8f7be60d1f6c30af0902bcc46fdae0ba2a06e5fdf44c329',
	playing: true,
	spatial: true,
	spatialMinDistance: 5,
	spatialMaxDistance: 10,
})

MeshRenderer.setPlane(videoPlayerEntity)

Material.setBasicMaterial(videoPlayerEntity, {
	texture: Material.Texture.Video({ videoPlayerEntity: videoPlayerEntity }),
})
```

{% hint style="warning" %}
**📔 Nota**: Algunos formatos de video no admiten audio espacial. Asegúrate de que el stream esté codificado en *mp4*, *m4a*, o *mov*.
{% endhint %}

## Análisis de audio

Puedes leer datos de amplitud y frecuencia en tiempo real desde la pista de audio de una `VideoPlayer` entity para impulsar visuales reactivos que se sincronicen con la banda sonora del video. Ver [Análisis de audio](/creator/content-creator-es/scenes-sdk7/media/audio-analysis.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/media/video-playing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
