123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <title>NodePlayer.js Demo</title>
- <meta
- name="viewport"
- content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
- />
- <style>
- body {
- padding: 0;
- margin: 0;
- }
- .box {
- margin: 8px 0;
- display: flex;
- }
- .fl1 {
- flex: 1;
- }
- .fl0 {
- flex: 0;
- }
- </style>
- </head>
- <body>
- <div style="max-width: 980px; margin: 0 auto">
- <h3>
- <a href="http://www.nodemedia.cn" target="_blank">NodePlayer.js Demo</a>
- </h3>
- <div
- style="
- width: 100%;
- padding-bottom: 56%;
- position: relative;
- overflow: hidden;
- "
- >
- <canvas
- id="video1"
- style="
- width: 150%;
- height: 150%;
- position: absolute;
- background-color: black;
- "
- ></canvas>
- </div>
- <div>
- <div class="box">
- <input
- id="url"
- class="fl1"
- value="https://liveplay.fis.plus/live/v6up727idvci5o9feckkhfwkw8.flv"
- />
- <button class="fl0" onclick="startFunc()">Play</button>
- <button class="fl0" onclick="stopFunc()">Stop</button>
- <button class="fl0" onclick="fullFunc()">Full</button>
- <button class="fl0" onclick="screenshot()">ScreenShot</button>
- <button class="fl0" onclick="initCapturer()">InitCapturer</button>
- <button class="fl0" onclick="setClipSize()">setClipSize</button>
- <button class="fl0" onclick="capture()">CaptureOneFrame</button>
- </div>
- <div>
- <input
- type="range"
- id="slider1"
- name="slider1"
- min="0"
- max="1920"
- value="1920"
- />
- <label for="slider1">ClipWidth:</label>
- <span id="slider1Value">1920</span>
- <br />
- <input
- type="range"
- id="slider2"
- name="slider2"
- min="0"
- max="1080"
- value="1080"
- />
- <label for="slider2">ClipHeight:</label>
- <span id="slider2Value">1080</span>
- <br />
- </div>
- <div class="box">
- <div class="fl1">
- <label>Volume:</label>
- <select onchange="volumeChange(event);">
- <option>300</option>
- <option>200</option>
- <option selected>100</option>
- <option>75</option>
- <option>50</option>
- <option>25</option>
- <option>0</option>
- </select>
- </div>
- <div class="fl1">
- <label>BufferTime:</label>
- <select id="buffertime" onchange="bufferChange(event);">
- <option>0</option>
- <option>100</option>
- <option>300</option>
- <option>500</option>
- <option selected>1000</option>
- <option>2000</option>
- <option>3000</option>
- </select>
- </div>
- <div class="fl1">
- <label>ScaleMode:</label>
- <select onchange="scaleModeChange(event);">
- <option selected>0</option>
- <option>1</option>
- <option>2</option>
- </select>
- </div>
- <div class="fl1">
- <label>CryptoKey:</label>
- <input id="key" class="fl1" value="" />
- </div>
- </div>
- <!-- /input-group -->
- </div>
- <div style="margin-top: 20px"></div>
- <div style="display: flex">
- <div style="width: 30%; padding-bottom: 20%; position: relative">
- <canvas
- id="camera1"
- style="
- width: 100%;
- height: 100%;
- position: absolute;
- background-color: black;
- transform: scaleY(-1);
- "
- ></canvas>
- </div>
- <div style="margin-right: 20px"></div>
- <div style="width: 30%; padding-bottom: 20%; position: relative">
- <canvas
- id="camera2"
- style="
- width: 100%;
- height: 100%;
- position: absolute;
- background-color: black;
- transform: scaleY(-1);
- "
- ></canvas>
- </div>
- <div style="margin-right: 20px"></div>
- <div style="width: 30%; padding-bottom: 20%; position: relative">
- <canvas
- id="camera3"
- style="
- width: 100%;
- height: 100%;
- position: absolute;
- background-color: black;
- transform: scaleY(-1);
- "
- ></canvas>
- </div>
- </div>
- </div>
- <script src="https://cdn.bootcdn.net/ajax/libs/vConsole/3.3.4/vconsole.min.js"></script>
- <script
- type="text/javascript"
- src="./nodeplayer/NodePlayer.min.js"
- ></script>
- <script
- type="text/javascript"
- src="./video_processor/webgl_video_processor.js"
- ></script>
- <script
- type="text/javascript"
- src="./video_capturer/rtmp_video_capturer.js"
- ></script>
- <script>
- if (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent)) {
- //手机开启vconsole,便于查看控制台调试信息,正式部署时无需使用,包括上面的vconsole.min.js也不用引入
- var vConsole = new VConsole();
- }
- var url = document.getElementById("url");
- var key = document.getElementById("key");
- var argurl = getQueryVariable("url");
- if (argurl) {
- url.value = argurl;
- }
- var argkey = getQueryVariable("key");
- if (argkey) {
- key.value = argkey;
- }
- /**
- * 是否打印debug信息
- */
- // NodePlayer.debug(true);
- //v0.5.70版之后,在Android手机端推荐使用以下音频引擎
- if (/(Android)/i.test(navigator.userAgent)) {
- NodePlayer.activeAudioEngine(true);
- }
- /// 创建视频裁切处理器(设置裁切方式)
- const videoProcessor = new VideoProcessor([
- { type: "scaleOnly", x: 2 / 3, y: 0.0, w: 1 / 3, h: 4 / 9 },
- { type: "threePart", x: 0.0, y: 2 / 3, w: 1, h: 4 / 27 },
- { type: "threePart", x: 0.0, y: 22 / 27, w: 1, h: 4 / 27 },
- ]);
- // 初始化(传入id)
- function initVideoProcessor() {
- videoProcessor.initializeById("video1", [
- "camera1",
- "camera2",
- "camera3",
- ]);
- }
- // 在播放器每一帧调用此方法(绘制裁切得到的部分)
- function onPlayerFrame() {
- videoProcessor.drawFrame();
- }
- var player;
- // 0.5.28之后, 为了统一asm与wasm版本api差异,现统一采用回调格式加载.
- NodePlayer.load(() => {
- player = new NodePlayer();
- /**
- * 自动测试浏览器是否支持MSE播放,如不支持,仍然使用软解码。
- * 紧随 new 后调用
- * 不调用则只使用软解
- */
- // player.useMSE();
- /**
- * 开启屏幕常亮
- * 在手机浏览器上,canvas标签渲染视频并不会像video标签那样保持屏幕常亮
- * 如果需要该功能, 可以调用此方法
- * H5目前在chrome\edge 84, android chrome 84及以上有原生亮屏API, 需要是https页面
- * 其余平台为模拟实现,非全兼容。
- */
- player.setKeepScreenOn();
- /**
- * 传入 canvas视图的id,当使用mse时,自动转换为video标签
- */
- player.setView("video1");
- /**
- * 设置最大缓冲时长,单位毫秒,只在软解时有效
- */
- player.setBufferTime(1000);
- /**
- * 设置超时时长, 单位秒,只在软解时有效
- * 在连接成功之前和播放中途,如果超过设定时长无数据返回,则回调timeout事件
- */
- // player.setTimeout(10);
- player.on("start", () => {
- console.log("player on start");
- });
- player.on("stop", () => {
- console.log("player on stop");
- });
- player.on("error", (e) => {
- console.log("player on error", e);
- });
- player.on("videoInfo", (w, h, codec) => {
- console.log(
- "player on video info width=" +
- w +
- " height=" +
- h +
- " codec=" +
- codec
- );
- initVideoProcessor();
- });
- player.on("audioInfo", (r, c, codec) => {
- console.log(
- "player on audio info samplerate=" +
- r +
- " channels=" +
- c +
- " codec=" +
- codec
- );
- });
- // player.on("metadata", (metadata) => {
- // var m = NodePlayer.AMF.parseScriptData(metadata.buffer, 0, metadata.length);
- // console.log(m);
- // });
- // player.on("videoSei", (sei, pts) => {
- // console.log("player on video sei=" + sei + " pts=" + pts);
- // });
- player.on("videoFrame", (pts) => {
- /// 每一帧执行一次视频处理
- onPlayerFrame();
- });
- // player.on("timeout", () => {
- // console.log("player on timeout");
- // player.stop();
- // });
- // player.on("buffer", (state) => {
- // console.log("player on buffer state=" + state);
- // });
- player.on("stats", (stats) => {
- // console.log("player on stats=", stats);
- });
- });
- function startFunc() {
- /**
- * 设置解密密码,必须是16字节
- */
- player.setCryptoKey(key.value);
- /**
- * 开始播放,参数为 http-flv或 websocket-flv 的url
- */
- player.start(url.value);
- }
- function stopFunc() {
- /**
- * 停止播放
- */
- player.stop();
- //按需清理画布为黑色背景
- // player.clearView();
- }
- function fullFunc() {
- player.fullscreen();
- }
- function volumeChange(event) {
- /**
- * 设置音量
- * 0.0 ~~ 3.0
- * 当为0.0时完全静音; 当为1.0时为正常音量; 继续增大之后进行音量增益,最大3.0
- */
- player.setVolume(event.target.value / 100.0);
- }
- function bufferChange(event) {
- player.setBufferTime(event.target.value);
- }
- function scaleModeChange(event) {
- /**
- * 视频缩放模式, 当视频分辨率比例与Canvas显示区域比例不同时,缩放效果不同:
- * 0 视频画面完全填充canvas区域,画面会被拉伸 --- 默认值
- * 1 视频画面做等比缩放后,对齐Canvas区域,画面不被拉伸,但有黑边
- * 2 视频画面做等比缩放后,完全填充Canvas区域,画面不被拉伸,没有黑边,但画面显示不全
- * 软解时有效
- */
- player.setScaleMode(event.target.value);
- }
- function screenshot() {
- // player.screenshot("np_screenshot.png", "png");
- player.screenshot("np_screenshot.jpeg", "jpeg", 0.8);
- }
- // 初始化截图器
- function initCapturer() {
- let videoSize = initRTMPVideoCapture("video1");
- console.log("videoSize", videoSize);
- }
- // 设置裁切区域
- function setClipSize() {
- var width = document.getElementById("slider1").value;
- var height = document.getElementById("slider2").value;
- setRTMPClipSize(width, height);
- }
- // 捕获一帧
- function capture() {
- captureRTMPOneFrame();
- }
- function getQueryVariable(variable) {
- var query = window.location.search.substring(1);
- var vars = query.split("&");
- for (var i = 0; i < vars.length; i++) {
- var pair = vars[i].split("=");
- if (pair[0] == variable) {
- return pair[1];
- }
- }
- return false;
- }
- // 获取 DOM 元素
- const slider1 = document.getElementById("slider1");
- const slider1Value = document.getElementById("slider1Value");
- const slider2 = document.getElementById("slider2");
- const slider2Value = document.getElementById("slider2Value");
- const showValuesButton = document.getElementById("showValuesButton");
- // 监听 input 事件
- slider1.addEventListener("input", () => {
- slider1Value.innerHTML = slider1.value;
- });
- slider2.addEventListener("input", () => {
- slider2Value.innerHTML = slider2.value;
- });
- </script>
- <script>
- (function () {
- var script = document.createElement("script");
- script.onload = function () {
- var stats = new Stats();
- stats.dom.style.position = "fixed";
- stats.dom.style.left = null;
- stats.dom.style.right = "0px";
- stats.dom.style.top = "0px";
- document.body.appendChild(stats.dom);
- requestAnimationFrame(function loop() {
- stats.update();
- requestAnimationFrame(loop);
- });
- };
- script.src = "https://mrdoob.github.io/stats.js/build/stats.min.js";
- document.head.appendChild(script);
- })();
- </script>
- </body>
- </html>
|