WebSocket播放视频是结合MediaSource的
总结:通过WebSocket获取视频流,提供给MediaSource,MediaSource结合video标签,播放视频。
这一套完全就是基于浏览器支持MediaSourceExtension(MSE)的,而我最终的目的是在unity3d里面播放视频,加入uinty3d不支持MediaSource和video标签,怎么折腾都没用。可能最后还会变成在uinty里面调要能够网页上的video来播放视频,调整一下窗口的大小。
在AppStore里面找了一下,没找到合适的资料,有个Embedded Browser说是完全支持HTML5包括视频,但是它的平台是windows,ios,linux,其实就是一个浏览器嵌入到unity程序中,没有webgl,而webgl其实就在浏览器里面了。这个在淘宝上有,3.0还买到35或者80。
接下来三个方向 调用浏览器 3.解码播放
参考:MediaSource
1.理解并修改
将文件和github上面的以及比较,将混淆后的变量名和方法名还原回去
function H5sPlayerWS(conf) {
var s;
, = [], this._mediaSource, , , , , = 0, = 0,
= 0, = false, = false, = false, , this._conf = conf, ("Websocket Conf:",
conf), this._videoId = , this._pbconf = , this._token = , void 0 === this._videoId ? (this._videoElemet = ,
(, "use dom directly")) : (this._videoElemet = (this._videoId), (,
"use videoid")), = this._videoElemet, null != this._pbconf && "false" == this._pbconf.showposter || (s = this._conf.protocol + "//" + this._conf.host + this._conf.rootpath + "api/v1/GetImage?token=" + this._token + "&session=" + this._conf.session,
(, "connect src"), this._videoElemet.setAttribute("poster", s))
}
function H5sPlayerRTC(conf) {
var s;
, , , = 0, = 0, = 0, = false, = false, this._conf = conf,
this._videoId = , this._pbconf = , this._token = , void 0 === this._videoId ? (this._videoElemet = ,
(, "use dom directly")) : (this._videoElemet = (this._videoId), (,
"use videoid")), = this._videoElemet, = null, = {
optional: [{
DtlsSrtpKeyAgreement: true
}]
},
= {
mandatory: {
offerToReceiveAudio: true, offerToReceiveVideo: true
}
},
= {
M: []
},
= [], null != this._pbconf && "false" == this._pbconf.showposter || (s = this._conf.protocol + "//" + this._conf.host + this._conf.rootpath + "api/v1/GetImage?token=" + this._token + "&session=" + this._conf.session,
("connect src", ), this._videoElemet.setAttribute("poster", s))
}
function createRTCSessionDescription(t) {
return ("createRTCSessionDescription "), new RTCSessionDescription(t)
}
function H5sPlayerHls(t) {
, , this._conf = t, this._videoId = , this._token = , , = , void 0 === this._videoId ? (this._videoElemet = ,
(, "use dom directly")) : (this._videoElemet = (this._videoId), (,
"use videoid")), = this._videoElemet, = "application/x-mpegURL", = 0, = 0;
var s = this._conf.protocol + "//" + + "/api/v1/GetImage?token=" + this._token + "&session=" + this._conf.session;
this._videoElemet.setAttribute("poster", s)
}
function H5sPlayerAudio(t) {
= [], , = false, = false, this._conf = t, ("Aduio Player Conf:",
t), this._token = , this._ = new AudioContext
}
function H5sPlayerAudBack(t) {
= [], , = false, = false, this._conf = t, = 0, = 48e3, = false,
("Aduio Back Conf:", t), this._token = , this._ = new AudioContext, ("sampleRate",
this._.sampleRate), ()
}
function float32ToInt16(t) {
for (var s = , e = new Int16Array(s); s--;) {
e[s] = 32767 * (1, t[s]);
}
return e
}
= function () {
('reconnectFunction'+new Date());
true === && (("Reconnect..."), (this._token), = false)
},
= function (url) {
('>> ');
var ws;
try {
"http:" == this._conf.protocol && (ws = "undefined" != typeof MozWebSocket ? new MozWebSocket("ws://" + this._conf.host + url) : new WebSocket("ws://" + this._conf.host + url)),
"https:" == this._conf.protocol && ((this._conf.host), ws = "undefined" != typeof MozWebSocket ? new MozWebSocket("wss://" + this._conf.host + url) : new WebSocket("wss://" + this._conf.host + url)),
(this._conf.host)
}
catch (err) {
return void alert("error")
}
return ws;
},
= function () {
//('F');
//();
if (null !== && void 0 !== ) {
if (0 !== && !) {
try {
var first = (), buff = new Uint8Array(first);
(buff)
}
catch (err) {
(err)
}
}
}
else {
(, "is null or undefined");
}
//();
},
= function () {
//('X keepaliveTimer');
//(this);
//();
try {
var t = {
cmd: "H5_KEEPALIVE"
};
((t))
}
catch (err) {
(err)
}
},
//获取websocket数据
= function (msg) {
//('>> ');
//();
//var ttt=(null, new Uint8Array());
//(ttt);
return , ArrayBuffer, "string" == typeof ? (("string"), void (null != this._pbconf && null != this._pbconf.callback && this._pbconf.callback(,
this._pbconf.userdata))) : true !== ? false === ? ( = (null, new Uint8Array()),
(this), void ( = true)) : ((), void ()) : void 0;
},
= function (player) {
('initMediaSource');
try {
= || , || ("MediaSource API is not available");
var codec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
"MediaSource" in window && (codec) ? ("MIME type or codec: ",
codec) : ("Unsupported MIME type or codec: ", codec), player._mediaSource = new , = true,
(player._videoId);
= (player._mediaSource), (), player._mediaSource.addEventListener("sourceopen",
(player), false)
}
catch (err) {
(err)
}
},
= function () {
("Add SourceBuffer"), = this._mediaSource.addSourceBuffer(), this._mediaSource.duration = 1 / 0,
this._mediaSource.removeEventListener("sourceopen", , false), ("updateend",
(this), false);
},
= function (token) {
('>> ');
= true;
var url = "api/v1/h5swsapi", prof = "main";
if (void 0 === this._conf.streamprofile || (prof = this._conf.streamprofile), void 0 === this._pbconf) {
url = this._conf.rootpath + url + "?token=" + token + "&profile=" + prof + "&session=" + this._conf.session;
}
else {
var i = "false", o = "fake";
void 0 === this._pbconf.serverpb || (i = this._pbconf.serverpb), void 0 === this._pbconf.filename || (o = this._pbconf.filename),
url = this._conf.rootpath + url + "?token=" + token + "&playback=true&profile=" + prof + "&serverpb=" + i + "&begintime=" + encodeURIComponent(this._pbconf.begintime) + "&endtime=" + encodeURIComponent(this._pbconf.endtime) + "&filename=" + o + "&session=" + this._conf.session
}
this._conf.session, (url), = (url), ("setupWebSocket", ), = "arraybuffer",
(._player = this). = (this), = function () {
("", this._player), this._player.checkSourceBufferTimerId = setInterval(this._player.(this._player), 1e4),
this._player.keepAliveTimerId = setInterval(this._player.(this._player), 1e3), null != this._player._pbconf && "true" === this._player._pbconf.autoplay && this._player.start();
},
= function () {
("", this._player), true === this._player.v ? (" disconnect") : this._player.S = true,
this._player.cleanupSourceBuffer(this._player), this._player.cleanupWebSocket(this._player), this._player.strCodec = "", this._player.p = false;
}
},
= function (player) {
("Cleanup Source Buffer", player);
try {
("updateend", , false), (), || /Edge/.test() ? ("IE or EDGE!") : player._mediaSource.removeSourceBuffer(),
= null, player._mediaSource = null, = []
}
catch (err) {
(err)
}
},
= function (player) {
("CleanupWebSocket", player);
//(player);
clearInterval(), clearInterval(), = 0, = 0, = 0;
},
= function () {
if (void 0 === this._pbconf) {
true === && (("CheckSourceBuffer has been disconnect", this), clearInterval(),
clearInterval(), clearInterval());
try {
if (("CheckSourceBuffer", this), <= 0) {
if (++ , 8 < ) {
return ("CheckSourceBuffer Close 1"), void ();
}
}
else {
= 0;
(0);
var t = (0), s = t - ;
if (5 < s || s < 0) {
return ("CheckSourceBuffer Close 2", s), void ();
}
if (t == ) {
if (++ , 3 < ) {
return ("CheckSourceBuffer Close 3"), void ();
}
}
else {
= 0;
}
= t;
}
}
catch (err) {
(err)
}
}
},
= function () {
(this._token);
= setInterval((this), 3e3);//没3s重连一次。
},
= function () {
("disconnect", this), = true, clearInterval(), null != && ((),
= null), ("disconnect", this);
},
= function () {
try {
var t = {
cmd: "H5_START"
};
((t))
}
catch (err) {
(err)
}
},
= function () {
try {
var t = {
cmd: "H5_PAUSE"
};
((t))
}
catch (err) {
(err)
}
},
= function () {
try {
var t = {
cmd: "H5_RESUME"
};
((t))
}
catch (err) {
(err)
}
},
= function (t) {
try {
var s = {
cmd: "H5_SEEK"
};
= t, ((s))
}
catch (err) {
(err)
}
},
= function (t) {
try {
var s = {
cmd: "H5_SPEED"
};
= t, ((s))
}
catch (err) {
(err)
}
},
= function () {
true === && (("Reconnect..."), (this._token), = false)
},
= function (t) {
var s;
("H5SWebSocketClient");
try {
"http:" == this._conf.protocol && (s = "undefined" != typeof MozWebSocket ? new MozWebSocket("ws://" + this._conf.host + t) : new WebSocket("ws://" + this._conf.host + t)),
"https:" == this._conf.protocol && ((this._conf.host), s = "undefined" != typeof MozWebSocket ? new MozWebSocket("wss://" + this._conf.host + t) : new WebSocket("wss://" + this._conf.host + t)),
(this._conf.host)
}
catch (err) {
return void alert("error")
}
return s;
},
= function () {
try {
var t = {
type: "keepalive"
};
((t))
}
catch (err) {
(err)
}
},
= function (t) {
if () {
var s;
("onIceCandidate currentice", ), s = , ("onIceCandidate currentice",
s, (s));
var e = ((s));
= "remoteice", ("onIceCandidate currentice new", e, (e)), ((e))
}
else {
("End of candidates.");
}
},
= function (t) {
var s;
("Remote track added:" + (t)), s = ? [0] : ;
var e = this._videoElemet;
= (s), ();
},
= function () {
("createPeerConnection config: " + () + " option:" + ());
var s = new RTCPeerConnection(, ), e = this;
return = function (t) {
(e, t)
},
void 0 !== ? = function (t) {
(e, t)
}
: = function (t) {
(e, t)
},
= function (t) {
("oniceconnectionstatechange state: " + )
},
("Created RTCPeerConnnection with config: " + () + "option:" + ()),
s
},
= function (t) {
("ProcessRTCOffer", t);
try {
= (), = 0;
var s = this;
(createRTCSessionDescription(t)), ().then(function (t) {
("Create answer:" + (t)), (t, function () {
("ProcessRTCOffer createAnswer", t), ((t))
},
function () { })
},
function (t) {
alert("Create awnser error:" + (t))
})
}
catch (err) {
(), alert("connect error: " + err)
}
},
= function (t) {
("ProcessRemoteIce", t);
try {
var s = new RTCIceCandidate({
sdpMLineIndex: , candidate:
});
("ProcessRemoteIce", s), ("Adding ICE candidate :" + (s)),
(s, function () {
("addIceCandidate OK")
},
function (t) {
("addIceCandidate error:" + (t))
})
}
catch (err) {
alert("connect ProcessRemoteIce error: " + err)
}
},
= function (msg) {
, ArrayBuffer, , ("RTC received ", );
var s = ();
return ("Get Message type ", ), "offer" === ? (("Process Message type ",
), void (s)) : "remoteice" === ? (("Process Message type ", ),
void (s)) : void (null != this._pbconf && null != this._pbconf.callback && this._pbconf.callback(, this._pbconf.userdata))
},
= function (t) {
= true;
var s = "api/v1/h5srtcapi", e = "main";
if (void 0 === this._conf.streamprofile || (e = this._conf.streamprofile), void 0 === this._pbconf) {
s = this._conf.rootpath + s + "?token=" + t + "&profile=" + e + "&session=" + this._conf.session;
}
else {
var i = "false", o = "fake";
void 0 === this._pbconf.serverpb || (i = this._pbconf.serverpb), void 0 === this._pbconf.filename || (o = this._pbconf.filename),
s = this._conf.rootpath + s + "?token=" + t + "&playback=true&profile=" + e + "&serverpb=" + i + "&begintime=" + encodeURIComponent(this._pbconf.begintime) + "&endtime=" + encodeURIComponent(this._pbconf.endtime) + "&filename=" + o + "&session=" + this._conf.session
}
(s), = (s), ("setupWebSocket", ), = "arraybuffer",
(._player = this). = (this), = function () {
("", this._player);
var t = {
type: "open"
};
this._player.((t)), this._player.keepAliveTimerId = setInterval(this._player.(this._player), 1e3), null != this._player._pbconf && "true" === this._player._pbconf.autoplay && this._player.start();
},
= function () {
("", this._player), true === this._player.v ? (" disconnect") : this._player.S = true,
this._player.cleanupWebSocket(this._player)
}
},
= function (t) {
("CleanupWebSocket", t), clearInterval(), = 0, = 0, = 0;
},
= function () {
(this._token), = setInterval((this), 3e3);
},
= function () {
("disconnect", this), = true, clearInterval(), null != && ((),
= null), ("disconnect", this);
},
= function () {
try {
var t = {
cmd: "H5_START"
};
((t))
}
catch (err) {
(err)
}
},
= function () {
try {
var t = {
cmd: "H5_PAUSE"
};
((t))
}
catch (err) {
(err)
}
},
= function () {
try {
var t = {
cmd: "H5_RESUME"
};
((t))
}
catch (err) {
(err)
}
},
= function (t) {
try {
var s = {
cmd: "H5_SEEK"
};
= t, ((s))
}
catch (err) {
(err)
}
},
= function (t) {
try {
var s = {
cmd: "H5_SPEED"
};
= t, ((s))
}
catch (err) {
(err)
}
},
= function (t) {
var s;
("H5SWebSocketClient");
try {
"http:" == this._conf.protocol && (s = "undefined" != typeof MozWebSocket ? new MozWebSocket("ws://" + this._conf.host + t) : new WebSocket("ws://" + this._conf.host + t)),
"https:" == this._conf.protocol && ((this._conf.host), s = "undefined" != typeof MozWebSocket ? new MozWebSocket("wss://" + this._conf.host + t) : new WebSocket("wss://" + this._conf.host + t)),
(this._conf.host)
}
catch (err) {
return void alert("error")
}
return s;
},
= function () {
try {
var t = {
type: "keepalive"
};
((t))
}
catch (err) {
(err)
}
},
= function (msg) {
("HLS received ", )
},
= function (t) {
var s = "api/v1/h5swscmnapi";
s = this._conf.rootpath + s + "?token=" + t + "&session=" + this._conf.session, (s), = (s),
("setupWebSocket", ), = "arraybuffer", (._player = this). = (this),
= function () {
("", this._player), this._player.keepAliveTimerId = setInterval(this._player.(this._player), 1e3);
},
= function () {
("", this._player), this._player.cleanupWebSocket(this._player)
}
},
= function (t) {
("H5sPlayerHls CleanupWebSocket", t), clearInterval()
},
= function () {
("HLS ", ), ("HLS ", );
var t = , s = t - ;
("HLS diff", s), 0 === s && ++ , = t, 3 < && (null != && ((),
= null), (this._token), ("HLS reconnect"), = "", = 0, = 0,
= this._conf.protocol + "//" + this._conf.host + this._conf.rootpath + "hls/" + + "/" + this._token + "/hls.m3u8",
());
},
= function () {
(this._token), = 0, = 0, = function (t) {
("The End")
},
= function (t) {
("Pause")
},
= function (t) {
("Playing")
},
= function (t) {
("seeking")
},
= function (t) {
("volumechange")
},
= this._conf.protocol + "//" + this._conf.host + this._conf.rootpath + "hls/" + + "/" + this._token + "/hls.m3u8",
(), = setInterval((this), 3e3);
},
= function () {
clearInterval(), = 0, = 0, null != && ((), = null),
("disconnect", this);
},
= function (t) {
var s;
("H5SWebSocketClient");
try {
"http:" == this._conf.protocol && (s = "undefined" != typeof MozWebSocket ? new MozWebSocket("ws://" + this._conf.host + t) : new WebSocket("ws://" + this._conf.host + t)),
"https:" == this._conf.protocol && ((this._conf.host), s = "undefined" != typeof MozWebSocket ? new MozWebSocket("wss://" + this._conf.host + t) : new WebSocket("wss://" + this._conf.host + t)),
(this._conf.host)
}
catch (err) {
return void alert("error")
}
return s;
},
= function () {
try {
("keepalive")
}
catch (err) {
(err)
}
},
= function (msg) {
for (var s = new Int16Array(), e = , i = this._.createBuffer(1, e, 8e3), o = 0; o < 1; o++) {
for (var n = (o), h = 0; h < e; h++) {
n[h] = s[h] / 16383.5;
}
}
var c = this._.createBufferSource();
= i, (this._.destination), ();
},
= function (t) {
("CleanupWebSocket", t), clearInterval()
},
= function (t) {
var s = "api/v1/h5saudapi";
s = this._conf.rootpath + s + "?token=" + t + "&session=" + this._conf.session, (s), = (s),
("setupWebSocket for audio", ), = "arraybuffer", (._player = this). = (this),
= function () {
("", this._player), this._player.keepAliveTimerId = setInterval(this._player.(this._player), 1e3);
},
= function () {
("", this._player), this._player.cleanupWebSocket(this._player)
}
},
= function () {
(this._token)
},
= function () {
("disconnect", this), null != && ((), = null), ("disconnect",
this);
},
= function (t) {
var s;
("H5SWebSocketClient");
try {
"http:" == this._conf.protocol && (s = "undefined" != typeof MozWebSocket ? new MozWebSocket("ws://" + this._conf.host + t) : new WebSocket("ws://" + this._conf.host + t)),
"https:" == this._conf.protocol && ((this._conf.host), s = "undefined" != typeof MozWebSocket ? new MozWebSocket("wss://" + this._conf.host + t) : new WebSocket("wss://" + this._conf.host + t)),
(this._conf.host)
}
catch (err) {
return void alert("error")
}
return s;
},
= function () {
try {
("keepalive")
}
catch (err) {
(err)
}
},
= function (msg) { },
= function (t) {
("CleanupWebSocket", t), clearInterval()
},
= function () {
("sampleRate", this._.sampleRate), = || || || ;
try {
({
video: false, audio: true
},
(this))
}
catch (err) {
return void alert("Audio back false getUserMedia", err);
}
},
= function () {
= true
},
= function (t) {
var s = "api/v1/h5saudbackapi";
s = this._conf.rootpath + s + "?token=" + t + "&samplerate=" + + "&session=" + this._conf.session,
(s), = (s), ("setupWebSocket for audio back", ), = "arraybuffer",
(._player = this). = (this), = (this), = function () {
("", this._player), this._player.cleanupWebSocket(this._player)
}
},
= function (t) {
var s = float32ToInt16((0));
true === && && (s)
},
= function (t) {
try {
var s = this._.createMediaStreamSource(t), e = this._.createScriptProcessor(1024, 1, 1);
(e), (this._.destination), = (this)
}
catch (err) {
return void alert("Audio intecomm error", err);
}
},
= function () {
(this._token)
},
= function () {
("disconnect", this), null != && ((), = null), ("disconnect",
this);
};
2.创建简单播放视频原型代码
结合前面H5Stream里面的,实验并成功播放了一个H5Stream的ws视频。
还有一些细节问题。
<html>
<head>
<title>WebsocketVideo</title>
<script src=""></script>
<script src=""></script>
</head>
<body>
<input style="width:100px;">
<button >Play</button>
<div>
<video autoplay webkit-playsinline playsinline></video>
</div>
</body>
<script>
$(document).ready(function(){
var conf={};
="ws://localhost:8080/api/v1/h5swsapi?token=token2&profile=main&session=c1782caf-b670-42d8-ba90-2244d0b0ee83";
='video1';
var player=new WebSocketPlayer(conf);
();
});
function WebSocketPlayer(conf){
=conf;
='';
=false;
=[];
=function(){
('openWebSocket');
var player=this;
var url=;
var wsImp= || ;
var ws=new wsImp(url);
='arraybuffer';
=function(){
('onopen');
};
=function(){
('onclose');
}
=;
=player;
};
=function(msg){
('onmessage',);
var ws=this;
var player=;
if(===false){
=true;
=(null,new Uint8Array());
(player);
();
}else{
//();
//();
();
}
};
=function(player){
try {
('initMediaSource',player);
var msImp= || ;
var ms=new msImp();
=player;
=ms;
var video=();
=(ms);
();
('sourceopen',)
=video;
}catch(ex){
(ex);
}
};
=function(){
('msSourceOpen');
var ms=this;
var player=;
var buffer=();
=Infinity;
('updateend',)
=buffer;
};
=function(){
('readFromBuffer1',this);
//var player=this;
//var buffer=;
//('readFromBuffer2',buffer);
//var first=();
//var sourceBuffer=;
//(first);
};
}
</script>
</html>