web-dev-qa-db-ja.com

HTML5はビデオをキャプチャして保存します

私は、ユーザーがmp3と共に歌っている自分のビデオをキャプチャできる歌唱用のサイトを構築しています。カメラにアクセスしてライブストリームを表示できるようになりましたが、ビデオを保存してユーザーがダウンロードして保存できるようにするにはどうすればよいですか?

私のコード:

<!DOCTYPE html>
<head>
<link href="css/bootstrap.css" rel="stylesheet"">
<style>
#container {
margin: 0px auto;
width: 500px;
height: 375px;
border: 10px #333 solid;
}
#videoElement {
width: 500px;
height: 375px;
background-color: #666;
}
</style>
</head>
<body>

<button class="btn" onclick="show();">Record!</button>


<div id="record" style="display:none; text-align:center;">
<div id="container">
<video autoplay="false" id="videoElement">
</video>
</div>
<button id="play" class="btn" onclick="play()">Start Recording!</button>
<audio id="song" style="hidden">
<source src="love.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
</div>



<script src="http://code.jquery.com/jquery.js"></script>
<script src="js/bootstrap.js"></script>
<script>

var video = document.querySelector("#videoElement");

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||    navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;

if (navigator.getUserMedia) {       
navigator.getUserMedia({video: true, audio: true}, handleVideo, videoError);
}

function handleVideo(stream) {
video.src = window.URL.createObjectURL(stream);
document.getElementById("videoElement").pause();
}

function videoError(e) {
alert("There was an error with the video stream.\nCheck that your webcam is connected.");
}

function play()
{
var video = document.getElementById("videoElement");
var music = document.getElementById("song");
   var button = document.getElementById("play");
   if (video.paused) {
      video.play();
      music.play();
      button.textContent = "Stop Recording";
   } else {
      video.pause();
      music.pause();
      button.textContent = "Continue Recording";
   }
}

function show()
{
document.getElementById("record").style.display="block";
}
</script>
</body>

handleVideoにストリームを保存する方法はありますか?

20
scalen121

UPDATE 12/2014FYI、その方法で呼び出される新しいAPIがあります- MediaRecorder。現在、Firefoxでのみサポートされており、初期状態ですが、心に留めておいてください。

mediaStreamおよびローカルストレージ

純粋なローカル環境では、非常に良い結果を得ることはできません。 canvas要素を使用してフレームを保存し、描画してjpeg画像をビデオストリームからローカルストレージにオーディオ(個別に保存する必要がある)とともにローカルストレージに保存し、その後、ライブラリを使用してMJPEGなどを作成します。ファイル(現在、オーディオをサポートするものはありません)。

ただし、このアプローチではいくつかの問題が発生します。JavaScriptを使用してこのすべての情報を処理するには時間がかかります。フレームをjpegとして保存し、それをblobに変換してファイルシステムまたはインデックス付きDBに保存するだけで、ほとんどが消費されます( 1つ以上のフレームで利用できる時間の予算。

ビデオフレームとオーディオを正しく同期させることはできません。タイムスタンプを保存してフレームを「修正」することができますが、FPSが変化してぎくしゃくしたビデオが作成される可能性が高くなります。また、時間的にある程度の順序で同期を取得しても、最初は2つの別々のストリームであるため、オーディオとビデオが一致しないというラグの問題に直面する可能性があります。

ただし、ビデオが30 FPS(米国)または25 FPS(ヨーロッパ)を超えることは非常にまれであるため、ブラウザが提供する完全な60 FPSレートは必要ありません。これにより、US(NTSC)システムの場合、フレームあたり約33ミリ秒という少し良い時間バジェットが得られます。PALシステムを使用している国の場合は、少し長くなります。さらに低いフレームレートを使用しても問題はありませんが、特定のポイント(<12-15 FPS)で、滑らかさが大幅に不足していることに気づきます。

ただし、CPU、ディスクシステム、フレームの寸法など、これに影響を与える多くの要素があります。 JavaScriptはシングルスレッドで、キャンバスAPIは同期しているため、12コアCPUはその点であまり役に立ちません。また、Webワーカーの有用性は、現在、長時間実行されるタスクにかなり制限されています。利用可能なメモリが大量にある場合は、フレームをメモリ内にキャッシュできます。これは実行可能で、すべての処理をポストで実行しますが、これにも時間がかかります。 720P @ 30 FPSで記録されたストリームは、毎秒最低105 mbを消費します(これは、これを2倍または3倍にする可能性のあるブラウザーのバッファーの内部処理を含まない未加工データです)。

WebRTC

より良い解決策は、おそらくWebRTCを使用してサーバー(外部またはローカル)に接続し、そこでストリームを処理することです。このストリームには同期されたオーディオとビデオが含まれ、ブラウザのサンドボックス化されたストレージ領域の制限なしに、ストリームを一時的にディスクに保存できます。ここでの欠点は、(外部接続の場合)帯域幅になり、これにより品質とサーバーの機能が低下する可能性があります。

これにより、たとえばNode.js、.NetまたはPHP=を使用して、サードパーティのコンポーネント(またはコンパイル済みのC/C++を使用するなどのより低レベルのアプローチ)を使用して実際の処理を行う可能性が広がりますCGI/pipingを使用している場合)。

WebRTCストリームの再コーディングをサポートするこのオープンソースプロジェクトをチェックアウトできます。
http://lynckia.com/licode/

LicodeプロジェクトはWebRTC用のNodeJSクライアントAPIを提供するため、サーバー側で使用できます ドキュメントを参照

そして、これは基本的に、現在のHTML5の状態をどの程度まで利用できるかということです。

Flash

次に、Flashをインストールしてそれを使用するオプションがあります-あなた まだサーバーが必要です サイドソリューション(Red5、WowzaまたはAMS)。

これはおそらくあなたにそれほど苦痛のない体験を与えるでしょうが、ブラウザにFlashをインストールする必要があります(明らかに)ライセンスのために多くの場合より高いコスト要因があります(オープンソースについては Red5を参照 を参照してください)代替)。

商用ソリューションにお金を払う気があるなら、次のようなソリューションがあります。
http://nimbb.com/

14
user1693593

ここでストリームが作成されます。

function handleVideo(stream) {
 video.src = window.URL.createObjectURL(stream);
 document.getElementById("videoElement").pause();
}

データはsream ..またはwindow.URL.createObjectURL(stream)です。

しかし、ストリームまたはwindow.URL.createObjectURL(stream)をlocalstorage(2mb ..からsmall)またはwebkitRequestFileSystem(GBを許可)に単に書き込むことはできません...ビデオタグに出力されたデータを読み取る必要がありますそしてそれを単一フレームとしてキャンバスに変換し、webkitfilesystemに保存します。

ファイルシステムが最近変更されたので、新しいコードを探してこの完璧な例を見つけました。 https://Gist.github.com/piatra/2549734

彼が使用する例では

setTimeout(function(){ draw(v, bc, w, h); }, 200);

200msごとにフレームを書き込みます

カスタムフレームレートが必要な場合は、200msを1000/25 ..(25fps)に変更するだけです。

または、requestanimationframeを使用します。urcpuでサポートされている場合は、60 fps程度になるはずです。

今、あなたはmp4のようなニース形式の本当のストリームを持っていません...しかし、別の関数で表示できるたくさんのフレーム...再び、本当に速いCPUが必要です。

この例では、オーディオは機能しません。

オーディオもWAVに録音するには(mp3またはaacは録音できません)...これを見つけました。

http://typedarray.org/from-microphone-to-wav-with-getusermedia-and-web-audio/

したがって、最後にそれを行うことができます...しかし、それはほんの数分のスペースを必要とし、すべてを詳しく説明するには非常に高速なCPUが必要です。

1
cocco

ビデオをキャプチャしてローカルに保存するための完全に機能するコードを次に示します。

ファイル、カメラ、マイクの保存などの許可が必要です。

<html>
    <div class="left">
        <div id="startButton" class="button">
        Start
        </div>
        <h2>Preview</h2>
        <video id="preview" width="160" height="120" autoplay muted></video>
    </div>

    <div class="right">
        <div id="stopButton" class="button">
        Stop
        </div>
        <h2>Recording</h2>
        <video id="recording" width="160" height="120" controls></video>
        <a id="downloadButton" class="button">
        Download
        </a>
    </div>

    <script>

    let preview = document.getElementById("preview");
    let recording = document.getElementById("recording");
    let startButton = document.getElementById("startButton");
    let stopButton = document.getElementById("stopButton");
    let downloadButton = document.getElementById("downloadButton");
    let logElement = document.getElementById("log");

    let recordingTimeMS = 5000;


    function log(msg) {
        //logElement.innerHTML += msg + "\n";
    }

    function wait(delayInMS) {
        return new Promise(resolve => setTimeout(resolve, delayInMS));
    }

    function startRecording(stream, lengthInMS) {
        let recorder = new MediaRecorder(stream);
        let data = [];

        recorder.ondataavailable = event => data.Push(event.data);
        recorder.start();
        log(recorder.state + " for " + (lengthInMS/1000) + " seconds...");

        let stopped = new Promise((resolve, reject) => {
        recorder.onstop = resolve;
        recorder.onerror = event => reject(event.name);
        });

        let recorded = wait(lengthInMS).then(
        () => recorder.state == "recording" && recorder.stop()
        );

        return Promise.all([
            stopped,
            recorded
        ])
        .then(() => data);
    }

    function stop(stream) {
        stream.getTracks().forEach(track => track.stop());
    }

    startButton.addEventListener("click", function() {
        navigator.mediaDevices.getUserMedia({
            video: true,
            audio: false
        }).then(stream => {
                preview.srcObject = stream;
                downloadButton.href = stream;
                preview.captureStream = preview.captureStream || preview.mozCaptureStream;
                return new Promise(resolve => preview.onplaying = resolve);
              }).then(() => startRecording(preview.captureStream(), recordingTimeMS))
              .then (recordedChunks => {
                let recordedBlob = new Blob(recordedChunks, { type: "video/webm" });
                recording.src = URL.createObjectURL(recordedBlob);  
                downloadButton.href = recording.src;
                downloadButton.download = "RecordedVideo.webm";

                log("Successfully recorded " + recordedBlob.size + " bytes of " +
                    recordedBlob.type + " media.");
              })
              .catch(log);
        }, false);


        stopButton.addEventListener("click", function() {
        stop(preview.srcObject);
        }, false);

    </script>
</html>

参照: メディア要素の記録

1
Vikash Kumar