采用的技术是vue+flv.js
前言
常见视频流格式
● RTMP(推流端、拉流端)
● RTSP(推流端)
● HLS(拉流端)
● FLV(拉流端)
视频流 | 是否依赖插件 | 直播/点播 | 协议 | web/移动端 |
---|---|---|---|---|
flv | 否 | 直播点播 | HTTP-FLV | web |
RTSP | 浏览器不能直接播放【只能通过转码或者插件】 | 直播点播 | RTSP协议 | web |
hls【以m3u8后缀结尾】 | 否【浏览器用video.js可以播放,但5秒左右的延迟】 | 点播 | 基于http | ios系统 |
RTMP | 浏览器中用flash播放器 但谷歌在2020年底带头不支持flash插件 或者 video.js | 直播 | RTMP | web/移动端 |
RTSP
需要安装插件或者转码
vue播放rtsp视频流
方案二:RTSP转RTMP到RTMP服务器,转http-flv,播放端用flv.js播放
方案三:RTSP转RTMP到RTMP服务器,转hls,播放端用video.js播放
方案四:VLC或者SmartPlayer第三方插件播放
方案五:RTSP转WebRTC播放
HLS
Http Live Streaming (简称HLS) ,是苹果公司(Apple Inc.)实现的基于HTTP的流媒体传输协议,它在移动 Web 浏览器支持挺好,所以现在好多移动端直播都在用此协议。但在 PC Chrome,Firefox 上不支持,所以还需要借助flash 或者 video.js 这个插件,但是它不直接支持播放 HLS 协议的播放. 需要借助 videojs-contrib-hls ,找见了这个库FZ-live 我看他也是基于 video.js 的。
还有个要求,就是资源 不能跨域,需要在同一域下。
而且因为HLS流是分片下载播放,需要浏览器先下载然后播放,所以延迟很高,在十秒多甚至更多。并且对浏览器和网速的要求还是比较高的,视频流畅度取决于网速。
可实现流媒体的直播和点播 ,主要应用在iOS系统,为iOS设备(如iPhone、iPad)提供音视频直播和点播方案。
video.js
npm install video.js
npm i videojs-contrib-hls --save
vue3-video-player
EasyPlayer.js
使用开源的EasyPlayer.js播放,这个控件支持多种流的播放,网上选择的也比较多。GITHUB
RTMP
需要安装插件; video.js 插件能提供 RTMP 的播放 但是需要flash支持
VLC media player用于检测rtmp是否可以正常播放;https://www.videolan.org/vlc/
rtmp视频流实际上就是以rtmp流媒体协议生成的流媒体;
视频流:视频流其实就是流媒体(streaming media),是指将一连串数据压缩后,经过网络分段发送,即时传输以供观看音视频的一种技术。监控、直播等实时播放的功能一般都使用的是流媒体。
流媒体协议:流媒体协议是一种标准化的传递方法,用于将视频分解为多个块,将其发送给视频播放器,播放器重新组合播放,常见的有rtmp、hls、hds、mss、MPEG-DASH等。
视频格式(format):视频格式指视频文件格式(container fORMat)。常见 container format 包括 .mp4、.m4v、.avi、.mov等。
FLV【已自测】
HTTP FLV则是将RTMP封装在HTTP协议之上的,可以更好的穿透防火墙等。rtmp和http-flv的视频格式都是flv格式的,只是传输协议而不同。rtmp是tcp的传输协议,而http-flv是http长链接的传输协议。
官方文档:
中文文档
官方文档
flvjs
flvjs是一个H5播放器。HTTP FLV是一种协议。FLV是一种格式。flvjs可以用于播放FLV格式的视频。 flvjs是一个较成熟的前端处理flv格式的插件库,是B站视频的开源插件,纯原生 JavaScript 开发,没有用到 Flash。
概览:
一个实现了在 HTML5 视频中播放 FLV 格式视频的 JavaScript 库。它的工作原理是将 FLV 文件流转码复用成 ISO BMFF(MP4 碎片)片段,然后通过 Media Source Extensions 将 MP4 片段喂进浏览器。
flv.js 是使用 ECMAScript 6 编写的,然后通过 Babel Compiler 编译成 ECMAScript 5,使用 Browserify 打包。
推流端视频编码必须是H.264
1. 安装
npm install --save flv.js
2. 引入
搭建组件
<template>
<!-- 增加静音属性:muted -->
<video
autoplay
muted
id="myVideo"
></video>
</template>
<script setup lang="ts">
/* eslint-disable */
import { ref, onMounted, onUnmounted } from 'vue';
import flvjs from 'flv.js/dist/flv.min.js'; // 代替 import flvjs from 'flv.js'; 否则504
const props = defineProps<{
videoSrc: string;
}>();
const flvPlayer = ref<any>(''); // 要声明一个播放器的容器 flvPlayer
onMounted(() => {
//在mounted声明周期里调用 如果出现DOM没加载出来的原因 可以使用定时器
videoPlayer();
});
const videoPlayer = () => {
// flvjs.isSupported() 判断当前浏览器是否支持flv。
if (flvjs.isSupported()) {
var videoElement = document.getElementById('myVideo');
flvPlayer.value = flvjs.createPlayer(
// 创建直播流,加载到DOM中去
{
type: 'auto', // 媒体类型 flv 或 mp4,默认 flv
// isLive: true, // 是否是直播流
// hasAudio: true, // 是否有音频
// hasVideo: true,
// enableStashBuffer: true,
url: props.videoSrc
}
// {
// cors: true, // 是否跨域
// enableWorker: false, // 是否多线程工作
// enableStashBuffer: false, // 是否启用缓存 关闭IO隐藏缓冲区
// stashInitialSize: 128, // 缓存大小(kb) 默认384kb
// autoCleanupSourceBuffer: true, // 是否自动清理缓存
// lazyLoad: false
// }
);
flvPlayer.value.attachMediaElement(videoElement); // 挂载video标签。
flvPlayer.value.load(); //加载流
// flvPlayer.value.play(); //播放流
// !!!!!!这里需要注意,有的时候load加载完成不一定可以播放,要是播放不成功,用settimeout 给下面的this.player.play() 延时几百毫秒再播放
setTimeout(() => {
flvPlayer.value.play(); //播放流
}, 1000);
}
};
// 在销毁的声明周期中 必须要销毁掉播放器的容器!!!!不然会占用TCP个数,导致其他页面的监控也播放不了
onUnmounted(() => {
if (flvPlayer.value) {
flvPlayer.value.pause();
flvPlayer.value.unload();
flvPlayer.value.detachMediaElement();
flvPlayer.value.destroy();
flvPlayer.value = null;
}
});
defineExpose({
videoPlayer
});
</script>
<style lang="scss" scoped>
video {
height: 100%;
width: 100%;
}
</style>
⚠️: 流地址 也可以不是flv结尾的
webrtc播放
webrtc可实现的功能特别强大,网上可参考的资料很少,目前尝试的是webrtc-streamer插件,实现了rtsp直接播放
有时候视频加载不出来,不是前端代码的问题,而是视频流提供的有问题,可以参看我这篇文章测试一下自己得到的flv是否正常
https://blog.csdn.net/changyana/article/details/126304833
我代码中的url是一个目前可用的在线测试的flv,只要视频流正常就可以在前端加载出来了!
测试-视频流2022/10/08
RTMP:
美国1: rtmp://ns8.indexforce.com/home/mystream
美国2: rtmp://media3.scctv.net/live/scctv_800
韩国GoodTV: rtmp://mobliestream.c3tv.com:554/live/goodtv.sdp
FLV:
超清 https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-720p.flv
高清 https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-480p.flv
标清 https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv
HLS(m3u8)
https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8
使用flv时候开发遇到的问题
- 报错 504
解决方式:引入方式改变
import flvjs from 'flv.js/dist/flv.min.js'; // 代替 import flvjs from 'flv.js'; 否则504
- 视频不自动播放
解决方式:增加autoplay 属性
<video
controls
autoplay
muted
id="myVideo"
></video>
-
联调时候:报错DemuxException: type = CodecUnsupported, info = Flv: Unsupported codec in video frame: 2
解决方式: 推流加上参数:-vcodec h264,表示强制使用h264进行编解码。-------------未解决 -
报错502
强制刷新 即可 -
DOMException: play() failed because the user didn’t interact with the document first
原因:因为用户没有先操作文档【用户没有先去跟网页做交互再执行音频播放】
Chrome的autoplay政策在2018年4月做了更改。
新的行为:浏览器为了提高用户体验,减少数据消耗,现在都在遵循autoplay政策,Chrome的autoplay 政策非常简单
muted autoplay始终被允许解决方案:
- 建议您再播放资源前,进行页面交互动作,比如点击后再播放
- 或者您可以在构建 DOM 元素时先设置 muted=“muted” 属性,调用 play 后再修改静音属性试下是否可以正常
- 如果使用的是 5.X 版本,在获取的 track 的时候做一个判断,如果是音频就不做 track.play(),用户点击的时候进行 play()
使用videojs开发播放hls视频
测试地址【http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8;】
-
Uncaught (in promise) DOMException: play() failed because the user didn’t interact with the document
设置muted 静音 和上面的问题5的原因一样 -
黑屏 中间有播放按钮。但是不播放 也不报错
-
VIDEOJS: ERROR: (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) The media could not be loaded, either because the server or network failed or because the format is not supported.
设置data-setup=“{}” -
video.es.js:222 VIDEOJS: ERROR: (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) No compatible source was found for this media.
出现的原因是你提供的视频连接可能没有扩展名导致,这样videojs无法知道视频的格式。
需要在type属性指定播放视频的格式即可。 -
video.es.js:222 VIDEOJS: ERROR: (CODE:2 MEDIA_ERR_NETWORK) HLS playlist request error at URL
-
VIDEOJS: ERROR: (CODE:3 MEDIA_ERR_DECODE) The media playback was aborted due to a corruption problem or because the media used features your browser did not support.
-
跨域
需要后端解决
在响应中添加CORS标头添加add_header Access-Control-Allow-Origin *; 不是在播放端nginx,是在提供视频服务的Nginx添加
error属性:
返回错误状态
1=MEDIA_ERR_ABORTER 取回过程中被用户终止
2=MEDIA_ERR_NETWORK 下载时发生错误
3=MEDIA_ERR_DECODE 解码时发生错误
4=MEDIA_ERR_SRC_NOT_SUPPORTED 媒体不可用或不支持
优秀文章
优秀文章
我先测试了能不能播放rtmp格式 但是需要flash插件 ,下面的代码是播放hls的demo
<template>
<video
id="my-video"
ref="myPlayer"
class="video-js"
controls
muted
preload="auto"
width="340"
height="164"
/>
<!-- data-setup="{}" -->
<!-- <source
:src="src"
type="rtmp/flv"
/>
</video> -->
<!-- <source
src="./MY_VIDEO.mp4"
type="video/mp4"
/>
</video> -->
</template>
<script setup lang="ts">
/* eslint-disable */
import videoJs from 'video.js';
import { ref, nextTick, onMounted, onUnmounted } from 'vue';
import 'videojs-flash';
// const src = 'src/components/video/MY_VIDEO.mp4';
const src = 'http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8';
const myPlayer = ref();
onMounted(() => {
// nextTick(() => {
setTimeout(() => {
init();
});
// });
});
const init = () => {
// videoJs.options.flash.swf = 'https://cdn.bootcss.com/videojs-swf/5.4.1/video-js.swf';
myPlayer.value = videoJs('my-video', {
autoplay: 'muted', //自动播放
controls: true, //用户可以与之交互的控件
loop: true, //视频一结束就重新开始
muted: false, //默认情况下将使所有音频静音
cors: true,
// aspectRatio: '16:9', //显示比率
// fullscreen: {
// options: { navigationUI: 'hide' }
// },
// techOrder: ['html5', 'flvjs'], // 兼容顺序
// html5: {
hls: {
withCredentials: true
},
// },
sources: [
{
src,
type: 'application/x-mpegURL'
// type: 'video/mp4'
// type: 'rtmp/flv'
}
]
});
// setTimeout(() => {
// myPlayer.value.src([
// {
// src,
// type: 'video/mp4'
// }
// ]);
setTimeout(() => {
// myPlayer.value.load();
myPlayer.value.play(); //播放流
}, 100);
// }, 1000);
};
onUnmounted(() => {
if (myPlayer.value) {
myPlayer.value.dispose();
}
});
</script>
<style lang="scss" scoped></style>
使用hlsjs开发播放hls视频
安装
npm i hls.js -S
代码
<template>
<!-- 增加静音属性:muted autoplay controls-->
<video
ref="videoElementRef"
id="videoElement"
controls
muted
style="width: 100%; height: 100%; object-fit: fill"
></video>
</template>
<script setup lang="ts">
/* eslint-disable */
import { ref, nextTick, onUnmounted, onMounted } from 'vue';
import hlsjs from 'hls.js';
// const props = defineProps<{
// videoSrc: 'http://192.168.5.2:9080/hls_save/stream1.m3u8';
// }>();
const src = 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8';
const videoElementRef = ref<any>();
const hlsjsInstance = ref<any>();
const videoPlayer = () => {
// const hlsjsInstance = ref();
// const video: any = document.getElementById('videoElement');
console.log(videoElementRef.value);
if (hlsjs.isSupported()) {
if (hlsjsInstance.value) {
hlsjsInstance.value.destroy();
hlsjsInstance.value = null;
}
hlsjsInstance.value = new hlsjs({
// liveRetryDvrMaxHead: 300,
// liveMaxLatencyDuration: Infinity,
// manifestLoadingMaxRetry: 10,
// manifestLoadingTimeOut: 10 * 1000
});
hlsjsInstance.value.loadSource(src); // 加载音视频源。
hlsjsInstance.value.attachMedia(videoElementRef.value); // 将HLS.js与一个HTML5 video元素相关联。
hlsjsInstance.value.on(hlsjs.Events.MANIFEST_PARSED, () => {
// 监听HLS.js事件。
setTimeout(() => {
videoElementRef.value.play();
}, 1000);
console.log('加载成功');
});
hlsjsInstance.value.on(hlsjs.Events.ERROR, (event, data) => {
console.log('加载失败');
// 重试
// videoPlayer();
hlsjsInstance.value.recoverMediaError(); // 尝试恢复
});
} else {
// 处理不支持的情况
console.log('处理不支持的情况');
}
};
// 在销毁的声明周期中 必须要销毁掉播放器的容器!!!!不然会占用TCP个数,导致其他页面的监控也播放不了
onUnmounted(() => {
if (hlsjsInstance.value) {
videoElementRef.value.pause();
//HLS.js销毁
hlsjsInstance.value.detachMedia();
hlsjsInstance.value.destroy();
hlsjsInstance.value = null;
// this.$emit("closeVideo");
}
});
onMounted(() => {
nextTick(() => {
setTimeout(() => {
videoPlayer();
});
});
});
</script>
<style lang="scss" scoped>
video {
height: 100%;
width: 100%;
}
</style>
常用的事件
- His.isSupported):检查当前浏览器是否支持 HLS。
- .His.loadSource(url):加载 HLS流。url 是流的 URL。
- His.attachMedia(videoElement):将视频元素与 HLS 实例相关联。
- Hs.on(event, callback):监听特定的 HLS 事件井调用相应的回调函数。
- Hls.startLoad():开始加载 HLS流。
- His.stopLoad:停止加载 HLS流。
- His.destroy():销毀 HLS 实例井释放资源。
- Hs.recoverMediaError():尝试恢复 HLS 流中的错误。
- Hls.swapAudioCodec():交换音频编解码器,以支持 Apple 设备上的HILS流。
- Hs.detachMedia0) :从视频元素中解除 HLS 实例的关联。
https://zhuanlan.zhihu.com/p/573964295?utm_id=0