匯入 SRT 字幕檔案
使用 @remotion/captions 的 parseSrt() 將現有的 .srt 字幕檔案匯入 Remotion,並轉換為標準 Caption 格式以便後續使用。
匯入 SRT 字幕檔案
如果您已有現成的 .srt 字幕檔,可以使用 @remotion/captions 套件中的 parseSrt() 函式將其匯入 Remotion,並轉換為標準的 Caption 格式。
安裝
npm install @remotion/captions
# 或
yarn add @remotion/captions
# 或
pnpm add @remotion/captions讀取 .srt 檔案
從 public 資料夾載入
將 .srt 字幕檔放置於專案的 public 資料夾中,然後使用 staticFile() 取得路徑,再透過 fetch 讀取並解析:
// MyComponent.tsx
import { useState, useEffect, useCallback } from 'react';
import { AbsoluteFill, staticFile, useDelayRender } from 'remotion';
import { parseSrt } from '@remotion/captions';
import type { Caption } from '@remotion/captions';
export const MyComponent: React.FC = () => {
const [captions, setCaptions] = useState<Caption[] | null>(null);
// useDelayRender 確保 Remotion 等待資料載入完成後再開始渲染
const { delayRender, continueRender, cancelRender } = useDelayRender();
const [handle] = useState(() => delayRender());
const fetchCaptions = useCallback(async () => {
try {
// staticFile() 將 public 資料夾中的檔案路徑轉換為可存取的 URL
const response = await fetch(staticFile('subtitles.srt'));
const text = await response.text();
// parseSrt() 解析 SRT 格式並回傳標準 Caption 陣列
const { captions: parsed } = parseSrt({ input: text });
setCaptions(parsed);
// 通知 Remotion 可以繼續渲染
continueRender(handle);
} catch (e) {
// 發生錯誤時取消渲染並回報錯誤
cancelRender(e);
}
}, [continueRender, cancelRender, handle]);
useEffect(() => {
fetchCaptions();
}, [fetchCaptions]);
// 資料尚未載入時不渲染任何內容
if (!captions) {
return null;
}
return (
<AbsoluteFill>
{/* 在此使用 captions 陣列渲染字幕 */}
</AbsoluteFill>
);
};資料夾結構
my-remotion-project/
├── public/
│ └── subtitles.srt ← 將 .srt 檔案放在這裡
├── src/
│ └── MyComponent.tsx
└── package.json
從遠端 URL 載入
您也可以直接 fetch 遠端的 .srt 檔案:
import { useState, useEffect, useCallback } from 'react';
import { AbsoluteFill, useDelayRender } from 'remotion';
import { parseSrt } from '@remotion/captions';
import type { Caption } from '@remotion/captions';
export const RemoteCaptionsComponent: React.FC = () => {
const [captions, setCaptions] = useState<Caption[] | null>(null);
const { delayRender, continueRender, cancelRender } = useDelayRender();
const [handle] = useState(() => delayRender());
const fetchCaptions = useCallback(async () => {
try {
// 直接從遠端 URL 讀取
const response = await fetch(
'https://example.com/subtitles/my-video.srt'
);
const text = await response.text();
const { captions: parsed } = parseSrt({ input: text });
setCaptions(parsed);
continueRender(handle);
} catch (e) {
cancelRender(e);
}
}, [continueRender, cancelRender, handle]);
useEffect(() => {
fetchCaptions();
}, [fetchCaptions]);
if (!captions) return null;
return (
<AbsoluteFill>
{/* 使用字幕資料 */}
</AbsoluteFill>
);
};parseSrt() API
import { parseSrt } from '@remotion/captions';
const { captions } = parseSrt({
input: srtString, // 原始 SRT 格式字串
});回傳值:Caption 格式
解析完成後,每個字幕項目都會轉換為 Caption 物件:
type Caption = {
text: string; // 字幕文字內容
startMs: number; // 字幕開始時間(毫秒)
endMs: number; // 字幕結束時間(毫秒)
timestampMs: number | null; // 字幕時間戳(毫秒,可為 null)
confidence: number | null; // 信心分數(0–1,SRT 解析時通常為 null)
};SRT 格式範例
1
00:00:01,000 --> 00:00:04,000
歡迎來到 Remotion 教學
2
00:00:05,500 --> 00:00:09,000
在這段影片中,我們將學習如何使用字幕
3
00:00:10,000 --> 00:00:13,500
讓我們開始吧!解析後的結果:
[
{
"text": "歡迎來到 Remotion 教學",
"startMs": 1000,
"endMs": 4000,
"timestampMs": 1000,
"confidence": null
},
{
"text": "在這段影片中,我們將學習如何使用字幕",
"startMs": 5500,
"endMs": 9000,
"timestampMs": 5500,
"confidence": null
},
{
"text": "讓我們開始吧!",
"startMs": 10000,
"endMs": 13500,
"timestampMs": 10000,
"confidence": null
}
]使用已解析的字幕
解析完成後,字幕資料符合標準 Caption 格式,可直接使用 @remotion/captions 的所有工具。
根據當前影格顯示字幕
import { useCurrentFrame, useVideoConfig } from 'remotion';
import type { Caption } from '@remotion/captions';
const SubtitleDisplay: React.FC<{ captions: Caption[] }> = ({ captions }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// 將影格轉換為毫秒
const currentMs = (frame / fps) * 1000;
// 找出目前時間點應顯示的字幕
const currentCaption = captions.find(
(caption) =>
currentMs >= caption.startMs && currentMs <= caption.endMs
);
if (!currentCaption) return null;
return (
<div
style={{
position: 'absolute',
bottom: 80,
left: 0,
right: 0,
textAlign: 'center',
fontSize: 36,
color: 'white',
textShadow: '2px 2px 4px black',
padding: '0 40px',
}}
>
{currentCaption.text}
</div>
);
};完整整合範例
import { useState, useEffect, useCallback } from 'react';
import {
AbsoluteFill,
OffthreadVideo,
staticFile,
useCurrentFrame,
useDelayRender,
useVideoConfig,
} from 'remotion';
import { parseSrt } from '@remotion/captions';
import type { Caption } from '@remotion/captions';
export const VideoWithCaptions: React.FC = () => {
const [captions, setCaptions] = useState<Caption[] | null>(null);
const { delayRender, continueRender, cancelRender } = useDelayRender();
const [handle] = useState(() => delayRender());
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
useEffect(() => {
(async () => {
try {
const response = await fetch(staticFile('subtitles.srt'));
const text = await response.text();
const { captions: parsed } = parseSrt({ input: text });
setCaptions(parsed);
continueRender(handle);
} catch (e) {
cancelRender(e);
}
})();
}, [continueRender, cancelRender, handle]);
if (!captions) return null;
const currentMs = (frame / fps) * 1000;
const activeCaption = captions.find(
(c) => currentMs >= c.startMs && currentMs <= c.endMs
);
return (
<AbsoluteFill>
<OffthreadVideo src={staticFile('video.mp4')} />
{activeCaption && (
<div
style={{
position: 'absolute',
bottom: 80,
left: 0,
right: 0,
textAlign: 'center',
fontSize: 36,
color: 'white',
textShadow: '2px 2px 4px rgba(0,0,0,0.8)',
}}
>
{activeCaption.text}
</div>
)}
</AbsoluteFill>
);
};後續步驟
成功匯入字幕後,您可以:
相關連結
parseSrt()— API 文件Caption資料結構 — 字幕物件格式說明- 顯示字幕 — 渲染字幕到畫面
staticFile()— 靜態檔案路徑工具useDelayRender()— 非同步資料載入