모든 요소에서 동영상 스트림 캡처

François Beaufort
François Beaufort

Screen Capture API를 사용하여 현재 탭 전체를 캡처할 수 있습니다. Element Capture API를 사용하여 특정 HTML 요소를 캡처하고 기록할 수 있습니다. 전체 탭의 캡처를 특정 DOM 하위 트리의 캡처로 변환하여 타겟 요소의 직접 하위 트리만 캡처합니다. 즉, 가리는 콘텐츠와 가려진 콘텐츠를 모두 자르고 삭제합니다.

요소 캡처를 사용해야 하는 이유

화상 회의 애플리케이션의 요구사항을 고려하면 요소 캡처가 유용한 위치를 파악하는 데 도움이 됩니다. iframe에 타사 애플리케이션을 삽입할 수 있도록 하는 화상 회의 애플리케이션이 있는 경우 해당 iframe을 동영상으로 캡처하여 원격 참여자에게 전송하는 것이 좋습니다.

Chrome 화상 회의 통화 스크린샷
엘라드는 프랑수아와의 화상 회의 통화에 서드 파티 애플리케이션을 사용합니다.

getDisplayMedia()를 호출하고 사용자가 현재 탭을 선택하도록 허용하면 현재 탭 전체가 전송됩니다. 이렇게 하면 사람들이 만든 동영상을 다시 전송할 가능성이 커집니다. Region Capture를 사용하여 이 부분을 자를 수 있습니다.

하지만 발표자가 화상 회의 애플리케이션을 사용할 때 드롭다운 목록과 같은 일부 콘텐츠가 캡처용 콘텐츠 위에 그리면 어떻게 될까요?

캡처용 콘텐츠를 가리는 드롭다운 목록의 스크린샷
드롭다운 목록이 캡처용 콘텐츠 위에 표시됩니다.

이 경우 지역 캡처가 도움이 되지 않습니다. 드롭다운 목록의 일부가 원격 참석자의 화면에 표시될 수도 있습니다.

드롭다운 목록을 캡처한 스크린샷
엘라드의 드롭다운 목록이 프랑수아가 받은 콘텐츠 위에 표시됩니다.

지역 캡처가 이러한 방식으로 요소의 일부를 캡처 (콘텐츠 가리기라고 함)한다는 사실은 여러 문제를 일으킵니다.

  • 콘텐츠를 가리면 사용자가 공유하려는 콘텐츠를 보지 못할 수 있습니다.
  • 콘텐츠를 가리는 것은 비공개일 수 있습니다 (예: 채팅 알림).
  • 콘텐츠가 가려지면 혼란스러울 수 있습니다. (예를 들어 애플리케이션의 레이아웃을 변경하면 원격 참여자의 동영상이 캡처된 대상 위로 잠시 표시될 수 있습니다.)

Element Capture API를 사용하면 공유하려는 요소를 타겟팅할 수 있어 이러한 문제가 모두 해결됩니다.

뷰에 드롭다운 목록이 없는 타겟 요소의 스크린샷
프랑수아에게 Elad의 드롭다운 목록이 표시되지 않습니다.

요소 캡처는 어떻게 사용하나요?

captureTarget는 사용자가 캡처하려는 콘텐츠가 포함된 페이지의 요소입니다. 화상 회의 웹 앱에서 captureTarget을(를) 캡처하여 원격 참석자와 공유하려고 합니다. 따라서 captureTarget에서 RestrictionTarget를 파생합니다. 이 RestrictionTarget를 사용하여 동영상 트랙을 제한한 후 동영상 트랙의 프레임은 이제 captureTarget의 일부인 픽셀과 직접 DOM 하위 요소로만 구성됩니다.

captureTarget의 크기, 모양 또는 위치가 변경되면 웹 앱의 추가 입력 없이도 동영상 트랙이 따라갑니다. 표시되거나 사라지거나 이동하는 콘텐츠를 차단하는 경우에도 특별한 처리가 필요하지 않습니다.

다음 단계를 다시 검토하세요.

먼저 사용자가 현재 탭을 캡처하도록 허용합니다.

// Ask the user for permission to start capturing the current tab.
const stream = await navigator.mediaDevices.getDisplayMedia({
 preferCurrentTab: true,
});
const [track] = stream.getVideoTracks();

원하는 요소를 입력으로 사용하여 RestrictionTarget.fromElement()를 호출하여 RestrictionTarget를 정의합니다.

// Associate captureTarget with a new RestrictionTarget
const captureTarget = document.querySelector("#captureTarget");
const restrictionTarget = await RestrictionTarget.fromElement(captureTarget);

그런 다음 RestrictionTarget를 입력으로 사용하여 동영상 트랙에서 restrictTo()를 호출합니다. 마지막 프라미스가 확인되면 모든 후속 프레임이 제한됩니다.

// Start restricting the self-capture video track using the RestrictionTarget.
await track.restrictTo(restrictionTarget);

// Enjoy! Transmit remotely.

자세히 알아보기

특성 감지

RestrictionTarget.fromElement()가 지원되는지 확인하려면 다음을 사용합니다.

if ("RestrictionTarget" in self && "fromElement" in RestrictionTarget) {
  // Deriving a restriction target is supported.
}

RestrictionTarget 파생

captureTarget라는 요소에 포커스를 둡니다. 여기서 RestrictionTarget를 파생하려면 RestrictionTarget.fromElement(captureTarget)를 호출합니다. 성공하면 반환된 프로미스가 새 RestrictionTarget 객체로 리졸브됩니다. 부당한 수의 RestrictionTarget 객체를 발행한 경우 주문이 거부됩니다.

const captureTarget = document.querySelector("#captureTarget");
const restrictionTarget = await RestrictionTarget.fromElement(captureTarget);

요소와 달리 RestrictionTarget 객체는 직렬화 가능합니다. 예를 들어 Window.postMessage()를 사용하여 다른 문서로 전달할 수 있습니다.

제한

탭을 캡처할 때 동영상 트랙은 restrictTo()를 노출합니다. 현재 탭을 캡처할 때 null 또는 현재 탭 내의 요소에서 파생된 RestrictionTarget를 사용하여 restrictTo()를 호출하는 것이 유효합니다.

restrictTo(restrictionTarget) 호출은 동영상 트랙을 나머지 DOM과 독립적으로 그 자체로 그린 것처럼 동영상 트랙을 captureTarget의 캡처로 변경합니다. captureTarget의 모든 하위 요소도 캡처됩니다. captureTarget의 동위 요소는 캡처에서 제거됩니다. 결과적으로 트랙에 전달된 모든 프레임이 마치 captureTarget의 윤곽에 맞게 잘린 것처럼 표시되고 가려지고 가려진 콘텐츠가 삭제됩니다.

// Start restricting the self-capture video track using the RestrictionTarget.
await track.restrictTo(restrictionTarget);

restrictTo(null)를 호출하면 트랙을 원래 상태로 되돌립니다.

// Stop restricting.
await track.restrictTo(null);

restrictTo() 호출이 성공하면 모든 후속 동영상 프레임이 captureTarget로 제한된다는 것이 보장되면 반환된 프로미스가 리졸브됩니다.

실패하면 프로미스가 거부됩니다. restrictTo() 호출에 실패하면 다음 이유 중 하나가 원인일 수 있습니다.

  • restrictionTarget이 캡처되는 탭이 아닌 다른 탭에서 발급된 경우입니다. '대신 이 탭 공유' 버튼을 사용하면 사용자가 언제든지 캡처되는 탭을 변경할 수 있습니다.
  • restrictionTarget이 더 이상 존재하지 않는 요소에서 파생된 경우.
  • 트랙에 클론이 있는지 여부 문제 1509418을 참고하세요.
  • 현재 트랙이 자체 캡처 동영상 트랙이 아닌 경우
  • restrictionTarget가 파생된 요소를 제한할 수 없습니다.

셀프 캡처 고려사항

앱이 getDisplayMedia()를 호출하고 사용자가 앱의 자체 탭을 캡처하도록 선택하면 이를 '자체 캡처'라고 합니다.

restrictTo() 메서드는 자체 캡처뿐만 아니라 모든 탭 캡처 동영상 트랙에 노출됩니다. 하지만 요소 캡처는 현재 셀프 캡처에만 사용할 수 있습니다. 따라서 트랙을 제한하기 전에 사용자가 현재 탭을 선택했는지 확인하는 것이 좋습니다. 이 작업은 캡처 핸들을 사용하여 실행할 수 있습니다. preferCurrentTab를 사용하여 사용자가 셀프 캡처로 이동하도록 브라우저에 요청할 수도 있습니다.

투명성

앱이 getDisplayMedia()를 통해 통과하는 동영상 프레임에는 알파 채널이 포함되지 않습니다. 앱이 부분적으로 투명한 캡처 타겟을 설정하는 경우 알파 채널을 제거하면 다음과 같은 결과가 발생할 수 있습니다.

  • 색상이 변경될 수 있습니다. 밝은 배경 위에 그려진 부분적으로 투명한 대상 요소는 알파 채널이 삭제될 때 어둡게 표시되고 어두운 배경 위에 그려진 대상 요소는 더 밝게 표시될 수 있습니다.
  • 알파 채널이 최댓값으로 설정되었을 때 사용자가 볼 수 없거나 감지할 수 없는 색상은 알파 채널이 삭제되면 표시됩니다. 예를 들어 투명 섹션에 RGBA 코드 rgba(0, 0, 0, 0)가 있는 경우 캡처된 프레임에 예상치 못한 검은색 영역이 발생할 수 있습니다.
직사각형이 아닌 투명한 캡처 타겟의 결과 스크린샷
직사각형이 아닌 투명한 캡처 대상 동영상 스트림 (오른쪽)은 불투명한 파란색 원이 포함된 검은색 배경의 직사각형입니다.

사용할 수 없는 캡처 대상

언제든지 유효한 캡처 타겟으로 트랙을 제한하는 것이 가능합니다. 그러나 요소 또는 상위 항목이 display:none인 경우와 같이 특정 조건에서는 프레임이 생성되지 않습니다. 일반적인 근거는 제한이 응집력 있는 단일 2차원 직사각형 영역으로 구성된 요소에만 적용되며, 이 영역의 픽셀은 상위 또는 동위 요소로부터 분리되어 논리적으로 결정될 수 있다는 것입니다.

요소가 제한 대상이 되도록 하기 위한 한 가지 중요한 고려사항은 요소가 자체 스택 컨텍스트를 형성해야 한다는 것입니다. 이를 위해 isolation CSS 속성을 isolate로 설정할 수 있습니다.

<div id="captureTarget" style="isolation: isolate;"></iframe>

타겟 요소는 임의의 시점에(예: 앱이 CSS 속성을 변경하는 경우) 제한 대상 여부를 전환할 수 있습니다. 적절한 캡처 타겟을 사용하고 예기치 않게 속성이 변경되지 않도록 하는 것은 앱에 달려 있습니다. 대상 요소를 사용할 수 없게 되면 대상 요소가 다시 제한 대상이 될 때까지 새 프레임이 트랙에서 내보내지지 않습니다.

요소 캡처 사용 설정

Element Capture API는 데스크톱의 Chrome에서 요소 캡처 플래그 뒤에 사용할 수 있으며 chrome://flags/#element-capture에서 사용 설정할 수 있습니다.

또한 이 기능은 데스크톱용 Chrome 121의 오리진 트라이얼에 시작되며, 이를 통해 개발자는 사이트 방문자가 실제 사용자로부터 데이터를 수집할 수 있는 기능을 사용 설정할 수 있습니다. 오리진 트라이얼에 대한 자세한 내용은 오리진 트라이얼 시작하기를 참고하세요.

보안 및 개인 정보 보호

보안의 장단점을 알아보려면 요소 캡처 사양의 개인 정보 보호 및 보안 고려사항 섹션을 참고하세요.

Chrome 브라우저에서 캡처된 탭의 가장자리 주위에 파란색 테두리를 그립니다.

데모

Glitch에서 데모를 실행하여 요소 캡처를 사용해 볼 수 있습니다. 소스 코드를 확인하세요.

의견

Chrome팀과 웹 표준 커뮤니티는 여러분의 요소 캡처 사용 경험에 관한 의견을 듣고자 합니다.

디자인에 대해 알려주세요.

Region Capture에서 예상대로 작동하지 않는 부분이 있나요? 아니면 아이디어를 구현하는 데 필요한 메서드나 속성이 누락되었나요? 보안 모델에 대한 질문이나 의견이 있습니까?

  • GitHub 저장소에서 사양 문제를 신고하거나 기존 문제에 의견을 추가하세요.

구현에 문제가 있습니까?

Chrome 구현에서 버그를 발견하셨나요? 아니면 구현이 사양과 다른가요?

  • https://new.crbug.com에서 버그를 신고합니다. 재현을 위한 간단한 안내와 가능한 한 많은 세부정보를 포함하세요. Glitch는 쉽고 빠른 재현을 공유하는 데 효과적입니다.

감사의 말

사진: Paul Skorupskas, Unsplash