Подтвердить что ты не робот

Запись и сохранение видео в формате 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, я могу сохранить поток по мере его поступления или что-то в этом роде?

4b9b3361

Ответ 1

ОБНОВЛЕНИЕ 12/2014 FYI, на его пути появился новый API, называемый MediaRecorder. В настоящее время поддерживается только в Firefox и в раннем состоянии, но что-то иметь в виду.

mediaStream и локальное хранилище

В чистой локальной среде вы не можете и не получите очень хороший результат. Вы можете сэкономить кадры с помощью элемента canvas, нарисуя на нем и сохранить jpeg-изображения в локальном хранилище из видеопотока вместе с аудио (который должен быть сохранен отдельно), а затем в post использовать библиотеку для создания, например, MJPEG файла (AFAIK в настоящее время не поддерживает аудио).

Однако вы столкнетесь с несколькими проблемами с этим подходом: для обработки всей этой информации потребуется много времени, чтобы использовать JavaScript, просто сохраняя фрейм как jpeg, преобразовывая его в blob и сохраняя его в файловой системе или индексированный DB потребляйте больше всего (или более) бюджета времени, доступного для одного кадра.

Вы не сможете синхронизировать видеокадры с аудио должным образом - вы можете сохранить отметку времени и использовать ее для "исправления" фреймов, но ваш FPS, скорее всего, изменится, создавая резкое видео. И даже если вы немного синхронизируете синхронизацию, вы, вероятно, столкнетесь с проблемами с задержкой, когда аудио и видео не совпадают, поскольку изначально они состоят из двух отдельных потоков.

Но видео очень редко выше 30 FPS (США) или 25 FPS (Европа), поэтому вам не понадобится полная скорость 60 FPS, которую может предоставить браузер. Это дает вам немного лучшего бюджета времени около 33 миллисекунд за кадр для системы США (NTSC) и немного больше, если вы находитесь в стране, использующей систему PAL. Нет ничего плохого в использовании еще более низкой частоты кадров, но в определенной точке (< 12-15 FPS) вы начнете замечать серьезную нехватку гладкости.

Однако на это влияют многие факторы, такие как процессор, дисковая система, размер рамки и т.д. JavaScript является однопоточным, а canvas API синхронно, поэтому 12-ядерный процессор не поможет вам в этом отношении, и полезность Web Workers в настоящее время в значительной степени ограничена более долгосрочными задачами. Если у вас много доступной памяти, вы можете кэшировать фреймы в оперативной памяти и выполнять всю обработку в сообщении, что снова займет некоторое время. Поток, записанный при 720P @30 FPS, будет потреблять не менее 105 Мбит/с (это просто необработанные данные, не включающие внутреннюю обработку браузером буферов, которые могут удвоить или даже утроить это).

WebRTC

Лучшим решением, вероятно, будет использование WebRTC и подключение к серверу (внешнему или локальному) и обработка потока там. Этот поток будет содержать синхронизированное аудио и видео, и вы можете временно сохранить поток на диск без ограничений области хранения с песочницей в браузере. Недостатком здесь будет (для внешних соединений) пропускная способность, так как это может снизить качество, а также возможности сервера.

Это открывает возможность использовать, например, Node.js,.Net или PHP для фактической обработки с использованием сторонних компонентов (или более низкоуровневого подхода, например, с использованием скомпилированных C/С++ и CGI/трубопроводов если вы в этом).

Вы можете проверить этот проект с открытым исходным кодом, который поддерживает перекодирование потоков WebRTC:
http://lynckia.com/licode/

Проект Licode предоставляет API-интерфейс NodeJS для WebRTC, чтобы вы могли использовать его на стороне сервера, видеть документы

И это в основном, насколько вы можете идти с текущим состоянием HTML5.

Вспышка

Тогда есть возможность установить Flash и использовать ее - вам по-прежнему потребуется стороннее решение сервера (Red5, Wowza или AMS).

Это, вероятно, даст вам менее болезненный опыт, но вам необходимо установить Flash в браузере (очевидно), и во многих случаях из-за лицензий существует более высокий коэффициент затрат (см. Red5 для альтернативы с открытым исходным кодом.

Если вы готовы платить за коммерческие решения, есть такие решения, как: http://nimbb.com/

Ответ 2

здесь создается поток.

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

ваши данные - это sream.. или window.URL.createObjectURL(поток).

но вы не можете просто написать поток или window.URL.createObjectURL(поток) в localstorage (2mb.. to small) или webkitRequestFileSystem (который позволяет вам использовать gb)... вам нужно прочитать данные, выводимые на тег видео, и преобразовать их в холст как один кадр, сохраняющий это в webkitfilesystem.

так как файловая система в последнее время менялась в googled для нового кода и нашла этот прекрасный пример для вас. https://gist.github.com/piatra/2549734

в примере, который он использует

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

который записывает кадр каждые 200 мс

если вы хотите, чтобы пользовательская рамка изменила только 200 мс на 1000/25.. (25 кадров в секунду)

или используйте requestanimationframe, и вы должны получить около 60 кадров в секунду, если ур cpu поддерживает это.

теперь у вас нет реального потока в хорошем формате, таком как mp4... но много кадров, которые вы можете отобразить с помощью другой функции... снова вам понадобится очень быстрый процессор.

в этом примере звук не работает.

для записи звука в WAV (вы не можете записывать mp3 или aac)... я нашел это.

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

поэтому в theend вы могли бы это сделать... но это займет много места в течение нескольких минут и требует очень быстрого процессора, чтобы все продумать.

Ответ 3

Вот полностью рабочий код для захвата видео и его сохранения на локальном компьютере:

Требуется разрешение, например, сохранение файлов, камеры и микрофона:

<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>

Ссылка: Запись медиа-элемента