1.还是基于h5stream的h5splayer.js学习,还是基于websocket。

与原来的不同,在onopen里面要发送一些open指令

            ws.onopen = function () {inc.innerHTML += '.. connection open<br/>';var t = {type: "open"};ws.send(JSON.stringify(t))};

然后会onreceive里面会受到一些信息。

connecting to server ..
.. connection open
receive:{"sdp" : "v=0\r\no=- 2612379890657624089 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE video\r\na=msid-semantic: WMS token1\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:M7/v\r\na=ice-pwd:s+xvE6/hacBd5++3xPE+1qpT\r\na=ice-options:trickle\r\na=fingerprint:sha-256 44:D2:9C:A6:A3:9F:01:5C:AD:CE:86:E6:2F:E8:EF:C0:6D:26:68:F5:2E:6A:82:89:C8:87:74:42:C8:FC:7F:F5\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 H264/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=fmtp:96 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 H264/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 red/90000\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:127 ulpfec/90000\r\na=ssrc-group:FID 3833096967 1073194061\r\na=ssrc:3833096967 cname:C1L/zoQ17dXx0SDt\r\na=ssrc:3833096967 msid:token1 video_label\r\na=ssrc:3833096967 mslabel:token1\r\na=ssrc:3833096967 label:video_label\r\na=ssrc:1073194061 cname:C1L/zoQ17dXx0SDt\r\na=ssrc:1073194061 msid:token1 video_label\r\na=ssrc:1073194061 mslabel:token1\r\na=ssrc:1073194061 label:video_label\r\n","type" : "offer"
}type:string   length:2130
receive:{"candidate" : "candidate:725387133 1 tcp 1518280447 169.254.250.71 50001 typ host tcptype passive generation 0 ufrag M7/v network-id 1","sdpMLineIndex" : 0,"sdpMid" : "video","type" : "remoteice"
}type:string   length:215
receive:{"candidate" : "candidate:3525817373 1 tcp 1518214911 192.168.6.12 50001 typ host tcptype passive generation 0 ufrag M7/v network-id 2","sdpMLineIndex" : 0,"sdpMid" : "video","type" : "remoteice"
}type:string   length:214
receive:{"candidate" : "candidate:2564955588 1 tcp 1518149375 192.168.1.16 50001 typ host tcptype passive generation 0 ufrag M7/v network-id 3","sdpMLineIndex" : 0,"sdpMid" : "video","type" : "remoteice"
}type:string   length:214

从type来看,第一个是offer,后面三个是remoteice

对应不同的消息,做不同的处理

对于offer(请求),创建RTCPeerConnection,参考:https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection

一个基本的RTCPeerConnection使用需要协调本地机器以及远端机器的连接,它可以通过在两台机器间生成Session Description的数据交换协议来实现。呼叫方发送一个offer(请求),被呼叫方发出一个answer(应答)来回答请求。双方-呼叫方以及被呼叫方,最开始的时候都要建立他们各自的RTCPeerConnection对象。

setRemoteDescription=>onaddstream=>URL.createObjectURL,video.play()

createAnswer,setLocalDescription

代码 rtc.html,虽然功能还没有实现。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>websocket client</title><script src="js/jquery-3.1.1.js"></script><script src="js/adapter.js"></script><script type="text/javascript">var count=0;function getImageString(arrayBuffer){var bytes = new Uint8Array(arrayBuffer);var binary= "";var len = bytes.byteLength;for (var i = 0; i < len; i++) {binary += String.fromCharCode( bytes[ i ] )}var src="https://img-blog.csdnimg.cn/2022010702372264874.png"+window.btoa( binary );//png,jpg都没有关系return src;}function loadImage(imgId,data){var reader = new FileReader();reader.onload = () => {var img = document.getElementById(imgId);img.src = getImageString(reader.result);};reader.readAsArrayBuffer(data);}function processRTCOffer(offer){var description=new RTCSessionDescription(offer);console.log("ProcessRTCOffer", offer);var config={M:[]};var option={optional:[{DtlsSrtpKeyAgreement: true}]};var connection=new RTCPeerConnection(config,option);connection.onicecandidate=function(event){//只要本地代理ICE 需要通过信令服务器传递信息给其他对等端时就会触发console.log("-------------  RTCPeerConnection.onicecandidate",event);// if (event.candidate) {//     var candidate;//     //console.log("onIceCandidate currentice", event.candidate);//     candidate = event.candidate;//     //console.log("onIceCandidate currentice",candidate, JSON.stringify(candidate));//     var candidateObj = JSON.parse(JSON.stringify(candidate));//     candidateObj.type = "remoteice";//     //console.log("onIceCandidate currentice new", candidateObj, JSON.stringify(candidateObj));//     //ws.send(JSON.stringify(candidateObj));//h5spalyer.js里面有发送,但是测试发现这里不发送也能获取到视频。// }// else {//     console.log("End of candidates.");// }};connection.onaddstream=function(mediaStreamEvent){//console.log("-------------  RTCPeerConnection.onaddstream",mediaStreamEvent);var stream=mediaStreamEvent.stream;var video=document.getElementById('video1');video.src=URL.createObjectURL(stream);//需要引用Adapter.js,默认的URL.createObjectURL不支持MediaSource类型//Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.video.play();//开始播放//Uncaught (in promise) DOMException//需要将video设置为muted(静音),或者由用户点击来播放。};connection.oniceconnectionstatechange=function(event){console.log("-------------  RTCPeerConnection.oniceconnectionstatechange  state: " + connection.iceConnectionState)};connection.setRemoteDescription(description); //=>onaddstreamvar offerOptions={mandatory:{offerToReceiveAudio: true, offerToReceiveVideo: true}};connection.createAnswer(offerOptions).then(function(answer){console.log("Create answer:",answer);//answer is RTCSessionDescriptionconnection.setLocalDescription(answer,function(){ //=>onicecandidateconsole.log("ProcessRTCOffer createAnswer", answer);ws.send(JSON.stringify(answer));//=>onicecandidate});});ws.connection=connection;}function processRemoteIce(remoteIce){var connection=ws.connection;try {var iceCandidate = new RTCIceCandidate({sdpMLineIndex: remoteIce.sdpMLineIndex, candidate: remoteIce.candidate});console.log("ProcessRemoteIce", iceCandidate);//console.log("Adding ICE candidate :" + JSON.stringify(iceCandidate));//当本机当前页面的 RTCPeerConnection 接收到一个从远端页面通过信号通道发来的新的 ICE 候选地址信息,本机可以通过调用RTCPeerConnection.addIceCandidate() 来添加一个 ICE 代理connection.addIceCandidate(iceCandidate, function () {console.log("  addIceCandidate OK")},function (error) {console.log("addIceCandidate error:" + JSON.stringify(error))})}catch (err) {alert("connect ProcessRemoteIce error: " + err)}}var startPlay = function (url) {var inc = document.getElementById('incomming');var wsImpl = window.WebSocket || window.MozWebSocket;var form = document.getElementById('sendForm');var input = document.getElementById('sendText');inc.innerHTML += "connecting to server ..<br/>";window.video=document.getElementById('video1');window.ws = new wsImpl(url);//To receive the image as ArrayBuffer on the client side, you have to specify the binaryType after creating a WebSocket:ws.binaryType = "arraybuffer";//有了这个,就不用FileReader读取Blob的内容了。// when data is comming from the server, this metod is calledws.onmessage = function (evt) {console.log('>>>>> websocket.onmessage');//console.log('onmessage',evt.data);var dataObj = JSON.parse(evt.data);if(dataObj.type =='offer'){ processRTCOffer(dataObj);//第一次}else if (dataObj.type=='remoteice'){processRemoteIce(dataObj);//后面3次}};window.isVideoPlaying=false;// when the connection is established, this method is calledws.onopen = function () {console.log('>>>>> websocket.onopen',video);inc.innerHTML += '.. connection open<br/>';ws.send(JSON.stringify({type: "open"})); //必须发送open指令,不然后续的都无法开始,onmessage将收不到offer};// when the connection is closed, this method is calledws.onclose = function () {inc.innerHTML += '.. connection closed<br/>';}}window.onload = function(){var url=$('#inputUrl').val();$('#btnPlay').click(function(){console.log('play',url);var inc = document.getElementById('incomming');inc.innerHTML="";startPlay(url);});}</script>
</head>
<body><input id='inputUrl' value='ws://localhost:8085/api/v1/h5srtcapi?token=token1&profile=main&session=null' style='width:100%;'/><button id='btnPlay'>play</button><pre id="incomming"></pre><video class="h5video1" id="video1" autoplay webkit-playsinline playsinline></video>
</body>
</html>

其中在video.src=URL.createObjectURL(stream);卡了一下,原来需要引用adapter.js,不然不支持MediaStream类型的参数,导致提示,URL没有createObjectURL函数。

adapter.js里面有个

URL.createObjectURL = function(stream) {if ('getTracks' in stream) {var url = 'polyblob:' + (++newId);streams.set(url, stream);utils.deprecated('URL.createObjectURL(stream)','elem.srcObject = stream');return url;}return nativeCreateObjectURL(stream);};

结果是src="polyblob:1"

------------------------------------------------------------------------

然后在video.play卡住了。

然后不知怎么,多刷新几次,可以了,有一定概率可以播放。

此时:chrome://webrtc-internals/

还是那些代码。

----------------------------------------------------------------------------------------

Uncaught (in promise) DOMException问题处理

参考1:Uncaught (in promise) DOMException谷歌浏览器js报错分析

输入chrome://flags/#autoplay-policy后,我的和它的结果不一样

参考2:解决Chrome浏览器无法自动播放音频视频的问题,Uncaught (in promise) DOMException

解决办法 1.静音 2.让用户手动点击

感觉现在的方式都是让用户点击吧

界面上加个按钮,而之所以我的代码会出错,h5s的代码没这个问题是它原本就是让人点击再播放的。

 window.onload = function(){var url=$('#inputUrl').val();$('#btnPlay').click(function(){console.log('play',url);var inc = document.getElementById('incomming');inc.innerHTML="";startPlay(url);});}</script>
</head>
<body><input id='inputUrl' value='ws://localhost:8085/api/v1/h5srtcapi?token=token1&profile=main&session=null' style='width:100%;'/><button id='btnPlay'>play</button><pre id="incomming"></pre><video class="h5video1" id="video1" autoplay webkit-playsinline playsinline></video>
</body>
</html>

------------------------------------------------------------------------------------

总之就是通过几次请求(offer)、应答(answer),建立的webrtc连接。

最后wireshark里面发现有RTP协议的包

就是不知道是发给浏览器的呢,还是发给H5Stream的呢。

-----------------------------------------------------------------------------------

整理一下代码的过程,

1.通过websocket连接一个ws地址

window.ws = new wsImpl('ws://localhost:8085/api/v1/h5srtcapi?token=token1&profile=main&session=null');//To receive the image as ArrayBuffer on the client side, you have to specify the binaryType after creating a WebSocket:ws.binaryType = "arraybuffer";//有了这个,就不用FileReader读取Blob的内容了。

2.在onopen里面发送open消息

ws.onopen = function () {console.log('>>>>> websocket.onopen',video);inc.innerHTML += '.. connection open<br/>';ws.send(JSON.stringify({type: "open"})); //必须发送open指令,不然后续的都无法开始,onmessage将收不到offer};

3.在onmessage中处理收到的消息,建立webrtc通道

 ws.onmessage = function (evt) {console.log('>>>>> websocket.onmessage');//console.log('onmessage',evt.data);var dataObj = JSON.parse(evt.data);if(dataObj.type =='offer'){ processRTCOffer(dataObj);//第一次}else if (dataObj.type=='remoteice'){processRemoteIce(dataObj);//后面3次}};

3.1 第一次返回的类型是offer,处理

创建RTCPeerConnection,

3.1.1.根据offer,setRemoteDescription,触发onaddstream,用mediastream设置video.src。

3.1.2.createAnswer,根据新的answer设置setLocalDescription,ws发送answer

3.1.3.触发onicecandidate,ws发送candidate(发现不发送也可以)

3.2 后面有3次返回remoteice,处理

3.2.1 RTCPeerConnection添加addIceCandidate

整个过程的事件在chrome://webrtc-internals/里面其实就列出来了。

--------------------------------------------------------------------

我的代码在FireFox中无法使用,H5Sream的可以。而IE则都不行。

网页中播放RTSP(6) WebRTC播放视频相关推荐

  1. html flash 循环播放,在网页中插入flv格式的flash视频怎么让其循环播放_html/css_WEB-ITnose...

    求解 在网页中插入flv格式的flash视频怎么让其循环播放 回复讨论(解决方案) 求解 在网页中插入flv格式的flash视频怎么让其循环播放 这个得让flash coder设置flash播放器吧 ...

  2. 浏览器播放rtsp视频流:3、rtsp转webrtc播放

    浏览器播放rtsp视频流:3.rtsp转webrtc播放 文章目录 浏览器播放rtsp视频流:3.rtsp转webrtc播放 1. 前言 2. rtsp转webRTC 3. 初步测试结果 4. 结合我 ...

  3. 静态博客网页中的网易云音乐播放器

    见我的博客 https://blog.wyue.site/2020/04/12/1/ 转载前请联系我,联系方式请见我博客 https://blog.wyue.site/ 一直想做个博客中的音乐播放器, ...

  4. 网页中插入视频播放,音频播放,自动验证输入框格式

    <body>         <progress value="30" max="100" min="1" >进度条 ...

  5. html播放rtsp流,浏览器播放rtsp视频流解决方案

    最近项目中需要实时播放摄像头rtsp视频流,于是就专门做了些研究.而浏览器不能直接播放,只有通过插件或者转码来实现这个需求. 要实现这个目的,可以采用的方案非常得多,有商业的也有开源的,这里主要列举一 ...

  6. PHP如何调取vlc播放rtsp,H5+VLC播放RTSP视频流

    最新项目涉及到摄像头,这篇文章记录一下在VUE中播放RTSP视频流. 这篇文章主要介绍使用VLC插件播放RTSP视频流,目前支持的浏览器有 360浏览器.2345浏览器,可用于一些对播放器要求不高的项 ...

  7. 网页中播放RTSP(5) WebSocket播放视频

    WebSocket播放视频是结合MediaSource的 总结:通过WebSocket获取视频流,提供给MediaSource,MediaSource结合video标签,播放视频. 这一套完全就是基于 ...

  8. 网页中插入能全屏播放swf,flv视频的播放器

    原帖地址:http://aykkk.blog.163.com/blog/static/161779533201211044316285/ 今天一客户提出此要求,上网查资料,无意中看到一个网站有此功能, ...

  9. android使用Ffmpeg JNI实时播放RTSP、RTMP等视频(主码流,子码流均能流畅播放)

    前言:最近 公司项目需要在电视上 播放摄像头视频,而且可以随时切换流,延时要求在500ms以内,网上试过了 各种开源库 ,都不能达到要求.于是自己找到公司C++开发人员请教,最后终于完成,在此记录,也 ...

最新文章

  1. 域名管理系统 二级域名_域名系统简介
  2. 怎么搞技术呢?我觉得最简单的方法
  3. react 引用本地js_从零配置webpack 4+react脚手架(二)
  4. excel2010冻结行列
  5. [软件]Beyond Compare
  6. servlet 验证生命周期过程调用方法的次数
  7. 选择WebSockets还是REST?
  8. 【UE】UE4下载安装及测试demo
  9. 关于PMBus一些知识
  10. 运放 - 输出阻抗(Open loop output resistance)Ro
  11. linux下部署项目,下载文件时,中文文件名乱码问题
  12. ACM.大一寒假2.15考试
  13. escape()和unescape()函数的使用方法
  14. yum.repos.d没有这个文件和目录解决方法
  15. Carson带你学Android:RxJava过滤操作符
  16. [CTFSHOW]命令执行
  17. STM32 FLASH的擦写寿命
  18. 局域网SDN技术硬核内幕 - 前传 突破多核的瓶颈——虚拟化
  19. 小鸟伏特加怎么用计算机,生活常识:小鸟伏特加是什么梗
  20. GhostNet实战:使用GhostNet实现图像分类任务(二)

热门文章

  1. MySQL/oracle服务器误删文件的恢复过程
  2. C#编写的基于VLC的播放器
  3. ITECH IT63XX/ IT90XX系列可编程直流电源RS-232调试记录
  4. vivos机器人_【vivoNEXS评测】操作:人工智能无处不在 Jovi AI正在接管系统-中关村在线...
  5. SQLDER--工具参数--中英文对照
  6. Android 通过MediaMetadataRetriever获取视频封面和时长
  7. 最佳免费网络爬虫工具
  8. JavaScript 内容总结(DOM和BOM)(一)DOM基础
  9. 【修复日常bug】微信小程序canvas画商品海报出现个别用户无法生成的情况
  10. 草根网站的不完全的建设规划