H.265 Stream Type Added

- Now play H.265 video in almost any browser with the help of libde265.js!
+ minor bug fixes
+ preparation for slickslider page (timed switcher)
merge-requests/63/head
Moe 2018-08-20 23:07:08 -07:00
parent 7f05c62c08
commit 9166d7e8a9
7 changed files with 11750 additions and 99 deletions

175
camera.js
View File

@ -684,9 +684,9 @@ s.systemLog = function(q,w,e){
}
//system log
s.debugLog = function(q,w,e){
if(!w){w = ''}
if(!e){e = ''}
if(config.debugLog === true){
if(!w){w = ''}
if(!e){e = ''}
console.log(s.timeObject().format(),q,w,e)
if(config.debugLogVerbose === true){
console.log(new Error())
@ -2198,12 +2198,15 @@ s.ffmpeg = function(e){
x.pipe+=' -an -c:v mjpeg -f mpjpeg -boundary_tag shinobi'+x.cust_stream+x.stream_video_filters+' pipe:1';
}
break;
case'pam':
if(e.coProcessor === false){
case'h265':
x.cust_stream+=' -movflags +frag_keyframe+empty_moov+default_base_moof -metadata title="Shinobi H.265 Stream" -reset_timestamps 1'
if(e.details.stream_vcodec!=='copy'){
if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions}
if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality;
x.pipe+=' -an -c:v pam -pix_fmt rgba -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1';
if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -crf '+e.details.stream_quality;
x.cust_stream+=x.preset_stream
x.cust_stream+=x.stream_video_filters
}
x.pipe+=' -f hevc'+x.stream_acodec+x.stream_vcodec+x.cust_stream+' pipe:1';
break;
case'b64':case'':case undefined:case null://base64
if(e.coProcessor === false){
@ -2223,23 +2226,23 @@ s.ffmpeg = function(e){
}
//detector - plugins, motion
if(e.details.detector==='1' && e.details.detector_send_frames==='1' && e.coProcessor === false){
if(e.details.input_map_choices&&e.details.input_map_choices.detector){
//add input feed map
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
}
if(!e.details.detector_fps||e.details.detector_fps===''){e.details.detector_fps=2}
if(e.details.detector_scale_x&&e.details.detector_scale_x!==''&&e.details.detector_scale_y&&e.details.detector_scale_y!==''){x.dratio=' -s '+e.details.detector_scale_x+'x'+e.details.detector_scale_y}else{x.dratio=' -s 320x240'}
if(e.details.cust_detect&&e.details.cust_detect!==''){x.cust_detect+=e.details.cust_detect;}
if(e.details.detector_pam==='1'){
x.pipe+=' -an -c:v pam -pix_fmt gray -f image2pipe -r '+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3'
if(e.details.detector_use_detect_object === '1'){
//for object detection
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
x.pipe += ' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:4';
}
}else{
x.pipe+=' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3';
}
if(e.details.input_map_choices&&e.details.input_map_choices.detector){
//add input feed map
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
}
if(!e.details.detector_fps||e.details.detector_fps===''){e.details.detector_fps=2}
if(e.details.detector_scale_x&&e.details.detector_scale_x!==''&&e.details.detector_scale_y&&e.details.detector_scale_y!==''){x.dratio=' -s '+e.details.detector_scale_x+'x'+e.details.detector_scale_y}else{x.dratio=' -s 320x240'}
if(e.details.cust_detect&&e.details.cust_detect!==''){x.cust_detect+=e.details.cust_detect;}
if(e.details.detector_pam==='1'){
x.pipe+=' -an -c:v pam -pix_fmt gray -f image2pipe -r '+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3'
if(e.details.detector_use_detect_object === '1'){
//for object detection
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
x.pipe += ' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:4';
}
}else{
x.pipe+=' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3';
}
}
//api - snapshot bin/ cgi.bin (JPEG Mode)
if(e.details.snap === '1'){
@ -3673,6 +3676,12 @@ s.camera=function(x,e,cn,tx){
s.group[e.ke].mon[e.id].emitter.emit('data',d);
}
break;
case'h265':
e.frame_to_stream=function(d){
resetStreamCheck()
s.group[e.ke].mon[e.id].emitter.emit('data',d);
}
break;
// case'pam':
// s.group[e.ke].mon[e.id].p2pStream = new P2P();
// s.group[e.ke].mon[e.id].spawn.stdout.pipe(s.group[e.ke].mon[e.id].p2pStream)
@ -4032,6 +4041,79 @@ var tx;
}
})
//unique Base64 socket stream
cn.on('h265',function(d){
if(!s.group[d.ke]||!s.group[d.ke].mon||!s.group[d.ke].mon[d.id]){
cn.disconnect();return;
}
cn.ip=cn.request.connection.remoteAddress;
var toUTC = function(){
return new Date().toISOString();
}
var tx=function(z){cn.emit('data',z);}
d.failed=function(msg){
tx({f:'stop_reconnect',msg:msg,token_used:d.auth,ke:d.ke});
cn.disconnect();
}
d.success=function(r){
r=r[0];
var Emitter,chunkChannel
if(!d.channel){
Emitter = s.group[d.ke].mon[d.id].emitter
chunkChannel = 'MAIN'
}else{
Emitter = s.group[d.ke].mon[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
chunkChannel = parseInt(d.channel)+config.pipeAddition
}
if(!Emitter){
cn.disconnect();return;
}
if(!d.channel)d.channel = 'MAIN';
cn.ke=d.ke,
cn.uid=d.uid,
cn.auth=d.auth;
cn.channel=d.channel;
cn.removeListenerOnDisconnect=true;
cn.socketVideoStream=d.id;
var contentWriter
cn.closeSocketVideoStream = function(){
Emitter.removeListener('data', contentWriter);
}
Emitter.on('data',contentWriter = function(base64){
tx(base64)
})
}
//check if auth key is user's temporary session key
if(s.group[d.ke]&&s.group[d.ke].users&&s.group[d.ke].users[d.auth]){
d.success(s.group[d.ke].users[d.auth]);
}else{
s.sqlQuery('SELECT ke,uid,auth,mail,details FROM Users WHERE ke=? AND auth=? AND uid=?',[d.ke,d.auth,d.uid],function(err,r) {
if(r&&r[0]){
d.success(r)
}else{
s.sqlQuery('SELECT * FROM API WHERE ke=? AND code=? AND uid=?',[d.ke,d.auth,d.uid],function(err,r) {
if(r&&r[0]){
r=r[0]
r.details=JSON.parse(r.details)
if(r.details.auth_socket==='1'){
s.sqlQuery('SELECT ke,uid,auth,mail,details FROM Users WHERE ke=? AND uid=?',[r.ke,r.uid],function(err,r) {
if(r&&r[0]){
d.success(r)
}else{
d.failed('User not found')
}
})
}else{
d.failed('Permissions for this key do not allow authentication with Websocket')
}
}else{
d.failed('Not an API key')
}
})
}
})
}
})
//unique Base64 socket stream
cn.on('Base64',function(d){
if(!s.group[d.ke]||!s.group[d.ke].mon||!s.group[d.ke].mon[d.id]){
cn.disconnect();return;
@ -5442,6 +5524,8 @@ if(config.renderPaths === undefined){config.renderPaths={}}
if(config.renderPaths.mjpeg === undefined){config.renderPaths.mjpeg='pages/mjpeg'}
//gridstack only page
if(config.renderPaths.grid === undefined){config.renderPaths.grid='pages/grid'}
//slick.js (cycle) page
if(config.renderPaths.cycle === undefined){config.renderPaths.cycle='pages/cycle'}
////Pages
app.enable('trust proxy');
app.use('/libs',express.static(__dirname + '/web/libs'));
@ -5979,8 +6063,42 @@ app.get([config.webPaths.apiPrefix+':auth/flv/:ke/:id/s.flv',config.webPaths.api
},res,req)
},res,req)
})
//Get H.265/h265 HEVC stream
app.get([config.webPaths.apiPrefix+':auth/h265/:ke/:id/s.hevc',config.webPaths.apiPrefix+':auth/h265/:ke/:id/:channel/s.hevc'], function(req,res) {
res.header("Access-Control-Allow-Origin",req.headers.origin);
s.auth(req.params,function(user){
s.checkChildProxy(req.params,function(){
var Emitter,chunkChannel
if(!req.params.channel){
Emitter = s.group[req.params.ke].mon[req.params.id].emitter
chunkChannel = 'MAIN'
}else{
Emitter = s.group[req.params.ke].mon[req.params.id].emitterChannel[parseInt(req.params.channel)+config.pipeAddition]
chunkChannel = parseInt(req.params.channel)+config.pipeAddition
}
//variable name of contentWriter
var contentWriter
//set headers
res.setHeader('Content-Type', 'video/mp4');
res.setHeader('Access-Control-Allow-Origin','*');
//write new frames as they happen
Emitter.on('data',contentWriter=function(buffer){
res.write(buffer)
})
//remove contentWriter when client leaves
res.on('close', function () {
Emitter.removeListener('data',contentWriter)
})
},res,req)
},res,req)
})
//montage - stand alone squished view with gridstackjs
app.get([config.webPaths.apiPrefix+':auth/grid/:ke',config.webPaths.apiPrefix+':auth/grid/:ke/:group'], function(req,res) {
app.get([
config.webPaths.apiPrefix+':auth/grid/:ke',
config.webPaths.apiPrefix+':auth/grid/:ke/:group',
config.webPaths.apiPrefix+':auth/cycle/:ke',
config.webPaths.apiPrefix+':auth/cycle/:ke/:group'
], function(req,res) {
res.header("Access-Control-Allow-Origin",req.headers.origin);
s.auth(req.params,function(user){
if(user.permissions.get_monitors==="0"){
@ -6066,14 +6184,19 @@ app.get([config.webPaths.apiPrefix+':auth/grid/:ke',config.webPaths.apiPrefix+':
}
}
})
res.render(config.renderPaths.grid,{
var page = config.renderPaths.grid
if(req.path.indexOf('/cycle/') > -1){
page = config.renderPaths.cycle
}
res.render(page,{
data:Object.assign(req.params,req.query),
baseUrl:req.protocol+'://'+req.hostname,
config:config,
lang:user.lang,
$user:user,
monitors:r,
originalURL:s.getOriginalUrl(req)
originalURL:s.getOriginalUrl(req),
query:req.query
});
})
},res,req)

View File

@ -486,6 +486,7 @@
"Bottom Left": "Bottom Left",
"WebM (libvpx)": "WebM (libvpx)",
"Poseidon": "Poseidon",
"HEVC (H.265)": "HEVC (H.265)",
"MP4 (copy, libx264, libx265)": "MP4 (copy, libx264, libx265)",
"Default": "Default",
"libvpx (Default)": "libvpx (Default)",

11456
web/libs/js/libde265.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -383,6 +383,9 @@ switch($user.details.lang){
case'flv':
streamURL=$.ccio.init('location',user)+user.auth_token+'/flv/'+d.ke+'/'+d.mid+'/s.flv'
break;
case'h265':
streamURL=$.ccio.init('location',user)+user.auth_token+'/h265/'+d.ke+'/'+d.mid+'/s.hevc'
break;
case'mp4':
streamURL=$.ccio.init('location',user)+user.auth_token+'/mp4/'+d.ke+'/'+d.mid+'/s.mp4'
break;
@ -514,7 +517,7 @@ switch($user.details.lang){
$.ccio.mon_groups[b][v.mid]=v;
})
}catch(er){
}
})
return $.ccio.mon_groups;
@ -655,7 +658,7 @@ switch($user.details.lang){
d.fn=function(){
if(!d.speed){d.speed=1000}
switch(d.d.stream_type){
case'b64':case'pam':
case'b64':case'h265':
d.p.resize()
break;
case'hls':case'flv':case'mp4':
@ -779,7 +782,7 @@ switch($user.details.lang){
image_data.src = base64;
extend(atob(base64),image_data.width,image_data.height)
break;
case'jpeg':
case'jpeg':case'h265':
url=e.p.find('.stream-element').attr('src');
image_data = new Image();
image_data.src = url;
@ -1129,7 +1132,7 @@ switch($user.details.lang){
case'jpeg':
tmp+='<img class="stream-element">';
break;
default://base64
default://base64//h265
tmp+='<canvas class="stream-element"></canvas>';
break;
}
@ -2260,6 +2263,39 @@ $.ccio.globalWebsocket=function(d,user){
case'mjpeg':
$('#monitor_live_'+d.id+user.auth_token+' .stream-element').attr('src',$.ccio.init('location',user)+user.auth_token+'/mjpeg/'+d.ke+'/'+d.id+'/?full=true')
break;
case'h265':
var player = $.ccio.mon[d.ke+d.id+user.auth_token].h265Player
var video = $('#monitor_live_'+d.id+user.auth_token+' .stream-element')[0]
if (player) {
player.stop()
}
player = new libde265.RawPlayer(video)
player.set_status_callback(function(msg, fps) {
})
player.launch()
if($.ccio.mon[d.ke+d.id+user.auth_token].h265Socket && $.ccio.mon[d.ke+d.id+user.auth_token].h265Socket.connected){
$.ccio.mon[d.ke+d.id+user.auth_token].h265Socket.disconnect()
}
$.ccio.mon[d.ke+d.id+user.auth_token].h265Socket = io(url,{transports: ['websocket'], forceNew: false})
var ws = $.ccio.mon[d.ke+d.id+user.auth_token].h265Socket
var buffer
ws.on('diconnect',function(){
console.log('h265Socket Stream Disconnected')
})
ws.on('connect',function(){
ws.emit('h265',{
url: url,
auth: user.auth_token,
uid: user.uid,
ke: d.ke,
id: d.id,
// channel: channel
})
ws.on('data',function(imageData){
player._handle_onChunk(imageData)
})
})
break;
}
}
d.signal=parseFloat(d.d.signal_check);
@ -2420,7 +2456,7 @@ $.ccio.globalWebsocket=function(d,user){
}
}
});
var eventsToCheck = Object.assign({},events)
$.each(data,function(m,b){
startTimeFormatted = $.ccio.timeObject(b.time).format('YYYY-MM-DD HH:mm:ss');
@ -2908,7 +2944,7 @@ $.zO.initCanvas=function(){
$.zO.e.find('.cord_name').text(e.val)
$.zO.f.find('[name="sensitivity"]').val(e.cord.sensitivity)
$.zO.e.find('.canvas_holder canvas').remove();
$.zO.initLiveStream()
e.e=$.zO.ca.val(e.ar.join(','))
e.e.canvasAreaDraw({
@ -2988,7 +3024,7 @@ $.zO.e.on('changed','#regions_canvas',function(e){
})
$.zO.f.submit(function(e){
e.preventDefault();e.e=$(this),e.s=e.e.serializeObject();
return false;
});
$('#regions_points')
@ -3022,7 +3058,7 @@ $.pB.f.submit(function(e){
$.pB.o.empty();
$.pB.e.find('.stop').show();
$.pB.e.find('[type="submit"]').hide();
e.preventDefault();e.e=$(this),e.s=e.e.serializeObject();
e.s.url=e.s.url.trim();
var flags = '';
@ -3183,7 +3219,7 @@ $.multimon.e.find('.import_config').click(function(){
newMon.details.auto_host = Monitor.Device
break;
case'remote':
break;
}
newMon.details = JSON.stringify(newMon.details)
@ -3764,12 +3800,12 @@ $.aM.f.submit(function(ee){
var copyMonitors = $.aM.monitorsForCopy.val();
var chosenSections = [];
var chosenMonitors = {};
if(!copyMonitors||copyMonitors.length===0){
$.ccio.init('note',{title:'<%-cleanLang(lang['No Monitors Selected'])%>',text:'<%-cleanLang(lang.monSavedButNotCopied)%>'})
return
}
$.aM.e.find('[copy]').each(function(n,v){
var el = $(v)
if(el.val() === '1'){
@ -3839,7 +3875,7 @@ $.aM.f.submit(function(ee){
})
console.log(chosenMonitors)
}
$.aM.e.modal('hide')
return false;
});
@ -4655,7 +4691,7 @@ $.timelapse.play = function(x){
clearInterval($.timelapse.interval)
videoNow.currentTime = videoNow.duration
}else{
videoNow.currentTime += .5
videoNow.currentTime += .5
}
},500 / $.timelapse.playRate)
}
@ -4833,7 +4869,7 @@ $.timelapse.e.on('click','[timelapse]',function(){
var vidTime = e.videoNow.duration * percentage;
e.videoNow.currentTime = vidTime;
});
$.ccio.log('$.timelapse',e.video)
$.timelapse.line.find('.timelapse_video').removeClass('active')
e.videoCurrentNow=$.timelapse.display.find('.videoNow')
@ -4954,7 +4990,7 @@ $.pwrvid.e.on('click','[preview]',function(e){
})
if(e.status==1){
$.get($.ccio.init('videoHrefToRead',e.href),function(d){
})
}
var labels=[]
@ -5085,7 +5121,7 @@ $.pwrvid.drawTimeline=function(getData){
e.eventLimit = $('#pvideo_event_limit').val();
if(e.eventLimit===''||isNaN(e.eventLimit)){e.eventLimit=500}
if(e.videoLimit===''||isNaN(e.videoLimit)){e.videoLimit=0}
var getTheData = function(){
e.live_header.text($.ccio.mon[$user.ke+mid+$user.auth_token].name)
e.live.attr('src',$.ccio.init('location',$user)+$user.auth_token+'/embed/'+$user.ke+'/'+mid+'/fullscreen|jquery|relative|gui')
@ -5342,7 +5378,7 @@ $('body')
$.ccio.op(e.localStorage,e.value)
})
.on('click','[system]',function(e){
var e={};
var e={};
e.e=$(this),
e.a=e.e.attr('system');//the function
switch(e.a){
@ -5426,7 +5462,7 @@ $('body')
})
//monitor functions
.on('click','[monitor]',function(){
var e={};
var e={};
e.e=$(this),
e.a=e.e.attr('monitor'),//the function
e.p=e.e.parents('[mid]'),//the parent element for monitor item
@ -5529,7 +5565,7 @@ $('body')
e.d.detector_scale_x=e.width.val();
e.d.detector_scale_y=e.height.val();
}
$.zO.e.modal('show');
$.zO.o().attr('width',e.d.detector_scale_x).attr('height',e.d.detector_scale_y);
$.zO.c.css({width:e.d.detector_scale_x,height:e.d.detector_scale_y});

View File

@ -26,7 +26,7 @@
<%-lang.IdentityText2%>
</blockquote>
<div class="form-group">
<label>
<label>
<div><span><%-lang.Mode%></span></div>
<div><select class="form-control" name="mode" selector="h_m">
<option value="stop"><%-lang.Disabled%></option>
@ -124,10 +124,10 @@
<div class="form-group h_p_input h_p_rtsp">
<label><div><span><%-lang['RTSP Transport']%></span></div>
<div><select class="form-control" detail="rtsp_transport">
<option value="no" selected><%-lang['Auto']%></option>
<option value="tcp"><%-lang['TCP']%></option>
<option value="udp"><%-lang['UDP']%></option>
<option value="http"><%-lang['HTTP']%></option>
<option value="no" selected><%-lang['Auto']%></option>
<option value="tcp"><%-lang['TCP']%></option>
<option value="udp"><%-lang['UDP']%></option>
<option value="http"><%-lang['HTTP']%></option>
</select></div>
</label>
</div>
@ -294,9 +294,9 @@
</div>
<div class="form-group">
<label><div><span><%-lang['Stream Type']%></span></div>
<div><select class="form-control" detail="stream_type" selector="h_st" triggerChange="#add_monitor [detail=stream_vcodec]" triggerChangeIgnore="b64,mjpeg,jpeg">
<div><select class="form-control" detail="stream_type" selector="h_st" triggerChange="#add_monitor [detail=stream_vcodec]" triggerChangeIgnore="b64,mjpeg,jpeg,gif">
<option value="mp4"><%-lang['Poseidon']%></option>
<!-- <option value="pam">PAM</option>-->
<option value="h265"><%-lang['HEVC (H.265)']%></option>
<option value="b64" selected><%-lang['Base64 over Websocket']%></option>
<option value="jpeg"><%-lang['JPEG (Auto Enables JPEG API)']%></option>
<option value="mjpeg"><%-lang['MJPEG']%></option>
@ -305,7 +305,7 @@
</select></div>
</label>
</div>
<div class="form-group h_st_input h_st_flv h_st_mp4">
<div class="form-group h_st_input h_st_flv h_st_mp4 h_st_h265">
<label><div><span><%-lang['Connection Type']%></span></div>
<div><select class="form-control" detail="stream_flv_type" selector="h_st_lat">
<option value="http" selected><%-lang['HTTP']%></option>
@ -323,7 +323,7 @@
<div><input class="form-control" detail="stream_mjpeg_clients" placeholder="20"></div>
</label>
</div>
<div class="h_st_input h_st_hls h_st_flv h_st_mp4">
<div class="h_st_input h_st_hls h_st_flv h_st_mp4 h_st_h265">
<div class="form-group">
<label><div><span><%-lang['HLS Video Encoder']%></span></div>
<div><select class="form-control" detail="stream_vcodec" selector="h_hls_v">
@ -357,7 +357,7 @@
</label>
</div>
</div>
<div class="h_st_input h_st_mjpeg h_st_b64 h_st_hls h_st_flv h_st_mp4 h_hls_v_input h_hls_v_libx264 h_hls_v_libx265 h_hls_v_h264_nvenc h_hls_v_hevc_nvenc h_hls_v_no">
<div class="h_st_input h_st_mjpeg h_st_b64 h_st_hls h_st_gif h_st_flv h_st_mp4 h_st_h265 h_hls_v_input h_hls_v_libx264 h_hls_v_libx265 h_hls_v_h264_nvenc h_hls_v_hevc_nvenc h_hls_v_no">
<div class="h_st_input h_st_hls">
<div class="form-group">
<label><div><span><%-lang['HLS Segment Length']%></span></div>
@ -370,7 +370,7 @@
</label>
</div>
</div>
<div class="form-group h_st_input h_st_hls h_st_flv h_st_mp4">
<div class="form-group h_st_input h_st_hls h_st_flv h_st_mp4 h_st_h265">
<label><div><span><%-lang['HLS Preset']%></span></div>
<div><input class="form-control" detail="preset_stream" placeholder="ultrafast"></div>
</label>
@ -453,8 +453,8 @@
<div class="form-group">
<label><div><span><%-lang['Enabled']%></span></div>
<div><select class="form-control" detail="stream_timestamp" selector="h_tm">
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
</select></div>
</label>
</div>
@ -584,8 +584,8 @@
<div class="form-group">
<label><div><span><%-lang['Record File Type']%></span></div>
<div><select class="form-control" name="ext" selector="h_f">
<option value="webm"><%-lang['WebM (libvpx)']%></option>
<option value="mp4"><%-lang['MP4 (copy, libx264, libx265)']%></option>
<option value="webm"><%-lang['WebM (libvpx)']%></option>
<option value="mp4"><%-lang['MP4 (copy, libx264, libx265)']%></option>
<!-- <option value="mkv">MKV</option> -->
</select></div>
</label>
@ -712,8 +712,8 @@
<div class="form-group">
<label><div><span><%-lang['Enabled']%></span></div>
<div><select class="form-control" detail="timestamp" selector="h_tm">
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
</select></div>
</label>
</div>
@ -1265,8 +1265,8 @@
<div class="form-group">
<label><div><span><%-lang['Controllable']%></span></div>
<div><select class="form-control" detail="control" selector="h_c">
<option value="0"><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0"><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -1279,7 +1279,7 @@
<div class="form-group">
<label><div><span><%-lang['Call Method']%></span></div>
<div><select class="form-control" detail="control_url_method" selector="h_control_call">
<option value="GET">GET (<%-lang.Default%>)</option>
<option value="GET">GET (<%-lang.Default%>)</option>
<option value="PUT">PUT</option>
<option value="POST">POST</option>
<option value="ONVIF">ONVIF</option>
@ -1289,7 +1289,7 @@
<div class="form-group h_control_call_input h_control_call_GET h_control_call_PUT h_control_call_POST">
<label><div><span><%-lang['Digest Authentication']%></span></div>
<div><select class="form-control" detail="control_digest_auth">
<option value="0"><%-lang.No%></option>
<option value="0"><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
@ -1297,7 +1297,7 @@
<div class="form-group">
<label><div><span><%-lang['Stop Command']%></span></div>
<div><select class="form-control" detail="control_stop" selector="h_cs">
<option value="0"><%-lang.No%></option>
<option value="0"><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
@ -1398,8 +1398,8 @@
<div class="form-group">
<label><div><span><%-lang['Copy to Settings']%></span></div>
<div><select class="form-control" id="copy_settings" selector="h_copy_settings">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -1407,32 +1407,32 @@
<div class="form-group">
<label><div><span><%-lang['Copy Connection Settings']%></span></div>
<div><select class="form-control" copy="#monSectionConnection">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Copy Input Settings']%></span></div>
<div><select class="form-control" copy="#monSectionInput">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Copy Stream Settings']%></span></div>
<div><select class="form-control" copy="#monSectionStream,#monSectionStreamTimestamp,#monSectionStreamWatermark">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Copy JPEG API Settings']%></span></div>
<div><select class="form-control" copy="#monSectionJPEGAPI">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -1440,8 +1440,8 @@
<div class="form-group">
<label><div><span><%-lang['Copy Stream Channel Settings']%></span></div>
<div><select class="form-control" copy="stream_channel">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -1449,40 +1449,40 @@
<div class="form-group">
<label><div><span><%-lang['Copy Recording Settings']%></span></div>
<div><select class="form-control" copy="#monSectionRecording">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Copy Detector Settings']%></span></div>
<div><select class="form-control" copy="#monSectionDetector,#monSectionDetectorBuffer,#monSectionLisencePlateDetector,#monSectionNoMotionDetector">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Copy Custom Settings']%></span></div>
<div><select class="form-control" copy="#monSectionCustom">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Copy Group Settings']%></span></div>
<div><select class="form-control" copy="#monSectionGrouping">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Copy Logging Settings']%></span></div>
<div><select class="form-control" copy="#monSectionLogging">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -1511,8 +1511,8 @@
<div class="form-group">
<label><div><span><%-lang['Save Log in SQL']%></span></div>
<div><select class="form-control" detail="sqllog">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -1553,8 +1553,8 @@
</div>
<div style="display:inline-block;margin-right:5px">
<div><select class="form-control btn-default" dropdown_toggle="monedit_user_type" selector="h_us">
<option value="simple" selected><%-lang['Simple']%></option>
<option value="advanced"><%-lang['Advanced']%></option>
<option value="simple" selected><%-lang['Simple']%></option>
<option value="advanced"><%-lang['Advanced']%></option>
</select></div>
</div>
<button type="submit" class="btn btn-success"><i class="fa fa-check"></i> <%-lang.Save%></button>

View File

@ -20,6 +20,7 @@ if(data.url.charAt(data.url.length - 1) !== '/'){
<script src="<%=data.url%>libs/js/poseidon.js"></script>
<script src="<%=data.url%>libs/js/hls.min.js"></script>
<script src="<%=data.url%>libs/js/flv.min.js"></script>
<script src="<%=data.url%>libs/js/libde265.js"></script>
<% if(data.addon){
var ar={}
decodeURI(data.addon).split('|').forEach(function(v){
@ -133,7 +134,7 @@ $(document).ready(function(){
})
</script>
<div class="shinobi_stream" id="<%= data.name %>">
<% switch(mon.details.stream_type){
case'jpeg':
%><img class="stream-element"><%
@ -148,8 +149,8 @@ $(document).ready(function(){
%><canvas class="stream-element"></canvas><%
break;
} %>
<% if(data.addon&&data.addon.indexOf('gui')>-1){ %>
<div class="shinobi_hud">
<div class="shinobi_viewers" title="Current number of viewers"></div>
@ -209,7 +210,7 @@ $(document).ready(function(){
// }
// ctx.getContext("2d").drawImage(image,d.x,d.y,d.width,d.height)
ctx.getContext("2d").drawImage(image,d.x,d.y,ctx.width,ctx.height)
URL.revokeObjectURL($.ccio.mon[d.ke+d.id+user.auth_token].imageUrl)
URL.revokeObjectURL($.shinobi.mon[d.id].imageUrl)
}
ws.on('data',function(imageData){
try{
@ -261,6 +262,39 @@ $(document).ready(function(){
stream.attr('src','<%=data.url%><%=data.auth%>/mp4/'+d.ke+'/'+d.id+'/s.mp4')
}
break;
case'h265':
var player = $.shinobi.mon[d.id].h265Player
var video = $('#SHINOBI_'+d.ke+'_'+d.id+' .stream-element')[0]
if (player) {
player.stop()
}
player = new libde265.RawPlayer(video)
player.set_status_callback(function(msg, fps) {
})
player.launch()
if($.shinobi.mon[d.id].h265Socket && $.shinobi.mon[d.id].h265Socket.connected){
$.shinobi.mon[d.id].h265Socket.disconnect()
}
$.shinobi.mon[d.id].h265Socket = io('<%=data.url%>',{transports: ['websocket'], forceNew: false})
var ws = $.shinobi.mon[d.id].h265Socket
var buffer
ws.on('diconnect',function(){
console.log('h265Socket Stream Disconnected')
})
ws.on('connect',function(){
ws.emit('h265',{
auth:'<%=data.auth%>',
ke:d.ke,
uid:'<%=data.uid%>',
id:d.id,
url: '<%=data.url%>'
// channel: channel
})
ws.on('data',function(imageData){
player._handle_onChunk(imageData)
})
})
break;
case'flv':
if (flvjs.isSupported()) {
if($.shinobi.mon[d.id].flv){
@ -413,4 +447,4 @@ $(document).ready(function(){
$.shinobi.init(monitor);
})
$('.shinobi_ws_http_toggle').show()
</script>
</script>

View File

@ -180,6 +180,7 @@
<script src="<%-originalURL%>libs/js/socket.io.js"></script>
<script src="<%-originalURL%>libs/js/fullcalendar.min.js"></script>
<script src="<%-originalURL%>libs/js/hls.min.js"></script>
<script src="<%-originalURL%>libs/js/libde265.js"></script>
<script type="text/javascript" src="<%-originalURL%>libs/js/flv.shinobi.js">;</script>
<script src="<%-originalURL%>libs/js/menu.js"></script>
<script src="<%-originalURL%>libs/js/clock.js"></script>
@ -194,4 +195,4 @@
<script src="<%-originalURL%>libs/js/gridstack.min.js"></script>
<script src="<%-originalURL%>libs/js/gridstack.jQueryUI.min.js"></script>
<script><% include ../libs/js/main.dash2.js %></script>
<% include blocks/help.ejs %>
<% include blocks/help.ejs %>