๊ฐœ๋ฐœ ๊ณต๋ถ€/๋ฐ๋ธŒ์ฝ”์Šค TIL

[ํด๋ผ์šฐ๋”ฉ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—”์ง€๋‹ˆ์–ด๋ง TIL] 240311 - ReactJS ๋น„๋””์˜ค ์—๋””ํ„ฐ ์ œ์ž‘ํ•˜๊ธฐ ํ”„๋กœ์ ํŠธ (4)

๊ฐ€์šค์ด 2024. 3. 11. 23:53

Intro


ffmpeg ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋น„๋””์˜ค๋ฅผ ๋‚ด๋ณด๋‚ด๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๊ณต์‹ ๋ฌธ์„œ๊ฐ€ ์กฐ๊ธˆ ๋นˆ์•ฝํ•˜๋‹ค๊ณ  ๋А๊ปด์ ธ์„œ ffmpeg ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ธฐ๋Š” ๋ฐ์— ์กฐ๊ธˆ ์–ด๋ ค์› ๋‹ค ใ… 

 

 

 

ํ”„๋กœ์ ํŠธ ์ง„ํ–‰์‚ฌํ•ญ


FFmpeg

 

Overview | ffmpeg.wasm

For 0.11.x, visit https://ffmpegwasm-0-11-x.netlify.app

ffmpegwasm.netlify.app

 

์œ„์˜ ๊ณต์‹ ์‚ฌ์ดํŠธ์™€ ๋”๋ถˆ์–ด ๋ฆฌ์•กํŠธ์—์„œ FFmpeg๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๊ตฌํ˜„ํ–ˆ๋‹ค.

https://github.com/ffmpegwasm/ffmpeg.wasm/blob/main/apps/react-vite-app/src/App.tsx

 

๋ฒ„์ „์ด ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ๋ฐ”๋€ ๋ถ€๋ถ„์ด ๋งŽ์•„ ํ”„๋กœ์ ํŠธ ์ „ ๊ฐ•์˜์—์„œ๋Š” ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œํ•˜์—ฌ FFmpeg๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ๋‚˜๋Š” ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๋งˆ์Œ์— ํ•˜๋‚˜ํ•˜๋‚˜ ๋ถ„์„ํ•ด ๋ณด์•˜๋‹ค.

 

๋จผ์ €, FFmpeg๋ฅผ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋กœ ์„ ์–ธํ•œ๋‹ค.

const ffmpeg = new FFmpeg();

 

ffmpeg ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ์ ํŠธ ๋งˆ์šดํŠธ ์‹œ ffmpeg๋ฅผ ๋กœ๋“œํ•œ๋‹ค.

useEffect(() => {
  async function loadFFmpeg() {
    await ffmpeg.load();
  }

  loadFFmpeg();
  setFfmpegLoaded(true);
}, []);

 

๋‹ค์Œ์œผ๋กœ ํŒŒ์ผ ๋‚ด๋ณด๋‚ด๊ธฐ์— ๊ด€๋ จ๋œ ํ•จ์ˆ˜์ด๋‹ค.

writeFile์ด๋ž€ ํ•จ์ˆ˜๋Š” ๋น„๋””์˜ค ํŒŒ์ผ์„ ๋กœ์ปฌ ํ™˜๊ฒฝ์— ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.

ํŒŒ์ผ ์ด๋ฆ„๊ณผ ๊ฐ€์ ธ์˜ฌ ํŒŒ์ผ์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

URL.createObjectURL ํ•จ์ˆ˜๋กœ ๋น„๋””์˜ค ํŒŒ์ผ์˜ Blob URL์„ ์ƒ์„ฑํ•˜๊ณ  fetchFileํ•จ์ˆ˜์— ์ „๋‹ฌํ•ด ๋น„๋””์˜ค ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜จ๋‹ค.

const writeFile = async inputFileName => {
  return await ffmpeg.writeFile(
    inputFileName,
    await fetchFile(URL.createObjectURL(videoFile))
  );
};

 

exec ํ•จ์ˆ˜๋กœ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

ffmpeg -ss [์‹œ์ž‘์‹œ๊ฐ„] -i input.mp4 -t [์ง€์†์‹œ๊ฐ„] -f gif output.gif

 

์œ„์˜ ๋ช…๋ น์–ด๋Š” mp4 ํŒŒ์ผ์„ ์›ํ•˜๋Š” ์‹œ๊ฐ„ ๋งŒํผ ์ž˜๋ผ gif ํŒŒ์ผ๋กœ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ffmpeg ๋ช…๋ น์–ด์ด๋‹ค.

์œ„ ๊ฐ’๋“ค์„ ๋ฐฐ์—ด์— ๋‹ด์•„ exec ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•œ๋‹ค.

await ffmpeg.exec([
  '-i',
  `${inputFileName}`,
  '-ss',
  `${minTime}`,
  '-t',
  `${maxTime - minTime}`,
  '-f',
  'gif',
  `${outputFileName}`,
]);

 

๋ณ€ํ™˜๋œ ํŒŒ์ผ์„ ์ฝ์–ด์™€ Bolo URL๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ ,

const data = await ffmpeg.readFile(outputFileName);
const gifURL = URL.createObjectURL(
  new Blob([data.buffer], { type: 'image/gif' })
);

 

url์„ a ํƒœ๊ทธ์— ๋‹ด์•„ ํด๋ฆญํ•˜์—ฌ ๋‹ค์šด๋กœ๋“œ ๋˜๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

const downloadFile = dataURL => {
  const link = document.createElement('a');
  link.href = dataURL;
  link.setAttribute('download', '');
  link.click();
};

 

 

 

 

 

๋งˆ๋ฌด๋ฆฌ


์ฒ˜์Œ์—” ์ฝ”๋“œ๋งŒ ๋ณด๊ณ  ffmpeg ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์› ๋Š”๋ฐ ๊ณ„์† ๋ณด๋ฉด์„œ ์—ด์‹ฌํžˆ ๋ถ„์„ํ•ด์„œ ์ดํ•ดํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ทธ ๋•์— ๋น„๋””์˜ค ๋‚ด๋ณด๋‚ด๊ธฐ, ์Œ์„ฑ ๋‚ด๋ณด๋‚ด๊ธฐ ๋“ฑ์˜ ๊ธฐ๋Šฅ๋„ ์‰ฝ๊ฒŒ ์‘์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋ฟŒ๋“ฏํ–ˆ๋‹ค ^__^