<?php include ("./link/session.php") ?><!doctype html><html lang="uft-8"><head><?php include ("./public/head.inc") ?></head><body><?php include ("./public/menu.inc") ?><div data-simplebar><main class="page-content stream" id="app" v-cloak><div class="row"><div class="col-lg-12 mx-auto"><div class="card"><div class="card-header bg-transparent"><div class="p-2 mb-0 d-flex align-items-end"><cn>全局配置</cn><en>Overall config</en></div></div><div class="card-body all" ><div class="row"><div class="col-lg-12" v-if="Object.keys(globalConf).length !== 0"><div class="row"><div class="col-2"></div><div class="col text-center"><cn>HTTP</cn><en>HTTP</en></div><div v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.hls" class="col text-center"><cn>HLS</cn><en>HLS</en></div><div class="col text-center"><cn>RTMP</cn><en>RTMP</en></div><div class="col text-center"><cn>RTSP</cn><en>RTSP</en></div><div class="col text-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.chip !== 'HI3520DV400' && hardwareConf.chip !== 'HI3521DV100' && hardwareConf.chip !== 'HI3531DV100'"><cn>WebRTC</cn><en>WebRTC</en></div><div class="col text-center"><cn>SRT</cn><en>SRT</en></div><div class="col text-center"><cn>RIST</cn><en>RIST</en></div><div class="col text-center"><cn>组播</cn><en>multicast</en></div><div class="col-2 text-center"><cn>组播地址</cn><en>multicast addr</en></div><div class="col"></div></div><div class="row mt-1"><div class="col-2 text-center p-0 pt-2"><cn>主流协议</cn><en>Main protocol</en></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream.http" ></bs-switch></div><div v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.hls" class="col lp-align-center"><bs-switch v-model="globalConf.stream.hls"></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream.rtmp" @switch-change="state => onGlobalProtocolSwitchChange(state,'stream',globalConf.enca.codec,globalConf.encv.codec,globalConf.encv.profile,'rtmp')"></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream.rtsp.enable"></bs-switch></div><div class="col lp-align-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.chip !== 'HI3520DV400' && hardwareConf.chip !== 'HI3521DV100' && hardwareConf.chip !== 'HI3531DV100'"><bs-switch v-model="globalConf.stream.webrtc" @switch-change="state => onGlobalProtocolSwitchChange(state,'stream',globalConf.enca.codec,globalConf.encv.codec,globalConf.encv.profile,'webrtc')"></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream.srt.enable"></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream.rist.enable"></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream.udp.enable"></bs-switch></div><div class="col-2"><multiple-input type="text" class="form-control" v-model:value1="globalConf.stream.udp.ip" v-model:value2="globalConf.stream.udp.port" split=":"></multiple-input></div><div class="col"></div></div><div class="row mt-2"><div class="col-2 text-center p-0 pt-2"><cn>辅流协议</cn><en>Sub protocol</en></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream2.http" ></bs-switch></div><div v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.hls" class="col lp-align-center"><bs-switch v-model="globalConf.stream2.hls" ></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream2.rtmp" @switch-change="state => onGlobalProtocolSwitchChange(state,'stream2',globalConf.enca.codec,globalConf.encv2.codec,globalConf.encv2.profile,'rtmp')"></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream2.rtsp.enable" ></bs-switch></div><div class="col lp-align-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.chip !== 'HI3520DV400' && hardwareConf.chip !== 'HI3521DV100' && hardwareConf.chip !== 'HI3531DV100'"><bs-switch v-model="globalConf.stream2.webrtc" @switch-change="state => onGlobalProtocolSwitchChange(state,'stream2',globalConf.enca.codec,globalConf.encv2.codec,globalConf.encv2.profile,'webrtc')"></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream2.srt.enable" ></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream2.rist.enable"></bs-switch></div><div class="col lp-align-center"><bs-switch v-model="globalConf.stream2.udp.enable" ></bs-switch></div><div class="col-2"><multiple-input type="text" class="form-control" v-model:value1="globalConf.stream2.udp.ip" v-model:value2="globalConf.stream2.udp.port" split=":"></multiple-input></div><div class="col"></div></div><hr class="my-4"><div class="row text-center"><div class="col-lg-12"><button type="button" class="btn border-3 btn-primary me-2" @click="saveGlobalConfByLocal"><cn>应用到全部</cn><en>Apply to all</en></button></div></div></div></div></div></div></div></div><div class="row mt-3"><div class="col-lg-12 mx-auto"><ul class="nav nav-tabs nav-primary" role="tablist"><li class="nav-item" role="presentation"><a class="nav-link active" data-bs-toggle="tab" href="#tab1" role="tab" aria-selected="true"><div class="d-flex align-items-center"><div class="tab-icon"><i class="fa-solid fa-upload me-1"></i></div><div class="tab-title"><cn>码流配置</cn><en>Stream config</en></div></div></a></li><li class="nav-item" role="presentation"><a class="nav-link" data-bs-toggle="tab" href="#tab2" role="tab" aria-selected="false"><div class="d-flex align-items-center"><div class="tab-icon"><i class="fa-solid fa-gear me-1"></i></div><div class="tab-title"><cn>TS设置</cn><en>TS config</en></div></div></a></li><li v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.hls" class="nav-item" role="presentation"><a class="nav-link" data-bs-toggle="tab" href="#tab3" role="tab" aria-selected="false"><div class="d-flex align-items-center"><div class="tab-icon"><i class="fa-solid fa-gear me-1"></i></div><div class="tab-title"><cn>HLS设置</cn><en>HLS config</en></div></div></a></li><li v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.rtspAuth" class="nav-item" role="presentation"><a class="nav-link" data-bs-toggle="tab" href="#tab4" role="tab" aria-selected="false"><div class="d-flex align-items-center"><div class="tab-icon"><i class="fa-solid fa-gear me-1"></i></div><div class="tab-title"><cn>RTSP设置</cn><en>RTSP config</en></div></div></a></li><li v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.srt" class="nav-item" role="presentation"><a class="nav-link" data-bs-toggle="tab" href="#tab5" role="tab" aria-selected="false"><div class="d-flex align-items-center"><div class="tab-icon"><i class="fa-solid fa-gear me-1"></i></div><div class="tab-title"><cn>SRT设置</cn><en>SRT config</en></div></div></a></li><li v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.srt" class="nav-item" role="presentation"><a class="nav-link" data-bs-toggle="tab" href="#tab6" role="tab" aria-selected="false"><div class="d-flex align-items-center"><div class="tab-icon"><i class="fa-solid fa-gear me-1"></i></div><div class="tab-title"><cn>RIST设置</cn><en>RIST config</en></div></div></a></li><li v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.ndi" class="nav-item" role="presentation"><a class="nav-link" data-bs-toggle="tab" href="#tab7" role="tab" aria-selected="false"><div class="d-flex align-items-center"><div class="tab-icon"><i class="fa-solid fa-gear me-1"></i></div><div class="tab-title"><cn>NDI设置</cn><en>NDI config</en></div></div></a></li><li class="nav-item" role="presentation"><a class="nav-link" data-bs-toggle="tab" href="#tab8" role="tab" aria-selected="false"><div class="d-flex align-items-center"><div class="tab-icon"><i class="fa-regular fa-circle-play me-1"></i></div><div class="tab-title"><cn>播放地址</cn><en>Play URL</en></div></div></a></li></ul><div class="tab-content py-3 pe-2 ps-2"><div class="tab-pane fade show active" id="tab1" role="tabpanel"><div class="row d-flex flex-nowrap"><div class="calc-18-3 text-center"><cn>频道名称</cn><en>Channel name</en></div><div class="calc-18-1 text-center"><cn>HTTP</cn><en>HTTP</en></div><div class="calc-18-1 text-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.hls"><cn>HLS</cn><en>HLS</en></div><div class="calc-18-1 text-center"><cn>RTMP</cn><en>RTMP</en></div><div class="calc-18-1 text-center"><cn>RTSP</cn><en>RTSP</en></div><div class="calc-18-1 text-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.chip !== 'HI3520DV400' && hardwareConf.chip !== 'HI3521DV100' && hardwareConf.chip !== 'HI3531DV100'"><cn>WebRTC</cn><en>WebRTC</en></div><div class="calc-18-1 text-center"><cn>SRT</cn><en>SRT</en></div><div class="calc-18-1 text-center"><cn>RIST</cn><en>RIST</en></div><div class="calc-18-1 text-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.ndi"><cn>NDI</cn><en>NDI</en></div><div class="calc-18-1 text-center"><cn>组播</cn><en>multicast</en></div><div class="calc-18-3 text-center"><cn>组播地址</cn><en>multicast addr</en></div></div><hr ><div class="row mt-1" v-for="(item,index) in handleEnableConf" :key="item.id"><div class="col-lg-12"><div class="row d-flex flex-nowrap"><div class="calc-18-3 text-center"><input type="text" class="form-control" v-model.trim.lazy="item.name"></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream.http" ></bs-switch></div><div class="calc-18-1 lp-align-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.hls"><bs-switch v-model="item.stream.hls" ></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream.rtmp" @switch-change="state => onProtocolSwitchChange(item.id,item.name,'stream',state,item.enca.codec,item.encv.codec,item.encv.profile,'rtmp')"></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream.rtsp.enable" ></bs-switch></div><div class="calc-18-1 lp-align-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.chip !== 'HI3520DV400' && hardwareConf.chip !== 'HI3521DV100' && hardwareConf.chip !== 'HI3531DV100'"><bs-switch v-model="item.stream.webrtc" @switch-change="state => onProtocolSwitchChange(item.id,item.name,'stream',state,item.enca.codec,item.encv.codec,item.encv.profile,'webrtc')"></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream.srt.enable" ></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream.rist.enable" ></bs-switch></div><div class="calc-18-1 lp-align-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.ndi"><bs-switch v-model="item.ndi.enable" ></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream.udp.enable" ></bs-switch></div><div class="calc-18-3"><multiple-input type="text" class="form-control" v-model:value1="item.stream.udp.ip" v-model:value2="item.stream.udp.port" split=":"></multiple-input></div></div><div class="row mt-2 d-flex flex-nowrap"><div class="calc-18-3 text-center">[<cn style="margin: 0 14px">辅码流</cn><en style="margin: 0 4px">sub stream</en>]</div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream2.http" ></bs-switch></div><div class="calc-18-1 lp-align-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.hls"><bs-switch v-model="item.stream2.hls" ></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream2.rtmp" @switch-change="state => onProtocolSwitchChange(item.id,item.name,'stream2',state,item.enca.codec,item.encv2.codec,item.encv2.profile,'rtmp')"></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream2.rtsp.enable" ></bs-switch></div><div class="calc-18-1 lp-align-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.chip !== 'HI3520DV400' && hardwareConf.chip !== 'HI3521DV100' && hardwareConf.chip !== 'HI3531DV100'"><bs-switch v-model="item.stream2.webrtc" @switch-change="state => onProtocolSwitchChange(item.id,item.name,'stream2',state,item.enca.codec,item.encv2.codec,item.encv2.profile,'webrtc')"></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream2.srt.enable" ></bs-switch></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream2.rist.enable" ></bs-switch></div><div class="calc-18-1 lp-align-center" v-if="Object.keys(hardwareConf).length > 0 && hardwareConf.function.ndi"></div><div class="calc-18-1 lp-align-center"><bs-switch v-model="item.stream2.udp.enable" ></bs-switch></div><div class="calc-18-3"><multiple-input type="text" class="form-control" v-model:value1="item.stream2.udp.ip" v-model:value2="item.stream2.udp.port" split=":"></multiple-input></div></div><hr ></div></div></div><div class="tab-pane fade" id="tab2" role="tabpanel"><div class="row"><div class="col text-center"><cn>频道名称</cn><en>Channel name</en></div><div class="col-10"><div class="row"><div class="col text-center">TTL</div><div class="col text-center"><cn>流控</cn><en>Flow Control</en></div><div class="col text-center"><cn>带宽</cn><en>Bandwidth</en></div><div class="col text-center">RTP Head</div><div class="col text-center">PID</div><div class="col text-center">PMT PID</div><div class="col text-center">ServiceID</div><div class="col text-center">StreamID</div><div class="col text-center">NetworkID</div><div class="col-2 text-center">PacketSize</div></div></div></div><hr ><div class="row mt-1" v-for="(item,index) in handleEnableConf" :key="item.id"><div class="col-lg-12"><div class="row"><div class="col text-center"><input type="text" class="form-control" v-model.trim.lazy="item.name"></div><div class="col-10"><div class="row"><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream.udp.ttl"></div><div class="col lp-align-center"><bs-switch v-model="item.stream.udp.flowCtrl"></bs-switch></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream.udp.bandwidth"></div><div class="col lp-align-center"><bs-switch v-model="item.stream.udp.rtp"></bs-switch></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.ts.mpegts_start_pid"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.ts.mpegts_pmt_start_pid"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.ts.mpegts_service_id"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.ts.mpegts_transport_stream_id"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.ts.mpegts_original_network_id"></div><div class="col-2"><select class="form-select" v-model="item.ts.tsSize"><option value="188">188</option><option value="376">376</option><option value="564">564</option><option value="752">752</option><option value="940">940</option><option value="1128">1128</option><option value="1316">1316</option><option value="1504">1504</option><option value="1692">1692</option><option value="1880">1880</option></select></div></div></div></div><hr ></div></div></div><div class="tab-pane fade" id="tab3" role="tabpanel"><div class="row"><div class="col-2 text-center"><cn>频道名称</cn><en>Channel name</en></div><div class="col-2 text-center"><cn>分片长度(秒)</cn><en>Segment length(s)</en></div><div class="col-2 text-center"><cn>列表长度</cn><en>List length</en></div><div class="col-2 text-center"><cn>URL前缀</cn><en>Base url</en></div><div class="col-2 text-center"><cn>文件名后缀</cn><en>Name format</en></div></div><hr ><div class="row mt-1" v-for="(item,index) in handleEnableConf" :key="item.id"><div class="col-lg-12"><div class="row"><div class="col-2 text-center"><input type="text" class="form-control" v-model.trim.lazy="item.name"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.hls.hls_time"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.hls.hls_list_size"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.hls.hls_base_url"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.hls.hls_filename"></div></div><hr ></div></div></div><div class="tab-pane fade" id="tab4" role="tabpanel"><div class="row"><div class="col-2 text-center"><cn>频道名称</cn><en>Channel name</en></div><div class="col-2 text-center"><cn>用户名</cn><en>username</en></div><div class="col-2 text-center"><cn>密码</cn><en>password</en></div><div class="col-1 text-center"><cn>启用认证</cn><en>auth</en></div><div class="col-1 text-center"><cn>Onvif</cn><en>onvif</en></div><div class="col-1 text-center"><cn>开关</cn><en>enable</en></div></div><hr ><div class="row mt-1" v-for="(item,index) in defaultConf" :key="item.id"><div class="col-lg-12"><div class="row"><div class="col-2 text-center"><input type="text" class="form-control" v-model.trim.lazy="item.name"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.stream.rtsp.name"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.stream.rtsp.passwd"></div><div class="col-1 lp-align-center"><bs-switch v-model="item.stream.rtsp.auth"></bs-switch></div><div class="col-1 lp-align-center"><bs-switch v-model="item.stream.rtsp.onvif" @switch-change="state => onSwitchOnvif(state,item.id,'stream')"></bs-switch></div><div class="col-1 lp-align-center"><bs-switch v-model="item.stream.rtsp.enable"></bs-switch></div></div><div class="row mt-2"><div class="col-2 text-center">[<cn style="margin: 0 14px">辅码流</cn><en style="margin: 0 4px">sub stream</en>]</div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.rtsp.name"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.rtsp.passwd"></div><div class="col-1 lp-align-center"><bs-switch v-model="item.stream2.rtsp.auth"></bs-switch></div><div class="col-1 lp-align-center"><bs-switch v-model="item.stream2.rtsp.onvif" @switch-change="state => onSwitchOnvif(state,item.id,'stream2')"></bs-switch></div><div class="col-1 lp-align-center"><bs-switch v-model="item.stream2.rtsp.enable"></bs-switch></div></div><hr ></div></div><div class="row mt-3"><div class="col-lg-12 tips"><cn>1、最多开启 2 条 ONVIF 输出流,修改ONVIF设置后,重启设备生效。</cn><en>1. Up to 2 ONVIF output streams allowed.After modifying the ONVIF settings,the device needs to be restarted for the changes to take effect.</en></div><div class="col-lg-12 tips"><cn>2、ONVIF 输出流可以任意搭配,比如同时使用2个通道的主码流等。</cn><en>2. ONVIF output streams can be freely combined, such as using main streams from two channels at the same time.</en></div></div></div><div class="tab-pane fade" id="tab5" role="tabpanel"><div class="row"><div class="col-2 text-center"><cn>频道名称</cn><en>Channel name</en></div><div class="col text-center"><cn>模式</cn><en>Mode</en></div><div class="col text-center">IP</div><div class="col text-center">StreamID</div><div class="col text-center"><cn>端口</cn><en>Port</en></div><div class="col text-center"><cn>延时</cn><en>Latency</en></div><div class="col text-center"><cn>密码</cn><en>Password</en></div><div class="col text-center"><cn>开关</cn><en>Enable</en></div></div><hr ><div class="row mt-1" v-for="(item,index) in handleEnableConf" :key="item.id"><div class="col-lg-12"><div class="row"><div class="col-2 text-center"><input type="text" class="form-control" v-model.trim.lazy="item.name"></div><div class="col"><select class="form-select" v-model="item.stream.srt.mode"><option value="caller">caller</option><option value="listener">listener</option><option value="rendezvous">rendezvous</option></select></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream.srt.ip"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream.srt.streamid"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream.srt.port"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream.srt.latency"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream.srt.passwd"></div><div class="col lp-align-center"><bs-switch v-model="item.stream.srt.enable"></bs-switch></div></div><div class="row mt-2"><div class="col-2 text-center">[<cn style="margin: 0 14px">辅码流</cn><en style="margin: 0 4px">sub stream</en>]</div><div class="col"><select class="form-select" v-model="item.stream2.srt.mode"><option value="caller">caller</option><option value="listener">listener</option><option value="rendezvous">rendezvous</option></select></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.srt.ip"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.srt.streamid"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.srt.port"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.srt.latency"></div><div class="col"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.srt.passwd"></div><div class="col lp-align-center"><bs-switch v-model="item.stream2.srt.enable"></bs-switch></div></div><hr ></div></div></div><div class="tab-pane fade" id="tab6" role="tabpanel"><div class="row"><div class="col-2 text-center"><cn>频道名称</cn><en>Channel name</en></div><div class="col-2 text-center"><cn>地址</cn><en>IP</en></div><div class="col-2 text-center"><cn>端口</cn><en>Port</en></div><div class="col-1 text-center"><cn>开关</cn><en>Enable</en></div></div><hr ><div class="row mt-1" v-for="(item,index) in handleEnableConf" :key="item.id"><div class="col-lg-12"><div class="row"><div class="col-2 text-center"><input type="text" class="form-control" v-model.trim.lazy="item.name"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.stream.rist.ip"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.stream.rist.port"></div><div class="col-1 lp-align-center"><bs-switch v-model="item.stream.rist.enable"></bs-switch></div></div><div class="row mt-2"><div class="col-2 text-center">[<cn style="margin: 0 14px">辅码流</cn><en style="margin: 0 4px">sub stream</en>]</div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.rist.ip"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.rist.port"></div><div class="col-1 lp-align-center"><bs-switch v-model="item.stream2.rist.enable"></bs-switch></div></div><hr ></div></div></div><div class="tab-pane fade" id="tab7" role="tabpanel"><div class="row"><div class="col-2 text-center"><cn>频道名称</cn><en>Channel name</en></div><div class="col-2 text-center"><cn>NDI名称</cn><en>NDI name</en></div><div class="col-2 text-center"><cn>NDI分组</cn><en>NDI group</en></div><div class="col-1 text-center"><cn>开关</cn><en>Enable</en></div></div><hr ><div class="row mt-1" v-for="(item,index) in handleEnableConf" :key="item.id"><div class="col-lg-12"><div class="row"><div class="col-2 text-center"><input type="text" class="form-control" v-model.trim.lazy="item.name"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.ndi.name"></div><div class="col-2"><input type="text" class="form-control" v-model.trim.lazy="item.ndi.group"></div><div class="col-1 lp-align-center"><bs-switch v-model="item.ndi.enable"></bs-switch></div></div><hr ></div></div></div><div class="tab-pane fade" id="tab8" role="tabpanel"><div class="row"><div class="col-2 text-center"><cn>频道名称</cn><en>Channel name</en></div><div class="col-5"><div class="row"><div class="col-3 text-center"><cn>主码流标识</cn><en>Main Suffix</en></div><div class="col text-center"><cn>主码流地址</cn><en>Main URL</en></div></div></div><div class="col-5"><div class="row"><div class="col-3 text-center"><cn>辅码流标识</cn><en>Sub Suffix</en></div><div class="col text-center"><cn>辅码流地址</cn><en>Sub URL</en></div></div></div></div><hr ><div class="row mt-1" v-for="(item,index) in handleEnableConf" :key="item.id"><div class="col-lg-12"><div class="row"><div class="col-2 text-center"><input type="text" class="form-control" v-model.trim.lazy="item.name"></div><div class="col-5"><div class="row"><div class="col-3"><input type="text" class="form-control" v-model.trim.lazy="item.stream.suffix"></div><div class="col"><div class="play-url"><div class="row"><div class="col-lg-12 mt-1" v-for="(item,urlIdx) in handlePlayUrl(index,'main')"><div class="input-group"><input class="form-control" v-model.trim.lazy="item" disabled readonly><button class="btn btn-primary input-group-text input-group-addon lp-cursor-pointer"@click="onCopyPlayerUrl(index,urlIdx,'main')"><i class="fa-regular fa-copy"></i></button></div></div></div></div></div></div></div><div class="col-5"><div class="row"><div class="col-3"><input type="text" class="form-control" v-model.trim.lazy="item.stream2.suffix"></div><div class="col"><div class="play-url"><div class="row"><div class="col-lg-12 mt-1" v-for="(item,urlIdx) in handlePlayUrl(index,'sub')"><div class="input-group"><input class="form-control" v-model.trim.lazy="item" disabled readonly><button class="btn btn-primary input-group-text input-group-addon lp-cursor-pointer"@click="onCopyPlayerUrl(index,urlIdx,'sub')"><i class="fa-regular fa-copy"></i></button></div></div></div></div></div></div></div></div><hr ></div></div></div><div class="row mt-3"><div class="col-lg-12 text-center"><button type="button" class="btn btn-primary border-3 px-5" @click="saveDefaultConf"><cn>保存</cn><en>Save</en></button></div></div></div></div></div><warn-modal :modal-title="'警告&Warning'" :modal-show="showWarnModal":confirm-btn-name="'确定&OK'" :cancel-btn-name="'取消&Cancel'"@confirm-btn-click="onWarnConfirm" @modal-visible="onWarnModalVisible"><div class="row"><div class="col-lg-12"><div class="row"><div class="col-lg-12 mb-1" v-if="warnConf.chnId === 'global' && warnConf.type === 'rtmp'"><cn>检测到下面列表中,频道的音频编码是OPUS</cn><en>Detected OPUS audio in the following channels.</en></div><div class="col-lg-12 mb-1" v-if="warnConf.chnId === 'global' && warnConf.type === 'webrtc'"><cn>检测到下面列表中,音频编码不是OPUS或者视频编码不是H264</cn><en>Detected audio not using OPUS or video not using H264 in the following channels.</en></div><div class="col-lg-12" v-if="warnConf.type === 'rtmp'"><cn>RTMP不支持音频OPUS编码,请调整编码格式</cn><en>RTMP does not support OPUS audio codec.</en></div><div class="col-lg-12" v-if="warnConf.type === 'webrtc'"><cn>WebRTC仅支持音频OPUS编码和视频H264编码,请调整编码格式</cn><en>WebRTC only supports OPUS for audio and H264 for video.</en></div></div><div class="row mt-3" v-if="warnConf.chnId === 'global'"><div class="col-lg-3 lp-align-center"><cn>应用列表:</cn><en>Channel: </en></div><div class="col-lg-5 d-flex align-items-center ps-0"><select class="form-select"><option v-for="item in warnConf.chnList" :value="item.id">{{item.name}}</option></select></div></div><div class="row mt-3" v-if="warnConf.chnId !== 'global'"><div class="col-lg-3 lp-align-center"><cn>应用频道:</cn><en>Channel:</en></div><div class="col-lg-5 d-flex align-items-center ps-0"><input class="form-control" v-model.trim.lazy="warnConf.chnName" readonly disabled></div></div><div class="row mt-2"><div class="col-lg-3 lp-align-center"><cn>音频编码:</cn><en>Audio codec</en></div><div class="col-lg-5 d-flex align-items-center ps-0"><select class="form-select" v-model.trim.lazy="warnConf.codecA"><option value="aac">AAC</option><option value="aache">AAC-HE</option><option value="pcma">PCMA</option><option value="mp2">MPEG2</option><option value="mp3">MP3</option><option value="opus">OPUS</option><option value="close" cn="关闭" en="close" v-language-option></option></select></div></div><div class="row mt-2" v-if="warnConf.type === 'webrtc'"><div class="col-lg-3 lp-align-center"><cn>视频编码:</cn><en>Video codec</en></div><div class="col-lg-5 d-flex align-items-center ps-0"><multiple-select v-model:value1="warnConf.codecV" v-model:value2="warnConf.profile" split=","><option value="h264,base">H.264 Base</option><option value="h264,main">H.264 Main</option><option value="h264,high">H.264 High</option><option value="h265,main">H.265 Main</option><option value="close,base" cn="关闭" en="Close" v-language-option></option></multiple-select></div></div><div class="row mt-3"><div class="col-lg-12 mt-1" v-if="warnConf.type === 'rtmp' && warnConf.codecA !== 'close'"><cn>注意:点击确定会打开RTMP,同时会关闭WebRTC</cn><en>Tip: Clicking OK will open the RTMP and close the WebRTC.</en></div><div class="col-lg-12 mt-1" v-if="warnConf.type === 'webrtc' && warnConf.codecA !== 'close'"><cn>注意:点击确定会打开WebRTC,同时会关闭RTMP</cn><en>Tip: Clicking OK will open the WebRTC and close the RTMP.</en></div></div></div></div></warn-modal></main></div><?php include ("./public/foot.inc") ?><script type="module">import {alertMsg, rpc, extend, deepCopy, clearReactiveObject, isEmpty, clearReactiveArray,confirm} from "./assets/js/lp.utils.js?hash=e82520f08";import { useDefaultConf,useHardwareConf,usePortConf } from "./assets/js/vue.hooks.js?hash=89523e901";import { ignoreCustomElementPlugin,filterKeywordPlugin,bootstrapSwitchComponent,multipleInputComponent,customModalComponent,multipleSelectComponent,languageOptionDirective } from "./assets/js/vue.helper.js?hash=68eefc36f"import vue from "./assets/js/vue.build.js?hash=879ea7dbc";const {createApp,ref,reactive,toRefs,watch,watchEffect,computed} = vue;const app = createApp({directives:{"language-option": languageOptionDirective},components:{"bs-switch" : bootstrapSwitchComponent,"multiple-input": multipleInputComponent,"warn-modal": customModalComponent,"multiple-select": multipleSelectComponent},setup(props,context) {const { defaultConf,updateDefaultConf } = useDefaultConf();const { hardwareConf } = useHardwareConf();const { portConf } = usePortConf();const state = {globalConf : reactive({}),playUrls:reactive([]),pushSpeed: reactive([]),showWarnModal: ref(false),isConfirm: ref(false),warnConf: reactive({chnId:-1,chnName:"",chnList:[],stream:"stream",codecA:"aac",codecV:"h264",profile:"high",type:"rtmp"})}const getport = (type) => {const list =portConf[type];if(list[2] !== list[0])return list[2];else if(list[1] !== list[0])return list[1];else if((type === "http" && list[0] === 80) || (type === "rtsp" && list[0] === 554) ||(type === "rtmp" && list[0] === 1935) || (type === "httpts" && list[0] === 8090))return "";elsereturn list[0];}const transURL = stream => {const urls = [];if (stream.http) {const port = getport("httpts");const portPart = port ? `:${port}` : '';urls.push(`http://${window.location.hostname}${portPart}/live/${stream.suffix}`);}if (stream.hls)urls.push(`http://${window.location.host}/hls/${stream.suffix}.m3u8`);if (stream.rtmp) {const port = getport("rtmp");const portPart = port ? `:${port}` : '';urls.push(`rtmp://${window.location.hostname}${portPart}/live/${stream.suffix}`);let flvUrl = `http://${window.location.host}/flv?app=live&stream=${stream.suffix}`;if(port)flvUrl += `&port=${port}`;urls.push(flvUrl);}if (stream.rtsp.enable) {const port = getport("rtsp");const portPart = port ? `:${port}` : '';if(stream.rtsp.auth) {const name = stream.rtsp.name;const passwd = stream.rtsp.passwd;urls.push(`rtsp://${name}:${passwd}@${window.location.host}${portPart}/${stream.suffix}`);} elseurls.push(`rtsp://${window.location.host}${portPart}/${stream.suffix}`);}if (stream.srt.enable) {const mode = stream.srt.mode === "listener" ? "caller" : "listener";const ip = stream.srt.ip === "127.0.0.1" ? window.location.hostname : stream.srt.ip;let url = `srt://${ip}:${stream.srt.port}?mode=${mode}`if(!isEmpty(stream.srt.latency))url += `&latency=${stream.srt.latency}`;if(!isEmpty(stream.srt.passwd))url += `&passphrase=${stream.srt.passwd}`;if(!isEmpty(stream.srt.streamid))url += `&streamid=${stream.srt.streamid}`;urls.push(url);}if (stream.webrtc)urls.push(`http://${window.location.host}/webrtc?app=live&stream=${stream.suffix}`);if(stream.udp.enable)urls.push(`udp://@${stream.udp.ip}:${stream.udp.port}`)if(stream?.rist.enable) {let url = `rist://${stream.rist.ip}:${stream.rist.port}`;url = url.replace("@0.0.0.0",window.location.host);url = url.replace("@127.0.0.1",window.location.host);url = url.replace("127.0.0.1",window.location.host);urls.push(url);}return urls;};const updatePlayUrl = () => {clearReactiveArray(state.playUrls);defaultConf.forEach(item => {if (!item.enable && !item.enable2) return;state.playUrls.push({main: transURL(item.stream),sub: transURL(item.stream2)});});}const onCopyPlayerUrl = (chnIndex,urlIndex,type) => {const chnUrl = state.playUrls[chnIndex];const urls = chnUrl[type];const url = urls[urlIndex];const textarea = document.createElement("textarea");textarea.value = url;document.body.appendChild(textarea);textarea.select();let success = document.execCommand("copy");document.body.removeChild(textarea);if (!success) {alertMsg('<cn>复制失败,请手动复制</cn><en>Copy failed, please copy manually</en>', 'error');return;}alertMsg('<cn>已复制</cn><en>Have copied</en>', 'success');}const getPushSpeed = () => {rpc("enc.getPushSpeed").then(data => {state.pushSpeed.splice(0, state.pushSpeed.length, ...data);});setTimeout(getPushSpeed,2000);}const unwatch = watchEffect(()=>{if(defaultConf.length > 0 && Object.keys(portConf).length >0 && Object.keys(hardwareConf).length > 0) {for (let i = 0; i < defaultConf.length; i++) {if(defaultConf[i].hasOwnProperty("stream")) {let rtsp = defaultConf[i].stream.rtsp;if(!rtsp.hasOwnProperty("onvif"))rtsp.onvif = (i===0 && hardwareConf.chip !== "SS626V100");if(!defaultConf[i].stream.hasOwnProperty("suffix"))defaultConf[i].stream.suffix = "stream"+defaultConf[i].id;if(!defaultConf[i].stream.hasOwnProperty("rist")) {defaultConf[i].stream.rist = {enable: false,ip: "@0.0.0.0",port: 9601+i}}}if(defaultConf[i].hasOwnProperty("stream2")) {let rtsp = defaultConf[i].stream2.rtsp;if(!rtsp.hasOwnProperty("onvif"))rtsp.onvif = (i===0 && hardwareConf.chip !== "SS626V100");if(!defaultConf[i].stream2.hasOwnProperty("suffix"))defaultConf[i].stream2.suffix = "sub"+defaultConf[i].id;if(!defaultConf[i].stream2.hasOwnProperty("rist")) {defaultConf[i].stream2.rist = {enable: false,ip: "@0.0.0.0",port: 9701+i}}}}Object.assign(state.globalConf, deepCopy(defaultConf[0]))if(hardwareConf.chip === 'SS626V100') {clearReactiveObject(state.globalConf);Object.assign(state.globalConf, deepCopy(defaultConf[defaultConf.length-1]));}state.globalConf.stream.udp.port += "+";state.globalConf.stream2.udp.port += "+";updatePlayUrl();getPushSpeed();unwatch();}})const handlePushSpeed = (index) => {return state.pushSpeed[index];}const handleEnableConf = computed(()=> {return defaultConf.filter(item => {if(hardwareConf.chip === 'SS626V100')return item.type !== 'net' && !!(item.enable || item.enable2);return !!(item.enable || item.enable2);})})const handlePlayUrl = (index,type)=>{if(state.playUrls.length > index)return state.playUrls[index][type];return "";}const onProtocolSwitchChange = (chnId,chnName,stream,open,codecA,codecV,profile,type) => {if(open) {state.warnConf.chnId = chnId;state.warnConf.chnName = chnName;state.warnConf.stream = stream;state.warnConf.codecA = codecA;state.warnConf.codecV = codecV;state.warnConf.profile = profile;state.warnConf.type = type;if ((type === "rtmp" && codecA === "opus") || (type === "webrtc" && ((codecA !== "opus" && codecA !== "close") || codecV !== "h264"))){state.showWarnModal.value = true;if(type === "rtmp" && codecA === "opus")state.warnConf.codecA="aac";if(type === "webrtc") {if(codecA !== "opus" && codecA !== "close")state.warnConf.codecA = "opus";if(codecV !== "h264")state.warnConf.codecV = "h264"}}}}const onWarnConfirm = () => {const { chnId,stream,codecA,codecV,type } = state.warnConf;if(type === "rtmp" && codecA === "opus") {alertMsg("<cn>RTMP协议流,不支持音频OPUS编码</cn><en>RTMP stream does not support OPUS audio codec.</en>", "error",5000);return;}if(type === "webrtc" && ((codecA !== "opus" && codecA !== "close") || codecV !== "h264")) {alertMsg("<cn>WebRTC协议流,仅支持音频OPUS编码,视频H264编码</cn><en>WebRTC stream only supports OPUS audio codec and H264 video codec..</en>", "error",5000);return;}if(chnId === "global") {state.isConfirm.value = true;state.globalConf[stream==="stream"?"encv":"encv2"].codec = codecV;state.globalConf[stream][type]=true;state.globalConf.enca.codec = codecA;if(type === "rtmp" && codecA !== "opus" && codecA !== "close") {state.globalConf.stream.webrtc = false;state.globalConf.stream2.webrtc = false;}if(type === "webrtc" && codecA === "opus") {state.globalConf.stream.rtmp = false;state.globalConf.stream2.rtmp = false;}state.showWarnModal.value = false;} else {defaultConf.forEach(item => {if(item.id === chnId) {item[stream==="stream"?"encv":"encv2"].codec = codecV;item[stream][type]=true;item.enca.codec = codecA;if(type === "rtmp" && codecA !== "opus" && codecA !== "close") {item.stream.webrtc = false;item.stream2.webrtc = false;}if(type === "webrtc" && codecA === "opus") {item.stream.rtmp = false;item.stream2.rtmp = false;}state.showWarnModal.value = false;}})}}const onWarnModalVisible = visible => {if(!visible) {state.showWarnModal.value = false;const { chnId,stream,type } = state.warnConf;setTimeout(()=>{if(chnId === "global") {if(!state.isConfirm.value) {let openRtmp = true, openWebrtc = true;for (let i = 0; i < defaultConf.length; i++) {const item = defaultConf[i];if (item.enca && item.enca.codec === "opus")openRtmp = false;const encv = stream === "stream" ? "encv" : "encv2";if ((item.enca && item.enca.codec !== "opus" && item.enca.codec !== "close") || (item[encv] && item[encv].codec !== "h264" && item[encv].codec !== "close"))openWebrtc = false;}if(type === "rtmp")state.globalConf[stream].rtmp = openRtmp;if(type === "webrtc")state.globalConf[stream].webrtc = openWebrtc;}state.isConfirm.value = false;} else {defaultConf.forEach(item => {if(item.id === chnId) {if(item.enca.codec === "opus")item[stream].rtmp = false;if(item.enca.codec !== "opus" && item.enca.codec !== "close")item[stream].webrtc = false;}})}},500);}}const onSwitchOnvif = (state,chnId,type) => {if(state) {let count = 0;defaultConf.forEach(item => {["stream", "stream2"].forEach(stream => {if(item.hasOwnProperty(stream)) {let hadOnvif = item[stream].rtsp.onvif;if(hadOnvif)count++;}})});if(count > 2) {alertMsg("<cn>最多任选 2 条 ONVIF 输出流,请重新调整设置</cn><en>Select up to 2 ONVIF output streams only. Please adjust the settings.</en>", "warning",5000);setTimeout(()=>{defaultConf.forEach(item => {if(item.id === chnId)item[type].rtsp.onvif = false;})},800)}}}const onGlobalProtocolSwitchChange = (open,stream,codecA,codecV,profile,type) => {if(open) {let chnList = [];defaultConf.forEach(item => {let showWarn = false;if(type === "rtmp" && item.enca && item.enca.codec === "opus")showWarn = true;const encv = stream==="stream"?"encv":"encv2";if(type === "webrtc" && ((item.enca && item.enca.codec !== "opus" && item.enca.codec !== "close") || (item.hasOwnProperty(encv) && item[encv].codec !== "h264")))showWarn = true;if(showWarn)chnList.push(item);})state.warnConf.chnId = "global";state.warnConf.chnList.splice(0, state.warnConf.chnList.length, ...chnList);state.warnConf.stream = stream;state.warnConf.codecA = codecA;state.warnConf.codecV = codecV;state.warnConf.profile = profile;state.warnConf.type = type;state.showWarnModal.value = chnList.length > 0;if ((type === "rtmp" && codecA === "opus") || (type === "webrtc" && ((codecA !== "opus" && codecA !== "close") || codecV !== "h264"))){state.showWarnModal.value = true;if(type === "rtmp" && codecA === "opus")state.warnConf.codecA="aac";if(type === "webrtc") {if(codecA !== "opus" && codecA !== "close")state.warnConf.codecA = "opus";if(codecV !== "h264")state.warnConf.codecV = "h264"}}}}const saveGlobalConfByLocal = () => {let globalConf = deepCopy(state.globalConf);for ( let i = 0; i < defaultConf.length; i++ ) {if (!defaultConf[i].enable || !defaultConf[i].stream || !defaultConf[i].enca)continue;for (let key of ['stream','stream2']) {delete globalConf[key].suffix;delete globalConf[key].rtsp.onvif;delete globalConf[key].srt.port;delete globalConf[key].rist.port;extend(defaultConf[i][key], deepCopy(globalConf[key]));let port = defaultConf[i][key].udp.port;if(typeof port === "string" && port.indexOf("+") > 0) {port = port.replace(/[+\s]/g, '');port = isNaN(Number(port)) ? (3000+i) : (Number(port)+i);defaultConf[i][key].udp.port = port;}if(globalConf[key].rtmp && defaultConf[i].enca.codec === "opus")defaultConf[i].enca.codec = globalConf.enca.codec;if(globalConf[key].webrtc && defaultConf[i].enca.codec !== "opus" && defaultConf[i].enca.codec !== "close")defaultConf[i].enca.codec =globalConf.enca.codec;const encv = key==="stream"?"encv":"encv2";if(globalConf[key].webrtc && defaultConf[i][encv].codec !== "h264") {defaultConf[i][encv].codec = globalConf[encv].codec;defaultConf[i][encv].profile = globalConf[encv].profile;}}}saveDefaultConf();}const saveDefaultConf = () => {let count = 0;defaultConf.forEach(item => {["stream", "stream2"].forEach(stream => {if(item.hasOwnProperty(stream)) {let hadOnvif = item[stream].rtsp.onvif;if(hadOnvif)count++;}})});if (count < 2 ) {const targetItem = defaultConf.find(item =>item.stream.rtsp.onvif || item.stream2.rtsp.onvif) || defaultConf[0];targetItem.stream.rtsp.onvif = true;targetItem.stream2.rtsp.onvif = true;}if(count > 2) {for(let i=0;i<defaultConf.length;i++) {const item = defaultConf[i];["stream", "stream2"].forEach(stream => {if(item.hasOwnProperty(stream)) {item[stream].rtsp.onvif = false;if(hardwareConf.chip !== 'SS626V100' && i === 0)item[stream].rtsp.onvif = true;if(hardwareConf.chip === 'SS626V100' && i === defaultConf.length-1)item[stream].rtsp.onvif = true;}})}}updateDefaultConf().then(updatePlayUrl);}return {...state,defaultConf,hardwareConf,handleEnableConf,handlePlayUrl,handlePushSpeed,onProtocolSwitchChange,onWarnConfirm,onWarnModalVisible,onSwitchOnvif,onGlobalProtocolSwitchChange,saveGlobalConfByLocal,saveDefaultConf,onCopyPlayerUrl}}});app.use(ignoreCustomElementPlugin);app.use(filterKeywordPlugin);app.mount('#app');</script></body></html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。