자막
자막(caption)은 자체 트랙에 놓이는 시간 지정 텍스트이며, 엔진이 텍스트 제너레이터와 같은 텍스트 렌더러로 그립니다. 이 페이지에서는 자막 트랙, 큐, 스타일, 단어 타이밍, 그리고 SubRip과 WebVTT 파일을 가져오는 방법을 설명합니다. 다 읽고 나면 영상에 자막을 달고, 말하는 단어를 강조할 수 있습니다.
자막 트랙
섹션 제목: “자막 트랙”"kind": "caption"인 트랙에는 클립이 없습니다. 대신 captions가 다음을 담습니다.
cues: 각각timeline_range와text를 가진CaptionCue. 큐는 타임라인 순서이고 서로 겹치지 않습니다. 트랙은 한 번에 큐 하나만 보여 줍니다.style: 모든 큐의 출발점이 되는TextStyle. 텍스트 제너레이터와 같은 스타일입니다. 기본값은 캔버스 짧은 변의 5% 크기의 흰 글자이며, 아래쪽 가운데 근처에 놓입니다.styles: 이 스타일에 대한 이름 있는 패치. 최대 32개이며, 패치가 지정한 필드는 기본 스타일의 값을 대체합니다.
자막 트랙은 앞에 있는 트랙들 위에, 뒤에 있는 트랙들 아래에 그려집니다. 맨 위에 그리려면 마지막에 두세요.
{ "id": "subs", "name": "Subtitles", "kind": "caption", "captions": { "style": { "font_family": "Hanken Grotesk", "font_size": 0.06, "background": { "color": { "red": 0, "green": 0, "blue": 0, "alpha": 0.6 }, "padding": 0.3 } }, "styles": { "Narrator": { "fill": { "type": "solid", "color": { "red": 1, "green": 0.85, "blue": 0.3, "alpha": 1 } } }, "karaoke": { "animators": [ { "selector": { "type": "timing", "state": "upcoming" }, "properties": { "opacity": { "mode": "constant", "value": 0.45 } } } ] } }, "cues": [ { "timeline_range": { "start": 0, "end": 240000 }, "text": "The tide comes in twice a day." }, { "timeline_range": { "start": 240000, "end": 480000 }, "text": "Every word lands on time.", "speaker": "Narrator" }, { "timeline_range": { "start": 480000, "end": 720000 }, "style": "karaoke", "text": [ { "text": "One ", "time": { "start": 0, "end": 60000 } }, { "text": "word ", "time": { "start": 60000, "end": 120000 } }, { "text": "at ", "time": { "start": 120000, "end": 168000 } }, { "text": "a time.", "time": { "start": 168000, "end": 240000 } } ] } ] }}큐마다 스타일 고르기
섹션 제목: “큐마다 스타일 고르기”큐는 트랙의 styles 중 하나를 두 가지 방법으로 고릅니다.
- **
style**로 직접 이름을 지정합니다. 세 번째 큐는karaoke를 씁니다. - **
speaker**는 누가 말하는지를 나타냅니다(예: WebVTT voice). 큐가 스타일을 지정하지 않으면 화자 이름과 같은 트랙 스타일이 적용됩니다. 두 번째 큐의 화자가Narrator이므로Narrator스타일의 노란색으로 그려집니다.
런과 가라오케
섹션 제목: “런과 가라오케”큐의 텍스트는 문자열이거나, 텍스트를 이어 붙이면 전체 텍스트가 되는 **런(run)**의 목록입니다. 런에는 class 이름과 time 구간을 붙일 수 있습니다. time은 큐 시작을 기준으로 하며 큐 안에 있어야 합니다.
텍스트 애니메이터의 timing 선택자는 런의 시간을 현재 시각과 비교해 글자를 고릅니다. upcoming(아직 말하지 않음), active(말하는 중), spoken(말함) 중 하나입니다. 예제의 karaoke 스타일은 아직 오지 않은 단어를 불투명도 45%로 흐리게 하므로, 각 단어가 자기 차례가 되면 밝아집니다. ramp를 주면 즉시 바뀌는 대신 그 시간 동안 서서히 바뀌고, sweep을 켜면 런의 시간을 글자들에 나누어 강조가 단어 안에서 한 글자씩 지나갑니다.
자막 스타일 안의 애니메이터 키프레임은 각 큐가 시작한 뒤의 시간을 따릅니다.
SRT와 WebVTT 가져오기
섹션 제목: “SRT와 WebVTT 가져오기”alpha2/captions의 parseCaptions는 엔진 자체의 파서로 SubRip("srt")이나 WebVTT("webvtt") 텍스트를 읽고, captionTrack은 큐로 트랙을 만듭니다.
import init, * as wasm from "alpha2/wasm";import { captionTrack, parseCaptions } from "alpha2/captions";
await init();const { rows, skipped, notes } = parseCaptions(wasm, vttText, "webvtt");const tracks = rows.map((cues, index) => captionTrack(`subtitles-${index}`, "Subtitles", cues, { font_family: "Hanken Grotesk" }),);- 타임스탬프는 정확합니다. 1밀리초가 120틱입니다.
rows에는 자막 트랙 하나 분량의 큐가 한 행씩 들어 있습니다. 파일에서 겹치는 큐는 서로 다른 행으로 갑니다. 트랙은 한 번에 큐 하나만 보여 주기 때문입니다. 한 행에는 트랙이 담을 수 있는 최대치인 4096개까지 들어갑니다.- WebVTT voice는 큐의
speaker가 됩니다. voice,<c.class>,<b>,<i>,<u>는 런의 클래스가 되고, 인라인 타임스탬프는 큐를 시간이 지정된 런으로 나눕니다. 나머지 마크업은 버립니다. skipped는 읽을 수 없었던 블록의 수이고,notes는 읽었지만 유지할 수 없었던 마크업의 수입니다.
예를 들어 다음 WebVTT 큐는 시간이 지정된 런 네 개가 되며, 위 예제의 세 번째 큐와 같습니다.
00:00:04.000 --> 00:00:06.000One <00:00:04.500>word <00:00:05.000>at <00:00:05.400>a time.splitCue와 trimCue는 런의 시간을 유지하고 기준점을 다시 잡으면서 큐를 나누거나 줄입니다. 에디터에서는 importCaptions가 자막 파일을 실행 취소 한 단계로 가져옵니다. Python에서는 alpha2.compose.Captions가 SubRip, WebVTT, 큐 목록, 단어 타임스탬프를 받습니다.
