如何讓合成時長與影片一致
學習如何使用 calculateMetadata 和 parseMedia 讓 Remotion 合成的時長自動對齊影片或音訊的實際長度
如何讓合成時長與影片一致
在使用 Remotion 製作影片時,你常常需要讓合成(Composition)的時長與嵌入的影片素材精確吻合。本文介紹完整的實作方式。
問題說明
假設你有一個元件負責渲染一段影片:
import React from 'react';
import {OffthreadVideo, staticFile} from 'remotion';
export const MyComp: React.FC = () => {
return <OffthreadVideo src={staticFile('video.mp4')} />;
};此時合成的 durationInFrames 是寫死的固定值,無法自動跟隨影片實際長度變化。當影片更換或時長不同時,就需要手動修改,既不靈活也容易出錯。
解決方案:使用 calculateMetadata
第一步:將影片來源改為 React prop
首先將 src 從寫死的路徑改為元件的 props,讓它可以從外部傳入:
import React from 'react';
import {OffthreadVideo, staticFile} from 'remotion';
type MyCompProps = {
src: string;
};
export const MyComp: React.FC<MyCompProps> = ({src}) => {
return <OffthreadVideo src={src} />;
};第二步:撰寫 calculateMetadata 函式
接下來定義一個 calculateMetadata() 函式,根據影片的實際長度動態計算合成的時長。
請先安裝 @remotion/media-parser(若尚未安裝):
npm install @remotion/media-parser然後撰寫計算函式:
import {CalculateMetadataFunction} from 'remotion';
import {parseMedia} from '@remotion/media-parser';
export const calculateMetadata: CalculateMetadataFunction<MyCompProps> = async ({props}) => {
const {slowDurationInSeconds, dimensions} = await parseMedia({
src: props.src,
fields: {
slowDurationInSeconds: true,
dimensions: true,
},
});
if (dimensions === null) {
// 例如傳入 MP3 音訊檔案時:
throw new Error('Not a video file');
}
const fps = 30;
return {
durationInFrames: Math.floor(slowDurationInSeconds * fps),
fps,
width: dimensions.width,
height: dimensions.height,
};
};注意: 若你的資源未啟用 CORS,可以改用
@remotion/media-utils中的getVideoMetadata函式,而非parseMedia()。
第三步:在 Composition 中套用
最後,將 calculateMetadata 函式傳入 <Composition> 元件,並透過 defaultProps 設定預設的 src:
import React from 'react';
import {Composition} from 'remotion';
import {MyComp, calculateMetadata} from './MyComp';
export const Root: React.FC = () => {
return (
<Composition
id="MyComp"
component={MyComp}
durationInFrames={300}
fps={30}
width={1920}
height={1080}
defaultProps={{
src: 'https://remotion.media/BigBuckBunny.mp4',
}}
calculateMetadata={calculateMetadata}
/>
);
};Remotion 會在渲染前自動呼叫 calculateMetadata,並以回傳值覆蓋 durationInFrames、fps、width、height 等合成屬性。
如何讓合成時長與音訊一致
流程與影片相同,差別在於使用 @remotion/media-utils 中的 getAudioDurationInSeconds() 函式來取得音訊時長:
import {getAudioDurationInSeconds} from '@remotion/media-utils';
export const calculateMetadata: CalculateMetadataFunction<MyCompProps> = async ({props}) => {
const durationInSeconds = await getAudioDurationInSeconds(props.src);
const fps = 30;
return {
durationInFrames: Math.floor(durationInSeconds * fps),
fps,
};
};重點整理
- 使用
calculateMetadata可讓合成時長動態對齊影片或音訊的實際長度 parseMedia()來自@remotion/media-parser,可同時取得時長與尺寸資訊- 若影片資源有 CORS 限制,改用
getVideoMetadata()來自@remotion/media-utils defaultProps中的src會作為預覽時的預設影片來源