@sgrsoft/vpe-react-sdk
v2.4.24
Published
<img src="https://tkmenfxu2702.edge.naverncp.com/profile/202602/76303c7f18eb7e2e70c0e1a152419545.png" style="max-width:600px">
Readme
Video Player Enhancement React SDK
React 를 지원하는 Video Player Enhancement SDK입니다. hls.js/dashjs는 번들에 포함되지 않으며 외부에서 주입합니다.
개발자 가이드: https://developer.vpe.naverncp.com/ UI 레이아웃 에디터: https://vpe-player-editor.web.app/ 콘솔: https://console.ncloud.com/vpe/playerManagement
주요 기능
- JSON 레이아웃 시스템: PC/모바일/전체화면 × VOD/Live 분기, 런타임 머지·전환
- 커스텀 컴포넌트 삽입: React 컴포넌트/HTML을 컨트롤바에 직접 배치
- 기본 동작 오버라이드: 재생·일시정지·탐색 등 기본 동작 가로채기
- HLS & DASH 외부 주입:
hls.js,dashjs를 props로 주입 - 멀티 DRM: Widevine, PlayReady, FairPlay 통합 (One Click Multi DRM / DoveRunner)
- 자막: WebVTT / SRT 외부 자막, HTML·native 렌더링
- OTT 기능: 인트로/오프닝/엔딩 스킵, 연령등급·콘텐츠 경고, 시리즈 메타데이터
- Pre-roll 광고: Google IMA (VAST/VMAP) 연동
- 워터마크 / Signed URL 토큰 갱신
지원 런타임 및 패키지
Video Player Enhancement V2는 Web / Mobile / TV에서 동일한 API로 동작합니다. 본 저장소는 그중 Web(React) SDK입니다.
| 패키지 | 환경 |
| --- | --- |
| @sgrsoft/vpe-react-sdk | React / Next.js 플레이어 컴포넌트 (본 패키지) |
| vpe-react-native | iOS / Android React Native 플레이어 |
| @sgrsoft/vpe-reactnative-tv-sdk | Android TV / Apple TV / Fire TV |
| vpe-drm-helper | 멀티 DRM 라이선스 토큰 생성 헬퍼 |
지원 버전
- React 최소 버전:
18.0.0(React 18.x/19.x 지원) - Next.js 권장 버전:
- React 18 사용 시:
14.2+ - React 19 사용 시:
15.x+
Modules 이용하기
npm 이용한 설치
npm install @sgrsoft/vpe-react-sdkyarn 이용한 설치
yarn add @sgrsoft/vpe-react-sdkpnpm 이용한 설치
pnpm add @sgrsoft/vpe-react-sdk스트리밍 라이브러리 설치(선택)
npm install hls.js dashjs플레이어 생성
React (ESM)
import Hls from "hls.js";
import dashjs from "dashjs";
import { VpePlayer } from "@sgrsoft/vpe-react-sdk";
export function App() {
return (
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
hls={Hls}
dashjs={dashjs}
options={{
aspectRatio: "16/9",
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4",
poster: "https://CDN_DOMAIN/example_video_01.png",
},
],
}}
/>
);
}컴포넌트 Props
VpePlayer에 직접 전달하는 최상위 props입니다. 재생 동작 세부 설정은 options로 전달합니다.
| Prop | 타입 | 필수 | 설명 |
| --- | --- | --- | --- |
| accessKey | string | Yes | NCP Sub Account access key (Master API key 사용 금지) |
| platform | "pub" \| "gov" | No | 재생 환경 (민간/공공). 기본 pub |
| stage | "prod" \| "stg" | No | 호출 스테이지. 기본 prod |
| hls | Hls | No | hls.js 라이브러리 주입 (HLS 재생 시) |
| dashjs | dashjs | No | dashjs 라이브러리 주입 (DASH 재생 시) |
| options | PlayerOptions | No | 플레이어 옵션 객체 |
| layout | ControlBarLayout | No | 컨트롤바 레이아웃 |
| onEvent | (event) => void | No | 이벤트 콜백 |
| ref | PlayerHandle | No | 명령형 제어 핸들 |
보안:
accessKey는 반드시 Sub Account 키를 사용하세요. Master API key가 노출되면 NCP 전체 리소스가 탈취될 수 있습니다.
Next.js (App Router)
클라이언트 컴포넌트("use client")에서 사용합니다. hls.js는 top-level import해도 안전하지만, dashjs는 SSR 충돌을 피하기 위해 useEffect 내 dynamic import로 주입하세요.
"use client";
import { useEffect, useState } from "react";
import { VpePlayer } from "@sgrsoft/vpe-react-sdk";
export default function Player() {
const [dashjs, setDashjs] = useState<unknown>(null);
useEffect(() => {
import("dashjs").then((m) => setDashjs(m.default ?? m));
}, []);
if (!dashjs) return null;
return (
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
dashjs={dashjs}
options={{ playlist: [{ file: "https://CDN_DOMAIN/manifest.mpd" }] }}
/>
);
}platform 안내
platform은 재생 환경을 구분하는 필수 설정입니다.
pub: 민간 클라우드 환경gov: 공공 클라우드 환경
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
platform="pub"
hls={Hls}
dashjs={dashjs}
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
}}
/>옵션 레퍼런스
options는 vpe-core-sdk에서 검증/보정됩니다. 기본값은 코어에서 결정되는 항목이 많아, 명시되지 않은 경우는 “vpe-core-sdk 기본값”으로 표기합니다.
| 옵션 | 타입 | 기본값 | 필수 | 설명 |
| --- | --- | --- | --- | --- |
| autostart | boolean | vpe-core-sdk 기본값 | No | 자동 재생 여부 |
| muted | boolean | vpe-core-sdk 기본값 | No | 시작 시 음소거 |
| aspectRatio | string | vpe-core-sdk 기본값 | No | 비율 ("16/9", "9/16" 등) |
| objectFit | "contain" \| "cover" \| "fill" \| "scale-down" \| "stretch" | vpe-core-sdk 기본값 | No | 비디오 fit 방식 |
| controls | boolean | vpe-core-sdk 기본값 | No | 기본 컨트롤 표시 |
| keyboardShortcut | boolean | vpe-core-sdk 기본값 | No | 키보드 단축키 |
| seekingPreview | boolean | vpe-core-sdk 기본값 | No | 시킹 프리뷰 표시 |
| touchGestures | boolean | vpe-core-sdk 기본값 | No | 터치 제스처 사용 |
| startMutedInfoNotVisible | boolean | vpe-core-sdk 기본값 | No | 시작 음소거 안내 표시 여부 |
| lang | string | vpe-core-sdk 기본값 | No | UI 언어 |
| ui | string | vpe-core-sdk 기본값 | No | UI 모드/스킨 키 |
| controlBtn | object | vpe-core-sdk 기본값 | No | 버튼 표시 on/off 설정 |
| progressBarColor | string | vpe-core-sdk 기본값 | No | 진행바 색상 |
| controlActiveTime | number | 3000 | No | 컨트롤 자동 숨김(ms) |
| playIndex | number | 0 | No | 플레이리스트 시작 인덱스 |
| modalFullscreen | boolean | vpe-core-sdk 기본값 | No | 모달 형태 전체화면 (Fullscreen API 미사용) |
| captionType | "html" \| "native" | "html" | No | 자막 렌더링 방식 (자막 섹션 참고) |
| captionStyle | object | vpe-core-sdk 기본값 | No | 자막 스타일 (html 모드에서만 전체 적용) |
| retry | boolean | object | vpe-core-sdk 기본값 | No | 에러 시 재시도 ({ count, delay }) |
| icon | IconOverrides | - | No | 컨트롤 아이콘 커스터마이징 |
| playRateSetting | number[] | vpe-core-sdk 기본값 | No | 재생 속도 리스트 |
| autoPause | boolean | vpe-core-sdk 기본값 | No | 자동 정지 |
| repeat | boolean | vpe-core-sdk 기본값 | No | 반복 재생 |
| setStartTime | string | null | vpe-core-sdk 기본값 | No | 시작 시간 (문자열) |
| lowLatencyMode | boolean | vpe-core-sdk 기본값 | No | 저지연 모드 |
| descriptionNotVisible | boolean | vpe-core-sdk 기본값 | No | 메타 설명 숨김 |
| iosFullscreenNativeMode | boolean | vpe-core-sdk 기본값 | No | iOS 네이티브 전체화면 |
| visibleWatermark | boolean | vpe-core-sdk 기본값 | No | 워터마크 표시 |
| watermarkText | string | vpe-core-sdk 기본값 | No | 워터마크 텍스트 |
| watermarkConfig | object | vpe-core-sdk 기본값 | No | 워터마크 상세 설정 |
| devTestAppId | string | vpe-core-sdk 기본값 | No | 개발 테스트용 AppId |
| token | string | vpe-core-sdk 기본값 | No | 스트림 URL 토큰 |
| override | object | vpe-core-sdk 기본값 | No | 이벤트/동작 오버라이드 |
| ads | AdOptions | - | No | Pre-roll 광고 설정 (Google IMA) |
| layout | ControlBarLayout | Variant | Responsive | SDK 기본 레이아웃 | No | 컨트롤바 레이아웃 |
참고
playlist등 재생 관련 옵션은vpe-core-sdk에서 확장 처리됩니다. 예시는 위 “플레이어 생성” 섹션을 참고하세요.
옵션 사용 예시
아래 예시는 각 옵션을 단독으로 적용하는 형태입니다. 공통으로 accessKey와 playlist를 포함한 실행 코드를 제공합니다.
autostart
- 자동 재생 여부를 설정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
autostart: true,
}}
/>muted
- 시작 시 음소거를 적용합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
muted: true,
}}
/>aspectRatio
- 플레이어 비율을 지정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
aspectRatio: "16/9",
}}
/>objectFit
- 비디오 표시 방식을 설정합니다.
- cover | contain | fill | stretch
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
objectFit: "cover",
}}
/>controls
- 기본 컨트롤 표시 여부를 설정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
controls: true
}}
/>keyboardShortcut
- 키보드 단축키를 활성화합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
keyboardShortcut: true,
}}
/>seekingPreview
- 시킹 프리뷰 표시 여부를 설정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
seekingPreview: true,
}}
/>touchGestures
- 터치 제스처 사용 여부를 설정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
touchGestures: true,
}}
/>startMutedInfoNotVisible
- 시작 음소거 안내 문구 표시 여부를 설정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
startMutedInfoNotVisible: true,
}}
/>lang
- UI 언어를 설정합니다.
- 설정하지 않거나 'auto'로 설정되면 브라우저 or 기기설정을 따라갑니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
lang: "ko",
}}
/>ui
- UI 모드/스킨 키를 설정합니다.
- auto | pc | mobile
- 설정하지 않거나 'auto'로 설정되면 브라우저 가로폭이나 기기를 따라갑니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
ui: "auto",
}}
/>controlBtn
- 컨트롤 버튼 표시 여부를 설정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
controlBtn: {
play: true,
fullscreen: true,
progressBar: true,
volume: true,
times: true,
pictureInPicture: true,
setting: true,
subtitle: true,
},
}}
/>progressBarColor
- 진행바 색상을 설정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
progressBarColor: "#00E0FF",
}}
/>controlActiveTime
- 컨트롤 자동 숨김 시간을 설정합니다(ms).
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
controlActiveTime: 3000,
}}
/>playRateSetting
- 재생 속도 옵션을 설정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
playRateSetting: [0.5, 1, 1.5, 2],
}}
/>autoPause
- 탭 전환/창 최소화 시 자동 정지를 설정합니다.
- 인앱의 웹뷰 상황에서는 정상동작하지 않습니다. (앱의 백그라운드 상황은 지원하지 않습니다.)
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
autoPause: true,
}}
/>repeat
- 반복 재생을 설정합니다.
- 여러 영상의 플레이리스트 상태라면 모든 영상이 재생 후 맨처음 영상으로 이동하여 반복 재생됩니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
repeat: true,
}}
/>setStartTime
- 시작 시간을 지정합니다(문자열).
- 기존적으로 UTC 시간을 지원하지만, 로컬포멧도 지원합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
setStartTime: "2026-02-03T09:00:00Z",
}}
/>lowLatencyMode
- 저지연 모드를 활성화합니다.
- LL-HLS를 제대로 재생하려면 해당 옵션이 필수입니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
lowLatencyMode: true,
}}
/>descriptionNotVisible
- 메타 설명 표시 여부를 설정합니다.
- 기본값은 false 이며 ture 설정시 화면에 표시되지 않습니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
descriptionNotVisible: true,
}}
/>iosFullscreenNativeMode
- iOS 네이티브 전체화면 모드를 사용합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
iosFullscreenNativeMode: true,
}}
/>visibleWatermark
- 워터마크 표시 여부를 설정합니다.
- 이 옵션은 Video Player Enhancement 콘솔 옵션에서만 적용 가능합니다.
- 코드사에서 이 옵션을 수정할 수 없습니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
visibleWatermark: true,
}}
/>watermarkText
- 워터마크 텍스트를 지정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
watermarkText: "[email protected]",
}}
/>watermarkConfig
- 워터마크 상세 설정을 지정합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
watermarkConfig: {
randPosition: true, //위치 랜덤 여부
randPositionInterVal: 5000, //랜덤 주기 (ms)
x: 10, //randPosition 이 false 라면 워터마크 위치 고정시 X값 (단위 %)
y: 10, //randPosition 이 false 라면 워터마크 위치 고정시 Y값 (단위 %)
opacity: 0.4, //워터마크 투명도
},
}}
/>token
- 스트림 URL에 자동으로 붙일 토큰을 설정합니다.
- 글로벌엣지 CDN 보안 토큰을 설정합니다. hls/dash 적용시 하위 ts 파일까지 함께 적용됩니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
token: "token=...",
}}
/>override
- 내부 동작을 오버라이드합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
override: {
error: (error) => console.log(error), //에러 발생시 실행
nextSource: () => {}, //다음 동영상 이동시 실행
prevSource: () => {}, //이전 동영상 이동시 실행
pip: { //pip 오버라이드, pip를 직접 구현할때 사용
on: () => {},
off: () => {},
},
},
}}
/>ads
- Pre-roll 광고를 설정합니다. Google IMA SDK 기반으로 동작합니다.
tagUrl에 VAST 태그 URL을 전달하면 콘텐츠 재생 전에 광고가 자동 재생됩니다.- 광고 재생 중 콘텐츠 비디오는 자동으로 일시정지되고, 컨트롤바가 숨겨집니다.
- 광고 완료/스킵/에러 후 콘텐츠가 자동 재생됩니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
hls={Hls}
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example.m3u8"
}
],
autostart: true,
muted: true,
ads: {
tagUrl: "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=",
enabled: true, // 기본값: true. false로 설정하면 광고 비활성화
},
}}
/>AdOptions 타입
| 옵션 | 타입 | 기본값 | 필수 | 설명 |
| --- | --- | --- | --- | --- |
| tagUrl | string | - | Yes | VAST/VMAP 광고 태그 URL |
| enabled | boolean | true | No | 광고 활성화 여부 |
layout
- 레이아웃을 옵션으로 전달해 컨트롤바를 변경합니다.
- 레이아웃 Video Player Enhancement 시스템은 콘솔에 UI 편집툴을 이용하여 작성할 수 있습니다.
- PC | Mobile | FullScreen 상태에 vod | live 별로 레이아웃 구성 지원합니다.
- 전체 레이아웃이 아닌 일부만 입력한다면 기존 레이아웃과 머지되어 동작합니다.
- 자세한건 하위 레이아웃 시스템에 기술되어 있습니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
layout: {
pc:{
vod: {
bottom: [{ key: "play", items: ["PlayBtn"] }],
},
live:{
bottom: [{ key: "play", items: ["PlayBtn"] }],
}
}
},
}}
/>레이아웃 시스템
layout props로 컨트롤바를 커스터마이즈할 수 있습니다.
기본 레이아웃
const layout = {
top: [],
center: [{ key: "bigPlayBtn", items: ["BigPlayBtn"] }],
bottom: [
{ key: "play", items: ["PlayBtn"], wrapper: "Group", noPadding: true },
{ key: "volume", items: ["VolumeBtn"], wrapper: "Group" },
{ key: "time", items: ["TimeBtn"], wrapper: "Group" },
{ key: "blank", wrapper: "Blank", items: [] },
{ key: "right", items: ["SubtitleBtn", "FullscreenBtn"], cap: 2, wrapper: "Group" },
],
};
<VpePlayer layout={layout} />;라이브/다시보기 분기
const layoutVariant = {
live: { /* live 전용 레이아웃 */ },
vod: { /* vod 전용 레이아웃 */ },
};
<VpePlayer layout={layoutVariant} />;반응형 레이아웃
const responsiveLayout = {
pc: {
live: { /* pc live */ },
vod: { /* pc vod */ },
},
mobile: {
live: { /* mobile live */ },
vod: { /* mobile vod */ },
},
fullscreen: {
live: { /* fullscreen live */ },
vod: { /* fullscreen vod */ },
},
breakpoint: 768,
};
<VpePlayer layout={responsiveLayout} />;레이아웃 실시간 변경
Ref 인스턴스에서 layout(nextLayout, merge?)를 호출하면 즉시 반영됩니다.
import { setup } from "@sgrsoft/vpe-react-sdk";
const instance = setup("#video", "YOUR_ACCESS_KEY", {
options: {
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
},
});
instance.layout({
bottom: [{ key: "custom", items: ["SettingBtn"] }],
});자막 (Caption)
외부 자막 파일(WebVTT / SRT)은 반드시 playlist[].vtt 또는 playlist[].srt 배열에 등록합니다.
options.subtitles, options.captions, <track> 요소 등은 동작하지 않습니다.
WebVTT 자막 등록
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
hls={Hls}
options={{
playlist: [
{
file: "https://CDN_DOMAIN/master.m3u8",
vtt: [
{ id: "ko", src: "https://CDN_DOMAIN/ko.vtt", label: "한국어", default: true },
{ id: "en", src: "https://CDN_DOMAIN/en.vtt", label: "English" },
{ id: "ja", src: "https://CDN_DOMAIN/ja.vtt", label: "日本語" },
],
},
],
}}
/>| 필드 | 타입 | 필수 | 설명 |
| --- | --- | --- | --- |
| src | string | Yes | 자막 파일 URL |
| id | string | No | 언어 코드 등 식별자 ("ko", "en") |
| label | string | No | 설정 메뉴에 표시될 라벨 |
| default | boolean | No | 초기 선택 자막 (배열 중 1개만) |
| file | string | No | V1 호환 alias. src가 없을 때만 사용 |
SRT 자막 등록
playlist[].srt 배열에 등록하면 SDK가 런타임에 SRT를 WebVTT로 변환합니다.
브라우저는 SRT를 native로 인식하지 못하므로, SRT 사용 시 captionType은 "html"로 강제됩니다.
vtt와 srt를 동시에 지정하면 vtt가 우선합니다.
options={{
playlist: [
{
file: "https://CDN_DOMAIN/master.m3u8",
srt: [
{ id: "ko", src: "https://CDN_DOMAIN/ko.srt", label: "한국어", default: true },
],
},
],
}}자막 렌더링 방식 (captionType)
captionType은 자막 소스 등록이 아니라 렌더링 방식을 결정합니다.
| 항목 | "html" (기본) | "native" |
| --- | --- | --- |
| 렌더링 | 플레이어 위 별도 div 오버레이 | 브라우저 기본 ::cue |
| captionStyle | 모두 적용 | 무시됨 |
| OS 접근성 설정 | 무시 (일관된 스타일) | OS 설정 따름 (iOS/Android) |
| 추천 케이스 | 디자인 일관성, 다크모드 | 접근성 우선 |
자막 스타일 (captionStyle)
captionType: "html"에서만 전체 적용됩니다. fontSize, lineHeight, bottomOffset, sidePadding은 단일값 또는 { pc, mobile } 객체를 지원합니다.
options={{
playlist: [{ file: "https://CDN_DOMAIN/master.m3u8", vtt: [/* ... */] }],
captionType: "html",
captionStyle: {
fontSize: { pc: 20, mobile: 14 },
fontFamily: "Pretendard, sans-serif",
color: "#ffffff",
backgroundColor: "rgba(0,0,0,0.5)",
opacity: 1,
lineHeight: { pc: 1.4, mobile: 1.3 },
edgeStyle: "uniform", // none | dropshadow | raised | depressed | uniform
bottomOffset: { pc: 50, mobile: 20 },
sidePadding: { pc: 80, mobile: 40 },
padding: "5px 10px",
},
}}OTT 기능
playlist 아이템에 OTT 메타데이터를 추가하면 스킵 버튼, 진입 안내, 시리즈 UI가 자동으로 표시됩니다.
구간 스킵 (인트로/오프닝/엔딩)
start("HH:MM:SS")부터 duration(초) 구간에 스킵 버튼이 노출되며, 클릭 시 start + duration 시점으로 이동합니다.
options={{
playlist: [
{
file: "https://CDN_DOMAIN/episode_01.m3u8",
intro: { start: "00:00:00", duration: 10 }, // 인트로 스킵
opening: { start: "00:00:30", duration: 90 }, // 오프닝 스킵
ending: { start: "00:42:00", duration: 180 }, // 다음화/엔딩
},
],
}}각 스킵 발생 시 introSkip / openingSkip / endingSkip 이벤트가 발생합니다.
연령등급 / 콘텐츠 경고
영상 진입 시 오버레이로 자동 표시됩니다.
options={{
playlist: [
{
file: "https://CDN_DOMAIN/episode_01.m3u8",
ageRating: "15", // "all" | "12" | "15" | "19"
contentWarnings: ["violence", "language"],
// sexuality | violence | language | drugs | horror | imitation | provocative
},
],
}}시리즈 메타데이터 (description)
title, profile_name은 다국어 객체({ ko, en, ja })도 지원합니다.
options={{
playlist: [
{
file: "https://CDN_DOMAIN/episode_01.m3u8",
description: {
title: { ko: "시즌1 1화: 첫 만남", en: "S1 E1: First Meeting" },
profile_name: "OTT 스튜디오",
profile_image: "https://CDN_DOMAIN/logo.png",
created_at: "2026-05-15",
},
},
],
}}자동재생 정책 안내
autostart: true 만으로는 모든 진입 방식에서 자동재생이 보장되지 않습니다. 브라우저 정책상 사용자 제스처 없이 소리가 있는 자동재생은 차단됩니다.
| 진입 방식 | 음소거 자동재생 | 무음소거 자동재생 | | --- | --- | --- | | 새로고침 / URL 직접 입력 / 새 탭 | 가능 | 차단 | | 링크 클릭 진입 | 가능 | 브라우저별 상이 | | iOS Safari | 가능 (playsInline) | 항상 차단 |
모든 환경에서 자동재생을 보장하려면 autostart와 muted를 함께 사용하세요.
options={{
playlist: [{ file: "https://CDN_DOMAIN/master.m3u8" }],
autostart: true,
muted: true, // 모든 환경에서 자동재생 허용
}}무음소거 자동재생을 시도하다 실패하면 error 이벤트에서 음소거 폴백 후 "소리 켜기" 버튼을 노출하는 패턴을 권장합니다.
전체화면 동작 안내
플랫폼별 전체화면 동작이 다릅니다.
| 플랫폼 | 동작 | | --- | --- | | Desktop / Android Chrome | 표준 Fullscreen API. SDK 커스텀 컨트롤 유지 | | iPadOS (13.4+) | 표준 Fullscreen API 지원 | | iPhone Safari | Fullscreen API 미지원 → iOS 네이티브 비디오 플레이어로 전환. SDK 커스텀 컨트롤바가 iOS 기본 컨트롤로 대체됨 |
iosFullscreenNativeMode(기본 동작)와 modalFullscreen 옵션으로 iOS 전체화면 방식을 조정할 수 있습니다.
DoveRunner(Pallycon) DRM 예제
NCP One Click Multi DRM 외에 DoveRunner(Pallycon) 라이선스 서버도 사용할 수 있습니다. pallycon-customdata-v2 토큰은 백엔드에서 생성해 전달합니다(SiteKey 노출 금지).
options={{
playlist: [
{
file: "https://contents.pallycon.com/.../stream.mpd",
drm: {
"com.widevine.alpha": {
licenseUri: "https://license-global.pallycon.com/ri/licenseManager.do",
licenseRequestHeader: {
"pallycon-customdata-v2": "BACKEND_ISSUED_TOKEN",
},
},
"com.apple.fps": {
src: "https://contents.pallycon.com/.../master.m3u8",
certificateUri: "https://license-global.pallycon.com/ri/fpsKeyManager.do?siteId=SITE_ID",
licenseUri: "https://license-global.pallycon.com/ri/licenseManager.do",
licenseRequestHeader: {
"Content-type": "application/x-www-form-urlencoded",
"pallycon-customdata-v2": "BACKEND_ISSUED_TOKEN",
},
},
},
},
],
}}DRM 라이선스 서명/토큰은 항상 백엔드에서 생성하세요. NCP DRM은 DRM 권한 전용 Sub Account 키만 사용합니다.
플레이어 메소드 (Ref)
ref로 전달되는 PlayerHandle에서 아래 메소드를 사용할 수 있습니다.
import { useRef } from "react";
import { VpePlayer, type PlayerHandle } from "@sgrsoft/vpe-react-sdk";
export function App() {
const playerRef = useRef<PlayerHandle>(null);
return (
<>
<VpePlayer
ref={playerRef}
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
}}
/>
<button onClick={() => playerRef.current?.play()}>Play</button>
<button onClick={() => playerRef.current?.pause()}>Pause</button>
</>
);
}지원 메소드
| 메소드 | 시그니처 | 설명 |
| --- | --- | --- |
| play | play() | 재생 시작 |
| pause | pause() | 재생 일시정지 |
| mute | mute() | 음소거 |
| prev | prev() | 이전 플레이리스트 아이템 |
| next | next() | 다음 플레이리스트 아이템 |
| fullscreen | fullscreen() | 전체화면 토글 |
| fullscreenOn | fullscreenOn() | 전체화면 진입 |
| fullScreenOff | fullScreenOff() | 전체화면 종료 |
| pip | pip() | PIP 토글 |
| volume | volume(vol?) | 볼륨 설정 |
| uiHidden | uiHidden() | UI 숨김 |
| uiVisible | uiVisible() | UI 표시 |
| currentTime | currentTime(time?) | 현재 재생 시간 설정 |
| controlBarActive | controlBarActive() | 컨트롤바 활성화 |
| controlBarDeactive | controlBarDeactive() | 컨트롤바 비활성화 |
| tokenChange | tokenChange(token) | 토큰 변경 |
| layout | layout(nextLayout, merge?) | 레이아웃 변경 |
| changeUiMode | changeUiMode(mode) | UI 모드 변경 |
| changePlayMode | changePlayMode(mode) | 재생 모드 변경 |
| addNextSource | addNextSource(source) | 다음 영상 플레이리스트에 추가 |
| addPrevSource | addPrevSource(source) | 이전 영상 플레이리스트에 추가 |
| changeOptions | changeOptions(nextOptions) | 옵션 부분 변경 (런타임 적용) |
| on | on(type, callback) | 특정 이벤트 구독 (해제 함수 반환, "*"는 전체 구독) |
| destroy | destroy() | 플레이어 인스턴스 정리 |
addNextSource / addPrevSource
현재 재생 중인 영상의 다음/이전 위치에 새로운 영상을 동적으로 추가합니다.
// 단일 영상 추가
playerRef.current?.addNextSource({
file: "https://CDN_DOMAIN/new_video.mp4",
poster: "https://CDN_DOMAIN/new_poster.jpg",
});
// 여러 영상 동시 추가
playerRef.current?.addPrevSource([
{ file: "https://CDN_DOMAIN/video_1.mp4" },
{ file: "https://CDN_DOMAIN/video_2.mp4" },
]);이벤트
onEvent로 이벤트를 수신합니다.
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example_video_01.mp4"
}
],
}}
onEvent={(event) => {
if (event.type === "error") {
console.log(event.data);
}
}}
/>;지원 이벤트
| 이벤트 | 설명 | | --- | --- | | stateChange | 플레이어 상태 스냅샷 변경 | | ready | 초기화 완료 및 재생 준비 | | play | 재생 시작 | | pause | 재생 일시정지 | | ended | 재생 종료 | | fullscreen | 전체화면 진입 | | fullscreenExit | 전체화면 종료 | | loadingStart | 로딩 시작 | | loadingEnd | 로딩 종료 | | bufferingStart | 버퍼링 시작 | | bufferingEnd | 버퍼링 종료 | | seeking | 탐색 시작 | | seeked | 탐색 종료 | | waiting | 재생 대기 상태 | | volumechange | 볼륨 변경 | | timeupdate | 재생 시간 변경 | | controlbarActive | 컨트롤바 활성화 | | controlbarDeactive | 컨트롤바 비활성화 | | next | 다음 아이템으로 이동 | | prev | 이전 아이템으로 이동 | | skipForward | 앞으로 건너뜀 | | skipBack | 뒤로 건너뜀 | | playlistChange | 플레이리스트 변경 | | ratechange | 재생 속도 변경 | | introSkip | 인트로 구간 스킵 | | openingSkip | 오프닝 구간 스킵 | | endingSkip | 엔딩 구간 스킵 | | licenseRequest | DRM 라이선스 요청 | | licenseSuccess | DRM 라이선스 발급 성공 | | licenseError | DRM 라이선스 발급 실패 | | error | 오류 발생 | | adStart | 광고 재생 시작 | | adComplete | 광고 재생 완료 | | adSkip | 사용자가 광고 스킵 | | adError | 광고 로드/재생 에러 |
One Click Multi DRM 예제
options={{
aspectRatio: "16/9",
autostart: true,
muted: true,
playlist: [
{
poster: "https://CDN_DOMAIN/example_poster.jpg",
description: {
title: "테스트 영상",
created_at: "2024.07.13",
profile_name: "VPE",
profile_image: "https://CDN_DOMAIN/profile.png",
},
drm: {
"com.widevine.alpha": {
src: "https://CDN_DOMAIN/manifest.mpd",
licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
licenseRequestHeader: {
"x-ncp-region_code": "KR",
"x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
"x-ncp-apigw-timestamp": 1770125949480,
"x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
"x-drm-token": "YOUR_DRM_TOKEN",
},
},
"com.microsoft.playready": {
src: "https://CDN_DOMAIN/manifest.mpd",
licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
licenseRequestHeader: {
"x-ncp-region_code": "KR",
"x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
"x-ncp-apigw-timestamp": 1770125949480,
"x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
"x-drm-token": "YOUR_DRM_TOKEN",
},
},
"com.apple.fps": {
src: "https://CDN_DOMAIN/index.m3u8",
certificateUri: "https://multi-drm.apigw.ntruss.com/api/v1/license/fairPlay",
certificateRequestHeader: {
"x-ncp-region_code": "KR",
"x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
"x-ncp-apigw-timestamp": 1770125949480,
"x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
"x-drm-token": "YOUR_DRM_TOKEN",
"accept": "application/json",
},
licenseUri: "https://multi-drm.apigw.ntruss.com/api/v1/license",
licenseRequestHeader: {
"x-ncp-region_code": "KR",
"x-ncp-iam-access-key": "YOUR_ACCESS_KEY",
"x-ncp-apigw-timestamp": 1770125949481,
"x-ncp-apigw-signature-v2": "YOUR_SIGNATURE",
"x-drm-token": "YOUR_DRM_TOKEN",
},
},
},
},
],
}}Pre-roll 광고 (Google IMA)
Google IMA SDK를 사용한 Pre-roll 영상 광고를 지원합니다.
options.ads.tagUrl에 VAST 태그 URL을 전달하면 콘텐츠 재생 전에 광고가 자동으로 재생됩니다.
- Google IMA SDK는 외부에서 자동 로드됩니다 (번들에 포함되지 않음)
- 광고 재생 중 콘텐츠 비디오는 자동으로 일시정지되고, 컨트롤바가 숨겨집니다
- 광고 완료/스킵/에러 후 콘텐츠가 자동 재생됩니다
ads옵션이 없으면 기존과 동일하게 동작합니다
React (ESM) 예제
"use client";
import Hls from "hls.js";
import { VpePlayer } from "@sgrsoft/vpe-react-sdk";
export default function AdPlayer() {
return (
<VpePlayer
accessKey="YOUR_ACCESS_KEY"
hls={Hls}
options={{
playlist: [
{
file: "https://CDN_DOMAIN/example.m3u8",
poster: "https://CDN_DOMAIN/poster.jpg",
},
],
autostart: true,
muted: true,
ads: {
tagUrl: "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=",
},
}}
onEvent={(event) => {
switch (event.type) {
case "adStart":
console.log("광고 시작");
break;
case "adComplete":
console.log("광고 완료");
break;
case "adSkip":
console.log("광고 스킵");
break;
case "adError":
console.log("광고 에러", event.data?.message);
break;
}
}}
/>
);
}UMD 예제
<script src="https://player.vpe.naverncp.com/v2/ncplayer.js?access_key=YOUR_ACCESS_KEY"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>
<div id="video"></div>
<script>
const player = new ncplayer("video", {
playlist: [
{ file: "https://CDN_DOMAIN/example.m3u8" },
],
autostart: true,
muted: true,
ads: {
tagUrl: "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=",
},
});
player.on("adStart", function(e) { console.log("광고 시작"); });
player.on("adComplete", function(e) { console.log("광고 완료"); });
player.on("adSkip", function(e) { console.log("광고 스킵"); });
player.on("adError", function(e) { console.log("광고 에러", e.data?.message); });
</script>광고 이벤트
| 이벤트 | 설명 |
| --- | --- |
| adStart | 광고 재생 시작 |
| adComplete | 광고 재생 완료 |
| adSkip | 사용자가 광고 스킵 |
| adError | 광고 로드/재생 에러 (event.data.message에 상세 메시지) |
