안녕 깃갤러들아
오늘은 Github라는 갤명에 맞게 내 오픈소스 프로젝트를 공유하고, 프로젝트에 참여할 collaborator를 모집하기 위해 글을 써
글을 읽어보고 혹시라도 프로젝트에 참여할 흥미가 생겼다면 댓글 남겨주길 바래




Introduction

OliveOpensource Lightweight Video Editor 라는 뜻으로 지은건데, 말 그대로 오픈소스 비디오 에디터 프로그램을 만드는게 목표야

Lightweight는 지향은 하고자 하지만 솔직히 이 부분을 달성하려면 멀고도 먼 이야기라..


요즘 유튜브가 굉장히 핫해지면서 많은 편집자들이 Premiere proFinal cut Pro를 이용해서 편집을 하고 있는데, 사실 PPFCPX는 유튜브같은 가벼운 편집 스타일도 당연히 작업이 가능하지만 태생 자체가 영화 편집같은 프로페셔널 유즈를 위해서 만들어진 프로그램이기 때문에 유튜브 편집만을 위해서 사용하기에는 좀 과한 부분이 있지.


최근에는 업데이트를 통해서 자막 기능도 보강하는 등 유튜브 편집에 대한 편의성을 강화하는 중이기도 해. 또 어도비에서 최근 Premiere Rush 라는 프로그램을 만들었는데, 데스크탑 뿐만 아니라 모바일에서도 영상 편집이 가능한 앱으로, 예전 Windows Movie Editor처럼 심플한 인터페이스와 기능을 제공하고 있어. 이렇게 프로그램을 따로 내놓을 정도로 유튜브 편집 / 개인 영상 편집에 대한 영상 편집쪽의 관심도 핫하다고 할 수 있지.


사실 Premiere Rush는 오늘 화장실에서 유튜브보다가 알았는데 1차적인 목표를 이 Premiere Rush 정도의 기능을 구현하는걸 목표로 잡아야 겠다고 생각했어.


상업적인 모델같은건 생각해본적 없고, 내 개인적 취미와 실력 향상을 위해 꾸준히 개발하는 중이야. 놀고먹는 시간이 더 많지만.


현재까지의 프로그램은 이렇게 생겼어.




<embed src="https://giphy.com/embed/hWAaErKA0NpgQNOrst" width="480" height="296" frameborder="0" class="giphy-embed">

via GIPHY


움짤 재생이 안된다면 이미지를 클릭하거나, 여기로

https://giphy.com/gifs/hWAaErKA0NpgQNOrst


보는 것 처럼 아직 많은 기능은 없어.


영상 리소스를 Drag and Drop으로 불러오고, (현재는 .mp4만 지원) 타임라인에 끌어놓고, 키프레임 애니메이션을 주고, 재생하는 장면이야.


사실상 지금 구현되어있는 모든 기능을 단 10초만에 모두 보여준거라고 보면 돼






Structure

Electron은 많이 들어봤겠지만 웹 플랫폼을 데스크탑 앱에서 활용할 수 있도록 해주는 플랫폼이야


요즘 가장 많이 에디터인 VSCode 라던가, 대표적인 보이스 채팅 서비스로 자리잡은 DiscordElectron으로 만들어졌지


Electron을 플랫폼으로 택한 이유는 GUI를 프로그래밍하는데에 가장 파워풀한 도구가 웹이라고 생각하기 때문이야


예로 부터 크로스 플랫폼을 지원하는 GUI 프레임워크로는 Qt, GTK, Swing 등이 많이 쓰였지만, 최근 추세는 역시 웹이라고 생각해


HTML/CSS 자체가 워낙 사용하기 쉽고, 파워풀하고, ReactVue같은 라이브러리까지 활용하면 금상첨화기 때문이지


사실 프로젝트를 처음 착수한게 1년 전인데, 그 당시에는 비디오 편집 프로그램에 필요한 스펙들, 예를 들면 디코딩, 비디오 렌더링, 오디오 렌더링 등이 가능한가? 를 고려하기 보단 다른 거지같은 GUI 프레임워크는 죽어도 사용하기 싫었기 때문이야


Olive는 다음과 같은 구조로 이루어져있어.





Electron을 사용해본 사람이라면 알겠지만 ElectronNodeBrowser, 두 영역으로 나뉘어져.


우선 Browser 영역은 웹 브라우저가 실행되는 영역이야. Chrome 브라우저가 하나의 독립적인 프로그램으로 돌아간다고 보면 돼. 여기서 우리는 일반적인 웹 프로그램을 실행시키게 돼.


Node 영역은 백그라운드에서 돌아가는 영역으로, 우리가 흔히 사용하는 Node 프로그램이 똑같이 돌아간다고 보면 돼. 이 영역에서 Browser를 생성하고, 관리하게 돼.


두 영역은 독립적인 프로세스로 돌아가기 때문에 서로 메모리를 공유한다거나 하는 일은 할 수 없어.


Electron이 데스크탑 프로그램을 만드는 데 사용될 수 있는 이유는 Node 환경을 Browser에서도 사용할 수 있기 때문이야. Node에서는 fs 같은 모듈을 통해서 시스템 파일에 접근하는 등 기존 웹 브라우저 보안이라는 장벽에 가로막혀있던 기능들을 사용할 수 있기 때문에, 이런 기능을 브라우저에서 사용할 수 있게 됨으로써 데스크탑 프로그램을 만들 수 있게 된 것이지.


다시 Olive 구조로 넘어와서, NodeBrowser를 생성하고 관리하는 역할을 하고 있어. 그 외에는 다른 일을 하지 않아.


모든 일들은 Browser에서 일어나게 돼. Browser 밑에는 Internal BrowserWindow Browser 라는 두 가지 브라우저가 존재해. 즉 두 개의 크롬 웹 브라우저가 열려있다고 생각하면 돼.


Internal Browser는 프로그램의 핵심 데이터들이 관리되는 곳이야. 비디오 에디터라면 프로젝트 데이터, Timeline에 대한 데이터, Track에 대한 데이터 등이 가장 아래에 깔려있는 핵심 데이터가 되겠지? 즉 백엔드라고 보면 돼.


Window Browser는 이 핵심 데이터들을 View로 보여주는 곳이야. Timeline같은 데이터를 유저가 조작할 수 있도록 View로 제공해주는 부분이지. 즉 프론트엔드라고 보면 돼.


앞서 말했지만 위 두 개는 브라우저야. 크롬 창이 두 개 띄워져있다는 말이지. 일반적으로 Chrome에서 브라우저끼리는 메모리를 공유하지 않거나(사이트 간 도메인이 달라서 프로세스 자체가 다른 경우가 대부분이야. 그래서 크롬 탭을 덕지덕지 띄워놓고 작업 관리자를 보면 엄청난 수의 크롬 프로세스가 생성되었는걸 흔히 볼 수 있지), 공유한다고 하더라도 Javascript context를 서로 공유하지 않아. 하지만 예외적인 상황이 하나 있지. 바로 브라우저가 다른 브라우저에 의해 팝업으로 생성되었을 때야.


팝업으로 생성된 브라우저 끼리는 서로 Javascript context를 공유하기 때문에, 다른 브라우저의 Javascript 객체에 바로 접근하는 일이 가능하지. 즉 Window BrowserInternal Browser에 의해 생성된 (window.open(....)) 자식 팝업 브라우저의 관계야. 같은 프로세스 상에 존재하고, 같은 Javascript context를 공유하지. Window Browser가 생성되면 Internal Browser로 부터 데이터들을 전달받고, 이 데이터들을 이용해 View를 렌더링하게 돼.




Window Browser

Window BrowserReact + mobx 를 기반으로 디자인되어 있어. 아래에는 여러 Widget들이 있어. 이건 보통 프로그램들에서 Window라고 부르는 패널들이야.


현재 만들어진 Widget

  • TimelineWidget - 타임라인 위젯
  • ResourceWidget - 불러온 영상 파일등을 나타내는 위젯
  • EffectControlWidget - 키프레임 애니메이션을 나타내는 위젯
  • MonitorWidget - 영상 프리뷰를 보여주는 위젯

으로 총 4가지가 정말 기본적인 기능만을 해서 구현되어 있어.







WidgetMVVM을 기반으로 한 약간 혼종의 디자인을 따르고 있어. MVVMModel-View-ViewModel 디자인의 약자로, 디자인 철학은 구글링해보면 바로 나올거야.

여기서 ModelInternal Browser에 존재하는 핵심 데이터들이고, ViewModel은 그 핵심 데이터들을 View에 맞게 랩핑한 모델이야.


예를 들면, TimelineInternal Browser에 존재하는 핵심 데이터인데, 이 TimelineTimelineWidgetEffectControlWidget 등 여러가지 위젯에서 사용될 수 있어. 두 위젯은 같은 Timeline을 사용하지만, 그 Timeline을 어떻게 조작해야 하는지, Timeline에 대한 어떤 추가적인 데이터가 필요한지는 위젯의 특성에 따라 또 나뉘겠지? 그래서 같은 Timeline을 사용하더라도 TimelineWidget은 TimelineWidgetTimelineViewModel을, EffectControlWidget은 EffectControlWidgetTimelineViewModel이라는 ViewModel을 만들어서 각자 위젯에 필요한 인터페이스들을 구현하고 있어.


그리고 필요에 따라 Controller도 만들어서 사용하고 있어. 예를 들면 아래와 같이 타임라인 트랙 아이템을 조작하는 기능은 TimelineWidgetManipulatorController 라는 Controller가 모두 담당해.



움짤 재생이 안된다면 이미지를 클릭하거나, 여기로

https://giphy.com/gifs/URw9g8wBmuwyVhZRv6


Rendering

마지막으로 렌더링 부분이야. 렌더링은 비디오 렌더링과 오디오 렌더링이 필요하겠지. 비디오 렌더링과 오디오 렌더링은 모두 별도의 WebWorker 에서 돌아가. WebWorker는 별도의 Thread라고 보면 돼. 한 가지 주의해야 할 점은, 일반적으로 알고있는 Thread에서는 메모리가 공유되지만, WebWorker는 같은 프로세스에서 돌아간다고 하더라도 메모리가 공유되지 않아.


애초에 렌더링 작업을 생각해보면 메모리가 공유되는것도 문제야. UI Thread(브라우저가 돌아가는 메인 Thread)와 Rendering Thread에서 같은 데이터를 공유해서 사용한다면, UI 업데이트가 일어나거나 렌더링이 진행되는 도중에는 해당 데이터에 Lock을 걸어야하는데, 이렇게 되면 UI 작업때문에 렌더링이 지연되거나, 렌더링때문에 UI 쓰레드가 지연된다면 최악의 유저 경험으로 이어지겠지.


그래서 UI Thread에서 데이터가 업데이트될 때 마다 렌더링 Thread들에 해당 데이터를 복사하는 방식을 쓰고 있어. UI Thread에서 데이터가 업데이트되면, 이 데이터들을 렌더링 Thread에 보내주고, 복사된 데이터들을 가지고 비디오/오디오를 렌더링하는거지. 렌더링 Thread에서 데이터를 수정하는 일은 일어나지 않아.

비디오 렌더링에는 FFMPEGWebGL을 사용하고 있고, FFMPEG는 앞에서 언급한 C/C++ Native Module을 이용해서 작성되었어. 여기 지금 좀 치명적인 버그가 있는걸로 보이는데 수정하기가 꽤 쉽지 않아보여서 일단은 그대로 놔두고 있어.


오디오 렌더링에는 Web Audio API를 사용하고 있어. 우선 불러와진 사운드 데이터를 FFMPEG를 이용해 압축을 푼 RAW 파일로 만들고, 이 RAW 파일을 재생시키고 있어. 이는 latency를 줄이기 위함인데, Adobe Premiere Pro에서도 이와 같은 과정을 똑같이 거치고 있어. 만약 .mp3 같은 압축된 파일들을 압축을 풀지 않고 그대로 사용한다면 오디오를 렌더링하기 위해 매번 압축을 푸는 과정이 필요할거고, 이는 지연으로 이어지겠지. 비디오도 이와 같은 과정이 있으면 좋겠지만 비디오는 압축을 풀게 되면 용량이 테라바이트정도는 가뿐하게 넘기기 때문에 현실적으로 불가능한 이야기지.




Build

빌드 과정이 지금은 정갈하지 않고 복잡한 부분이 있어서 우선은 궁금하다면 미리 빌드된 파일을 받아서 실행해보는 옵션밖에 없어. 이것도 잘 실행될진 잘 모르겠네. 윈도우 x64만 되고, 빌드한 CPU가 AMD라 Intel에서도 잘 돌아갈지는 모르겠다.


https://drive.google.com/file/d/1jjSOzs5Ke5qKh7iKUE6MA6TKKNHboYYa/view?usp=sharing

  1. NodeJS 필요
  2. 콘솔 창 오픈
  3. > npm install -g http-server
  4. > cd olive-dump
  5. > cd dist/app
  6. > http-server -c-1
  7. 새로운 콘솔 창 오픈
  8. > cd olive-dump
  9. > ./Release/electron.exe ./dist/main/main.js
에러가 난다거나 하면 댓글 남겨줘



Looking for collaborators

프로젝트를 시작한지 1년이 넘어가는데 사실 놀고먹고 한 시간도 많아서 처음 계획한 것 보단 훨씬 뒤쳐지게 개발하고 있는 상황이야. 그래도 매년 재밌는 프로젝트가 없나 찾다가 짜잘한 것 정도나 만들던가, 그것조차도 때려치웠던 옛날을 생각해보면 이 정도 온것도 내 기준으론 꽤 잘 끌어왔다고 생각해. 프로젝트 레벨이 내 기준으로 난이도가 크게 쉽지도, 크게 어렵지도 않은 수준이라 지루해지지 않는 부분도 한 몫 하는 듯 해.


그럼에도 최근에는 속도가 점점 더뎌지고 있는데, 가장 큰 이유는 그래픽 렌더링에 대한 부분이야. Premiere Pro를 다뤄본 사람들은 알겠지만, 이 프로그램에는 각 트랙 아이템에 여러가지 효과, 예를 들면 블러 효과라던지, 마스크 효과라던지 하는 효과를 추가하는 기능이 있어. 우선 이런 기능을 어떻게 만들어야 할지 막막하더라고. 대강적인 느낌은 알겠는데, 그래픽스쪽은 뭔가 내 취향이랑 안맞는듯 --;


규모가 좀 있어지다보니, 설계가 엉망인 부분도 많고, 만들어놓은 설계도 이게 맞을까 항상 의문을 가지면서 코딩을 하고 있어. 1년이라는 시간동안에도 진행이 더딘것도 같은 내용을 가지고서 리팩토링만 한 3번은 해서 그런것도 있거든. 그리고 여기저기 건드려야 할 부분이 많아졌어. TimelineWidget만 해도 아직 만들어야 할 기능이 산더미고, 누군가 물어보고 의논할 사람이 있다면 서로의 의견을 공유하면서 발전할 수 있을거라 생각해.


그래서 함께 프로젝트를 만들어 갈 Collaborator를 찾고 있는 중이야. 참여자로써 개발 지식은 어느정도 있었으면 해. 내가 글을 조리있게 잘 쓰는편은 아니지만 적어도 여기서 말한 내용/용어들을 이해할 수 있는 정도라면 괜찮지 않을까.

그래픽스쪽을 맡아줄 수 있는 사람이 있다면 정말 좋겠고, 디코딩 모듈 / 렌더링 모듈 / UI 모듈(Typescript) 등 어느쪽이라도 관심이 있으면 댓글 남겨주길 바래.

Repository: https://github.com/orange4glace/olive