当视频较大时会产生相当长时间的延迟(具体延迟时间由网络状况和视频文件大小决定);因此开始尝试视频的切片传输。基于没有过多的音视频编码基础,所以尝试了对webm格式视频的强制型切片传输。之所以选择webm格式的视频,一是webm格式被html5和目前大多数浏览器所支持,二是webm格式视频相对编码方式比较单一,所使用的codec比较单一,所以在添加sourcebuffer时直接使用addSourceBuffer('video/webm; codecs=

当视频较大时会产生相当长时间的延迟(具体延迟时间由网络状况和视频文件大小决定);因此开始尝试视频的切片传输。

基于没有过多的音视频编码基础,所以尝试了对webm格式视频的强制型切片传输。

之所以选择webm格式的视频,一是webm格式被html5和目前大多数浏览器所支持,二是webm格式视频相对编码方式比较单一,所使用的codec比较单一,所以在添加sourcebuffer时直接使用addSourceBuffer('video/webm; codecs="vorbis,vp8"')即可;

其基本思想比较简单:

对于视频发送端,用fileReader读取文件后,使用slice()函数将文件切片,然后将每个segment逐一传输到对等接收端;

对于视频接收端,将接收到得每一个文件片append到<video>标签对应的sourcebuffer上

但是具体实现时使用了一下几个技巧来解决一些问题:

(1)在发送端开始发送视频数据之前,需要先向对等端发送初始化消息通知(video command: start)对等端准备接受视频数据

对等端接收到初始化消息后,开始初始化工作:

if(data['type']=="video_com"){  
  if(data['content']=="start"){  
      var oSourceBuffer, oMediaSource = new MediaSource();  
      var url = window.URL.createObjectURL(oMediaSource);  
      video.src = url;  
      oMediaSource.addEventListener(prefix +'sourceopen', function () {  
          oSourceBuffer = oMediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');  
          //oSourceBuffer = oMediaSource.addSourceBuffer('video/mp4; codecs="avc1.4d401f,mp4a.40.2"');  
          mediaSource = oMediaSource;  
          sourceBuffer = oSourceBuffer;  
          console.debug('MediaSource readyState: <', this.readyState, '>');  
      }, false);  
      //video.src = window.URL.createObjectURL(oMediaSource);  
      seg_num=0;  
  }  
  if(data['content']== "end"){  
      mediaSource.endOfStream();  
  }  
}

(2)对等端接收到分片的视频数据之后会将数据append到sourcebuffer上

if(data['type'] == "video_seg"){  
      console.debug("get the " + seg_num + " segment");  
      var uint8array = new window.Uint8Array(data['content']);  
      sourceBuffer.appendBuffer(uint8array);  
      if(seg_num==20){  
          video.play();  
      }  
      seg_num++;  
}


          此处需注意;append()函数时需要一定的执行时间的,如果在很短的时间内接收到两片及以上的数据,就会引发两次append()函数,在前次append()函数未执行结束的情况下再次调用append()函数会产生错误从而导致该sourcebuffer被移除从而出现错误

         对于这个问题的解决方法有两种:

一是在接收端建立一个List或者Queue来按序存放接收到得视频数据片, 然后按顺序append到sourcebuffer上,此时可以通过检测sourcebuffer的appendingstate来检测当然的append函数是否执行完毕,当前一次执行完毕后再新append一个数据片

二是在发送端设置一定的发送间隔,为append()函数留出一定的执行时间,当然这个时间间隔的设置要合理。

实现代码为:

function inner_streamer() {  
  reader = new window.FileReader();  
  reader.onload = function (e) {  
      //self.push(new window.Uint8Array(e.target.result));  
      var send_data = new window.Uint8Array(e.target.result);  
      myconn.send({type:"video_seg",content:send_data});  
      startIndex += plus;  
      if (startIndex <= size)  
      {  
          setTimeout('inner_streamer()',100);  
      }  
      else {  
          //self.push({end: true});  
          myconn.send({type:"video_com",content:"end"});  
      }  
  };  
  reader.readAsArrayBuffer(send_blob.slice(startIndex, startIndex + plus));  
}


上一篇:H5流式播放(FMP4转封装与mediaSource)

下一篇:适用window.URL.createObjectURL(Object obj)时出现的Not allowed to load local resource错误

评论列表
发表评论
称呼
邮箱
网址
验证码(*)
热评文章
相关阅读