SkeyeWebPlayer.js H5播放器开发之播放器video动态创建(三)

时间:2021-02-23 00:53:36

SkeyeWebPlayer.js H5播放器是由成都视开信息科技开发和维护的一个完善的RTSP、FLV、HLS等多种流媒体协议播放,视频编码支持H.264,H.265,音频支持AAC,支持TCP/UDP协议,是一套极佳的且适合用于综合安防视频云服务播放组件,已经非常稳定、完整。功能包括:直播、录像、抓图,目前在功能性、稳定性、可扩展性和完整性极强的一款H5播放器!

上一节加到编译flvjs播放器,实现基础的播放器功能,本节将实现自定义动态创建video标签渲染。如下图:

SkeyeWebPlayer.js H5播放器开发之播放器video动态创建(三)

首先为了方便开发,需要将项目的目录结构做以下调整

SkeyeWebPlayer.js H5播放器开发之播放器video动态创建(三)

  • 新建flv目录,将之前的flvjs代码放到这个目录内,
  • 新建一个element 目录下新建index.js,具体代码:放在下面,
  • 首先创建一个 class 类,Element 接受self:(调用this),dom:(播放器容器:由初始化传入ID去获取:document.getElementById(ID))options:{height},当然如果有需要其他参数也可以传入,根据自己的需求来即可,
  • 首先判断有没dom (播放器容器)
  • height:是否继承外部容器的高度 Boolean值 ,false:动态设置播放器容器 56.25% 也就是默认值 16:9,
  • createElement js动态创建video标签,设置宽高为容器的宽高
export default class Element {
constructor(self, dom, {height}) {
if (!dom) {
return '';
}
if (height) {
dom.style.position = 'relative';
dom.style.backgroundColor = '#000000';
dom.style.overflow = 'hidden';
} else {
dom.style.position = 'relative';
dom.style.backgroundColor = '#000000';
dom.style.width = '100%';
dom.style.height = '100%';
dom.style.paddingTop = '56.25%';
dom.style.overflow = 'hidden';
}
this.elDom = dom;

this.videoEl = document.createElement('video');
this.videoEl.style.width = '100%';
this.videoEl.style.height = '100%';
this.videoEl.style.position = 'absolute';
this.videoEl.style.top = '0';
this.videoEl.style.left = '0';
this.videoEl.style.background = '#000000';
this.videoEl.style.background = '#000000';
this.elDom.appendChild(this.videoEl);

// this.videoEl.setAttribute('webkit-playsinline', 'true');
// this.videoEl.setAttribute('playsinline', 'true');
}
}

在播放器初始化的时候将创建出来video添加到页面

  • 在src 目录下index.js 完整代码放在最后面
  • import Element from './element';
  • this.videoElement = new Element(this, this.boxDom, { height: height });

至此SkeyeWebPlayer播放器之flv播放功能就已经实现

// videoEl
this.videoElement = new Element(this, this.boxDom, {
height: height,
isFill: showMode
});

import Features from './flv/core/features.js';
import ScreenCanvas from './element/off-screen-canvas';
import Element from './element';
import BigPlayButton from './element/big-play-button';
import Emitter from './utils/emitter';
import {isNum, parseLocation} from './utils';
import './font/iconfont.css';
import './styles/index.css';
import './styles/range.css';

import WebFlvPlayer from './player/webFlvPlayer.js';

export default class WebMediaPlayer extends Emitter {
constructor(url, ID, cbFunc, data = {}) {
super();
let {cbUserPtr, decodeType, openAudio, bigPlay = false, height = false, showMode = false, playbackRecord} = data;
this.player = null;
this.url = url;
this.callbackFunc = cbFunc || function () {

};
this.callbackUserPtr = cbUserPtr;
this.height = height;
this.bigPlay = bigPlay;
this.decodeType = 'auto';
this.version = __VERSION__;
this.isPlaying = false;
if (decodeType === 'auto' || decodeType === 'soft') {
this.decodeType = decodeType;
}
if (!Features.supportMSEH264Playback()) {
this.decodeType = 'soft';
}
//此处应为true, 则在所有平台上功能表现正常, 如为false,在苹果上则不能自动播放声音, 现应用在win chrome上,暂置为false;
this.internalTriggerPlay = true;
this.showMode = showMode;
this.playbackRecord = playbackRecord;
this.VideoCodec = '';
this.VideoWidth = 0;
this.VideoHeight = 0;

this.showTimeLabel = false;
this.seeking = false;
this.callbackEnd = false;

this.initH5Flag = false;
this.currentH5Status = false;
this.seekTimeSecs = 0;
this.fullScreenFlag = false;
if (!ID) {
return false;
}
// 声音
this.defaultAudioStatus = !!openAudio;
this.enableAudio = !!openAudio;

this.boxDom = document.getElementById(ID);
if (!this.boxDom) {
return false;
}

// videoEl
this.videoElement = new Element(this, this.boxDom, {
height: height,
isFill: showMode
});
this.h5Video = this.videoEl = this.videoElement.videoEl;
// canvas
this.screenCanvas = new ScreenCanvas(this, this.boxDom);
// 中间大播放按钮
this.bigPlayButton = new BigPlayButton(this, this.boxDom, bigPlay);

this.on('streamType', this._onChangeTypeCallback.bind(this));

if (url) {
this.play(url, true);
}
}

/**
* 播放 play
* @param url
* @param autoPlay
* @param time
* @returns {boolean|void}
*/
play(url, autoPlay = true, time = 0) {
if (!url) {
url = this.url;
}
if (!this.boxDom) {
return false;
} else if (!url) {
return console.log('播放地址不能为空');
} else if (!autoPlay) {
return false;
} else if (!isNum(time)) {
return console.log('time 必须传数字类型');
}
let locationObj = parseLocation(url);
if (!['rtsp:', 'http:', 'https:', 'ws:', 'wss:'].some(item => item === locationObj.protocol)) {
console.log('不支持 stream: ' + url);
}

this.url = url;
this.emit('play');
this.callbackFunc('play');
this.seekTimeSecs = time;

// 关闭加载动画
this._onConnectStatus(this, 99);

// 后缀
let postfix = url.split('.').pop().toLowerCase();
if (this.player) {
// 暂停之后继续播放
this.player.play(this.url, 0);
} else if (/flv$/.test(postfix)) {
// FLV流 (http-flv 、 ws-flv)
this.player = new WebFlvPlayer(this, {
type: 'flv',
isLive: true,
url: url,
videoDom: this.videoEl,
canvasDom: this.screenCanvas.canvas,
decodeType: this.decodeType,
}, {
onGetVideoInfo: this.onVideoInfo,
self: this
});
}
}

stop() {
if (!this.boxDom) return;
this.callbackFunc('stop');
this.callbackEnd = false;
this._onConnectStatus(this, 99); // 关闭加载动画
if (this.playerInstance) {
this.closeAudio();
this.playerInstance.stop();
this.showTimeLabel = false;
return true;
}
return false;
}

pause() {
this.player.pause();
}

removeAllChilds(p) {
for (var i = p.childNodes.length - 1; i >= 0; i--) {
this.removeAllChilds(p.childNodes[i]);
p.removeChild(p.childNodes[i]);
}
}

destroy() {
this.stop();

if (this.boxDom) {
this.removeAllChilds(this.boxDom);
}

if (this.playerInstance) {
this.playerInstance.stop();
this.playerInstance.destroy();
delete this.playerInstance;
this.playerInstance = null;
}
}

changeToH5Video(b) {
if (!this.initH5Flag) {
this.initH5Flag = true;
} else {
if (b === this.currentH5Status) {
return;
}
}
this.currentH5Status = b;
if (b) {
if (this.screenCanvas.canvas) {
this.boxDom.removeChild(this.screenCanvas.canvas);
}
} else {
if (this.h5Video) {
this.boxDom.removeChild(this.h5Video);
}
}
}

// 连接状态回调
_onConnectStatus(_this, status) {
_this.emit('status', status);
}

//流类型回调
_onChangeTypeCallback(streamType, isWasm) {
this.changeToH5Video(!isWasm);
}

/**
* 获取视频编码信息
* @param _this
* @param _videoCodec
* @param _width
* @param _height
* @private
*/
onVideoInfo(_this, _videoCodec, _width, _height) {
_this.VideoCodec = _videoCodec;
_this.VideoWidth = _width;
_this.VideoHeight = _height;
_this.emit('resolutionRatio', {code: _videoCodec, width: _width, height: _height});
_this._onConnectStatus(_this, 100);
}

rtspScale(scaleValue, ptsInterval) {
if (this.playerInstance) {
this.playerInstance.rtspScale(scaleValue, ptsInterval);
}
}

//外部调用(秒)
seekToSecs(seekValue) {
console.log('seekValue', seekValue);
if (this.playerInstance) {
this.playerInstance.seek(seekValue, 0);
}
}

//百分比
seekToPercent(seekValue) {
if (this.playerInstance) {
this.playerInstance.seek(seekValue, 1);
}
}

// 设置滚动条和时间标签
setTrack(timeTrack, timeLabel) {
if (this.playerInstance) {
this.playerInstance.setTrack(timeTrack, timeLabel);
}
}

openAudio() {
this.callbackFunc('openAudio');
if (this.playerInstance) {
if (this.playerInstance.openAudio()) {
//仅为内部判断是否启用音频进行remux
common.SetEnableAudio(true);
this.enableAudio = true;
} else {
this.enableAudio = false;
}
}
this.emit('audio', this.enableAudio);
return this.enableAudio;
}

closeAudio() {
this.callbackFunc('closeAudio');
if (this.playerInstance) {
if (!this.enableAudio) {
return true;
}
if (this.playerInstance.closeAudio()) {
this.enableAudio = false;
} else {
this.enableAudio = true;
}
}
this.emit('audio', this.enableAudio);
return !this.enableAudio;
}

showStaticsInfo(enable) {
if (this.playerInstance == null) {
return false;
}

if (enable) {
return this.playerInstance.openStatinfo();
} else {
return this.playerInstance.closeStatinfo();
}
return false;
}
}