#Frontend

왓챠 웹 PiP 적용기 — Document PiP는 어떻게 동작하고, 무엇이 어려웠나

왓챠 웹 PiP 적용기 — Document PiP는 어떻게 동작하고, 무엇이 어려웠나
01

Summary

영상 멈춤 없이 UI까지 통째로 떼어낸다! 왓챠가 Document PiP를 정복한 방법

React 포털의 함정과 브라우저 렌더링 엔진의 비밀을 파헤치며 완성한 끊김 없는 플레이어 이식기

왓챠 웹 개발팀이 표준 영상 전송 방식을 넘어 플레이어 UI와 자막까지 완벽하게 지원하는 Document PiP 기능을 도입하며 마주한 실무적 도전 과제들을 공유합니다. 리액트의 라이프사이클과 브라우저 렌더링 엔진(Blink)의 동작 원리를 결합하여 화면 끊김과 무한 버퍼링 버그를 해결한 과정을 상세히 담고 있습니다. 최종적으로 사파리를 위한 표준 PiP 폴백까지 포함한 실서비스 적용 가이드를 제공합니다.

  • 01Standard PiP와 Document PiP의 차이를 비교하고 왓챠가 후자를 선택한 구조적 배경 설명
  • 02브라우저 Blink 엔진 소스 분석을 통해 비디오 요소를 다른 창으로 옮길 때 재생이 멈추지 않는 원리 규명
  • 03리액트 createPortal 사용 시 컨테이너 변경으로 컴포넌트가 리마운트되는 현상을 고정 컨테이너 이동 트릭으로 극복
  • 04화면이 굳었으나 미디어 클럭은 흐르는 디코더 멈춤 현상을 감지하고 복구하는 5단계 감시 루프 구현
  • 05윈도우 엣지 환경에서 버퍼링 상태를 화면 굳음으로 잘못 판단해 발생했던 무한 로딩 루프의 트러블슈팅 사례 제공

RECOMMENDATION

리액트 기반 웹 비디오 플레이어에 커스텀 자막이나 제어 UI를 포함한 고급 PiP 기능을 도입하려는 프론트엔드 엔지니어에게 적극 추천합니다.

The Problem

왓챠 웹 서비스에서 브랜드 일관성을 유지하는 커스텀 UI와 자막을 포함한 비디오 재생기 환경을 PiP(Picture-in-Picture) 모드에서도 끊김 없이 제공해야 하는 과제가 있었습니다. 단순 비디오 요소만 분리하는 기존 API로는 한계가 있었고, 리액트 환경 및 DRM 상태에서 발생하는 컴포넌트 언마운트와 화면 프리징 현상을 해결해야 했습니다.

The Solution

출처가 동일한 별도 창을 생성하는 Document PiP API를 활용하고, 리액트 포털 컨테이너의 위치만 변경하여 상태를 보존했습니다. 또한, 디코딩된 프레임 수와 ReadyState를 주기적으로 검사하여 미디어 락 현상을 감지하고 단계적으로 복구(강제 시크 및 비디오 요소 교체)하는 감시 루프를 도입했습니다.

The Result

이를 통해 사파리 등 미지원 브라우저에서는 Standard PiP로 원활히 폴백하면서도, 지원 브라우저에서는 플레이어 상태(건너뛰기, 자막 등)를 고스란히 유지한 완벽한 커스텀 PiP 환경을 성공적으로 구축하였습니다.

Trade-off

스타일시트 복사가 완벽하지 않아 교차 출처 스타일의 경우 직접 주소로 내려받게 처리해야 하며, 도메인 비즈니스 로직(DRM, 에피소드 전환 등)과 비디오 소유권이 강하게 얽혀 있어 완벽한 범용 라이브러리로 추상화하는 데 한계가 있었습니다.

03

Key Concepts

Concept · 01

Document PiP API

HTML 비디오 요소뿐만 아니라 임의의 DOM 콘텐츠와 커스텀 UI를 통째로 별도 플로팅 윈도우로 분리해 띄울 수 있도록 지원하는 웹 API입니다.

  • 동일 출처(same-origin) 속성을 가진 about:blank 창을 열어 원래 페이지의 스크립트와 스타일을 공유할 수 있도록 설계되었습니다.
  • 왓챠의 플레이어 UI 및 자막 컴포넌트를 브랜딩 가이드에 맞춰 PiP 화면에 그대로 투사하는 데 핵심 역할을 했습니다.
Concept · 02

DOM Adopt

기존 문서에 존재하는 DOM 노드를 새로 생성하지 않고 다른 문서(여기서는 PiP 창)로 소속만 변경하여 그대로 가져오는 HTML5 표준 개념입니다.

  • 비디오 요소를 파괴하고 새로 만들지 않기 때문에 재생 중인 위치(currentTime)와 버퍼 상태를 유실 없이 보존합니다.
  • 이벤트 핸들러나 내부 메모리 상태가 끊김 없이 그대로 이전되는 구조적 기반이 되었습니다.
Concept · 03

Blink HTMLMediaElement::RemovedFrom

크롬 등의 렌더링 엔진인 Blink에서 미디어 요소가 DOM에서 제거될 때 일시정지 로직을 처리하는 C++ 핵심 메서드입니다.

  • 지연 시간이 0인 타이머를 사용하여 DOM 제거 시 즉시 재생을 멈추지 않고 다음 마이크로태스크에서 요소의 소속을 다시 확인하도록 설계되었습니다.
  • 이를 통해 비디오 제거 후 새 창으로 이동하는 동기 작업이 완료될 때까지 영상이 정지되지 않고 계속 재생되도록 보장합니다.