This commit is contained in:
ziyue 2021-06-08 14:41:52 +08:00
commit 9de39de88c
8 changed files with 404 additions and 217 deletions

View File

@ -402,7 +402,10 @@ void installWebApi() {
for (auto &pr : allArgs) { for (auto &pr : allArgs) {
if (ini.find(pr.first) == ini.end()) { if (ini.find(pr.first) == ini.end()) {
//没有这个key //没有这个key
continue; //continue;
// 新增配置选项,为了动态添加多个ffmpeg cmd 模板
ini[pr.first] = pr.second;
continue;// 防止changed变化
} }
if (ini[pr.first] == pr.second) { if (ini[pr.first] == pr.second) {
continue; continue;

View File

@ -183,7 +183,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
} }
} }
if(_lastPacket && (_lastPacket->time_stamp != frame->dts() || type == H264Frame::NAL_B_P)) { if(_lastPacket && (_lastPacket->time_stamp != frame->dts() || pcData[1]&0x80 != 0)) {
RtmpCodec::inputRtmp(_lastPacket); RtmpCodec::inputRtmp(_lastPacket);
_lastPacket = nullptr; _lastPacket = nullptr;
} }
@ -214,10 +214,12 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
_lastPacket->buffer.append((char *) &size, 4); _lastPacket->buffer.append((char *) &size, 4);
_lastPacket->buffer.append(pcData, iLen); _lastPacket->buffer.append(pcData, iLen);
_lastPacket->body_size = _lastPacket->buffer.size(); _lastPacket->body_size = _lastPacket->buffer.size();
/*
if (type == H264Frame::NAL_B_P) { if (type == H264Frame::NAL_B_P) {
RtmpCodec::inputRtmp(_lastPacket); RtmpCodec::inputRtmp(_lastPacket);
_lastPacket = nullptr; _lastPacket = nullptr;
} }
*/
} }
void H264RtmpEncoder::makeVideoConfigPkt() { void H264RtmpEncoder::makeVideoConfigPkt() {

View File

@ -463,6 +463,9 @@ void RtmpSession::onRtmpChunk(RtmpPacket::Ptr packet) {
std::string type = dec.load<std::string>(); std::string type = dec.load<std::string>();
if (type == "@setDataFrame") { if (type == "@setDataFrame") {
setMetaData(dec); setMetaData(dec);
} else if(type == "onMetaData"){
//setMetaData(dec);
_publisher_metadata = dec.load<AMFValue>();
}else { }else {
TraceP(this) << "unknown notify:" << type; TraceP(this) << "unknown notify:" << type;
} }

View File

@ -4,13 +4,14 @@ var ZLMRTCClient = (function (exports) {
const Events$1 = { const Events$1 = {
WEBRTC_NOT_SUPPORT: 'WEBRTC_NOT_SUPPORT', WEBRTC_NOT_SUPPORT: 'WEBRTC_NOT_SUPPORT',
WEBRTC_ICE_CANDIDATE_ERROR: 'WEBRTC_ICE_CANDIDATE_ERROR', WEBRTC_ICE_CANDIDATE_ERROR: 'WEBRTC_ICE_CANDIDATE_ERROR',
WEBRTC_OFFER_answer_EXCHANGE_FAILED: 'WEBRTC_OFFER_answer_EXCHANGE_FAILED', WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED: 'WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED',
WEBRTC_ON_REMOTE_STREAMS: 'WEBRTC_ON_REMOTE_STREAMS', WEBRTC_ON_REMOTE_STREAMS: 'WEBRTC_ON_REMOTE_STREAMS',
WEBRTC_ON_LOCAL_STREAM: 'WEBRTC_ON_LOCAL_STREAM' WEBRTC_ON_LOCAL_STREAM: 'WEBRTC_ON_LOCAL_STREAM',
CAPTURE_STREAM_FAILED: 'CAPTURE_STREAM_FAILED'
}; };
const VERSION = '1.0.1'; const VERSION = '1.0.1';
const BUILD_DATE = 'Wed Mar 31 2021 14:49:19 GMT+0800 (China Standard Time)'; const BUILD_DATE = 'Mon Jun 07 2021 18:09:53 GMT+0800 (China Standard Time)';
// Copyright (C) <2018> Intel Corporation // Copyright (C) <2018> Intel Corporation
// //
@ -7284,7 +7285,15 @@ var ZLMRTCClient = (function (exports) {
debug: false, debug: false,
// if output debug log // if output debug log
zlmsdpUrl: '', zlmsdpUrl: '',
simulecast: false simulecast: false,
useCamera: true,
audioEnable: true,
videoEnable: true,
recvOnly: false,
resolution: {
w: 0,
h: 0
}
}; };
this.options = Object.assign({}, defaults, options); this.options = Object.assign({}, defaults, options);
@ -7303,13 +7312,80 @@ var ZLMRTCClient = (function (exports) {
this.pc.onicecandidate = this.e.onicecandidate; this.pc.onicecandidate = this.e.onicecandidate;
this.pc.onicecandidateerror = this.e.onicecandidateerror; this.pc.onicecandidateerror = this.e.onicecandidateerror;
this.pc.ontrack = this.e.ontrack; this.pc.ontrack = this.e.ontrack;
this.start(); if (!this.options.recvOnly && (this.options.audioEnable || this.options.videoEnable)) this.start();else this.receive();
}
receive() {
const AudioTransceiverInit = {
direction: 'recvonly',
sendEncodings: []
};
const VideoTransceiverInit = {
direction: 'recvonly',
sendEncodings: []
};
this.pc.addTransceiver('audio', AudioTransceiverInit);
this.pc.addTransceiver('video', VideoTransceiverInit);
this.pc.createOffer().then(desc => {
log(this.TAG, 'offer:', desc.sdp);
this.pc.setLocalDescription(desc).then(() => {
axios({
method: 'post',
url: this.options.zlmsdpUrl,
responseType: 'json',
data: desc.sdp,
headers: {
'Content-Type': 'text/plain;charset=utf-8'
}
}).then(response => {
let ret = response.data; //JSON.parse(response.data);
if (ret.code != 0) {
// mean failed for offer/anwser exchange
this.dispatch(Events$1.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, ret);
return;
}
let anwser = {};
anwser.sdp = ret.sdp;
anwser.type = 'answer';
log(this.TAG, 'answer:', ret.sdp);
this.pc.setRemoteDescription(anwser).then(() => {
log(this.TAG, 'set remote sucess');
}).catch(e => {
error(this.TAG, e);
});
});
});
}).catch(e => {
error(this.TAG, e);
});
} }
start() { start() {
//todo 此处修改捕获桌面或摄像头 let videoConstraints = false;
let audioConstraints = new AudioTrackConstraints(AudioSourceInfo.MIC); let audioConstraints = false;
let videoConstraints = new VideoTrackConstraints(VideoSourceInfo.CAMERA);
if (this.options.useCamera) {
if (this.options.videoEnable) videoConstraints = new VideoTrackConstraints(VideoSourceInfo.CAMERA);
if (this.options.audioEnable) audioConstraints = new AudioTrackConstraints(AudioSourceInfo.MIC);
} else {
if (this.options.videoEnable) {
videoConstraints = new VideoTrackConstraints(VideoSourceInfo.SCREENCAST);
if (this.options.audioEnable) audioConstraints = new AudioTrackConstraints(AudioSourceInfo.SCREENCAST);
} else {
if (this.options.audioEnable) audioConstraints = new AudioTrackConstraints(AudioSourceInfo.MIC);else {
// error shared display media not only audio
error(this.TAG, 'error paramter');
}
}
}
if (this.options.resolution.w != 0 && this.options.resolution.h != 0 && typeof videoConstraints == 'object') {
videoConstraints.resolution = new Resolution(this.options.resolution.w, this.options.resolution.h);
}
MediaStreamFactory.createMediaStream(new StreamConstraints(audioConstraints, videoConstraints)).then(stream => { MediaStreamFactory.createMediaStream(new StreamConstraints(audioConstraints, videoConstraints)).then(stream => {
this._localStream = stream; this._localStream = stream;
this.dispatch(Events$1.WEBRTC_ON_LOCAL_STREAM, stream); this.dispatch(Events$1.WEBRTC_ON_LOCAL_STREAM, stream);
@ -7322,7 +7398,7 @@ var ZLMRTCClient = (function (exports) {
sendEncodings: [] sendEncodings: []
}; };
if (this.options.simulecast) { if (this.options.simulecast && stream.getVideoTracks().length > 0) {
VideoTransceiverInit.sendEncodings = [{ VideoTransceiverInit.sendEncodings = [{
rid: 'q', rid: 'q',
active: true, active: true,
@ -7337,8 +7413,19 @@ var ZLMRTCClient = (function (exports) {
}]; }];
} }
if (stream.getAudioTracks().length > 0) {
this.pc.addTransceiver(stream.getAudioTracks()[0], AudioTransceiverInit); this.pc.addTransceiver(stream.getAudioTracks()[0], AudioTransceiverInit);
} else {
AudioTransceiverInit.direction = 'recvonly';
this.pc.addTransceiver('audio', AudioTransceiverInit);
}
if (stream.getVideoTracks().length > 0) {
this.pc.addTransceiver(stream.getVideoTracks()[0], VideoTransceiverInit); this.pc.addTransceiver(stream.getVideoTracks()[0], VideoTransceiverInit);
} else {
VideoTransceiverInit.direction = 'recvonly';
this.pc.addTransceiver('video', VideoTransceiverInit);
}
/* /*
stream.getTracks().forEach((track,idx)=>{ stream.getTracks().forEach((track,idx)=>{
debug.log(this.TAG,track); debug.log(this.TAG,track);
@ -7346,6 +7433,7 @@ var ZLMRTCClient = (function (exports) {
}); });
*/ */
this.pc.createOffer().then(desc => { this.pc.createOffer().then(desc => {
log(this.TAG, 'offer:', desc.sdp); log(this.TAG, 'offer:', desc.sdp);
this.pc.setLocalDescription(desc).then(() => { this.pc.setLocalDescription(desc).then(() => {
@ -7358,19 +7446,19 @@ var ZLMRTCClient = (function (exports) {
'Content-Type': 'text/plain;charset=utf-8' 'Content-Type': 'text/plain;charset=utf-8'
} }
}).then(response => { }).then(response => {
let ret = response.data; let ret = response.data; //JSON.parse(response.data);
if (ret.code != 0) { if (ret.code != 0) {
// mean failed for offer/answer exchange // mean failed for offer/anwser exchange
this.dispatch(Events$1.WEBRTC_OFFER_answer_EXCHANGE_FAILED, ret); this.dispatch(Events$1.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, ret);
return; return;
} }
let answer = {}; let anwser = {};
answer.sdp = ret.sdp; anwser.sdp = ret.sdp;
answer.type = 'answer'; anwser.type = 'answer';
log(this.TAG, 'answer:', ret.sdp); log(this.TAG, 'answer:', ret.sdp);
this.pc.setRemoteDescription(answer).then(() => { this.pc.setRemoteDescription(anwser).then(() => {
log(this.TAG, 'set remote sucess'); log(this.TAG, 'set remote sucess');
}).catch(e => { }).catch(e => {
error(this.TAG, e); error(this.TAG, e);
@ -7381,7 +7469,7 @@ var ZLMRTCClient = (function (exports) {
error(this.TAG, e); error(this.TAG, e);
}); });
}).catch(e => { }).catch(e => {
error(this.TAG, e); this.dispatch(Events$1.CAPTURE_STREAM_FAILED); //debug.error(this.TAG,e);
}); //const offerOptions = {}; }); //const offerOptions = {};
/* /*
@ -7449,15 +7537,108 @@ var ZLMRTCClient = (function (exports) {
} }
const quickScan = [{
'label': '4K(UHD)',
'width': 3840,
'height': 2160
}, {
'label': '1080p(FHD)',
'width': 1920,
'height': 1080
}, {
'label': 'UXGA',
'width': 1600,
'height': 1200,
'ratio': '4:3'
}, {
'label': '720p(HD)',
'width': 1280,
'height': 720
}, {
'label': 'SVGA',
'width': 800,
'height': 600
}, {
'label': 'VGA',
'width': 640,
'height': 480
}, {
'label': '360p(nHD)',
'width': 640,
'height': 360
}, {
'label': 'CIF',
'width': 352,
'height': 288
}, {
'label': 'QVGA',
'width': 320,
'height': 240
}, {
'label': 'QCIF',
'width': 176,
'height': 144
}, {
'label': 'QQVGA',
'width': 160,
'height': 120
}];
function GetSupportCameraResolutions$1() {
return new Promise(function (resolve, reject) {
let resolutions = [];
let ok = 0;
let err = 0;
for (let i = 0; i < quickScan.length; ++i) {
let videoConstraints = new VideoTrackConstraints(VideoSourceInfo.CAMERA);
videoConstraints.resolution = new Resolution(quickScan[i].width, quickScan[i].height);
MediaStreamFactory.createMediaStream(new StreamConstraints(false, videoConstraints)).then(stream => {
resolutions.push(quickScan[i]);
ok++;
if (ok + err == quickScan.length) {
resolve(resolutions);
}
}).catch(e => {
err++;
if (ok + err == quickScan.length) {
resolve(resolutions);
}
});
}
});
}
function GetAllScanResolution$1() {
return quickScan;
}
function isSupportResolution$1(w, h) {
return new Promise(function (resolve, reject) {
let videoConstraints = new VideoTrackConstraints(VideoSourceInfo.CAMERA);
videoConstraints.resolution = new Resolution(w, h);
MediaStreamFactory.createMediaStream(new StreamConstraints(false, videoConstraints)).then(stream => {
resolve();
}).catch(e => {
reject(e);
});
});
}
console.log('build date:', BUILD_DATE); console.log('build date:', BUILD_DATE);
console.log('version:', VERSION); console.log('version:', VERSION);
const Events = Events$1; const Events = Events$1;
const Media = media; const Media = media;
const Endpoint = RTCEndpoint; const Endpoint = RTCEndpoint;
const GetSupportCameraResolutions = GetSupportCameraResolutions$1;
const GetAllScanResolution = GetAllScanResolution$1;
const isSupportResolution = isSupportResolution$1;
exports.Endpoint = Endpoint; exports.Endpoint = Endpoint;
exports.Events = Events; exports.Events = Events;
exports.GetAllScanResolution = GetAllScanResolution;
exports.GetSupportCameraResolutions = GetSupportCameraResolutions;
exports.Media = Media; exports.Media = Media;
exports.isSupportResolution = isSupportResolution;
Object.defineProperty(exports, '__esModule', { value: true }); Object.defineProperty(exports, '__esModule', { value: true });

File diff suppressed because one or more lines are too long

192
www/webrtc/index.html Normal file
View File

@ -0,0 +1,192 @@
<html>
<meta charset="utf-8">
<head>
<title>ZLM RTC demo</title>
<script src="./ZLMRTCClient.js"></script>
</head>
<body>
<div style="text-align: center;">
<div>
<video id='video' controls autoplay style="text-align:left;">
Your browser is too old which doesn't support HTML5 video.
</video>
<video id='selfVideo' controls autoplay style="text-align:right;">
Your browser is too old which doesn't support HTML5 video.
</video>
</div>
<div>
<p>
<label for="streamUrl">url:</label>
<input type="text" style="co" id='streamUrl' value="http://127.0.0.1/index/api/webrtc?app=live&stream=test&type=play">
</p>
<p>
<label for="simulecast">simulecast:</label>
<input type="checkbox" id='simulecast' checked="checked">
</p>
<p>
<label for="useCamera">useCamera:</label>
<input type="checkbox" id='useCamera' checked="checked">
</p>
<p>
<label for="audioEnable">audioEnable:</label>
<input type="checkbox" id='audioEnable' checked="checked">
</p>
<p>
<label for="videoEnable">videoEnable:</label>
<input type="checkbox" id='videoEnable' checked="checked">
</p>
<p>
<label for="methond">methond(play or push):</label>
<input type="radio" name="methond" value="push" >push
<input type="radio" name="methond" value="play" checked = true>play
</p>
<p>
<label for="resilution">resolution:</label>
<select id="resilution">
</select>
</p>
<button onclick="start()">开始</button>
<button onclick="stop()">停止</button>
</div>
</div>
<script>
var player = null
var recvOnly = true
var resArr = []
document.getElementsByName("methond").forEach((el,idx)=>{
el.onclick=function(e){
if(el.value == "play")
{
let url = document.getElementById('streamUrl').value;
document.getElementById('streamUrl').value = url.replace("&type=push","&type=play");
recvOnly = true;
}
else
{
let url = document.getElementById('streamUrl').value;
document.getElementById('streamUrl').value = url.replace("&type=play","&type=push");
recvOnly = false;
}
};
});
ZLMRTCClient.GetAllScanResolution().forEach((r,i)=>{
opt = document.createElement('option');
opt.text = r.label +"("+r.width+"x"+r.height+")";
opt.value = r;
document.getElementById("resilution").add(opt,null)
//console.log(opt.text.match(/\d+/g))
})
function start_play(){
let elr = document.getElementById("resilution");
let res = elr.options[elr.selectedIndex].text.match(/\d+/g);
let h = parseInt(res.pop());
let w = parseInt(res.pop());
player = new ZLMRTCClient.Endpoint(
{
element: document.getElementById('video'),// video 标签
debug: true,// 是否打印日志
zlmsdpUrl:document.getElementById('streamUrl').value,//流地址
simulecast:false,//document.getElementById('simulecast').checked,
useCamera:document.getElementById('useCamera').checked,
audioEnable:document.getElementById('audioEnable').checked,
videoEnable:document.getElementById('videoEnable').checked,
recvOnly:recvOnly,
resolution:{w:w,h:h}
}
);
player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,function(e)
{// ICE 协商出错
console.log('ICE 协商出错')
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,function(e)
{//获取到了远端流,可以播放
console.log('播放成功',e.streams)
});
player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,function(e)
{// offer anwser 交换失败
console.log('offer anwser 交换失败',e)
stop();
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,function(s)
{// 获取到了本地流
document.getElementById('selfVideo').srcObject=s;
document.getElementById('selfVideo').muted = true;
//console.log('offer anwser 交换失败',e)
});
player.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED,function(s)
{// 获取本地流失败
console.log('获取本地流失败')
});
}
function start()
{
stop();
let elr = document.getElementById("resilution");
let res = elr.options[elr.selectedIndex].text.match(/\d+/g);
let h = parseInt(res.pop());
let w = parseInt(res.pop());
if(document.getElementById('useCamera').checked && !recvOnly)
{
ZLMRTCClient.isSupportResolution(w,h).then(e=>{
start_play()
}).catch(e=>{
alert("not support resolution")
});
}else{
start_play()
}
}
function stop()
{
if(player)
{
player.close();
player = null;
var local = document.getElementById('selfVideo');
local.removeAttribute('srcObject');
local.load();
}
}
</script>
</body>
<script>
</script>
</html>

View File

@ -1,97 +0,0 @@
<html>
<meta charset="utf-8">
<head>
<title>ZLM RTC demo</title>
<script src="./ZLMRTCClient.js"></script>
</head>
<body>
<div style="text-align: center;">
<div>
<video id='video' controls autoplay style="text-align:left;">
Your browser is too old which doesn't support HTML5 video.
</video>
<video id='selfVideo' controls autoplay style="text-align:right;">
Your browser is too old which doesn't support HTML5 video.
</video>
</div>
<div>
<p>
<label for="streamUrl">url:</label>
<input type="text" id='streamUrl' value="http://127.0.0.1/index/api/webrtc?app=live&stream=test&type=play">
</p>
<p>
<label for="simulecast">simulecast:</label>
<input type="checkbox" id='simulecast'>
</p>
<button onclick="start()">开始</button>
<button onclick="stop()">停止</button>
</div>
</div>
<script>
var player = null
function start()
{
stop();
player = new ZLMRTCClient.Endpoint(
{
element: document.getElementById('video'),// video 标签
debug: true,// 是否打印日志
zlmsdpUrl:document.getElementById('streamUrl').value,//流地址
simulecast:document.getElementById('simulecast').checked
}
);
player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,function(e)
{// ICE 协商出错
console.log('ICE 协商出错')
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,function(e)
{//获取到了远端流,可以播放
console.log('播放成功',e.streams)
});
player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,function(e)
{// offer anwser 交换失败
console.log('offer anwser 交换失败',e)
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,function(s)
{// 获取到了本地流
document.getElementById('selfVideo').srcObject=s;
//console.log('offer anwser 交换失败',e)
});
}
function stop()
{
if(player)
{
player.close();
player = null;
var local = document.getElementById('selfVideo');
local.removeAttribute('srcObject');
local.load();
}
}
</script>
</body>
<script>
</script>
</html>

View File

@ -1,97 +0,0 @@
<html>
<meta charset="utf-8">
<head>
<title>ZLM RTC demo</title>
<script src="./ZLMRTCClient.js"></script>
</head>
<body>
<div style="text-align: center;">
<div>
<video id='video' controls autoplay style="text-align:left;">
Your browser is too old which doesn't support HTML5 video.
</video>
<video id='selfVideo' controls autoplay style="text-align:right;">
Your browser is too old which doesn't support HTML5 video.
</video>
</div>
<div>
<p>
<label for="streamUrl">url:</label>
<input type="text" id='streamUrl' value="http://127.0.0.1/index/api/webrtc?app=live&stream=test&type=push">
</p>
<p>
<label for="simulecast">simulecast:</label>
<input type="checkbox" id='simulecast'>
</p>
<button onclick="start()">开始</button>
<button onclick="stop()">停止</button>
</div>
</div>
<script>
var player = null
function start()
{
stop();
player = new ZLMRTCClient.Endpoint(
{
element: document.getElementById('video'),// video 标签
debug: true,// 是否打印日志
zlmsdpUrl:document.getElementById('streamUrl').value,//流地址
simulecast:document.getElementById('simulecast').checked
}
);
player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,function(e)
{// ICE 协商出错
console.log('ICE 协商出错')
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,function(e)
{//获取到了远端流,可以播放
console.log('播放成功',e.streams)
});
player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,function(e)
{// offer anwser 交换失败
console.log('offer anwser 交换失败',e)
});
player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,function(s)
{// 获取到了本地流
document.getElementById('selfVideo').srcObject=s;
//console.log('offer anwser 交换失败',e)
});
}
function stop()
{
if(player)
{
player.close();
player = null;
var local = document.getElementById('selfVideo');
local.removeAttribute('srcObject');
local.load();
}
}
</script>
</body>
<script>
</script>
</html>