← 기술 백서 목록으로 돌아가기

WinUI 3 스플래시 화면의 하드웨어 가속 비디오 엔진과 블랙 프레임(Black Frame) 0초 차단: ZeliDesk SplashWindow의 페이크 로딩 트릭(Fake Loading Trick) 및 무작위 비디오 디스패치 아키텍처

"스플래시 화면(Splash Screen)은 소프트웨어가 사용자와 만나는 최초의 3초이며, 브랜드의 기술적 완성도와 신뢰성을 각인시키는 가장 결정적인 순간입니다. 그러나 WinUI 3(Windows App SDK) 환경에서 동영상 스플래시를 구현할 때, C++ Media Foundation 디코더 파이프라인이 비동기로 초기화되는 50~150ms의 공백 동안 화면이 흉하게 깜빡이는 '블랙 프레임(Black Frame)' 현상과 비디오 창 크로징 시 발생하는 '0xc000027b Access Violation' 크래시는 개발자들을 괴롭히는 거대한 기술적 난제였습니다. ZeliDesk는 정적 이미지 사전 캐시를 비디오 개방 시점까지 일시 표출하는 '페이크 로딩 트릭(Fake Loading Trick)', 6대 영상 포맷 무작위 디스패치, 실시간 종횡비 수학 리사이징, 그리고 COM 파이프라인 4단계 안전 해제 메커니즘으로 단 1픽셀의 깜빡임도 없는 완벽한 하드웨어 가속 비디오 스플래시 엔진을 완성했습니다."

1. 비디오 스플래시의 딜레마: 왜 블랙 프레임(Black Frame)이 발생하는가?

현대 고성능 데스크톱 애플리케이션은 정적인 2D 로고 이미지를 넘어, 화려한 3D 모션 그래픽이나 브랜드 비디오를 스플래시로 재생하여 압도적인 몰입감을 제공하고자 합니다. 그러나 마이크로소프트의 최신 UI 프레임워크인 WinUI 3에서 MediaPlayerElement 컨트롤을 스플래시 윈도우에 얹어 재생을 시도하면 다음과 같은 치명적인 UX 결함이 드러납니다:

비교 항목 일반적인 WinUI 3 동영상 스플래시 구현 ZeliDesk SplashWindow 아키텍처
첫 프레임 표출 비디오 코덱 준비 전까지 100ms간 흉한 블랙 스크린 깜빡임 페이크 로딩 트릭: 정적 이미지 0ms 표출 후 MediaOpened 시 즉각 바톤 터치
영상 비율 대응 고정 크기(800x600)로 인해 상하좌우 검은 레터박스 발생 PlaybackSession 해상도 즉시 감지 후 동적 종횡비 자동 리사이징
종료 시 자원 해제 MediaPlayer.Dispose() 호출 시 WinUI 3 0xc000027b 커널 크래시 볼륨0 ➔ 참조 분리 ➔ Source null ➔ GC 위임 4단계 무결성 클린업
사용자 편의성 영상이 끝날 때까지 멍하니 대기 강요 (클릭 반응 없음) PointerPressed 스킵 가드: 화면 클릭 즉시 200ms 고속 페이드아웃 전환

2. 페이크 로딩 트릭(Fake Loading Trick): 0ms 정적 캐시와 비디오 바톤 터치

ZeliDesk의 SplashWindow.xaml.cs는 블랙 프레임을 원천 차단하기 위해 '정적 이미지 캐시를 전면에 띄운 상태에서 백그라운드로 비디오를 병렬 로드'하는 페이크 로딩 트릭(Fake Loading Trick)을 고안했습니다:

Splash/SplashWindow.xaml.cs (페이크 로딩 트릭 초기화 로직 발췌) C#
public SplashWindow()
{
    this.InitializeComponent();

    // 1. 윈도우 타이틀바 완전 붕괴(Collapsed)로 완전 무테(Borderless) 윈도우 구성
    ExtendsContentIntoTitleBar = true;
    if (AppWindow?.TitleBar != null)
    {
        AppWindow.TitleBar.ExtendsContentIntoTitleBar = true;
        AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Collapsed;
    }

    _selectedVideoPath = PickRandomVideo();

    if (_selectedVideoPath != null)
    {
        _isVideoMode = true;

        // ★ 페이크 로딩 트릭: 영상 파이프라인이 열리기 전까지 정적 이미지를 전면에 즉각 노출
        SplashImage.Visibility = Visibility.Visible;
        if (_cachedImage != null)
            SplashImage.Source = _cachedImage;
        else
            LoadSplashImage();

        SplashMedia.Visibility = Visibility.Visible;

        // ★ 비디오 로딩을 생성자에서 즉시 병렬 시작
        LoadVideo(_selectedVideoPath);
    }
    else
    {
        SetupImageFallback();
    }
}

그리고 하드웨어 가속 비디오 디코더가 첫 프레임을 성공적으로 디코딩하여 MediaOpened 이벤트가 발생하는 정확한 시점에 비로소 페이크 이미지를 숨깁니다:

Splash/SplashWindow.xaml.cs (MediaOpened 이벤트 핸들러) C#
private void OnMediaOpened(MediaPlayer sender, object args)
{
    sender.MediaOpened -= OnMediaOpened;
    DispatcherQueue.TryEnqueue(() =>
    {
        try
        {
            var session = sender.PlaybackSession;
            uint vw = session.NaturalVideoWidth;
            uint vh = session.NaturalVideoHeight;

            if (vw > 0 && vh > 0)
            {
                // 동영상 해상도에 맞춰 윈도우 크기와 위치를 픽셀 단위로 재계산
                ResizeWindowToVideo(vw, vh);
            }

            // ★ 비디오 디코딩 준비 완료: 페이크 이미지를 숨겨 완벽한 무이음(Seamless) 전환 달성
            SplashImage.Visibility = Visibility.Collapsed;
        }
        finally
        {
            _mediaOpenedTcs?.TrySetResult(true);
        }
    });
}

사용자의 눈에는 창이 뜨는 0.00초 순간 고화질 브랜드 이미지가 즉시 보이고, 0.08초 뒤 첫 프레임이 준비되는 순간 자연스럽게 영상이 이어지므로 단 1프레임의 깜빡임이나 블랙 스크린도 감지할 수 없습니다.

3. 동적 종횡비(Aspect Ratio) 수학과 모니터 80% 안전 리사이즈

영상 파일의 해상도는 1920x1080(16:9), 1080x1920(세로 숏폼 9:16), 1080x1080(1:1 정방형) 등 매우 다양합니다. ResizeWindowToVideo 메서드는 비디오의 NaturalVideoWidth와 NaturalVideoHeight를 기반으로 사용자 주 모니터의 유효 작업 영역(WorkArea)을 80% 이상 침범하지 않는 최적의 종횡비 수학을 실행합니다:

Splash/SplashWindow.xaml.cs (종횡비 자동 정렬 알고리즘) C#
private void ResizeWindowToVideo(uint videoWidth, uint videoHeight)
{
    if (AppWindow == null) return;

    var displayArea = DisplayArea.GetFromWindowId(AppWindow.Id, DisplayAreaFallback.Primary);
    if (displayArea == null) return;

    // 모니터 작업 영역의 80%를 최대 한계선으로 설정
    int maxW = (int)(displayArea.WorkArea.Width * 0.8);
    int maxH = (int)(displayArea.WorkArea.Height * 0.8);

    double aspectRatio = (double)videoWidth / videoHeight;
    int newW, newH;

    if (aspectRatio >= 1.0) // 가로 영상 또는 정사각형
    {
        newW = Math.Min((int)videoWidth, maxW);
        newH = (int)(newW / aspectRatio);
        if (newH > maxH)
        {
            newH = maxH;
            newW = (int)(newH * aspectRatio);
        }
    }
    else // 세로 숏폼 영상
    {
        newH = Math.Min((int)videoHeight, maxH);
        newW = (int)(newH * aspectRatio);
        if (newW > maxW)
        {
            newW = maxW;
            newH = (int)(newW / aspectRatio);
        }
    }

    // 최소 크기(320x240) 보장
    newW = Math.Max(newW, 320);
    newH = Math.Max(newH, 240);

    // 윈도우 크기 동적 재조정 및 모니터 정중앙(Center) 자동 이동
    AppWindow.Resize(new SizeInt32(newW, newH));
    int cx = (displayArea.WorkArea.Width - newW) / 2;
    int cy = (displayArea.WorkArea.Height - newH) / 2;
    AppWindow.Move(new PointInt32(cx, cy));
}

이 정밀한 수학적 바운딩 박스 덕분에 어떤 형태의 비디오를 넣더라도 모니터 화면을 벗어나거나 레터박스가 생기지 않고 화면 중앙에 조각상처럼 완벽히 배치됩니다.

4. 4단계 다중 디렉터리 스캐너와 6대 포맷 무작위 디스패치

학교 컴퓨터실 교사나 기업 전산실 관리자는 행사, 학기 시작, 기관 홍보 시즌에 맞춰 스플래시 동영상을 자유롭게 교체하고 싶어 합니다. ZeliDesk는 4단계 계층형 디렉터리 프로빙과 6대 확장자(.mp4, .avi, .wmv, .webm, .mkv, .mov) 스캔을 지원합니다:

graph TD
    Start[PickRandomVideo 호출] --> C1{1. %LOCALAPPDATA%/ZeliDesk/SplashVideos 존재?}
    C1 -->|Yes, 파일 있음| Pick[Random.Shared 무작위 1개 선정]
    C1 -->|No| C2{2. MSIX 패키지 Assets/SplashVideos 존재?}
    C2 -->|Yes, 파일 있음| Pick
    C2 -->|No| C3{3. AppContext.BaseDirectory/Assets/SplashVideos 존재?}
    C3 -->|Yes, 파일 있음| Pick
    C3 -->|No| C4{4. 개발 소스 루트 탐색}
    C4 -->|Yes, 파일 있음| Pick
    C4 -->|No| Fallback[정적 이미지 SplashZ.png 폴백]
    Pick --> VideoMode[하드웨어 가속 비디오 재생]
                

사용자 폴더(%LOCALAPPDATA%)를 최우선 순위로 탐색하므로, 관리자 권한 없이도 교사나 전산관이 원하는 홍보 영상을 폴더에 넣어두기만 하면 앱이 실행될 때마다 무작위로 다채로운 영상이 재생됩니다.

5. 포인터 클릭 스킵 및 WinUI 3 Storyboard 페이드아웃

화려한 영상도 매번 강제로 끝까지 봐야 한다면 사용자에게 큰 스트레스가 됩니다. ZeliDesk는 사용자 주도권(User Agency)을 최우선으로 존중합니다:

6. WinUI 3 0xc000027b 크래시를 방지하는 미디어 4단계 안전 클린업

스플래시 영상 재생이 끝나고 창을 닫을 때 수많은 개발자들이 마주치는 최악의 버그가 있습니다. 바로 C# 코딩 습관대로 _mediaPlayer.Dispose()를 호출했을 때 터지는 0xc000027b (Stowed Exception / Access Violation) 커널 크래시입니다.

WinUI 3의 XAML VisualTree는 내부적으로 DirectX 비디오 스왑체인과 강하게 엮여 있어, 네이티브 렌더러가 비디오 표면을 그리는 도중에 C# 쪽에서 강제로 Dispose를 날리면 파괴된 메모리를 참조하며 즉사합니다. ZeliDesk는 이 문제를 해결하기 위해 '4단계 무결성 클린업'을 설계했습니다:

Splash/SplashWindow.xaml.cs (4단계 미디어 파이프라인 안전 해제) C#
private void CleanupMediaPlayer()
{
    if (_mediaPlayer != null)
    {
        // 이벤트 리스너 해제 (메모리 누수 차단)
        _mediaPlayer.MediaEnded -= OnMediaEnded;
        _mediaPlayer.MediaFailed -= OnMediaFailed;
        _mediaPlayer.MediaOpened -= OnMediaOpened;

        // 1단계: 재생 중지 및 볼륨 0 음소거 (오디오 글리치 및 파이프라인 정지)
        try { _mediaPlayer.Pause(); } catch { }
        try { _mediaPlayer.Volume = 0; } catch { }

        // 2단계: MediaPlayerElement에서 분리 (XAML 트리의 COM 참조 안전 해제)
        try { SplashMedia.SetMediaPlayer(null); } catch { }

        // 3단계: 미디어 소스 분리 (하드웨어 디코더 파이프라인 닫기)
        try { _mediaPlayer.Source = null; } catch { }

        // 4단계: WinUI 3 버그 우회 — 명시적 Dispose()를 호출하지 않고 GC에 메모리 회수 위임
        // (직접 Dispose 시 XAML 내부 렌더러 충돌로 0xc000027b 크래시 발생 방지)
        _mediaPlayer = null;
    }
}

이 4단계 절차를 거친 후 300ms의 완충 시간을 두고 메인 윈도우에 Completed 이벤트를 발송한 뒤 스플래시 창을 닫음으로써, 단 한 번의 크래시나 메모리 릭 없이 완벽하게 메인 화면으로 바톤을 넘깁니다.

7. 결론: 가장 화려한 첫인상을 지탱하는 가장 치밀한 공학

스플래시 화면은 겉보기에는 단순한 3초짜리 영상 재생기처럼 보입니다. 하지만 그 이면에는 DirectX 하드웨어 가속, 블랙 프레임 방어용 페이크 로딩, 종횡비 기하학, 다중 경로 스캐닝, 그리고 WinUI 3 XAML-COM 메모리 모델과의 치열한 사투가 녹아 있습니다.

ZeliDesk의 SplashWindow.xaml.cs는 단 570줄의 정밀한 C# 코드로 이 모든 기술적 난제를 완벽히 제압했습니다. 앱을 켜는 순간 느껴지는 0초의 무결점 반응성과 유려한 영상미는, 타협 없는 장인정신으로 빚어낸 ZeliDesk 데스크톱 엔지니어링의 위대한 첫인상입니다.

← 이전 기술 백서 #891 72종 시스템 유틸리티와 AI 서비스를 아우르는 단일 진실 공급원(SSOT): LauncherItemRegistry의 선언적 메타데이터 카탈로그 및 4대 런처 타입(Web·NativeApp·SystemCmd·InternalApp) 디스패치 아키텍처 다음 기술 백서 → #889 40대 PC의 교실 맞춤형 데스크톱 UX: ZeliDesk의 동적 아코디언 드로어 및 퀵런치 바 핀(Pin) 상태 원자적 영속화 아키텍처
⚡ ZeliDesk 0ms 무결점 데스크톱 슈트 체험하기

블랙 프레임 없는 하드웨어 가속 스플래시와 72종 온디바이스 유틸리티를 지금 만나보세요.

ZeliDesk Suite 무료 다운로드