본문으로 건너뛰기
피드

애플 비디오 배경화면을 리버스 엔지니어링한 맥용 오픈소스 앱

open-source 약 9분
vote
0
댓글
북마크

Phosphene은 macOS Tahoe에서 사용자가 가진 동영상을 데스크톱과 잠금화면 배경화면으로 재생하게 해주는 메뉴바 앱이자 배경화면 확장이다. 애플의 비공개 WallpaperExtensionKit을 dlopen과 Mirror 기반 런타임 인트로스펙션으로 붙였고, AVSampleBufferDisplayLayer를 직접 구동해 끊김 없는 루프와 전원 상태별 재생 정책까지 구현했다.

  • 1

    Phosphene은 macOS 기본 배경화면 선택기에 사용자 동영상을 노출시키는 앱

  • 2

    애플의 비공개 WallpaperExtensionKit을 런타임 로딩해 시스템 WallpaperAgent와 통합

  • 3

    AVPlayerLayer 대신 AVSampleBufferDisplayLayer를 직접 구동해 원격 CAContext 안에서 프레임을 렌더링

  • 4

    PTS/DTS를 루프 경계마다 보정해 플러시 없는 갭리스 루프를 구현

  • 5

    배터리, 발열, 잠금화면, 창 가림 상태에 따라 재생 품질을 낮추거나 일시정지

그냥 동영상 배경화면 앱이 아님

  • Phosphene은 macOS Tahoe용 비디오 배경화면 엔진임. 메뉴바 앱과 배경화면 확장으로 구성돼 있고, 사용자가 가진 MP4, MOV, AVFoundation이 읽을 수 있는 파일을 데스크톱과 잠금화면 배경화면으로 쓸 수 있게 해줌

    • 동영상은 macOS 시스템 설정의 Wallpaper 화면에 애플 기본 Aerials 옆에 같이 나타남
    • 사용자가 별도 플레이어를 띄우는 게 아니라, macOS가 실제 배경화면 배정을 처리하고 Phosphene 확장이 프레임을 공급하는 구조임
  • 핵심은 애플의 비공개 WallpaperExtensionKit을 쓴다는 점임. 공개 API로 예쁘게 붙인 게 아니라, 시스템 내부 구조를 꽤 세게 건드림

    • Phosphene은 WallpaperExtensionKit을 dlopen으로 로드함
    • 애플의 XPC 요청 타입은 공개 SDK 헤더에 없어서 Mirror 기반 런타임 인트로스펙션으로 필드를 읽음
    • 원문도 대놓고 경고함. 애플이 macOS 메이저 릴리스에서 내부 필드 이름이나 타입을 바꾸면 외과수술급으로 깨질 수 있음

⚠️주의

> 이 프로젝트는 비공개 프레임워크에 기대고 있어서, macOS 업데이트 한 번에 동작이 깨질 수 있음. 실사용 앱이라기보다 “애플 배경화면 시스템이 내부적으로 이렇게 돌아가는구나”를 보는 재미가 큼.

구조가 꽤 본격적임

  • 앱 쪽은 Phosphene.app이고, 실제 배경화면 렌더링은 PhospheneExtension.appex가 맡음

    • 앱은 SwiftUI 메뉴바 UI, 비디오 라이브러리 관리, 비디오 메타데이터, HEVC 최적화, 환경설정, 라이브러리 변경 알림을 담당함
    • 확장은 시스템 WallpaperAgent 프로세스 안에서 실행되고, XPC 요청을 받아 AVSampleBufferDisplayLayer로 프레임을 렌더링함
    • 둘은 공유 App Group 컨테이너를 통해 비디오 라이브러리, 변형 파일, WallpaperPrefs.plist, BMP 스냅샷 캐시를 공유함
  • 원문에서 제일 맛있는 부분은 AVPlayerLayer를 안 쓴 이유임. 원격 CAContext 안에서는 AVPlayerLayer가 조용히 실패해서, 프로젝트가 AVSampleBufferDisplayLayer를 직접 구동함

    • 현재 루프용 AVAssetReader 하나, 다음 루프를 미리 준비하는 AVAssetReader 하나를 둠
    • 루프 경계마다 PTS/DTS 오프셋을 누적해서 타임라인이 계속 증가하도록 만듦
    • 덕분에 렌더러를 플러시하지 않고도 프레임 정확도 있는 갭리스 루프를 구현함. 배경화면에서 루프마다 툭 끊기면 바로 티 나니까 이 디테일이 꽤 중요함
  • 잠금화면 전환도 애플 Aerials처럼 맞추려고 했음

    • “Only on Lock Screen” 모드에서는 잠금과 해제 시점에 cubic curve로 영상이 부드럽게 들어오고 빠짐
    • 스냅샷 처리도 그냥 안 됐음. 시스템 스냅샷 인코더가 type(of: coder) == NSXPCCoder.self를 체크하는데 실제 coder는 서브클래스라서, 런타임 스위즐 없이는 회색 잠금화면이 나온다고 함

배터리와 발열까지 신경 씀

  • Phosphene은 PlaybackPolicy를 재생 동작의 단일 기준으로 둠

    • 입력값은 발열 상태, 배터리 잔량, 배터리 사용 여부, AC 전원, Game Mode, 프레젠테이션 모드, 사용자 일시정지, 창 가림 상태 등임
    • 결과는 full, reduced, minimal, paused 중 하나로 떨어지고, 렌더러는 상태가 바뀔 때마다 이 정책을 적용함
  • 창이 모든 디스플레이를 완전히 덮고 있으면 렌더링을 멈춤. 데스크톱이 안 보이는데 GPU와 배터리를 태우는 걸 피하려는 설계임

    • 멀티 디스플레이와 Space별 선택도 지원하고, 이 선택은 macOS 쪽에서 유지됨
    • 저해상도나 저프레임레이트 변형을 미리 만들어둘 수 있고, 렌더러는 루프 경계에서 현재 정책에 맞는 가장 싼 변형으로 갈아탐

중요

> “1080p@30” 변형이 있어도 무조건 그걸 쓰는 게 아님. PlaybackPolicy가 현재 전원, 발열, 유휴 상태를 보고 허용되는 가장 높은 티어를 고르는 구조임.

빌드 조건도 최신 맥 개발 환경에 맞춰져 있음

  • 타깃은 macOS Tahoe 26.0 이상, Apple Silicon, arm64-apple-macos26.0임

    • macOS 14에서 들어온 Wallpaper extension point에 의존하지만, Tahoe 전용 SwiftUI와 glassEffect() API도 사용함
    • Xcode 17 이상이 필요하고, Swift 6 strict concurrency가 켜져 있음
  • 설치 흐름은 일반적인 Xcode 프로젝트에 가까움

    • 저장소를 클론하고 Phosphene.xcodeproj를 열어 Phosphene scheme을 실행함
    • 코드 서명을 위해 development team 설정이 필요함
    • 앱을 실행하면 배경화면 확장이 앱 번들에 포함된 상태로 시스템에 등록됨
    • 이후 메뉴바에서 비디오를 추가하고, System Settings → Wallpaper에서 Phosphene 컬렉션을 골라 쓰면 됨

기술 맥락

  • 이 프로젝트가 고른 선택은 “공개 API로 가능한 만큼만 한다”가 아니라, 애플 내부 배경화면 확장 구조에 직접 올라타는 방식이에요. 그래야 사용자가 고른 영상이 macOS 기본 Wallpaper UI 안에 자연스럽게 들어가거든요. 대신 WallpaperExtensionKit이 비공개라서, macOS 업데이트에 깨질 위험을 그대로 떠안는 선택이에요.

  • 렌더링에서 AVPlayerLayer를 버린 이유도 꽤 현실적이에요. 원격 CAContext 안에서는 AVPlayerLayer가 조용히 실패하니까, 더 낮은 레벨의 AVSampleBufferDisplayLayer로 직접 프레임을 밀어 넣은 거예요. 배경화면 확장은 일반 앱 창 렌더링이 아니라 WallpaperAgent 안에서 돌아가니까, 익숙한 고수준 API가 그대로 먹히지 않는 상황이 생겨요.

  • 갭리스 루프 구현은 그냥 보기 좋은 디테일이 아니에요. 배경화면은 계속 반복 재생되기 때문에 루프마다 플러시나 스터터가 있으면 사용자가 바로 알아차려요. 그래서 AVAssetReader를 현재 루프와 다음 루프용으로 나누고, PTS/DTS를 계속 증가시키는 방식으로 타임라인을 끊기지 않게 만든 거예요.

  • PlaybackPolicy를 별도로 둔 것도 배경화면 앱이라서 중요해요. 영상 배경화면은 예쁘지만 배터리, 발열, 게임 모드, 잠금화면 상태에 따라 민폐가 될 수 있거든요. 그래서 여러 상태 입력을 full, reduced, minimal, paused 같은 단순한 정책으로 접어서 렌더러가 일관되게 움직이게 만든 구조예요.

이건 단순한 ‘동영상 배경화면 앱’이 아니라, 애플이 공개하지 않은 배경화면 확장 구조를 꽤 깊게 파고든 macOS 시스템 프로그래밍 사례다. 특히 원격 CAContext에서 AVPlayerLayer가 조용히 실패해서 AVSampleBufferDisplayLayer를 직접 몰았다는 부분은 맥 앱 개발자라면 재밌게 볼 만하다.

댓글

댓글

댓글을 불러오는 중...

open-source

위키피디아에도 빅테크식 반노조 플레이북이 들어왔다

위키미디어 재단이 5월 열흘 사이 MediaWiki 장기 핵심 개발자를 해고하고, 자원봉사 편집자 요청을 처리하던 Community Tech 팀을 해산했다는 비판 글이다. 해고된 인력 상당수가 노조 조직 활동과 연결돼 있었고, 위키피디아 편집자들은 연대 파업까지 거론하고 있다. 재단은 2억9660만 달러의 준비금과 빠르게 성장하는 AI 대상 API 매출을 갖고 있어, 이 사안이 단순 비용 절감으로 보기 어렵다는 게 글의 핵심이다.

open-source

캘리포니아, 연령 확인법에서 리눅스 빼려는 수정안 추진

캘리포니아가 운영체제에 사용자 나이 확인을 요구하는 법안에서 대부분의 오픈소스 운영체제를 제외하는 수정안을 추진 중이다. 데비안, 페도라, 우분투, 아치, 리눅스 민트 같은 배포판은 빠질 가능성이 커졌지만, 스팀OS처럼 독점 앱 생태계와 연결된 플랫폼은 여전히 애매한 상태다.

open-source

마이크로소프트, 45년 전 86-DOS 소스코드를 오픈소스로 공개

마이크로소프트가 86-DOS 1.00 출시 45주년에 맞춰 지금까지 발견된 것 중 가장 오래된 DOS 소스코드를 공개했어. 팀 패터슨의 차고에 있던 도트 매트릭스 출력물을 스캔하고 옮겨 적어, 원본 바이너리와 바이트 단위로 동일하게 다시 컴파일되는 수준까지 복원한 게 포인트야.

open-source

밤부 랩, AGPLv3 위반 논란으로 오픈소스 커뮤니티와 충돌

3D 프린터 제조사 밤부 랩이 AGPLv3 라이선스 위반 논란에 휘말렸고, Software Freedom Conservancy가 두 건의 위반 사례를 확인했다는 내용이야. Louis Rossmann과 Gamers Nexus는 관련 개발자의 법적 방어를 위해 2만달러를 기부했고, 갈등의 핵심은 오픈소스 기반 생태계를 클라우드와 DRM으로 점점 닫아가려는 움직임이야.

open-source

플리퍼, 리눅스 기반 확장형 기기 '플리퍼 원' 공개

플리퍼가 기존 플리퍼 제로를 대체하는 후속작이 아니라, 리눅스 기반 네트워킹·확장형 기기인 플리퍼 원을 공개했어. RK3576 8코어 ARM 칩, 와이파이 6E, 듀얼 이더넷, NVMe, HDMI 4K 120Hz까지 넣으면서 장난감 같은 해킹 도구에서 훨씬 범용적인 리눅스 장비 쪽으로 방향을 넓히는 그림이야.