언어/자바스크립트

동영상 썸네일 생성 방법(Blob, Canvas, video)

youngble 2023. 10. 24. 23:38

인트로

영상을 보기전에 활용되는 썸네일은 우리가 흔하게 유튜브, 인스타, 페이스북 등 여러 매체를 통해 볼수있다.

하지만 이러한 영상 썸네일을 영상자체속성으로써 보여줄지 아니면 이미지로 추출하여 보여줄지 등

썸네일을 만드는 방법이 여러가지 있지만 그중 현재 서비스에서 사용하는 방식을 설명하고자한다.

결과

위는 mp4 동영상을 선택했을때 img태그에 썸네일을 보여주는 결과물이다.

 

이렇게 만들기위해선 몇가지 기본적인 개념을 이해가 필요하다.

 

1. Blob

2. Canvas

 

먼저 Blob을 알아보면 Binary Large OBjects 의 약자로 바이너리 형태로 큰 오브젝트를 저장한다고 할수 있고, 주로 이미지, 비디오, 사운드 등의 멀티미디어 객체를 나타낸다.

 

Blob 객체 자체로 봤을때는 사실 데이터가 아닌 데이터를 간접적으로 접근하기 위한 포인터 객체이다. 위의 결과 GIF에서 파일 선택 버튼을 클릭하여 비디오를 선택한 파일 역시 기본적으로 File객체는 blob 객체로 되어있다. 전체 코드는 다음과 같다

<body>
<script>
  const FileURL = (e) => {
        const type = e.files[0].type
 try {
          if (type.includes('video')) {
            const blobURL = URL.createObjectURL(e.files[0])
            const videoEle = document.getElementById('video-play')
            videoEle.src = blobURL
            videoEle.autoplay = true
            videoEle.currentTime = 1

            videoEle.onseeked = (event) => {
              const target = event.target

              target.pause()
              const canvasElement = document.getElementById('canvasDraw')
              //canvas style
              canvasElement.style.position = 'fixed'
              canvasElement.style.top = '0'
              canvasElement.style.right = '0'
              canvasElement.style.width = '1px'
              canvasElement.style.height = '1px'
              canvasElement.style.opacity = '0'
              canvasElement.style.pointerEvents = 'none'
              canvasElement.style.zIndex = '-9999'

              const context = canvasElement.getContext('2d')

              // canvas 실제 그리는 공간의 width, height값
              canvasElement.width = target.videoWidth
              canvasElement.height = target.videoHeight

              // Canvas 에 그릴 media와 위의 canvas 그리는 공간 중 어디까지의 좌표를 그릴지 결정
              context.drawImage(
                target,
                0,
                0,
                target.videoWidth,
                target.videoHeight,
              )
       
              const imageeURL = canvasElement.toDataURL('image/jpeg')
              document.getElementById('merged-image').src = imageeURL
            }
          }
      } catch (e) {
          console.log('error', e)
        }
   }
</script>
<div>
<input type="file" onchange="FileURL(this)" />
</div>
</body>

 

파일을 선택하면 onChange 이벤트가 발생하고 이때 발생한 event를 파라미터로 받고 event.files[0]를 통해 해당 파일을 선택한다.

이 file blob객체를 DOM 이나 CSS에서 사용하기위해선 URL 형식으로 만들어야하는데 이때사용하는 것이 URL.createObjectURL 메서드이다. 그러면 이 Blob형식의 file을 주어진 객체를 가리키는 URL을 blob:http://localhost 란 형식의 DOMString으로 변환하는 기능을 한다.

그다음 썸네일을 만들고자하는 video 객체를 설정해준다. 먼저 DOM 트리에 미리 만들어 놓은 'video-play' 라는 id를 가진 video태그객체를 javascript를 통해 불러와 변수에 담아준다. 위의 코드를 보면 document.getElementById 를 사용하였다.

const videoEle = document.getElementById('video-play')
            videoEle.src = blobURL
            videoEle.autoplay = true
            videoEle.currentTime = 1

위와같이 videoEle 변수에 선택한 video 태그 요소 객체를 담고 src, autoplay, currentTime 속성을 넣어준다. 

먼저 src는 우리가 URL.createObjectURL을 통해 만들었던 DOMString을 넣어 영상 파일로 사용하고 autoplay를 통해 해당 비디오가 있으면 바로 재생하도록 하였다. currentTime은 썸네일만들기위해 사용할 onseeked 이벤트를 발생하기위해 사용하는데 이는 재생되는 시점을 1초로 이동(shift)시키는것을 의미한다. 

 

onseeked 이벤트가 발생했을때 event 파라미터로서 사용한 video 요소 객체를 변수에 담고, pause 메서드를 사용하여 영상을 정지시킨다. 그이후 canvas 요소를 가져와 getContext 메서드를 통해 드로잉 컨텍스트(drawing context)를 가져오고 width, height값을 으로 크기를 지정한다. 그다음 drawImage 메서드를 통해 첫번째 인수로 비디오 요소 객체를 넘겨주고, 2~5번째 인수로 비디오 객체에서 어느 영역까지 그려줄건지 정한다. 드로우가 만들어 졌기에 해당 canvas 객체에서 toDataURL()을 사용하여 바이너리 파일을 Base64로 인코딩하여 ASCII 문자열 형식으로 변환하여 data: 라는 접두사가 붙는 url을 사용한다.

dataURL, base64 인코딩

이렇게 만들어진 url 을 image 태그 src에 넣어 화면에 렌더링해준다. 

 

이렇게 하여 동영상을 이용한 썸네일 만들기가 완성된다.