프론트엔드 개발자는 동영상을 어떻게 편집해야할까?
Bestmoments는 사용자가 짧은 영상들을 빠르게 업로드 해야하고, 그 영상을 간단한 링크로 쉽게 공유할 수 있도록 하는 플랫폼 입니다. 영상을 짧은 시간안에 공유 가능한 상태로 만들어 주는 것이 주 목표 입니다.
하지만 문제는, 프론트엔드에서 동영상 편집을 처리하는 방법입니다. 동영상을 자르거나 인코딩하는 작업을 클라이언트에서만 처리하는 것은 성능과 안정성에서 여러 한계가 있었습니다.
과정
1. 프론트엔드에서의 동영상 편집 문제점
BestMoments 프로젝트를 진행하던중, "프론트엔드에서 동영상을 직접 편집하면 어떨까?" 라는 생각을 했었습니다.
그 과정에서 FFmpeg의 웹 어셈블리(WebAssembly) 버전을 사용해 동영상을 클라이언트측에서 처리하려 했습니다.
그러나 이를 사용하면서 몇 가지 문제가 있었습니다.
1.1 성능 문제
처음엔 FFmpeg 웹 어셈블리를 이용해 브라우저 내에서 동영상 편집과 인코딩을 시도했습니다. 하지만 큰 용량의 영상 파일이나 고화질 영상의 경우, 브라우저에서 처리하는데 정말 많은 시간이 소요되고, 특히 저사양 기기나 모바일 환경에서는 브라우저가 멈추거나, 심지어 충돌이 발생하는 일도 있었습니다.
- 긴 처리 시간 - 짧은 영상이라도 고화질일 경우 인코딩에 꽤 오랜시간이 걸렸습니다. 사용자 입장에서는 즉각적인 결과를 기대하는데, 처리 속도가 느리면 사용자가 이탈할 가능성이 높아집니다.
- 리소스 소모 - 웹 어셈블리는 브라우저 내에서 CPU와 메모리를 상당히 많이 사용하기 대문에, 동영상을 자르고 인코딩하는 작업은 상당한 리소스를 소모했습니다. 그 결과, 브라우저 성능이 저하되거나 멈춤 현상이 발생했습니다.
1.2 제한적인 기능
FFmpeg 웹 어셈블리는 어느 정도 동영상 처리를 가능하게 했지만, 서버에서 FFmpeg 바이너리를 직접 사용하는 것 만큼 완전한 기능을 제공하지는 않았습니다. 현재는 버전 지원이 멈춘 상태일 뿐더러, 다양한 포맷으로 변환하거나 여러 해상도를 동시에 처리하는 데 있어 한계가 있었습니다.
1.3 유지 보수 문제
1.2와 같은 이유로 앞으로의 프로젝트 확장성을 고려했을 때, 유지보수에 대한 부담이 크게 다가왔었습니다. 라이브러리 업데이트나 지원 중단에 따른 문제가 발생할 가능성이 있었고, 이는 장기적인 프로젝트 운영에 적합하지 않다고 느꼈습니다.
2. FFmpeg 바이너리로 해결하기: 백엔드에서의 동영상 처리
이러한 프론트엔드에서의 문제를 해결하기 위해서는 백엔드에서 동영상 처리를 맡기는 것이 훨씬 효율적 입니다.
이를 위해 FFmpeg 라는 오픈소스 도구를 사용할 수 있습니다. FFmpeg는 웹 어셈블리 버전보다 최적화된 동영상과 오디오를 변환, 편집, 인코딩할 수 있는 기능을 제공하며 작업을 빠르게 처리합니다.
FFmpeg는 기본적으로 명령어 기반으로 동작하는 프로그램이지만, 백엔드에서는 이를 프로세스로 실행하여 사용할 수 있습니다. 특히, Node.js에서는 child_process 모듈을 통해 FFmpeg 바이너리를 호출하여 사용합니다.
2.1 FFmpeg 명령어
FFmpeg 명령어는 다음과 같은 구조를 가집니다.
ffmpeg -i <input_file> [options] <output_file>
- -i <input_file>: 입력 파일을 지정하는 옵션
- [options]: 동영상 처리에 사용할 다양한 옵션을 추가할 수 있습니다.
- <output_file>: 처리된 결과를 저장할 파일 경로를 지정합니다.
이 명령어 구조에서 [options] 부분에 다양한 옵션을 추가하여 동영상 처리 방식을 정의할 수 있습니다.
옵션이 워낙 많다보니 BestMoments에서 주로 사용할 옵션들을 살펴보니
-ss <start_time>
동영상의 시작 시간을 지정하는 옵션입니다. -ss 뒤에 시간을 hh:mm:ss 형식으로 입력하여 그 시점부터 동영상 처리를 시작합니다.
// input.mp4 파일에서 10초 지점부터 동영상을 처리, 주로 영사으이 특정 구간을 자를 때 사용
ffmpeg -i input.mp4 -ss 00:00:10
-to <end_time>
동영상의 종료 시간을 지정하는 옵션, 시작 시간과 마찬가지로 hh:mm:ss 형식으로 입력하며, 이 시간이 끝나는 지점까지 동영상을 처리합니다.
// input.mp4 파일에서 10초부터 20초 까지의 구간을 자름
ffmpeg -i input.mp4 -ss 00:00:10 -to 00:00:20
-vf <video_filter>
비디오 필터를 지정하는 옵션, scale 필터를 사용하여 동영상의 해상도를 조정할 수 있습니다.
// 영상 비율을 1920:1080 비율로 맞춤
// 주로 동영상을 360p, 720p, 1080p 로 변환할때 자주 사용되는 방식
ffmpeg -i input.mp4 -vf scale=1920:1080 output_1080p.mp4
옵션 요약
- -i: 입력 파일 지정
- -ss: 시작 시간 지정 (동영상을 자르기 위한 시작 지점)
- -to: 종료 시간 지정 (동영상을 자르기 위한 끝 지점)
- -vf: 비디오 필터 적용 (해상도 조정을 위한 scale 필터 사용)
BestMoments 코드에서 FFmpeg 실제 사용 예시
FFmpeg로 동영상을 자르고 인코딩하기
const ffmpegProcess = spawn(ffmpegPath, [
'-i', inputFilePath, // 입력 파일 경로
'-ss', startTime.toString(), // 시작 시간
'-to', endTime.toString(), // 종료 시간
'-vf', scale, // 해상도 변경 (비디오 필터)
outputFilePath // 출력 파일 경로
]);
이 코드는 FFmpeg를 사용해 동영상을 자르고 지정된 해상도로 인코딩하는 작업을 처리합니다.
-ss, -to, -vf 옵션을 사용해 시작 시간, 종료 시간, 그리고 해상도 변경을 지정합니다.
여러 해상도 처리방법
const resolutions = [
{ name: '360p', scale: 'scale=-2:360' },
{ name: '720p', scale: 'scale=-2:720' },
{ name: '1080p', scale: 'scale=-2:1080' },
];
BestMoments에서는 동영상을 여러 해상도로 변환하여 저장합니다. 예를들어 360p, 720p, 1080p로 변환하려면 각각 다른 해상도를 적용한 FFmpeg 명령어를 병렬로 실행하여 작업을 동시에 처리합니다.
BestMoments에서는 각 해상도별로 FFmpeg 프로세스를 실행하고 또한 사용자가 인코딩 과정이 얼마나 남았는지 확인하기위해 websocket을 통해 클라이언트에 상태를 업데이트 하였습니다.
resolutions.forEach(({ name, scale }) => {
const outputFileName = `${path.parse(originalFileName).name}_${name}.mp4`;
const outputFilePath = path.join(outputDir, outputFileName);
console.log(`Starting FFmpeg process for ${name} resolution...`);
const ffmpegProcess = spawn(ffmpegPath, [
'-i', inputFilePath, // 입력 파일 경로
'-ss', startTime.toString(), // 시작 시간
'-to', endTime.toString(), // 종료 시간
'-vf', scale, // 해상도 변경 (비디오 필터)
outputFilePath // 출력 파일 경로
]);
// FFmpeg 작업이 완료되면 WebSocket으로 클라이언트에 알림
ffmpegProcess.on('close', (code) => {
if (code === 0) {
console.log(`FFmpeg ${name} 인코딩 완료, 코드: ${code}`);
completedResolutions++;
if (completedResolutions === resolutions.length) {
ws.send(JSON.stringify({ status: '완료' }));
ws.close(); // 모든 해상도 처리 완료 시 WebSocket 연결 종료
}
} else {
console.error(`FFmpeg ${name} 인코딩 중 오류 발생, 코드: ${code}`);
ws.send(JSON.stringify({ error: `FFmpeg 오류 발생, 코드: ${code}` }));
}
});
});
1. 360p, 720p, 1080p 해상도로 변환할 각 동영상을 지정합니다.
2. spawn을 통해 각 해상도에 맞는 FFmpeg 명령어를 병렬로 실행하여 동시에 처리합니다.
3. FFmpeg 프로세스가 완료될 때마다 close 이벤트가 발생하여, 완료된 해상도에 대해 로그를 남기고, WebSocket을 통해 클라이언트에 처리 완료 상태를 알려줍니다.
4. 모든 해상도 처리가 완료되면 ws.close() 로 Websocket 연결을 종료합니다.
결론
Bestmoments 프로젝트에서는 FFmpeg를 사용해 동영상을 자르고 여러 해상도로 인코딩하는 작업을 백엔드에서 처리합니다. 동영상 자르기와 해상도 변경을 통해 동영상 파일을 생성하고, Websocket을 통해 실시간으로 상태를 업데이트하는 방식으로 사용자에게 좀 더 나은 경험을 제공합니다.
이러한 구조를 통해 프론트엔드에서는 좀 더 페이지 렌더에 대해 집중할 수 있게 되었고 , 기존 웹 어셈블리보다 더 빠르고 효율적인 동영상 편집 시스템을 구축할 수 있었습니다.
구현 코드 보러가기
'프로젝트' 카테고리의 다른 글
1. BestMoments 프로젝트: 기획 단계에서 배우는 것들 (0) | 2024.07.01 |
---|