mirror of
https://github.com/cnotch/ipchub.git
synced 2025-09-26 19:41:18 +08:00
Update the library to streamedian_3.1
This commit is contained in:
BIN
demos/wsp/favicon.png
Normal file
BIN
demos/wsp/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
File diff suppressed because it is too large
Load Diff
502
demos/wsp/streamedian_1_8_5_3.min.js → demos/wsp/free.player.3.1.js
Executable file → Normal file
502
demos/wsp/streamedian_1_8_5_3.min.js → demos/wsp/free.player.3.1.js
Executable file → Normal file
@@ -61,8 +61,6 @@
|
|||||||
}
|
}
|
||||||
const Log = new Logger();
|
const Log = new Logger();
|
||||||
|
|
||||||
// export * from 'bp_logger';
|
|
||||||
|
|
||||||
class Url {
|
class Url {
|
||||||
static parse(url) {
|
static parse(url) {
|
||||||
let ret = {};
|
let ret = {};
|
||||||
@@ -275,8 +273,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// export * from 'bp_event';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate MP4 Box
|
* Generate MP4 Box
|
||||||
* got from: https://github.com/dailymotion/hls.js
|
* got from: https://github.com/dailymotion/hls.js
|
||||||
@@ -2012,7 +2008,6 @@
|
|||||||
case NALU.EOSEQ:
|
case NALU.EOSEQ:
|
||||||
case NALU.EOSTR:
|
case NALU.EOSTR:
|
||||||
push = false;
|
push = false;
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
if (push === null && unit.getNri() > 0 ) {
|
if (push === null && unit.getNri() > 0 ) {
|
||||||
push=true;
|
push=true;
|
||||||
@@ -2022,10 +2017,10 @@
|
|||||||
|
|
||||||
static parceSliceHeader(data) {
|
static parceSliceHeader(data) {
|
||||||
let decoder = new ExpGolomb(data);
|
let decoder = new ExpGolomb(data);
|
||||||
let first_mb = decoder.readUEG();
|
decoder.readUEG();
|
||||||
let slice_type = decoder.readUEG();
|
let slice_type = decoder.readUEG();
|
||||||
let ppsid = decoder.readUEG();
|
decoder.readUEG();
|
||||||
let frame_num = decoder.readUByte();
|
decoder.readUByte();
|
||||||
// console.log(`first_mb: ${first_mb}, slice_type: ${slice_type}, ppsid: ${ppsid}, frame_num: ${frame_num}`);
|
// console.log(`first_mb: ${first_mb}, slice_type: ${slice_type}, ppsid: ${ppsid}, frame_num: ${frame_num}`);
|
||||||
return slice_type;
|
return slice_type;
|
||||||
}
|
}
|
||||||
@@ -2067,16 +2062,15 @@
|
|||||||
frameCropTopOffset = 0,
|
frameCropTopOffset = 0,
|
||||||
frameCropBottomOffset = 0,
|
frameCropBottomOffset = 0,
|
||||||
sarScale = 1,
|
sarScale = 1,
|
||||||
profileIdc,profileCompat,levelIdc,
|
profileIdc,numRefFramesInPicOrderCntCycle, picWidthInMbsMinus1,
|
||||||
numRefFramesInPicOrderCntCycle, picWidthInMbsMinus1,
|
|
||||||
picHeightInMapUnitsMinus1,
|
picHeightInMapUnitsMinus1,
|
||||||
frameMbsOnlyFlag,
|
frameMbsOnlyFlag,
|
||||||
scalingListCount;
|
scalingListCount;
|
||||||
decoder.readUByte();
|
decoder.readUByte();
|
||||||
profileIdc = decoder.readUByte(); // profile_idc
|
profileIdc = decoder.readUByte(); // profile_idc
|
||||||
profileCompat = decoder.readBits(5); // constraint_set[0-4]_flag, u(5)
|
decoder.readBits(5); // constraint_set[0-4]_flag, u(5)
|
||||||
decoder.skipBits(3); // reserved_zero_3bits u(3),
|
decoder.skipBits(3); // reserved_zero_3bits u(3),
|
||||||
levelIdc = decoder.readUByte(); //level_idc u(8)
|
decoder.readUByte(); //level_idc u(8)
|
||||||
decoder.skipUEG(); // seq_parameter_set_id
|
decoder.skipUEG(); // seq_parameter_set_id
|
||||||
// some profiles have more optional data we don't need
|
// some profiles have more optional data we don't need
|
||||||
if (profileIdc === 100 ||
|
if (profileIdc === 100 ||
|
||||||
@@ -2442,14 +2436,17 @@
|
|||||||
|
|
||||||
class PayloadType {
|
class PayloadType {
|
||||||
static get H264() {return 1;}
|
static get H264() {return 1;}
|
||||||
|
static get H265() {return 1;}
|
||||||
static get AAC() {return 2;}
|
static get AAC() {return 2;}
|
||||||
|
|
||||||
static get map() {return {
|
static get map() {return {
|
||||||
|
[PayloadType.H265]: 'video',
|
||||||
[PayloadType.H264]: 'video',
|
[PayloadType.H264]: 'video',
|
||||||
[PayloadType.AAC]: 'audio'
|
[PayloadType.AAC]: 'audio'
|
||||||
}};
|
}};
|
||||||
|
|
||||||
static get string_map() {return {
|
static get string_map() {return {
|
||||||
|
H265: PayloadType.H265,
|
||||||
H264: PayloadType.H264,
|
H264: PayloadType.H264,
|
||||||
AAC: PayloadType.AAC,
|
AAC: PayloadType.AAC,
|
||||||
'MP4A-LATM': PayloadType.AAC,
|
'MP4A-LATM': PayloadType.AAC,
|
||||||
@@ -2572,6 +2569,8 @@
|
|||||||
this.initSegments[track_type] = MP4.initSegment([track.mp4track], track.duration*track.timescale, track.timescale);
|
this.initSegments[track_type] = MP4.initSegment([track.mp4track], track.duration*track.timescale, track.timescale);
|
||||||
initmse.push(this.initMSE(track_type, track.mp4track.codec));
|
initmse.push(this.initMSE(track_type, track.mp4track.codec));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.eventSource.dispatchEvent('mp4initsegement', this.tracks);
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
return Promise.all(initmse).then(()=>{
|
return Promise.all(initmse).then(()=>{
|
||||||
//this.mse.play();
|
//this.mse.play();
|
||||||
@@ -2623,7 +2622,9 @@
|
|||||||
let track = this.tracks[track_type];
|
let track = this.tracks[track_type];
|
||||||
let pay = track.getPayload();
|
let pay = track.getPayload();
|
||||||
if (pay && pay.byteLength) {
|
if (pay && pay.byteLength) {
|
||||||
this.mse.feed(track_type, [MP4.moof(track.seq, track.scaled(track.firstDTS), track.mp4track), MP4.mdat(pay)]);
|
let payload = [MP4.moof(track.seq, track.scaled(track.firstDTS), track.mp4track), MP4.mdat(pay)];
|
||||||
|
this.mse.feed(track_type, payload);
|
||||||
|
this.eventSource.dispatchEvent('mp4payload', payload);
|
||||||
track.flush();
|
track.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2779,8 +2780,6 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// export * from 'bp_statemachine';
|
|
||||||
|
|
||||||
const Log$6 = getTagged("parser:sdp");
|
const Log$6 = getTagged("parser:sdp");
|
||||||
|
|
||||||
class SDPParser {
|
class SDPParser {
|
||||||
@@ -3062,6 +3061,14 @@
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getVideoFormat() {
|
||||||
|
if (!this.videoFormat) {
|
||||||
|
this.videoFormat = this.media.video.rtpmap[this.media.video.fmt[0]].name.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.videoFormat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const LOG_TAG$2 = "rtsp:stream";
|
const LOG_TAG$2 = "rtsp:stream";
|
||||||
@@ -3107,16 +3114,17 @@
|
|||||||
} else if (Url.isAbsolute(`${sessionBlock.control}${track.control}`)) {
|
} else if (Url.isAbsolute(`${sessionBlock.control}${track.control}`)) {
|
||||||
return `${sessionBlock.control}${track.control}`;
|
return `${sessionBlock.control}${track.control}`;
|
||||||
} else if (Url.isAbsolute(`${this.client.contentBase}${track.control}`)) {
|
} else if (Url.isAbsolute(`${this.client.contentBase}${track.control}`)) {
|
||||||
|
/* Check the end of the address for a separator */
|
||||||
|
if (this.client.contentBase[this.client.contentBase.length - 1] !== '/') {
|
||||||
|
return `${this.client.contentBase}/${track.control}`;
|
||||||
|
}
|
||||||
|
|
||||||
/* Should probably check session level control before this */
|
/* Should probably check session level control before this */
|
||||||
return `${this.client.contentBase}${track.control}`;
|
return `${this.client.contentBase}${track.control}`;
|
||||||
}
|
}
|
||||||
else {//need return default
|
else {//need return default
|
||||||
return track.control;
|
return track.control;
|
||||||
}
|
}
|
||||||
Log$7.error('Can\'t determine track URL from ' +
|
|
||||||
'block.control:' + track.control + ', ' +
|
|
||||||
'session.control:' + sessionBlock.control + ', and ' +
|
|
||||||
'content-base:' + this.client.contentBase);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getControlURL() {
|
getControlURL() {
|
||||||
@@ -3170,9 +3178,8 @@
|
|||||||
sendSetup(session = null) {
|
sendSetup(session = null) {
|
||||||
this.state = RTSPClientSM.STATE_SETUP;
|
this.state = RTSPClientSM.STATE_SETUP;
|
||||||
this.rtpChannel = this.client.interleaveChannelIndex;
|
this.rtpChannel = this.client.interleaveChannelIndex;
|
||||||
let interleavedChannels = this.client.interleaveChannelIndex++ + "-" + this.client.interleaveChannelIndex++;
|
|
||||||
let params = {
|
let params = {
|
||||||
'Transport': `RTP/AVP/TCP;unicast;interleaved=${interleavedChannels}`,
|
'Transport': this.make_transport_string(),
|
||||||
'Date': new Date().toUTCString()
|
'Date': new Date().toUTCString()
|
||||||
};
|
};
|
||||||
if(session){
|
if(session){
|
||||||
@@ -3182,9 +3189,9 @@
|
|||||||
this.session = _data.headers['session'].split(';');
|
this.session = _data.headers['session'].split(';');
|
||||||
let transport = _data.headers['transport'];
|
let transport = _data.headers['transport'];
|
||||||
if (transport) {
|
if (transport) {
|
||||||
let interleaved = transport.match(/interleaved=([0-9]+)-([0-9]+)/)[1];
|
let interleaved = transport.match(/interleaved=([0-9]+)-([0-9]+)/);
|
||||||
if (interleaved) {
|
if (interleaved) {
|
||||||
this.rtpChannel = Number(interleaved);
|
this.rtpChannel = Number(interleaved[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3206,6 +3213,16 @@
|
|||||||
return {track: this.track, data: _data, session: this.session[0]};
|
return {track: this.track, data: _data, session: this.session[0]};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_transport_string() {
|
||||||
|
let udp_port = this.client.udp_port;
|
||||||
|
if (udp_port) {
|
||||||
|
return `RTP/AVP;unicast;client_port=${udp_port}-${udp_port + 2}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let interleavedChannels = this.client.interleaveChannelIndex++ + "-" + this.client.interleaveChannelIndex++;
|
||||||
|
return `RTP/AVP/TCP;unicast;interleaved=${interleavedChannels}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3505,9 +3522,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.headerLength = pktIndex;
|
this.headerLength = pktIndex;
|
||||||
let padLength = 0;
|
|
||||||
if (this.padding) {
|
if (this.padding) {
|
||||||
padLength = bytes.getUint8(pkt.byteLength-1);
|
bytes.getUint8(pkt.byteLength-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.bodyLength = pkt.byteLength-this.headerLength-padLength;
|
// this.bodyLength = pkt.byteLength-this.headerLength-padLength;
|
||||||
@@ -3660,14 +3676,13 @@
|
|||||||
parseAggregationPacket(rawData, header, dts, pts) {
|
parseAggregationPacket(rawData, header, dts, pts) {
|
||||||
let data = new DataView(rawData.buffer, rawData.byteOffset, rawData.byteLength);
|
let data = new DataView(rawData.buffer, rawData.byteOffset, rawData.byteLength);
|
||||||
let nal_start_idx = 0;
|
let nal_start_idx = 0;
|
||||||
let don = null;
|
|
||||||
if (NALU.STAP_B === header.type) {
|
if (NALU.STAP_B === header.type) {
|
||||||
don = data.getUint16(nal_start_idx);
|
data.getUint16(nal_start_idx);
|
||||||
nal_start_idx += 2;
|
nal_start_idx += 2;
|
||||||
}
|
}
|
||||||
let ret = [];
|
let ret = [];
|
||||||
while (nal_start_idx < data.byteLength) {
|
while (nal_start_idx < data.byteLength) {
|
||||||
let size = data.getUint16(nal_start_idx);
|
let size = data.getUint16(nal_start_idx) - 1;
|
||||||
nal_start_idx += 2;
|
nal_start_idx += 2;
|
||||||
let header = NALUAsm.parseNALHeader(data.getInt8(nal_start_idx));
|
let header = NALUAsm.parseNALHeader(data.getInt8(nal_start_idx));
|
||||||
nal_start_idx++;
|
nal_start_idx++;
|
||||||
@@ -3690,9 +3705,8 @@
|
|||||||
let ret = null;
|
let ret = null;
|
||||||
|
|
||||||
nal_start_idx++;
|
nal_start_idx++;
|
||||||
let don = 0;
|
|
||||||
if (NALU.FU_B === header.type) {
|
if (NALU.FU_B === header.type) {
|
||||||
don = data.getUint16(nal_start_idx);
|
data.getUint16(nal_start_idx);
|
||||||
nal_start_idx += 2;
|
nal_start_idx += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3802,15 +3816,15 @@
|
|||||||
let dts = 0;
|
let dts = 0;
|
||||||
for (let offset=0; offset<auHeadersLengthInBits;) {
|
for (let offset=0; offset<auHeadersLengthInBits;) {
|
||||||
let size = bits.readBits(sizeLength);
|
let size = bits.readBits(sizeLength);
|
||||||
let idx = bits.readBits(offset?indexDeltaLength:indexLength);
|
bits.readBits(offset?indexDeltaLength:indexLength);
|
||||||
offset+=sizeLength+(offset?indexDeltaLength:indexLength)/*+2*/;
|
offset+=sizeLength+(offset?indexDeltaLength:indexLength)/*+2*/;
|
||||||
if (/*ctsPresent &&*/ CTSDeltaLength) {
|
if (/*ctsPresent &&*/ CTSDeltaLength) {
|
||||||
let ctsPresent = bits.readBits(1);
|
bits.readBits(1);
|
||||||
cts = bits.readBits(CTSDeltaLength);
|
cts = bits.readBits(CTSDeltaLength);
|
||||||
offset+=CTSDeltaLength;
|
offset+=CTSDeltaLength;
|
||||||
}
|
}
|
||||||
if (/*dtsPresent && */DTSDeltaLength) {
|
if (/*dtsPresent && */DTSDeltaLength) {
|
||||||
let dtsPresent = bits.readBits(1);
|
bits.readBits(1);
|
||||||
dts = bits.readBits(DTSDeltaLength);
|
dts = bits.readBits(DTSDeltaLength);
|
||||||
offset+=CTSDeltaLength;
|
offset+=CTSDeltaLength;
|
||||||
}
|
}
|
||||||
@@ -4220,13 +4234,15 @@
|
|||||||
static get STATE_INITIAL() {return 1 << 0;}
|
static get STATE_INITIAL() {return 1 << 0;}
|
||||||
static get STATE_OPTIONS() {return 1 << 1;}
|
static get STATE_OPTIONS() {return 1 << 1;}
|
||||||
static get STATE_DESCRIBE () {return 1 << 2;}
|
static get STATE_DESCRIBE () {return 1 << 2;}
|
||||||
static get STATE_SETUP() {return 1 << 3;}
|
static get STATE_SWITCH () {return 1 << 3;}
|
||||||
static get STATE_STREAMS() {return 1 << 4;}
|
static get STATE_UDP () {return 1 << 4;}
|
||||||
static get STATE_TEARDOWN() {return 1 << 5;}
|
static get STATE_SETUP() {return 1 << 5;}
|
||||||
static get STATE_PLAY() {return 1 << 6;}
|
static get STATE_STREAMS() {return 1 << 6;}
|
||||||
static get STATE_PLAYING() {return 1 << 7;}
|
static get STATE_TEARDOWN() {return 1 << 7;}
|
||||||
static get STATE_PAUSE() {return 1 << 8;}
|
static get STATE_PLAY() {return 1 << 8;}
|
||||||
static get STATE_PAUSED() {return 1 << 9;}
|
static get STATE_PLAYING() {return 1 << 9;}
|
||||||
|
static get STATE_PAUSE() {return 1 << 10;}
|
||||||
|
static get STATE_PAUSED() {return 1 << 11;}
|
||||||
// static STATE_PAUSED = 1 << 6;
|
// static STATE_PAUSED = 1 << 6;
|
||||||
|
|
||||||
constructor(parent) {
|
constructor(parent) {
|
||||||
@@ -4238,6 +4254,7 @@
|
|||||||
this.rtp_channels = new Set();
|
this.rtp_channels = new Set();
|
||||||
this.sessions = {};
|
this.sessions = {};
|
||||||
this.ontracks = null;
|
this.ontracks = null;
|
||||||
|
this.udp_port = null;
|
||||||
|
|
||||||
this.addState(RTSPClientSM.STATE_INITIAL,{
|
this.addState(RTSPClientSM.STATE_INITIAL,{
|
||||||
}).addState(RTSPClientSM.STATE_OPTIONS, {
|
}).addState(RTSPClientSM.STATE_OPTIONS, {
|
||||||
@@ -4246,6 +4263,12 @@
|
|||||||
}).addState(RTSPClientSM.STATE_DESCRIBE, {
|
}).addState(RTSPClientSM.STATE_DESCRIBE, {
|
||||||
activate: this.sendDescribe,
|
activate: this.sendDescribe,
|
||||||
finishTransition: this.onDescribe
|
finishTransition: this.onDescribe
|
||||||
|
}).addState(RTSPClientSM.STATE_SWITCH, {
|
||||||
|
activate: this.sendSwitch,
|
||||||
|
finishTransition: this.onSwitch
|
||||||
|
}).addState(RTSPClientSM.STATE_UDP, {
|
||||||
|
activate: this.change_rtp_transport,
|
||||||
|
finishTransition: this.on_change_rtp_transport
|
||||||
}).addState(RTSPClientSM.STATE_SETUP, {
|
}).addState(RTSPClientSM.STATE_SETUP, {
|
||||||
activate: this.sendSetup,
|
activate: this.sendSetup,
|
||||||
finishTransition: this.onSetup
|
finishTransition: this.onSetup
|
||||||
@@ -4262,6 +4285,10 @@
|
|||||||
.addTransition(RTSPClientSM.STATE_INITIAL, RTSPClientSM.STATE_TEARDOWN)
|
.addTransition(RTSPClientSM.STATE_INITIAL, RTSPClientSM.STATE_TEARDOWN)
|
||||||
.addTransition(RTSPClientSM.STATE_OPTIONS, RTSPClientSM.STATE_DESCRIBE)
|
.addTransition(RTSPClientSM.STATE_OPTIONS, RTSPClientSM.STATE_DESCRIBE)
|
||||||
.addTransition(RTSPClientSM.STATE_DESCRIBE, RTSPClientSM.STATE_SETUP)
|
.addTransition(RTSPClientSM.STATE_DESCRIBE, RTSPClientSM.STATE_SETUP)
|
||||||
|
.addTransition(RTSPClientSM.STATE_DESCRIBE, RTSPClientSM.STATE_SWITCH)
|
||||||
|
.addTransition(RTSPClientSM.STATE_SWITCH, RTSPClientSM.STATE_SETUP)
|
||||||
|
.addTransition(RTSPClientSM.STATE_DESCRIBE, RTSPClientSM.STATE_UDP)
|
||||||
|
.addTransition(RTSPClientSM.STATE_UDP, RTSPClientSM.STATE_SETUP)
|
||||||
.addTransition(RTSPClientSM.STATE_SETUP, RTSPClientSM.STATE_STREAMS)
|
.addTransition(RTSPClientSM.STATE_SETUP, RTSPClientSM.STATE_STREAMS)
|
||||||
.addTransition(RTSPClientSM.STATE_TEARDOWN, RTSPClientSM.STATE_INITIAL)
|
.addTransition(RTSPClientSM.STATE_TEARDOWN, RTSPClientSM.STATE_INITIAL)
|
||||||
// .addTransition(RTSPClientSM.STATE_STREAMS, RTSPClientSM.STATE_PAUSED)
|
// .addTransition(RTSPClientSM.STATE_STREAMS, RTSPClientSM.STATE_PAUSED)
|
||||||
@@ -4269,6 +4296,7 @@
|
|||||||
.addTransition(RTSPClientSM.STATE_STREAMS, RTSPClientSM.STATE_TEARDOWN)
|
.addTransition(RTSPClientSM.STATE_STREAMS, RTSPClientSM.STATE_TEARDOWN)
|
||||||
// .addTransition(RTSPClientSM.STATE_PAUSED, RTSPClientSM.STATE_TEARDOWN)
|
// .addTransition(RTSPClientSM.STATE_PAUSED, RTSPClientSM.STATE_TEARDOWN)
|
||||||
.addTransition(RTSPClientSM.STATE_SETUP, RTSPClientSM.STATE_TEARDOWN)
|
.addTransition(RTSPClientSM.STATE_SETUP, RTSPClientSM.STATE_TEARDOWN)
|
||||||
|
.addTransition(RTSPClientSM.STATE_SWITCH, RTSPClientSM.STATE_TEARDOWN)
|
||||||
.addTransition(RTSPClientSM.STATE_DESCRIBE, RTSPClientSM.STATE_TEARDOWN)
|
.addTransition(RTSPClientSM.STATE_DESCRIBE, RTSPClientSM.STATE_TEARDOWN)
|
||||||
.addTransition(RTSPClientSM.STATE_OPTIONS, RTSPClientSM.STATE_TEARDOWN);
|
.addTransition(RTSPClientSM.STATE_OPTIONS, RTSPClientSM.STATE_TEARDOWN);
|
||||||
|
|
||||||
@@ -4336,9 +4364,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onData(data) {
|
onData(data) {
|
||||||
let channel = data[1];
|
if (this.sdp.getVideoFormat() === 'h265') {
|
||||||
if (this.rtp_channels.has(channel)) {
|
this.parent.eventSource.dispatchEvent('h265payload', data);
|
||||||
this.onRTP({packet: data.subarray(4), type: channel});
|
} else if (this.udp_port) {
|
||||||
|
this.onRTP({packet: data});
|
||||||
|
} else {
|
||||||
|
let channel = data[1];
|
||||||
|
if (this.rtp_channels.has(channel)) {
|
||||||
|
this.onRTP({packet: data.subarray(4), type: channel});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4425,7 +4459,7 @@
|
|||||||
'User-Agent': RTSPClientSM.USER_AGENT
|
'User-Agent': RTSPClientSM.USER_AGENT
|
||||||
});
|
});
|
||||||
if (this.authenticator) {
|
if (this.authenticator) {
|
||||||
_params['Authorization'] = this.authenticator(_cmd);
|
_params['Authorization'] = this.authenticator(_cmd, _host);
|
||||||
}
|
}
|
||||||
return this.send(MessageBuilder.build(_cmd, _host, _params, _payload), _cmd).catch((e)=>{
|
return this.send(MessageBuilder.build(_cmd, _host, _params, _payload), _cmd).catch((e)=>{
|
||||||
if ((e instanceof AuthError) && !_params['Authorization'] ) {
|
if ((e instanceof AuthError) && !_params['Authorization'] ) {
|
||||||
@@ -4448,6 +4482,10 @@
|
|||||||
let response = await this.transport.send(_data);
|
let response = await this.transport.send(_data);
|
||||||
let parsed = this.parse(response);
|
let parsed = this.parse(response);
|
||||||
// TODO: parse status codes
|
// TODO: parse status codes
|
||||||
|
if (parsed.code == 461) {
|
||||||
|
return Promise.reject(parsed.code);
|
||||||
|
}
|
||||||
|
|
||||||
if (parsed.code == 401 /*&& !this.authenticator */) {
|
if (parsed.code == 401 /*&& !this.authenticator */) {
|
||||||
Log$9.debug(parsed.headers['www-authenticate']);
|
Log$9.debug(parsed.headers['www-authenticate']);
|
||||||
let auth = parsed.headers['www-authenticate'];
|
let auth = parsed.headers['www-authenticate'];
|
||||||
@@ -4471,13 +4509,13 @@
|
|||||||
let [k,v] = c.split('=');
|
let [k,v] = c.split('=');
|
||||||
parsedChunks[k] = v.substr(1, v.length-2);
|
parsedChunks[k] = v.substr(1, v.length-2);
|
||||||
}
|
}
|
||||||
this.authenticator = (_method)=>{
|
this.authenticator = (_method, _url)=>{
|
||||||
let ep = this.parent.endpoint;
|
let ep = this.parent.endpoint;
|
||||||
let ha1 = md5(`${ep.user}:${parsedChunks.realm}:${ep.pass}`);
|
let ha1 = md5(`${ep.user}:${parsedChunks.realm}:${ep.pass}`);
|
||||||
let ha2 = md5(`${_method}:${this.url}`);
|
let ha2 = md5(`${_method}:${_url}`);
|
||||||
let response = md5(`${ha1}:${parsedChunks.nonce}:${ha2}`);
|
let response = md5(`${ha1}:${parsedChunks.nonce}:${ha2}`);
|
||||||
let tail=''; // TODO: handle other params
|
let tail=''; // TODO: handle other params
|
||||||
return `Digest username="${ep.user}", realm="${parsedChunks.realm}", nonce="${parsedChunks.nonce}", uri="${this.url}", response="${response}"${tail}`;
|
return `Digest username="${ep.user}", realm="${parsedChunks.realm}", nonce="${parsedChunks.nonce}", uri="${_url}", response="${response}"${tail}`;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
this.authenticator = ()=>{return `Basic ${btoa(this.parent.endpoint.auth)}`;};
|
this.authenticator = ()=>{return `Basic ${btoa(this.parent.endpoint.auth)}`;};
|
||||||
@@ -4533,6 +4571,38 @@
|
|||||||
throw new Error("No tracks in SDP");
|
throw new Error("No tracks in SDP");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.sdp.getVideoFormat() === 'h265') {
|
||||||
|
this.transitionTo(RTSPClientSM.STATE_SWITCH);
|
||||||
|
this.parent.eventSource.dispatchEvent('videoFormat', 'h265');
|
||||||
|
} else {
|
||||||
|
this.transitionTo(RTSPClientSM.STATE_SETUP);
|
||||||
|
this.parent.eventSource.dispatchEvent('videoFormat', 'h264');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSwitch() {
|
||||||
|
return this.transport.socket().send('h265', 'SWITCH');
|
||||||
|
}
|
||||||
|
|
||||||
|
onSwitch(data) {
|
||||||
|
this.transitionTo(RTSPClientSM.STATE_SETUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
change_rtp_transport() {
|
||||||
|
let payload = `udp,${this.url},`;
|
||||||
|
if (this.authenticator) {
|
||||||
|
payload += this.authenticator(this.url, 'TEARDOWN');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.transport.socket().send(payload, 'SWITCH').promise.then((response)=>{
|
||||||
|
return response;
|
||||||
|
}).catch((reason)=>{
|
||||||
|
console.error(reason.msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
on_change_rtp_transport(response) {
|
||||||
|
this.udp_port = response.payload;
|
||||||
this.transitionTo(RTSPClientSM.STATE_SETUP);
|
this.transitionTo(RTSPClientSM.STATE_SETUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4632,10 +4702,14 @@
|
|||||||
this.ontracks(tracks);
|
this.ontracks(tracks);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}).catch((e)=>{
|
}).catch((reason)=>{
|
||||||
console.error(e);
|
if (reason == 461) {
|
||||||
this.stop();
|
this.transitionTo(RTSPClientSM.STATE_UDP);
|
||||||
this.reset();
|
} else {
|
||||||
|
console.error(e);
|
||||||
|
this.stop();
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4913,9 +4987,9 @@
|
|||||||
typeName() {
|
typeName() {
|
||||||
if (this.tag === undefined)
|
if (this.tag === undefined)
|
||||||
return "unknown";
|
return "unknown";
|
||||||
var tagClass = this.tag >> 6,
|
var tagClass = this.tag >> 6;
|
||||||
tagConstructed = (this.tag >> 5) & 1,
|
(this.tag >> 5) & 1;
|
||||||
tagNumber = this.tag & 0x1F;
|
var tagNumber = this.tag & 0x1F;
|
||||||
switch (tagClass) {
|
switch (tagClass) {
|
||||||
case 0: // universal
|
case 0: // universal
|
||||||
switch (tagNumber) {
|
switch (tagNumber) {
|
||||||
@@ -5484,11 +5558,11 @@
|
|||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
if(navigator.appName == "Microsoft Internet Explorer") {
|
if((navigator.appName == "Microsoft Internet Explorer")) {
|
||||||
BigInteger.prototype.am = am2;
|
BigInteger.prototype.am = am2;
|
||||||
dbits = 30;
|
dbits = 30;
|
||||||
}
|
}
|
||||||
else if(navigator.appName != "Netscape") {
|
else if((navigator.appName != "Netscape")) {
|
||||||
BigInteger.prototype.am = am1;
|
BigInteger.prototype.am = am1;
|
||||||
dbits = 26;
|
dbits = 26;
|
||||||
}
|
}
|
||||||
@@ -8891,8 +8965,6 @@
|
|||||||
return this.getKey().getPublicBaseKeyB64();
|
return this.getKey().getPublicBaseKeyB64();
|
||||||
};
|
};
|
||||||
|
|
||||||
// export * from 'jsencrypt';
|
|
||||||
|
|
||||||
class BaseTransport {
|
class BaseTransport {
|
||||||
constructor(endpoint, stream_type, config={}) {
|
constructor(endpoint, stream_type, config={}) {
|
||||||
this.stream_type = stream_type;
|
this.stream_type = stream_type;
|
||||||
@@ -8947,7 +9019,7 @@
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
/^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||||
//navigator.hardwareConcurrency || 3;
|
//navigator.hardwareConcurrency || 3;
|
||||||
|
|
||||||
function SMediaError(data) {
|
function SMediaError(data) {
|
||||||
@@ -9394,7 +9466,7 @@
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
send(payload) {
|
send(payload, cmd) {
|
||||||
if (this.ctrlChannel.readyState != WebSocket.OPEN) {
|
if (this.ctrlChannel.readyState != WebSocket.OPEN) {
|
||||||
this.close();
|
this.close();
|
||||||
this.error(SMediaError.MEDIA_ERR_TRANSPORT);
|
this.error(SMediaError.MEDIA_ERR_TRANSPORT);
|
||||||
@@ -9409,21 +9481,235 @@
|
|||||||
seq:data.seq,
|
seq:data.seq,
|
||||||
promise: new Promise((resolve, reject)=>{
|
promise: new Promise((resolve, reject)=>{
|
||||||
this.awaitingPromises[data.seq] = {resolve, reject};
|
this.awaitingPromises[data.seq] = {resolve, reject};
|
||||||
let msg = this.builder.build(WSPProtocol.CMD_WRAP, data, payload);
|
let msg = this.builder.build(cmd || WSPProtocol.CMD_WRAP, data, payload);
|
||||||
Log$a.debug(msg);
|
Log$a.debug(msg);
|
||||||
this.ctrlChannel.send(this.encrypt(msg));
|
this.ctrlChannel.send(this.encrypt(msg));
|
||||||
})};
|
})};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MediaRecorder {
|
||||||
|
constructor(parent, prefix) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.prefix = prefix;
|
||||||
|
this.remuxer;
|
||||||
|
this.header;
|
||||||
|
this.firstBuffer = new Uint8Array(0);
|
||||||
|
this.secondBuffer = new Uint8Array(0);
|
||||||
|
this.byteBuffer = this.firstBuffer;
|
||||||
|
this.isSwaped = false;
|
||||||
|
this.isPaused = false;
|
||||||
|
this.isRecording = false;
|
||||||
|
|
||||||
|
this.fileLength = 180000; /*download every 3 minutes*/
|
||||||
|
}
|
||||||
|
|
||||||
|
setFileLength(milliseconds) {
|
||||||
|
if (milliseconds) {
|
||||||
|
this.fileLength = milliseconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(event) {
|
||||||
|
let tracks = event.detail;
|
||||||
|
let tracks_list = [];
|
||||||
|
for (let key in tracks) {
|
||||||
|
let type = tracks[key].mp4track.type;
|
||||||
|
if (type === "video" || type === "audio") {
|
||||||
|
tracks_list.push(tracks[key].mp4track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.header = MP4.initSegment(tracks_list, tracks[1].duration*tracks[1].timescale, tracks[1].timescale);
|
||||||
|
}
|
||||||
|
|
||||||
|
pushData(event) {
|
||||||
|
if (this.isRecording) {
|
||||||
|
if (this.byteBuffer.length == 0) {
|
||||||
|
this.setBuffer(this.header);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setBuffer(event.detail[0]);
|
||||||
|
this.setBuffer(event.detail[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record(recordvalue) {
|
||||||
|
if (recordvalue) {
|
||||||
|
if (!this.isRecording) {
|
||||||
|
this.flushInterval = setInterval(this.flush.bind(this), this.fileLength);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearInterval(this.flushInterval);
|
||||||
|
this.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRecording = recordvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pause(value) {
|
||||||
|
if (this.isRecording || this.isPaused) {
|
||||||
|
this.record(!value);
|
||||||
|
this.isPaused = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setBuffer(data) {
|
||||||
|
if (this.isRecording) {
|
||||||
|
let tmp = new Uint8Array(this.byteBuffer.byteLength + data.byteLength);
|
||||||
|
tmp.set(new Uint8Array(this.byteBuffer), 0);
|
||||||
|
tmp.set(new Uint8Array(data), this.byteBuffer.byteLength);
|
||||||
|
this.byteBuffer = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swapBuffer() {
|
||||||
|
this.isSwaped = !this.isSwaped;
|
||||||
|
|
||||||
|
if (this.isSwaped) {
|
||||||
|
this.byteBuffer = this.secondBuffer;
|
||||||
|
this.firstBuffer = new Uint8Array(0);
|
||||||
|
} else {
|
||||||
|
this.byteBuffer = this.firstBuffer;
|
||||||
|
this.secondBuffer = new Uint8Array(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flush() {
|
||||||
|
let byteBuffer = this.byteBuffer;
|
||||||
|
this.swapBuffer();
|
||||||
|
if (this.header && byteBuffer.length > this.header.length) {
|
||||||
|
this.parent.mediadata(byteBuffer, this.prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attachSource(remuxer) {
|
||||||
|
this.remuxer = remuxer;
|
||||||
|
this.remuxer.eventSource.addEventListener('mp4initsegement', this.init.bind(this));
|
||||||
|
this.remuxer.eventSource.addEventListener('mp4payload', this.pushData.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
dettachSource() {
|
||||||
|
if (this.remuxer) {
|
||||||
|
this.remuxer.eventSource.removeEventListener('mp4initsegement');
|
||||||
|
this.remuxer.eventSource.removeEventListener('mp4payload');
|
||||||
|
this.remuxer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.record(false);
|
||||||
|
this.dettachSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class H265Decoder {
|
||||||
|
constructor(canvas) {
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.remuxer;
|
||||||
|
this.decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushData(event) {
|
||||||
|
if (this.decoder == undefined) {
|
||||||
|
this.initDecoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
let err = this.decoder.push_data(event.detail);
|
||||||
|
|
||||||
|
if (!libde265.de265_isOK(err)) {
|
||||||
|
console.error(err, libde265.de265_get_error_text(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.decoder.decode(function(err) {
|
||||||
|
switch(err) {
|
||||||
|
case libde265.DE265_ERROR_WAITING_FOR_INPUT_DATA:
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!libde265.de265_isOK(err)) {
|
||||||
|
console.error(err, libde265.de265_get_error_text(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setBuffer(data) {
|
||||||
|
if (this.isRecording) {
|
||||||
|
let tmp = new Uint8Array(this.byteBuffer.byteLength + data.byteLength);
|
||||||
|
tmp.set(new Uint8Array(this.byteBuffer), 0);
|
||||||
|
tmp.set(new Uint8Array(data), this.byteBuffer.byteLength);
|
||||||
|
this.byteBuffer = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attachSource(client) {
|
||||||
|
this.client = client;
|
||||||
|
this.client.eventSource.addEventListener('h265payload', this.pushData.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
dettachSource() {
|
||||||
|
if (this.client) {
|
||||||
|
this.client.eventSource.removeEventListener('h265payload');
|
||||||
|
this.client = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.dettachSource();
|
||||||
|
this.decoder.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
initDecoder() {
|
||||||
|
let that = this;
|
||||||
|
this.ctx = this.canvas.getContext("2d");
|
||||||
|
this.decoder = new libde265.Decoder();
|
||||||
|
this.decoder.set_image_callback(function(image) {
|
||||||
|
that.displayImage(image);
|
||||||
|
image.free();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
displayImage(image) {
|
||||||
|
var w = image.get_width();
|
||||||
|
var h = image.get_height();
|
||||||
|
if (w != this.canvas.width || h != this.canvas.height || !this.image_data) {
|
||||||
|
this.canvas.width = w;
|
||||||
|
this.canvas.height = h;
|
||||||
|
this.image_data = this.ctx.createImageData(w, h);
|
||||||
|
var image_data = this.image_data.data;
|
||||||
|
for (var i=0; i<w*h; i++) {
|
||||||
|
image_data[i*4+3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
image.display(this.image_data, function(display_image_data) {
|
||||||
|
if (window.requestAnimationFrame) {
|
||||||
|
that.pending_image_data = display_image_data;
|
||||||
|
window.requestAnimationFrame(function() {
|
||||||
|
if (that.pending_image_data) {
|
||||||
|
that.ctx.putImageData(that.pending_image_data, 0, 0);
|
||||||
|
that.pending_image_data = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
that.ctx.putImageData(display_image_data, 0, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Log$b = getTagged('wsp');
|
const Log$b = getTagged('wsp');
|
||||||
|
|
||||||
class StreamType$1 {
|
class StreamType {
|
||||||
static get HLS() {return 'hls';}
|
static get HLS() {return 'hls';}
|
||||||
static get RTSP() {return 'rtsp';}
|
static get RTSP() {return 'rtsp';}
|
||||||
|
|
||||||
static isSupported(type) {
|
static isSupported(type) {
|
||||||
return [StreamType$1.HLS, StreamType$1.RTSP].includes(type);
|
return [StreamType.HLS, StreamType.RTSP].includes(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromUrl(url) {
|
static fromUrl(url) {
|
||||||
@@ -9435,11 +9721,11 @@
|
|||||||
}
|
}
|
||||||
switch (parsed.protocol) {
|
switch (parsed.protocol) {
|
||||||
case 'rtsp':
|
case 'rtsp':
|
||||||
return StreamType$1.RTSP;
|
return StreamType.RTSP;
|
||||||
case 'http':
|
case 'http':
|
||||||
case 'https':
|
case 'https':
|
||||||
if (url.indexOf('.m3u8')>=0) {
|
if (url.indexOf('.m3u8')>=0) {
|
||||||
return StreamType$1.HLS;
|
return StreamType.HLS;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -9451,10 +9737,10 @@
|
|||||||
static fromMime(mime) {
|
static fromMime(mime) {
|
||||||
switch (mime) {
|
switch (mime) {
|
||||||
case 'application/x-rtsp':
|
case 'application/x-rtsp':
|
||||||
return StreamType$1.RTSP;
|
return StreamType.RTSP;
|
||||||
case 'application/vnd.apple.mpegurl':
|
case 'application/vnd.apple.mpegurl':
|
||||||
case 'application/x-mpegurl':
|
case 'application/x-mpegurl':
|
||||||
return StreamType$1.HLS;
|
return StreamType.HLS;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -9470,6 +9756,12 @@
|
|||||||
this.player = node;
|
this.player = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof opts.canvas == typeof '') {
|
||||||
|
this.canvas = document.getElementById(opts.canvas);
|
||||||
|
} else {
|
||||||
|
this.canvas = opts.canvas;
|
||||||
|
}
|
||||||
|
|
||||||
let modules = opts.modules || {
|
let modules = opts.modules || {
|
||||||
client: RTSPClient,
|
client: RTSPClient,
|
||||||
transport: {
|
transport: {
|
||||||
@@ -9478,6 +9770,8 @@
|
|||||||
};
|
};
|
||||||
this.errorHandler = opts.errorHandler || null;
|
this.errorHandler = opts.errorHandler || null;
|
||||||
this.infoHandler = opts.infoHandler || null;
|
this.infoHandler = opts.infoHandler || null;
|
||||||
|
this.dataHandler = opts.dataHandler || null;
|
||||||
|
this.videoFormatHandler = opts.videoFormatHandler || null;
|
||||||
this.queryCredentials = opts.queryCredentials || null;
|
this.queryCredentials = opts.queryCredentials || null;
|
||||||
|
|
||||||
this.bufferDuration_ = opts.bufferDuration || 120;
|
this.bufferDuration_ = opts.bufferDuration || 120;
|
||||||
@@ -9486,6 +9780,11 @@
|
|||||||
this.bufferDuration_ = 120;
|
this.bufferDuration_ = 120;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.continuousRecording = new MediaRecorder(this, 'continuous');
|
||||||
|
this.eventRecording = new MediaRecorder(this, 'event');
|
||||||
|
this.continuousRecording.setFileLength(opts.continuousFileLength);
|
||||||
|
this.eventRecording.setFileLength(opts.eventFileLength);
|
||||||
|
|
||||||
this.modules = {};
|
this.modules = {};
|
||||||
for (let module of modules) {
|
for (let module of modules) {
|
||||||
let transport = module.transport || WebsocketTransport;
|
let transport = module.transport || WebsocketTransport;
|
||||||
@@ -9500,7 +9799,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.type = StreamType$1.RTSP;
|
this.type = StreamType.RTSP;
|
||||||
this.url = null;
|
this.url = null;
|
||||||
if (opts.url && opts.type) {
|
if (opts.url && opts.type) {
|
||||||
this.url = opts.url;
|
this.url = opts.url;
|
||||||
@@ -9523,6 +9822,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.player.addEventListener('play', ()=>{
|
this.player.addEventListener('play', ()=>{
|
||||||
|
this.continuousRecording.pause(false);
|
||||||
|
this.eventRecording.pause(false);
|
||||||
|
|
||||||
if (!this.isPlaying()) {
|
if (!this.isPlaying()) {
|
||||||
this.client.start();
|
this.client.start();
|
||||||
}
|
}
|
||||||
@@ -9530,6 +9832,8 @@
|
|||||||
|
|
||||||
this.player.addEventListener('pause', ()=>{
|
this.player.addEventListener('pause', ()=>{
|
||||||
this.client.stop();
|
this.client.stop();
|
||||||
|
this.continuousRecording.pause(true);
|
||||||
|
this.eventRecording.pause(true);
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
this.player.addEventListener('seeking', ()=>{
|
this.player.addEventListener('seeking', ()=>{
|
||||||
@@ -9542,7 +9846,7 @@
|
|||||||
if(this.player.currentTime < bStart){
|
if(this.player.currentTime < bStart){
|
||||||
this.player.currentTime = bStart;
|
this.player.currentTime = bStart;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
this.player.currentTime = bEnd - 1;
|
this.player.currentTime = bEnd - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9585,7 +9889,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let type in filteredModules) {
|
for (let type in filteredModules) {
|
||||||
if (type == StreamType$1.fromMime(mimeType)) {
|
if (type == StreamType.fromMime(mimeType)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9594,18 +9898,18 @@
|
|||||||
|
|
||||||
/// TODO: deprecate it?
|
/// TODO: deprecate it?
|
||||||
static canPlay(resource) {
|
static canPlay(resource) {
|
||||||
return StreamType$1.fromMime(resource.type) || StreamType$1.fromUrl(resource.src);
|
return StreamType.fromMime(resource.type) || StreamType.fromUrl(resource.src);
|
||||||
}
|
}
|
||||||
|
|
||||||
canPlayUrl(src) {
|
canPlayUrl(src) {
|
||||||
let type = StreamType$1.fromUrl(src);
|
let type = StreamType.fromUrl(src);
|
||||||
return (type in this.modules);
|
return (type in this.modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
_checkSource(src) {
|
_checkSource(src) {
|
||||||
if (!src.dataset['ignore'] && src.src && !this.player.canPlayType(src.type) && (StreamType$1.fromMime(src.type) || StreamType$1.fromUrl(src.src))) {
|
if (!src.dataset['ignore'] && src.src && !this.player.canPlayType(src.type) && (StreamType.fromMime(src.type) || StreamType.fromUrl(src.src))) {
|
||||||
this.url = src.src;
|
this.url = src.src;
|
||||||
this.type = src.type ? StreamType$1.fromMime(src.type) : StreamType$1.fromUrl(src.src);
|
this.type = src.type ? StreamType.fromMime(src.type) : StreamType.fromUrl(src.src);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -9636,7 +9940,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
let lastType = this.type;
|
let lastType = this.type;
|
||||||
this.type = (StreamType$1.isSupported(type)?type:false) || StreamType$1.fromMime(type);
|
this.type = (StreamType.isSupported(type)?type:false) || StreamType.fromMime(type);
|
||||||
if (!this.type) {
|
if (!this.type) {
|
||||||
this.error(SMediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
|
this.error(SMediaError.MEDIA_ERR_SRC_NOT_SUPPORTED);
|
||||||
return;
|
return;
|
||||||
@@ -9657,6 +9961,8 @@
|
|||||||
this.client.queryCredentials = this.queryCredentials;
|
this.client.queryCredentials = this.queryCredentials;
|
||||||
}
|
}
|
||||||
if (this.remuxer) {
|
if (this.remuxer) {
|
||||||
|
this.continuousRecording.dettachSource();
|
||||||
|
this.eventRecording.dettachSource();
|
||||||
this.remuxer.destroy();
|
this.remuxer.destroy();
|
||||||
this.remuxer = null;
|
this.remuxer = null;
|
||||||
}
|
}
|
||||||
@@ -9664,8 +9970,17 @@
|
|||||||
this.remuxer.MSE.bufferDuration = this.bufferDuration_;
|
this.remuxer.MSE.bufferDuration = this.bufferDuration_;
|
||||||
this.remuxer.attachClient(this.client);
|
this.remuxer.attachClient(this.client);
|
||||||
|
|
||||||
|
this.h265Decoder = new H265Decoder(this.canvas);
|
||||||
|
this.h265Decoder.attachSource(this.client);
|
||||||
|
|
||||||
|
this.continuousRecording.attachSource(this.remuxer);
|
||||||
|
this.eventRecording.attachSource(this.remuxer);
|
||||||
|
|
||||||
this.client.attachTransport(this.transport);
|
this.client.attachTransport(this.transport);
|
||||||
this.client.setSource(this.endpoint);
|
this.client.setSource(this.endpoint);
|
||||||
|
this.client.eventSource.addEventListener('videoFormat', (event)=>{
|
||||||
|
this.videoFormatEvent(event.detail);
|
||||||
|
});
|
||||||
|
|
||||||
if (this.player.autoplay) {
|
if (this.player.autoplay) {
|
||||||
this.start();
|
this.start();
|
||||||
@@ -9674,7 +9989,8 @@
|
|||||||
|
|
||||||
set bufferDuration(duration){
|
set bufferDuration(duration){
|
||||||
if(this.remuxer && this.remuxer.MSE) {
|
if(this.remuxer && this.remuxer.MSE) {
|
||||||
this.bufferDuration_ = duration; this.remuxer.MSE.bufferDuration = duration;
|
this.bufferDuration_ = duration;
|
||||||
|
this.remuxer.MSE.bufferDuration = duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9704,6 +10020,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
videoFormatEvent(format) {
|
||||||
|
if (format !== undefined) {
|
||||||
|
if (this.videoFormatHandler){
|
||||||
|
this.videoFormatHandler(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mediadata(data, prefix){
|
||||||
|
if (data !== undefined) {
|
||||||
|
if (this.dataHandler){
|
||||||
|
this.dataHandler(data, prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
if (this.client) {
|
if (this.client) {
|
||||||
this.client.start().catch((e)=>{
|
this.client.start().catch((e)=>{
|
||||||
@@ -9734,6 +10066,9 @@
|
|||||||
this.remuxer.destroy();
|
this.remuxer.destroy();
|
||||||
this.remuxer = null;
|
this.remuxer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.continuousRecording.destroy();
|
||||||
|
this.eventRecording.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -9776,8 +10111,22 @@
|
|||||||
opts.infoHandler(inf);
|
opts.infoHandler(inf);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
dataHandler(data, prefix) {
|
||||||
|
if(opts.dataHandler) {
|
||||||
|
opts.dataHandler(data, prefix);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
videoFormatHandler(format) {
|
||||||
|
if(opts.videoFormatHandler) {
|
||||||
|
opts.videoFormatHandler(format);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
redirectNativeMediaErrors: opts.redirectNativeMediaErrors,
|
redirectNativeMediaErrors: opts.redirectNativeMediaErrors,
|
||||||
bufferDuration : opts.bufferDuration,
|
bufferDuration : opts.bufferDuration,
|
||||||
|
continuousFileLength: opts.continuousFileLength,
|
||||||
|
eventFileLength: opts.eventFileLength,
|
||||||
|
canvas: opts.canvas,
|
||||||
|
|
||||||
queryCredentials(client) {
|
queryCredentials(client) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -9796,4 +10145,3 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
}());
|
}());
|
||||||
//# sourceMappingURL=streamedian.min.js.map
|
|
251
demos/wsp/index.html
Executable file → Normal file
251
demos/wsp/index.html
Executable file → Normal file
@@ -3,28 +3,40 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>RTSP player example(based streamedian)</title>
|
<title>RTSP player example(based streamedian)</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="sourcesNode"></div>
|
<div id="sourcesNode"></div>
|
||||||
<div>
|
<div>
|
||||||
<input id="stream_url" size="80" value="rtsp://localhost:1554/test/live1">
|
<input id="stream_url" value="rtsp://localhost:1554/test/live1" size="36">
|
||||||
<button id="set_new_url">Set</button>
|
<button id="set_new_url">Set</button>
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" id="continuous_recording">
|
||||||
|
<label class="custom-control-label" for="customSwitch1">Continuous recording</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p style="color:#808080">Enter your rtsp link to the stream, for example: "rtsp://localhost:1554/test/live1"</p>
|
<p style="color:#808080">Enter your rtsp link to the stream, for example: "rtsp://192.168.1.1:554/h264"</p>
|
||||||
<p style="color:#808080">If need token,for example: "rtsp://localhost:1554/test/live1?token=4df8f5d5d680385cb07c2e354dd0f3f3"</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<span style="color:#808080">Change video file length of the continuous recording</span>
|
||||||
|
<input id="continuous_file_length" type="range" min="10000" max="200000" value="180000" step="1000" style="width:40%;">
|
||||||
|
<p id="continuous_file_length_label">180sec.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span style="color:#808080">Change video file length of the event recording</span>
|
||||||
|
<input id="event_file_length" type="range" min="10000" max="200000" value="180000" step="1000" style="width:40%;">
|
||||||
|
<p id="event_file_length_label">180sec.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span style="color:#808080">Change buffer duration</span>
|
||||||
<input id="buffer_duration" type="range" min="10" max="200" style="width:40%;">
|
<input id="buffer_duration" type="range" min="10" max="200" style="width:40%;">
|
||||||
<span id="buffer_value">120sec.</span>
|
<p id="buffer_value">120sec.</p>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p style="color:#808080">Change buffer duration</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<canvas id="video_canvas" width="0" height="0"></canvas>
|
||||||
<video id="test_video" controls autoplay>
|
<video id="test_video" controls autoplay>
|
||||||
<!--<source src="rtsp://192.168.10.205:554/ch01.264" type="application/x-rtsp">-->
|
<!--<source src="rtsp://192.168.10.205:554/ch01.264" type="application/x-rtsp">-->
|
||||||
<!--<source src="rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov" type="application/x-rtsp">-->
|
<!--<source src="rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov" type="application/x-rtsp">-->
|
||||||
@@ -37,21 +49,42 @@
|
|||||||
<output for="rate" id="rate_res">live</output>
|
<output for="rate" id="rate_res">live</output>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button id="to_end" class="btn btn-success">live</button>
|
<button id="to_end" class="btn btn-success" disabled>live</button>
|
||||||
|
<button id="event_recording" class="btn btn-success" disabled>Start recording</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span style="color:#808080">Select a recorded file to playback</span>
|
||||||
|
<input id="file_input" type="file" accept=".mp4">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><br>Have any suggestions to improve our player? <br>Feel free to leave comments or ideas email: streamedian.player@gmail.com</p>
|
||||||
<p>View HTML5 RTSP video player log</p>
|
<p>View HTML5 RTSP video player log</p>
|
||||||
<div id="pllogs" class="logs"></div>
|
<div id="pllogs" class="logs"></div>
|
||||||
<button class="btn btn-success" onclick="cleanLog(pllogs)">clear</button>
|
<button class="btn btn-success" onclick="cleanLog(pllogs)">clear</button>
|
||||||
<button class="btn btn-success" onclick="scrollset(pllogs, true)">scroll up</button>
|
<button class="btn btn-success" onclick="scrollset(pllogs, true)">scroll up</button>
|
||||||
<button class="btn btn-success" onclick="scrollset(pllogs, false)">scroll down</button>
|
<button class="btn btn-success" onclick="scrollset(pllogs, false)">scroll down</button>
|
||||||
<button id="scrollSetPl" class="btn btn-success" onclick="scrollswitch(pllogs)">Scroll off</button>
|
<button id="scrollSetPl" class="btn btn-success" onclick="scrollswitch(pllogs)">Scroll off</button>
|
||||||
|
<button class="btn btn-success" onclick="statisticRequest('GET_INFO')">Get statistic</button>
|
||||||
|
<button class="btn btn-success" onclick="statisticRequest('SUBSCRIBE')">Subscribe statistic</button>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
<!-- Path to player js -->
|
<b>How to use the player in the global network</b>
|
||||||
<!-- <script src="free.player.1.8.js"></script> -->
|
<p>
|
||||||
<script src="streamedian_1_8_5_3.min.js"></script>
|
With an empty license file, you can only watch the stream on your computer locally (intranet).<br/>
|
||||||
|
If you would like to stream into the global network please take a key to activate the license.<br/>
|
||||||
|
You have personal 1 month validity key in the personal cabinet.<br/>
|
||||||
|
To activate key, please, use the activation application that is placed:
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Windows:</b> C:\Program Files\Streamedian\WS RTSP Proxy Server\activation_app<br/>
|
||||||
|
<b>Mac OS:</b> /Library/Application Support/Streamedian/WS RTSP Proxy Server/activation_app<br/>
|
||||||
|
<b>Linux (Ubunty, Debian, Centos, Fedora ):</b> /usr/bin/wsp/activation_app<br/>
|
||||||
|
</p>
|
||||||
|
<p>For more information go to <a href="https://streamedian.com/docs/">documentation</a></p>
|
||||||
|
|
||||||
|
<script src="libde265.js"></script>
|
||||||
|
<script src="free.player.3.1.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var scrollStatPl = true;
|
var scrollStatPl = true;
|
||||||
@@ -171,19 +204,61 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var link = document.createElement('a');
|
||||||
|
let dataHandler = function(data, prefix) {
|
||||||
|
let blob = new Blob([data], {type: "application/mp4"});
|
||||||
|
link.href = window.URL.createObjectURL(blob);
|
||||||
|
link.download = `${prefix}_${formatDate(new Date())}.mp4`;
|
||||||
|
link.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
let formatHandler = function (format) {
|
||||||
|
if (html5Player && html5Canvas) {
|
||||||
|
if (format === 'h265') {
|
||||||
|
html5Player.setAttribute('hidden', true);
|
||||||
|
html5Canvas.removeAttribute('hidden');
|
||||||
|
} else if (format === 'h264') {
|
||||||
|
html5Player.removeAttribute('hidden');
|
||||||
|
html5Canvas.setAttribute('hidden', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(dateObj) {
|
||||||
|
let month = String(dateObj.getMonth() + 1).padStart(2, '0');
|
||||||
|
let date = String(dateObj.getDate()).padStart(2, '0');
|
||||||
|
let hours = String(dateObj.getHours()).padStart(2, '0');
|
||||||
|
let minutes = String(dateObj.getMinutes()).padStart(2, '0');
|
||||||
|
let seconds = String(dateObj.getSeconds()).padStart(2, '0');
|
||||||
|
return`${dateObj.getFullYear()}-${month}-${date} ${hours}:${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
|
||||||
var playerOptions = {
|
var playerOptions = {
|
||||||
socket: "ws://localhost:1554/ws/test/live1", redirectNativeMediaErrors : true,
|
socket: "ws://localhost:8088/ws/",
|
||||||
|
redirectNativeMediaErrors : true,
|
||||||
bufferDuration: 30,
|
bufferDuration: 30,
|
||||||
errorHandler: errHandler,
|
errorHandler: errHandler,
|
||||||
infoHandler: infHandler
|
infoHandler: infHandler,
|
||||||
|
dataHandler: dataHandler,
|
||||||
|
videoFormatHandler: formatHandler,
|
||||||
|
continuousFileLength: 180000,
|
||||||
|
eventFileLength: 10000,
|
||||||
|
canvas: 'video_canvas',
|
||||||
};
|
};
|
||||||
|
|
||||||
var html5Player = document.getElementById("test_video");
|
var html5Player = document.getElementById("test_video");
|
||||||
|
var html5Canvas = document.getElementById("video_canvas");
|
||||||
var urlButton = document.getElementById("set_new_url");
|
var urlButton = document.getElementById("set_new_url");
|
||||||
var urlEdit = document.getElementById("stream_url");
|
var urlEdit = document.getElementById("stream_url");
|
||||||
var bufferRange = document.getElementById("buffer_duration");
|
var bufferRange = document.getElementById("buffer_duration");
|
||||||
var bufferValue = document.getElementById("buffer_value");
|
var bufferValue = document.getElementById("buffer_value");
|
||||||
|
var continuousRecording = document.getElementById("continuous_recording");
|
||||||
|
var eventRecording = document.getElementById("event_recording");
|
||||||
|
var continuousFileLength = document.getElementById("continuous_file_length");
|
||||||
|
var continuousFileLengthLabel = document.getElementById("continuous_file_length_label");
|
||||||
|
var eventFileLength = document.getElementById("event_file_length");
|
||||||
|
var eventFileLengthLabel = document.getElementById("event_file_length_label");
|
||||||
|
|
||||||
var player = Streamedian.player('test_video', playerOptions);
|
var player = Streamedian.player('test_video', playerOptions);
|
||||||
var nativePlayer = document.getElementById('test_video');
|
var nativePlayer = document.getElementById('test_video');
|
||||||
@@ -191,6 +266,10 @@
|
|||||||
var set_live = document.getElementById('to_end');
|
var set_live = document.getElementById('to_end');
|
||||||
var range_out = document.getElementById('rate_res');
|
var range_out = document.getElementById('rate_res');
|
||||||
|
|
||||||
|
var socket;
|
||||||
|
var keepAliveTimer;
|
||||||
|
var password = btoa('streamedian');
|
||||||
|
|
||||||
range.addEventListener('input', function () {
|
range.addEventListener('input', function () {
|
||||||
nativePlayer.playbackRate = range.value;
|
nativePlayer.playbackRate = range.value;
|
||||||
range_out.innerHTML = `x${range.value}`;
|
range_out.innerHTML = `x${range.value}`;
|
||||||
@@ -201,10 +280,33 @@
|
|||||||
nativePlayer.playbackRate = 1;
|
nativePlayer.playbackRate = 1;
|
||||||
nativePlayer.currentTime = nativePlayer.buffered.end(0);
|
nativePlayer.currentTime = nativePlayer.buffered.end(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Tab switching and window minimization processing
|
||||||
|
// for browsers that use the chrome rendering engine.
|
||||||
|
if (!!window.chrome) {
|
||||||
|
document.addEventListener('visibilitychange', function() {
|
||||||
|
if(document.visibilityState === 'hidden') {
|
||||||
|
nativePlayer.pause()
|
||||||
|
} else {
|
||||||
|
nativePlayer.play();
|
||||||
|
|
||||||
|
// Automatic jump to buffer end for view live video when returning to the web page.
|
||||||
|
setTimeout(function() {
|
||||||
|
nativePlayer.currentTime = nativePlayer.buffered.end(0)
|
||||||
|
}, 3000); // Delay for a few seconds is required for the player has time to update the timeline.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var updateRangeControls = function(){
|
var updateRangeControls = function(){
|
||||||
bufferRange.value = player.bufferDuration;
|
bufferRange.value = player.bufferDuration;
|
||||||
bufferValue.innerHTML = bufferRange.value + "sec.";
|
bufferValue.innerHTML = bufferRange.value + "sec.";
|
||||||
|
|
||||||
|
continuousFileLength.value = player.continuousRecording.fileLength;
|
||||||
|
continuousFileLengthLabel.innerText = `${continuousFileLength.value / 1000} sec.`;
|
||||||
|
|
||||||
|
eventFileLength.value = player.eventRecording.fileLength;
|
||||||
|
event_file_length_label.innerText = `${eventFileLength.value / 1000} sec.`;
|
||||||
};
|
};
|
||||||
|
|
||||||
bufferRange.addEventListener('input', function(){
|
bufferRange.addEventListener('input', function(){
|
||||||
@@ -216,6 +318,32 @@
|
|||||||
bufferRange.innerHTML = player.bufferDuration + "sec.";
|
bufferRange.innerHTML = player.bufferDuration + "sec.";
|
||||||
updateRangeControls();
|
updateRangeControls();
|
||||||
|
|
||||||
|
continuousRecording.addEventListener('change', function(event) {
|
||||||
|
player.continuousRecording.record(event.target.checked);
|
||||||
|
continuousFileLength.disabled = event.target.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
eventRecording.addEventListener('click', function(event) {
|
||||||
|
let state = !event.target.classList.contains('btn-recording');
|
||||||
|
player.eventRecording.record(state);
|
||||||
|
event.target.classList.toggle('btn-success');
|
||||||
|
event.target.classList.toggle('btn-recording');
|
||||||
|
event.target.innerText = state ? 'Stop recording': 'Start recording';
|
||||||
|
eventFileLength.disabled = state;
|
||||||
|
});
|
||||||
|
|
||||||
|
continuousFileLength.addEventListener('input', function(event) {
|
||||||
|
let milliseconds = parseInt(event.target.value, 10);
|
||||||
|
player.continuousRecording.fileLength = milliseconds;
|
||||||
|
continuousFileLengthLabel.innerText = `${milliseconds / 1000} sec.`;
|
||||||
|
});
|
||||||
|
|
||||||
|
eventFileLength.addEventListener('input', function(event) {
|
||||||
|
let milliseconds = parseInt(event.target.value, 10);
|
||||||
|
player.eventRecording.fileLength = milliseconds;
|
||||||
|
eventFileLengthLabel.innerText = `${milliseconds / 1000} sec.`;
|
||||||
|
});
|
||||||
|
|
||||||
urlButton.onclick = ()=> {
|
urlButton.onclick = ()=> {
|
||||||
setPlayerSource(urlEdit.value);
|
setPlayerSource(urlEdit.value);
|
||||||
};
|
};
|
||||||
@@ -243,8 +371,101 @@
|
|||||||
rtspUrl.pathname = "/ws"+rtspUrl.pathname
|
rtspUrl.pathname = "/ws"+rtspUrl.pathname
|
||||||
playerOptions.socket = rtspUrl.href
|
playerOptions.socket = rtspUrl.href
|
||||||
// <========= end
|
// <========= end
|
||||||
|
|
||||||
player = Streamedian.player("test_video", playerOptions);
|
player = Streamedian.player("test_video", playerOptions);
|
||||||
|
player.continuousRecording.record(continuousRecording.checked);
|
||||||
updateRangeControls();
|
updateRangeControls();
|
||||||
|
|
||||||
|
eventRecording.removeAttribute('disabled');
|
||||||
|
set_live.removeAttribute('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
file_input.addEventListener('change', function(event) {
|
||||||
|
html5Player.src = URL.createObjectURL(event.target.files[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('unload', function() {
|
||||||
|
player.continuousRecording.record(false);
|
||||||
|
player.eventRecording.record(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
function statisticRequest(cmd) {
|
||||||
|
if (socket == undefined || socket.readyState != 1) {
|
||||||
|
socket = new WebSocket(playerOptions.socket, "statistic");
|
||||||
|
socket.onmessage = onStatistic;
|
||||||
|
socket.onopen = function() {
|
||||||
|
socket.send(`WSP/1.1 ${cmd}\nAuthorization: ${password}\nseq: 1\n\n`);
|
||||||
|
|
||||||
|
keepAliveTimer = setInterval(()=>{
|
||||||
|
socket.send(`WSP/1.1 KEEPALIVE\nAuthorization: ${password}\nseq: 1\n\n`);
|
||||||
|
}, 30000); // Every 30 seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.onclose = function() {
|
||||||
|
clearInterval(keepAliveTimer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
socket.send(`WSP/1.1 ${cmd}\nAuthorization: ${password}\nseq: 1\n\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStatistic(msg) {
|
||||||
|
if (msg.data.length) {
|
||||||
|
let data = msg.data.split('\r\n\r\n');
|
||||||
|
|
||||||
|
if (data.length > 1) {
|
||||||
|
parseStatistic(JSON.parse(data[1]));
|
||||||
|
} else {
|
||||||
|
console.log("------------- Info -------------");
|
||||||
|
parseSession(JSON.parse(data[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseSession(session) {
|
||||||
|
console.log(`Requested domain: ${session.user.requestedDomain}`);
|
||||||
|
console.log(`User address: ${session.user.address}`);
|
||||||
|
console.log(`RTSP address: ${session.rtsp.host}:${session.rtsp.port}`);
|
||||||
|
console.log(`Session start time: ${new Date(Number(session.connectionTime + '000'))}`);
|
||||||
|
|
||||||
|
if (session.disconnectionTime) {
|
||||||
|
console.log(`Session end time: ${new Date(Number(session.disconnectionTime + '000'))}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('---');
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseStatistic(data) {
|
||||||
|
for (let i = 0; i < data.licenses.length; i++) {
|
||||||
|
let license = data.licenses[i].license;
|
||||||
|
let sessions = data.licenses[i].sessions;
|
||||||
|
let sessionNumber = data.licenses[i].sessionNumber;
|
||||||
|
|
||||||
|
console.log("------------- Info -------------");
|
||||||
|
console.log(' License ' + i);
|
||||||
|
console.log(`Activation Key: ${license.key}`)
|
||||||
|
console.log(`Expires: ${license.expiresAt}`);
|
||||||
|
console.log(`License max posible watchers: ${license.maxWatchers}`);
|
||||||
|
|
||||||
|
if (license.maxWatchers !== 'unlimited') {
|
||||||
|
console.log(`Remain watchers: ${license.maxWatchers - sessionNumber}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Sessions:');
|
||||||
|
for (let j = 0; j < sessions.length; j++) {
|
||||||
|
parseSession(sessions[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatistic() {
|
||||||
|
statisticRequest('GET_INFO', password);
|
||||||
|
socket.onmessage = statisticInfoParse;
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribeStatistic() {
|
||||||
|
statisticRequest('SUBSCRIBE', password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
11425
demos/wsp/libde265.js
Normal file
11425
demos/wsp/libde265.js
Normal file
File diff suppressed because one or more lines are too long
0
demos/wsp/style.css
Executable file → Normal file
0
demos/wsp/style.css
Executable file → Normal file
Reference in New Issue
Block a user