MediaRecorder - 如何在没有黑框的情况下播放视频块/ blob?

时间:2017-10-23 12:21:56

标签: video blob mediarecorder chunks mediastream

由于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());

感谢。

2 个答案:

答案 0 :(得分:1)

黑框与您使用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:每个片段一个,完整视频一个。 / p>

请注意,您可以根据需要pauseresume进行录制。

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>

作为fiddle,因为StackSnippets可能会阻止gUM请求。

答案 1 :(得分:0)

尝试使用recorder.pause和recorder.resume解决此问题。