/** * @file add-text-track-data.js */ import window from 'global/window'; import videojs from 'video.js'; /** * Define properties on a cue for backwards compatability, * but warn the user that the way that they are using it * is depricated and will be removed at a later date. * * @param {Cue} cue the cue to add the properties on * @private */ const deprecateOldCue = function(cue) { Object.defineProperties(cue.frame, { id: { get() { videojs.log.warn( 'cue.frame.id is deprecated. Use cue.value.key instead.' ); return cue.value.key; } }, value: { get() { videojs.log.warn( 'cue.frame.value is deprecated. Use cue.value.data instead.' ); return cue.value.data; } }, privateData: { get() { videojs.log.warn( 'cue.frame.privateData is deprecated. Use cue.value.data instead.' ); return cue.value.data; } } }); }; const durationOfVideo = function(duration) { let dur; if (isNaN(duration) || Math.abs(duration) === Infinity) { dur = Number.MAX_VALUE; } else { dur = duration; } return dur; }; /** * Add text track data to a source handler given the captions and * metadata from the buffer. * * @param {Object} sourceHandler the flash or virtual source buffer * @param {Array} captionArray an array of caption data * @param {Array} metadataArray an array of meta data * @private */ const addTextTrackData = function(sourceHandler, captionArray, metadataArray) { let Cue = window.WebKitDataCue || window.VTTCue; if (captionArray) { captionArray.forEach(function(caption) { let track = caption.stream; this.inbandTextTracks_[track].addCue( new Cue( caption.startTime + this.timestampOffset, caption.endTime + this.timestampOffset, caption.text )); }, sourceHandler); } if (metadataArray) { let videoDuration = durationOfVideo(sourceHandler.mediaSource_.duration); metadataArray.forEach(function(metadata) { let time = metadata.cueTime + this.timestampOffset; metadata.frames.forEach(function(frame) { let cue = new Cue( time, time, frame.value || frame.url || frame.data || ''); cue.frame = frame; cue.value = frame; deprecateOldCue(cue); this.metadataTrack_.addCue(cue); }, this); }, sourceHandler); // Updating the metadeta cues so that // the endTime of each cue is the startTime of the next cue // the endTime of last cue is the duration of the video if (sourceHandler.metadataTrack_ && sourceHandler.metadataTrack_.cues && sourceHandler.metadataTrack_.cues.length) { let cues = sourceHandler.metadataTrack_.cues; let cuesArray = []; // Create a copy of the TextTrackCueList... // ...disregarding cues with a falsey value for (let i = 0; i < cues.length; i++) { if (cues[i]) { cuesArray.push(cues[i]); } } // Group cues by their startTime value let cuesGroupedByStartTime = cuesArray.reduce((obj, cue) => { let timeSlot = obj[cue.startTime] || []; timeSlot.push(cue); obj[cue.startTime] = timeSlot; return obj; }, {}); // Sort startTimes by ascending order let sortedStartTimes = Object.keys(cuesGroupedByStartTime) .sort((a, b) => Number(a) - Number(b)); // Map each cue group's endTime to the next group's startTime sortedStartTimes.forEach((startTime, idx) => { let cueGroup = cuesGroupedByStartTime[startTime]; let nextTime = Number(sortedStartTimes[idx + 1]) || videoDuration; // Map each cue's endTime the next group's startTime cueGroup.forEach((cue) => { cue.endTime = nextTime; }); }); } } }; export default { addTextTrackData, durationOfVideo };