最近flv.js的事好像有点火,又重新把mse这个东西提上来了。
MSE(media source extensions)是html5的新功能,大致的作用就是可以实现流媒体功能。
如果MSE配合webRTC再加上js的二进制处理,那么可以实现服务器发送视频给其中一个浏览器用户,这个浏览器用户再将视频流传输给其他用户的功能。算是web端在p2p功能上的一种探索吧
思路
server发送视频流的二进制数据给web,web通过webRTC的dataChannel
发送给其他web用户。再通过MSE将二进制数据转换成视频流播出。
MSE相关API解析
MediaSource.addSourceBuffer()
MediaSource.removeSourceBuffer()
MediaSource.endOfStream()
MediaSource.addEventListener()
example
完整的代码见https://github.com/yuyugenius/js_video_p2p_demo
web端使用nodejs,启动方式为 node index.js
由于本人并不是写前端和js的,只是在这方面做了点尝试,所以代码丑陋bug频出请见谅。
由于代码是好几个月前写的,描述不清请见谅
部分webRTC代码来自google
web端获取码流数据
web端获取码流数据可以通过很多方法,我这里是ajax.
/**
* FILE LOADING
* method:XMLHttpRequest
*/function get(filename, callback) {
var request = new XMLHttpRequest();
request.responseType = 'arraybuffer';
request.onreadystatechange = function () {
if (request.readyState == 4 && (request.status == 200 || request.status == 304)) {
callback(request.response);
}
}; var file = 'chunks/' + filename;
request.open('GET', file, true);
request.send();
};12345678910111213141516
添加MSE的事件响应
_mediaSource.addEventListener('sourceopen',sourceOpenCallback, false);
_mediaSource.addEventListener('webkitsourceopen',sourceOpenCallback, false);123
设置事件响应,当MSE里有buffer,就播放,这里用的格式是vp8+vorbis,同时开始一个startFileLoading(0)函数。
function sourceOpenCallback() {
console.log('mediaSource readyState: ' + this.readyState); // Create the source buffer where we are going to append the
// new chunks.
_sourceBuffer = _mediaSource.addSourceBuffer('video/webm; codecs="vp8,vorbis"'); //_sourceBuffer.addEventListener('updateend', loadNextBuffer, false);
_sourceBuffer.mode = 'sequence'; // Start
startFileLoading(0);
}1234567891011
_sourceBuffer.mode = 'sequence';
mode的值此时表示按队列顺序播放,如果为segments
则表示按时间戳播放,具体可以参考html标准的SourceBuffer.
startFileLoading(i)
的作用是从服务器上读取视频码流,这里用的是读取视频文件,我的测试代码里预设了一个文件列表。
/**
* start File LOADING
*/function startFileLoading(i) {
// Load the chunk
get(_files[i], function (result) {
console.log('XMLHttpRequest: loaded', _files[i]); // Cache the buffer
_loadedBuffers.push(result); //if connect with webRTC ,sendMediaData to anothoer user
if (_isConnection) { //peer.sendData(result);
for (var index = 0; index < _peerIndex; index++) {
peerlist[index].sendData(result);
}
} if (!_sourceBuffer.updating) { //setTimeout(loadNextBuffer,3000);
loadNextBuffer();
} if (i == 0) { // Start playback
if (video.paused) {
video.play();
}
}
i++; if (i == _files.length) {
i = 0;
} // Recursively load next chunk (if one exists)
if (i < _files.length) {
setTimeout(function () { startFileLoading(i); }, 9000); //startFileLoading(i);
}
});
}12345678910111213141516171819202122232425262728293031323334353637383940414243
如果当前的web端已经通过webRTC连接了其他web用户,那么就可以通过如果方式将从服务器读取的视频数据发送给其他用户,此时就相当于第二个以后的web用户获得的视频不是从服务器获取,而是从第一个用户那获取。
//if connect with webRTC ,sendMediaData to anothoer userif (_isConnection) { //peer.sendData(result);
for (var index = 0; index < _peerIndex; index++) {
peerlist[index].sendData(result);
}
}1234567
loadNextBuffer
就是读取下一段buffer并且添加进MSE,这样MSE就可以连续不断的播放视频,可以不用等视频完全加载完成才播放,也可以利用这个实现直播效果。
/**
* video stuff
* It appends puts the next cached buffer into the source buffer.
*/function loadNextBuffer() {
if (_loadedBuffers.length) {
console.log('SourceBuffer: appending', _itemsAppendedToSourceBuffer); // append the next one into the source buffer.
_sourceBuffer.appendBuffer(_loadedBuffers.shift());
_itemsAppendedToSourceBuffer++;
} /*
if (_itemsAppendedToSourceBuffer >= _files.length && !_sourceBuffer.updating) {
// else close the stream
_mediaSource.endOfStream();
}
*/}12345678910111213141516171819
webRTC部分
js/peer.js文件中就是关于webRTC实现的相关操作,有关webRTC部分的实现下篇博客再完善啦