> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-ko/sdk7/media/video-playing.md).

# 비디오 재생

씬에 비디오 스트리밍

장면에서 비디오를 표시하는 방법에는 세 가지가 있습니다:

* 장면 콘텐츠의 일부로 비디오 파일을 업로드합니다
* 외부 소스에서 비디오를 스트리밍합니다
* Decentraland cast를 통해 라이브 스트리밍합니다

{% hint style="info" %}
**💡 팁**: 다음에서 [Creator Hub의 Scene Editor](/creator/content-creator-ko/scene-editor/get-started/about-editor.md), 이를 위해 다음을 사용할 수 있습니다 **비디오 플레이어** [스마트 아이템](/creator/content-creator-ko/scene-editor/interactivity/smart-items.md) 이것을 노코드 방식으로 구현하려면.
{% endhint %}

어떤 경우든 다음이 필요합니다:

* 다음을 가진 엔티티: [기본 도형](/creator/content-creator-ko/sdk7/3d/shape-components.md) 평면, 큐브, 심지어 원뿔 같은 것.
* 하나의 [material](/creator/content-creator-ko/sdk7/3d/materials.md) 및 `VideoTexture` 해당 텍스처에 할당된
* 하나의 `VideoPlayer` 비디오의 상태를 제어하는 컴포넌트.

## 성능 고려 사항

스트리밍 비디오는 플레이어의 기기에 상당한 부하를 준다는 점을 기억하세요. 한 번에 하나 이상의 비디오를 재생하지 않는 것이 좋습니다.

장면에서 너무 많은 비디오가 동시에 재생되면 일부는 엔진에 의해 일시 중지됩니다. 어떤 화면을 멈출지의 우선순위는 플레이어와의 거리, 크기, 화면이 플레이어의 시야 안에 있는지 여부 등을 포함한 여러 요소를 기반으로 결정됩니다. 동시에 재생할 수 있는 최대 비디오 수는 플레이어의 품질 설정에 따라 달라집니다.

* 낮음: 1
* 중간: 5
* 높음: 10

또한 플레이어가 가까이 있거나 해당 동작을 수행할 때 영상을 재생하기 시작하는 것을 권장합니다. 장면이 지평선 저 멀리 로드될 때 영상을 재생하기 시작하면 플레이어가 인접한 장면을 방문하는 동안 성능에 불필요하게 영향을 줍니다.

또한 매우 높은 해상도의 비디오 스트리밍은 피하세요. 다음보다 높은 것은 사용하지 마세요 *HD*.

아래의 모든 예제 스니펫과 마찬가지로, 성능 부담을 줄이기 위해 Basic(비조명) 머티리얼에서 비디오를 재생하는 것이 이상적입니다.

## 비디오 표시

다음 지침은 세 가지 비디오 표시 옵션 모두에 적용됩니다:

1. 비디오 화면 역할을 할 엔티티를 생성합니다. 이 엔티티에 다음을 부여하세요 `MeshRenderer` 눈에 보이는 모양을 갖도록 하는 컴포넌트
2. 만드세요 `VideoPlayer` 컴포넌트, 스트리밍 URL 또는 비디오 파일 경로를 참조합니다. 여기에서 비디오의 `playing` 상태와 볼륨도 설정할 수 있습니다. 이 컴포넌트는 비디오 화면 엔티티나 장면의 다른 어떤 엔티티에도 할당할 수 있습니다.
3. 만드세요 `VideoTexture` 객체를, 그리고 그 객체의 `videoPlayerEntity` 속성에 다음을 소유한 엔티티를 할당합니다 `VideoPlayer` 컴포넌트를 추가해야 합니다.
4. 만드세요 `재질`, 이를 화면 엔티티에 할당하고, 그 `텍스처` 에 추가됩니다. `VideoTexture` 생성한 것입니다.

이 예제는 로컬에 저장된 비디오를 사용합니다 `/videos` 장면 프로젝트의 폴더:

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

외부 스트리밍 URL의 비디오를 사용하려면 2단계를 다음과 같이 변경하세요: `src` 의 속성 `VideoPlayer` 컴포넌트가 스트리밍 URL을 참조하도록 합니다.

```ts
// #2
VideoPlayer.create(screen, {
	src: 'https://vz-7c61c1b5-d59.b-cdn.net/ccea595a-b910-4de6-b160-092819db021d/playlist.m3u8',
	playing: true,
})
```

다음 [Decentraland cast를 사용한 스트리밍](#streaming-using-decentraland-cast) 이 세 번째 대체 방법을 사용하는 방법에 대한 자세한 내용은

## 외부 스트리밍 정보

스트리밍의 소스는 다음이어야 합니다 *https* URL (*http* URL은 지원되지 않습니다).

대부분의 인기 비디오 스트리밍 사이트의 비디오를 가리키는 URL을 붙여넣을 수 있습니다. 해당 플랫폼의 이용 약관에 유의하세요.

로컬 컴퓨터에 있는 비디오 파일을 스트리밍하려면, 이 비디오를 공개 Google Drive에 업로드한 뒤 링크를 붙여넣는 것이 가장 쉽습니다.

또 다른 방법은 다음과 같은 관리형 호스팅 제공업체를 사용하는 것입니다 [Vimeo](https://vimeo.com/) , [Livepeer Studio](https://livepeer.studio/) 또는 [Serraform](https://serraform.gitbook.io/streaming-docs/guides/decentraland-playback) 여기서 제공업체에 요금을 지불해 모든 스트리밍 인프라를 관리하도록 합니다.

가장 강력한 방법은 무료 소프트웨어를 사용해 자체 서버를 설정하되, 다음과 같은 플랫폼에서 호스팅 비용을 지불하는 것입니다 [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) 또는 [Cloudflare](https://www.cloudflare.com/products/cloudflare-stream/). 다음과 같은 것을 배포할 수 있습니다 [Node Media Server](https://github.com/illuspas/Node-Media-Server), 기본적으로 필요한 대부분을 제공합니다.

이 모든 옵션은 상황에 따라 장단점이 있습니다. 자신의 필요, 기술 수준, 예산을 고려해 무엇이 가장 좋은지 평가해야 합니다.

## 원활한 스트리밍을 위한 OBS 설정하기

[OBS](https://obsproject.com/) 스트림을 관리하는 데 널리 쓰이는 인기 있고 무료인 도구입니다.

장소의 스트림 키를 사용하든 자체 RTMP 서버를 사용하든, OBS 설정은 스트림 성공에 중요합니다. 안정적이고 일관된 연결을 목표로 해야 합니다.

### 간단한 OBS 설정

다음의 간단한 설정이 권장됩니다:

* 비트레이트 2500kbps(모든 Decentraland 장소에서 작동함)
* 오디오 비트레이트 160kbps
* 비디오 인코더 프리셋: 하드웨어 NVENC
* 오디오 인코더 AAC
* 최대 해상도: 720(DCL에서는 그보다 높으면 문제가 발생함)
* 프레임 속도 30fps

{% hint style="warning" %}
**📔 참고**: OBS에서 Multitrack streaming을 비활성화하세요. Settings > Stream에서 찾을 수 있습니다.
{% endhint %}

### 새 스트리머를 위한 조언

* 초반 사운드 체크는 장소와의 설정을 테스트하는 데 필수적입니다.
* 스트림 키의 숫자 하나가 틀리는 것과 같은 작은 오류가 스트림을 망칠 가능성이 가장 높습니다.
* 720 해상도나 2500 kbps 비트레이트를 넘기지 마세요.

## 라이브 스트리밍

카메라로 라이브스트리밍하거나 화면을 공유할 수 있습니다 [라이브 스트리밍](/creator/content-creator-ko/scene-editor/operate-live/live-streaming.md) 다음 기능을 사용하여 [관리자 도구](/creator/content-creator-ko/scene-editor/operate-live/scene-admin.md) 스마트 아이템.

이 스트리밍 방식은 플레이어 간 실시간 통신에 사용되는 것과 동일한 통신 아키텍처를 사용합니다. 설정이 쉽고 외부 소스에서 스트리밍하는 것보다 지연이 훨씬 적습니다.

1. 다음 항목을 추가하세요 [관리자 도구](/creator/content-creator-ko/scene-editor/operate-live/scene-admin.md) 장면에 스마트 아이템을 추가하고, 또한 [비디오 플레이어](/creator/content-creator-ko/scene-editor/interactivity/video-screen.md) 스마트 아이템.
2. 장면을 World 또는 Genesis City에 게시하세요.
3. Admin 도구를 사용할 권한이 있는 플레이어로 장면에 들어가세요.
4. Admin 콘솔을 열고 다음을 선택하세요 **비디오** 탭을 선택한 다음 다음을 선택하세요 **라이브** 기능을 클릭하세요 **스트림 키 가져오기** 버튼.
5. 다음을 복사하세요 **서버 URL** 과 *스트리밍 키*\*를 스트리밍 소프트웨어(예: OBS)에 입력하세요.
6. 다음을 누르세요: **활성화** 버튼을 눌러 스트리밍을 시작하세요.

장면에 Video player 스마트 아이템을 추가하는 대신, URL도 사용할 수 있습니다 `livekit-video://current-stream` 를 비디오 소스로 사용하여 장면에서 스트림을 재생할 수 있습니다. 스트림 키를 얻으려면 여전히 Admin 도구가 필요합니다.

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

## 비디오 머티리얼

대부분의 경우 비조명 [Basic 머티리얼](/creator/content-creator-ko/sdk7/3d/materials.md#unlit-materials)PBR 머티리얼보다 이것을 사용해 비디오를 재생하고 싶을 것입니다. 그러면 훨씬 더 밝고 선명한 이미지를 얻을 수 있으며 성능에도 더 좋습니다.

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

일반적으로 성능상 Basic 비조명 머티리얼에서 비디오를 재생하는 것이 권장됩니다. 하지만 비디오를 PBR 머티리얼에 투사하려는 경우 기본 속성 때문에 비디오가 다소 불투명하게 보일 수 있다는 점을 기억하세요. 머티리얼의 다른 속성을 변경하여 이를 향상시킬 수 있습니다. 비디오를 더 돋보이게 하는 데 권장되는 설정은 다음과 같습니다:

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

{% hint style="info" %}
**💡 팁**: 비디오는 머티리얼에 추가되는 텍스처이므로, 색상으로 틴트하거나 다른 텍스처 레이어를 추가하는 등 머티리얼의 다른 속성도 실험해볼 수 있습니다. 예를 들어 더러운 화면 효과를 만들 수 있습니다.

다음 [재질](/creator/content-creator-ko/sdk7/3d/materials.md) 자세한 내용은.
{% endhint %}

## 비디오 파일 정보

다음 파일 형식이 지원됩니다:

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

비디오 파일은 장면의 총 크기에 추가되며, 이로 인해 플레이어가 장면에 들어올 때 다운로드하는 데 더 오래 걸린다는 점을 유의하세요. 또한 비디오 크기 때문에 다음 한도를 초과할 수도 있습니다 [씬 제한 사항](/creator/content-creator-ko/sdk7/optimizing/scene-limitations.md), 사용 가능한 파셀당 최대 15MB가 있기 때문입니다. 가능한 한 영상을 최대한 압축하는 것을 권장합니다. 그래야 문제가 덜합니다.

플레이어가 가까이 있거나 트리거를 발생시키는 동작을 할 때 비디오 재생을 시작하는 것도 권장합니다. 장면이 지평선 멀리 로드될 때 비디오 재생을 시작하면, 플레이어가 주변 장면을 방문하는 동안 불필요하게 성능에 영향을 줍니다.

## 비디오 시작, 일시중지 및 중지

비디오 재생을 시작하거나 일시중지하려면 다음을 설정하세요 `playing` 속성을 *true* 또는 *false*. 만약 `playing` 가 false로 설정되면 비디오는 마지막으로 표시된 프레임에서 일시중지됩니다.

아래와 같이 포인터 이벤트를 추가하면 화면을 토글 가능하게 만들 수 있습니다:

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

비디오를 멈추고 첫 프레임으로 되돌리려면 다음을 설정하세요 `위치` 속성을 0으로 설정하세요. 다음 예제에서는 비디오를 클릭하면 중지됩니다.

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

## 비디오 플레이어 구성

다음 선택적 속성을 설정할 수 있습니다 `VideoPlayer` 컴포넌트:

* `playing`: 비디오가 현재 재생 중인지 결정합니다. false이면 비디오는 일시중지됩니다.

{% hint style="warning" %}
**📔 참고**: 플레이어의 품질 설정에 따라 동시에 재생할 수 있는 비디오는 제한됩니다. 장면에서 그 수보다 많이 재생되면 엔진이 우선순위가 가장 낮은 것들을 일시중지합니다. 참고: [성능 고려 사항](#performance-considerations).
{% endhint %}

* `playbackRate`: 비디오 재생 속도를 변경합니다. *1* 내보냅니다.
* `volume`: 오디오 볼륨을 변경할 수 있습니다. *1* 내보냅니다.
* `위치`: 비디오의 시작 위치를 다르게 설정할 수 있습니다. 비디오의 원래 시작 시점을 기준으로 한 초 단위로 표현됩니다. *0* 기본값으로, 비디오의 실제 시작 지점에서 재생을 시작합니다.
* `loop`: 비디오가 계속 반복 재생될지, 한 번 재생 후 멈출지를 결정하는 불리언 값입니다. *false* 내보냅니다.

## 여러 비디오 재생

성능 문제를 피하려면 동시에 재생되는 서로 다른 비디오 수를 적게 유지하세요. 엔진은 플레이어의 품질 설정에 따라 동시에 재생 가능한 비디오 수를 제한합니다(참고: [성능 고려 사항](#performance-considerations)). 그러나 장면에서는 여러 다른 화면에서 동일한 비디오 텍스처의 여러 복사본을 재생할 수 있습니다. 이는 별도의 비디오를 재생하는 것보다 성능에 미치는 영향이 훨씬 적기 때문에 제한되지 않습니다. 같은 비디오를 여러 엔티티에서 재생하려면 비디오 텍스처 객체의 동일한 인스턴스를 다음에 단순히 할당하세요 `재질` 각 화면 엔티티의 컴포넌트에.

```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://vz-7c61c1b5-d59.b-cdn.net/ccea595a-b910-4de6-b160-092819db021d/playlist.m3u8',
	playing: true,
})

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

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

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

위 예제에서는 하나만 생성하면 된다는 점에 유의하세요 `VideoPlayer` 컴포넌트가 두 비디오 화면의 상태를 모두 제어합니다. 이 경우 컴포넌트는 다음에 할당됩니다 `screen1` 엔티티이며, 반드시 화면 중 하나일 필요는 없고 장면의 다른 어떤 엔티티에도 할당할 수 있습니다.

## 비디오 이벤트

비디오에서 상태 변경을 쉽게 처리하여 비디오 재생 시작, 일시중지 등에 대응할 수 있습니다. 예를 들어 비디오와 완벽하게 동기화된 애니메이션을 재생하여 비디오와 동시에 시작되도록 할 수 있습니다.

다음을 사용하세요 `videoEventsSystem.registerVideoEventsEntity` 엔티티에 할당된 비디오의 상태가 변경될 때마다 실행되는 함수를 정의합니다. 상태가 바뀔 때마다 함수는 새 상태를 확인하고 그에 맞게 대응할 수 있습니다.

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

// ... VideoPlayer 컴포넌트, Transform, MeshRenderer.setPlane() 등을 사용해 videoPlayerEntity를 생성합니다. ...

videoEventsSystem.registerVideoEventsEntity(
	videoPlayerEntity,
	function (videoEvent) {
		console.log(
			'비디오 이벤트 - 상태: ' +
				videoEvent.state +
				'\n현재 오프셋:' +
				videoEvent.currentOffset +
				'\n비디오 길이:' +
				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
		}
	}
)
```

함수의 입력으로 전달되는 videoEvent 객체에는 다음 속성이 포함됩니다:

* `currentOffset` (*number*): 비디오의 `위치` 속성의 현재 값입니다. 이 값은 비디오의 원래 시작 시점 이후의 초를 보여줍니다. *-1* 비디오 재생이 시작되지 않은 경우.
* `state`: 새 비디오 상태이며 다음 값으로 표현됩니다 `VideoState` enum 값으로 나타낸 것입니다. 이 enum에는 다음과 같은 가능한 값이 있습니다:
  * `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* ): 전체 비디오의 길이(초)입니다. *-1* 길이를 알 수 없는 경우.
* `타임스탬프` ( *number*): 하나의 *lamport* 비디오 상태가 변경될 때마다 증가하는 타임스탬프입니다.
* `tickNumber` (*number*): 이벤트가 발생한 시점으로, 장면이 실행되기 시작한 이후의 틱 수로 표현됩니다.

이미 콜백이 있는 엔티티에 콜백을 다시 등록하면(예: 상태 변경 시 동작을 바꾸기 위해), 새 콜백이 이전 콜백을 대체하고 마지막으로 보고된 상태는 유지됩니다. 즉, 새 콜백은 이전 콜백에 이미 보고된 상태에 대해서는 다시 호출되지 않습니다.

### 엔티티가 등록되었는지 확인

다음을 사용하세요 `videoEventsSystem.hasVideoEventsEntity()` 엔티티에 이미 등록된 비디오 이벤트 콜백이 있는지 확인합니다.

```ts
if (videoEventsSystem.hasVideoEventsEntity(videoPlayerEntity)) {
	console.log('This entity already has a video event listener')
}
```

### 최신 비디오 이벤트

다음을 사용하여 비디오의 마지막 상태 변경을 조회하세요 `videoEventsSystem.getVideoState()`. 그러면 최신 `VideoEvent` 값을 엔티티에 대해 반환합니다, 또는 `undefined` 아직 이벤트가 보고되지 않았다면. 콜백을 등록하지 않고도 시스템에서 이를 호출하여 매 프레임 비디오 상태를 폴링할 수 있습니다.

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

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

## 비디오의 알파 마스크

직사각형이 아닌 비디오 화면을 만드는 멋진 방법은 평면 위에 알파 텍스처를 적용하는 것입니다. 평면의 일부를 원하는 어떤 모양으로든 잘라낼 수 있습니다.

다음 이미지를 사용해 비디오를 원형으로 자르고, 모서리는 투명하게 만드세요.

![](https://3980763956-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-4a71dbd3206e2ccafdba8990cb5099b48c9a97cf%2Fcircle_mask.png?alt=media\&token=c1e0f780-7fd0-4e06-a27f-00222068bf81)

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

![](https://3980763956-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-29eeafc704d19336cc3b0dc023c91e278b4bcd94%2Fcircular-video-screen.png?alt=media\&token=13d1560a-3d64-4a17-943c-25338f931f48)

{% hint style="warning" %}
**📔 참고**: 이전 버전에서는 `alphaTexture` 속성은 PBR 머티리얼에만 존재했습니다. 현재는 Basic 머티리얼에서만 작동합니다.
{% endhint %}

## glTF 모델에서 비디오 재생

다음에서 비디오를 재생할 수 있습니다 *glTF* 모델의 재질을 [GltfNodeModifiers](/creator/content-creator-ko/sdk7/3d/materials.md#modify-gltf-materials) 컴포넌트가 붙은 모든 플레이어를 순회하세요. 자세한 내용은 [glTF 재질 수정](/creator/content-creator-ko/sdk7/3d/materials.md#modify-gltf-materials) 자세한 내용은.

이를 통해 평면뿐 아니라 어떤 모양이든 비디오를 재생할 수 있습니다. 예를 들어 곡면 화면이나 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://vz-7c61c1b5-d59.b-cdn.net/ccea595a-b910-4de6-b160-092819db021d/playlist.m3u8',
	playing: true,
})

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

비디오의 매핑은 모델이 사용하는 원래 UV 매핑을 따릅니다. 즉, 모델에서 특정 부분에 매핑된 텍스처가 있다면 비디오도 그 같은 부분에 매핑됩니다.

다음도 사용할 수 있습니다. `GltfNodeModifiers` 모델 내부의 특정 메시에만 비디오를 재생하는 컴포넌트입니다. 예를 들어 모델이 건물 전체를 차지하더라도 건물의 특정 벽에만 재생할 수 있습니다. 참고: [glTF 재질 수정](/creator/content-creator-ko/sdk7/3d/materials.md#modify-gltf-materials) 자세한 내용은.

## 공간 오디오

기본적으로 다음의 비디오 `VideoPlayer` 컴포넌트는 전역으로, 장면 전체에서 일관된 볼륨으로 들린다는 뜻입니다. 플레이어가 장면 밖으로 나가면 스트리밍은 전혀 들리지 않습니다.

오디오를 공간 음향으로 만들려면 다음을 설정하세요 `spatial` 속성을 *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,
})
```

이제 비디오는 다음을 소유한 엔티티의 위치에서 들리게 됩니다 `VideoPlayer` 컴포넌트이며, 플레이어가 가까워질수록 더 크게 들립니다.

다음 속성으로 공간 음향을 제어하세요:

* `spatialMinDistance`: 오디오가 공간 음향으로 전환되는 최소 거리입니다. 플레이어가 더 가까우면 오디오는 최대 볼륨으로 들립니다. *0* 내보냅니다.
* `spatialMaxDistance`: 오디오가 들리는 최대 거리입니다. 플레이어가 더 멀리 있으면 오디오는 0 볼륨으로 들립니다. *60* 기본값으로

```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" %}
**📔 참고**: 일부 비디오 형식은 공간 음향을 지원하지 않습니다. 스트림이 다음 형식으로 인코딩되었는지 확인하세요 *mp4*, *m4a*또는 *mov*.
{% endhint %}

## 오디오 분석

다음의 오디오 트랙에서 실시간 진폭 및 주파수 데이터를 읽을 수 있습니다 `VideoPlayer` 엔티티를 사용해 비디오 사운드트랙과 동기화되는 반응형 비주얼을 구동할 수 있습니다. 참고: [오디오 분석](/creator/content-creator-ko/sdk7/media/audio-analysis.md).

{% hint style="info" %}
**💡 팁**: 프리미티브가 아닌 GLTF 모델에서 재생되는 비디오를 보려면 다음을 참조하세요 [`74,-8-gltfnodemodifier`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/74,-8-gltfnodemodifier) 테스트 장면. 여기서는 다음을 사용해 특정 GLTF 노드에 HLS 스트림을 전달합니다 `GltfNodeModifiers` 비디오 텍스처
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/creator/content-creator-ko/sdk7/media/video-playing.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
