ปัจจุบันเบราว์เซอร์จำนวนมากสามารถเข้าถึงอินพุตวิดีโอและเสียงจากผู้ใช้ได้ อย่างไรก็ตาม ประสบการณ์การใช้งานอาจเป็นแบบไดนามิกและในหน้าเว็บอย่างเต็มรูปแบบ หรืออาจมอบสิทธิ์ให้แอปอื่นในอุปกรณ์ของผู้ใช้ ทั้งนี้ขึ้นอยู่กับเบราว์เซอร์
เริ่มต้นด้วยวิธีง่ายๆ และค่อยๆ พัฒนา
วิธีที่ง่ายที่สุดคือขอไฟล์ที่บันทึกไว้ล่วงหน้าจากผู้ใช้ โดยสร้างองค์ประกอบอินพุตไฟล์แบบง่ายและเพิ่มตัวกรอง accept ที่ระบุว่าเรายอมรับเฉพาะไฟล์วิดีโอและแอตทริบิวต์ capture ที่ระบุว่าเราต้องการรับไฟล์จากกล้องโดยตรง
<input type="file" accept="video/*" capture />
วิธีนี้ใช้ได้กับทุกแพลตฟอร์ม ในเดสก์ท็อป ระบบจะแจ้งให้ผู้ใช้อัปโหลดไฟล์จากระบบไฟล์ (โดยไม่สนใจแอตทริบิวต์ capture) ใน Safari บน iOS ระบบจะเปิดแอปกล้องถ่ายรูปเพื่อให้คุณบันทึกวิดีโอแล้วส่งกลับไปยังหน้าเว็บ ส่วนใน Android ระบบจะให้ผู้ใช้เลือกแอปที่จะใช้บันทึกวิดีโอก่อนส่งกลับไปยังหน้าเว็บ
อุปกรณ์เคลื่อนที่หลายรุ่นมีกล้องมากกว่า 1 ตัว หากต้องการ คุณสามารถตั้งค่าแอตทริบิวต์ capture เป็น user หากต้องการกล้องที่หันเข้าหาผู้ใช้ หรือ environment หากต้องการกล้องที่หันออกด้านนอก
<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />
โปรดทราบว่านี่เป็นเพียงคำแนะนำเท่านั้น หากเบราว์เซอร์ไม่รองรับตัวเลือกนี้ หรือประเภทกล้องที่คุณขอไม่พร้อมใช้งาน เบราว์เซอร์อาจเลือกกล้องอื่น
เมื่อผู้ใช้บันทึกเสร็จแล้วและกลับมาที่เว็บไซต์ คุณจะต้องรับข้อมูลไฟล์ด้วยวิธีใดวิธีหนึ่ง คุณสามารถเข้าถึงได้อย่างรวดเร็วโดยแนบเหตุการณ์ onchange กับองค์ประกอบอินพุต แล้วอ่านพร็อพเพอร์ตี้ files ของออบเจ็กต์เหตุการณ์
<input type="file" accept="video/*" capture="camera" id="recorder" />
<video id="player" controls></video>
<script>
var recorder = document.getElementById('recorder');
var player = document.getElementById('player');
recorder.addEventListener('change', function (e) {
var file = e.target.files[0];
// Do something with the video file.
player.src = URL.createObjectURL(file);
});
</script>
เมื่อมีสิทธิ์เข้าถึงไฟล์แล้ว คุณจะทำอะไรกับไฟล์ก็ได้ตามต้องการ ตัวอย่างเช่น คุณสามารถทำสิ่งต่อไปนี้ได้
- แนบกับองค์ประกอบ
<video>โดยตรงเพื่อให้เล่นได้ - ดาวน์โหลดลงในอุปกรณ์ของผู้ใช้
- อัปโหลดไปยังเซิร์ฟเวอร์โดยแนบไปกับ
XMLHttpRequest - วาดเฟรมลงใน Canvas และใช้ฟิลเตอร์กับเฟรม
แม้ว่าการใช้วิธีการขององค์ประกอบอินพุตเพื่อเข้าถึงข้อมูลวิดีโอจะเป็นที่นิยม แต่ก็เป็นตัวเลือกที่น่าสนใจน้อยที่สุด เราต้องการเข้าถึงกล้องและมอบประสบการณ์การใช้งานที่ดีในหน้าเว็บโดยตรง
เข้าถึงกล้องแบบอินเทอร์แอกทีฟ
เบราว์เซอร์ที่ทันสมัยสามารถเชื่อมต่อกับกล้องได้โดยตรง ซึ่งช่วยให้เราสร้างประสบการณ์ที่ผสานรวมกับหน้าเว็บได้อย่างสมบูรณ์ และผู้ใช้จะไม่ต้องออกจากเบราว์เซอร์เลย
รับสิทธิ์เข้าถึงกล้อง
เราสามารถเข้าถึงกล้องได้โดยตรงโดยใช้ API ในข้อกำหนดเฉพาะของ WebRTC ที่เรียกว่า getUserMedia() getUserMedia() จะแจ้งให้ผู้ใช้ให้สิทธิ์เข้าถึงไมโครโฟนและกล้องที่เชื่อมต่ออยู่
หากสำเร็จ API จะแสดงผล Stream ซึ่งจะมีข้อมูลจากกล้องหรือไมโครโฟน จากนั้นเราจะแนบข้อมูลดังกล่าวกับองค์ประกอบ <video>, แนบกับสตรีม WebRTC หรือบันทึกโดยใช้ MediaRecorder API ก็ได้
หากต้องการรับข้อมูลจากกล้องที่เราเพิ่งตั้งค่า video: true ในออบเจ็กต์ข้อจำกัดที่ส่งไปยัง getUserMedia() API
<video id="player" controls></video>
<script>
var player = document.getElementById('player');
var handleSuccess = function (stream) {
player.srcObject = stream;
};
navigator.mediaDevices
.getUserMedia({audio: true, video: true})
.then(handleSuccess);
</script>
หากต้องการเลือกกล้องที่เฉพาะเจาะจง คุณสามารถแจกแจงกล้องที่ใช้ได้ก่อน
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices = devices.filter((d) => d.kind === 'videoinput');
});
จากนั้นคุณสามารถส่ง deviceId ที่ต้องการใช้เมื่อเรียกใช้ getUserMedia
navigator.mediaDevices.getUserMedia({
audio: true,
video: {
deviceId: devices[0].deviceId,
},
});
ซึ่งข้อมูลนี้เพียงอย่างเดียวอาจไม่มีประโยชน์มากนัก สิ่งที่เราทำได้คือรับข้อมูลวิดีโอและเล่นวิดีโอ
เข้าถึงข้อมูลดิบจากกล้อง
หากต้องการเข้าถึงข้อมูลวิดีโอดิบจากกล้อง คุณสามารถวาดแต่ละเฟรมลงใน <canvas> และจัดการพิกเซลได้โดยตรง
สำหรับ Canvas 2 มิติ คุณสามารถใช้เมธอด drawImage ของบริบทเพื่อวาดเฟรมปัจจุบันขององค์ประกอบ <video> ลงใน Canvas
context.drawImage(myVideoElement, 0, 0);
เมื่อใช้ Canvas ของ WebGL คุณจะใช้องค์ประกอบ <video> เป็นแหล่งที่มาของพื้นผิวได้
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
myVideoElement,
);
โปรดทราบว่าไม่ว่าจะเลือกวิธีใด ระบบจะใช้เฟรมปัจจุบันของวิดีโอที่กำลังเล่นอยู่ หากต้องการประมวลผลหลายเฟรม คุณต้องวาดวิดีโอใหม่ลงใน Canvas ทุกครั้ง
ดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในบทความเกี่ยวกับการใช้เอฟเฟกต์แบบเรียลไทม์กับรูปภาพและวิดีโอ
บันทึกข้อมูลจากกล้อง
วิธีที่ง่ายที่สุดในการบันทึกข้อมูลจากกล้องคือการใช้ API MediaRecorder
MediaRecorder API จะใช้สตรีมที่สร้างโดย getUserMedia แล้วบันทึกข้อมูลจากสตรีมไปยังปลายทางที่ต้องการอย่างต่อเนื่อง
<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
let shouldStop = false;
let stopped = false;
const downloadLink = document.getElementById('download');
const stopButton = document.getElementById('stop');
stopButton.addEventListener('click', function() {
shouldStop = true;
})
var handleSuccess = function(stream) {
const options = {mimeType: 'video/webm'};
const recordedChunks = [];
const mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.addEventListener('dataavailable', function(e) {
if (e.data.size > 0) {
recordedChunks.push(e.data);
}
if(shouldStop === true && stopped === false) {
mediaRecorder.stop();
stopped = true;
}
});
mediaRecorder.addEventListener('stop', function() {
downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
downloadLink.download = 'acetest.webm';
});
mediaRecorder.start();
};
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(handleSuccess);
</script>
ในกรณีของเรา เราจะบันทึกข้อมูลลงในอาร์เรย์โดยตรง ซึ่งเราสามารถเปลี่ยนเป็น Blob ในภายหลังได้ จากนั้นจึงใช้เพื่อบันทึกลงในเว็บเซิร์ฟเวอร์หรือในพื้นที่เก็บข้อมูลบนอุปกรณ์ของผู้ใช้โดยตรง
ขอสิทธิ์ใช้กล้องอย่างมีความรับผิดชอบ
หากผู้ใช้ไม่เคยให้สิทธิ์เว็บไซต์ของคุณเข้าถึงกล้องมาก่อน ทันทีที่คุณเรียกใช้ getUserMedia เบราว์เซอร์จะแจ้งให้ผู้ใช้ให้สิทธิ์เว็บไซต์ของคุณเข้าถึงกล้อง
ผู้ใช้มักไม่ชอบให้มีการแจ้งเตือนเพื่อขอสิทธิ์เข้าถึงอุปกรณ์ที่มีประสิทธิภาพในเครื่องของตน และมักจะบล็อกคำขอหรือเพิกเฉยหากไม่เข้าใจบริบทที่สร้างข้อความแจ้งนั้นขึ้นมา แนวทางปฏิบัติแนะนำคือให้ขอสิทธิ์เข้าถึงกล้องเมื่อจำเป็นต้องใช้เป็นครั้งแรกเท่านั้น เมื่อผู้ใช้ให้สิทธิ์เข้าถึงแล้ว ระบบจะไม่ขอสิทธิ์อีก อย่างไรก็ตาม หากผู้ใช้ปฏิเสธสิทธิ์เข้าถึง คุณจะไม่สามารถเข้าถึงเพื่อขอสิทธิ์จากผู้ใช้ได้อีก
ใช้ Permissions API เพื่อตรวจสอบว่าคุณมีสิทธิ์เข้าถึงอยู่แล้วหรือไม่
getUserMedia API ไม่ได้ให้ข้อมูลว่าคุณมีสิทธิ์เข้าถึงกล้องอยู่แล้วหรือไม่ ซึ่งทำให้เกิดปัญหาว่าหากต้องการแสดง UI ที่สวยงามเพื่อขอให้ผู้ใช้ให้สิทธิ์เข้าถึงกล้อง คุณต้องขอสิทธิ์เข้าถึงกล้อง
ปัญหานี้แก้ไขได้ในบางเบราว์เซอร์โดยใช้ Permission API navigator.permission API ช่วยให้คุณค้นหาสถานะของความสามารถในการเข้าถึง API ที่เฉพาะเจาะจงได้โดยไม่ต้องแจ้งอีกครั้ง
หากต้องการค้นหาว่าคุณมีสิทธิ์เข้าถึงกล้องของผู้ใช้หรือไม่ คุณสามารถส่ง {name: 'camera'} ไปยังเมธอดการค้นหา ซึ่งจะแสดงผลอย่างใดอย่างหนึ่งต่อไปนี้
granted— ผู้ใช้เคยให้สิทธิ์เข้าถึงกล้องแก่คุณแล้วprompt— ผู้ใช้ไม่ได้ให้สิทธิ์เข้าถึงแก่คุณ และจะได้รับข้อความแจ้งเมื่อคุณโทรหาgetUserMediadenied— ระบบหรือผู้ใช้ได้บล็อกการเข้าถึงกล้องอย่างชัดเจน และคุณจะไม่สามารถเข้าถึงกล้องได้
และตอนนี้คุณสามารถตรวจสอบได้อย่างรวดเร็วว่าจำเป็นต้องปรับเปลี่ยนอินเทอร์เฟซผู้ใช้เพื่อรองรับการดำเนินการที่ผู้ใช้ต้องทำหรือไม่
navigator.permissions.query({name: 'camera'}).then(function (result) {
if (result.state == 'granted') {
} else if (result.state == 'prompt') {
} else if (result.state == 'denied') {
}
result.onchange = function () {};
});