index.html 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="description" content="jMuxer - a simple javascript mp4 muxer for non-standard streaming communications protocol">
  6. <meta name="keywords" content="h264 player, mp4 player, mse, mp4 muxing, jmuxer, aac player">
  7. <title>JMuxer demo</title>
  8. <script async defer src="https://buttons.github.io/buttons.js"></script>
  9. <style type="text/css">
  10. .github-tools {
  11. position: absolute;
  12. top: 15px;
  13. right: 15px;
  14. }
  15. a.h264-player {
  16. font-size: 20px;
  17. text-decoration: none;
  18. color: #07568e;
  19. margin-top: 10px;
  20. display: block;
  21. }
  22. .gesture {
  23. font-size: 15px;
  24. color: #ad4903;
  25. margin-top: 10px;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div id="container" style="width: 600px; margin: 0 auto;">
  31. <video width="100%" autoplay poster="images/loader-thumb.jpg" id="player"></video>
  32. <audio width="50%" controls autoplay poster="images/loader-thumb.jpg" id="audioPlayer" ></audio>
  33. </div>
  34. <body oncontextmenu="Back()">
  35. </body>
  36. <script src="helper.js" >
  37. </script>
  38. <script>
  39. //隐藏控件 controls
  40. var fpsCount = 0;
  41. var timeCount = 0;
  42. var isFeed = true;
  43. var isDrag = false;
  44. var curTime = new Date().getTime();
  45. var requestTime = new Date().getTime();//记录离开时间
  46. var myVideo = document.getElementById("player");
  47. var myAudio = document.getElementById("audioPlayer");
  48. document.addEventListener("visibilitychange", () => {
  49. if (document.visibilityState == "visible")
  50. {
  51. console.log("页面可见,继续喂视频");
  52. requestTime = new Date().getTime();
  53. myVideo.play();
  54. }
  55. else
  56. {
  57. isFeed = false;
  58. //myVideo.pause();
  59. }
  60. });
  61. myVideo.addEventListener('pause',function(){
  62. console.log("视频播放暂停");
  63. isFeed = false;
  64. });
  65. myAudio.addEventListener('onerror',function(){
  66. console.log("音频播放暂停");
  67. //myAudio.play();
  68. });
  69. function parse(data) {
  70. var input = new Uint8Array(data),
  71. dv = new DataView(input.buffer),
  72. duration,
  73. audioLength,
  74. audio,
  75. video;
  76. duration = dv.getUint16(0, true);//获取duration
  77. audioLength = dv.getUint16(2, true);
  78. if(audioLength == 0)
  79. {
  80. video = input.subarray(4);
  81. console.log("只有视频");
  82. }
  83. else
  84. {
  85. audio = input.subarray(4, (audioLength + 4));
  86. video = input.subarray(audioLength + 4);
  87. console.log("视频 + 音频");
  88. }
  89. return {
  90. audio: audio,
  91. video: video,
  92. duration: duration
  93. };
  94. }
  95. //解协议
  96. function ParseProto(data)
  97. {
  98. var temp = "";
  99. var input = new Uint8Array(data),
  100. duration,
  101. video,
  102. audio;
  103. if(input[0] == 0 && input[1] == 0 && input[2] == 0 && input[3] == 1)
  104. {
  105. // debugger
  106. video = input;
  107. duration = 24;
  108. var nalType = input[4] &0x1f;//
  109. if(nalType == 0x07|| nalType == 0x08 || nalType == 0x05)//策略, 找到sps、sps、或I帧,才继续渲染
  110. {
  111. if(!isFeed)
  112. {
  113. console.log("%d, 检测到I帧,重新渲染, 耗时 %d ms", nalType, new Date().getTime() - requestTime);
  114. }
  115. isFeed = true;
  116. }
  117. else
  118. {
  119. }
  120. }
  121. else if(input[0] == 0xff)
  122. {
  123. audio = input;
  124. duration = 22;
  125. }
  126. else if(input[0] == 0x68)
  127. {
  128. if(input[23] == 0x05)//横竖屏标识
  129. {
  130. var state = CheckScreenDirection(input.slice(24, 24 + 8));
  131. if(state == 1)
  132. {
  133. console.log("安卓卡此时竖屏");
  134. //竖屏处理
  135. }
  136. else
  137. {
  138. console.log("安卓卡此时横屏");
  139. //横屏处理
  140. }
  141. }
  142. //console.log("屏幕旋转 %s", PrintArry(input));
  143. }
  144. return {
  145. audio: audio,
  146. video: video,
  147. duration: duration
  148. };
  149. }
  150. window.onload = function() {
  151. var socketURL = 'wss://jmuxer-demo-server.herokuapp.com';
  152. // socketURL = "ws://localhost:8080"
  153. // socketURL = "ws://192.168.11.238:8080";//C# websocket服务器中转
  154. // socketURL="wss://test.androidscloud.com/videoWebSocket?clientType=1&cardIp=14.215.128.96&port=2005&sn=RK3930C2301900005"
  155. //socketURL = "ws://127.0.0.1:8022/videoWebSocket?clientType=0&sn=RK3923C1201900139&cardIp=192.168.11.66&port=9100";
  156. /*socketURL = "ws://192.168.31.242:8022/videoWebSocket?clientType=0&sn=RK3923C1201900139&cardIp=192.168.11.66&port=9100";*/
  157. //flushingTime, 缓存刷新时间
  158. //socketURL = "ws://14.215.128.98:14112";
  159. socketURL = "ws://192.168.11.66:9101";
  160. var jmuxer = new JMuxer({
  161. node: 'player',
  162. flushingTime:15 ,
  163. fps: 30,
  164. mode:'video',
  165. debug: false
  166. });
  167. var audioMuxer = new JMuxer({
  168. node: 'audioPlayer',
  169. flushingTime:1,
  170. clearBuffer: true,
  171. fps: 43,//可以不选
  172. mode:'audio',
  173. debug: false
  174. });
  175. /*var costTime = new Date().getTime() - curTime;
  176. if(costTime > 5)
  177. {
  178. console.log("websocket接收延迟 %d ms", costTime);
  179. }*/
  180. curTime = new Date().getTime();
  181. var ws = new WebSocket(socketURL);
  182. ws.binaryType = 'arraybuffer';
  183. //断开检测
  184. ws.onclose = function (e) {
  185. alert("websocket连接断开");
  186. console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean);
  187. console.log(e);
  188. }
  189. ws.addEventListener('message',function(event) {
  190. //console.log("喂数据");
  191. //jmuxer.feed(data);
  192. var data = ParseProto(event.data);//JAVA服务器转发
  193. //var data = parse(event.data);//分离音视频数据,C#转发
  194. // console.log("推流详情============",event.data);
  195. var audioData = {
  196. audio: data.audio,
  197. video: null,
  198. duration: data.duration
  199. };
  200. var videoData = {
  201. audio: null,
  202. video: data.video,
  203. duration: data.duration
  204. };
  205. var streamTemp = myAudio.captureStream();
  206. if(myAudio.readyState == 2)
  207. {
  208. console.log("出现声音停止");
  209. //alert("出现声音停止");
  210. //console.log("出现声音停止,当今进度 %s, %s", myAudio.played.end(0), myAudio.buffered.end(0));
  211. myAudio.play();
  212. }
  213. if(data.audio != null)//喂音频
  214. {
  215. //console.log("feed audio");
  216. audioMuxer.feed(audioData);
  217. }
  218. if(data.video != null)//喂视频
  219. {
  220. if(isFeed)
  221. {
  222. jmuxer.feed(data);
  223. }
  224. //jmuxer.feed(videoData);
  225. }
  226. if(data.video)
  227. {
  228. if(new Date().getTime() - curTime >= 1000)
  229. {
  230. //console.log("fps %d", fpsCount);
  231. fpsCount = 0;
  232. curTime = new Date().getTime();
  233. }
  234. else
  235. {
  236. fpsCount++;
  237. }
  238. }
  239. });
  240. myVideo.onmousedown = function(event)
  241. {
  242. //放在此处只是为了方便演示,实际使用中查找横竖屏只要刚连接上时调用一次就好。
  243. //var checkBuffer = GetScreenState();
  244. //ws.send(checkBuffer);
  245. /*if(!isFeed)
  246. {
  247. console.log("重新申请I帧");
  248. requestTime = new Date().getTime();
  249. var buffer = RequestIFrame();
  250. ws.send(buffer);
  251. }*/
  252. //console.log("报文 %s", PrintArry(buffer));
  253. if(event.button == 0)
  254. {
  255. var posX = event.offsetX * 1080 *1.0/myVideo.clientWidth;
  256. var posY = event.offsetY * 1920 *1.0/myVideo.clientHeight;
  257. var buffer = ExexuteMouseDown(posX.toString(), posY.toString());
  258. ws.send(buffer);
  259. isDrag = true;
  260. }
  261. }
  262. myVideo.onmousemove = function(event)
  263. {
  264. if(isDrag && event.button == 0)
  265. {
  266. var posX = event.offsetX * 1080 *1.0/myVideo.clientWidth;
  267. var posY = event.offsetY * 1920 *1.0/myVideo.clientHeight;
  268. var buffer = ExexuteMouseMove(posX.toString(), posY.toString());
  269. ws.send(buffer);
  270. //console.log("移动位置 %d, %d", posX, posY);
  271. }
  272. }
  273. myVideo.onmouseup = function(event)
  274. {
  275. isDrag = false;
  276. var posX = event.offsetX * 1080 *1.0/myVideo.clientWidth;
  277. var posY = event.offsetY * 1920 *1.0/myVideo.clientHeight;
  278. var buffer = ExexuteMouseUp(posX.toString(), posY.toString());
  279. ws.send(buffer);
  280. }
  281. myVideo.onkeydown = function(event)
  282. {
  283. ExexuteKeyDown(e.keyCode);
  284. }
  285. }
  286. function Back()
  287. {
  288. if(event.button == 2)
  289. {
  290. //ExexuteKeyDown(4);
  291. }
  292. ExexuteKeyDown(4);
  293. window.event.returnValue=false;
  294. return false;
  295. }
  296. </script>
  297. <script type="text/javascript" src="jmuxer.js"></script>
  298. </body>
  299. </html>