Ghi lại luồng video từ bất kỳ phần tử nào

François Beaufort
François Beaufort
Sao Elad Alon
Elad Alon

Với Screen Capture API (API Chụp ảnh màn hình), bạn có thể chụp toàn bộ thẻ hiện tại. Element Capture API (API Thu thập phần tử) cho phép bạn chụp và ghi lại một phần tử HTML cụ thể. Thao tác này chuyển đổi ảnh chụp toàn bộ thẻ thành ảnh chụp một cây con DOM cụ thể, chỉ thu thập các thành phần con trực tiếp của phần tử mục tiêu. Nói cách khác, tính năng này sẽ cắt và loại bỏ cả nội dung bị che khuất và bị che khuất.

Tại sao bạn nên dùng tính năng Chụp phần tử?

Việc xem xét các yêu cầu của một ứng dụng hội nghị truyền hình có thể giúp bạn hiểu được tính năng Element Capture hữu ích ở đâu. Nếu có ứng dụng hội nghị truyền hình cho phép bạn nhúng các ứng dụng của bên thứ ba vào iframe, thì đôi khi, bạn có thể muốn chụp iframe đó dưới dạng video và truyền tệp đó đến những người tham gia từ xa.

Ảnh chụp màn hình một cuộc gọi hội nghị truyền hình trên Chrome.
Elad sử dụng ứng dụng bên thứ ba trong một cuộc gọi hội nghị truyền hình với François.

Việc gọi getDisplayMedia() và cho phép người dùng chọn thẻ hiện tại sẽ truyền toàn bộ thẻ hiện tại. Điều đó có khả năng truyền video của chính mọi người cho họ. Bạn có thể cắt ảnh này bằng tính năng Chụp theo vùng.

Tuy nhiên, điều gì sẽ xảy ra nếu người trình bày tương tác với ứng dụng hội nghị truyền hình và một số nội dung, chẳng hạn như danh sách thả xuống, xuất hiện phía trên nội dung mà bạn muốn chụp?

Ảnh chụp màn hình một danh sách thả xuống che đi nội dung mà bạn muốn chụp.
Một danh sách thả xuống sẽ xuất hiện ở phía trên nội dung bạn muốn chụp.

Tính năng Chụp khu vực sẽ không giúp được bạn ở đó. Một phần của danh sách thả xuống có thể xuất hiện trên màn hình của người tham gia từ xa.

Ảnh chụp màn hình danh sách thả xuống đã được chụp.
Danh sách thả xuống của Elad xuất hiện ở đầu nội dung mà François nhận được.

Trên thực tế, tính năng Chụp khu vực chụp các phần của các thành phần theo cách này (được gọi là ẩn nội dung) sẽ tạo ra nhiều vấn đề:

  • Việc che khuất nội dung có thể cản trở việc xem nội dung mà người dùng định chia sẻ.
  • Nội dung che khuất có thể ở chế độ riêng tư (ví dụ: thông báo trò chuyện).
  • Việc che khuất nội dung có thể gây nhầm lẫn. (Ví dụ: việc sắp xếp lại bố cục của ứng dụng có thể đưa video của chính người tham gia từ xa vượt qua mục tiêu được chụp trong thời gian ngắn.)

Element Capture API giải quyết tất cả các vấn đề này bằng cách cho phép bạn nhắm mục tiêu phần tử bạn muốn chia sẻ.

Ảnh chụp màn hình của phần tử mục tiêu không có danh sách thả xuống trong chế độ xem.
François không thấy danh sách thả xuống từ Elad.

Làm cách nào để sử dụng Element Capture?

captureTarget là một Phần tử trên trang chứa nội dung mà người dùng muốn chụp. Bạn muốn ứng dụng hội nghị truyền hình trên web ghi lại captureTarget và chia sẻ với những người tham gia từ xa. Vì vậy, bạn sẽ nhận được RestrictionTarget từ captureTarget. Sau khi hạn chế bản nhạc video bằng RestrictionTarget này, các khung hình trên bản video đó hiện chỉ bao gồm các pixel thuộc captureTarget và các thành phần con con của DOM trực tiếp.

Nếu captureTarget thay đổi kích thước, hình dạng hoặc vị trí, thì bản video đó sẽ tiếp tục hoạt động mà không yêu cầu dữ liệu đầu vào bổ sung nào từ ứng dụng web. Việc che khuất nội dung xuất hiện, biến mất hoặc di chuyển xung quanh, tương tự như vậy, không cần phải xử lý đặc biệt.

Xem lại các bước này:

Bắt đầu bằng cách cho phép người dùng chụp thẻ hiện tại.

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

Xác định RestrictionTarget bằng cách gọi RestrictionTarget.fromElement() có phần tử bạn chọn làm dữ liệu đầu vào.

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

Sau đó, hãy gọi restrictTo() trên kênh video với đầu vào là RestrictionTarget. Sau khi lời hứa cuối cùng được giải quyết, tất cả các khung tiếp theo sẽ bị hạn chế.

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

// Enjoy! Transmit remotely.

Tìm hiểu chuyên sâu

Phát hiện tính năng

Để kiểm tra xem RestrictionTarget.fromElement() có được hỗ trợ hay không, hãy dùng:

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

Truy xuất một mục tiêu hạn chế

Tập trung vào Phần tử có tên là captureTarget. Để lấy giá trị RestrictionTarget từ đó, hãy gọi RestrictionTarget.fromElement(captureTarget). Lời hứa được trả về sẽ được giải quyết bằng đối tượng RestrictionTarget mới nếu thành công. Nếu không, yêu cầu này sẽ bị từ chối nếu bạn đã đúc một số lượng đối tượng RestrictionTarget không hợp lý.

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

Không giống như Phần tử, đối tượng RestrictionTarget có tính năng chuyển đổi tuần tự. Ví dụ: bạn có thể truyền tệp đến tài liệu khác bằng cách sử dụng Window.postMessage().

Hạn chế

Khi quay một thẻ, bản nhạc video sẽ hiển thị restrictTo(). Khi chụp thẻ hiện tại, bạn có thể gọi restrictTo() bằng null hoặc bất kỳ RestrictionTarget nào bắt nguồn từ một Phần tử trong thẻ hiện tại.

Các lệnh gọi đến restrictTo(restrictionTarget) sẽ làm biến đổi bản nhạc video thành phần chụp captureTarget, như thể nó là tự vẽ, độc lập với phần còn lại của DOM. Mọi thành phần con cháu của captureTarget cũng được thu thập; các thành phần con cháu của captureTarget bị loại bỏ khỏi quá trình chụp. Kết quả là mọi khung hình được phân phối trên kênh sẽ trông như thể chúng đã được cắt theo đường viền của captureTarget, đồng thời mọi nội dung bị che khuất và bị che khuất sẽ bị xoá.

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

Các lệnh gọi đến restrictTo(null) sẽ chuyển kênh về trạng thái ban đầu.

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

Nếu lệnh gọi đến restrictTo() thành công, Lời hứa được trả về sẽ được phân giải khi có thể đảm bảo rằng tất cả khung hình video tiếp theo sẽ bị giới hạn ở captureTarget.

Nếu không thành công thì Lời hứa sẽ bị từ chối. Lệnh gọi đến restrictTo() không thành công sẽ vì một trong những lý do sau:

  • Nếu restrictionTarget được đúc trong một thẻ khác với thẻ đang được chụp. (Xin lưu ý rằng bằng cách sử dụng nút "chia sẻ thẻ này", người dùng có thể thay đổi thẻ được chụp bất cứ lúc nào.)
  • Nếu restrictionTarget bắt nguồn từ một Phần tử không còn tồn tại.
  • Nếu bản nhạc có bản sao. (Xem vấn đề 1509418.)
  • Nếu đoạn đường hiện tại không phải là đoạn video tự chụp.
  • Nếu Phần tử tạo ra restrictionTarget không đủ điều kiện bị hạn chế.

Những điểm cần cân nhắc khi tự chụp ảnh

Khi một ứng dụng gọi getDisplayMedia() và người dùng chọn chụp thẻ của riêng ứng dụng đó, chúng ta gọi đó là "tự chụp".

Phương thức restrictTo() được hiển thị trên mọi đoạn video chụp bằng thẻ, chứ không chỉ để tự chụp. Tuy nhiên, tính năng Element Capture hiện chỉ được bật để tự chụp. Do đó, bạn nên kiểm tra xem người dùng có chọn thẻ hiện tại hay không trước khi cố gắng hạn chế kênh đó. Bạn có thể thực hiện việc này bằng cách sử dụng Capture Xử lý. Bạn cũng có thể yêu cầu trình duyệt nhắc người dùng tự chụp bằng cách sử dụng preferCurrentTab.

Sự minh bạch

Các khung hình video mà ứng dụng nhận được thông qua getDisplayMedia() không bao gồm kênh alpha. Nếu ứng dụng đặt mục tiêu chụp trong suốt một phần, thì việc loại bỏ kênh alpha có một số hậu quả có thể xảy ra:

  • Màu sắc có thể thay đổi. Các thành phần mục tiêu có độ trong suốt một phần được vẽ trên nền sáng có thể hiển thị tối hơn khi kênh alpha bị xoá và các thành phần được vẽ trên nền tối có thể có vẻ sáng hơn.
  • Các màu không hiển thị hoặc không nhận biết được với người dùng khi kênh alpha được đặt ở mức tối đa sẽ xuất hiện sau khi kênh alpha bị xoá. Ví dụ: điều này có thể dẫn đến các vùng màu đen không mong muốn trong khung hình đã chụp, nếu các phần trong suốt có mã RGBA rgba(0, 0, 0, 0).
Ảnh chụp màn hình kết quả của mục tiêu chụp trong suốt không hình chữ nhật.
Luồng video đích trong suốt không hình chữ nhật chụp (bên phải) là một hình chữ nhật nền đen chứa một vòng tròn màu xanh dương mờ.

Mục tiêu chụp không đủ điều kiện

Bạn luôn có thể bắt đầu giới hạn bản nhạc đối với mọi mục tiêu chụp hợp lệ. Tuy nhiên, khung sẽ không được tạo trong một số điều kiện nhất định, chẳng hạn như nếu phần tử hoặc đối tượng cấp trên là display:none. Lý do chung là quy định hạn chế chỉ áp dụng cho một phần tử bao gồm một vùng hình chữ nhật đơn, cố định, hai chiều mà có pixel có thể được xác định theo logic khi tách biệt với bất kỳ phần tử mẹ hoặc phần tử phụ nào.

Một điều quan trọng cần cân nhắc để đảm bảo phần tử đủ điều kiện bị hạn chế là phần tử đó phải tạo ngữ cảnh xếp chồng riêng. Để đảm bảo điều này, bạn có thể chỉ định thuộc tính CSS cách ly, đặt thuộc tính này thành isolate.

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

Xin lưu ý rằng phần tử mục tiêu có thể chuyển đổi giữa trạng thái đủ điều kiện và không đủ điều kiện bị hạn chế tại bất kỳ thời điểm nào, chẳng hạn như khi ứng dụng thay đổi thuộc tính CSS. Ứng dụng có quyền quyết định việc sử dụng các mục tiêu nắm bắt hợp lý và tránh thay đổi đột ngột thuộc tính của các mục tiêu đó. Nếu phần tử mục tiêu không đủ điều kiện, thì các khung hình mới sẽ không được phát trên kênh cho đến khi phần tử mục tiêu lại đủ điều kiện để bị hạn chế.

Bật tính năng chụp phần tử

API Element Capture có sẵn trong Chrome trên máy tính phía sau cờ Element Capture và có thể được bật tại chrome://flags/#element-capture.

Tính năng này cũng bước vào bản dùng thử theo nguyên gốc từ Chrome 121 trên máy tính, để cho phép nhà phát triển bật tính năng này cho khách truy cập vào trang web của họ để thu thập dữ liệu từ người dùng thực. Hãy xem bài viết Bắt đầu sử dụng bản dùng thử theo nguyên gốc để biết thêm thông tin về bản dùng thử theo nguyên gốc.

Mức độ bảo mật và quyền riêng tư

Để tìm hiểu về các đánh đổi về bảo mật, hãy xem phần Các cân nhắc về quyền riêng tư và bảo mật trong thông số kỹ thuật của Element Capture.

Trình duyệt Chrome vẽ một đường viền màu xanh dương xung quanh cạnh của thẻ được chụp.

Bản minh hoạ

Bạn có thể chơi bằng tính năng Element Capture (Ghi phần tử) bằng cách chạy bản minh hoạ trên Glitch. Hãy nhớ xem mã nguồn.

Ý kiến phản hồi

Nhóm Chrome và cộng đồng tiêu chuẩn web muốn biết về trải nghiệm của bạn với Element Capture.

Cho chúng tôi biết về thiết kế

Có điều gì đó về tính năng Chụp ảnh vùng không hoạt động như bạn mong đợi không? Hoặc có phương thức hoặc thuộc tính nào bị thiếu mà bạn cần triển khai ý tưởng không? Bạn có câu hỏi hoặc nhận xét về mô hình bảo mật?

  • Gửi một vấn đề về thông số kỹ thuật lên kho lưu trữ GitHub hoặc thêm ý kiến vào một vấn đề hiện có.

Bạn gặp vấn đề khi triển khai?

Bạn có tìm thấy lỗi khi triển khai Chrome không? Hay cách triển khai có khác với quy cách không?

  • Gửi lỗi tại https://new.crbug.com. Hãy nhớ cung cấp nhiều thông tin chi tiết nhất có thể và hướng dẫn đơn giản để tái tạo. Hiệu ứng nhiễu rất phù hợp để chia sẻ bản sao chép nhanh chóng và dễ dàng.

Thư cảm ơn

Ảnh của Paul Skorupskas trên Unsplash