본문 바로가기
REACT

[클론코딩] 따라하며 배우는 노드, 리액트 시리즈 - 유튜브 사이트 만들기 #5. ffmpeg로 비디오 썸네일 생성하기

by kmyobin 2022. 8. 23.


1. 썸네일 생성을 위한 dependency 다운 받기

 

FFmpeg : 멀티미디어 디코딩, 인코딩, 스트리밍 에 대한 모든 기능을 제공하는 오픈 소스 라이브러리

맥은 설정하기 쉽다는데 나는 윈도우라 ^^ ;; 구글에 치면 ffmpeg 다운로드 방법 굉장히 많이 나온다

난 7z 파일 압축 해제를 못해서 아래의 사이트에서 압축을 풀어주었다

 

압축 풀기 사이트 : https://extract.me/ko/

 

아카이브 추출기 온라인

이 앱이 Google 드라이브와 함께 작동하도록 승인하세요. OK

extract.me

 

환경변수 편집까지 마치고 나서 

npm install fluent-ffmpeg --save

해주면 끝이 난다

 

 

 

2. 서버에 저장된 비디오를 이용한 썸네일 생성, 3.생성된 썸네일을 서버에 저장

저번에 콘솔로 서버에서 온 data를 찍어봤을 때

fileName과 url이 있었다!

 

썸네일에 넘겨주려고 이것을 변수로 설정해줄 것이다

 

 

비디오를 업로드할 때 썸네일을 생성해줄 것이기 때문에 Axios.post('/api/video/uploads') 안에다 또 다시 Axios.post를 해준다

VideoUploadPage.js에 있는 onDrop function 안에 아래의 코드를 작성한다

    Axios.post('/api/video/uploads', formData, config)
    .then(response => {
      if(response.data.success) {
        console.log(response.data);

        let variable = {
          url : response.data.url,
          fileName: response.data.fileName
        }

        Axios.post('/api/video/thumbnail', variable)
        .then(response => {
          if(response.data.success){

          }
          else{
            alert("썸네일 생성에 실패했습니다.")
          }
          
        })
      }else{
        alert('비디오 업로드에 실패했습니다.')
      }
    })

 

 

그리고 video.js로 가서 client에서 받은 정보를 처리한다

router.post('/thumbnail', (req, res) => {
  // 썸네일 생성 후 비디오 정보(러닝타임) 가져오기

  let filePath = ""
  let fileDuration = ""


  // 비디오 정보 가져오기
  ffmpeg.ffprobe(req.body.url, function(err, metadata){ // video 넣고나서
    console.dir(metadata);
    console.log(metadata.format.duration);
    fileDuration = metadata.format.duration; // metadata 가져와서 정보 넣기
  })

  // 썸네일 생성
  ffmpeg(req.body.url) // client에서 온 video 저장 경로
  .on('filenames', function (filenames) {
    console.log('Will generate ' + filenames.join(', '))
    console.log(filenames)

    filePath = "uploads/thumbnails/"+filenames[0]
  })
  .on('end', function () { // 썸네일 생성 후 작업
    console.log ('Screenshots taken');
    return res.json({ success: true, url: filePath, fileDuration: fileDuration})
  })
  .on('error', function (err){
    console.error(err);
    return res.json({success: false, err});
  })
  .screenshots({
    // Will take screenshots at 20%, 40%, 60%, 80% of the video
    count: 3, // 3개의 썸네일 촬영 가능
    folder: 'uploads/thumbnails',
    size: '320x240',
    filename: 'thumbnail-%b.png' // %b : input basename(확장자 제외)
  })

})

 

 

잘 되는지 확인하기 위해 실행해봤는데 504 에러가 떴다

그래서 video.js에서 ffmpeg 쓰기 직전 상단에 아래의 코드를 넣어주었더니 해결됐다

  ffmpeg.setFfmpegPath("C:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe");

 

 

url, fileDuration 잘 왔당

썸네일과 비디오도 잘 들어감

 

 

 

4. 썸네일 이미지 파일 경로를 클라이언트에게 보내기

아까 video.js에서 썸네일 생성에 성공했을 경우 아래의 코드가 실행되었다

  .on('end', function () { // 썸네일 생성 후 작업
    console.log ('Screenshots taken');
    return res.json({ success: true, url: filePath, fileDuration: fileDuration})
  })

url과 fileDuration으로 왔다는거지~ 

 

그럼 클라이언트로 가서 써먹어보자

 

VideoUploadPage.js에 const 상수를 3개 더 만들어준다

  const [FilePath, setFilePath] = useState("")
  const [Duration, setDuration] = useState("")
  const [ThumbnailPath, setThumbnailPath] = useState("");

그 다음 onDrop 함수 안에서 손을 좀 봐준다

 

받아온 파일 경로는 Axios.post('/api/video/uploads') 안에, 받아온 지속 시간과 썸네일경로는 Axios.post('/api/video/thumbnail') 안에 작성하였다

 

 

그리하여 완성된 onDrop 함수는 아래와 같다

  const onDrop = (files) => {
    let formData = new FormData;
    const config = {
      header: {'content-type': 'multipart/form-data'}
    }
    formData.append("file", files[0])

    // Axios 이용하여 request를 서버에 보냄
    // 위에 것들 보내주지 않으면 파일에 오류 발생
    Axios.post('/api/video/uploads', formData, config)
    .then(response => {
      if(response.data.success) {
        console.log(response.data);

        let variable = {
          url : response.data.url,
          fileName: response.data.fileName
        }

        setFilePath(response.data.url)
        

        Axios.post('/api/video/thumbnail', variable)
        .then(response => {
          if(response.data.success){
            console.log(response.data);

            setDuration(response.data.fileDuration)
            setThumbnailPath(response.data.url)
          }
          else{
            alert("썸네일 생성에 실패했습니다.")
          }
          
        })
      }else{
        alert('비디오 업로드에 실패했습니다.')
      }
    })
  }

 

 

 

5. 썸네일 이미지를 화면에 표시

          {/*Thumbnail*/}
          {ThumbnailPath &&
            <div>
              <img src={`http://localhost:5000/${ThumbnailPath}`} alt="thumbnail" />
            </div>
          }

 

ThumbnailPath가 null값이 아닐 경우 이미지를 띄운다

ThumbnailPath는 참고로 서버에 저장되어있으므로 앞에 localhost:5000을 붙여주었다

 

 

댓글