Javascript 视频&x27;卡住';使用媒体源扩展API时

Javascript 视频&x27;卡住';使用媒体源扩展API时,javascript,html,video-streaming,html5-video,media-source,Javascript,Html,Video Streaming,Html5 Video,Media Source,我很少有机会使用媒体源API实现自己的实现 我只是想看看一个工作示例是否可以在本地正常工作,所以我复制并粘贴了示例中的源代码: 资料来源: 查看来源: 我没有“test.webm”视频,因此我可以使用自己的.webm视频文件。 我使用的测试文件是.webm视频文件14.6m 结果是,它的工作原理并不完全相同。 检查控制台,我可以看到有一些错误,所以我添加了一个队列,在媒体源的sourceBuffer更新时收集视频块 这有助于修复错误&我可以看到视频完全加载到播放器上,但问题是视频从未开始播放。

我很少有机会使用媒体源API实现自己的实现

我只是想看看一个工作示例是否可以在本地正常工作,所以我复制并粘贴了示例中的源代码:

资料来源: 查看来源:

我没有“test.webm”视频,因此我可以使用自己的.webm视频文件。 我使用的测试文件是.webm视频文件14.6m

结果是,它的工作原理并不完全相同。 检查控制台,我可以看到有一些错误,所以我添加了一个队列,在媒体源的sourceBuffer更新时收集视频块

这有助于修复错误&我可以看到视频完全加载到播放器上,但问题是视频从未开始播放。它只是一个显示视频时间长度的黑屏

如果我手动将它移动到1秒的起始点,它将一直播放到结束。我假设这意味着实现工作正常。检查视频的video.paused bool(当它有一个黑屏时)也会返回为false。不确定这是否只是html视频的一个问题

下面是我对示例脚本的更新:

<script>
var FILE = 'test.webm';
// var FILE = 'perigny.mp4';
var NUM_CHUNKS = 10;
var video = document.querySelector('video');
finished = false;

window.MediaSource = window.MediaSource || window.WebKitMediaSource;
if (!!!window.MediaSource) {
  alert('MediaSource API is not available');
}

var mediaSource = new MediaSource();

video.src = window.URL.createObjectURL(mediaSource);

function callback(e) {
  console.log("video.paused: ", video.paused);

  var sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');
  // sourceBuffer = mediaSource.addSourceBuffer('video/mp4;codecs="avc1.4d001e"');

  queue = [];

  sourceBuffer.addEventListener('updatestart', 
    function(e) { console.error('updatestart: ' + mediaSource.readyState);});
  sourceBuffer.addEventListener('update', 
    function(e) { 
      console.log('update: ' + mediaSource.readyState);
    });
  sourceBuffer.addEventListener('updateend', function() { // Note: Have tried 'updateend'
    console.log('updateend: ' + mediaSource.readyState);
      if (queue.length > 0 && !sourceBuffer.updating) {
        console.error("queue.shift");
      // if (queue.length) {
        sourceBuffer.appendBuffer(queue.shift());
      }
      if (finished && !sourceBuffer.updating) {
        console.log("finished");
        mediaSource.endOfStream();
        console.log("MediaSource", mediaSource);
        console.log("video.paused: ", video.paused);

        video.pause();
        video.play();
      }
  }, false);

  logger.log('mediaSource readyState: ' + this.readyState);

  GET(FILE, function(uInt8Array) {
    var file = new Blob([uInt8Array], {type: 'video/webm'});
    var chunkSize = Math.ceil(file.size / NUM_CHUNKS);

    logger.log('num chunks:' + NUM_CHUNKS);
    logger.log('chunkSize:' + chunkSize + ', totalSize:' + file.size);

    // Slice the video into NUM_CHUNKS and append each to the media element.
    var i = 0;

    (function readChunk_(i) {
      var reader = new FileReader();

      // Reads aren't guaranteed to finish in the same order they're started in,
      // so we need to read + append the next chunk after the previous reader
      // is done (onload is fired).
      reader.onload = function(e) {
        console.log("i", i);
        if (sourceBuffer.updating || queue.length > 0) {
          console.log("addSourceBuffer is updating");
          queue.push(new Uint8Array(e.target.result));
        }
        else {
          console.log("sourceBuffer.appendBuffer();");
          sourceBuffer.appendBuffer(new Uint8Array(e.target.result));
        }

        logger.log('appending chunk:' + i);
        if (i == NUM_CHUNKS - 1) {
          console.log("End of stream");
          finished = true;
          // if (!sourceBuffer.updating)
          //   mediaSource.endOfStream();
        } else {
          if (video.paused) {
            video.play(); // Start playing after 1st chunk is appended.
          }
          readChunk_(++i);
        }
      };

      var startByte = chunkSize * i;
      var chunk = file.slice(startByte, startByte + chunkSize);

      reader.readAsArrayBuffer(chunk);
    })(i);  // Start the recursive call by self calling.
  });
}

mediaSource.addEventListener('sourceopen', callback, false);
mediaSource.addEventListener('webkitsourceopen', callback, false);

mediaSource.addEventListener('sourceended', function(e) {
  logger.log('mediaSource readyState: ' + this.readyState);
}, false);

function GET(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer';
  xhr.send();

  xhr.onload = function(e) {
    if (xhr.status != 200) {
      alert("Unexpected status code " + xhr.status + " for " + url);
      return false;
    }
    callback(new Uint8Array(xhr.response));
  };
}
</script>

var文件='test.webm';
//var文件='perigny.mp4';
var NUM_CHUNKS=10;
var video=document.querySelector('video');
完成=错误;
window.MediaSource=window.MediaSource | | window.WebKitMediaSource;
如果(!!!window.MediaSource){
警报(“MediaSource API不可用”);
}
var mediaSource=新的mediaSource();
video.src=window.URL.createObjectURL(mediaSource);
函数回调(e){
console.log(“video.paused:,video.paused”);
var sourceBuffer=mediaSource.addSourceBuffer('video/webm;codecs=“vorbis,vp8”);
//sourceBuffer=mediaSource.addSourceBuffer('video/mp4;codecs=“avc1.4d001e”);
队列=[];
sourceBuffer.addEventListener('updatestart',
函数(e){console.error('updatestart:'+mediaSource.readyState);});
sourceBuffer.addEventListener('update',
函数(e){
log('update:'+mediaSource.readyState);
});
sourceBuffer.addEventListener('updateend',function(){//注意:您尝试过'updateend'
log('updateend:'+mediaSource.readyState);
if(queue.length>0&&!sourceBuffer.updateing){
控制台错误(“queue.shift”);
//if(队列长度){
appendBuffer(queue.shift());
}
if(已完成&&!sourceBuffer.update){
控制台日志(“完成”);
mediaSource.endOfStream();
console.log(“MediaSource”,MediaSource);
console.log(“video.paused:,video.paused”);
video.pause();
video.play();
}
},假);
logger.log('mediaSource readyState:'+this.readyState);
获取(文件、函数(uInt8Array){
var file=newblob([uInt8Array],{type:'video/webm'});
var chunkSize=Math.ceil(file.size/NUM\u CHUNKS);
log('num chunks:'+num_chunks);
logger.log('chunkSize:'+chunkSize+',totalSize:'+file.size);
//将视频切成NUM_块,并将每个块附加到媒体元素。
var i=0;
(函数readChunk_Ui){
var reader=new FileReader();
//读取不能保证以与开始时相同的顺序完成,
//因此,我们需要在前一个读取器之后读取并附加下一个块
//完成(启动onload)。
reader.onload=函数(e){
控制台日志(“i”,i);
if(sourceBuffer.updateing | | queue.length>0){
log(“addSourceBuffer正在更新”);
push(新的Uint8Array(e.target.result));
}
否则{
log(“sourceBuffer.appendBuffer();”);
appendBuffer(新的Uint8Array(e.target.result));
}
logger.log('追加块:'+i);
if(i==NUM_CHUNKS-1){
控制台日志(“流结束”);
完成=正确;
//如果(!sourceBuffer.update)
//mediaSource.endOfStream();
}否则{
如果(视频暂停){
video.play();//附加第一个块后开始播放。
}
readChunk_(++i);
}
};
var startByte=chunkSize*i;
var chunk=file.slice(startByte,startByte+chunkSize);
reader.readAsArrayBuffer(块);
})(i) ;//通过自调用启动递归调用。
});
}
mediaSource.addEventListener('sourceopen',回调,false);
mediaSource.addEventListener('webkitsourceopen',回调,false);
mediaSource.addEventListener('sourceended',函数(e){
logger.log('mediaSource readyState:'+this.readyState);
},假);
函数GET(url,回调){
var xhr=new XMLHttpRequest();
xhr.open('GET',url,true);
xhr.responseType='arraybuffer';
xhr.send();
xhr.onload=函数(e){
如果(xhr.status!=200){
警报(“意外状态代码”+xhr.status+”表示“+url”);
返回false;
}
回调(新的Uint8Array(xhr.response));
};
}

编辑:为了帮助可能遇到此问题的其他人,让我添加解决方案/结果

事实证明,这是我尝试使用的原始.webm视频文件的关键帧问题。似乎MSE API非常挑剔,即使它是所需的确切文件格式。 我最终从以下网站下载了.webm视频:


我计划现在继续使用这些其他文件格式。

不要从HTML页面获取代码,从Github下载整个项目:

确保将其放置在可以调用localhost/dash的位置

您必须确保“bunny_2s_700kbit”目录中包含媒体文件,您必须从此处下载:

然后确保在bigbuckbunny\u mp.mpd中有正确的路径:

<BaseURL>http://localhost/dash/</BaseURL>

检查这个几乎相同的问题的答案(因为你的代码可以处理较小的文件,比如:谢谢,我会研究这个。我看到了这个pos
<Initialization sourceURL="bunny_2s_700kbit/bunny_480_700kbit_dash.mp4"/>
var dashPlayer = new DASHPlayer(video,"bigbuckbunny_mp.mpd");