Browse Source

视频修改提交

wangqin
Joe 10 months ago
parent
commit
88922f8f5b
  1. 9
      ruoyi-ui/src/views/JiHeExpressway/components/Video/Video.vue
  2. 167
      ruoyi-ui/src/views/JiHeExpressway/components/Video/videoStream.js
  3. 2
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/Dialogs/Broadcast/components/BroadcastReleases.vue

9
ruoyi-ui/src/views/JiHeExpressway/components/Video/Video.vue

@ -3,7 +3,7 @@
</template> </template>
<script> <script>
import { HttpLivePlayer } from "./videoStream.js" import { HttpLivePlayer, openLiveVideo } from "./videoStream.js"
export default { export default {
name: 'Video', name: 'Video',
@ -21,10 +21,11 @@ export default {
default: null default: null
} }
}, },
mounted() { async mounted() {
const player = new HttpLivePlayer(this.$refs.videoContainerRef, { camId: this.camId, url: this.url, pileNum: this.pileNum }); const player = await openLiveVideo(this.$refs.videoContainerRef, { camId: this.camId, url: this.url, pileNum: this.pileNum })
// const player = new HttpLivePlayer(this.$refs.videoContainerRef, { camId: this.camId, url: this.url, pileNum: this.pileNum });
this.$once("hook:beforeDestroy", () => player.destroy()); this.$once("hook:beforeDestroy", () => player?.destroy());
} }
} }
</script> </script>

167
ruoyi-ui/src/views/JiHeExpressway/components/Video/videoStream.js

@ -1,10 +1,26 @@
import flvJs from "flv.js"; import flvJs from "flv.js";
import mpegTsJs from "mpegts.js";
import { Message } from "element-ui";
// mpegts.js // mpegts.js
import { import {
getCameraStream, getCameraStream,
getNearCamera, getNearCamera,
} from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js"; } from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js";
/**
* flv 视频测试
* https://bilibili.github.io/flv.js/demo/
* https://www.zngg.net/tool/detail/FlvPlayer
* https://xqq.im/mpegts.js/demo/arib.html
*/
/**
* flv 视频流
*/
const testFlvUrl =
"https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-720p.flv";
// "https://v17.dogevideo.com/vcloud/17/v/20190424/1556036075_818c4125ec9c8cbc7a7a8a7cc1601512/1057/e51d88e79732fb952ebdbb4a57aa628a.flv?vkey=D9EAC2&tkey=17062414799ec7c466dc&auth_key=1706255879-zQK6JYToEeRiUark-0-6e363fb7709e783e64efc919d2267bdc";
/** /**
* *
* @param {HTMLElement} container 容器 * @param {HTMLElement} container 容器
@ -42,6 +58,34 @@ export async function openVideoStream(container, { camId, url } = {}) {
return player; return player;
} }
async function getUrl({ camId, url, pileNum } = {}) {
// return testFlvUrl;
if (url) return url;
if (pileNum) {
const { code, data } = await getNearCamera(pileNum).catch(() => ({}));
if (code != 200 || !data?.length) {
Message.warning("未获取到附近的相机信息");
return;
}
camId = data[0].camId;
}
if (camId) {
const { code, data } = await getCameraStream(camId).catch(() => ({}));
if (code != 200) {
Message.warning("未获取到当前相机的播放地址");
return;
}
url = data.liveUrl;
}
if (!url) return Promise.reject("获取 url 失败!");
return url;
}
export class HttpLivePlayer { export class HttpLivePlayer {
/** /**
* @type { flvJs.Player } * @type { flvJs.Player }
@ -60,33 +104,37 @@ export class HttpLivePlayer {
constructor(container, options) { constructor(container, options) {
this.container = container; this.container = container;
if (!flvJs.getFeatureList().mseLiveFlvPlayback)
return Message.error("浏览器不支持播放 flv 视频流");
this.getUrl(options).then(() => { this.initLiveVideo();
getUrl(options).then((url) => {
this.url = url;
this.initLiveVideo(); this.initLiveVideo();
}); });
} }
async getUrl({ camId, url, pileNum } = {}) { // async getUrl({ camId, url, pileNum } = {}) {
this.url = url; // this.url = url;
if (pileNum) { // if (pileNum) {
const { code, data } = await getNearCamera(pileNum).catch(() => ({})); // const { code, data } = await getNearCamera(pileNum).catch(() => ({}));
if (code != 200 || !data?.length) return; // if (code != 200 || !data?.length) return;
camId = data[0].camId; // camId = data[0].camId;
} // }
if (camId) { // if (camId) {
const { code, data } = await getCameraStream(camId).catch(() => ({})); // const { code, data } = await getCameraStream(camId).catch(() => ({}));
if (code != 200) return; // if (code != 200) return;
url = data.liveUrl; // url = data.liveUrl;
} // }
if (!url) return Promise.reject("获取 url 失败!"); // if (!url) return Promise.reject("获取 url 失败!");
this.url = url; // this.url = url;
} // }
destroy() { destroy() {
if (!this.player) return; if (!this.player) return;
@ -117,10 +165,11 @@ export class HttpLivePlayer {
}, },
{ {
autoCleanupSourceBuffer: true, autoCleanupSourceBuffer: true,
// enableWorker: false, //不启用分离线程 enableWorker: true, // 启用分离的线程进行转换
// enableStashBuffer: true, //关闭IO隐藏缓冲区 enableStashBuffer: false, // 关闭IO隐藏缓冲区 如果您需要实时(最小延迟)来进行实时流播放,则设置为false
stashInitialSize: 128,
isLive: true, isLive: true,
lazyLoad: false, lazyLoad: true,
} }
); );
@ -129,13 +178,35 @@ export class HttpLivePlayer {
this.player.load(); this.player.load();
this.player.play(); this.player.play();
this.container.addEventListener("progress", () => {
let end = player.buffered.end(0); //获取当前buffered值(缓冲区末尾)
let delta = end - player.currentTime; //获取buffered与当前播放位置的差值
// 延迟过大,通过跳帧的方式更新视频
if (delta > 10 || delta < 0) {
this.player.currentTime = this.player.buffered.end(0) - 1;
return;
}
// 追帧
if (delta > 1) {
this.container.playbackRate = 1.1;
} else {
this.container.playbackRate = 1;
}
});
this.player.on(flvJs.Events.ERROR, (errorType, errorDetail, errorInfo) => { this.player.on(flvJs.Events.ERROR, (errorType, errorDetail, errorInfo) => {
console.log("errorType", errorType); console.log("errorType", errorType);
console.log("errorDetail", errorDetail); console.log("errorDetail", errorDetail);
console.log("errorInfo", errorInfo); console.log("errorInfo", errorInfo);
// 视频出错后销毁重建 // 视频出错后销毁重建
this.player.pause();
this.player.unload();
this.player.detachMediaElement();
this.destroy(); this.destroy();
this.player = null;
this.initLiveVideo(); this.initLiveVideo();
}); });
@ -145,9 +216,61 @@ export class HttpLivePlayer {
this.lastDecodedFrames = res.decodedFrames; this.lastDecodedFrames = res.decodedFrames;
} else { } else {
this.lastDecodedFrames = 0; this.lastDecodedFrames = 0;
this.destroy(); // this.destroy();
this.initLiveVideo(); // this.initLiveVideo();
} }
}); });
} }
} }
/**
* https://juejin.cn/post/6855577308271476743
* https://www.cnblogs.com/xiahj/p/flvExtend.html
* 使用 mpegTsJs
* @param {*} container
* @param {*} options
*/
export async function openLiveVideo(container, options) {
if (!mpegTsJs.getFeatureList().mseLivePlayback)
return Message.error("浏览器不支持播放 flv 视频流");
const url = await getUrl(options).catch(() => {});
console.log(
"%c [ url ]-212-「videoStream.js」",
"font-size:15px; background:#6f87e8; color:#b3cbff;",
url
);
if (!url) return;
const player = mpegTsJs.createPlayer(
{
type: "flv",
url,
isLive: true,
},
{
autoCleanupSourceBuffer: true,
enableWorker: true, // 启用分离的线程进行转换
enableStashBuffer: false, // 关闭IO隐藏缓冲区 如果您需要实时(最小延迟)来进行实时流播放,则设置为false
stashInitialSize: 128,
isLive: true,
lazyLoad: true,
}
);
player.attachMediaElement(container);
container.addEventListener("play", () => {
try {
let end = player.buffered.end(0) - 1;
player.currentTime = end;
} catch (error) {}
});
player.load();
player.play();
return player;
}

2
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/Dialogs/Broadcast/components/BroadcastReleases.vue

@ -67,7 +67,7 @@ export default {
deviceId: String, deviceId: String,
pileNum: String, pileNum: String,
currentId: [String, Number], currentId: [String, Number],
otherConfig: Object otherConfig: String
}, },
data() { data() {
return { return {

Loading…
Cancel
Save