FFmpeg를 이용한 영상 편집 프로그램 개발 시작

치킨치·2024년 12월 21일
0

동기

다양한 환경에서 동영상을 쉽게 편집할 수 있는 vrew앱을 발견했다.
어떻게 만들었을까 분석한 결과 FFmpeg의 기능을 UX로 잘 풀어낸 것 뿐이라는 결론에 도달한다.
FFmepg가 핵심인 것이다.
FFmepg는 CLI로 작동하기 때문에 명령어 노하우만 가지고 있다면 핵심기능을 따라 만들 수 있을 것이다.
원체 만들어진 솔루션을 사용하기 싫어하는 나로서는 오랜만에 개발해보고 싶은 목표를 발견했다.
구글 검색결과 vrew앱은 멀티플랫폼을 지원하기 위해 eletron으로 개발된 게 아닐까라는 의심을 하고있다.
iOS, Android, Web, Windows를 모두 커버하기 위해서는 나쁘지 않은 선택이었을 것이다.
하지만 난 Flutter나 Eletron에 익숙하지 않기 떄문에, macOS, iOS 네이티브앱을 기반으로하여 유저 커버리지를 낮추지만 개발속도를 높이는 선택을 할 예정이다.
vrew는 편집중에도 preview player로 실시간으로 보는 기능을 제공하는데, 레코딩결과를 사용하는 것이 아니라 레코딩결과와 최대한 비슷하게 나오도록 preview player를 따로 개발한 게 아닐까 예상하고 있다, 물론 FFmpeg에서 실시간 렌더링 플레이 기능을 발견한다면 내 예상이 틀린것이겠지만.
FFmepg라는 강력한 개발도구를 발견했음에도 AI와 컨텐츠 편집기에 관심을 가져왔던 나에게 큰 자극이 되었다.
밥상은 만들어놨으니 숫가락만 만들어와라고 누가 손짓하는 것 같다.

앱의 예상 시나리오

  1. (앱이 꺼진 상태에서) 시리를 이용해 동영상 주제를 말한다.
  2. '동영상 주제'를 프롬프트화하여 AI서버에 쿼리를 던지고, 결과로 동영상에 사용할 텍스트 스크립트를 생성한다.
  3. 텍스트 스크립트의 분위기를 감지하고 동영상 제작 템플릿을 준비해둔다.
  4. 앱이 영상렌더링 준비가 끝난 화면으로 런칭되고, 사용자는 동영상의 프리뷰 플레이어를 즉시 볼수 있다.
  5. 만들어진 텍스트 스크립트, 템플릿, 일부 씬이 마음에 안든다면 각 프로세스의 refresh 버튼을 이용해 갱신한다.
  6. 만족할만한 프리뷰가 만들어지면 렌더링을 누른다.
  7. 렌더링 결과를 보고 어떤 플랫폼에 업로드할것인지 선택할 수 있다.

필수 구현 스펙

  • Preview Player의 슬라이더로 편집위치로 바로갈 수 있다.
  • Preview Player의 슬라이더 트랙 호버링 위치를 바꾸면 Thumbnail 이미지가 보인다.
  • Preview Player 최대화 버튼 (present UIViewController)
  • Preview Player 재생속도 조절 버튼
  • 여러 영상 조각이나 영상화된 이미지들이 Preview Player에서 하나의 영상처럼 보이는 기술
  • 현재 시간/총 시간 표시라벨이 있다.
  • 드래그로 대부분의 아이템을 옮길 수 있다.
  • 영상의 소리를 분석해서 STT를 뽑아낼 수 있다. (FFmpeg 명령어로 오디오만 뽑아낼 수 있다)
  • resource폴더에 원본을 저장하고, temp폴더에 원본을 수정한 파일을 모아두자. 원본의 복사본 또한 temp에서 관리되어야 한다.
  • 자주 사용하는 영상(인트로 같이)을 쉽게 추가할 수 있다.
  • 배경음 음량 및 구간 설정

기술 확보

워터마크 만들기

ffmpeg -i input.mp4 -i watermark.png -c:v libx264 filter_complex "[1]format=rgba,colorchannelmixer=aa=0.5[logo];[0][logo]overlay=5:5:format=auto,format=yuv420p" -c:a copy

영상 이어붙이기

concat 비디오 필터: 서로 다른 포맷이나 코덱의 파일을 재인코딩하여 결합할 때 사용한다.
concat demuxer: 동일한 포맷, 코덱, 해상도의 파일을 재인코딩 없이 결합할 때 사용한다.
concat 프로토콜: 파일 레벨의 결합을 지원하는 특정 포맷에서 사용한다. MP4에서는 사용하지 않는다.

Image to Video
results/video 경로에 있는 output_xxxx.png 파일들을 합쳐 result_video.mp4 파일로 저장하는 코드이다.

ffmpeg -framerate 30 -i results/video/output_%04d.png -preset slow -qp 18 -pix_fmt yuv420p result_video.mp4
ffmpeg -framerate 30 -i image_sr2/v1885/V1885_p2_SSL_%05d-2275000_E.png -c:v libx264 -crf 18 -preset veryslow sr_vids2/v1885.mp4

12월 21일 오후 4시 30분까지 검색한 바로는 영상 렌더링 이전에 preview player를 지원하지 않는다. 따라서 입력한 데이터를 이용해 Player에 직접 그리는 방식을 사용할 것으로 보인다. 이 경우 렌더링 결과와 preview 영상의 유격이 있을 수 있다고 예상할 수 있다.

FFmpegKit
https://github.com/arthenica/ffmpeg-kit
iOS나 macOS에서 쉽게 프레임워크를 사용할 수 있게 해준다. 2023년 9월 18일 v6.0 LTS에서 업데이트가 멈춰있다. 하지만 공식코드를 이용해 iOS에 탑재시키려면 큰 노력이 필요하므로 프로젝트가 완성될때까지는 이 프레임워크를 사용하도록 하자.

24년 12월 23일엔 실행가능할 정도까지 셋팅이 완료되었다.

GPUImage3을 사용한 필터링
https://github.com/BradLarson/GPUImage3
예를들어 화면 전환 효과를 넣을 수 있다. 클립1과 클립2의 사이에 전환 애니메이션을 넣을 때 GPUImage3을 이용해 클립1 후반과 클립2의 전반을 잘라서 전환애니메이션이 들어가 있는 클립3를 만들고 FFmpeg의 concat을 이용해 클립1,클립3,클립2를 이어붙이면 전환애니메이션이 들어간 걸 만들 수 있을 것이다.

FDWaveformView (오디오 편집점 선택을 위한 뷰)
https://github.com/fulldecent/FDWaveformView

영상에 애니메이션 붙이기 기술 확보 필요

NextLevelSessionExporter
https://github.com/NextLevel/NextLevelSessionExporter
NextLevelSessionExporter와 FFmpeg을 함께 사용하는 이유

NextLevelSessionExporter는 Apple 생태계에 최적화된 작업(압축, 기본 변환)에서 유용하지만, FFmpeg과 함께 사용하면 더욱 강력한 워크플로우를 구축할 수 있습니다.

조합 사례
1. NextLevelSessionExporter로 기본 변환 → FFmpeg으로 고급 작업
- NextLevelSessionExporter로 기본적인 동영상 압축(H.264)과 해상도 조정을 수행.
- FFmpeg으로 필터 적용, 자막 삽입, 복잡한 트랜지션 추가, 오디오 트랙 믹싱.
2. FFmpeg으로 포맷 변환 → NextLevelSessionExporter로 모바일 최적화
- FFmpeg을 사용해 MKV, AVI, VP9 등 비표준 파일을 H.264로 변환.
- NextLevelSessionExporter로 iOS/macOS에서 재생 가능한 최적의 파일로 압축.
3. FFmpeg으로 디코딩 → NextLevelSessionExporter로 결과 파일 생성
- FFmpeg으로 비표준 파일을 디코딩하여 프레임 데이터를 추출.
- NextLevelSessionExporter를 사용해 Apple 생태계에서 활용 가능한 포맷으로 저장.
4. 서버와 모바일의 협업
- 서버에서 FFmpeg으로 미리 복잡한 작업(트랜지션, 자막 삽입)을 수행.
- NextLevelSessionExporter로 모바일 디바이스에서 최종적으로 압축 및 렌더링.

온라인에서 FFmpeg을 테스트할 수 있는 곳: https://ffmpeg.lav.io

AVComposition과 AVMutableComposition을 사용해 여러 비디오를 하나의 AVPlayerItem으로 병합할 수 있는 것으로 보인다.
이 기술을이용해 Preview Player을 구현할 수 있지 않을까?

iOS STT

@available(iOS 10.0, *)
open class SFTranscriptionSegment : NSObject, NSCopying, NSSecureCoding {
    open var substring: String { get } // 세그먼트에 해당하는 텍스트 문자열
    open var substringRange: NSRange { get } // 이 범위를 사용하여 substring이 전체 텍스트에서 어디에 위치하는지 확인할 수 있습니다.
    open var timestamp: TimeInterval { get } // 단어가 시작된 시간(초 단위).
    open var duration: TimeInterval { get } // 단어의 지속 시간(초 단위).
    open var confidence: Float { get } // 세그먼트 텍스트의 인식에 대한 신뢰도, 0.0~1.0 범위의 Float 값으로 나타냄
    open var alternativeSubstrings: [String] { get } // 유사하게 들리는 단어
profile
풀스텍이었던 iOS개발자

0개의 댓글