[HTML5 Canvas] 05 캔버스 비디오

9rganizedChaos·2021년 6월 9일
3

HTML5_Canvas

목록 보기
5/6
post-thumbnail

✹ 해당 포스팅은 Youtube에 업로드된 1분코딩님의 <HTML5 Canvas 캔버스 라이브 강좌>의 필기입니다.
이 곳을 클릭하시면 유튜브에서 직접 강좌를 들으실 수 있습니다.
대부분의 샘플 코드는 해당 강좌에서 제공되는 코드임을 밝힙니다.

HTML5 Video 태그

HTML5에서 비디오태그가 추가되었다. 기본적으로는 태그 안에 src 속성으로 비디오 주소를 작성해주면 비디오가 출력되는 것을 확인할 수 있다. autoplay, muted를 비롯해 다양한 옵션이 있는데, 이는 공식문서에서 확인하는 것으로...

MDN 비디오태그

오히려 주의해야 할 부분은 브라우저마다 비디오 태그에 대한 기본설정이 상이하다!
크롬에서는 기본적으로 소리는 영상을 오토플레이가 불가하도록 되어 있다.
때문에 그롬에서 autoplay 속성을 먹여주려면, 뮤트 설정도 함께 해야 가능하다.

비디오 태그를 쓰지 않고, 캔버스로 비디오를 그려줄 수도 있다!

비디오 태그가 있는데도 이런 짓을 하는 이유는!?
캔버스는 기본적으로 픽셀단위의 그래픽 조작이 가능하다는 막강한 장점이 있기 때문이다

비디오의 색상값을 조작하거나, 위치값을 조작하는 게 가능하다.
이런 것들을 기본 HTML로 할 수 없는 일들이기 때문에 비디오를 캔버스 위에 그려주는 방식으로 비디오를 다루기도 한다.
캔버스로 동영상 표현을 하는 기본적인 원리는 requestAnimationFrame을 통해 소스가 될 비디오를 잡아두고 반복적으로 프레임을 그려내는 것이다. (이미지 대신 비디오를 그려내는 것)

기본 구조

  <body>
    <h1>Video</h1>
    <video class="video" src="../images/video.mp4" autoplay muted loop></video>
// 우리 눈에 보이지 않고 있는 비디오 태그!
    <canvas class="canvas" width="600" height="400">이 브라우저는 캔버스를 지원하지 않습니다.</canvas>

    <script>
      const canvas = document.querySelector('.canvas');
      const ctx = canvas.getContext('2d');
      let canPlayState = false;

      ctx.textAlign = 'center';
      ctx.fillText('비디오 로딩 중..', 300, 200);

      const videoElem = document.querySelector('.video');
      videoElem.addEventListener('canplaythrough', render);

      function render() {
        ctx.drawImage(videoElem, 0, 0, 600, 400);
        // 첫 번째 인자로 비디오를 넣어준다.
        requestAnimationFrame(render);
      }
    </script>
  </body>

canPlayThrough

공식문서 says "The canplaythrough event is fired when the user agent can play the media, and estimates that enough data has been loaded to play the media up to its end without having to stop for further buffering of content."

비디오에 바인딩되는 특수한 이벤트로, 비디오가 준비되면 실행되는 이벤트이다!

drawImage 메소드

공식문서
drawImage 인자에 넣을 수 있는 세 가지

  • 비디오
  • 이미지
  • 또 다른 캔버스!

비디오 위에 낙서하기!

      const canvas = document.querySelector('.canvas');
      const ctx = canvas.getContext('2d');
// 캔버스 다룰 때 기본 세팅! 캔버스콘텍스트 가져오기
      ctx.font = 'bold 50px serif';
      ctx.fillStyle = 'red';
// 폰트 및 색상 세팅!

      const videoElem = document.querySelector('.video');
      videoElem.addEventListener('canplaythrough', render);

      const messages = [
        {time: 1, message: '1 ㅋㅋ', x: 100, y: 100},
        {time: 3, message: '2 ㅎㅎ', x: 300, y: 300},
        {time: 5, message: '3 ㅊㅊ', x: 400, y: 200}
      ];

      function render() {
        console.log(videoElem.currentTime);
        ctx.drawImage(videoElem, 0, 0, 600, 400);
        
        for (let i = 0; i < messages.length; i++) {
          if (videoElem.currentTime > messages[i].time) {
            ctx.fillText(messages[i].message, messages[i].x, messages[i].y);
          }
        }
        // 글자쓰는 방식을 잘 살펴보면, 전체 다 지웠다가 새로 쓰는 것임!
        // 이미 쓴 것 킵하고 그런 개념이 아니다.

        requestAnimationFrame(render);
      }

fillText

공식문서
쉽게 말해 캔버스에 글씨 써주는 메소드이다.

사실 자막 넣는 건 그냥 비디오에서 currentTime 속성 가져와서 쓰면 된다!

비디오 그래픽 조작하기!

강의에서 다룬 예제는 색상값 조절해서 RGB에 따른 필터 버튼을 생성하는 것이었다.
캔버스로 비디오를 다루는 이유는 다시 한 번 강조하지만, 그래픽 조작이 가능하기 때문이다.
이때 아주 중요한 메소드가 바로!

getImageData()

공식문서
getImageData로 가져온 데이터에서 data라는 속성으로 값을 불러내면 그 안에 픽셀 색상값이 전부 담겨 있다!

      function render() {
        ctx.drawImage(videoElem, 0, 0, 600, 400);
        imageData = ctx.getImageData(0, 0, 600, 400);
        leng = imageData.data.length / 4;

        for (let i = 0; i < leng; i++) {
          switch (colorValue) {
            case "red":
              imageData.data[i * 4 + 0] = 255;
              break;
            case "green":
              imageData.data[i * 4 + 1] = 255;
              break;
            case "blue":
              imageData.data[i * 4 + 2] = 255;
              break;
          }
        }
        // 컬러 밸류에 따라 rgba에 해당하는 부분을 최대치로 끌어올려주는 원리!

        ctx.putImageData(imageData, 0, 0);
        requestAnimationFrame(render);
      }

      btnsElem.addEventListener("click", function (e) {
        colorValue = e.target.getAttribute("data-color");
      });
profile
부정확한 정보나 잘못된 정보는 댓글로 알려주시면 빠르게 수정토록 하겠습니다, 감사합니다!

0개의 댓글