VUE 3.0 -- 直播推拉流、流视频播放

news/2024/11/24 5:48:02/

🛴🛴前言:
Demo 基于 OBS推流 + Nginx + Vue 3.0 + Nplayer.js + hls.js ,目的只是实现流媒体播放,以及简易推拉流直播。

文章目录

    • 前端组件 NPlayer.js
      • 安装 nplayer.js
    • 流视频播放
      • 页面元素
      • 初始化播放器
      • 清晰度控件样式
      • 效果如下
    • 直播推拉流
      • Nginx 安装 rmtp 模块
        • Linux 环境可以通过重新编译 nginx 加入 rtmp 模块
        • Window 安装 rmtp 模块
      • Nginx 配置 hls 服务器
        • 配置服务器
        • 启动nginx
      • OBS推流
        • 下载OBS
        • 简单配置一下
        • 开启直播
      • hls.js 拉流 + NPlayer 播放
        • 引入 hls.js
        • 切换视频流来源
        • 查看直播

前端组件 NPlayer.js

一个比较简单自定义的视频流播放组件,可以自定义控件元素等,自带弹幕组件,具体使用文档可访问 https://nplayer.js.org/

安装 nplayer.js

npm i -S nplayer
或者
yarn add nplayer

根据官网描述,需要创建根组件
在main.ts中添加

import App from './App.vue';
import { createApp } from 'vue';
import NPlayer from '@nplayer/vue'; //加上这一行
async function bootstrap() {const app = createApp(App);... ...app.use(NPlayer); //加上这一行app.mount('#app');
}bootstrap();

流视频播放

页面元素

<template><div class="broad"><div class="left_adv"> TODO </div><div ref="centerPlayer" class="center_player"></div><div class="right_chat"> TODO </div></div><div class="bottom"> </div>
</template>

初始化播放器

设置播放器,并增加弹幕发送、清晰度调整,修改播放速排序等。

<script lang="ts">import { ref } from 'vue';import NPlayer, { Popover } from 'nplayer';import Danmaku from '@nplayer/danmaku';import Hls from 'hls.js';import './style.less';export default {components: {},setup() {let player = null;const centerPlayer = ref(null);// 右键菜单增加截图const Screenshot = {html: '截图',click(player) {const canvas = document.createElement('canvas');canvas.width = player.video.videoWidth;canvas.height = player.video.videoHeight;canvas.getContext('2d').drawImage(player.video, 0, 0, canvas.width, canvas.height);canvas.toBlob((blob) => {let dataURL = URL.createObjectURL(blob);const link = document.createElement('a');link.href = dataURL;link.download = 'NPlayer.png';link.style.display = 'none';document.body.appendChild(link);link.click();document.body.removeChild(link);URL.revokeObjectURL(dataURL);});},};// 插件设置// 速度设置const speedSettingItem = (): SettingItem => ({id: 'speed',html: '播放速度',type: 'select',value: 1,options: [{ value: 2, html: '2' },{ value: 1.5, html: '1.5' },{ value: 1, html: '正常' },{ value: 0.5, html: '0.5' },{ value: 0.25, html: '0.25' },],init(player) {player.playbackRate = 1;},change(value, player) {this.value = player.playbackRate = value;},});// 1. 首先创建一个清晰度控制条项const Quantity = {el: document.createElement('div'),init() {this.btn = document.createElement('div');this.btn.textContent = '画质';this.el.appendChild(this.btn);this.popover = new Popover(this.el);this.btn.addEventListener('click', () => this.popover.show());// 点击按钮的时候展示 popover// 默认隐藏this.el.style.display = 'none';this.el.classList.add('quantity');this.btn.classList.add('quantity_btn');},};const newPlugin = {apply(player) {player.registerSettingItem(speedSettingItem(), 'speed');},};// 弹幕设置const danmakuOptions = {items: [{ time: 1, text: '前方弹幕来袭~' }],};//初始化播放器const initPlayer = () => {// 设置视频const video = document.createElement('video');player = new NPlayer({seekStep: 10,volumeStep: 0.1,video: video,videoProps: { autoplay: 'true' },contextMenus: [Screenshot, 'loop', 'pip'],contextMenuToggle: true,controls: [['play','volume','time','spacer',Quantity,'airplay','settings','web-fullscreen','fullscreen',],['progress'],],bpControls: {},plugins: [new Danmaku(danmakuOptions), newPlugin],});// 绑定流const hls = new Hls();hls.on(Hls.Events.MEDIA_ATTACHED, function () {hls.on(Hls.Events.MANIFEST_PARSED, function () {// 4. 给清晰度排序,清晰度越高的排在最前面hls.levels.sort((a, b) => b.height - a.height);const frag = document.createDocumentFragment();// 5. 给与清晰度对应的元素添加,点击切换清晰度功能const listener = (i) => (init) => {const last = Quantity.itemElements[Quantity.itemElements.length - 1];const prev = Quantity.itemElements[Quantity.value] || last;const el = Quantity.itemElements[i] || last;prev.classList.remove('quantity_item-active');el.classList.add('quantity_item-active');Quantity.btn.textContent = el.textContent;if (init !== true && !player.paused) setTimeout(() => player.play());// 因为 HLS 切换清晰度会使正在播放的视频暂停,我们这里让它再自动恢复播放Quantity.value = hls.currentLevel = hls.loadLevel = i;Quantity.popover.hide();};// 6. 添加清晰度对应元素Quantity.itemElements = hls.levels.map((l, i) => {const el = document.createElement('div');el.textContent = l.name + 'P';if (l.height === 1080) el.textContent += ' 超清';if (l.height === 720) el.textContent += ' 高清';if (l.height === 480) el.textContent += ' 清晰';el.classList.add('quantity_item');el.addEventListener('click', listener(i));frag.appendChild(el);return el;});const el = document.createElement('div');el.classList.add('quantity_item');el.textContent = '自动';el.addEventListener('click', listener(-1));frag.appendChild(el);Quantity.itemElements.push(el);// 这里再添加一个 `自动` 选项,HLS 默认是根据网速自动切换清晰度Quantity.popover.panelEl.appendChild(frag);Quantity.el.style.display = 'block';listener(hls.currentLevel)(true);// 初始化当前清晰度});// 绑定 video 元素成功的时候,去加载视频hls.loadSource('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8');});hls.attachMedia(video);player.mount(centerPlayer.value);};return {player,initPlayer,centerPlayer,setPlayer: (p) => (player = p),};},mounted() {this.initPlayer();console.log(this.player);},};
</script>
<style lang="less" scoped>.tab-header {background: white;padding-left: 1%;padding-right: 1%;}.broad {display: flex;width: 100%;height: 80%;}.left_adv {width: 60px;border: #222222 2px solid;}.center_player {flex: 1;border: #222222 2px solid;border-left: 0px;border-right: 0px;}.right_chat {width: 400px;border: #222222 2px solid;}.bottom {width: 100%;height: 20%;border: #222222 2px solid;border-top: 0px;}
</style>

清晰度控件样式

清晰度设置的样式在一个单独的样式文件中 ./style.less ,因为我们的清晰度设置控件是在代码中动态生成的,但是当前文件为了防止样式渗透影响到其他页面或公共组件的样式,所以加上了 scoped 属性,这就导致动态生成的元素获取不到当前文件中定义的样式。
在这里插入图片描述
所以我们将清晰度样式单独存放

.quantity_btn {font-family: sans-serif;color: rgb(255, 255, 255);
}
.quantity {position: relative;padding: 0 8px;cursor: pointer;font-size: 14px;font-weight: bold;white-space: nowrap;opacity: 0.8;
}
.quantity:hover {opacity: 1;
}
.quantity_item {height: 30px;width: 100px;padding: 5px;font-weight: normal;
}
.quantity_item:hover {background: rgba(255, 255, 255, 0.3);
}
.quantity_item-active {height: 30px;width: 100px;padding: 5px;color: var(--theme-color);
}

效果如下

在这里插入图片描述

直播推拉流

为实现直播间的推拉流,使用 nginx-rtmp-module 模块扩展 Nginx 功能,借助 Nginx 的 Rtmp 模块搭建一个流服务器

Nginx 安装 rmtp 模块

Linux 环境可以通过重新编译 nginx 加入 rtmp 模块

  1. 先安装 nginx 必要的库
    sudo apt-get install build-essential libpcre3 libpcre3-dev libssl-dev
    
  2. 下载 nginx
    wget http://nginx.org/download/nginx-1.20.2.tar.gz
    
  3. 下载 nginx-rtmp-module 模块
    wget https://github.com/arut/nginx-rtmp-module/archive/master.zip
    
  4. 解压下载的文件并进入 nginx 文件夹
    tar -zxvf nginx-1.20.2.tar.gz
    unzip nginx-rtmp-module-master.zip
    cd nginx-1.20.2
    
  5. 重新编译nginx
    ./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master
    make
    make install
    

Window 安装 rmtp 模块

官方网站 windows 版本的 nginx 并未提供 rtmp 模块,我们可以从以下网站下载,亲测可用
http://nginx-win.ecsds.eu/download/
版本为

nginx 1.7.11.3 Gryphon.zip  

Nginx 配置 hls 服务器

使用 nginx 做一个 hls 的服务器,hls协议可以跨平台,而且码率切换快,基本不会被防火墙屏蔽。

配置服务器

修改 nginx.conf

rtmp {server {listen 1935;chunk_size 4096;application hls {live on;hls on;hls_path F:/,,,SpringCloudEnv/nginxrtmpvideo/;#视频流存放地址hls_fragment 5s;hls_playlist_length 10s;hls_continuous on; #连续模式。hls_cleanup off;    #对多余的切片进行删除。默认会自动删除,如果想要保留直播内容需要加上这一行hls_nested on;     #嵌套模式。}}
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;server {listen       81;server_name  localhost;location / {root   html;index  index.html index.htm;}# 前端请求的时候需要请求这里的直播文件location /hls {types {application/vnd.apple.mpegurl m3u8;video/mp2t ts;}#访问权限开启,否则访问这个地址会报403autoindex on;alias F:/,,,SpringCloudEnv/nginxrtmpvideo/;#视频流存放地址,与上面的hls_path相对应,这里root和alias的区别可自行百度expires -1;add_header Cache-Control no-cache;#防止跨域问题add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Credentials' 'true';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';  }error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}
}

启动nginx

查看是否正常启动nginx

OBS推流

下载OBS

https://obs.yjjxx.cn/index.html?bd_vid=8452749110375400746

简单配置一下

在这里插入图片描述
要注意 这里设置的推流码,会在nginx对应存储直播流的文件夹中创建一个同名文件夹 test1,在开启直播后会在 test1 文件中生成一个 m3u8 索引文件,和一系列媒体文件。如下
在这里插入图片描述

开启直播

可以使用摄像头、或者使用现存的视频设置媒体源
在这里插入图片描述
在这里插入图片描述
设置好媒体源后,点击开始直播,nginx 文件夹中就有媒体文件不断生成了

hls.js 拉流 + NPlayer 播放

引入 hls.js

npm install hls.js -S
或者 
yarn add hls.js 

上面的代码中已经使用了 hls.js ,所以不用再做修改。我们只需要把视频流来源切换一下。

切换视频流来源

在这里插入图片描述

查看直播

直播开了延迟
在这里插入图片描述


http://www.ppmy.cn/news/108163.html

相关文章

关于java k8s容器环境中的jvm配置与优化

1. 前言 环境 版本 备注 k8s v1.22 配置cpu/mem limit、健康/就绪检查 openjdk 8 openjdk version "1.8.0_342" k8s容器化&#xff08;docker&#xff09;环境更好的解决了 java app 运行环境的封装问题。但存在着一些限制&#xff0c;比如 Java 并不能发现…

15天学习MySQL计划(运维篇)分库分表-监控-第十四天

15天学习MySQL计划分库分表-监控-第十四天 1.介绍 1.问题分析 ​ 随着互联网及移动互联网的发展&#xff0c;应用系统的数据量也是成指数式增加&#xff0c;若采用但数据进行数据存储&#xff0c;存在以下性能瓶颈&#xff1a; IO瓶颈&#xff1a;热点数据太多&#xff0c;数…

从中国人民大学与加拿大女王大学金融硕士的学员构成,了解金融行业都有哪些职位

金融行业最受欢迎的岗位莫过于券商、银行、基金公司、私募市场、体制内&#xff08;监管部门、交易所等&#xff09;、信托、大企业投资部、保险、管理咨询、资产管理。在当下如果要选择工作&#xff0c;想找就业率第一、薪酬排名第一的行业&#xff0c;那一定是金融工作。中国…

软件测试基础知识整理(九)-项目信息来源、项目测试流程

目录 一、项目信息来源 1.1 熟悉项目步骤 1.2 熟悉项目的信息来源 二、项目测试流程 2.1 需求分析 2.2 测试计划 2.3 测试方案 2.4 测试用例设计 2.4.1 测试用例需求来源 2.4.2 编写测试用例步骤 2.4.3 编写测试用例的原则 2.4.4 执行测试用例原则 一、项目信息来源…

C++内存总结

1.2 C内存 参考 https://www.nowcoder.com/issue/tutorial?tutorialId93&uuid8f38bec08f974de192275e5366d8ae24 1.2.1 简述一下堆和栈的区别 参考回答 区别&#xff1a; 堆栈空间分配不同。栈由操作系统自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变…

JeecgBoot企业级开发中实现自定义导出EXCEL的前端表格字段功能

文章目录 如何在后端实现导出前端列表字段到Excel功能需求前端的实现1. 提供一个导出的点击函数2.引入组件中的userMethod3.tableProps中导出中添加对应的查询参数4. 编写导出函数 后端逻辑的实现1.Controller层2.创建Modal类3.Sevice层 检验成果总结 如何在后端实现导出前端列…

WebGPU你让我等的好辛苦啊

什么是WebGPU WebGPU是一种新兴的Web标准&#xff0c;旨在为Web应用程序提供高性能的图形和计算功能。它是一种低级别的图形API&#xff0c;为开发人员提供了对现代GPU的直接访问&#xff0c;以实现更高效的图形渲染和通用计算。 WebGPU的设计目标是提供与现代图形API&#x…

代码随想录二刷 day07 |哈希表 之 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和

day07 454 四数相加II383 赎金信15. 三数之和18. 四数之和 454 四数相加II 题目链接 解题思路&#xff1a; 类似两数相加的变形。将四数变成两组&#xff0c;这样的时间复杂度O(n)是最小的。 不用考虑有重复的四个元素相加等于0的情况&#xff0c; class Solution { public:i…