Copyright © 2023 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
이 문서는 현재 탭의 디스플레이 캡처에서 파생된 비디오 트랙을 자르기 위한 API를 소개합니다.
이 절은 이 문서가 공개된 시점에서의 문서 상태를 설명합니다. 현재 W3C 공개 문서 목록과 이 기술 보고서의 최신 개정판은 https://www.w3.org/TR/의 W3C 기술 보고서 색인에서 확인할 수 있습니다.
이 첫 공개 작업 초안은 브라우징 컨텍스트의 부분 캡처라는 사용 사례를 해결하기 위해 Web Real-Time Communications Working Group이 탐색하려는 방향을 나타냅니다. Working Group은 API의 잠재적 채택자들로부터 이 방향이 해당 사용 사례에 얼마나 잘 부합하는지에 대한 피드백에 특히 관심이 있습니다.이 문서는 Web Real-Time Communications Working Group에서 Recommendation 트랙을 사용하여 작업 초안으로 공개했습니다.
작업 초안으로 공개되었다고 해서 W3C와 그 회원들이 보증한다는 의미는 아닙니다.
이 문서는 초안 문서이며 언제든지 다른 문서로 갱신, 대체 또는 폐기될 수 있습니다. 진행 중인 작업 이외의 것으로 이 문서를 인용하는 것은 적절하지 않습니다.
이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성했습니다. W3C는 해당 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지합니다. 해당 페이지에는 특허를 공개하기 위한 지침도 포함되어 있습니다. 본인이 필수 청구항을 포함한다고 믿는 특허에 대해 실제 지식을 가진 개인은 W3C 특허 정책 6절에 따라 해당 정보를 공개해야 합니다.
이 문서는 2021년 11월 2일 W3C 프로세스 문서의 적용을 받습니다.
비규범으로 표시된 절뿐만 아니라, 이 명세의 모든 작성 지침, 도표, 예제 및 참고는 비규범입니다. 이 명세의 그 밖의 모든 내용은 규범입니다.
이 문서의 핵심 단어 MUST 및 MUST NOT은 여기 보이는 것처럼 모두 대문자로 나타나는 경우에, 그리고 오직 그 경우에만 BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석됩니다.
이 문서는 [SCREEN-CAPTURE]의 다음 개념 정의를 사용합니다: display-surface 및 browser display-surface.
이 절은 비규범입니다.
복잡한 애플리케이션은 서로 다른 iframe
안의
여러 문서로 구성되는 경우가 많으며, 모두
동일한 브라우징
컨텍스트 안에 표시됩니다. 이러한 애플리케이션을 생각해 보십시오. 이 문서들 중 하나인
CAPTURING-DOC가 getDisplayMedia()
또는
getViewportMedia를 사용하여 현재 전체 브라우징
컨텍스트를 캡처한다고 가정합니다. 그런 다음 이
문서가 비디오 트랙을 협업 문서 CAPTURED-DOC의 어떤 하위 섹션
CAPTURE-TARGET의 좌표로 자르고자 한다면, 어떻게 하면
CAPTURING-DOC가 이를 성능 좋고 안정적으로 수행할 수 있을까요? 특히
스크롤, 확대/축소 또는 창 크기 변경으로 인한 레이아웃 변화가 추가적인 문제를
제시한다는 점을 떠올리십시오.
같은 탭 안의 서로 다른 iframe에 호스팅되는 두 가지 주요 부분, 즉 화상 회의
애플리케이션과 생산성 도구 모음 애플리케이션으로 이루어진 결합 애플리케이션을
생각해 보십시오. 화상 회의 애플리케이션이
getDisplayMedia()
및/또는 getViewportMedia 같은 기존/예정 API를 사용하여
전체 탭을 캡처한다고 가정합니다. 이제 생산성 도구 모음의 특정 섹션을
제외한 모든 것을 잘라내야 합니다. 결과로 얻은 잘린 비디오를 원격으로
전송하기 전에, 자체 화상 회의 콘텐츠, 발표자 노트, 생산성 도구 모음 안의
기타 비공개 및/또는 관련 없는 콘텐츠를 잘라내야 합니다.
또한 두 협업 애플리케이션은 서로 cross-origin일 가능성이 높다고 생각해 보십시오. 이들은 메시지를 게시할 수 있지만, 모든 통신은 비동기이며, 둘 사이에서 정보가 드물게 전송되는 것이 더 쉽고 성능도 좋습니다. 이는 전체 프레임을 게시하는 해결책뿐만 아니라 레이아웃 변화(예: 스크롤, 확대/축소 및 창 크기 변화)에 반응하기에 너무 느린 해결책도 배제합니다.
대부분의 애플리케이션은 이러한 시나리오에서
getViewportMedia를 사용하는 것을 선호할 가능성이 높다는 점은
언급할 가치가 있습니다. 그러나 이 글을 쓰는 시점에서
getViewportMedia는 아직 명세화되지 않았고 구현되지도 않았습니다. 이는
채택에 어느 정도 시간과 노력이 필요한, 사소하지 않은 요구사항을 갖게 될 것입니다.
따라서 많은 애플리케이션은 당분간 getDisplayMedia()
및
Region Capture의 조합을 사용할 가능성이 높습니다.
영역 캡처 메커니즘은 두 부분으로 구성됩니다:
Element를
자르기 메커니즘의
잠재적 대상으로 태그 지정하는
메커니즘입니다.
Element의 윤곽으로
비디오 트랙을 자르기 시작하도록 사용자 에이전트에 지시하거나, 그러한 자르기를
중지하고 트랙을 잘리지 않은 상태로 되돌리는
메커니즘입니다.
비디오 트랙에 대해 두 가지 자르기 상태, 즉 잘린 상태와
잘리지 않은 상태를
정의합니다. 트랙은 잘리지 않은 상태로 시작하며,
cropTo가 성공적으로 호출되면
잘린
상태가 될 수 있습니다.
이 문서에서 제시하는 자르기 메커니즘
(cropTo)은 직접적인
노드 참조가 아니라 Crop-session 대상에 의존합니다. 이는 두 가지
목적에 기여합니다.
CropTarget은 의도적으로 비어 있는 불투명 식별자입니다. 그 목적은
cropTo에 입력으로
전달되는 것입니다.
WebIDL[Exposed=(Window,Worker), Serializable]
interface CropTarget {
[Exposed=Window, SecureContext] static Promise<CropTarget> fromElement(Element element);
};
fromElement를
보안 컨텍스트 밖에서도 노출해야 하는지에 대해서는 아직 합의가 없습니다.
fromElement()
지원되는 타입의 Element와 함께
fromElement를 호출하면,
그 Element가 CropTarget와 연결됩니다. 이 CropTarget는
cropTo의 입력으로
사용될 수 있습니다. 우리는 CropTarget.fromElement()
호출이 반환한 것 중, 아직
활성 상태인
문서에서 반환된 것을
유효한
CropTarget으로 정의합니다.
주어진 element와 함께 fromElement가
호출되면,
사용자 에이전트는 element를 입력으로 사용하여
CropTarget을 생성합니다.
사용자 에이전트는 Promise p를
MUST 반환해야 합니다.
사용자 에이전트는 새 CropTarget와 연관된 상태의 필요한
내부
전파를 모두 완료한 후에만 p를 MUST 이행해야 하며, 그 시점에서 사용자 에이전트는 새
CropTarget를
cropTo의 유효한
매개변수로 받을 준비가 되어 있어야 MUST 합니다.
이전에 fromElement가 호출된 Element를 복제할 때,
그 복제본은 어떤 CropTarget와도 연결되지 않습니다.
나중에
복제본에서 fromElement가 호출되면, 새 CropTarget가 그 복제본에 할당됩니다.
CropTarget을 생성하는 일을
CropTarget.fromElement()
같은 비동기 메서드를 호출하여 수행해야 하는지, 아니면
Element를 입력으로 받는
CropTarget 생성자를 통해
수행해야 하는지에 대해서는 아직 합의가 없습니다. 이는
이슈 #17에서
더 논의됩니다.
element를 입력으로 사용하여 CropTarget을 생성하려면, 다음 단계를 실행합니다:
cropTarget을 CropTarget 타입의 새 객체로
둡니다.
weakRef를 element에 대한 약한 참조로 둡니다.
cropTarget.[[Element]]를 weakRef로 초기화하여 생성합니다.
cropTarget은 자신이 나타내는 요소에 대한 약한 참조를 유지합니다. 다시 말해, cropTarget은 해당 요소의 가비지 컬렉션을 막지 않습니다.
CropTarget 객체는 직렬화 가능합니다. value,
serialized 및 불리언 forStorage가 주어졌을 때,
직렬화
단계는 다음과 같습니다:
forStorage가 true이면, DOMException 객체를
새로 만들어 throw하며, 그 name 속성은
"DataCloneError"
값을 갖습니다.
serialized.[[CropTargetElement]]를
value.[[Element]]로 설정합니다.
serialized 및 value가 주어졌을 때, 역직렬화 단계는 다음과 같습니다:
value.[[Element]]를
serialized.[[CropTargetElement]]로 설정합니다.
[SCREEN-CAPTURE]에 따라, getDisplayMedia()가
호출되면, 그것은 Promise<MediaStream>를
반환하며, 이 MediaStream은
정확히 하나의 비디오 트랙을 포함하고, 그 타입은 MediaStreamTrack이라는
점을 떠올리십시오.
사용자가 browser display-surface를 캡처하기로 선택한 경우,
사용자 에이전트는 비디오 트랙을 MediaStreamTrack
또는 MediaStreamTrack의
어떤 하위 클래스로 인스턴스화해야 MUST 하며, 이 트랙에
cropTo가 노출되어야
MUST 한다고 명세합니다. 단순성을 위해, 이 문서는 사용자 에이전트가
BrowserCaptureMediaStreamTrack이라는
하위 클래스를 사용한다고 가정합니다.
트랙은 처음에 잘리지 않은 상태여야 MUST 합니다.
WebIDL[Exposed = Window]
interface BrowserCaptureMediaStreamTrack : MediaStreamTrack {
Promise<undefined> cropTo(CropTarget? cropTarget);
BrowserCaptureMediaStreamTrack clone();
};
cropTo()
이 메서드 호출은 비디오 트랙을 cropTarget.[[Element]]의
경계 클라이언트 직사각형으로 자르기 시작/중지하도록 사용자 에이전트에 지시합니다.
트랙은 display-surface의
보이는 viewport로 제한되므로, 캡처되는 영역은 보이는 viewport와 요소의
경계 클라이언트 직사각형의 교차 영역이 됩니다.
cropTo가 호출될 때마다,
사용자 에이전트는 다음 알고리즘을 실행해야 MUST 합니다:
cropTarget이 유효한 CropTarget도 아니고
null도 아니면, 사용자 에이전트는 UnknownError로
거부된 Promise를
반환해야 MUST 합니다.
Promise로 둡니다.다음 단계를 병렬로 실행합니다:
undefined도
아니고 유효한 CropTarget도
아니면, p를 NotAllowedError로
거부하고 이 단계를 중단합니다.
cropTarget이 undefined이거나
유효한
CropTarget이면,
사용자 에이전트는 this 비디오 트랙의 자르기 상태를
cropTarget에 따라 갱신해야 MUST 합니다:
undefined로
설정되면, 사용자 에이전트는 자르기를 중지해야
MUST 합니다. This 비디오
트랙은
잘리지 않은 상태로
되돌아갑니다.
CropTarget이 참조하는
요소의 윤곽으로 자르기 시작해야 합니다. 이는
트랙에서 생성되는 각각의 새 프레임마다, 사용자 에이전트가
요소에 속하는 픽셀들의 경계 상자를 계산하고, 프레임을
이 경계 상자의 좌표로 자른다는 뜻입니다.
이 메서드 호출 전의 트랙 상태를 PRE-STATE, 이 메서드 호출 후의 상태를 POST-STATE라고 합니다. 사용자 에이전트는 MUST PRE-STATE에 따라 잘린(또는 잘리지 않은) 프레임이 더 이상 애플리케이션에 전달되지 않으며, 애플리케이션에 전달되는 추가 프레임은 따라서 POST-STATE 또는 이후 상태에 따라 잘린(또는 잘리지 않은) 프레임임이 보장될 때 p를 이행해야 합니다.
cropTo promise의 이행 시점과 실제 비디오 프레임 자르기 시점은 MediaStreamTrack transforms를 통해 JavaScript에서 관찰할 수 있습니다. 새로 잘린 첫 번째 비디오 프레임은 cropTo promise가 이행된 직후 MediaStreamTrack ReadableStream에 enqueue될 것으로 예상됩니다.
clone()
BrowserCaptureMediaStreamTrack가
복제되면, 사용자 에이전트는 원본 트랙의
자르기 상태와 관계없이 처음에
잘리지 않은 상태인
트랙을 생성해야 MUST 합니다.
CropTarget이 생성된(fromElement 호출을 통해) Element를
잠재적
자르기 대상으로 정의합니다.
cropTo의 성공적인
호출이 대상으로 삼는 잠재적 자르기 대상을
crop-session 대상으로 정의합니다.
잘린 상태의 비디오 트랙에서 생성된 프레임을 생각해 보십시오. 사용자 에이전트는 (i) 최상위 브라우징 컨텍스트의 viewport와 (ii) crop-session 대상에 속하는 모든 픽셀의 경계 상자의 교차 영역을 계산합니다. 이 교차 영역은 해당 프레임에 대한 crop-session 대상의 좌표로 정의됩니다.
주어진 crop-session 대상 TARGET으로 잘린 비디오 트랙 VT를 생각해 보십시오. TARGET이 겪는 변화에 직면했을 때 VT의 crop-session의 동작을 정의합니다.
crop-session 대상이 DOM에 연결되어 있지만 최상위 브라우징 컨텍스트의 viewport 안에 그려지는 픽셀이 0개인 경우를 빈 crop-session 대상으로 정의합니다.
이러한 일이 발생할 수 있는 몇 가지 예는 다음과 같습니다:
사용자 에이전트는 빈 crop-session 대상을 가진 트랙에서 새 프레임을 생성해서는 MUST NOT 안 됩니다. 그러한 트랙에 대해, 사용자 에이전트는 트랙이 잘리지 않은 상태가 되거나, 그 crop-session 대상이 빈 상태가 아니게 되면 프레임 생성을 재개해야 MUST 합니다.
DOM에서 분리된 crop-session 대상을 연결이 끊긴 crop-session 대상으로 정의합니다.
빈 crop-session 대상과 연결이 끊긴 crop-session 대상의 차이는, 연결이 끊긴 것은 도달 불가능해질 수 있으며, 이 경우 새 프레임을 생성하지 않는다는 점입니다. 그럼에도 사용자 에이전트는 연결이 끊긴 crop-session 대상을 빈 crop-session 대상과 같은 방식으로 처리해야 MUST 합니다.
애플리케이션은 undefined 또는 새
CropTarget와 함께 트랙에서
cropTo를 호출하여,
트랙에서 프레임 생성이 재개될 수 있게 할 수 있습니다.
capture-target의 코드:
const mainContentArea = navigator.getElementById('mainContentArea');
const cropTarget = await CropTarget.fromElement(mainContentArea);
sendCropTarget(cropTarget);
function sendCropTarget(cropTarget) {
// crop-target을 이 탭 안의 다른 문서로 보낼 수 있습니다
// postMessage()를 사용하거나 다른 수단을 사용할 수 있습니다.
// 다른 문서가 없고, 로컬에서만 소비될 수도 있습니다.
}
capturing-document의 코드:
async function startCroppedCapture(cropTarget) {
const stream = await navigator.mediaDevices.getDisplayMedia();
const [track] = stream.getVideoTracks();
if (!!track.cropTo) {
handleError(stream);
return;
}
await track.cropTo(cropTarget);
transmitVideoRemotely(track);
}
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: