別ブラウザを開き,カメラを起動させる

別ブラウザを開く部分に関しては,以下を参考ください

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>