Render Video Sử Dụng React.js và Remotion

7 min read

Giới thiệu

Video cho phép chúng ta thiết lập sự uy tín và tạo cảm giác cá nhân hơn cho thông điệp của mình. Nó giúp chúng ta kết nối với cảm xúc của khán giả. React là một thư viện JavaScript tuyệt vời để mô tả giao diện người dùng thay đổi theo thời gian. Để tạo nội dung video một cách lập trình với React.js, chúng ta sẽ sử dụng một công cụ tuyệt vời có tên là Remotion.

Hãy cùng khám phá cách chúng ta có thể đạt được điều này.

Github

Xem kho lưu trữ GitHub này để có mã nguồn đầy đủ.

Codesandbox

Bạn có thể xem dự án hoàn chỉnh trên Codesandbox.

Yêu cầu trước

Dưới đây là một số yêu cầu bạn cần đáp ứng để theo dõi bài viết này:

  • Kiến thức cơ bản về JavaScript
  • Kiến thức cơ bản về React.js

Thiết lập Dự án Mẫu

Trong thư mục bạn chọn, tạo một dự án remotion mới bằng cách sử dụng:

bashCopy codeyarn create video

Bạn có thể muốn chọn mẫu được đề xuất, nhưng cho mục đích của bài viết này, hãy chọn một mẫu trống. Chạy lệnh:

yarn start

Điều này sẽ khởi động máy chủ phát triển cục bộ của bạn. Bạn sẽ thấy một cửa sổ như sau:

Ở bên trái, chúng ta có một thanh bên hiển thị tất cả các composition cho dự án, cho phép bạn cô lập và kiểm tra từng cảnh trong video. Mỗi composition là một component có thể render. Composition được tạo thành từ các sequence, chỉ định cho video biết nên hiển thị nội dung trong các khung hình nào. Điểm vào của một dự án remotion là file index.tsx, tại đây chúng ta gọi hàm registerRoot(RemotionVideo); nằm trong Video.tsx.

Một số showcases của remotion

https://www.remotion.dev/showcase

Bắt đầu

Mở file Video.tsx. File này chứa component RemotionVideo. Bạn có thể coi component này như toàn bộ video của mình.

export const RemotionVideo: React.FC = () => {
  return (
    <>
      <Composition
        id="Empty"
        component={MyComposition}
        durationInFrames={450}
        fps={30}
        width={1280}
        height={720}
      />
    </>
  );
};

Một video về cơ bản được tạo thành từ một hoặc nhiều composition. Bên trong composition, chúng ta định nghĩa các thuộc tính video như:

  • durationInFrames: số khung hình mà video sẽ có
  • fps: số khung hình mỗi giây
  • widthheight: kích thước video tính bằng pixel

Khi nói về khung hình, bạn có thể nghĩ về nó như một hình ảnh tĩnh tại một điểm cụ thể trong video.

id xác định composition trong trình phát video và tham chiếu đến component chứa giao diện người dùng mà bạn muốn hiển thị. Các thuộc tính widthheight được sử dụng để thay đổi độ phân giải của video, ví dụ: để thay đổi độ phân giải thành chế độ dọc:

width={1080}
height={1920}

Độ dài thực tế của video tính bằng giây dựa trên fps:





durationInFrames / fps = length(s)

Điều này có nghĩa rằng trong demo này, video của chúng ta dài 15 giây:





450 / 30 = 15

Tùy chỉnh Video

Chúng ta sẽ tạo một component mới tên là Main ngay bên dưới component RemotionVideo:

const Main = () => {
  return <h1>Welcome to Cloudinary!</h1>;
};

Để xem điều này trên trình duyệt, bạn cần thay đổi giá trị của id từ id="Empty" thành id="Main", và giá trị của component thành component={Main}. Khi bạn thay đổi giá trị id, bạn cũng cần thay đổi file package.json:

jsonCopy code"build": "remotion render src/index.tsx Main out/video.mp4"

Khi mở trình phát video, bạn sẽ thấy video với dòng chữ Welcome to Cloudinary. Để chỉnh sửa CSS của video một cách lập trình, hãy sử dụng CSS inline:





const Main = () => {
  return (
    <div style={{ backgroundColor: 'white', flexGrow: 1 }}>
      <h1
        style={{
          position: 'absolute',
          top: '50%',
          width: '100%',
          textAlign: 'center',
          fontSize: '5rem',
        }}
      >
        Welcome to Cloudinary!
      </h1>
    </div>
  );
};

Chúng ta có thể tạo ba component cho video này: Title, SubTitleImage, sau đó gọi chúng bên trong component Main.





const Title = () => {
  return (
    <h1
      style={{
        position: 'absolute',
        top: '50%',
        width: '100%',
        textAlign: 'center',
        fontSize: '5rem',
      }}
    >
      Welcome to Cloudinary!
    </h1>
  );
};

const SubTitle = () => {
  return (
    <h3
      style={{
        position: 'absolute',
        top: '60%',
        width: '100%',
        textAlign: 'center',
        fontSize: '3rem',
      }}
    >
      Transform images and videos to load faster with no visual degradation, automatically generate image and video variants, and deliver high quality responsive experiences to increase conversions.
    </h3>
  );
};

Để thêm hình ảnh và render chúng, chúng ta cần sử dụng thẻ Img được import từ Remotion:

import { Composition, Img } from 'remotion';
import cloudinary from './cloudinary.png';

Chúng ta có thể tạo component Image:

const Image = () => {
  return (
    <Img
      src={cloudinary}
      alt="cloudinary"
      style={{
        display: 'block',
        marginLeft: 'auto',
        marginRight: 'auto',
        width: '30%',
        height: '50%',
      }}
    />
  );
};

const Main = () => {
  return (
    <div style={{ backgroundColor: 'white', flexGrow: 1 }}>
      <Title />
      <Image />
      <SubTitle />
    </div>
  );
};

Hiện tại, mọi thứ chúng ta cần cho video đã được thiết lập, nhưng chúng ta cần thêm một số hiệu ứng để làm cho video trở nên thú vị và hấp dẫn hơn.

Animation

Để tạo nên toàn bộ đoạn video, chúng ta sẽ sử dụng các Sequence. Đây là những phần nhỏ riêng lẻ trong thời gian hữu hạn tạo nên toàn bộ video. Chúng ta chỉ định thời gian mà một component xuất hiện bằng cách sử dụng from={0} (bắt đầu từ giây 0). Bạn cũng có thể chỉ định thời gian component biến mất bằng thuộc tính durationInFrames={60}.

<div style={{ backgroundColor: 'white', flexGrow: 1 }}>
  <Sequence from={0}>
    <Image />
  </Sequence>
  <Sequence from={60}>
    <Title />
  </Sequence>
  <Sequence from={120}>
    <SubTitle />
  </Sequence>
</div>

Thêm Âm Thanh Cho Video

Chúng ta có thể thêm âm thanh bằng cách sử dụng thẻ <Audio /> trong Remotion. Hãy thêm một component AudVoice để render giọng nói:

import { Composition, Img, Audio } from 'remotion';
import voice from './voice.mp3';
// phần còn lại của code
const AudVoice = () => {
  return <Audio src={voice} startFrom={0} endAt={30 * 15} />;
};

Remotion cung cấp nhiều hook khác nhau cho phép chúng ta lấy dữ liệu về video.

  • useVideoConfig() cho phép chúng ta lấy dữ liệu về fps, durationInFrames, widthheight. Chúng ta có thể sử dụng nó để tính toán các giá trị cho việc animation các khung hình.
  • useCurrentFrame() cung cấp khung hình hiện tại và timeline. Những khung hình này sẽ được render lại cho mỗi thời điểm trong video.

Hiện tại, video của bạn đang hoạt động tốt, nhưng chúng ta cần sử dụng dữ liệu về video thay cho các số 0, 60 và 90. Import useVideoConfig từ remotion:


const Main = () => {
  const { fps, durationInFrames } = useVideoConfig();
  return (
    <div style={{ backgroundColor: 'white', flexGrow: 1 }}>
      <Sequence from={fps * 0.3} durationInFrames={durationInFrames}>
        <Image />
      </Sequence>
      <Sequence from={fps} durationInFrames={durationInFrames}>
        <AudVoice />
      </Sequence>
      <Sequence from={fps} durationInFrames={durationInFrames}>
        <Title />
      </Sequence>
      <Sequence from={fps * 2} durationInFrames={durationInFrames}>
        <SubTitle />
      </Sequence>
    </div>
  );
};

Hiệu Ứng Fade-In Cho SubTitle

Hãy làm cho animation của chúng ta hấp dẫn hơn với hiệu ứng fade-in. Chúng ta sẽ sử dụng hook useCurrentFrame() như sau:

const SubTitle = () => {
  const frame = useCurrentFrame();
  const opacity = frame > 30 ? 1 : frame / 30;
  return (
    <h3
      style={{
        position: 'absolute',
        top: '60%',
        width: '100%',
        textAlign: 'center',
        fontSize: '3rem',
        opacity,
      }}
    >
      Transform images and videos to load faster with no visual degradation, automatically generate image and video variants, and deliver high quality responsive experiences to increase conversions.
    </h3>
  );
};

useCurrentFrame trả về khung hình hiện tại, trong ngữ cảnh này là SubTitle trong sequence.

Chúng ta muốn opacity bằng 0 ở đầu, sau đó tăng dần lên 1. Nếu frame lớn hơn 30, trả về opacity là 1; ngược lại, opacity sẽ là frame / 30.

Hiệu Ứng Bounce Cho Image


const Image = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const translate = spring({ frame, fps, to: 100 });
  return (
    <Img
      src={cloudinary}
      alt="cloudinary"
      style={{
        display: 'block',
        marginLeft: 'auto',
        marginRight: 'auto',
        width: '30%',
        height: '50%',
        transform: `translateY(${translate}px)`,
      }}
    />
  );
};

Hàm spring làm cho component của chúng ta bật lên từ một điểm đến một điểm. Chúng ta lấy fps từ hook như trên. Hàm này nhận vào framefps để biết tốc độ di chuyển, fromto để xác định phạm vi bạn muốn, với from có giá trị mặc định là 0.

Build Dự Án

Để build dự án, chạy lệnh sau trên terminal:

yarn build

hoặc

npm run build

Điều này yêu cầu bạn cài đặt ffmpeg. Terminal sẽ cung cấp hướng dẫn về cách cấu hình nó trên máy của bạn.

Khi hoàn tất, bạn sẽ tìm thấy video bên trong thư mục out của dự án.

Nhấn vào liên kết này để xem video cuối cùng.

Kết luận

Thật tuyệt vời! Trong bài viết này, chúng ta đã tạo được một video dài 15 giây mà không cần sử dụng bất kỳ công cụ chỉnh sửa video nào, chỉ với React. Thật đáng kinh ngạc khi chúng ta có thể tạo video bằng React, phải không?

Avatar photo

Unity IAP: Triển khai Mua Hàng Consumable

Giới Thiệu Việc tích hợp tính năng mua hàng trong ứng dụng Unity là không thể tránh khỏi. Mua hàng trong ứng dụng có...
Avatar photo Tam Canh Le Chi
6 min read

Leave a Reply

Your email address will not be published. Required fields are marked *