Youtube Clone Coding (12. FFMPEG.WASM)

LeeJaeHoon·2021년 11월 13일
1
post-thumbnail
  1. ffmpeg이란?
    • 동영상의 인코딩과 디코딩을 하는 프로그램 중 하나이며 가장 유명한 오픈소스 라이브러리이다.
  2. FFMPEG.WASM사용법
    • 1) npm install @ffmpeg/ffmpeg @ffmpeg/core
    • 2) ffmpeg를 쓰고싶은 파일에 import한다.
      • import { createFFmpeg, fetchFile } from "@ffmpeg/ffmpeg"
    • 3) 나는 video를 recorder하고 유저가 다운로드할때 video를 webm가 아닌 mp4로 변환하기 위해 ffmpeg를 쓸 것 이다.
      • handleDownload함수에 다음과 같이 설정한다.
        • 첫번째로 ffmpeg instance를 생성후 load()를 해준다.
        • 두번째로 ffmpeg에 파일을 만들어야 한다.
          • ffmpeg.FS("writeFile", "recording.webm", await fetchFile(videoFile))
            • "writeFile" → 파일을 만들어준다.
            • "recording.webm" → 만드는 파일의 이름
            • await fetchFile(videoFile) → binaryData를 줘야한다.(여기선 videoFile이 binaryData이다.)
        • 세번째로 await ffmpeg.run("-i", "recording.webm", "-r", "60", "output.mp4")을 써준다
          • "recording.webm"을 input으로 받아서 output.mp4로 변환해주는 명령어
          • "-r", "60"은 초당 60프레임으로 인코딩 해주는 명령어이다.
        • 코드는 다음과 같음
          const handleDownload = async () => {
            const ffmpeg = createFFmpeg({
              log: true,
              corePath: "https://unpkg.com/@ffmpeg/core@0.10.0/dist/ffmpeg-core.js",
            });
            await ffmpeg.load();
            ffmpeg.FS("writeFile", "recording.webm", await fetchFile(videoFile));
            await ffmpeg.run("-i", "recording.webm", "-r", "60", "output.mp4");
            
          	const a = document.createElement("a");
            a.href = videoFile;
            a.download = "My Recording.webm";
            document.body.appendChild(a);
            a.click();
          };
        • fmpeg.wasm 깃헙 리드미에도 나와있지만 SharedArrayBuffer는 교차 출처가 격리된 페이지(cross-origin isolation)에서만 사용할 수 있다. 그래서 사용하기 위해서는 서버 헤더에 다음과 같이 추가 해주어야 한다.
          app.use((req, res, next) => {
            res.header("Cross-Origin-Embedder-Policy", "require-corp");
            res.header("Cross-Origin-Opener-Policy", "same-origin");
            next();
          });
        • 다음과 같이 설정하면 img가 안불러와 지는데 img속성에 crossorigin 이라는 속성을 추가해야 외부 origin에서 불러오기 가능하다.
    • 4) 만든 output.mp4를 이용하여 mp4파일 다운받게 만들기
      • const mp4File = ffmpeg.FS("readFile", "output.mp4")
        • 생성된 output.mp4 파일을 읽겠다는 뜻
        • console.log(mp4File)
          • 수많은 숫자들로 표현된 자바스크립트 방식의 파일

            Uint8Array(91210) [0, 0, 0, 32, 102, 116, 121, 112, 105, 115, 111, 109, 0, 0, 2, 0, 105, 115, 111, 109, 105, 115, 111, 50, 97, 118, 99, 49, 109, 112, 52, 49, 0, 0, 0, 8, 102, 114, 101, 101, 0, 1, 83, 66, 109, 100, 97, 116, 0, 0, 2, 160, 6, 5, 255, 255, 156, 220, 69, 233, 189, 230, 217, 72, 183, 150, 44, 216, 32, 217, 35, 238, 239, 120, 50, 54, 52, 32, 45, 32, 99, 111, 114, 101, 32, 49, 54, 48, 32, 45, 32, 72, 46, 50, 54, 52, 47, 77, 80, 69,]
        • console.log(mp4File.buffer)
          ArrayBuffer(91210)
          	byteLength: 91210
          	[[Prototype]]: ArrayBuffer
          	[[Int8Array]]: Int8Array(91210)
          	[[Uint8Array]]: Uint8Array(91210)
          	[[Int16Array]]: Int16Array(45605)
          	[[ArrayBufferByteLength]]: 91210
          	[[ArrayBufferData]]: "0x007004c68000
      • mp4File.buffer을 이용하여 Blob만들기
        • const mp4Blob = new Blob([mp4File.buffer], { type: "video/mp4" })
      • 만든 mp4Blob을 이용하여 mp4Url을 만들기
        • const mp4Url = URL.createObjectURL(mp4Blob)
      • 최종코드
        const handleDownload = async () => {
          const ffmpeg = createFFmpeg({
            log: true,
            corePath: "https://unpkg.com/@ffmpeg/core@0.10.0/dist/ffmpeg-core.js",
          });
          await ffmpeg.load();
          ffmpeg.FS("writeFile", "recording.webm", await fetchFile(videoFile));
          await ffmpeg.run("-i", "recording.webm", "-r", "60", "output.mp4");
          const mp4File = ffmpeg.FS("readFile", "output.mp4");
          console.log(mp4File);
          console.log(mp4File.buffer);
          const mp4Blob = new Blob([mp4File.buffer], { type: "video/mp4" });
          const mp4Url = URL.createObjectURL(mp4Blob);
          console.log(mp4Url);
          const a = document.createElement("a");
          a.href = mp4Url;
          a.download = "My Recording.mp4";
          document.body.appendChild(a);
          a.click();
        };
  3. Tumbnail만들기
    • 밑의 코드는 "recording.webm"을 인풋으로 받고 여기서 00:00:01 시간대를 찾고 1장의 스크린샷을 찍어서 그파일을 thumbnail.jpg로 저장하는것
      • 만들어진파일은 파일시스템의(FS) 메모리에 만들어지는것이다.

        await ffmpeg.run(
            "-i",
            "recording.webm",
            "-ss",
            "00:00:01",
            "-frames:v",
            "1",
            "thumbnail.jpg"
          );
    • const thumbFile = ffmpeg.FS("readFile", "thumbnail.jpg")
      • 만들어진 thumbnail.jpg을 읽어온다는 뜻
    • 읽어온 thumbFile로 Blob URL만들기
      const thumbBlob = new Blob([thumbFile.buffer], { type: "image/jpg" });
      const thumbUrl = URL.createObjectURL(thumbBlob);
    • 만들어진 thumbUrl으로 강제로 다운 시키기
      const thumbA = document.createElement("a");
      thumbA.href = thumbUrl;
      thumbA.download = "MyThumbnail.jpg";
      document.body.appendChild(thumbA);
      thumbA.click();
  4. 만든 link와 url 제거해주기
    • 제거해주면 속도가 더 빨라짐
      ffmpeg.FS("unlink", "recording.webm");
      ffmpeg.FS("unlink", "output.mp4");
      ffmpeg.FS("unlink", "thumbnail.jpg");
      
      URL.revokeObjectURL(mp4Url);
      URL.revokeObjectURL(thumbUrl);
      URL.revokeObjectURL(videoFile);

0개의 댓글