HTML 5 视频录制和存储流

63

我想使用Html 5录制视频并将流保存到本地文件中。以下是代码。在按钮单击时,它已调用摄像头并在HTML的“VIDEO”标签中捕获了视频。我能把流存储到本地文件吗?或者可以将其存储为MP4文件吗?

<!DOCTYPE html>
<html>
<head>

<script type="text/javascript">

function enter() {

    if (navigator.mozGetUserMedia) { 
       navigator.myGetMedia=navigator.mozGetUserMedia;
       navigator.myGetMedia({video: true}, connect, error); 
    } 
    else {
       alert("NO");
    }

    function connect(stream) {

        var video = document.getElementById("my_video");
            video.src = window.URL ? window.URL.createObjectURL(stream) : stream;
            video.play();

        var canvas = document.getElementById("c"); 
    }

    function error(e) { console.log(e); }

}

</script>

</head>    
<body>
    <canvas width="640" height="480" id="c"></canvas>
    <input type="button" value="RECORD" onClick="enter()"/>
    <input type="button" value="SAVE" />
    <video id="my_video" width="640" height="480"/>
</body>
</html>

我希望在点击保存按钮时保存流。

5个回答

46

RecordRTC:WebRTC音视频录制

https://github.com/muaz-khan/WebRTC-Experiment/tree/master/RecordRTC

  • Chrome和Firefox均支持音频录制
  • 仅限于Chrome的视频/Gif录制;(Firefox有一些问题,不久后将恢复)

演示:https://www.webrtc-experiment.com/RecordRTC/


从getUserMedia()创建.webm视频

http://ericbidelman.tumblr.com/post/31486670538/creating-webm-video-from-getusermedia

演示:http://html5-demos.appspot.com/static/getusermedia/record-user-webm.html


在HTML5中捕获音频和视频

http://www.html5rocks.com/en/tutorials/getusermedia/intro/


1
好的链接,有趣的解决方案。但请注意,这仍然是一些变通方法,依赖于对画布元素进行快照并逐帧编码处理。 - Georg
1
在Chrome中被静音了,而在Firefox中不支持视频。我该如何在Chrome中录制声音,在Firefox中录制视频呢? - Rizwan Gill
有其他人也遇到了Gill的问题吗?我想在尝试这些解决方案之前先了解一下。 - Daniel
1
这并没有说明实际上如何保存任何东西。 - john k

21

MediaRecorder API 是你正在寻找的解决方案。

Firefox 已经支持了一段时间,而 Chrome 正在计划在下一个版本(Chrome 48)中实现它,但你可能仍需要启用实验性标志。显然,从 Chrome 版本49开始将不需要此标志,如需更多信息,请查看此Chrome问题

同时,以下是 Firefox 的示例:

var video, reqBtn, startBtn, stopBtn, ul, stream, recorder;
video = document.getElementById('video');
reqBtn = document.getElementById('request');
startBtn = document.getElementById('start');
stopBtn = document.getElementById('stop');
ul = document.getElementById('ul');
reqBtn.onclick = requestVideo;
startBtn.onclick = startRecording;
stopBtn.onclick = stopRecording;
startBtn.disabled = true;
ul.style.display = 'none';
stopBtn.disabled = true;

function requestVideo() {
  navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    })
    .then(stm => {
      stream = stm;
      reqBtn.style.display = 'none';
      startBtn.removeAttribute('disabled');
      video.src = URL.createObjectURL(stream);
    }).catch(e => console.error(e));
}

function startRecording() {
  recorder = new MediaRecorder(stream, {
    mimeType: 'video/mp4'
  });
  recorder.start();
  stopBtn.removeAttribute('disabled');
  startBtn.disabled = true;
}


function stopRecording() {
  recorder.ondataavailable = e => {
    ul.style.display = 'block';
    var a = document.createElement('a'),
      li = document.createElement('li');
    a.download = ['video_', (new Date() + '').slice(4, 28), '.webm'].join('');
    a.href = URL.createObjectURL(e.data);
    a.textContent = a.download;
    li.appendChild(a);
    ul.appendChild(li);
  };
  recorder.stop();
  startBtn.removeAttribute('disabled');
  stopBtn.disabled = true;
}
<div>

  <button id='request'>
    Request Camera
  </button>
  <button id='start'>
    Start Recording
  </button>
  <button id='stop'>
    Stop Recording
  </button>
  <ul id='ul'>
    Downloads List:
  </ul>

</div>
<video id='video' autoplay></video>


3
@jim,这可能是一个https问题,你可以尝试访问https://mido22.github.io/MediaRecorder-sample/。 - mido
你有没有想过为什么在第47行出现了"NotSupportedError: Operation is not supported"的错误,而该行代码是recorder = new MediaRecorder(stream, {mimeType:'video/mp4' }); - Mitya
Firefox 62在我的HTTPS本地主机上显示MediaStreamError{name:"NotFoundError",message:"无法在此处找到对象。"} - dakab
1
它支持Safari吗? - Umesh Patadiya
视频的src属性应该使用stm而不是srcObject,参考以下文章:https://www.fxsitecompat.dev/en-CA/docs/2018/url-createobjecturl-no-longer-accepts-mediastream-as-argument/。 - NazimZeeshan

10

目前没有适用于生产的仅基于HTML5的解决方案可以在网页上录制视频。目前可用的解决方案如下:

HTML媒体捕获

适用于移动设备,使用操作系统的视频捕获应用程序来捕获视频并将其上传/POST到Web服务器。您将在iOS上得到.mov文件(这些无法在Android上播放,我已经尝试过),而在Android上则得到.mp4和.3gp文件。至少编解码器将是相同的:99%的设备中的视频为H.264,音频为AAC。

HTML Media Capture

图片提供自https://blog.addpipe.com/the-new-video-recording-prompt-for-media-capture-in-ios9/

桌面上的Flash和媒体服务器

Flash中的视频录制工作方式如下:从网络摄像头和麦克风捕获音频和视频数据,使用Sorenson Spark或H.264(视频)和Nellymoser Asao或Speex(音频)进行编码,然后将它们流式传输(rtmp)到媒体服务器(Red5、AMS、Wowza),在那里保存为.flv或.f4v文件。

MediaStream Recording 提案

MediaStream Recording 是由媒体捕获工作组(WebRTC和设备API工作组的联合工作组)提出的一个提案,其目的是使浏览器中的基本视频录制非常简单。

尚未受到主流浏览器的支持。如果实现了(如果可以),您可能会得到不同的文件类型(至少为.ogg和.webm)和音频/视频编解码器,这取决于浏览器。

商业解决方案

目前市场上有一些SaaS和软件解决方案可以处理以上任务,包括addpipe.com、HDFVR、Nimbb和Cameratag。

进一步阅读:


6

1
这篇Medium文章甚至提供了更详细的描述,介绍了高级功能,如保存到本地文件、服务器等。https://medium.com/@manivannan_data/record-audio-video-image-and-gif-from-browser-using-videojs-record-2249fcc6ea9e - ssp4all

5
以下示例展示了如何在HTML5中捕获和处理视频帧:
```html

以下示例展示了如何在HTML5中捕获和处理视频帧:

```

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Capturing & Processing Video in HTML5</title>
</head>
<body>
    <div>
        <h2>Camera Preview</h2>
        <video id="cameraPreview" width="240" height="180" autoplay></video>
        <p>
            <button id="startButton" onclick="startCapture();">Start Capture</button>
            <button id="stopButton" onclick="stopCapture();">Stop Capture</button>
        </p>
    </div>

    <div>
        <h2>Processing Preview</h2>
        <canvas id="processingPreview" width="240" height="180"></canvas>
    </div>

    <div>
        <h2>Recording Preview</h2>
        <video id="recordingPreview" width="240" height="180" autoplay controls></video>
        <p>
            <a id="downloadButton">Download</a>
        </p>
    </div>

    <script>

    const ROI_X = 250;
    const ROI_Y = 150;
    const ROI_WIDTH = 240;
    const ROI_HEIGHT = 180;
    
    const FPS = 25;
    
    let cameraStream = null;
    let processingStream = null;
    let mediaRecorder = null;
    let mediaChunks = null;
    let processingPreviewIntervalId = null;

    function processFrame() {
        let cameraPreview = document.getElementById("cameraPreview");
        
        processingPreview
            .getContext('2d')
            .drawImage(cameraPreview, ROI_X, ROI_Y, ROI_WIDTH, ROI_HEIGHT, 0, 0, ROI_WIDTH, ROI_HEIGHT);
    }
    
    function generateRecordingPreview() {
        let mediaBlob = new Blob(mediaChunks, { type: "video/webm" });
        let mediaBlobUrl = URL.createObjectURL(mediaBlob);
        
        let recordingPreview = document.getElementById("recordingPreview");
        recordingPreview.src = mediaBlobUrl;

        let downloadButton = document.getElementById("downloadButton");
        downloadButton.href = mediaBlobUrl;
        downloadButton.download = "RecordedVideo.webm";
    }
        
    function startCapture() {
        const constraints = { video: true, audio: false };
        navigator.mediaDevices.getUserMedia(constraints)
        .then((stream) => {
            cameraStream = stream;
            
            let processingPreview = document.getElementById("processingPreview");
            processingStream = processingPreview.captureStream(FPS);
            
            mediaRecorder = new MediaRecorder(processingStream);
            mediaChunks = []
            
            mediaRecorder.ondataavailable = function(event) {
                mediaChunks.push(event.data);
                if(mediaRecorder.state == "inactive") {
                    generateRecordingPreview();
                }
            };
            
            mediaRecorder.start();
            
            let cameraPreview = document.getElementById("cameraPreview");
            cameraPreview.srcObject = stream;
        
            processingPreviewIntervalId = setInterval(processFrame, 1000 / FPS);
        })
        .catch((err) => {
            alert("No media device found!");
        });
    };
    
    function stopCapture() {
        if(cameraStream != null) {
            cameraStream.getTracks().forEach(function(track) {
                track.stop();
            });
        }
        
        if(processingStream != null) {
            processingStream.getTracks().forEach(function(track) {
                track.stop();
            });
        }
        
        if(mediaRecorder != null) {
            if(mediaRecorder.state == "recording") {
                mediaRecorder.stop();
            }
        }
        
        if(processingPreviewIntervalId != null) {
            clearInterval(processingPreviewIntervalId);
            processingPreviewIntervalId = null;
        }
    };
    </script>
</body>
</html>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接