hm-ng-video
Version:
(1)引入 npm 包,在==package.json==里面添加:
548 lines (542 loc) • 21.7 kB
JavaScript
import videojs from 'video.js';
import { Component, ViewChild, Input, ElementRef, ViewEncapsulation, EventEmitter, Output, Renderer2, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
/**
* @fileoverview added by tsickle
* Generated from: lib/hm-ng-video.component.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class HmNgVideoComponent {
// 监听全屏
/**
* @param {?} el
* @param {?} renderer
*/
constructor(el, renderer) {
this.el = el;
this.renderer = renderer;
this.PauseEventListener = new EventEmitter(); // 暂停回调
// 暂停回调
this.PlayingEventListener = new EventEmitter(); // 开始播放回调
// 开始播放回调
this.WaitingEventListener = new EventEmitter(); // 缓冲回调
// 缓冲回调
this.ErrorEventListener = new EventEmitter(); // 错误回调
// 错误回调
this.DataLoadedEventListener = new EventEmitter(); // 数据加载完成回调
// 数据加载完成回调
this.CanPlayEventListener = new EventEmitter(); // 可以播放回调
// 可以播放回调
this.ReLoadVideoEventListener = new EventEmitter(); // 重新加载
// 重新加载
this.FullScreenToggeleEventListener = new EventEmitter(); // 切换全屏
// 切换全屏
this.liveLoaded = false;
}
/**
* @param {?} type
* @return {?}
*/
createDom(type) {
if (type === "file") {
this.fileVideo.nativeElement.innerHTML = `<video id='${this.className}-fileVideo' class='video-js vjs-big-play-centered' controls muted preload='none' x-webkit-airplay='true' webkit-playsinline='isiPhoneShowPlaysinline' playsinline='isiPhoneShowPlaysinline' x5-playsinline='true' x5-video-player-type='h5'></video>`;
}
else {
/** @type {?} */
const guide = `<div class='loading ${this.className}-loading'><img src='` +
(this.loadingSrc || "") +
`' alt='' ></div>`;
/** @type {?} */
const error = `<div class='error ${this.className}-error'><span>` +
(this.errorContent || "") +
`</span></div>`;
this.liveVideo.nativeElement.innerHTML =
`<video id='${this.className}-liveVideo' class='video-js vjs-big-play-centered' controls muted preload='none' x-webkit-airplay='true' webkit-playsinline='isiPhoneShowPlaysinline' playsinline='isiPhoneShowPlaysinline' x5-playsinline='true' x5-video-player-type='h5'></video>` +
guide +
error;
this.el.nativeElement
.querySelector(`.${this.className}-error`)
.addEventListener("click", (/**
* @return {?}
*/
() => {
this.setBgVisible("error", false);
this.createLivePlayer(true);
}));
}
}
/**
* @return {?}
*/
init() {
this.liveLoaded = false;
// 只播放其中一种就传一种类型的option
if (this.fileOptions) {
this.createDom("file");
/** @type {?} */
const fileVideoEl = this.el.nativeElement.querySelector(`#${this.className}-fileVideo`);
this.filePlayer = videojs(fileVideoEl, Object.assign(this.fileOptions, {
autoplay: this.autoplay,
errorDisplay: false,
controlBar: {
playToggle: true,
volumePanel: false,
// 不需要静音按钮
pictureInPictureToggle: false,
// 不需要画中画
fullscreenToggle: false,
},
}));
this.setDefaultProperty(this.filePlayer);
this.filePlayer.on("error", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
this.ErrorEventListener.emit($event);
console.log("文件流出错了!");
this.dispose(this.filePlayer);
this.fileOptions = null;
this.createLivePlayer(true, true);
}));
this.filePlayer.on("playing", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
this.PlayingEventListener.emit($event);
if (!this.livePlayer) {
this.createLivePlayer(true); // 文件流和直播流都存在的情况下,如果不是自动播放,则强行创造自动播放的直播流
}
}));
this.filePlayer.on("pause", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
this.PauseEventListener.emit($event);
}));
}
else {
this.createLivePlayer(); // 如果没有文件流,则按照设置的是否自动播放执行
}
}
// 创建直播流 ,内部传就按照内部传的,不传则根据调用的决定
/**
* @param {?=} isAutoPlay
* @param {?=} isLoading
* @return {?}
*/
createLivePlayer(isAutoPlay, isLoading) {
if (!this.liveOptions) {
return;
}
this.createDom("live");
if (isLoading) {
this.setBgVisible("loading", true);
}
/** @type {?} */
const liveVideoEl = this.el.nativeElement.querySelector(`#${this.className}-liveVideo`);
/** @type {?} */
let startTime = 0;
/** @type {?} */
let endTime = 0;
this.livePlayer = videojs(liveVideoEl, Object.assign(this.liveOptions, {
autoplay: isAutoPlay ? isAutoPlay : this.autoplay,
errorDisplay: false,
liveui: true,
controlBar: {
playToggle: true,
volumePanel: false,
// 不需要静音按钮
pictureInPictureToggle: false,
// 不需要画中画
fullscreenToggle: false,
},
}));
this.addFullScreen();
this.setDefaultProperty(this.livePlayer);
this.livePlayer.on("loadstart", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
console.log("直播流开始load");
startTime = new Date().getTime();
// this.setBgVisible("loading", true);
if (!this.isVideoLoadingTimeout) {
this.isVideoLoadingTimeout = setTimeout((/**
* @return {?}
*/
() => {
if (this.livePlayer &&
this.livePlayer.readyState() !== 3 &&
this.livePlayer.readyState() !== 4) {
this.openModal();
this.ErrorEventListener.emit("overtime");
console.log("加载超时!");
}
}), this.maxLoadTime || 15000);
}
}));
this.livePlayer.on("loadedmetadata", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
endTime = new Date().getTime();
console.log("直播流加载成功");
this.setBgVisible("loading", false);
this.DataLoadedEventListener.emit(Object.assign($event, { bufferTime: endTime - startTime }));
}));
this.livePlayer.on("canplaythrough", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
if (this.livePlayer.readyState() === 3 ||
this.livePlayer.readyState() === 4) {
setTimeout((/**
* @return {?}
*/
() => {
if (this.filePlayer) {
this.dispose(this.filePlayer);
}
this.liveLoaded = true;
this.setBgVisible("loading", false);
}), 1000);
this.CanPlayEventListener.emit($event);
}
console.log(this.livePlayer.readyState(), "canplaythrough");
}));
this.livePlayer.on("playing", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
console.log("直播流正在播放!");
this.destroyTimeout();
this.setBgVisible("loading", false);
this.PlayingEventListener.emit($event);
}));
this.livePlayer.on("error", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
this.ErrorEventListener.emit($event);
console.log("直播流出错了!");
this.openModal();
}));
this.livePlayer.on("pause", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
this.PauseEventListener.emit($event);
}));
this.livePlayer.on("timeupdate", (/**
* @param {?} $event
* @return {?}
*/
($event) => {
if (!this.isVideoBreak) {
if (this.livePlayer.readyState() !== 3 &&
this.livePlayer.readyState() !== 4) {
this.WaitingEventListener.emit($event);
this.isVideoBreak = setTimeout((/**
* @return {?}
*/
() => {
if (this.livePlayer &&
this.livePlayer.readyState() !== 3 &&
this.livePlayer.readyState() !== 4) {
this.openModal();
this.ErrorEventListener.emit("overtime");
console.log("缓冲超时!");
}
}), this.maxLoadTime || 15000);
}
}
}));
}
// 获取player实例
/**
* @return {?}
*/
getFilePlayer() {
return this.filePlayer || undefined;
}
/**
* @return {?}
*/
getLivePlayer() {
return this.livePlayer || undefined;
}
// 默认配置
/**
* @param {?} player
* @return {?}
*/
setDefaultProperty(player) {
player.playsinline(true);
//player.crossOrigin("anonymous");
}
// 销毁
/**
* @param {?} player
* @return {?}
*/
dispose(player) {
if (!player) {
return;
}
if (!player.isDisposed()) {
player.dispose();
player = undefined;
}
}
// 销毁定时器
/**
* @return {?}
*/
destroyTimeout() {
clearTimeout(this.isVideoBreak);
clearTimeout(this.isVideoLoadingTimeout);
clearInterval(this.fullScreenTimer);
this.isVideoBreak = undefined;
this.isVideoLoadingTimeout = undefined;
this.fullScreenTimer = undefined;
}
// 全部销毁
/**
* @return {?}
*/
destroy() {
this.destroyTimeout();
this.dispose(this.filePlayer);
this.dispose(this.livePlayer);
}
// 绑定错误事件
// 自定义错误显示方式
// 0,1,2,3,4,5
// MEDIA_ERR_CUSTOM、
// MEDIA_ERR_ABORTED、取回过程被用户中止
// MEDIA_ERR_NETWORK、当下载时发生错误
// MEDIA_ERR_DECODE、当解码时发生错误
// MEDIA_ERR_SRC_NOT_SUPPORTED、不支持音频/视频
// MEDIA_ERR_ENCRYPTED // 被加密
// 错误弹窗
/**
* @return {?}
*/
openModal() {
this.fileOptions = null;
this.destroy();
this.setBgVisible("loading", false);
this.setBgVisible("error", true);
}
// 设置加载背景/错误背景显示隐藏
/**
* @param {?} type
* @param {?} isShow
* @return {?}
*/
setBgVisible(type, isShow) {
/** @type {?} */
const el = type === "loading"
? this.el.nativeElement.querySelector(`.${this.className}-loading`)
: this.el.nativeElement.querySelector(`.${this.className}-error`);
this.renderer.setStyle(el, "display", isShow ? "block" : "none");
}
// 判断是ios设备
/**
* @return {?}
*/
isIOS() {
/** @type {?} */
const u = navigator.userAgent;
/** @type {?} */
const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
console.log("ios", isIOS);
return isIOS;
}
// 添加自定义全屏和播放按钮
/**
* @return {?}
*/
addFullScreen() {
/** @type {?} */
const vjsButtonComponent = videojs.getComponent("Button");
videojs.registerComponent("FullScreenButton", videojs.extend(vjsButtonComponent, {
handleClick: (/**
* @return {?}
*/
() => {
if (!this.livePlayer.isFullscreen()) {
try {
this.toFullScreen();
if (this.isIOS()) {
this.fullScreenTimer = setInterval((/**
* @return {?}
*/
() => {
if (!this.livePlayer.isFullscreen()) {
// 退出了全屏
this.FullScreenToggeleEventListener.emit(false);
this.destroy();
this.createLivePlayer(true);
// clearInterval(this.fullScreenTimer);
// setTimeout(() => {
// this.livePlayer.play();
// }, 1000);
}
}), 1000);
}
}
catch (error) {
console.warn(error);
}
}
else {
this.FullScreenToggeleEventListener.emit(false);
this.livePlayer.exitFullscreen();
}
}),
buildCSSClass: (/**
* @return {?}
*/
() => {
return "my_fullscreen";
}),
}));
this.livePlayer.getChild("controlBar").addChild("FullScreenButton", {});
}
// 自定义全屏
/**
* @return {?}
*/
toFullScreen() {
this.FullScreenToggeleEventListener.emit(true);
if (this.livePlayer.requestFullscreen) {
return this.livePlayer.requestFullscreen();
}
else if (this.livePlayer.webkitRequestFullScreen) {
return this.livePlayer.webkitRequestFullScreen();
}
else if (this.livePlayer.mozRequestFullScreen) {
return this.livePlayer.mozRequestFullScreen();
}
else {
return this.livePlayer.msRequestFullscreen();
}
}
/**
* @return {?}
*/
ngOnInit() {
console.log("hm-ng-video 1.5.6");
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (this.exitFullScreen) {
console.log("按返回键退出全屏");
this.FullScreenToggeleEventListener.emit(false);
this.livePlayer.exitFullscreen();
}
if ((changes.fileOptions &&
changes.fileOptions.firstChange &&
changes.fileOptions.currentValue) ||
(changes.liveOptions &&
changes.liveOptions.firstChange &&
changes.liveOptions.currentValue)) {
this.init();
}
if ((changes.fileOptions &&
changes.fileOptions.currentValue &&
!changes.fileOptions.firstChange) ||
(changes.liveOptions &&
changes.liveOptions.currentValue &&
!changes.liveOptions.firstChange)) {
this.destroy();
setTimeout((/**
* @return {?}
*/
() => {
this.init();
}), 1000);
}
}
/**
* @return {?}
*/
ngOnDestroy() {
this.destroy();
}
}
HmNgVideoComponent.decorators = [
{ type: Component, args: [{
selector: "hm-ng-video",
template: "<!--\r\n * @Descripttion:\r\n * @version:\r\n * @Author: yding\r\n * @Date: 2020-05-08 19:05:06\r\n * @LastEditors: yding\r\n * @LastEditTime: 2020-06-19 10:44:58\r\n-->\r\n<!-- <button\r\n class=\"button\"\r\n style=\"background: red;\"\r\n (click)=\"fullScreen()\"\r\n value=\"\u5168\u5C4F\"\r\n>\r\n \u5168\u5C4F\r\n</button> -->\r\n<div\r\n class=\"vjs-video\"\r\n #fileVideoEl\r\n [ngStyle]=\"{\r\n height: videoHeight + 'px',\r\n width: videoWidth + 'px',\r\n position: 'relative'\r\n }\"\r\n [hidden]=\"(liveLoaded && liveOptions && fileOptions) || !fileOptions\"\r\n></div>\r\n<div\r\n class=\"vjs-video\"\r\n #liveVideoEl\r\n [ngStyle]=\"{\r\n height: videoHeight + 'px',\r\n width: videoWidth + 'px',\r\n position: 'relative'\r\n }\"\r\n [hidden]=\"(!liveLoaded && liveOptions && fileOptions) || !liveOptions\"\r\n></div>\r\n",
encapsulation: ViewEncapsulation.None,
styles: [".video-js{width:100%;height:100%}.retry:focus,.vjs-big-play-button:focus,video:focus{outline:0}.vjs-paused .vjs-big-play-button,.vjs-paused.vjs-has-started .vjs-big-play-button{display:none}.video-js .vjs-big-play-button{font-size:2.5em;line-height:2.3em;height:2.5em;width:2.5em;border-radius:2.5em;background-color:rgba(115,133,159,.5);border-width:.15em;margin-top:-1.25em;margin-left:-1.75em}.vjs-big-play-button .vjs-icon-placeholder{font-size:1.63em}.vjs-progress-control.vjs-control,.vjs-remaining-time.vjs-time-control.vjs-control{display:none}.vjs-loading-spinner{border:none;visibility:visible;border-radius:0}.vjs-waiting .vjs-loading-spinner{-webkit-animation:none!important;animation:none!important}.video-js .vjs-control.vjs-close-button{display:none}.loading{width:100%;height:100%;top:0;left:0;position:absolute;pointer-events:none;z-index:71;background:#000;display:none}.loading img{width:35px;height:35px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.error{width:100%;height:100%;top:0;left:0;position:absolute;background:#000;cursor:pointer;z-index:70;display:none}.error span{display:block;text-align:center;padding-top:30%;color:#fff}.vjs-control-bar>button.my_fullscreen::before{display:block!important;content:\"\u5168\u5C4F/\u9000\u51FA\";cursor:pointer}"]
}] }
];
/** @nocollapse */
HmNgVideoComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: Renderer2 }
];
HmNgVideoComponent.propDecorators = {
fileVideo: [{ type: ViewChild, args: ["fileVideoEl",] }],
liveVideo: [{ type: ViewChild, args: ["liveVideoEl",] }],
fileOptions: [{ type: Input }],
liveOptions: [{ type: Input }],
autoplay: [{ type: Input }],
videoHeight: [{ type: Input }],
videoWidth: [{ type: Input }],
className: [{ type: Input }],
loadingSrc: [{ type: Input }],
maxReloadTimes: [{ type: Input }],
errorContent: [{ type: Input }],
maxLoadTime: [{ type: Input }],
exitFullScreen: [{ type: Input }],
PauseEventListener: [{ type: Output }],
PlayingEventListener: [{ type: Output }],
WaitingEventListener: [{ type: Output }],
ErrorEventListener: [{ type: Output }],
DataLoadedEventListener: [{ type: Output }],
CanPlayEventListener: [{ type: Output }],
ReLoadVideoEventListener: [{ type: Output }],
FullScreenToggeleEventListener: [{ type: Output }]
};
/**
* @fileoverview added by tsickle
* Generated from: lib/hm-ng-video.module.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class HmNgVideoModule {
}
HmNgVideoModule.decorators = [
{ type: NgModule, args: [{
declarations: [HmNgVideoComponent],
imports: [CommonModule],
exports: [HmNgVideoComponent],
},] }
];
/**
* @fileoverview added by tsickle
* Generated from: public-api.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* Generated from: hm-ng-video.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { HmNgVideoComponent, HmNgVideoModule };
//# sourceMappingURL=hm-ng-video.js.map