1

多亏了 MediaRecorder,我正在录制我的网络摄像头的短视频大约 1 秒。录制视频后,我将其推入桌子。最后,当我有一些视频被推到桌子上时,我会尝试一个接一个地阅读每个视频(就像只有一个大视频)。但是我在每个视频之间都有某种黑框。就好像视频之间的过渡并不完美,阅读时断断续续。有人可以告诉我它发生的原因吗?

这是我用来录制小视频的部分代码:

                navigator.mediaDevices.getUserMedia().then(function(media_stream) {
                    var recorder = new MediaRecorder(media_stream);

                    recorder.start();

                    recorder.onstart = function(event) {
                        setTimeout(function(){ recorder.stop(); }, 1000);
                    };

                    recorder.ondataavailable = event => {
                        tableau_rondelle.push(event.data);
                    };

                    recorder.onstop = function(event) {
                        recorder.start();
                    };
                })
                .catch(function(error) {});

这是我用来阅读大视频的部分代码:

                            document.getElementById("video_output").onended = function(event) {
                                document.getElementById("video_output").src = URL.createObjectURL(tableau_rondelle.shift());
                            };

                            document.getElementById("video_output").src = URL.createObjectURL(tableau_rondelle.shift());

谢谢。

4

2 回答 2

3

黑框与您使用 MediaRecorder 制作视频的事实无关。这只是由于事件和加载视频
的整个过程的不同步引起的:onend

// We will first load all the video's data in order to avoid HTTP request timings
console.log('generating all blobURIs');
const base_url = "https://dl.dropboxusercontent.com/s/";
const urls = [
  'ihleenn2498tg0a/BigChunksBunny0.mp4',
  'hyeredbcn60feei/BigChunksBunny1.mp4',
  'sjd141zuyc6giaa/BigChunksBunny2.mp4',
  'i9upd28ege6di7s/BigChunksBunny3.mp4',
  'nf43s8jnzk0rmkt/BigChunksBunny4.mp4',
  'mewgtcucsq3lrgq/BigChunksBunny5.mp4',
  '4qan8epsratlkxo/BigChunksBunny6.mp4',
  '28a6i3646ruh5dt/BigChunksBunny7.mp4',
  'prwo7uyqbjbfrc5/BigChunksBunny8.mp4',
  'n2ak9x3zuww8yf4/BigChunksBunny9.mp4',
  '12ic7m1cgmjrygc/BigChunksBunny10.mp4'
].map(url => fetch(base_url + url)
  .then(response => response.blob())
  .then(blob => URL.createObjectURL(blob))
);
Promise.all(urls)
  .then(urls => {
    console.log('generated all blobURIs');
    var current = -1;

    var timings = {
      timeupdate: null,
      end: null,
      play: null
    };
    vid.onended = playNext;
    vid.ontimeupdate = ontimeupdate;
    vid.onplaying = logTimings;
    playNext();

    function playNext() {
      timings.end = performance.now(); // save the current time

      if (++current >= urls.length) return;
      vid.src = urls[current];
      vid.play();
    }

    function ontimeupdate() {
      // timeupdate fires just before onend
      if (this.currentTime >= vid.duration) {
        timings.timeupdate = performance.now();
      }
    }

    function logTimings() {
      if (!timings.timeupdate) return;
      timings.play = performance.now();
      console.log('took ' + (timings.end - timings.timeupdate) + 'ms to fire onend event');
      console.log('took ' + (timings.play - timings.end) + 'ms to start the video');
      console.log('black frame lasted ' + (timings.play - timings.timeupdate) + 'ms');
    }
  });
<video id="vid" autoplay></video>

那么如何规避呢? 好吧,这并不容易,因为我们无法确定开始播放视频需要多长时间。

可以肯定的是,将所有视频预加载到他们自己的视频播放器中会对您有所帮助。
可能有帮助的另一件事是在显示前一个视频的最后一帧之前触发下一个视频的播放,因此,在timeupdate事件中。

console.log('preloading all videos');
const base_url = "https://dl.dropboxusercontent.com/s/";
const vids = [
  'ihleenn2498tg0a/BigChunksBunny0.mp4',
  'hyeredbcn60feei/BigChunksBunny1.mp4',
  'sjd141zuyc6giaa/BigChunksBunny2.mp4',
  'i9upd28ege6di7s/BigChunksBunny3.mp4',
  'nf43s8jnzk0rmkt/BigChunksBunny4.mp4',
  'mewgtcucsq3lrgq/BigChunksBunny5.mp4',
  '4qan8epsratlkxo/BigChunksBunny6.mp4',
  '28a6i3646ruh5dt/BigChunksBunny7.mp4',
  'prwo7uyqbjbfrc5/BigChunksBunny8.mp4',
  'n2ak9x3zuww8yf4/BigChunksBunny9.mp4',
  '12ic7m1cgmjrygc/BigChunksBunny10.mp4'
].map(url => fetch(base_url + url)
  .then(response => response.blob())
  .then(blob => URL.createObjectURL(blob))
  // convert all these urls directly to video players, preloaded
  .then(blobURI => {
    const vid = document.createElement('video');
    vid.src = blobURI;
    return vid.play()
      .then(() => {
        vid.pause();
        vid.currentTime = 0;
        return vid;
      });
  })
);

Promise.all(vids)
  .then(vids => {
    console.log('preloaded all videos');
    let current = -1;
    let vid = vids[0];
    vids.forEach(vid => {
      vid.onended = onend;
      vid.ontimeupdate = ontimeupdate;
    });
    document.body.appendChild(vid);
    playNext();

    function playNext() {
      if (++current >= vids.length) return;
      let next = vids[current];
      vid.replaceWith(next);
      vid = next;
      vid.play();
    }

    function onend() {
      if (!chck.checked) {
        playNext();
      }
    }

    function ontimeupdate() {
      // timeupdate fires just before onend
      if (chck.checked) {
        if (this._ended) return;
        let buffer_time = 400 / 1000; // this is completely arbitrary...
        if (this.currentTime >= this.duration - buffer_time) {
          this._ended = true;
          playNext();
        }
      }
    }
  });
<label>update in timeupdate<input type="checkbox" id="chck"></label><br>

但是,由于您自己的问题是使用 MediaRecorder API 录制的视频,并且您想要播放整个序列,因此只需并行使用多个 MediaRecorder:一个用于每个片段,一个用于完整视频。

请注意,您可以根据需要暂停恢复录制。

navigator.mediaDevices.getUserMedia({video: true}).then(stream => {
  window.stream = stream;
  vid.srcObject = stream;
  vid.play();
  recordSegments(stream);
  recordFull(stream);
  });
const segments = [];
function recordSegments(stream){
  let int = setInterval(()=>{
    if(segments.length >= 10){
      clearInterval(int);
      stream.getTracks().forEach(t=>t.stop());
      return;
      }
    const chunks = [];
    const rec = new MediaRecorder(stream);
    rec.ondataavailable = e => chunks.push(e.data);
    rec.onstop = e => segments.push(new Blob(chunks));
    rec.start();
    setTimeout(()=>rec.stop(), 1000);
  }, 1000);
}

function recordFull(stream){
  const chunks = [];
  const rec = new MediaRecorder(stream);
  rec.ondataavailable = e => chunks.push(e.data);
  rec.onstop = e => exportAll(new Blob(chunks));
  rec.start();
  setTimeout(()=>rec.stop(), 10000);
  }

function exportAll(full){
  vid.remove();
  segments.unshift(full);
  segments.forEach(blob=>{
    const vid = document.createElement('video');
    vid.src = URL.createObjectURL(blob);
    vid.controls = true;
    document.body.appendChild(vid);
  });
}
<video id="vid"></video>

并且因为 StackSnippets 可能会阻止 gUM 请求,所以作为一个小提琴。

于 2017-10-25T02:39:59.250 回答
0

尝试使用 recorder.pause 和 recorder.resume 来解决这个问题。

于 2020-05-30T07:40:25.247 回答