/**
* @file tech.js
* /
importiere Komponente von '../komponente';
import mergeOptions from '../utils/merge-options.js';
import * as Fn from '../utils/fn.js';
import log from '../utils/log.js';
importiere {createTimeRange} aus '.. /utils/time-ranges.js ';
importiere {bufferedPercent} aus '.. /utils/buffer.js ';
importiere MediaError aus '.. /media-error.js ';
import window from 'global/window';
dokument aus 'global/document' importieren;
importiere {isPlain} von '../utils/obj';
importiere * als TRACK_TYPES aus '.. /tracks/track-Typen ';
importiere {toTitleCase, toLowerCase} aus '.. /utils/string-cases.js ';
importiere vtt aus 'videojs-vtt.js';
import * as Guid from '../utils/guid.js';
/**
* Ein Objekt, das eine Struktur wie: `{src: 'url', type: 'mimetype'}` oder eine Zeichenfolge enthält
* das enthält nur die src-URL allein.
* * `var sourceObject = {src: 'http://ex.com/video.mp4', typ: 'video/mp4'}; `
* `var sourceString = 'http://example.com/some-video.mp4'; `
*
* @typedef {object|String} tech~sourceObject
*
* @property {string} src
* Die URL zur Quelle
*
* Typ @property {string}
* Der MIME-Typ der Quelle
* /
/**
* Eine Funktion, die von {@link Tech} verwendet wird, um einen neuen {@link TextTrack} zu erstellen.
*
* @privat
*
* @param {Tech} selbst
* Ein Beispiel der Tech-Klasse.
*
* @param {string} kind
* textTrack"-Typ (Untertitel, Untertitel, Beschreibungen, Kapitel oder Metadaten)
*
* @param {string} [label]
* Label zur Kennzeichnung der Textspur
*
* @param {string} [Sprache]
* Sprachabkürzung mit zwei Buchstaben
*
* @param {Object} [options={}]
* Ein Objekt mit zusätzlichen Texttrack-Optionen
*
* @return {TextTrack}
* Der Texttrack, der erstellt wurde.
* /
function createTrackHelper (self, kind, label, language, options = {}) {
const tracks = self.textTracks ();
options.kind = nett;
wenn (Etikett) {
options.label = label;
}
wenn (Sprache) {
options.language = Sprache;
}
options.tech = selbst;
const track = new track_types.all.text.trackClass (Optionen);
Tracks.addTrack (Track);
rückweg;
}
/**
* Dies ist die Basisklasse für Controller der Medienwiedergabetechnologie wie
* {@link HTML5}
*
* @erweitert Komponente
* /
class Tech erweitert Komponente {
/**
* Erstellen Sie eine Instanz dieser Tech.
*
* @param {Object} [Optionen]
* Der Schlüssel/Wertspeicher der Playeroptionen.
*
* @param {Component~ReadyCallback} ready
* Callback-Funktion, die aufgerufen wird, wenn die "HTML5"-Technologie bereit ist.
* /
konstruktor (Optionen = {}, bereit = Funktion () {}) {
//Wir wollen nicht, dass der Techniker Benutzeraktivitäten automatisch meldet.
//Dies erfolgt manuell in addControlsListeners
options.reportTouchActivity = false;
super(null, options, ready);
this.onDurationChange_ = (e) => this.onDurationChange (e);
this.trackProgress_ = (e) => this.trackProgress (e);
this.trackCurrentTime_ = (e) => this.trackCurrentTime (e);
this.stopTrackingCurrentTime_ = (e) => this.stopTrackingCurrentTime (e);
this.dispeSourceHandler_ = (e) => this.dispeSourceHandler (e);
this.queuedHanders_ = neues Set ();
//verfolge, ob die aktuelle Quelle überhaupt abgespielt hat, bis
//implementiere ein sehr limitiertes Played ()
this.hasStarted_ = false;
this.on ('spielt', function () {
this.hasStarted_ = wahr;
});
this.on ('loadstart', Funktion () {
this.hasStarted_ = false;
});
track_types.all.names.forEach ((name) => {
const props = TRACK_TYPES.ALL[name];
if (Optionen && Optionen [props.getterName]) {
this [props.PrivateName] = Optionen [props.getterName];
}
});
//Verfolge den Fortschritt manuell, wenn der Browser/die Technik ihn nicht meldet.
wenn (! this.featuresProgressEvents) {
this.manualProgresson ();
}
//Manuelles Nachverfolgen von Zeitaktualisierungen in Fällen, in denen der Browser/die Technik sie nicht meldet.
wenn (! this.featuresTimeUpdateEvents) {
this.manualTimeUpdatesOn ();
}
['Text', 'Audio', 'Video'] .forEach (track) => {
if (options [`native$ {track} Tracks`] === falsch) {
this [`featuresNative$ {track} Tracks`] = falsch;
}
});
wenn (options.nativeCaptions === falsch || options.nativeTextTracks === falsch) {
this.featureNativeTextTracks = falsch;
} sonst wenn (options.nativeCaptions === true || options.nativeTextTracks === true) {
this.featuresNativeTextTracks = wahr;
}
if (!this.featuresNativeTextTracks) {
this.emulateTextTracks ();
}
this.preloadTextTracks = Optionen.preloadTextTracks! == falsch;
this.autoRemoteTextTracks_ = neues track_types.all.text.listClass ();
this.initTrackListeners ();
//Aktiviere Component-Tap-Events nur, wenn du keine nativen Steuerelemente verwendest
wenn (! Options.native Steuerelemente für Touch) {
this.emitTapEvents();
}
wenn (this.constructor) {
this.name_ = this.constructor.name || 'Unbekannte Technologie';
}
}
/**
* Eine spezielle Funktion, um den Quellensatz so auszulösen, dass der Spieler es ermöglicht
* um erneut auszulösen, falls der Spieler oder der Techniker noch nicht bereit sind.
*
* @fires Technik #sourceset
* @param {string} src Die Quellzeichenfolge zum Zeitpunkt der Quelländerung.
* /
TriggerSourceSet (src) {
if (!this.isReady_) {
//wenn das erste Mal bereit ist, müssen wir den Quellsatz auslösen
//1 ms nach Bereit, damit der Spieler darauf achten kann.
this.one ('bereit', () => this.setTimeout () => this.triggerSourceSet (src), 1));
}
/**
* Wird ausgelöst, wenn die Quelle auf die Technologie eingestellt ist, die das Medienelement verursacht
* um neu zu laden.
*
* @see {@link Spieler #event:sourceset}
* @event Technik #sourceset
* @Typ {EventTarget~Event}
* /
this.trigger({
src,
typ: 'Quellensatz'
});
}
/* Fallbacks für nicht unterstützte Ereignistypen
============================================================================ */
/**
* Füllen Sie das `progress`-Ereignis für Browser, die es nicht nativ unterstützen, mit Polyfill aus.
*
* @see {@link Technik #trackProgress}
* /
Manueller Fortschritt auf () {
this.on ('durationchange', this.onDurationChange_);
this.manualProgress = wahr;
//Löse die Fortschrittsüberwachung aus, wenn eine Quelle zu laden beginnt
this.one ('bereit', this.trackProgress_);
}
/**
* Deaktivieren Sie das Polyfill für "Fortschritts"-Ereignisse, das in
* {@link Tech#manualProgressOn}
* /
Manueller Fortschritt von () {
this.manualProgress = falsch;
this.stopTrackingProgress();
this.off ('durationchange', this.onDurationChange_);
}
/**
* Dies wird verwendet, um ein Fortschrittsereignis auszulösen, wenn sich der gepufferte Prozentsatz ändert. Es
* legt eine Intervallfunktion fest, die alle 500 Millisekunden aufgerufen wird, um zu überprüfen, ob
* Der Endprozentsatz des Puffers hat sich geändert.
*
* > Diese Funktion wird von {@link Tech #manualProgressOn} aufgerufen
*
* @param {EventTarget~Event} event
* Das `read`-Ereignis, das dazu geführt hat, dass dies ausgeführt wurde.
*
* @listens Technik #ready
* @fires Technik #progress
* /
trackProgress (Ereignis) {
this.stopTrackingProgress();
this.progressInterval = this.setInterval (fn.Bind (this, function () {
//Nicht auslösen, es sei denn, die gepufferte Menge ist größer als beim letzten Mal
const numBufferedPercent = this.bufferedPercent ();
wenn (this.BufferedPercent_! == NumBufferedPercent) {
/**
* Siehe {@link Player #progress}
*
* @event Technik #progress
* @Typ {EventTarget~Event}
* /
this.trigger ('Fortschritt');
}
this.bufferedPercent_ = NumBufferedPercent_;
wenn (numBufferedPercent === 1) {
this.stopTrackingProgress();
}
}), 500);
}
/**
* Aktualisiere unsere interne Dauer eines `durationchange`-Events, indem du uns anrufst
* {@link Tech #duration}.
*
* @param {EventTarget~Event} event
* Das `durationchange`-Ereignis, das dazu geführt hat, dass dies ausgeführt wurde.
*
* @listens Tech#durationchange
* /
onDurationChange (Ereignis) {
this.duration_ = this.duration ();
}
/**
* Ruft ein `TimeRange`-Objekt für die Pufferung ab und erzeugt es.
*
* @return {TimeRange}
* Das Zeitbereichsobjekt, das erstellt wurde.
* /
gepuffert() {
return createTimeRange(0, 0);
}
/**
* Ruft den Prozentsatz des aktuellen Videos ab, der derzeit gepuffert ist.
*
* @return {number}
* Eine Zahl von 0 bis 1, die den Dezimalprozentsatz der
* Video, das gepuffert ist.
*
* /
bufferedPercent() {
gib bufferedPercent (this.buffered (), this.duration_) zurück;
}
/**
* Deaktivieren Sie das Polyfill für "Fortschritts"-Ereignisse, das in
* {@link Tech#manualProgressOn}
* Beenden Sie die manuelle Verfolgung von Fortschrittsereignissen, indem Sie das eingestellte Intervall löschen
* {@link Technik #trackProgress}.
* /
stopTrackingProgress () {
this.clearInterval (this.ProgressInterval);
}
/**
* Füllen Sie das `timeupdate`-Ereignis für Browser, die es nicht unterstützen, mit Polyfill aus.
*
* @see {@link Technik #trackCurrentTime}
* /
ManualTimeUpdatesOn () {
this.manualTimeUpdates = wahr;
this.on ('abspielen', this.trackCurrentTime_);
this.on ('pause', this.stopTrackingCurrentTime_);
}
/**
* Schalten Sie das Polyfill für `timeupdate`-Ereignisse aus, das in erstellt wurde
* {@link Technik #manualTimeUpdatesOn}
* /
ManualTimeUpdatesOff () {
this.manualTimeUpdates = falsch;
this.stopTrackingCurrentTime();
this.off ('abspielen', this.trackCurrentTime_);
this.off ('pause', this.stopTrackingCurrentTime_);
}
/**
* Richtet eine Intervallfunktion ein, um die aktuelle Uhrzeit zu verfolgen und jedes Mal ein `timeupdate` auszulösen
* 250 Millisekunden.
*
* @listens Tech#play
* @triggers Technik #timeupdate
* /
TrackCurrentTime () {
wenn (this.currentTimeInterval) {
this.stopTrackingCurrentTime();
}
this.currentTimeInterval = this.setInterval (function () {
/**
* Wird in einem Intervall von 250 ms ausgelöst, um anzuzeigen, dass im Video Zeit vergeht.
*
* @event Tech#timeupdate
* @Typ {EventTarget~Event}
* /
this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
//42 = 24 fps//250 verwendet Webkit//FF verwendet 15
}, 250);
}
/**
* Stoppen Sie die in {@link Tech #trackCurrentTime} erstellte Intervallfunktion, sodass
* Das Ereignis `timeupdate` wird nicht mehr ausgelöst.
*
* @listens {Tech #pause}
* /
stopTrackingCurrentTime () {
this.clearInterval (this.currentTimeInterval);
//#1002 - wenn das Video kurz vor dem nächsten Update endet,
//der Fortschrittsbalken wird es nicht bis zum Ende schaffen
this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
}
/**
* Schalten Sie alle Event-Polyfills aus, löschen Sie die `Tech`s {@link AudioTrackList},
* {@link videoTrackList} und {@link textTrackList} und verfügen über diese Technologie.
*
* @feuert Komponente#entsorgen
* /
dispose() {
// alle Spuren löschen, da wir sie nicht zwischen den Techs wiederverwenden können
this.clearTracks (track_types.normal.Names);
//Deaktiviere jegliche manuelle Fortschritts- oder Zeitaktualisierungsverfolgung
wenn (this.manualProgress) {
this.manualProgressOff ();
}
if (this.manualTimeUpdates) {
this.manualTimeUpdatesOff ();
}
super.dispose();
}
/**
* Lösche eine einzelne `TrackList` oder ein Array von `TrackLists` mit ihren Namen.
*
* > Anmerkung: Techniker ohne Quellhandler sollten dies zwischen den Quellen für `Video` aufrufen
* & `Audio` Titel. Du willst sie nicht zwischen Tracks benutzen!
*
* @param {string [] |string} -Typen
* Zu löschende TrackList-Namen, gültige Namen sind `Video`, `Audio` und
* `Text`.
* /
ClearTracks (Typen) {
typen = [] .concat (Typen);
// alle Spuren löschen, da wir sie nicht zwischen den Techs wiederverwenden können
types.forEach (Typ) => {
const list = this [`$ {type} Tracks`] () || [];
let i = list.length;
while (i--) {
const track = list[i];
if (type === 'text') {
this.removeRemoteTextTrack(track);
}
list.removeTrack (verfolgen);
}
});
}
/**
* Entferne alle TextTracks, die über addRemoteTextTrack hinzugefügt wurden und die
* markiert für automatische Müllabfuhr
* /
AutoTextTracks aufräumen () {
const list = this.autoRemoteTextTracks_ || [];
let i = list.length;
while (i--) {
const track = list[i];
this.removeRemoteTextTrack(track);
}
}
/**
* Setzen Sie die Technologie zurück, wodurch alle Quellen entfernt und der interne ReadyState zurückgesetzt wird.
*
* @Abstrakt
* /
zurücksetzen () {}
/**
* Holen Sie sich den Wert von `crossOrigin` vom Techniker.
*
* @Abstrakt
*
* @see {Html5 #crossOrigin}
* /
CrossOrigin () {}
/**
* Stellen Sie den Wert von `CrossOrigin` für die Technologie ein.
*
* @Abstrakt
*
* @param {string} crossOrigin der crossOrigin-Wert
* @see {Html5 #setCrossOrigin}
* /
setCrossOrigin () {}
/**
* Erhalte einen Fehler auf dem Tech oder stelle ihn ein.
*
* @param {MediaError} [Fehler]
* Fehler beim Einstellen der Technik
*
* @return {MediaError|null}
* Das aktuelle Fehlerobjekt auf der Technologie oder null, wenn es keins gibt.
* /
error(err) {
wenn (irr! == undefiniert) {
this.error_ = new MediaError(err);
this.trigger('error');
}
gib das.error_ zurück;
}
/**
* Gibt die `TimeRange`s zurück, die für die aktuelle Quelle abgespielt wurden.
*
* > HINWEIS: Diese Implementierung ist unvollständig. Der abgespielte `TimeRange` wird nicht aufgezeichnet.
* Es wird nur geprüft, ob die Quelle überhaupt abgespielt hat oder nicht.
*
* @return {TimeRange}
* - Ein einzelner Zeitraum, wenn dieses Video abgespielt wurde
* - Ein leerer Satz von Bereichen, falls nicht.
* /
gespielt() {
if (this.hasStarted_) {
return createTimeRange(0, 0);
}
gib createTimeRange () zurück;
}
/**
* Wiedergabe starten
*
* @Abstrakt
*
* @see {Html5 #play}
* /
abspielen () {}
/**
* Stellen Sie ein, ob wir schrubben oder nicht
*
* @Abstrakt
*
* @see {Html5 #setScrubbing}
* /
setScrubbing () {}
/**
* Finde heraus, ob wir schrubben oder nicht
*
* @Abstrakt
*
* @see {Html5 #scrubbing}
* /
schrubben () {}
/**
* Führt zu einer manuellen Zeitaktualisierung, wenn {@link Tech #manualTimeUpdatesOn}
* zuvor angerufen.
*
* @fires Technik #timeupdate
* /
setCurrentTime () {
//die Genauigkeit manueller Zeitaktualisierungen verbessern
if (this.manualTimeUpdates) {
/**
* Ein manuelles `timeupdate`-Ereignis.
*
* @event Tech#timeupdate
* @Typ {EventTarget~Event}
* /
this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
}
}
/**
* Schalten Sie die Listener für {@link videoTrackList}, {@link {AudioTrackList} ein und
* {@link textTrackList} Ereignisse.
*
* Dadurch wird {@link eventTarget~eventListeners} für `addtrack` und `removetrack` hinzugefügt.
*
* @fires Technik #audiotrackchange
* @fires Technik #videotrackchange
* @fires Technik #texttrackchange
* /
initTrackListener () {
/**
* Wird ausgelöst, wenn Titel auf der Tech {@link AudioTrackList} hinzugefügt oder entfernt werden
*
* @event Technik #audiotrackchange
* @Typ {EventTarget~Event}
* /
/**
* Wird ausgelöst, wenn Tracks auf der Tech {@link videoTrackList} hinzugefügt oder entfernt werden
*
* @event Technik #videotrackchange
* @Typ {EventTarget~Event}
* /
/**
* Wird ausgelöst, wenn Tracks auf der Tech {@link textTrackList} hinzugefügt oder entfernt werden
*
* @event Technik #texttrackchange
* @Typ {EventTarget~Event}
* /
track_types.normal.names.forEach ((name) => {
const props = TRACK_TYPES.NORMAL [Name];
const trackListChanges = () => {
this.trigger (`$ {name} trackchange`);
};
const tracks = this [props.getterName] ();
tracks.addEventListener ('Track entfernen', tracklistChanges);
tracks.addEventListener ('addTrack', tracklistChanges);
this.on('dispose', () => {
tracks.removeEventListener ('Track entfernen', trackListChanges);
tracks.removeEventListener ('Track hinzufügen', trackListChanges);
});
});
}
/**
* Emulieren Sie TextTracks mit vtt.js, falls erforderlich
*
* @fires Technik #vttjsloaded
* @fires Technik #vttjserror
* /
WebVTTScript_ () {hinzufügen
wenn (window.webVTT) {
rückkehr;
}
//Anfänglich ist Tech.el_ ein Kind eines Dummy-Div warte bis das Komponentensystem
//signalisiert, dass der Tech bereit ist. Zu diesem Zeitpunkt ist Tech.el_ Teil des DOM
//vor dem Einfügen des WebVTT-Skripts
wenn (document.body.contains (this.el ())) {
//lade über require, falls verfügbar und der Skriptort vtt.js wurde nicht übergeben
//als Option. novtt builds wandelt den obigen Reque-Aufruf in ein leeres Objekt um
//was dazu führt, dass die Überprüfung immer fehlschlägt.
wenn (! this.options_ ['vtt.js'] && isPlain (vtt) && Object.keys (vtt) .length > 0) {
this.trigger('vttjsloaded');
rückkehr;
}
//lade vtt.js über die Script-Location-Option oder das CDN, wenn kein Speicherort vorhanden war
//übergeben
const script = document.createElement ('Skript');
script.src = this.options_ ['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.14.1/vtt.min.js';
script.onload = () => {
/**
* Wird ausgelöst, wenn vtt.js geladen wird.
*
* @event Tech#vttjsloaded
* @Typ {EventTarget~Event}
* /
this.trigger('vttjsloaded');
};
script.onerror = () => {
/**
* Wird ausgelöst, als vtt.js aufgrund eines Fehlers nicht geladen wurde
*
* @event Tech#vttjsloaded
* @Typ {EventTarget~Event}
* /
this.trigger ('vttjs-Fehler');
};
this.on('dispose', () => {
script.onload = null;
script.onerror = null;
});
//haben es aber noch nicht geladen und wir haben es vor dem Inject auf true gesetzt, damit
//wir überschreiben das eingefügte window.webVTT nicht, wenn es sofort geladen wird
window.webVTT = wahr;
this.el () .parentNode.appendChild (Skript);
} sonst {
this.ready (this.addWebVTTScript_);
}
}
/**
* Texttracks emulieren
*
* /
emulieren Sie TextTracks () {
const tracks = this.textTracks ();
const remoteTracks = this.remoteTextTracks ();
const handleAddTrack = (e) => tracks.addTrack (e.track);
const handleRemoveTrack = (e) => tracks.removeTrack (e.track);
remoteTracks.on ('addtrack', handleAddTrack);
remoteTracks.on ('removeTrack', handleRemoveTrack);
Das.addWebVTTScript_ ();
const updateDisplay = () => this.trigger ('texttrackchange');
const textTracksChanges = () => {
Anzeige aktualisieren ();
for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];
track.removeEventListener('cuechange', updateDisplay);
if (track.mode === 'showing') {
track.addEventListener ('cuechange', updateDisplay);
}
}
};
TextTrack-Änderungen ();
tracks.addEventListener ('ändern', textTracksChanges);
tracks.addEventListener ('addTrack', textTracksChanges);
tracks.addEventListener ('Track entfernen', textTracksChanges);
this.on('dispose', function() {
remoteTracks.off ('addtrack', handleAddTrack);
removeTracks.off ('removeTrack', handleRemoveTrack);
tracks.removeEventListener ('ändern', textTracksChanges);
tracks.removeEventListener ('Track hinzufügen', textTracksChanges);
tracks.removeEventListener ('removeTrack', textTracksChanges);
for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];
track.removeEventListener('cuechange', updateDisplay);
}
});
}
/**
* Erstellt ein entferntes {@link TextTrack}-Objekt und gibt es zurück.
*
* @param {string} kind
* textTrack"-Typ (Untertitel, Untertitel, Beschreibungen, Kapitel oder Metadaten)
*
* @param {string} [label]
* Label zur Kennzeichnung der Textspur
*
* @param {string} [Sprache]
* Sprachabkürzung mit zwei Buchstaben
*
* @return {TextTrack}
* Die TextSpur, die erstellt wird.
* /
addTextTrack(kind, label, language) {
wenn (! nett) {
einen neuen Fehler auslösen ('Die Art von TextTrack ist erforderlich, wurde aber nicht bereitgestellt');
}
return createTrackHelper (this, kind, label, language);
}
/**
* Erstellen Sie einen emulierten TextTrack zur Verwendung durch addRemoteTextTrack
*
* Dies soll durch Klassen außer Kraft gesetzt werden, die von
* Technologie, um native oder benutzerdefinierte TextTracks zu erstellen.
*
* @param {Object} options
* Das Objekt sollte die Optionen enthalten, mit denen der TextTrack initialisiert werden soll.
*
* @param {string} [options.kind]
* textTrack"-Typ (Untertitel, Untertitel, Beschreibungen, Kapitel oder Metadaten).
*
* @param {string} [options.label].
* Label zur Kennzeichnung der Textspur
*
* @param {string} [options.language]
* Sprachabkürzung mit zwei Buchstaben.
*
* @return {HTMLTrackElement}
* Das Spurelement, das erstellt wird.
* /
createRemoteTextTrack(options) {
const track = mergeOptions (Optionen, {
Technik: das
});
gib das neue track_types.remote.remoteText.trackClass (track) zurück;
}
/**
* Erzeugt ein entferntes Text-Track-Objekt und gibt ein HTML-Track-Element zurück.
*
* > Anmerkung: Dies kann ein emuliertes {@link HtmlTrackElement} oder ein natives sein.
*
* @param {Object} options
* Siehe {@link Tech #createRemoteTextTrack} für detailliertere Eigenschaften.
*
* @param {boolean} [manualCleanup=Wahr]
* - Wenn falsch: Der TextTrack wird automatisch aus dem Video entfernt
* Element immer dann, wenn sich die Quelle ändert
* - Wenn wahr: Der TextTrack muss manuell bereinigt werden
*
* @return {HTMLTrackElement}
* Ein HTML-Track-Element.
*
* @deprecated Die Standardfunktionalität für diese Funktion wird gleichwertig sein
* in Zukunft auf „manualCleanup=False“. Der ManualCleanup-Parameter wird
* ebenfalls entfernt werden.
* /
addRemoteTextTrack (Optionen = {}, ManualCleanup) {
const htmlTrackElement = this.createRemoteTextTrack (Optionen);
wenn (ManualCleanup! == wahr & ManualCleanup! == falsch) {
//Warnung vor Verfall
log.warn ('Der Aufruf von addRemoteTextTrack, ohne den Parameter „ManualCleanup“ explizit auf `true` zu setzen, ist veraltet und wird in zukünftigen Versionen von video.js standardmäßig auf `false` gesetzt.);
ManualCleanup = wahr;
}
// HTMLTrackElement und TextTrack in entfernter Liste speichern
this.remoteTextTrackels () .addTrackElement_ (htmlTrackElement);
this.remoteTextTracks () .addTrack (htmlTrackElement.track);
wenn (ManualCleanup! == wahr) {
//erstelle die TextTrackList falls sie nicht existiert
this.ready () => this.autoRemoteTextTracks_.addTrack (htmlTrackElement.track));
}
return htmlTrackElement;
}
/**
* Entferne einen Remote-Texttrack aus der Remote-`TextTrackList`.
*
* @param {TextTrack} track
* `TextTrack` zum Entfernen aus der `TextTrackList`
* /
removeRemoteTextTrack(track) {
const trackElement = this.remoteTextTrackels () .getTrackElementByTrack_ (track);
//entferne HtmlTrackElement und TextTrack aus der Remote-Liste
this.remoteTextTrackels () .removeTrackElement_ (trackElement);
this.remoteTextTracks () .removeTrack (track);
this.autoRemoteTextTracks_.removeTrack (track);
}
/**
* Ruft verfügbare Metriken zur Qualität der Medienwiedergabe ab, wie sie vom W3C's Media
* Wiedergabequalität API.
*
* @see [Spec]{@link https://wicg.github.io/media-playback-quality}
*
* @return {Object}
* Ein Objekt mit unterstützten Qualitätsmetriken für die Medienwiedergabe
*
* @Abstrakt
* /
getVideoPlaybackQuality() {
kehre {} zurück;
}
/**
* Versuchen Sie, ein schwebendes Videofenster immer über anderen Fenstern zu erstellen
* damit Benutzer weiterhin Medien konsumieren können, während sie mit anderen interagieren
* Inhaltsseiten oder Anwendungen auf ihrem Gerät.
*
* @see [Spec]{@link https://wicg.github.io/picture-in-picture}
*
* @return {Versprechen|undefiniert}
* Ein Versprechen mit einem Bild-im-Bild-Fenster, sofern der Browser das unterstützt
* Versprechen (oder eines wurde optional abgegeben). Es gibt undefiniert zurück
* sonst.
*
* @Abstrakt
* /
requestPictureInPicture() {
const PromiseClass = this.options_.Promise || window.Promise;
if (PromiseClass) {
gib promiseClass.reject () zurück;
}
}
/**
* Eine Methode, um den Wert der <video>-Eigenschaft 'disablePictureInPicture' zu überprüfen.
* Der Standardwert ist true, da es als deaktiviert betrachtet werden sollte, wenn der Techniker Pip nicht unterstützt
*
* @Abstrakt
* /
DisablePictureInPicture () {
true zurückgeben;
}
/**
* Eine Methode, um die <video>-Eigenschaft 'disablePictureInPicture' zu setzen oder zu deaktivieren.
*
* @Abstrakt
* /
setDisablePictureInPicture () {}
/**
* Eine Fallback-Implementierung von RequestVideoFrameCallback mit RequestAnimationFrame
*
* @param {function} cb
* @return {number} Anfrage-ID
* /
requestVideoFrameCallback(cb) {
const id = GUID.newGUID ();
wenn (! this.isReady_ || this.pausiert () {
this.queuedHanders_.add (id);
this.one ('spielt', () => {
if (this.queuedHanders_.has(id)) {
this.queuedHanders_.delete(id);
cb();
}
});
} sonst {
this.requestNamedAnimationFrame (id, cb);
}
return id;
}
/**
* Eine Fallback-Implementierung von CancelVideoFrameCallback
*
* @param {number} id ID des Rückrufs, der storniert werden soll
* /
cancelVideoFrameCallback(id) {
if (this.queuedHanders_.has(id)) {
this.queuedHanders_.delete(id);
} sonst {
this.cancelNamedAnimationFrame (id);
}
}
/**
* Eine Methode, um ein Poster aus einem `Tech` zu erstellen.
*
* @Abstrakt
* /
setPoster () {}
/**
* Eine Methode, um zu überprüfen, ob das <Video>-Attribut 'playsinline' vorhanden ist.
*
* @Abstrakt
* /
spielt online () {}
/**
* Eine Methode, um das <Video>-Attribut 'playsinline' zu setzen oder zu deaktivieren.
*
* @Abstrakt
* /
setPlaysInline () {}
/**
* Versuch, die Überschreibung der nativen Audiospuren zu erzwingen.
*
* @param {boolean} override - Wenn auf true gesetzt, wird das native Audio außer Kraft gesetzt,
* andernfalls wird möglicherweise natives Audio verwendet.
*
* @Abstrakt
* /
NativeAudioTracks überschreiben () {}
/**
* Versuch, die Überschreibung der nativen Videospuren zu erzwingen.
*
* @param {boolean} override - Wenn auf true gesetzt, wird natives Video außer Kraft gesetzt,
* andernfalls wird möglicherweise natives Video verwendet.
*
* @Abstrakt
* /
NativeVideoTracks () überschreiben {}
/*
* Prüfen Sie, ob der Techniker den angegebenen MIME-Typ unterstützen kann.
*
* Die Basistechnologie unterstützt keinen Typ, aber Quellbearbeiter können
* überschreiben.
*
* @param {string} type
* Der Mimetype, um nach Unterstützung zu suchen
*
* @return {string}
* 'wahrscheinlich', 'vielleicht' oder leere Zeichenfolge
*
* @see [Spezifikation] {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType}
*
* @Abstrakt
* /
canPlayType () {
zurückgeben '';
}
/**
* Prüfen Sie, ob der Typ von dieser Technologie unterstützt wird.
*
* Die Basistechnologie unterstützt keinen Typ, aber Quellbearbeiter können
* überschreiben.
*
* @param {string} type
* Der zu prüfende Medientyp
* @return {string} Gibt die Antwort des nativen Videoelements zurück
* /
statischer canPlayType () {
zurückgeben '';
}
/**
* Prüfen Sie, ob der Techniker die angegebene Quelle unterstützen kann
*
* @param {Object} srcObj
* Das Quellobjekt
* @param {Object} options
* Die an die Technik übergebenen Optionen
* @return {string} 'wahrscheinlich', 'vielleicht', oder '' (leere Zeichenkette)
* /
statisch canPlaySource (srcoBJ, Optionen) {
gib tech.canPlayType (srcobj.Type) zurück;
}
/*
* Gibt an, ob das Argument ein Tech ist oder nicht.
* Es kann entweder eine Klasse wie `Html5` oder eine Instanz wie `player.tech_` übergeben werden
*
* @param {Object} component
* Der zu prüfende Artikel
*
* @return {boolean}
* Ob es sich um eine Technologie handelt oder nicht
* - Stimmt, wenn es sich um eine Technologie handelt
* - Falsch, wenn nicht
* /
statisches iTech (Komponente) {
gib component.prototype instanceof Tech zurück ||
Komponenteninstanz von Tech ||
Komponente === Technik;
}
/**
* Registriert einen `Tech` in eine gemeinsame Liste für videojs.
*
* @param {string} name
* Name des `Tech`, der registriert werden soll.
*
* @param {Object} -Technologie
* Die Klasse `Tech`, die registriert werden soll.
* /
statisches RegisterTech (Name, Technologie) {
wenn (! Technik.technik_) {
tech.techs_ = {};
}
wenn (! Tech.iTech (Technik) {
einen neuen Fehler auslösen (`Tech $ {name} muss ein Techniker sein`);
}
wenn (! tech.canPlayType) {
einen neuen Fehler auslösen ('Techniker müssen eine statische CanPlayType-Methode verwenden');
}
wenn (! tech.canplayQuelle) {
einen neuen Fehler auslösen ('Techniker müssen eine statische CanPlaySource-Methode haben. ');
}
name = toTitleCase(name);
tech.techs_ [Name] = Technik;
tech.techs_ [toLowerCase (Name)] = Technik;
wenn (Name! == 'Technik') {
//camel case der TechName zur Verwendung in TechOrder
tech.defaultTechOrder_.push (Name);
}
Technologie zurückgeben;
}
/**
* Holen Sie sich einen `Tech` aus der geteilten Liste mit Namen.
*
* @param {string} name
* `CamelCase` oder `TitleCase` Name des Tech, der abgerufen werden soll
*
* @return {tech|undefiniert}
* Das `Tech` oder undefined, wenn es keinen Techniker mit dem angeforderten Namen gab.
* /
statisches GetTech (Name) {
if (!name) {
rückkehr;
}
wenn (Tech.techs_ && Tech.techs_ [Name]) {
gib tech.techs_ [name] zurück;
}
name = toTitleCase(name);
wenn (Fenster && Fenstervideojs && Fenstervideojs [Name]) {
log.warn (`Die $ {name} -Technologie wurde dem videojs-Objekt hinzugefügt, obwohl es mit videoJS.registerTech (name, tech) registriert werden sollte `);
gib window.videojs [Name] zurück;
}
}
}
/**
* Abrufen der {@link VideoTrackList}
*
* @returns {videoTrackList}
* @method tech.prototype.VideoTracks
* /
/**
* Abrufen der {@link AudioTrackList}
*
* @returns {AudioTrackList}
* @method tech.prototype.AudioTracks
* /
/**
* Abrufen der {@link TextTrackList}
*
* @returns {TextTrackList}
* @method tech.prototype.TextTracks
* /
/**
* Holen Sie sich das Remote-Element {@link textTrackList}
*
* @returns {TextTrackList}
* @method tech.prototype.remoteTextTracks
* /
/**
* Holen Sie sich das Remote-Element {@link htmlTrackElementList}
*
* @returns {htmlTrackElementList}
* @method tech.prototype.remoteTextTrackels
* /
track_types.all.names.forEach (Funktion (Name) {
const props = TRACK_TYPES.ALL[name];
tech.prototype [props.getterName] = Funktion () {
this[props.privateName] = this[props.privateName] || new props.ListClass();
return this[props.privateName];
};
});
/**
* Liste der zugehörigen Texttracks
*
* @type {TextTrackList}
* @privat
* @property Technik #textTracks_
* /
/**
* Liste der zugehörigen Audiotracks.
*
* @type {AudioTrackList}
* @privat
* @property Technik #audioTracks_
* /
/**
* Liste der zugehörigen Videotracks.
*
* @type {videoTrackList}
* @privat
* @property Technik #videoTracks_
* /
/**
* Boolescher Wert, der angibt, ob das "Tech" die Lautstärkeregelung unterstützt.
*
* @Typ {boolean}
* @default
* /
tech.prototype.featuresVolumeControl = wahr;
/**
* Boolescher Wert, der angibt, ob das "Tech" die Stummschaltung der Lautstärke unterstützt.
*
* @Typ {bolean}
* @default
* /
tech.prototype.featuresMuteControl = wahr;
/**
* Boolescher Wert, der angibt, ob `Tech` die Größenänderung im Vollbildmodus unterstützt.
* Das Ändern der Größe von Plugins mithilfe von Request Fullscreen lädt das Plugin neu
*
* @Typ {boolean}
* @default
* /
tech.prototype.featuresFullScreenResize = falsch;
/**
* Boolescher Wert, der angibt, ob der `Tech` das Ändern der Geschwindigkeit unterstützt, mit der das Video aufgenommen wird
* spielt. Beispiele:
* - Player so einstellen, dass er 2x (doppelt) so schnell spielt
* - Player so einstellen, dass er 0,5x (halb) so schnell spielt
*
* @Typ {boolean}
* @default
* /
tech.prototype.featurePlaybackRate = falsch;
/**
* Boolescher Wert, der angibt, ob das `Tech` das `Progress`-Ereignis unterstützt. Dies ist derzeit
* nicht durch video-js-swf ausgelöst. Auf diese Weise wird festgestellt, ob
* {@link Tech #manualProgressOn} sollte aufgerufen werden.
*
* @Typ {boolean}
* @default
* /
tech.prototype.featureProgressEvents = falsch;
/**
* Boolescher Wert, der angibt, ob das "Tech" das Ereignis "Sourceset" unterstützt.
*
* Ein Techniker sollte dies auf `true` setzen und dann {@link Tech #triggerSourceset} verwenden
* um ein {@link Tech #event:sourceset} zum frühestmöglichen Zeitpunkt nach dem Abrufen auszulösen
* eine neue Quelle.
*
* @Typ {boolean}
* @default
* /
tech.prototype.FeatureResourceSet = falsch;
/**
* Boolescher Wert, der angibt, ob `Tech` das `timeupdate`-Ereignis unterstützt. Dies ist derzeit
* nicht durch video-js-swf ausgelöst. Auf diese Weise wird festgestellt, ob
* {@link Tech #manualTimeUpdates} sollte aufgerufen werden.
*
* @Typ {boolean}
* @default
* /
tech.prototype.featurestimeUpdateEvents = falsch;
/**
* Boolescher Wert, der angibt, ob der `Tech` den nativen `TextTrack`s unterstützt.
* Dies hilft uns bei der Integration mit nativen `TextTrack`s, sofern der Browser sie unterstützt.
*
* @Typ {boolean}
* @default
* /
tech.prototype.featuresNativeTextTracks = falsch;
/**
* Boolescher Wert, der angibt, ob der `Tech` `RequestVideoFrameCallback` unterstützt.
*
* @Typ {boolean}
* @default
* /
tech.prototype.featuresVideoFrameCallback = falsch;
/**
* Ein funktionales Mixin für Techniker, die das Source Handler-Pattern verwenden möchten.
* Quellhandler sind Skripte für den Umgang mit bestimmten Formaten.
* Das Quellhandlermuster wird für adaptive Formate (HLS, DASH) verwendet, die
* manuelles Laden von Videodaten und Einspeisen in einen Quellpuffer (Media Source Extensions)
* Beispiel: `tech.withSourceHandlers.Call (myTech); `
*
* @param {Technik} _Technik
* Die Technologie zum Hinzufügen von Quellhandler-Funktionen.
*
* @mixes Tech~SourceHandlerAdditions
* /
tech.withSourceHandlers = Funktion (_Tech) {
/**
* Registrieren Sie einen Quellhandler
*
* @param {Function} -Handler
* Die Source-Handler-Klasse
*
* @param {Zahl} [Index]
* Registriere es im folgenden Index
* /
_tech.registerSourceHandler = Funktion (Handler, Index) {
let-Handler = _tech.SourceHandlers;
if (!handlers) {
Handler = _tech.SourceHandlers = [];
}
if (index === undefiniert) {
//an das Ende der Liste hinzufügen
index = Handlers.length;
}
handlers.splice (Index, 0, Handler);
};
/**
* Prüfen Sie, ob der Techniker den angegebenen Typ unterstützen kann. Überprüft auch die
* Tech SourceHandlers.
*
* @param {string} type
* Der zu prüfende Mimetyp.
*
* @return {string}
* 'wahrscheinlich', 'vielleicht', oder '' (leere Zeichenfolge)
* /
_tech.canPlayType = Funktion (Typ) {
const handlers = _Tech.sourceHandlers || [];
können;
for (let i = 0; i < handlers.length; i++) {
can = Handler [i] .canPlayType (Typ);
wenn (kann) {
zurückgeben können;
}
}
zurückgeben '';
};
/**
* Gibt den ersten Quellhandler zurück, der die Quelle unterstützt.
*
* ALLES: Frage beantworten: sollte „wahrscheinlich“ vor „vielleicht“ priorisiert werden
*
* @param {Tech~SourceObject} source
* Das Quellobjekt
*
* @param {Object} options
* Die an die Technik übergebenen Optionen
*
* @return {sourceHandler|Null}
* Der erste Quellhandler, der die Quelle unterstützt, oder null, wenn
* kein SourceHandler unterstützt die Quelle
* /
_tech.selectSourceHandler = Funktion (Quelle, Optionen) {
const handlers = _Tech.sourceHandlers || [];
können;
for (let i = 0; i < handlers.length; i++) {
can = handlers [i] .canHandleSource (Quelle, Optionen);
wenn (kann) {
Return-Handler [i];
}
}
null zurückgeben;
};
/**
* Prüfen Sie, ob der Techniker die angegebene Quelle unterstützen kann.
*
* @param {Tech~SourceObject} srcObj
* Das Quellobjekt
*
* @param {Object} options
* Die an die Technik übergebenen Optionen
*
* @return {string}
* 'wahrscheinlich', 'vielleicht', oder '' (leere Zeichenfolge)
* /
_tech.canPlaySource = Funktion (srcoBJ, Optionen) {
const sh = _tech.SelectSourceHandler (srcObj, Optionen);
wenn (sh) {
gib sh.canHandleSource zurück (srcObj, Optionen);
}
zurückgeben '';
};
/**
* Wenn Sie einen Quellhandler verwenden, bevorzugen Sie dessen Implementierung von
* jede Funktion, die normalerweise vom Techniker bereitgestellt wird.
* /
const deferrable = [
suchbar',
suchen",
'Dauer'
];
/**
* Ein Wrapper rund um {@link Tech #seekable}, der ein `SourceHandler`s seekable aufruft
* Funktion, falls sie existiert, mit einem Fallback auf die suchbare Funktion von Techs.
*
* @method _tech.Seekable
* /
/**
* Ein Wrapper rund um {@link Tech #duration}, der eine `SourceHandler`s duration aufruft
* funktioniert, falls sie existiert, andernfalls wird auf die Duration-Funktion des Technikers zurückgegriffen.
*
* @method _tech.Dauer
* /
deferrable.forEach (function (fnName) {
const originalFn = dieser [FNName];
if (Typ des Original-FN! == 'Funktion') {
rückkehr;
}
dies [fnName] = Funktion () {
wenn (this.SourceHandler_ && this.SourceHandler_ [fnName]) {
gib this.sourceHandler_ [fnName] .apply (this.SourceHandler_, Argumente) zurück;
}
gib originalFN.apply zurück (dies, Argumente);
};
}, _Tech.prototype);
/**
* Erstellen Sie eine Funktion zum Festlegen der Quelle mithilfe eines Quellobjekts
* und Quellhandler.
* Sollte niemals aufgerufen werden, es sei denn, ein Quellhandler wurde gefunden.
*
* @param {Tech~SourceObject} source
* Ein Quellobjekt mit den Schlüsseln src und type
* /
_tech.prototype.setSource = Funktion (Quelle) {
sei sh = _tech.SelectSourceHandler (source, this.options_);
wenn (! sh) {
//Fallen Sie auf einen nativen Source-Hander zurück, wenn Quellen nicht unterstützt werden
//bewusst gesetzt
wenn (_tech.nativeSourceHandler) {
sh = _Tech.NativeSourceHandler;
} sonst {
log.error ('Kein Quellhandler für die aktuelle Quelle gefunden. ');
}
}
//Lösche jeden existierenden Quell-Handler
this.dispeSourceHandler ();
this.off ('entsorgen', this.dispeSourceHandler_);
wenn (sh! == _Tech.NativeSourceHandler) {
this.currentSource_ = Quelle;
}
this.sourceHandler_ = sh.handleSource (source, this, this.options_);
this.one ('entsorgen', this.disponeSourceHandler_);
};
/**
* Bereinigen Sie alle vorhandenen SourceHandler und Listener, wenn der Tech entsorgt ist.
*
* @listens Technik #dispose
* /
_tech.prototype.dispeSourceHandler = Funktion () {
//wenn wir eine Quelle haben und eine andere bekommen
//dann laden wir etwas Neues
//dann lösche alle unsere aktuellen Tracks
if (this.currentSource_) {
this.clearTracks (['Audio', 'Video']);
this.currentSource_ = null;
}
//Autotext-Tracks immer bereinigen
this.cleanupAutoTextTracks ();
wenn (this.SourceHandler_) {
wenn (this.SourceHandler_.dispose) {
this.sourceHandler_.dispose ();
}
this.sourceHandler_ = null;
}
};
};
//Die Basisklasse Tech muss als Komponente registriert werden. Es ist das einzige
//Technologie, die als Komponente registriert werden kann.
component.registerComponent ('Technik', Technik);
tech.registerTech ('Technik', Technik);
/**
* Eine Liste der Techniker, die zu TechOrder on Players hinzugefügt werden sollten
*
* @privat
* /
tech.defaultTechOrder_ = [];
Standard-Tech exportieren;