最近flv.js的事好像有點火,又重新把mse這個東西提上來了。
MSE(media source extensions)是html5的新功能,大致的作用就是可以實現流媒體功能。
如果MSE配合webRTC再加上js的二進位處理,那麼可以實現伺服器發送視頻給其中一個瀏覽器使用者,這個瀏覽器使用者再將視頻流傳輸給其他使用者的功能。算是web端在p2p功能上的一種探索吧 思路
server發送視頻流的位元據給web,web通過webRTC的dataChannel發送給其他web使用者。再通過MSE將位元據轉換成視頻流播出。 MSE相關API解析 MediaSource.addSourceBuffer()
添加資料到buff 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();};
添加MSE的事件響應
_mediaSource.addEventListener('sourceopen',sourceOpenCallback, false);_mediaSource.addEventListener('webkitsourceopen',sourceOpenCallback, false);
設定事件響應,當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);}
_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); } });}
如果當前的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); }}
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(); } */}
webRTC部分
js/peer.js檔案中就是關於webRTC實現的相關操作,有關webRTC部分的實現下篇部落格再完善啦