# Reprodução de vídeo

Há três maneiras diferentes de mostrar um vídeo numa scene:

* Carregar um arquivo de vídeo como parte do conteúdo da scene
* Transmitir o vídeo a partir de uma fonte externa
* Transmitir ao vivo via Decentraland cast

{% hint style="info" %}
**💡 Dica**: No [Scene Editor no Creator Hub](/creator/content-creator-pt/scene-editor/comecar/about-editor.md), você pode usar um **Video Player** [Smart Item](/creator/content-creator-pt/scene-editor/interatividade/smart-items.md) para uma forma sem código de conseguir isso.
{% endhint %}

Em todos os casos, você vai precisar de:

* Uma entity com um [forma primitiva](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/shape-components.md) como um plane, cube ou até mesmo um cone.
* A [material](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md) com um `VideoTexture` atribuído à sua texture
* A `VideoPlayer` component para controlar o estado do vídeo.

## Considerações de desempenho

Tenha em mente que transmitir vídeo exige um esforço significativo da máquina do jogador. É recomendável evitar reproduzir mais de um vídeo ao mesmo tempo.

Se muitos vídeos estiverem sendo reproduzidos ao mesmo tempo na sua scene, alguns serão pausados pelo engine. A prioridade para pausar uma tela é determinada com base em vários fatores, incluindo a proximidade do jogador, o tamanho e se a tela está no campo de visão do jogador. O número máximo de vídeos simultâneos depende das configurações de qualidade do jogador.

* Low: 1
* Medium: 5
* High: 10

Também recomendamos começar a reproduzir o vídeo quando o player estiver perto ou execute uma action para o fazer. Começar a reproduzir um vídeo quando a tua scene é carregada longe no horizonte afetará desnecessariamente o desempenho enquanto os players visitam scenes vizinhas.

Evite também transmitir vídeos em resolução muito alta. Não use nada acima de *HD*.

Também é ideal reproduzir vídeos em materiais Basic (unlit), para reduzir a carga de desempenho, como é o caso de todos os exemplos abaixo.

## Mostrar um vídeo

As instruções a seguir se aplicam a todas as três opções de exibição de vídeo:

1. Crie uma entity para servir como tela do vídeo. Dê a essa entity um `MeshRenderer` component para que ela tenha uma forma visível.
2. Crie um `VideoPlayer` component, referenciando uma URL de streaming ou um caminho para um arquivo de vídeo. Aqui você também pode definir o `playing` estado do vídeo e seu volume. Esse component pode ser atribuído à entity da tela do vídeo ou a qualquer outra entity na scene.
3. Crie um `VideoTexture` object, e em sua `videoPlayerEntity` property atribua a entity que possui o `VideoPlayer` componente.
4. Crie um `Material`, atribua-o à entity da tela e defina seu `texture` a `VideoTexture` que você criou.

Este exemplo usa um vídeo armazenado localmente em uma `/videos` folder no projeto da 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 um vídeo de uma URL de streaming externa, altere o passo 2 para que o `src` propriedade em `VideoPlayer` component referencie a URL de streaming.

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

Veja [Transmitir usando Decentraland cast](#streaming-using-decentraland-cast) para detalhes sobre como usar este terceiro método alternativo.

## About External Streaming

A source do streaming tem de ser um *https* URL (*http* URLs não são suportadas).

Você deve conseguir colar uma URL apontando para um vídeo da maioria dos sites populares de streaming de vídeo. Tenha atenção aos termos de serviço dessas plataformas.

Para transmitir a partir de um arquivo de vídeo que você tem na sua máquina local, o caminho mais simples é carregar esse vídeo para um Google Drive público e colar o link.

Outra opção é usar um provedor de hospedagem gerenciado como [Vimeo](https://vimeo.com/) , [Livepeer Studio](https://livepeer.studio/) ou [Serraform](https://serraform.gitbook.io/streaming-docs/guides/decentraland-playback) onde pagas uma taxa ao fornecedor para gerir toda a infraestrutura de streaming.

A abordagem mais poderosa é configurar o seu próprio servidor, usando software gratuito, mas pagando pela hospedagem numa 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) ou [Cloudflare](https://www.cloudflare.com/products/cloudflare-stream/). Você pode implantar algo como um [Node Media Server](https://github.com/illuspas/Node-Media-Server), que fornece a maior parte do que você precisa pronto para uso.

Todas essas opções têm prós e contras para diferentes cenários. Você deve avaliar o que é melhor para você, levando em conta suas necessidades, habilidades técnicas e orçamento.

## Setting up OBS for successful streaming

[OBS](https://obsproject.com/) é uma ferramenta popular e gratuita para gerenciar suas transmissões.

Quer você esteja usando a chave de stream de um local ou seu próprio servidor RTMP, suas configurações no OBS são importantes para o sucesso da sua transmissão. Você deve buscar uma conexão sólida e consistente.

### Configuração simples do OBS

A seguinte configuração simples é recomendada:

* Bitrate 2500kbps (o que funcionará com todos os locais do Decentraland)
* Bitrate de áudio 160kbps
* Predefinição do codificador de vídeo: Hardware NVENC
* Codificador de áudio AAC
* Resolução máxima: 720 (qualquer valor maior causa problemas no DCL)
* Taxa de quadros 30fps

{% hint style="warning" %}
**📔 Nota**: Certifique-se de desativar o Multitrack streaming no OBS. Você pode encontrar isso em Settings > Stream.
{% endhint %}

### Conselhos para novos streamers

* As verificações iniciais de som são essenciais para testar sua configuração com o local.
* Pequenos erros, como um dígito errado na stream key, são os mais prováveis de estragar a transmissão.
* Não ultrapasse a resolução de 720 nem um bitrate de 2500 kbps.

## Live streaming

Você pode fazer livestream da sua câmera ou compartilhar sua tela usando o [Live streaming](/creator/content-creator-pt/scene-editor/operar-em-direto/live-streaming.md) feature do [Admin tools](/creator/content-creator-pt/scene-editor/operar-em-direto/scene-admin.md) smart item.

Este método de streaming usa a mesma arquitetura de comms usada para comunicações ao vivo entre jogadores. É fácil de configurar e tem muito menos atraso do que transmitir a partir de fontes externas.

1. Adicione um [Admin tools](/creator/content-creator-pt/scene-editor/operar-em-direto/scene-admin.md) smart item à sua scene, assim como um [Video player](/creator/content-creator-pt/scene-editor/interatividade/video-screen.md) smart item.
2. Publique sua scene, seja em um World ou em Genesis City.
3. Entre na scene como um jogador com permissão para usar as ferramentas de Admin.
4. Abra o console de Admin, selecione a **Vídeo** tab e, em seguida, selecione a **Live** functionalidade e clique no **Get Stream Key** .
5. Copie o **Server URL** e *Streaming key*\* para o seu software de streaming (por exemplo, OBS).
6. Pressione a tecla **Ative o botão** para iniciar a transmissão.

Em vez de adicionar um smart item Video player à sua scene, você também pode usar a URL `livekit-video://current-stream` como source de vídeo, para reproduzir a transmissão na sua scene. Você ainda precisará das ferramentas de Admin para obter a 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,
})
```

## Materiais de vídeo

Na maioria das vezes, você vai querer reproduzir vídeos em um [material Basic](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md#unlit-materials)unlit, em vez de um material PBR. Isso resulta numa imagem muito mais brilhante e nítida e é melhor para o desempenho.

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

Normalmente é recomendado reproduzir vídeos em materiais Basic unlit, pois isso é melhor para o desempenho. No entanto, se você quiser projetar um vídeo sobre um material PBR, tenha em mente que as propriedades padrão fazem o vídeo parecer bastante opaco. Você pode melhorar isso alterando outras propriedades do material. Aqui estão algumas configurações recomendadas para fazer o vídeo se destacar mais:

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

{% hint style="info" %}
**💡 Dica**: Como o vídeo é uma texture adicionada a um material, você também pode experimentar outras propriedades dos materiais, como tingi-lo com uma cor ou adicionar outras camadas de texture, por exemplo para produzir um efeito de tela suja.

Veja [materials](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md) para mais detalhes.
{% endhint %}

## Sobre Video Files

Os seguintes formatos de ficheiro são suportados:

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

Tem em conta que um ficheiro de vídeo aumenta o tamanho total da scene, o que faz com que a scene demore mais tempo a descarregar para os players que entram na tua scene. O tamanho do vídeo também pode fazer com que ultrapasses o [limitações da scene](/creator/content-creator-pt/scenes-sdk7/otimizacao/scene-limitations.md), uma vez que tens um máximo de 15 MB por parcel para usar. Recomendamos comprimir o vídeo o máximo possível, para que isso seja menos problemático.

Também recomendamos começar a reproduzir o vídeo quando o jogador estiver próximo ou realizar uma ação para acioná-lo. Começar a reproduzir um vídeo quando sua scene é carregada longe no horizonte afetará desnecessariamente o desempenho enquanto os jogadores visitam scenes vizinhas.

## Iniciar, pausar e parar um vídeo

Para começar a reproduzir o vídeo ou pausá-lo, defina o `playing` propriedade para *true* ou *false*. Se `playing` for definido como false, o vídeo fica pausado no último frame mostrado.

Você pode tornar uma tela alternável adicionando a ela um pointer event, como mostrado abaixo:

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

Para parar o vídeo e enviá-lo de volta ao primeiro frame, defina a `posição` property para 0. No exemplo a seguir, clicar no vídeo o interrompe.

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

## Configurar o video player

As seguintes propriedades opcionais estão disponíveis para definir no `VideoPlayer` component:

* `playing`: Determina se o vídeo está sendo reproduzido no momento. Se false, o vídeo fica pausado.

{% hint style="warning" %}
**📔 Nota**: Só pode haver um `VideoPlayer` component ativo por vez em cada scene.
{% endhint %}

* `playbackRate`: Altera a velocidade com que o vídeo é reproduzido. *1* por padrão.
* `volume`: Permite alterar o volume do áudio. *1* por padrão.
* `posição`: Permite definir uma posição inicial diferente no vídeo. Ela é expressa em segundos após o início original do vídeo. *-1* por padrão, o que faz com que ele comece no início real do vídeo.
* `loop`: Booleano que determina se o vídeo é reproduzido continuamente em loop ou se para após ser reproduzido uma vez. *false* por padrão.

## Reproduzir vários vídeos

Para evitar problemas de desempenho, cada scene só pode reproduzir uma video texture por vez. No entanto, uma scene pode reproduzir várias cópias da mesma video texture em várias telas diferentes. Isso não é restrito, pois impacta o desempenho consideravelmente menos do que reproduzir vídeos separados. Para reproduzir o mesmo vídeo em várias entities, basta atribuir a mesma instância do objeto de video texture aos `Material` components de cada entity de tela.

```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,
})
```

Observe que, no exemplo acima, só é necessário criar um `VideoPlayer` component, que controla o estado de ambas as telas de vídeo. Nesse caso, o component é atribuído à `screen1` entity, mas também poderia ser atribuído a qualquer outra entity na scene, não necessariamente a uma das telas.

## Eventos de vídeo

Lide facilmente com mudanças de estado em um vídeo, para responder quando um vídeo começa a ser reproduzido, é pausado, etc. Isso pode ser usado, por exemplo, para reproduzir animações em sincronização perfeita com um vídeo, garantindo que comecem ao mesmo tempo que o vídeo.

Use `videoEventsSystem.registerVideoEventsEntity` para definir uma função que é executada toda vez que o estado do vídeo atribuído a uma entity muda. Cada vez que o estado muda, sua função pode verificar o novo estado e responder adequadamente.

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

// ... Crie videoPlayerEntity com o 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
		}
	}
)
```

O objeto videoEvent passado como input para a função contém as seguintes propriedades:

* `currentOffset` (*number*): O valor atual da property `posição` no vídeo. Esse valor mostra os segundos após o início original do vídeo. *-1* por padrão, se o vídeo ainda não tiver começado a ser reproduzido.
* `state`: O novo status do vídeo, expresso como um valor do enum `VideoState` . Esse enum pode conter os seguintes valores possíveis:
  * `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* ): O comprimento em segundos do vídeo inteiro. *-1* se a duração for desconhecida.
* `timeStamp` ( *number*): Um *lamport* timestamp que é incrementado toda vez que o vídeo muda de estado.
* `tickNumber` (*number*): O momento em que o evento ocorreu, expresso como a contagem de ticks desde que a scene começou a ser executada.

### Último evento de vídeo

Consulte um vídeo para ver sua última mudança de estado usando `videoEventsSystem.getVideoState()`. Essa função sempre retorna o último valor de `VideoEvent` para o vídeo.

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

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

## Máscaras alfa em vídeos

Um truque interessante para ter telas de vídeo não retangulares é aplicar uma alpha texture sobre um plane. Você pode recortar parte do plane em qualquer forma que quiser.

Use a imagem a seguir para recortar seu vídeo em uma forma circular, com cantos transparentes.

![](/files/38af55f8bd8dad7a873c6695c89e5159890b5fa9)

```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/60327cfcf67be1e64f6a5e8774b0fe81d800f36d)

{% hint style="warning" %}
**📔 Nota**: Em versões anteriores, a property `alphaTexture` só estava presente em materiais PBR. Atualmente, ela só funciona em materiais basic.
{% endhint %}

## Reproduzir um vídeo em um modelo glTF

Você pode reproduzir um vídeo em um *glTF* model usando o [GltfNodeModifiers](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md#modify-gltf-materials) component. Veja [Modificar materiais glTF](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md#modify-gltf-materials) para mais detalhes.

Isso permite reproduzir seus vídeos em qualquer forma, não apenas em planes. Por exemplo, você pode reproduzir vídeos em uma tela curva ou até mesmo no corpo inteiro de um 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,
						}),
					},
				},
			},
		},
	],
})
```

O mapeamento do vídeo seguirá o mapeamento UV original que o model usa. Isso significa que, se o model tiver uma texture mapeada para uma parte específica dele, o vídeo será mapeado para essa mesma parte.

Você também pode usar a `GltfNodeModifiers` component para reproduzir um vídeo apenas em uma mesh específica dentro do model. Por exemplo, você pode reproduzi-lo em uma parede específica de um edifício, mesmo que o model cubra o edifício inteiro. Veja [Modificar materiais glTF](/creator/content-creator-pt/scenes-sdk7/essenciais-de-conteudo-3d/materials.md#modify-gltf-materials) para mais detalhes.

## Áudio espacial

Por padrão, o vídeo de um `VideoPlayer` component é global, o que significa que será ouvido com volume consistente em toda a sua scene. Se um jogador sair da scene, ele não ouvirá a transmissão de forma alguma.

Para tornar o áudio espacial, defina o `spatial` propriedade para *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,
})
```

O vídeo agora será ouvido a partir da posição da entity que possui o `VideoPlayer` component, e ficará mais alto à medida que o jogador se aproximar dele.

Controle o áudio espacial com as seguintes propriedades:

* `spatialMinDistance`: A distância mínima na qual o áudio se torna espacial. Se o jogador estiver mais perto, o áudio será ouvido em volume total. *0* por padrão.
* `spatialMaxDistance`: A distância máxima na qual o áudio é ouvido. Se o jogador estiver mais longe, o áudio será ouvido em volume 0. *60* por padrão

```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**: Alguns formatos de vídeo não suportam áudio espacial. Certifique-se de que a stream esteja codificada em *mp4*, *m4a*, ou *mov*.
{% endhint %}

## Análise de áudio

Você pode ler dados em tempo real de amplitude e frequência da faixa de áudio de uma `VideoPlayer` entity para acionar visuais reativos que sincronizem com a trilha sonora do vídeo. Veja [Análise de áudio](/creator/content-creator-pt/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-pt/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.
