別ブラウザを開き,カメラを起動させる
別ブラウザを開く部分に関しては,以下を参考ください
challenge-think.hatenablog.com
htmlに関しては,上の記事と似たものを使用します.
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>サンプル</title>
</head>
<body>
<p>サンプルページです。</p>
<!-- video part -->
<div id="videoBox">
<video id="videoMain"></video>
<div id="captionMain">支援者</div>
</div>
<div id="cameraIcon">
<input type="image" id="UserCamIcon">
</div>
</body>
次に,後々変更が加えやすいように,一番最初に実行されるファイルにすべて記述するのではなく,カメラに関する関数類は別ファイルに記述することにします.
以下index.tsです.
import { CameraManager } from "./ts/Manager/Modules/CameraManager";
// 接続されているカメラを取得する
const CamMG = await CameraManager.setup();
次に,CameraManager.tsです.
export const UserCamIcon: HTMLElement = document.getElementById("UserCamIcon") as HTMLElement;
export const videoMain : HTMLMediaElement = document.getElementById("videoMain") as HTMLMediaElement;
export const videoBox : HTMLElement = document.getElementById("videoBox") as HTMLElement;
export class CameraManager{
public CameraLists : any;
private IntegratedCam: any;
// private WebCam : any;
public static async setup(): Promise<cameramanager>{
const CamMG = new CameraManager();
CamMG.CameraLists = await this.getCameraInfo();
CamMG.detectCam();
CamMG.CameraStart();
return CamMG;
}
// 使用できるカメラ情報を取得する
private static async getCameraInfo(){
try {
const CamLists = (await navigator.mediaDevices.enumerateDevices()).filter(device => device.kind === "videoinput");
// console.log(CamLists);
return CamLists;
} catch (error){
console.log(error);
return null;
}
}
private detectCam(){
this.CameraLists.forEach((Cam) => {
if(Cam.label.includes('Integrated Camera')){
this.IntegratedCam = Cam;
}else if(Cam.label.includes('Webcam')){
// this.WebCam = Cam;
}
});
}
// カメラを起動する
private CameraStart(){
// 内蔵カメラとウェブカメラを起動する
navigator.mediaDevices.getUserMedia({
video: {
deviceId: this.IntegratedCam.deviceId,
},
audio: false,
}).then(stream => {
videoMain.srcObject = stream;
videoMain.style.transform = "scaleX(-1)";
videoMain.play()
}).catch(error => {
console.log("Integrated Camera Error:"+ error);
return;
})
// ユーザカメラのアイコンクリック時の処理
UserCamIcon.addEventListener('click', () => { // width=300,height=300,left=0,top=0
let option = 'width=1000,height=1000,left=0,top=0'
open('./src/html/userCam.html','mywindow', option);
});
}
// ビデオを表示する
public CamShow(){
// videoを表示する
videoBox.style.display = "block";
}
}
最後に表示させるhtmlファイルを設定します.
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ユーザカメラ</title>
<script src="../ts/Modules/CameraManager.ts"></script>
<link rel="stylesheet" href="../css/style(UserCam).css">
<!-- bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body style="margin: 5%; background-color: rgb(202, 202, 202);">
<div class="row">
<div class="col">
<div class="backgroundCaputure">
<h3 style="background-color: wheat;">ユーザが見ている画面</h3>
<p>
<button id="start">表示画面の選択する</button>
<button id="stop">画面表示を終了する</button>
</p>
<video id="video" autoplay width="800" height="400" style="object-fit: contain;"></video>
<br>
</div>
</div>
<div class="col" style="margin: 2%;">
<div class="backgroundVideo">
<div id="videoBox1">
<video id="videoSub"></video>
<div id="captionSub">ユーザ</div>
</div>
<div id="control">
<button class="recordStart" onClick="beginRecorde()">録画開始</button>
<button class="recordEnd">録画終了</button>
<div id="stateBox">
状態:&tl;a id="state">カメラが見つかりません</a>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
const videoSub = document.getElementById("videoSub");
const myPlayer = document.getElementById('myPlayer');
const state = document.getElementById('state');
// カメラ起動
state.innerText = "カメラ起動中";
navigator.mediaDevices.getUserMedia({
video: {
deviceId: "7ac074b780a5ceccfa6ac177ffcf014a24a684b67a1dbe9fe22388f53994b250",
},
audio: false,
}).then(stream => {
videoSub.srcObject = stream;
videoSub.style.transform = "scaleX(-1)";
videoSub.play();
}).catch(error => {
console.log("Web Camera Error:"+ error);
return;
})
//========== Recorder ==========//
var recorder = null;
var chunks = [];
function beginRecorde(){
if(!videoSub.srcObject) return;
if(recorder) return;
recorder = new MediaRecorder(videoSub.srcObject, {
audioBitsPerSecond : 64000,
videoBitsPerSecond : 512000,
mimeType : 'video/webm; codecs=vp9'
});
chunks = [];
state.innerText = "録画開始";
recorder.ondataavailable = function(e){
chunks.push(e.data);
};
recorder.onstop = function(e){
recorder = null;
startDownload();
};
recorder.start(1000);
};
function endRecorde(){
if(recorder) recorder.stop();
};
//========== Downloader ==========//
var blobUrl = null;
function startDownload(){
const recodeDate = getDate();
if(!blobUrl){
window.URL.revokeObjectURL(blobUrl);
blobUrl = null;
};
var videoBlob = new Blob(chunks, { type : "video/webm" });
console.log(videoBlob);
blobUrl = window.URL.createObjectURL(videoBlob);
console.log(blobUrl);
// ビデオをダウンロードする(Blob→mp4)
/* dawnload先を変更する */
if(blobUrl){
const a = document.createElement("a");
document.body.appendChild(a);
state.innerText = 'ダウンロードします';
a.download = 'ユーザ表情録画'+recodeDate+'.mp4';
a.href = blobUrl;
a.click();
a.remove();
URL.revokeObjectURL(blobUrl);
state.innerText = 'ダウンロード完了';
};
};
/* 日付を取得する関数 */
function getDate(){
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth();
const date = now.getDate();
const hour = now.getHours();
const minute = now.getMinutes();
const recodeDate = year+'/'+month+'/'+date+'/'+hour+'/'+minute;
return recodeDate;
}
</script>