| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- import EventEmitter from 'events';
- import PlayerEvents from './player-events.js';
- import {createDefaultConfig} from '../config.js';
- import {InvalidArgumentException, IllegalStateException} from '../utils/exception.js';
- // Player wrapper for browser's native player (HTMLVideoElement) without MediaSource src.
- class NativePlayer {
- constructor(mediaDataSource, config) {
- this.TAG = 'NativePlayer';
- this._type = 'NativePlayer';
- this._emitter = new EventEmitter();
- this._config = createDefaultConfig();
- if (typeof config === 'object') {
- Object.assign(this._config, config);
- }
- if (mediaDataSource.type.toLowerCase() === 'flv') {
- throw new InvalidArgumentException('NativePlayer does\'t support flv MediaDataSource input!');
- }
- if (mediaDataSource.hasOwnProperty('segments')) {
- throw new InvalidArgumentException(`NativePlayer(${mediaDataSource.type}) doesn't support multipart playback!`);
- }
- this.e = {
- onvLoadedMetadata: this._onvLoadedMetadata.bind(this)
- };
- this._pendingSeekTime = null;
- this._statisticsReporter = null;
- this._mediaDataSource = mediaDataSource;
- this._mediaElement = null;
- }
- destroy() {
- if (this._mediaElement) {
- this.unload();
- this.detachMediaElement();
- }
- this.e = null;
- this._mediaDataSource = null;
- this._emitter.removeAllListeners();
- this._emitter = null;
- }
- on(event, listener) {
- if (event === PlayerEvents.MEDIA_INFO) {
- if (this._mediaElement != null && this._mediaElement.readyState !== 0) { // HAVE_NOTHING
- Promise.resolve().then(() => {
- this._emitter.emit(PlayerEvents.MEDIA_INFO, this.mediaInfo);
- });
- }
- } else if (event === PlayerEvents.STATISTICS_INFO) {
- if (this._mediaElement != null && this._mediaElement.readyState !== 0) {
- Promise.resolve().then(() => {
- this._emitter.emit(PlayerEvents.STATISTICS_INFO, this.statisticsInfo);
- });
- }
- }
- this._emitter.addListener(event, listener);
- }
- off(event, listener) {
- this._emitter.removeListener(event, listener);
- }
- attachMediaElement(mediaElement) {
- this._mediaElement = mediaElement;
- mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
- if (this._pendingSeekTime != null) {
- try {
- mediaElement.currentTime = this._pendingSeekTime;
- this._pendingSeekTime = null;
- } catch (e) {
- // IE11 may throw InvalidStateError if readyState === 0
- // Defer set currentTime operation after loadedmetadata
- }
- }
- }
- detachMediaElement() {
- if (this._mediaElement) {
- this._mediaElement.src = '';
- this._mediaElement.removeAttribute('src');
- this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
- this._mediaElement = null;
- }
- if (this._statisticsReporter != null) {
- window.clearInterval(this._statisticsReporter);
- this._statisticsReporter = null;
- }
- }
- load() {
- if (!this._mediaElement) {
- throw new IllegalStateException('HTMLMediaElement must be attached before load()!');
- }
- this._mediaElement.src = this._mediaDataSource.url;
- if (this._mediaElement.readyState > 0) {
- this._mediaElement.currentTime = 0;
- }
- this._mediaElement.preload = 'auto';
- this._mediaElement.load();
- this._statisticsReporter = window.setInterval(
- this._reportStatisticsInfo.bind(this),
- this._config.statisticsInfoReportInterval);
- }
- unload() {
- if (this._mediaElement) {
- this._mediaElement.src = '';
- this._mediaElement.removeAttribute('src');
- }
- if (this._statisticsReporter != null) {
- window.clearInterval(this._statisticsReporter);
- this._statisticsReporter = null;
- }
- }
- play() {
- return this._mediaElement.play();
- }
- pause() {
- this._mediaElement.pause();
- }
- get type() {
- return this._type;
- }
- get buffered() {
- return this._mediaElement.buffered;
- }
- get duration() {
- return this._mediaElement.duration;
- }
- get volume() {
- return this._mediaElement.volume;
- }
- set volume(value) {
- this._mediaElement.volume = value;
- }
- get muted() {
- return this._mediaElement.muted;
- }
- set muted(muted) {
- this._mediaElement.muted = muted;
- }
- get currentTime() {
- if (this._mediaElement) {
- return this._mediaElement.currentTime;
- }
- return 0;
- }
- set currentTime(seconds) {
- if (this._mediaElement) {
- this._mediaElement.currentTime = seconds;
- } else {
- this._pendingSeekTime = seconds;
- }
- }
- get mediaInfo() {
- let mediaPrefix = (this._mediaElement instanceof HTMLAudioElement) ? 'audio/' : 'video/';
- let info = {
- mimeType: mediaPrefix + this._mediaDataSource.type
- };
- if (this._mediaElement) {
- info.duration = Math.floor(this._mediaElement.duration * 1000);
- if (this._mediaElement instanceof HTMLVideoElement) {
- info.width = this._mediaElement.videoWidth;
- info.height = this._mediaElement.videoHeight;
- }
- }
- return info;
- }
- get statisticsInfo() {
- let info = {
- playerType: this._type,
- url: this._mediaDataSource.url
- };
- if (!(this._mediaElement instanceof HTMLVideoElement)) {
- return info;
- }
- let hasQualityInfo = true;
- let decoded = 0;
- let dropped = 0;
- if (this._mediaElement.getVideoPlaybackQuality) {
- let quality = this._mediaElement.getVideoPlaybackQuality();
- decoded = quality.totalVideoFrames;
- dropped = quality.droppedVideoFrames;
- } else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
- decoded = this._mediaElement.webkitDecodedFrameCount;
- dropped = this._mediaElement.webkitDroppedFrameCount;
- } else {
- hasQualityInfo = false;
- }
- if (hasQualityInfo) {
- info.decodedFrames = decoded;
- info.droppedFrames = dropped;
- }
-
- return info;
- }
- _onvLoadedMetadata(e) {
- if (this._pendingSeekTime != null) {
- this._mediaElement.currentTime = this._pendingSeekTime;
- this._pendingSeekTime = null;
- }
- this._emitter.emit(PlayerEvents.MEDIA_INFO, this.mediaInfo);
- }
- _reportStatisticsInfo() {
- this._emitter.emit(PlayerEvents.STATISTICS_INFO, this.statisticsInfo);
- }
- }
- export default NativePlayer;
|