Embed:
- updated videojs and dashjs - combo selection algorithm now tries to find maximum simultracks - when requesting stream info, add ?metaeverywhere=1 to the url to not count meta/subtitle tracks to simul_tracks and source priority sorting - updated videojs, dashjs and hlsjs players - improved html5 codec support testing - urlappend: improved behaviour when url already contains search params
This commit is contained in:
parent
6d86f98148
commit
eee3595d46
26 changed files with 452 additions and 185 deletions
File diff suppressed because one or more lines are too long
|
@ -82,7 +82,7 @@ svg.icon .spin,svg.icon.spin{animation:mistvideo-spin 1.5s infinite linear;trans
|
|||
svg.icon.timeout{display:inline-block;height:1em;width:1em;margin:0;margin-right:.25em;vertical-align:top}
|
||||
.mist.largeplay,.mist.muted{position:absolute;opacity:.5}
|
||||
.mist.largeplay{top:50%;left:0;right:0;margin:auto;transform:translateY(-50%)}
|
||||
.mist.muted{top:0;right:0;margin:1em}
|
||||
.mist.muted{top:0;right:0;margin:1%;max-height:20%;width:auto}
|
||||
.mistvideo-secondaryVideo{z-index:1;position:absolute;right:0;top:0;width:50%;height:50%;max-width:fit-content;max-height:fit-content}
|
||||
.mistvideo-polling{display:inline-block;position:relative;width:25px;height:25px}
|
||||
.mistvideo-polling svg.icon.loading{z-index:0;opacity:1}
|
||||
|
|
|
@ -82,7 +82,7 @@ svg.icon .spin,svg.icon.spin{animation:mistvideo-spin 1.5s infinite linear;trans
|
|||
svg.icon.timeout{display:inline-block;height:1em;width:1em;margin:0;margin-right:.25em;vertical-align:top}
|
||||
.mist.largeplay,.mist.muted{position:absolute;opacity:.5}
|
||||
.mist.largeplay{top:50%;left:0;right:0;margin:auto;transform:translateY(-50%)}
|
||||
.mist.muted{top:0;right:0;margin:1em}
|
||||
.mist.muted{top:0;right:0;margin:1%;max-height:20%;width:auto}
|
||||
.mistvideo-secondaryVideo{z-index:1;position:absolute;right:0;top:0;width:50%;height:50%;max-width:fit-content;max-height:fit-content}
|
||||
.mistvideo-polling{display:inline-block;position:relative;width:25px;height:25px}
|
||||
.mistvideo-polling svg.icon.loading{z-index:0;opacity:1}
|
||||
|
|
|
@ -1 +1 @@
|
|||
mistplayers.dashjs={name:"Dash.js player",mimes:["dash/video/mp4"],priority:MistUtil.object.keys(mistplayers).length+1,isMimeSupported:function(t){return MistUtil.array.indexOf(this.mimes,t)==-1?false:true},isBrowserSupported:function(t,e,i){if(location.protocol!=MistUtil.http.url.split(e.url).protocol){i.log("HTTP/HTTPS mismatch for this source");return false}if(location.protocol=="file:"){i.log("This source ("+t+") won't load if the page is run via file://");return false}var r={};for(var a in i.info.meta.tracks){if(i.info.meta.tracks[a].type!="meta"){r[i.info.meta.tracks[a].codec]=1}}r=MistUtil.object.keys(r);for(var a=r.length-1;a>=0;a--){if(r[a].substr(0,4)=="HEVC"){r.splice(a,1)}}if(r.length<e.simul_tracks){return false}return"MediaSource"in window},player:function(){this.onreadylist=[]},scriptsrc:function(t){return t+"/dashjs.js"}};var p=mistplayers.dashjs.player;p.prototype=new MistPlayer;p.prototype.build=function(t,e){var i=this;this.onDashLoad=function(){if(t.destroyed){return}t.log("Building DashJS player..");var r=document.createElement("video");if("Proxy"in window){var a={get:{},set:{}};t.player.api=new Proxy(r,{get:function(t,e,i){if(e in a.get){return a.get[e].apply(t,arguments)}var r=t[e];if(typeof r==="function"){return function(){return r.apply(t,arguments)}}return r},set:function(t,e,i){if(e in a.set){return a.set[e].call(t,i)}return t[e]=i}});if(t.info.type=="live"){a.get.duration=function(){var e=0;if(this.buffered.length){e=this.buffered.end(this.buffered.length-1)}var i=((new Date).getTime()-t.player.api.lastProgress.getTime())*.001;return e+i+-1*t.player.api.liveOffset+45};a.set.currentTime=function(e){var i=e-t.player.api.duration;t.log("Seeking to "+MistUtil.format.time(e)+" ("+Math.round(i*-10)/10+"s from live)");t.video.currentTime=e};MistUtil.event.addListener(r,"progress",function(){t.player.api.lastProgress=new Date});t.player.api.lastProgress=new Date;t.player.api.liveOffset=0}}else{i.api=r}if(t.options.autoplay){r.setAttribute("autoplay","")}if(t.options.loop&&t.info.type!="live"){r.setAttribute("loop","")}if(t.options.poster){r.setAttribute("poster",t.options.poster)}if(t.options.muted){r.muted=true}if(t.options.controls=="stock"){r.setAttribute("controls","")}var s=dashjs.MediaPlayer().create();s.initialize(r,t.source.url,t.options.autoplay);i.dash=s;var o=["METRIC_ADDED","METRIC_UPDATED","METRIC_CHANGED","METRICS_CHANGED","FRAGMENT_LOADING_STARTED","FRAGMENT_LOADING_COMPLETED","LOG","PLAYBACK_TIME_UPDATED","PLAYBACK_PROGRESS"];for(var n in dashjs.MediaPlayer.events){if(o.indexOf(n)<0){i.dash.on(dashjs.MediaPlayer.events[n],function(e){t.log("Player event fired: "+e.type)})}}t.player.setSize=function(t){this.api.style.width=t.width+"px";this.api.style.height=t.height+"px"};t.player.api.setSource=function(e){t.player.dash.attachSource(e)};var l=false;i.dash.on("allTextTracksAdded",function(){l=true});t.player.api.setSubtitle=function(e){if(!l){var r=function(){t.player.api.setSubtitle(e);i.dash.off("allTextTracksAdded",r)};i.dash.on("allTextTracksAdded",r);return}if(!e){i.dash.enableText(false);return}var a=i.dash.getTracksFor("text");for(var s in a){var o="idx"in e?e.idx:e.trackid;if(a[s].id==o){i.dash.setTextTrack(s);if(!i.dash.isTextEnabled()){i.dash.enableText()}return true}}return false};MistUtil.event.addListener(r,"progress",function(e){if(t.container.getAttribute("data-loading")=="stalled"){t.container.removeAttribute("data-loading")}});i.api.unload=function(){i.dash.reset()};t.log("Built html");e(r)};if("dashjs"in window){this.onDashLoad()}else{var r=MistUtil.scripts.insert(t.urlappend(mistplayers.dashjs.scriptsrc(t.options.host)),{onerror:function(e){var i="Failed to load dashjs.js";if(e.message){i+=": "+e.message}t.showError(i)},onload:i.onDashLoad},t)}};
|
||||
mistplayers.dashjs={name:"Dash.js player",mimes:["dash/video/mp4"],priority:MistUtil.object.keys(mistplayers).length+1,isMimeSupported:function(e){return MistUtil.array.indexOf(this.mimes,e)==-1?false:true},isBrowserSupported:function(e,t,i){if(location.protocol!=MistUtil.http.url.split(t.url).protocol){i.log("HTTP/HTTPS mismatch for this source");return false}if(location.protocol=="file:"){i.log("This source ("+e+") won't load if the page is run via file://");return false}if(!("MediaSource"in window)){return false}if(!MediaSource.isTypeSupported){return true}var r={};var a=false;for(var s in i.info.meta.tracks){if(i.info.meta.tracks[s].type=="meta"){if(i.info.meta.tracks[s].codec=="subtitle"){a=true}continue}if(!(i.info.meta.tracks[s].type in r)){r[i.info.meta.tracks[s].type]={}}r[i.info.meta.tracks[s].type][MistUtil.tracks.translateCodec(i.info.meta.tracks[s])]=1}var o=[];for(var n in r){var l=false;for(var f in r[n]){if(MediaSource.isTypeSupported('video/mp4;codecs="'+f+'"')){l=true;break}}if(l){o.push(n)}}if(a){for(var s in i.info.source){if(i.info.source[s].type=="html5/text/vtt"){o.push("subtitle");break}}}return o.length?o:false},player:function(){this.onreadylist=[]},scriptsrc:function(e){return e+"/dashjs.js"}};var p=mistplayers.dashjs.player;p.prototype=new MistPlayer;p.prototype.build=function(e,t){var i=this;this.onDashLoad=function(){if(e.destroyed){return}e.log("Building DashJS player..");var r=document.createElement("video");if("Proxy"in window){var a={get:{},set:{}};e.player.api=new Proxy(r,{get:function(e,t,i){if(t in a.get){return a.get[t].apply(e,arguments)}var r=e[t];if(typeof r==="function"){return function(){return r.apply(e,arguments)}}return r},set:function(e,t,i){if(t in a.set){return a.set[t].call(e,i)}return e[t]=i}});if(e.info.type=="live"){a.get.duration=function(){var t=0;if(this.buffered.length){t=this.buffered.end(this.buffered.length-1)}var i=((new Date).getTime()-e.player.api.lastProgress.getTime())*.001;return t+i+-1*e.player.api.liveOffset+45};a.set.currentTime=function(t){var i=t-e.player.api.duration;e.log("Seeking to "+MistUtil.format.time(t)+" ("+Math.round(i*-10)/10+"s from live)");e.video.currentTime=t};MistUtil.event.addListener(r,"progress",function(){e.player.api.lastProgress=new Date});e.player.api.lastProgress=new Date;e.player.api.liveOffset=0}}else{i.api=r}if(e.options.autoplay){r.setAttribute("autoplay","")}if(e.options.loop&&e.info.type!="live"){r.setAttribute("loop","")}if(e.options.poster){r.setAttribute("poster",e.options.poster)}if(e.options.muted){r.muted=true}if(e.options.controls=="stock"){r.setAttribute("controls","")}var s=dashjs.MediaPlayer().create();s.initialize(r,e.source.url,e.options.autoplay);i.dash=s;var o=["METRIC_ADDED","METRIC_UPDATED","METRIC_CHANGED","METRICS_CHANGED","FRAGMENT_LOADING_STARTED","FRAGMENT_LOADING_COMPLETED","LOG","PLAYBACK_TIME_UPDATED","PLAYBACK_PROGRESS"];for(var n in dashjs.MediaPlayer.events){if(o.indexOf(n)<0){i.dash.on(dashjs.MediaPlayer.events[n],function(t){e.log("Player event fired: "+t.type)})}}e.player.setSize=function(e){this.api.style.width=e.width+"px";this.api.style.height=e.height+"px"};e.player.api.setSource=function(t){e.player.dash.attachSource(t)};var l=false;i.dash.on("allTextTracksAdded",function(){l=true});e.player.api.setSubtitle=function(t){if(!l){var r=function(){e.player.api.setSubtitle(t);i.dash.off("allTextTracksAdded",r)};i.dash.on("allTextTracksAdded",r);return}if(!t){i.dash.enableText(false);return}var a=i.dash.getTracksFor("text");for(var s in a){var o="idx"in t?t.idx:t.trackid;if(a[s].id==o){i.dash.setTextTrack(s);if(!i.dash.isTextEnabled()){i.dash.enableText()}return true}}return false};MistUtil.event.addListener(r,"progress",function(t){if(e.container.getAttribute("data-loading")=="stalled"){e.container.removeAttribute("data-loading")}});i.api.unload=function(){i.dash.reset()};e.log("Built html");t(r)};if("dashjs"in window){this.onDashLoad()}else{var r=MistUtil.scripts.insert(e.urlappend(mistplayers.dashjs.scriptsrc(e.options.host)),{onerror:function(t){var i="Failed to load dashjs.js";if(t.message){i+=": "+t.message}e.showError(i)},onload:i.onDashLoad},e)}};
|
|
@ -1 +1 @@
|
|||
mistplayers.flv={name:"HTML5 FLV Player",mimes:["flash/7"],priority:MistUtil.object.keys(mistplayers).length+1,isMimeSupported:function(e){return MistUtil.array.indexOf(this.mimes,e)==-1?false:true},isBrowserSupported:function(e,t,r){if(location.protocol!=MistUtil.http.url.split(t.url).protocol){if(location.protocol=="file:"&&MistUtil.http.url.split(t.url).protocol=="http:"){r.log("This page was loaded over file://, the player might not behave as intended.")}else{r.log("HTTP/HTTPS mismatch for this source");return false}}if(!window.MediaSource){return false}try{function o(e){return window.MediaSource.isTypeSupported('video/mp4;codecs="'+e+'"')}function a(e){function t(t){return("0"+e.init.charCodeAt(t).toString(16)).slice(-2)}switch(e.codec){case"AAC":return"mp4a.40.2";case"MP3":return"mp3";case"AC3":return"ec-3";case"H264":return"avc1."+t(1)+t(2)+t(3);case"HEVC":return"hev1."+t(1)+t(6)+t(7)+t(8)+t(9)+t(10)+t(11)+t(12);default:return e.codec.toLowerCase()}}var i={};for(var l in r.info.meta.tracks){if(r.info.meta.tracks[l].type!="meta"){i[a(r.info.meta.tracks[l])]=r.info.meta.tracks[l].type}}t.supportedCodecs=[];for(var l in i){var n=o(l);if(n){t.supportedCodecs.push(i[l])}}if(!r.options.forceType&&!r.options.forcePlayer){if(t.supportedCodecs.length<t.simul_tracks){r.log("Not enough playable tracks for this source");return false}}return t.supportedCodecs.length>0}catch(e){}return false},player:function(){this.onreadylist=[]},scriptsrc:function(e){return e+"/flv.js"}};var p=mistplayers.flv.player;p.prototype=new MistPlayer;p.prototype.build=function(e,t){this.onFLVLoad=function(){if(e.destroyed){return}e.log("Building flv.js player..");var r=document.createElement("video");r.setAttribute("playsinline","");var o=["autoplay","loop","poster"];for(var a in o){var i=o[a];if(e.options[i]){r.setAttribute(i,e.options[i]===true?"":e.options[i])}}if(e.options.muted){r.muted=true}if(e.options.controls=="stock"){r.setAttribute("controls","")}if(e.info.type=="live"){r.loop=false}flvjs.LoggingControl.applyConfig({enableVerbose:false});flvjs.LoggingControl.addLogListener(function(t,r){e.log("[flvjs] "+r)});var l={type:"flv",url:e.source.url,hasAudio:false,hasVideo:false};for(var a in e.source.supportedCodecs){l["has"+e.source.supportedCodecs[a].charAt(0).toUpperCase()+e.source.supportedCodecs[a].slice(1)]=true}e.player.create=function(t){t=MistUtil.object.extend({},t);e.player.flvPlayer=flvjs.createPlayer(t,{lazyLoad:false});e.player.flvPlayer.attachMediaElement(r);e.player.flvPlayer.load();e.player.flvPlayer.play();if(!e.options.autoplay){r.pause()}};e.player.create(l);e.player.api={};function n(t){Object.defineProperty(e.player.api,t,{get:function(){return r[t]},set:function(e){return r[t]=e}})}var s=["volume","buffered","muted","loop","paused",,"error","textTracks","webkitDroppedFrameCount","webkitDecodedFrameCount"];if(e.info.type!="live"){s.push("duration")}else{Object.defineProperty(e.player.api,"duration",{get:function(){if(!r.buffered.length){return 0}return r.buffered.end(r.buffered.length-1)}})}for(var a in s){n(s[a])}function p(t){if(t in r){e.player.api[t]=function(){return r[t].call(r,arguments)}}}var s=["load","getVideoPlaybackQuality","play","pause"];for(var a in s){p(s[a])}e.player.api.setSource=function(t){if(t!=l.url&&t!=""){e.player.flvPlayer.unload();e.player.flvPlayer.detachMediaElement();e.player.flvPlayer.destroy();l.url=t;e.player.create(l)}};e.player.api.unload=function(){e.player.flvPlayer.unload();e.player.flvPlayer.detachMediaElement();e.player.flvPlayer.destroy()};e.player.setSize=function(e){r.style.width=e.width+"px";r.style.height=e.height+"px"};Object.defineProperty(e.player.api,"currentTime",{get:function(){return r.currentTime},set:function(t){var o=.5;for(var a=0;a<r.buffered.length;a++){if(t>=r.buffered.start(a)&&t<=r.buffered.end(a)-o){return r.currentTime=t}}e.log("Seek attempted outside of buffer, but MistServer does not support seeking in progressive flash. Setting to closest available instead");return r.currentTime=r.buffered.length?r.buffered.end(r.buffered.length-1)-o:0}});t(r)};if("flvjs"in window){this.onFLVLoad()}else{var r=MistUtil.scripts.insert(e.urlappend(mistplayers.flv.scriptsrc(e.options.host)),{onerror:function(t){var r="Failed to load flv.js";if(t.message){r+=": "+t.message}e.showError(r)},onload:e.player.onFLVLoad},e)}};
|
||||
mistplayers.flv={name:"HTML5 FLV Player",mimes:["flash/7"],priority:MistUtil.object.keys(mistplayers).length+1,isMimeSupported:function(e){return MistUtil.array.indexOf(this.mimes,e)==-1?false:true},isBrowserSupported:function(e,t,r){if(location.protocol!=MistUtil.http.url.split(t.url).protocol){if(location.protocol=="file:"&&MistUtil.http.url.split(t.url).protocol=="http:"){r.log("This page was loaded over file://, the player might not behave as intended.")}else{r.log("HTTP/HTTPS mismatch for this source");return false}}if(!window.MediaSource){return false}if(!MediaSource.isTypeSupported){return true}try{var o={};for(var a in r.info.meta.tracks){if(r.info.meta.tracks[a].type=="meta"){continue}if(!(r.info.meta.tracks[a].type in o)){o[r.info.meta.tracks[a].type]={}}o[r.info.meta.tracks[a].type][MistUtil.tracks.translateCodec(r.info.meta.tracks[a])]=1}var i=[];for(var l in o){var n=false;for(var s in o[l]){if(MediaSource.isTypeSupported('video/mp4;codecs="'+s+'"')){n=true;break}}if(n){i.push(l)}}t.supportedCodecs=i;return i.length?i:false}catch(e){}return false},player:function(){this.onreadylist=[]},scriptsrc:function(e){return e+"/flv.js"}};var p=mistplayers.flv.player;p.prototype=new MistPlayer;p.prototype.build=function(e,t){this.onFLVLoad=function(){if(e.destroyed){return}e.log("Building flv.js player..");var r=document.createElement("video");r.setAttribute("playsinline","");var o=["autoplay","loop","poster"];for(var a in o){var i=o[a];if(e.options[i]){r.setAttribute(i,e.options[i]===true?"":e.options[i])}}if(e.options.muted){r.muted=true}if(e.options.controls=="stock"){r.setAttribute("controls","")}if(e.info.type=="live"){r.loop=false}flvjs.LoggingControl.applyConfig({enableVerbose:false});flvjs.LoggingControl.addLogListener(function(t,r){e.log("[flvjs] "+r)});var l={type:"flv",url:e.source.url,hasAudio:false,hasVideo:false};for(var a in e.source.supportedCodecs){l["has"+e.source.supportedCodecs[a].charAt(0).toUpperCase()+e.source.supportedCodecs[a].slice(1)]=true}e.player.create=function(t){t=MistUtil.object.extend({},t);e.player.flvPlayer=flvjs.createPlayer(t,{lazyLoad:false});e.player.flvPlayer.attachMediaElement(r);e.player.flvPlayer.load();e.player.flvPlayer.play();if(!e.options.autoplay){r.pause()}};e.player.create(l);e.player.api={};function n(t){Object.defineProperty(e.player.api,t,{get:function(){return r[t]},set:function(e){return r[t]=e}})}var s=["volume","buffered","muted","loop","paused",,"error","textTracks","webkitDroppedFrameCount","webkitDecodedFrameCount"];if(e.info.type!="live"){s.push("duration")}else{Object.defineProperty(e.player.api,"duration",{get:function(){if(!r.buffered.length){return 0}return r.buffered.end(r.buffered.length-1)}})}for(var a in s){n(s[a])}function f(t){if(t in r){e.player.api[t]=function(){return r[t].call(r,arguments)}}}var s=["load","getVideoPlaybackQuality","play","pause"];for(var a in s){f(s[a])}e.player.api.setSource=function(t){if(t!=l.url&&t!=""){e.player.flvPlayer.unload();e.player.flvPlayer.detachMediaElement();e.player.flvPlayer.destroy();l.url=t;e.player.create(l)}};e.player.api.unload=function(){e.player.flvPlayer.unload();e.player.flvPlayer.detachMediaElement();e.player.flvPlayer.destroy()};e.player.setSize=function(e){r.style.width=e.width+"px";r.style.height=e.height+"px"};Object.defineProperty(e.player.api,"currentTime",{get:function(){return r.currentTime},set:function(t){var o=.5;for(var a=0;a<r.buffered.length;a++){if(t>=r.buffered.start(a)&&t<=r.buffered.end(a)-o){return r.currentTime=t}}e.log("Seek attempted outside of buffer, but MistServer does not support seeking in progressive flash. Setting to closest available instead");return r.currentTime=r.buffered.length?r.buffered.end(r.buffered.length-1)-o:0}});t(r)};if("flvjs"in window){this.onFLVLoad()}else{var r=MistUtil.scripts.insert(e.urlappend(mistplayers.flv.scriptsrc(e.options.host)),{onerror:function(t){var r="Failed to load flv.js";if(t.message){r+=": "+t.message}e.showError(r)},onload:e.player.onFLVLoad},e)}};
|
|
@ -1 +1 @@
|
|||
mistplayers.hlsjs={name:"HLS.js player",mimes:["html5/application/vnd.apple.mpegurl","html5/application/vnd.apple.mpegurl;version=7"],priority:MistUtil.object.keys(mistplayers).length+1,isMimeSupported:function(e){return this.mimes.indexOf(e)==-1?false:true},isBrowserSupported:function(e,t,s){if(location.protocol!=MistUtil.http.url.split(t.url).protocol){s.log("HTTP/HTTPS mismatch for this source");return false}var l={};for(var r in s.info.meta.tracks){if(s.info.meta.tracks[r].type!="meta"){l[s.info.meta.tracks[r].codec]=1}}l=MistUtil.object.keys(l);for(var r=l.length-1;r>=0;r--){if(l[r].substr(0,4)=="HEVC"){l.splice(r,1)}}if(l.length<t.simul_tracks){return false}return true},player:function(){},scriptsrc:function(e){return e+"/hlsjs.js"}};var p=mistplayers.hlsjs.player;p.prototype=new MistPlayer;p.prototype.build=function(e,t){var s=this;var l=document.createElement("video");l.setAttribute("playsinline","");var r=["autoplay","loop","poster"];for(var i in r){var o=r[i];if(e.options[o]){l.setAttribute(o,e.options[o]===true?"":e.options[o])}}if(e.options.muted){l.muted=true}if(e.info.type=="live"){l.loop=false}if(e.options.controls=="stock"){l.setAttribute("controls","")}l.setAttribute("crossorigin","anonymous");this.setSize=function(e){l.style.width=e.width+"px";l.style.height=e.height+"px"};this.api=l;e.player.api.unload=function(){if(e.player.hls){e.player.hls.destroy();e.player.hls=false;e.log("hls.js instance disposed")}};function n(t){e.player.hls=new Hls({maxBufferLength:15,maxMaxBufferLength:60});e.player.hls.attachMedia(l);e.player.hls.on(Hls.Events.MEDIA_ATTACHED,function(){console.log("video and hls.js are now bound together !");e.player.hls.loadSource(t);e.player.hls.on(Hls.Events.MANIFEST_PARSED,function(e,t){console.log("manifest loaded, found "+t.levels.length+" quality level")})})}e.player.api.setSource=function(t){if(!e.player.hls){return}if(e.player.hls.url!=t){e.player.hls.destroy();n(t)}};e.player.api.setSubtitle=function(e){var t=l.getElementsByTagName("track");for(var s=t.length-1;s>=0;s--){l.removeChild(t[s])}if(e){var r=document.createElement("track");l.appendChild(r);r.kind="subtitles";r.label=e.label;r.srclang=e.lang;r.src=e.src;r.setAttribute("default","")}};function a(){n(e.source.url)}if("Hls"in window){a()}else{var p=e.urlappend(mistplayers.hlsjs.scriptsrc(e.options.host));MistUtil.scripts.insert(p,{onerror:function(t){var s="Failed to load hlsjs.js";if(t.message){s+=": "+t.message}e.showError(s)},onload:a},e)}t(l)};
|
||||
mistplayers.hlsjs={name:"HLS.js player",mimes:["html5/application/vnd.apple.mpegurl","html5/application/vnd.apple.mpegurl;version=7"],priority:MistUtil.object.keys(mistplayers).length+1,isMimeSupported:function(t){return this.mimes.indexOf(t)==-1?false:true},isBrowserSupported:function(t,e,r){if(location.protocol!=MistUtil.http.url.split(e.url).protocol){r.log("HTTP/HTTPS mismatch for this source");return false}if(!("MediaSource"in window)){return false}if(!MediaSource.isTypeSupported){return true}var i={};var s=false;for(var o in r.info.meta.tracks){if(r.info.meta.tracks[o].type=="meta"){if(r.info.meta.tracks[o].codec=="subtitle"){s=true}continue}if(!(r.info.meta.tracks[o].type in i)){i[r.info.meta.tracks[o].type]={}}i[r.info.meta.tracks[o].type][MistUtil.tracks.translateCodec(r.info.meta.tracks[o])]=1}var a=[];for(var l in i){var n=false;for(var p in i[l]){if(MediaSource.isTypeSupported('video/mp4;codecs="'+p+'"')){n=true;break}}if(n){a.push(l)}}if(s){for(var o in r.info.source){if(r.info.source[o].type=="html5/text/vtt"){a.push("subtitle");break}}}return a.length?a:false},player:function(){},scriptsrc:function(t){return t+"/hlsjs.js"}};var p=mistplayers.hlsjs.player;p.prototype=new MistPlayer;p.prototype.build=function(t,e){var r=this;var i=document.createElement("video");i.setAttribute("playsinline","");var s=["autoplay","loop","poster"];for(var o in s){var a=s[o];if(t.options[a]){i.setAttribute(a,t.options[a]===true?"":t.options[a])}}if(t.options.muted){i.muted=true}if(t.info.type=="live"){i.loop=false}if(t.options.controls=="stock"){i.setAttribute("controls","")}i.setAttribute("crossorigin","anonymous");this.setSize=function(t){i.style.width=t.width+"px";i.style.height=t.height+"px"};this.api=i;t.player.api.unload=function(){if(t.player.hls){t.player.hls.destroy();t.player.hls=false;t.log("hls.js instance disposed")}};function l(e){t.player.hls=new Hls({maxBufferLength:15,maxMaxBufferLength:60});t.player.hls.attachMedia(i);t.player.hls.on(Hls.Events.MEDIA_ATTACHED,function(){t.player.hls.loadSource(e)})}t.player.api.setSource=function(e){if(!t.player.hls){return}if(t.player.hls.url!=e){t.player.hls.destroy();l(e)}};t.player.api.setSubtitle=function(t){var e=i.getElementsByTagName("track");for(var r=e.length-1;r>=0;r--){i.removeChild(e[r])}if(t){var s=document.createElement("track");i.appendChild(s);s.kind="subtitles";s.label=t.label;s.srclang=t.lang;s.src=t.src;s.setAttribute("default","")}};function n(){l(t.source.url)}if("Hls"in window){n()}else{var p=t.urlappend(mistplayers.hlsjs.scriptsrc(t.options.host));MistUtil.scripts.insert(p,{onerror:function(e){var r="Failed to load hlsjs.js";if(e.message){r+=": "+e.message}t.showError(r)},onload:n},t)}e(i)};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -105,7 +105,7 @@ function MistVideo(streamName,options) {
|
|||
|
||||
this.urlappend = function(url){
|
||||
if (this.options.urlappend) {
|
||||
url += this.options.urlappend;
|
||||
url = MistUtil.http.url.append(url,this.options.urlappend);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
@ -235,6 +235,39 @@ function MistVideo(streamName,options) {
|
|||
return 0; //carry on!
|
||||
}
|
||||
|
||||
var best = {
|
||||
score: 0,
|
||||
source_index: null,
|
||||
player: null
|
||||
};
|
||||
function calcScore(tracktypes) {
|
||||
//player.isBrowserSupported returns either true or an array of track types that are in the source and that it can play in this browser.
|
||||
//loop over the returned track types and calculate a score of how good this player+source combo is
|
||||
if (tracktypes === true) { return 1.9; } //something will play, but the player doesn't tell us what. Hopefully video will work?
|
||||
|
||||
var scores = {
|
||||
video: 2,
|
||||
audio: 1,
|
||||
subtitle: 0.5
|
||||
};
|
||||
var score = 0;
|
||||
for (var i in tracktypes) {
|
||||
score += scores[tracktypes[i]];
|
||||
}
|
||||
return score;
|
||||
}
|
||||
//calculate the best possible score for this stream, so that we can break the loop early
|
||||
var hastracktypes = {};
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type == "meta") {
|
||||
hastracktypes[MistVideo.info.meta.tracks[i].codec] = 1;
|
||||
}
|
||||
else {
|
||||
hastracktypes[MistVideo.info.meta.tracks[i].type] = 1;
|
||||
}
|
||||
}
|
||||
var maxscore = calcScore(MistUtil.object.keys(hastracktypes));
|
||||
|
||||
outerloop:
|
||||
for (var n in variables[map.outer].list) {
|
||||
variables[map.outer].current = n;
|
||||
|
@ -255,18 +288,32 @@ function MistVideo(streamName,options) {
|
|||
|
||||
if (player.isMimeSupported(source.type)) {
|
||||
//this player supports this mime
|
||||
if (player.isBrowserSupported(source.type,source,MistVideo)) {
|
||||
//this browser is supported
|
||||
return {
|
||||
var tracktypes = player.isBrowserSupported(source.type,source,MistVideo);
|
||||
if (tracktypes) {
|
||||
var score = calcScore(tracktypes);
|
||||
if (score > best.score) {
|
||||
if (!quiet) MistVideo.log("Found a "+(best.score ? "better" : "working")+" combo: "+player.name+" with "+source.url+" (Score: "+score+")");
|
||||
|
||||
best = {
|
||||
score: score,
|
||||
player: p_shortname,
|
||||
source: source,
|
||||
source_index: variables.source.current
|
||||
};
|
||||
|
||||
if (best.score == maxscore) {
|
||||
//this is the max possible score, no need to continue searching
|
||||
return best;
|
||||
}
|
||||
}
|
||||
if (!quiet) { MistVideo.log("Checking "+player.name+" with "+source.type+".. Nope."); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best.score) {
|
||||
return best;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -280,7 +327,7 @@ function MistVideo(streamName,options) {
|
|||
var player = mistplayers[result.player];
|
||||
var source = result.source;
|
||||
|
||||
MistVideo.log("Found a working combo: "+player.name+" with "+source.type+" @ "+source.url);
|
||||
MistVideo.log("Selected: "+player.name+" with "+source.type+" @ "+source.url);
|
||||
MistVideo.playerName = result.player;
|
||||
source = MistUtil.object.extend({},source);
|
||||
source.index = result.source_index;
|
||||
|
@ -1004,7 +1051,7 @@ function MistVideo(streamName,options) {
|
|||
//switch to polling-mode if websockets are not supported
|
||||
|
||||
function openWithGet() {
|
||||
var url = MistVideo.urlappend(options.host+"/json_"+encodeURIComponent(MistVideo.stream)+".js");
|
||||
var url = MistUtil.http.url.addParam(MistVideo.urlappend(options.host+"/json_"+encodeURIComponent(MistVideo.stream)+".js"),{metaeverywhere:1});
|
||||
MistVideo.log("Requesting stream info from "+url);
|
||||
MistUtil.http.get(url,function(d){
|
||||
if (MistVideo.destroyed) { return; }
|
||||
|
@ -1023,7 +1070,7 @@ function MistVideo(streamName,options) {
|
|||
function openSocket() {
|
||||
MistVideo.log("Opening stream status stream through websocket..");
|
||||
var url = MistVideo.options.host.replace(/^http/i,"ws");
|
||||
url = MistVideo.urlappend(url+"/json_"+encodeURIComponent(MistVideo.stream)+".js");
|
||||
url = MistUtil.http.url.addParam(MistVideo.urlappend(url+"/json_"+encodeURIComponent(MistVideo.stream)+".js"),{metaeverywhere:1});
|
||||
var socket;
|
||||
try {
|
||||
socket = new WebSocket(url);
|
||||
|
|
4
embed/players/dash.all.min.js
vendored
4
embed/players/dash.all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -5,4 +5,7 @@ wget https://cdn.dashjs.org/latest/dash.all.min.js -O dash.all.min.js
|
|||
|
||||
echo "Videojs"
|
||||
echo "You'll want to check for the latest version at https://videojs.com/getting-started/#download-cdn"
|
||||
wget https://vjs.zencdn.net/7.8.4/video.min.js -O video.min.js
|
||||
wget https://vjs.zencdn.net/8.0.4/video.min.js -O video.min.js
|
||||
|
||||
echo "HLSjs"
|
||||
echo "Releases at https://github.com/video-dev/hls.js/ - download the .zip, extract, and replace hls.js with hls.min.js"
|
||||
|
|
52
embed/players/video.min.js
vendored
52
embed/players/video.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -90,7 +90,9 @@ svg.icon.timeout {
|
|||
.mist.muted {
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 1em;
|
||||
margin: 1%;
|
||||
max-height: 20%;
|
||||
width: auto;
|
||||
}
|
||||
.mistvideo-secondaryVideo {
|
||||
z-index: 1;
|
||||
|
|
|
@ -473,6 +473,30 @@ var MistUtil = {
|
|||
if (splitparams.length) { ret.push(splitparams.join("&")); }
|
||||
return ret.join("?");
|
||||
},
|
||||
append: function(url,append){
|
||||
var a = document.createElement("a");
|
||||
a.href = url;
|
||||
if (append[0] == "?") {
|
||||
if (a.search == "") {
|
||||
a.search = append;
|
||||
}
|
||||
else {
|
||||
a.search += "&"+append.slice(1);
|
||||
}
|
||||
}
|
||||
else if (append[0] == "&") {
|
||||
if (a.search == "") {
|
||||
a.search = "?"+append.slice(1);
|
||||
}
|
||||
else {
|
||||
a.search += append;
|
||||
}
|
||||
}
|
||||
else {
|
||||
a.href += append;
|
||||
}
|
||||
return a.href;
|
||||
},
|
||||
split: function(url){
|
||||
var a = document.createElement("a");
|
||||
a.href = url;
|
||||
|
@ -895,6 +919,28 @@ var MistUtil = {
|
|||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
translateCodec: function(track){
|
||||
|
||||
function bin2hex(index) {
|
||||
return ("0"+track.init.charCodeAt(index).toString(16)).slice(-2);
|
||||
}
|
||||
|
||||
switch (track.codec) {
|
||||
case "AAC":
|
||||
return "mp4a.40.2";
|
||||
case "MP3":
|
||||
return "mp3";
|
||||
//return "mp4a.40.34";
|
||||
case "AC3":
|
||||
return "ec-3";
|
||||
case "H264":
|
||||
return "avc1."+bin2hex(1)+bin2hex(2)+bin2hex(3);
|
||||
case "HEVC":
|
||||
return "hev1."+bin2hex(1)+bin2hex(6)+bin2hex(7)+bin2hex(8)+bin2hex(9)+bin2hex(10)+bin2hex(11)+bin2hex(12);
|
||||
default:
|
||||
return track.codec.toLowerCase();
|
||||
}
|
||||
}
|
||||
},
|
||||
isTouchDevice: function(){
|
||||
|
|
|
@ -19,22 +19,49 @@ mistplayers.dashjs = {
|
|||
return false;
|
||||
}
|
||||
|
||||
var codecs = {};
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type != "meta") {
|
||||
codecs[MistVideo.info.meta.tracks[i].codec] = 1;
|
||||
}
|
||||
}
|
||||
codecs = MistUtil.object.keys(codecs);
|
||||
//if there's a h265 track, remove it from the list of codecs
|
||||
for (var i = codecs.length-1; i >= 0; i--) {
|
||||
if (codecs[i].substr(0,4) == "HEVC") {
|
||||
codecs.splice(i,1);
|
||||
}
|
||||
}
|
||||
if (codecs.length < source.simul_tracks) { return false; } //if there's no longer enough playable tracks, skip this player
|
||||
if (!("MediaSource" in window)) { return false; }
|
||||
if (!MediaSource.isTypeSupported) { return true; } //we can't ask, but let's assume something will work
|
||||
|
||||
return ("MediaSource" in window);
|
||||
//check if both audio and video have at least one playable track
|
||||
//gather track types and codec strings
|
||||
var playabletracks = {};
|
||||
var hassubtitles = false;
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type == "meta") {
|
||||
if (MistVideo.info.meta.tracks[i].codec == "subtitle") { hassubtitles = true; }
|
||||
continue;
|
||||
}
|
||||
if (!(MistVideo.info.meta.tracks[i].type in playabletracks)) {
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type] = {};
|
||||
}
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type][MistUtil.tracks.translateCodec(MistVideo.info.meta.tracks[i])] = 1;
|
||||
}
|
||||
|
||||
var tracktypes = [];
|
||||
for (var type in playabletracks) {
|
||||
var playable = false;
|
||||
|
||||
for (var codec in playabletracks[type]) {
|
||||
if (MediaSource.isTypeSupported("video/mp4;codecs=\""+codec+"\"")) {
|
||||
playable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (playable) {
|
||||
tracktypes.push(type);
|
||||
}
|
||||
}
|
||||
if (hassubtitles) {
|
||||
//there is a subtitle track, check if there is a webvtt source
|
||||
for (var i in MistVideo.info.source) {
|
||||
if (MistVideo.info.source[i].type == "html5/text/vtt") {
|
||||
tracktypes.push("subtitle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tracktypes.length ? tracktypes : false;
|
||||
},
|
||||
player: function(){this.onreadylist = [];},
|
||||
scriptsrc: function(host) { return host+"/dashjs.js"; }
|
||||
|
|
|
@ -19,55 +19,53 @@ mistplayers.flv = {
|
|||
}
|
||||
|
||||
if (!window.MediaSource) { return false; }
|
||||
if (!MediaSource.isTypeSupported) { return true; } //we can't ask, but let's assume something will work
|
||||
|
||||
try {
|
||||
function test(mime) {
|
||||
return window.MediaSource.isTypeSupported("video/mp4;codecs=\""+mime+"\"");
|
||||
}
|
||||
function translateCodec(track) {
|
||||
|
||||
function bin2hex(index) {
|
||||
return ("0"+track.init.charCodeAt(index).toString(16)).slice(-2);
|
||||
}
|
||||
|
||||
switch (track.codec) {
|
||||
case "AAC":
|
||||
return "mp4a.40.2";
|
||||
case "MP3":
|
||||
return "mp3";
|
||||
//return "mp4a.40.34";
|
||||
case "AC3":
|
||||
return "ec-3";
|
||||
case "H264":
|
||||
return "avc1."+bin2hex(1)+bin2hex(2)+bin2hex(3);
|
||||
case "HEVC":
|
||||
return "hev1."+bin2hex(1)+bin2hex(6)+bin2hex(7)+bin2hex(8)+bin2hex(9)+bin2hex(10)+bin2hex(11)+bin2hex(12);
|
||||
default:
|
||||
return track.codec.toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
var codecs = {};
|
||||
//check if both audio and video have at least one playable track
|
||||
//gather track types and codec strings
|
||||
var playabletracks = {};
|
||||
//var hassubtitles = false;
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type != "meta") {
|
||||
codecs[translateCodec(MistVideo.info.meta.tracks[i])] = MistVideo.info.meta.tracks[i].type;
|
||||
if (MistVideo.info.meta.tracks[i].type == "meta") {
|
||||
//if (MistVideo.info.meta.tracks[i].codec == "subtitle") { hassubtitles = true; }
|
||||
continue;
|
||||
}
|
||||
if (!(MistVideo.info.meta.tracks[i].type in playabletracks)) {
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type] = {};
|
||||
}
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type][MistUtil.tracks.translateCodec(MistVideo.info.meta.tracks[i])] = 1;
|
||||
}
|
||||
|
||||
var tracktypes = [];
|
||||
for (var type in playabletracks) {
|
||||
var playable = false;
|
||||
|
||||
for (var codec in playabletracks[type]) {
|
||||
if (MediaSource.isTypeSupported("video/mp4;codecs=\""+codec+"\"")) {
|
||||
playable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
source.supportedCodecs = [];
|
||||
for (var i in codecs) {
|
||||
//i is the long name (like mp4a.40.2), codecs[i] is the type (audio/video)
|
||||
var s = test(i);
|
||||
if (s) {
|
||||
source.supportedCodecs.push(codecs[i]);
|
||||
if (playable) {
|
||||
tracktypes.push(type);
|
||||
}
|
||||
}
|
||||
if ((!MistVideo.options.forceType) && (!MistVideo.options.forcePlayer)) { //unless we force mews, skip this player if not both video and audio are supported
|
||||
if (source.supportedCodecs.length < source.simul_tracks) {
|
||||
MistVideo.log("Not enough playable tracks for this source");
|
||||
return false;
|
||||
source.supportedCodecs = tracktypes;
|
||||
/*if (hassubtitles) {
|
||||
//there is a subtitle track, check if there is a webvtt source
|
||||
for (var i in MistVideo.info.source) {
|
||||
if (MistVideo.info.source[i].type == "html5/text/vtt") {
|
||||
tracktypes.push("subtitle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return source.supportedCodecs.length > 0;
|
||||
}*/
|
||||
|
||||
return tracktypes.length ? tracktypes : false;
|
||||
|
||||
|
||||
} catch(e){}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -12,22 +12,49 @@ mistplayers.hlsjs = {
|
|||
return false;
|
||||
}
|
||||
|
||||
var codecs = {};
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type != "meta") {
|
||||
codecs[MistVideo.info.meta.tracks[i].codec] = 1;
|
||||
}
|
||||
}
|
||||
codecs = MistUtil.object.keys(codecs);
|
||||
//if there's a h265 track, remove it from the list of codecs
|
||||
for (var i = codecs.length-1; i >= 0; i--) {
|
||||
if (codecs[i].substr(0,4) == "HEVC") {
|
||||
codecs.splice(i,1);
|
||||
}
|
||||
}
|
||||
if (codecs.length < source.simul_tracks) { return false; } //if there's no longer enough playable tracks, skip this player
|
||||
if (!("MediaSource" in window)) { return false; }
|
||||
if (!MediaSource.isTypeSupported) { return true; } //we can't ask, but let's assume something will work
|
||||
|
||||
return true;
|
||||
//check if both audio and video have at least one playable track
|
||||
//gather track types and codec strings
|
||||
var playabletracks = {};
|
||||
var hassubtitles = false;
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type == "meta") {
|
||||
if (MistVideo.info.meta.tracks[i].codec == "subtitle") { hassubtitles = true; }
|
||||
continue;
|
||||
}
|
||||
if (!(MistVideo.info.meta.tracks[i].type in playabletracks)) {
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type] = {};
|
||||
}
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type][MistUtil.tracks.translateCodec(MistVideo.info.meta.tracks[i])] = 1;
|
||||
}
|
||||
|
||||
var tracktypes = [];
|
||||
for (var type in playabletracks) {
|
||||
var playable = false;
|
||||
|
||||
for (var codec in playabletracks[type]) {
|
||||
if (MediaSource.isTypeSupported("video/mp4;codecs=\""+codec+"\"")) {
|
||||
playable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (playable) {
|
||||
tracktypes.push(type);
|
||||
}
|
||||
}
|
||||
if (hassubtitles) {
|
||||
//there is a subtitle track, check if there is a webvtt source
|
||||
for (var i in MistVideo.info.source) {
|
||||
if (MistVideo.info.source[i].type == "html5/text/vtt") {
|
||||
tracktypes.push("subtitle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tracktypes.length ? tracktypes : false;
|
||||
},
|
||||
player: function(){},
|
||||
scriptsrc: function(host) { return host+"/hlsjs.js"; }
|
||||
|
@ -81,13 +108,13 @@ p.prototype.build = function (MistVideo,callback) {
|
|||
});
|
||||
MistVideo.player.hls.attachMedia(video);
|
||||
MistVideo.player.hls.on(Hls.Events.MEDIA_ATTACHED, function () {
|
||||
console.log("video and hls.js are now bound together !");
|
||||
//console.log("video and hls.js are now bound together !");
|
||||
//hls.loadSource("https://cattop/mist/cmaf/live/v9.m3u8");
|
||||
//hls.loadSource("https://mira:4433/cmaf/live/v9.m3u8");
|
||||
MistVideo.player.hls.loadSource(url);
|
||||
MistVideo.player.hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
|
||||
/*MistVideo.player.hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
|
||||
console.log("manifest loaded, found " + data.levels.length + " quality level");
|
||||
});
|
||||
});*/
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -33,27 +33,16 @@ mistplayers.html5 = {
|
|||
|
||||
try {
|
||||
shortmime = shortmime.join("/");
|
||||
|
||||
function test(mime) {
|
||||
var v = document.createElement("video");
|
||||
if ((v) && (v.canPlayType(mime) != "")) {
|
||||
support = v.canPlayType(mime);
|
||||
}
|
||||
return support;
|
||||
}
|
||||
|
||||
//works for mp4 but not for webm
|
||||
function translateCodec(track) {
|
||||
|
||||
function bin2hex(index) {
|
||||
return ("0"+track.init.charCodeAt(index).toString(16)).slice(-2);
|
||||
}
|
||||
|
||||
switch (track.codec) {
|
||||
case "AAC":
|
||||
return "mp4a.40.2";
|
||||
case "MP3":
|
||||
return "mp3";
|
||||
//return "mp4a.40.34";
|
||||
return "mp4a.40.34";
|
||||
case "AC3":
|
||||
return "ec-3";
|
||||
case "H264":
|
||||
|
@ -63,43 +52,64 @@ mistplayers.html5 = {
|
|||
default:
|
||||
return track.codec.toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var codecs = {};
|
||||
var playabletracks = {};
|
||||
var hassubtitles = false;
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type != "meta") {
|
||||
codecs[translateCodec(MistVideo.info.meta.tracks[i])] = 1;
|
||||
codecs[translateCodec(MistVideo.info.meta.tracks[i])] = MistVideo.info.meta.tracks[i];
|
||||
}
|
||||
else if (MistVideo.info.meta.tracks[i].codec == "subtitle") { hassubtitles = true; }
|
||||
}
|
||||
codecs = MistUtil.object.keys(codecs);
|
||||
var container = mimetype.split("/")[2];
|
||||
|
||||
if (shortmime == "video/mp4") {
|
||||
if (codecs.length) {
|
||||
if (codecs.length > source.simul_tracks) {
|
||||
//not all of the tracks have to work
|
||||
var working = 0;
|
||||
source.supportedCodecs = [];
|
||||
for (var i in codecs) {
|
||||
var s = test(shortmime+";codecs=\""+codecs[i]+"\"");
|
||||
//i is the long name (like mp4a.40.2), codecs[i] is the track meta, codecs[i].codec is the short name (like AAC)
|
||||
var s = test(i);
|
||||
if (s) {
|
||||
working++;
|
||||
source.supportedCodecs.push(codecs[i].codec);
|
||||
playabletracks[codecs[i].type] = 1;
|
||||
}
|
||||
}
|
||||
return (working >= source.simul_tracks);
|
||||
function test(codecs) {
|
||||
var v = document.createElement("video");
|
||||
if ((v) && (typeof v.canPlayType == "function")) {
|
||||
var result;
|
||||
switch (shortmime) {
|
||||
case "video/webm": {
|
||||
//if codecs are included here, at least chrome reports it as not working, even though it does. So we'll just assume it will play if webm returns maybe.
|
||||
result = v.canPlayType(shortmime);
|
||||
break;
|
||||
}
|
||||
return test(shortmime+";codecs=\""+codecs.join(",")+"\"");
|
||||
case "video/mp4":
|
||||
case "html5/application/vnd.apple.mpegurl":
|
||||
default: {
|
||||
result = v.canPlayType(shortmime+";codecs=\""+codecs+"\"");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//if there's a h265 track, remove it from the list of codecs
|
||||
for (var i = codecs.length-1; i >= 0; i--) {
|
||||
if (codecs[i].substr(0,4) == "hev1") {
|
||||
codecs.splice(i,1);
|
||||
if (result != "") {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (codecs.length < source.simul_tracks) { return false; } //if there's no longer enough playable tracks, skip this player
|
||||
return false;
|
||||
}
|
||||
|
||||
support = test(shortmime);
|
||||
|
||||
if (hassubtitles) {
|
||||
//there is a subtitle track, check if there is a webvtt source
|
||||
for (var i in MistVideo.info.source) {
|
||||
if (MistVideo.info.source[i].type == "html5/text/vtt") {
|
||||
playabletracks.subtitle = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
support = MistUtil.object.keys(playabletracks);
|
||||
} catch(e){}
|
||||
return support;
|
||||
},
|
||||
|
|
|
@ -42,14 +42,17 @@ mistplayers.mews = {
|
|||
|
||||
}
|
||||
var codecs = {};
|
||||
var playabletracks = {};
|
||||
var hassubtitles = false;
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type != "meta") {
|
||||
if (MistVideo.info.meta.tracks[i].codec == "HEVC") {
|
||||
/*if (MistVideo.info.meta.tracks[i].codec == "HEVC") {
|
||||
//the iPad claims to be able to play MP4/WS H265 tracks.. haha no.
|
||||
continue;
|
||||
}*/
|
||||
codecs[translateCodec(MistVideo.info.meta.tracks[i])] = MistVideo.info.meta.tracks[i];
|
||||
}
|
||||
codecs[translateCodec(MistVideo.info.meta.tracks[i])] = MistVideo.info.meta.tracks[i].codec;
|
||||
}
|
||||
else if (MistVideo.info.meta.tracks[i].codec == "subtitle") { hassubtitles = true; }
|
||||
}
|
||||
var container = mimetype.split("/")[2];
|
||||
function test(codecs) {
|
||||
|
@ -58,19 +61,25 @@ mistplayers.mews = {
|
|||
}
|
||||
source.supportedCodecs = [];
|
||||
for (var i in codecs) {
|
||||
//i is the long name (like mp4a.40.2), codecs[i] is the short name (like AAC)
|
||||
//i is the long name (like mp4a.40.2), codecs[i] is the track meta, codecs[i].codec is the short name (like AAC)
|
||||
var s = test(i);
|
||||
if (s) {
|
||||
source.supportedCodecs.push(codecs[i]);
|
||||
source.supportedCodecs.push(codecs[i].codec);
|
||||
playabletracks[codecs[i].type] = 1;
|
||||
}
|
||||
}
|
||||
if ((!MistVideo.options.forceType) && (!MistVideo.options.forcePlayer)) { //unless we force mews, skip this players if not both video and audio are supported
|
||||
if (source.supportedCodecs.length < source.simul_tracks) {
|
||||
MistVideo.log("Not enough playable tracks for this source");
|
||||
return false;
|
||||
|
||||
if (hassubtitles) {
|
||||
//there is a subtitle track, check if there is a webvtt source
|
||||
for (var i in MistVideo.info.source) {
|
||||
if (MistVideo.info.source[i].type == "html5/text/vtt") {
|
||||
playabletracks.subtitle = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return source.supportedCodecs.length > 0;
|
||||
}
|
||||
|
||||
return MistUtil.object.keys(playabletracks);
|
||||
},
|
||||
player: function(){}
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ mistplayers.rawws = {
|
|||
}
|
||||
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].codec == "HEVC") { return true; }
|
||||
if (MistVideo.info.meta.tracks[i].codec == "HEVC") { return ["video"]; }
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -19,22 +19,63 @@ mistplayers.videojs = {
|
|||
return false;
|
||||
}
|
||||
|
||||
var codecs = {};
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type != "meta") {
|
||||
codecs[MistVideo.info.meta.tracks[i].codec] = 1;
|
||||
}
|
||||
}
|
||||
codecs = MistUtil.object.keys(codecs);
|
||||
//if there's a h265 track, remove it from the list of codecs
|
||||
for (var i = codecs.length-1; i >= 0; i--) {
|
||||
if (codecs[i].substr(0,4) == "HEVC") {
|
||||
codecs.splice(i,1);
|
||||
}
|
||||
}
|
||||
if (codecs.length < source.simul_tracks) { return false; } //if there's no longer enough playable tracks, skip this player
|
||||
function checkPlaybackOfTrackTypes(mime) {
|
||||
if (!MediaSource.isTypeSupported) { return true; } //we can't ask, but let's assume something will work
|
||||
|
||||
return ("MediaSource" in window);
|
||||
//check if both audio and video have at least one playable track
|
||||
//gather track types and codec strings
|
||||
var playabletracks = {};
|
||||
var hassubtitles = false;
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type == "meta") {
|
||||
if (MistVideo.info.meta.tracks[i].codec == "subtitle") { hassubtitles = true; }
|
||||
continue;
|
||||
}
|
||||
if (!(MistVideo.info.meta.tracks[i].type in playabletracks)) {
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type] = {};
|
||||
}
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type][MistUtil.tracks.translateCodec(MistVideo.info.meta.tracks[i])] = 1;
|
||||
}
|
||||
|
||||
var tracktypes = [];
|
||||
for (var type in playabletracks) {
|
||||
var playable = false;
|
||||
|
||||
for (var codec in playabletracks[type]) {
|
||||
if (MediaSource.isTypeSupported(mime+";codecs=\""+codec+"\"")) {
|
||||
playable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (playable) {
|
||||
tracktypes.push(type);
|
||||
}
|
||||
}
|
||||
if (hassubtitles) {
|
||||
//there is a subtitle track, check if there is a webvtt source
|
||||
for (var i in MistVideo.info.source) {
|
||||
if (MistVideo.info.source[i].type == "html5/text/vtt") {
|
||||
tracktypes.push("subtitle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tracktypes.length ? tracktypes : false;
|
||||
}
|
||||
|
||||
//can this browser play this natively?
|
||||
if (document.createElement("video").canPlayType(mimetype.replace("html5/",""))) {
|
||||
|
||||
//we can't ask, but let's assume something will work
|
||||
if (!("MediaSource" in window)) { return true; }
|
||||
if (!MediaSource.isTypeSupported) { return true; }
|
||||
|
||||
return checkPlaybackOfTrackTypes(mimetype.replace("html5/",""));
|
||||
}
|
||||
|
||||
if (!("MediaSource" in window)) { return false; }
|
||||
return checkPlaybackOfTrackTypes("video/mp4");
|
||||
},
|
||||
player: function(){},
|
||||
scriptsrc: function(host) { return host+"/videojs.js"; }
|
||||
|
|
|
@ -7,7 +7,7 @@ mistplayers.webrtc = {
|
|||
},
|
||||
isBrowserSupported: function (mimetype,source,MistVideo) {
|
||||
|
||||
if ((!("WebSocket" in window)) || (!("RTCPeerConnection" in window))) { return false; }
|
||||
if ((!("WebSocket" in window)) || (!("RTCPeerConnection" in window) || (!("RTCRtpReceiver" in window)))) { return false; }
|
||||
|
||||
//check for http/https mismatch
|
||||
if (location.protocol.replace(/^http/,"ws") != MistUtil.http.url.split(source.url.replace(/^http/,"ws")).protocol) {
|
||||
|
@ -15,7 +15,52 @@ mistplayers.webrtc = {
|
|||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
//check if both audio and video have at least one playable track
|
||||
//gather track types and codec strings
|
||||
var playabletracks = {};
|
||||
var hassubtitles = false;
|
||||
for (var i in MistVideo.info.meta.tracks) {
|
||||
if (MistVideo.info.meta.tracks[i].type == "meta") {
|
||||
if (MistVideo.info.meta.tracks[i].codec == "subtitle") { hassubtitles = true; }
|
||||
continue;
|
||||
}
|
||||
if (!(MistVideo.info.meta.tracks[i].type in playabletracks)) {
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type] = {};
|
||||
}
|
||||
playabletracks[MistVideo.info.meta.tracks[i].type][MistVideo.info.meta.tracks[i].codec] = 1;
|
||||
}
|
||||
|
||||
var tracktypes = [];
|
||||
for (var type in playabletracks) {
|
||||
var playable = false;
|
||||
|
||||
for (var codec in playabletracks[type]) {
|
||||
var supported = RTCRtpReceiver.getCapabilities(type).codecs;
|
||||
for (var i in supported) {
|
||||
if (supported[i].mimeType.toLowerCase() == (type+"/"+codec).toLowerCase()) {
|
||||
playable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (playable) {
|
||||
tracktypes.push(type);
|
||||
}
|
||||
}
|
||||
if (hassubtitles) {
|
||||
//there is a subtitle track, check if there is a webvtt source
|
||||
for (var i in MistVideo.info.source) {
|
||||
if (MistVideo.info.source[i].type == "html5/text/vtt") {
|
||||
tracktypes.push("subtitle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tracktypes.length ? tracktypes : false;
|
||||
|
||||
//return true;
|
||||
},
|
||||
player: function(){}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue