如何使用 HTML5 WebRTC 录制和保存视频

Was*_*siF 5 html javascript webrtc angular angular6

首先运行代码片段,然后阅读说明...它将为您提供结构

我想在第二个中录制、播放和保存视频video element。我面临的问题是:流正在第一个运行video-element但无法录制和保存视频

.video {
    border: 1px solid gray;
    box-shadow: 3px 4px lightgray;
}
Run Code Online (Sandbox Code Playgroud)
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>

<div style="text-align:center">
    <h1>Welcome to WebRTC</h1>
    <video class="video" #video autoplay controls></video>
    <video class="video" style="width:360;" autoplay controls #recordedVideo></video>
    <br>
    <button class="btn btn-warning" (click)="startRecording()">Start</button>
    <button class="btn btn-warning" (click)="stopRecording()">Stop</button>
    <button class="btn btn-warning" (click)="playRecording()">Play</button>
</div>
Run Code Online (Sandbox Code Playgroud)

------------------------ 修改并解决了问题

我在这里所做的,在Luis Estevez代码中,我在方法中声明了该事件startRecording,因为当我尝试将流块推送到 blob 数组中时,它响应了一个错误:推送方法不存在,即使我在之后创建了一个对象数组我声明了一个数组。

startRecording(stream) {
    let options = { mimeType: 'video/webm' }
    this.recordedBlobs = []
    console.log(this.recordedBlobs)
    try {
      this.mediaRecorder = new MediaRecorder(stream, options)
    } catch (e0) {
      console.log('Try different mimeType')
    }

    console.log('Created MediaRecorder', this.mediaRecorder, 'with options', options)
    // this.mediaRecorder.onstop = this.handleStop
    this.mediaRecorder.onstop = (event) => {
      console.log('Recorder stopped: ', event)
      const videoBuffer = new Blob(this.recordedBlobs, { type: 'video/webm' })
      this.downloadUrl = window.URL.createObjectURL(videoBuffer) // you can download with <a> tag

      this.recordVideoElement = this.recordVideoElementRef.nativeElement
      this.recordVideoElement.src = this.downloadUrl
    }
    // this.mediaRecorder.ondataavailable = this.handleDataAvailable
    this.mediaRecorder.ondataavailable = (event) => {
      if (event.data && event.data.size > 0) {
        this.recordedBlobs.push(event.data)
      }
    }
    this.mediaRecorder.start(100) // collect 100ms of data
    console.log('MediaRecorder started', this.mediaRecorder)
  }
Run Code Online (Sandbox Code Playgroud) 谢谢路易斯·埃斯特维兹:)

Lui*_*vez 4

您并没有“真正”记录流,您只是复制了流对象,而不是来自流的事件数据。

使用MediaRecorder流并将其作为构造函数参数传递。从事件处理程序 ondataavailable 中获取视频blob 。将记录的 Blob 数组连接到新的 Blob。从那里你可以使用获取网址createObbjectURL(blob);

以下片段是伪代码:

** typescript 无法识别“MediaRecorder”,因此您必须找到一种方法将任何类型添加到 MediaRecorder


mediaRecorder: any;
recordedBlobs: Blob[];
downloadUrl: string;

handleDataAvailable(event) {
    if (event.data && event.data.size > 0) {
      this.recordedBlobs.push(event.data);
    }
}

handleStop(event) {
    console.log('Recorder stopped: ', event);
    const videoBuffer = new Blob(this.recordedBlobs, {type: 'video/webm'});
    this.downloadUrl = window.URL.createObjectURL(videoBuffer); // you can download with <a> tag
    this.recordVideoElement.src = this.downloadUrl;
}

startRecording(stream) {
    let options = {mimeType: 'video/webm'};
    this.recordedBlobs = [];
    try {
        this.mediaRecorder = new MediaRecorder(stream, options);
    } catch (e0) {
        console.log('Try different mimeType');
    }
    console.log('Created MediaRecorder', this.mediaRecorder, 'with options', options);
    this.mediaRecorder.onstop = this.handleStop;
    this.mediaRecorder.ondataavailable = this.handleDataAvailable;
    this.mediaRecorder.start(100); // collect 100ms of data
    console.log('MediaRecorder started', this.mediaRecorder);
}

stopRecording() {
  this.mediaRecorder.stop();
  console.log('Recorded Blobs: ', this.recordedBlobs);
  this.recordVideoElement.controls = true;
}

playRecording() {
  if (!this.recordedBlobs.length) {
      console.log('cannot play.');
      return;
  }
  this.recordVideoElement.play();
}

async ngOnInit() {
  navigator.mediaDevices.getUserMedia({ video: { width: 360 } }).then(stream => {
    this.videoElement.srcObject = stream
    this.startRecording(stream);
  })
}
Run Code Online (Sandbox Code Playgroud)