
React 포털의 함정과 브라우저 렌더링 엔진의 비밀을 파헤치며 완성한 끊김 없는 플레이어 이식기
왓챠 웹 개발팀이 표준 영상 전송 방식을 넘어 플레이어 UI와 자막까지 완벽하게 지원하는 Document PiP 기능을 도입하며 마주한 실무적 도전 과제들을 공유합니다. 리액트의 라이프사이클과 브라우저 렌더링 엔진(Blink)의 동작 원리를 결합하여 화면 끊김과 무한 버퍼링 버그를 해결한 과정을 상세히 담고 있습니다. 최종적으로 사파리를 위한 표준 PiP 폴백까지 포함한 실서비스 적용 가이드를 제공합니다.
리액트 기반 웹 비디오 플레이어에 커스텀 자막이나 제어 UI를 포함한 고급 PiP 기능을 도입하려는 프론트엔드 엔지니어에게 적극 추천합니다.
왓챠 웹 서비스에서 브랜드 일관성을 유지하는 커스텀 UI와 자막을 포함한 비디오 재생기 환경을 PiP(Picture-in-Picture) 모드에서도 끊김 없이 제공해야 하는 과제가 있었습니다. 단순 비디오 요소만 분리하는 기존 API로는 한계가 있었고, 리액트 환경 및 DRM 상태에서 발생하는 컴포넌트 언마운트와 화면 프리징 현상을 해결해야 했습니다.
출처가 동일한 별도 창을 생성하는 Document PiP API를 활용하고, 리액트 포털 컨테이너의 위치만 변경하여 상태를 보존했습니다. 또한, 디코딩된 프레임 수와 ReadyState를 주기적으로 검사하여 미디어 락 현상을 감지하고 단계적으로 복구(강제 시크 및 비디오 요소 교체)하는 감시 루프를 도입했습니다.
이를 통해 사파리 등 미지원 브라우저에서는 Standard PiP로 원활히 폴백하면서도, 지원 브라우저에서는 플레이어 상태(건너뛰기, 자막 등)를 고스란히 유지한 완벽한 커스텀 PiP 환경을 성공적으로 구축하였습니다.
Trade-off
스타일시트 복사가 완벽하지 않아 교차 출처 스타일의 경우 직접 주소로 내려받게 처리해야 하며, 도메인 비즈니스 로직(DRM, 에피소드 전환 등)과 비디오 소유권이 강하게 얽혀 있어 완벽한 범용 라이브러리로 추상화하는 데 한계가 있었습니다.
HTML 비디오 요소뿐만 아니라 임의의 DOM 콘텐츠와 커스텀 UI를 통째로 별도 플로팅 윈도우로 분리해 띄울 수 있도록 지원하는 웹 API입니다.
기존 문서에 존재하는 DOM 노드를 새로 생성하지 않고 다른 문서(여기서는 PiP 창)로 소속만 변경하여 그대로 가져오는 HTML5 표준 개념입니다.
크롬 등의 렌더링 엔진인 Blink에서 미디어 요소가 DOM에서 제거될 때 일시정지 로직을 처리하는 C++ 핵심 메서드입니다.




