匯出字幕檔案
學習如何將 Remotion 影片的字幕匯出為 SRT 或 VTT 等獨立字幕檔案,或直接燒入影片。
總覽
本指南介紹從 Remotion 影片匯出字幕的不同方式:
- 燒入字幕 — 字幕直接嵌入影片畫面
- 匯出為獨立 SRT 檔案 — 產生可與影片分離使用的字幕檔案
燒入字幕
如果你希望字幕成為影片畫面的一部分(燒入字幕),請依照顯示字幕的說明渲染字幕,然後照常渲染影片即可:
npx remotion render燒入字幕的優點是字幕會永久附著在影片上,無需額外的字幕檔案。缺點是字幕無法被關閉或切換語言。
匯出為獨立 SRT 檔案
若要將字幕匯出為獨立的 .srt 檔案,搭配使用 <Artifact> 元件與 serializeSrt() 函式。
安裝相依套件
npm install @remotion/captions基本 SRT 匯出
import { useCurrentFrame } from 'remotion';
import { Artifact } from 'remotion';
import { serializeSrt } from '@remotion/captions';
export const MyComp: React.FC = () => {
const frame = useCurrentFrame();
// 將字幕轉換為 SRT 格式
// 每個字幕段落各自成為一行
const srtContent = serializeSrt({
lines: captions.map((caption) => [caption]),
});
return (
<>
{/* 只在第一幀輸出 artifact */}
{frame === 0 ? (
<Artifact filename="subtitles.srt" content={srtContent} />
) : null}
{/* 影片其他內容 */}
</>
);
};渲染後,字幕檔案會儲存至 out/[composition-id]/subtitles.srt。
<Artifact> 元件說明
<Artifact> 是 Remotion 提供的特殊元件,用於在渲染過程中輸出額外的檔案。它只應在第一幀(frame === 0)渲染,避免重複輸出。
<Artifact
filename="subtitles.srt" // 輸出檔名
content={srtContent} // 檔案內容(字串)
/>將字詞分組為字幕行
如果你的字幕是逐字拆分的(word-level),可能會想將多個字詞合併為單一字幕行。使用 createTikTokStyleCaptions() 建立分頁,再轉換回 serializeSrt() 所需的格式:
import { createTikTokStyleCaptions, serializeSrt } from '@remotion/captions';
import { Artifact, useCurrentFrame } from 'remotion';
export const MyComp: React.FC = () => {
const frame = useCurrentFrame();
// 將字詞分組,每 3 秒一組
const { pages } = createTikTokStyleCaptions({
captions,
combineTokensWithinMilliseconds: 3000,
});
const srtContent = serializeSrt({
lines: pages.map((page) => {
// 將頁面中的 token 轉換回 Caption 格式
return page.tokens.map((token) => ({
text: token.text,
startMs: token.fromMs,
endMs: token.toMs,
timestampMs: (token.fromMs + token.toMs) / 2,
confidence: null,
}));
}),
});
return (
<>
{frame === 0 ? (
<Artifact filename="subtitles.srt" content={srtContent} />
) : null}
{/* 影片其他內容 */}
</>
);
};SRT 格式說明
SRT(SubRip Text)是最常見的字幕格式之一。serializeSrt() 輸出的格式如下:
1
00:00:00,000 --> 00:00:02,500
第一段字幕文字
2
00:00:02,500 --> 00:00:05,000
第二段字幕文字
3
00:00:05,000 --> 00:00:07,800
第三段字幕文字
每個字幕條目包含:
- 序號(從 1 開始)
- 時間範圍(
開始時間 --> 結束時間,格式為HH:MM:SS,mmm) - 字幕文字(可多行)
- 空白行作為分隔
完整匯出範例
以下是一個完整範例,同時渲染燒入字幕的影片內容,並輸出 SRT 檔案:
import {
useState,
useEffect,
useCallback,
useMemo,
} from 'react';
import {
AbsoluteFill,
Artifact,
staticFile,
useCurrentFrame,
useDelayRender,
useVideoConfig,
} from 'remotion';
import {
createTikTokStyleCaptions,
serializeSrt,
} from '@remotion/captions';
import type { Caption } from '@remotion/captions';
const COMBINE_CAPTIONS_EVERY_MS = 3000;
export const VideoWithExportedCaptions: React.FC = () => {
const frame = useCurrentFrame();
const [captions, setCaptions] = useState<Caption[] | null>(null);
const { delayRender, continueRender, cancelRender } = useDelayRender();
const [handle] = useState(() => delayRender());
const fetchCaptions = useCallback(async () => {
try {
const response = await fetch(staticFile('captions.json'));
const data = await response.json();
setCaptions(data);
continueRender(handle);
} catch (e) {
cancelRender(e);
}
}, [continueRender, cancelRender, handle]);
useEffect(() => {
fetchCaptions();
}, [fetchCaptions]);
const srtContent = useMemo(() => {
if (!captions) return '';
const { pages } = createTikTokStyleCaptions({
captions,
combineTokensWithinMilliseconds: COMBINE_CAPTIONS_EVERY_MS,
});
return serializeSrt({
lines: pages.map((page) =>
page.tokens.map((token) => ({
text: token.text,
startMs: token.fromMs,
endMs: token.toMs,
timestampMs: (token.fromMs + token.toMs) / 2,
confidence: null,
}))
),
});
}, [captions]);
if (!captions) {
return null;
}
return (
<AbsoluteFill style={{ backgroundColor: 'black' }}>
{/* 輸出 SRT 字幕檔案(僅在第一幀) */}
{frame === 0 && srtContent ? (
<Artifact filename="subtitles.srt" content={srtContent} />
) : null}
{/* 影片主體內容(此處省略實際影片元素) */}
<AbsoluteFill
style={{
justifyContent: 'center',
alignItems: 'center',
color: 'white',
fontSize: 40,
}}
>
影片內容區域
</AbsoluteFill>
</AbsoluteFill>
);
};渲染並取得 SRT 檔案
渲染後,SRT 檔案會出現在輸出目錄中:
# 渲染影片
npx remotion render MyComposition
# 輸出檔案位置:
# out/MyComposition/
# ├── out.mp4 ← 影片檔案
# └── subtitles.srt ← 字幕檔案在伺服器端渲染時取得 Artifact
若使用 SSR API 渲染,可以從渲染結果取得所有 artifact:
import { renderMedia, selectComposition } from '@remotion/renderer';
const composition = await selectComposition({
serveUrl: 'http://localhost:3000',
id: 'MyComposition',
inputProps: {},
});
const { artifacts } = await renderMedia({
composition,
serveUrl: 'http://localhost:3000',
codec: 'h264',
outputLocation: 'out/video.mp4',
});
// artifacts 包含所有透過 <Artifact> 輸出的檔案
for (const artifact of artifacts) {
console.log(artifact.filename); // 'subtitles.srt'
console.log(artifact.content); // SRT 檔案內容
}參考資料
- 顯示字幕 — 在影片中渲染字幕
<Artifact>元件 — 渲染時輸出檔案serializeSrt()API — 將字幕轉換為 SRT 格式- 輸出 Artifact 完整指南 — Artifact 功能的完整說明