济菏高速业务端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

266 lines
6.7 KiB

import flvJs from "flv.js";
import mpegTsJs from "mpegts.js";
import { Message } from "element-ui";
// mpegts.js
import {
getCameraStream,
getNearCamera,
getNearCameraNew,
} from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js";
const ErrorTypesCn = {
NetworkError: "网络错误",
MediaError: "媒体错误",
OtherError: "其他错误",
};
/**
* 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 {{camId?: string; url?: string}?} options {camId: 相机ID; url: 直播地址}
* @returns
*/
export async function openVideoStream(container, { camId, url } = {}) {
if (camId) {
const { code, data } = await getCameraStream(camId).catch(() => ({}));
if (code != 200) return;
url = data.liveUrl;
}
if (!url) return;
// console.log(flvJs.getFeatureList().mseLivePlayback);
const player = flvJs.createPlayer({
type: "flv",
url: url,
isLive: true,
hasVideo: true,
hasAudio: true,
});
player.attachMediaElement(container);
player.load();
player.play();
player.on(flvJs.Events.ERROR, (e) => {});
return player;
}
async function getUrl({ camId, url, pileNum, rangeIndex } = {}) {
// return testFlvUrl;
if (url) return url;
if (pileNum) {
let code, data, cameraData;
if (rangeIndex) {
if (typeof rangeIndex === "string")
cameraData = await getNearCameraNew(pileNum).catch(() => ({}));
else cameraData = await getNearCamera(pileNum).catch(() => ({}));
} else {
cameraData = await getNearCamera(pileNum).catch(() => ({}));
}
code = cameraData.code;
data = cameraData.data;
// console.log(rangeIndex, "rangeIndex", cameraData);
if (
code != 200 ||
(Array.isArray(data) ? !data?.length : !Object.keys(data || {}).length)
) {
Message.warning("未获取到附近的相机信息");
return;
}
camId = data[rangeIndex || 0]?.camId;
console.log("rangeIndex", rangeIndex, data[rangeIndex]);
}
if (camId) {
const { code, data } = await getCameraStream(camId).catch(() => ({}));
if (code != 200) {
// Message.warning("未获取到当前相机的播放地址");
return;
}
url = data.liveUrl;
}
if (!url) {
// Message.warning("未获取到当前相机的播放地址");
return Promise.reject("获取 url 失败!");
}
return url;
}
export class HttpLivePlayer {
/**
* @type { flvJs.Player }
*/
player;
/**
* @type { HTMLVideoElement }
*/
container;
url;
// 解码 帧
lastDecodedFrames;
constructor(container, options) {
this.container = container;
if (!flvJs.getFeatureList().mseLiveFlvPlayback)
return Message.error("浏览器不支持播放 flv 视频流");
getUrl(options).then((url) => {
this.url = url;
this.initLiveVideo();
});
}
destroy() {
if (!this.player) return;
this.player.pause();
this.player.unload();
this.player.detachMediaElement();
this.player.destroy();
this.player = null;
}
initLiveVideo() {
this.destroy();
this.player = null;
this.lastDecodedFrames = null;
if (!this.url) return;
this.player = flvJs.createPlayer(
{
type: "flv",
url: this.url,
isLive: true,
},
{
autoCleanupSourceBuffer: true,
// enableWorker: true, // 启用分离的线程进行转换
enableStashBuffer: false, // 关闭IO隐藏缓冲区 如果您需要实时(最小延迟)来进行实时流播放,则设置为false
stashInitialSize: 128,
isLive: true,
lazyLoad: true,
}
);
this.player.attachMediaElement(this.container);
this.player.load();
this.player.play();
// this.container.addEventListener("progress", () => {
// let end = this.player.buffered.end(0); //获取当前buffered值(缓冲区末尾)
// let delta = end - this.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) => {
console.log("errorType", errorType);
console.log("errorDetail", errorDetail);
console.log("errorInfo", errorInfo);
Message.warning(
`视频流加载失败, ${ErrorTypesCn[errorType] || "其他错误"}`
);
this.initLiveVideo();
});
// 视频断流
this.player.on(flvJs.Events.STATISTICS_INFO, (res) => {
if (this.lastDecodedFrames != res.decodedFrames) {
this.lastDecodedFrames = res.decodedFrames;
} else {
this.lastDecodedFrames = 0;
// this.destroy();
// 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,
options
);
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;
}