123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="description" content="jMuxer - a simple javascript mp4 muxer for non-standard streaming communications protocol">
- <meta name="keywords" content="h264 player, mp4 player, mse, mp4 muxing, jmuxer, aac player">
- <title>JMuxer demo</title>
- <script async defer src="https://buttons.github.io/buttons.js"></script>
- <style type="text/css">
- .github-tools {
- position: absolute;
- top: 15px;
- right: 15px;
- }
- a.h264-player {
- font-size: 20px;
- text-decoration: none;
- color: #07568e;
- margin-top: 10px;
- display: block;
- }
- .gesture {
- font-size: 15px;
- color: #ad4903;
- margin-top: 10px;
- }
- </style>
- </head>
- <body>
- <h2>jMuxer Demo</h2>
- <p>Sample demo node server is running on heroku free hosting</p>
- <br /><br />
- <div class="github-tools">
- <!-- Place this tag where you want the button to render. -->
- </div>
- <div id="container" style="width: 600px; margin: 0 auto;">
- <video width="70%" disablePictureInPicture="true" autoplay poster="images/loader-thumb.jpg" id="player"></video>
- <audio width="50%" preload="auto" autoplay controls poster="images/loader-thumb.jpg" id="audioPlayer"></audio>
- <div class="gesture">If it does not play automatically, Click the `video play button` to initiate the video</div>
- </div>
- <body oncontextmenu="Back()">
- </body>
- <script src="helper.js">
- </script>
- <script>
- //隐藏控件 controls
- var fpsCount = 0;
- var requestCount = 0;
- var timeCount = 0;
- var isVisuable = true;
- var isFeed = true;
- var isDrag = false;
- var shoudDrop = false;
- var isEnough = true;
- var ifCanPlay = false;
- var isFinish = false;
- var delayTime = new Date().getTime();
- var feedTime = new Date().getTime();
- var readyTime = new Date().getTime();
- var requestTime = new Date().getTime();
- var curTime = new Date().getTime();
- var requestTime = new Date().getTime(); //记录离开时间
- var myVideo = document.getElementById("player");
- var myAudio = document.getElementById("audioPlayer");
- var audioBuffer = [];
- var audioBack = [];
- Module = {};
- Module.onRuntimeInitialized = function() {
- console.log("Wasm 加载成功!")
- isFinish = true;
- }
- document.addEventListener("visibilitychange", () => {
- if (document.visibilityState == "visible") {
- console.log("页面可见,继续喂视频");
- //requestTime = new Date().getTime();
- isVisuable = true;
- } else {
- isVisuable = false;
- isFeed = false;
- myVideo.pause();
- }
- });
- myVideo.play();
- myVideo.addEventListener('pause', function() {
- //console.log("视频播放暂停");
- isFeed = false;
- });
- myAudio.addEventListener('canplay', function() {
- console.log("缓冲区大小 %f", myAudio.buffered.end(0) - myAudio.buffered.start(0));
- });
- /*function decodeAAC(data)
- {
- var retPtr = Module._malloc(4 * 5 * 1024);//接收的数据
- var inputPtr = Module._malloc(4 * data.length);//输入数据
-
- for( i =0;i < data.length;i++)
- {
- Module.HEAPU8[(inputPtr)+i] = data[i];//转换为堆数据
- }
-
- var pcmLen = Module._feedData(retPtr, inputPtr, data.length);
-
- if(pcmLen > 0)
- {
- //console.log("%d帧 aac 解码成功, %d", decodeCount, pcmLen);
- var pcmData = new Uint8Array(pcmLen);
- for(i = 0;i < pcmLen;i++)
- {
- pcmData[i] = Module.HEAPU8[(retPtr)+i]
- }
-
- player.feed(pcmData);
- }
- else
- {
- console.log("%d帧 aac 解码失败, %d", decodeCount, pcmLen);
- }
-
- decodeCount++;
- Module._free(inputPtr);
- Module._free(retPtr);
- } */
- //解协议
- function ParseProto(data) {
- var temp = "";
- var input = new Uint8Array(data),
- duration,
- video,
- audio;
- if (input[0] == 0 && input[1] == 0 && input[2] == 0 && input[3] == 1) {
- // debugger
- video = input;
- duration = 24;
- var nalType = input[4] & 0x1f; //nalType == 0x07|| nalType == 0x08 || nalType == 0x05
- if (!isFeed) {
- if (nalType == 0x05) {
- console.log("发现I帧");
- }
- if (nalType == 0x05 && isVisuable) {
- console.log("检测到I帧 %d,重新渲染, 耗时 %d ms", nalType, new Date().getTime() - requestTime);
- isFeed = true;
- }
- }
- } else if (input[0] == 0xff) {
- if (!isEnough) {
- requestCount++;
- //audioBuffer.push(input);
- }
- audio = input;
- if (new Date().getTime() - curTime > 100) {
- delayTime = new Date().getTime();
- console.log("接收时间 %d ms", new Date().getTime() - curTime);
- }
- curTime = new Date().getTime();
- duration = 24;
- //console.log("duration %d", duration);
- } else if (input[0] == 0x68) {
- if (input[23] == 0x05) //横竖屏标识
- {
- var state = CheckScreenDirection(input.slice(24, 24 + 8));
- if (state == 1) {
- console.log("安卓卡此时竖屏");
- //竖屏处理
- } else {
- console.log("安卓卡此时横屏");
- //横屏处理
- }
- }
- if (input[23] == 0x0b) {
- console.log("多端登陆");
- }
- //console.log("屏幕旋转 %s", PrintArry(input));
- }
- return {
- audio: audio,
- video: video,
- duration: duration
- };
- }
- window.onload = function() {
- // var socketURL = 'wss://jmuxer-demo-server.herokuapp.com';
- //socketURL = "ws://127.0.0.1:8080"
- // socketURL = "ws://192.168.11.233:8080"
- //socketURL = "ws://14.215.128.98:14112";
- var socketURL = "ws://192.168.11.66:9101";
- // socketURL = "ws://14.215.128.98:14077";
- //socketURL = "wss://192.168.11.242:9104";
- var jmuxer = new JMuxer({
- node: 'player',
- flushingTime: 15,
- fps: 30,
- mode: 'video',
- debug: false
- });
- var audioMuxer = new JMuxer({
- node: 'audioPlayer',
- flushingTime: 15,
- clearBuffer: true,
- fps: 60, //可以不选,原先43
- mode: 'audio',
- debug: false
- });
- curTime = new Date().getTime();
- var ws = new WebSocket(socketURL);
- ws.binaryType = 'arraybuffer';
- //断开检测
- ws.onclose = function(e) {
- alert("websocket连接断开");
- console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean);
- console.log(e);
- }
- ws.addEventListener('open', function(event) {
- console.log("发送配置帧");
- ws.send(ConfigChannel("RK3923C1201900139"));
- });
- ws.addEventListener('error', function(event) {
- console.log("连接失败");
- });
- ws.addEventListener('message', function(event) {
- var data = ParseProto(event.data); //JAVA服务器转发
- //console.log("收到数据");
- var audioData = {
- audio: data.audio,
- video: null,
- duration: data.duration
- };
- var videoData = {
- audio: null,
- video: data.video,
- duration: data.duration
- };
- if (myAudio.readyState == 2) {
- requestTime = new Date().getTime();
- isEnough = false;
- console.log("数据存储不够,出现声音停止,时间差 %f", myAudio.buffered.end(0));
- myAudio.pause();
- //myAudio.playbackRate = 2;
- } else if (myAudio.readyState == 4 && isEnough == false) {
- myAudio.play();
- var time = new Date().getTime();
- isEnough = true;
- console.log("填满耗时 %d ms, 填充帧数 %d, 填充延迟 %d ms", time - requestTime, requestCount, requestCount * 23);
- console.log("----接收到启动 %d ms, 缓冲区 %f---", time - delayTime, myAudio.buffered.end(0) - myAudio.played.end(0));
- }
- if (data.audio != null) //喂音频
- {
- if (myAudio.buffered.length > 0 && myAudio.played.length > 0) {
- var bufferTime = myAudio.buffered.end(0) - myAudio.played.end(0);
- //console.log(" bufferTime %d", bufferTime);
- if (bufferTime > 1) {
- //console.log("丢掉一些包");
- //return;
- }
- }
- audioMuxer.feed(audioData);
- }
- if (data.video != null) //喂视频
- {
- if (isFeed) {
- jmuxer.feed(data);
- }
- //jmuxer.feed(videoData);
- }
- });
- myVideo.onmousedown = function(event) {
- //放在此处只是为了方便演示,实际使用中查找横竖屏只要刚连接上时调用一次就好。
- //var checkBuffer = GetScreenState();
- //ws.send(checkBuffer);
- if (!isFeed) {
- console.log("重新申请I帧");
- requestTime = new Date().getTime();
- var buffer = RequestIFrame();
- //var buffer = new Uint8Array([0x01]);
- ws.send(buffer);
- }
- //console.log("报文 %s", PrintArry(buffer));
- if (event.button == 0) {
- var posX = event.offsetX * 1080 * 1.0 / myVideo.clientWidth;
- var posY = event.offsetY * 1920 * 1.0 / myVideo.clientHeight;
- var buffer = ExexuteMouseDown(posX.toString(), posY.toString());
- ws.send(buffer);
- isDrag = true;
- }
- }
- myVideo.onmousemove = function(event) {
- if (isDrag && event.button == 0) {
- var posX = event.offsetX * 1080 * 1.0 / myVideo.clientWidth;
- var posY = event.offsetY * 1920 * 1.0 / myVideo.clientHeight;
- var buffer = ExexuteMouseMove(posX.toString(), posY.toString());
- ws.send(buffer);
- //console.log("移动位置 %d, %d", posX, posY);
- }
- }
- myVideo.onmouseup = function(event) {
- isDrag = false;
- var posX = event.offsetX * 1080 * 1.0 / myVideo.clientWidth;
- var posY = event.offsetY * 1920 * 1.0 / myVideo.clientHeight;
- var buffer = ExexuteMouseUp(posX.toString(), posY.toString());
- ws.send(buffer);
- }
- myVideo.onkeydown = function(event) {
- ExexuteKeyDown(e.keyCode);
- }
- }
- function Back() {
- if (event.button == 2) {
- //ExexuteKeyDown(4);
- }
- ExexuteKeyDown(4);
- window.event.returnValue = false;
- return false;
- }
- </script>
- <script type="text/javascript" src="jmuxer.js"></script>
- <!--<script type="text/javascript" src="aac.js"></script>-->
- </body>
- </html>
|