update components
This commit is contained in:
parent
2a72f0256e
commit
048ba20590
26 changed files with 1377 additions and 136 deletions
|
@ -60,11 +60,12 @@ class LevelController extends EventHandler {
|
|||
|
||||
// only keep level with supported audio/video codecs
|
||||
levels = levels.filter(function(level) {
|
||||
var checkSupported = function(codec) { return MediaSource.isTypeSupported(`video/mp4;codecs=${codec}`);};
|
||||
var checkSupportedAudio = function(codec) { return MediaSource.isTypeSupported(`audio/mp4;codecs=${codec}`);};
|
||||
var checkSupportedVideo = function(codec) { return MediaSource.isTypeSupported(`video/mp4;codecs=${codec}`);};
|
||||
var audioCodec = level.audioCodec, videoCodec = level.videoCodec;
|
||||
|
||||
return (!audioCodec || checkSupported(audioCodec)) &&
|
||||
(!videoCodec || checkSupported(videoCodec));
|
||||
return (!audioCodec || checkSupportedAudio(audioCodec)) &&
|
||||
(!videoCodec || checkSupportedVideo(videoCodec));
|
||||
});
|
||||
|
||||
if(levels.length) {
|
||||
|
|
|
@ -1076,7 +1076,7 @@ class MSEMediaController extends EventHandler {
|
|||
logger.log(`selected A/V codecs for sourceBuffers:${audioCodec},${videoCodec}`);
|
||||
// create source Buffer and link them to MediaSource
|
||||
if (audioCodec) {
|
||||
sb = this.sourceBuffer.audio = this.mediaSource.addSourceBuffer(`video/mp4;codecs=${audioCodec}`);
|
||||
sb = this.sourceBuffer.audio = this.mediaSource.addSourceBuffer(`audio/mp4;codecs=${audioCodec}`);
|
||||
sb.addEventListener('updateend', this.onsbue);
|
||||
sb.addEventListener('error', this.onsbe);
|
||||
}
|
||||
|
|
69
dashboard-ui/bower_components/hls.js/src/controller/timeline-controller.js
vendored
Normal file
69
dashboard-ui/bower_components/hls.js/src/controller/timeline-controller.js
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Timeline Controller
|
||||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import CEA708Interpreter from '../utils/cea-708-interpreter';
|
||||
|
||||
class TimelineController extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
super(hls, Event.MEDIA_ATTACHING,
|
||||
Event.MEDIA_DETACHING,
|
||||
Event.FRAG_PARSING_USERDATA,
|
||||
Event.MANIFEST_LOADING,
|
||||
Event.FRAG_LOADED);
|
||||
|
||||
this.hls = hls;
|
||||
this.config = hls.config;
|
||||
|
||||
if (this.config.enableCEA708Captions)
|
||||
{
|
||||
this.cea708Interpreter = new CEA708Interpreter();
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onMediaAttaching(data) {
|
||||
var media = this.media = data.media;
|
||||
this.cea708Interpreter.attach(media);
|
||||
}
|
||||
|
||||
onMediaDetaching() {
|
||||
this.cea708Interpreter.detach();
|
||||
}
|
||||
|
||||
onManifestLoading()
|
||||
{
|
||||
this.lastPts = Number.POSITIVE_INFINITY;
|
||||
}
|
||||
|
||||
onFragLoaded(data)
|
||||
{
|
||||
var pts = data.frag.start; //Number.POSITIVE_INFINITY;
|
||||
|
||||
// if this is a frag for a previously loaded timerange, remove all captions
|
||||
// TODO: consider just removing captions for the timerange
|
||||
if (pts <= this.lastPts)
|
||||
{
|
||||
this.cea708Interpreter.clear();
|
||||
}
|
||||
|
||||
this.lastPts = pts;
|
||||
}
|
||||
|
||||
onFragParsingUserdata(data) {
|
||||
// push all of the CEA-708 messages into the interpreter
|
||||
// immediately. It will create the proper timestamps based on our PTS value
|
||||
for (var i=0; i<data.samples.length; i++)
|
||||
{
|
||||
this.cea708Interpreter.push(data.samples[i].pts, data.samples[i].bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default TimelineController;
|
|
@ -72,6 +72,12 @@ var DemuxerWorker = function (self) {
|
|||
var objData = {event: event, samples: data.samples};
|
||||
self.postMessage(objData);
|
||||
});
|
||||
|
||||
observer.on(Event.FRAG_PARSING_USERDATA, function(event, data) {
|
||||
var objData = {event: event, samples: data.samples};
|
||||
self.postMessage(objData);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
export default DemuxerWorker;
|
||||
|
|
|
@ -101,6 +101,11 @@ class Demuxer {
|
|||
samples: ev.data.samples
|
||||
});
|
||||
break;
|
||||
case Event.FRAG_PARSING_USERDATA:
|
||||
this.hls.trigger(Event.FRAG_PARSING_USERDATA, {
|
||||
samples: ev.data.samples
|
||||
});
|
||||
break;
|
||||
default:
|
||||
this.hls.trigger(ev.data.event, ev.data.data);
|
||||
break;
|
||||
|
|
|
@ -125,6 +125,15 @@ class ExpGolomb {
|
|||
return this.readBits(8);
|
||||
}
|
||||
|
||||
// ():int
|
||||
readUShort() {
|
||||
return this.readBits(16);
|
||||
}
|
||||
// ():int
|
||||
readUInt() {
|
||||
return this.readBits(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the ExpGolomb decoder past a scaling list. The scaling
|
||||
* list is optionally transmitted as part of a sequence parameter
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
this.remuxerClass = remuxerClass;
|
||||
this.lastCC = 0;
|
||||
this.remuxer = new this.remuxerClass(observer);
|
||||
this._userData = [];
|
||||
}
|
||||
|
||||
static probe(data) {
|
||||
|
@ -42,6 +43,7 @@
|
|||
this._avcTrack = {type: 'video', id :-1, sequenceNumber: 0, samples : [], len : 0, nbNalu : 0};
|
||||
this._aacTrack = {type: 'audio', id :-1, sequenceNumber: 0, samples : [], len : 0};
|
||||
this._id3Track = {type: 'id3', id :-1, sequenceNumber: 0, samples : [], len : 0};
|
||||
this._txtTrack = {type: 'text', id: -1, sequenceNumber: 0, samples: [], len: 0};
|
||||
this.remuxer.switchLevel();
|
||||
}
|
||||
|
||||
|
@ -81,6 +83,9 @@
|
|||
avcId = this._avcTrack.id,
|
||||
aacId = this._aacTrack.id,
|
||||
id3Id = this._id3Track.id;
|
||||
|
||||
// don't parse last TS packet if incomplete
|
||||
len -= len % 188;
|
||||
// loop through TS packets
|
||||
for (start = 0; start < len; start += 188) {
|
||||
if (data[start] === 0x47) {
|
||||
|
@ -165,7 +170,7 @@
|
|||
}
|
||||
|
||||
remux() {
|
||||
this.remuxer.remux(this._aacTrack,this._avcTrack, this._id3Track, this.timeOffset, this.contiguous);
|
||||
this.remuxer.remux(this._aacTrack, this._avcTrack, this._id3Track, this._txtTrack, this.timeOffset, this.contiguous);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -281,8 +286,10 @@
|
|||
debug = false,
|
||||
key = false,
|
||||
length = 0,
|
||||
expGolombDecoder,
|
||||
avcSample,
|
||||
push;
|
||||
push,
|
||||
i;
|
||||
// no NALu found
|
||||
if (units.length === 0 && samples.length > 0) {
|
||||
// append pes.data to previous NAL unit
|
||||
|
@ -298,6 +305,7 @@
|
|||
//free pes.data to save up some memory
|
||||
pes.data = null;
|
||||
var debugString = '';
|
||||
|
||||
units.forEach(unit => {
|
||||
switch(unit.type) {
|
||||
//NDR
|
||||
|
@ -315,11 +323,67 @@
|
|||
}
|
||||
key = true;
|
||||
break;
|
||||
//SEI
|
||||
case 6:
|
||||
push = true;
|
||||
if(debug) {
|
||||
debugString += 'SEI ';
|
||||
}
|
||||
expGolombDecoder = new ExpGolomb(unit.data);
|
||||
|
||||
// skip frameType
|
||||
expGolombDecoder.readUByte();
|
||||
|
||||
var payloadType = expGolombDecoder.readUByte();
|
||||
|
||||
// TODO: there can be more than one payload in an SEI packet...
|
||||
// TODO: need to read type and size in a while loop to get them all
|
||||
if (payloadType === 4)
|
||||
{
|
||||
var payloadSize = 0;
|
||||
|
||||
do {
|
||||
payloadSize = expGolombDecoder.readUByte();
|
||||
}
|
||||
while (payloadSize === 255);
|
||||
|
||||
var countryCode = expGolombDecoder.readUByte();
|
||||
|
||||
if (countryCode === 181)
|
||||
{
|
||||
var providerCode = expGolombDecoder.readUShort();
|
||||
|
||||
if (providerCode === 49)
|
||||
{
|
||||
var userStructure = expGolombDecoder.readUInt();
|
||||
|
||||
if (userStructure === 0x47413934)
|
||||
{
|
||||
var userDataType = expGolombDecoder.readUByte();
|
||||
|
||||
// Raw CEA-608 bytes wrapped in CEA-708 packet
|
||||
if (userDataType === 3)
|
||||
{
|
||||
var firstByte = expGolombDecoder.readUByte();
|
||||
var secondByte = expGolombDecoder.readUByte();
|
||||
|
||||
var totalCCs = 31 & firstByte;
|
||||
var byteArray = [firstByte, secondByte];
|
||||
|
||||
for (i=0; i<totalCCs; i++)
|
||||
{
|
||||
// 3 bytes per CC
|
||||
byteArray.push(expGolombDecoder.readUByte());
|
||||
byteArray.push(expGolombDecoder.readUByte());
|
||||
byteArray.push(expGolombDecoder.readUByte());
|
||||
}
|
||||
|
||||
this._txtTrack.samples.push({type: 3, pts: pes.pts, bytes: byteArray});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
//SPS
|
||||
case 7:
|
||||
|
@ -328,7 +392,7 @@
|
|||
debugString += 'SPS ';
|
||||
}
|
||||
if(!track.sps) {
|
||||
var expGolombDecoder = new ExpGolomb(unit.data);
|
||||
expGolombDecoder = new ExpGolomb(unit.data);
|
||||
var config = expGolombDecoder.readSPS();
|
||||
track.width = config.width;
|
||||
track.height = config.height;
|
||||
|
@ -337,7 +401,7 @@
|
|||
track.duration = this.remuxer.timescale * this._duration;
|
||||
var codecarray = unit.data.subarray(1, 4);
|
||||
var codecstring = 'avc1.';
|
||||
for (var i = 0; i < 3; i++) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
var h = codecarray[i].toString(16);
|
||||
if (h.length < 2) {
|
||||
h = '0' + h;
|
||||
|
@ -358,7 +422,7 @@
|
|||
}
|
||||
break;
|
||||
case 9:
|
||||
push = true;
|
||||
push = false;
|
||||
if(debug) {
|
||||
debugString += 'AUD ';
|
||||
}
|
||||
|
@ -443,10 +507,6 @@
|
|||
}
|
||||
lastUnitStart = i;
|
||||
lastUnitType = unitType;
|
||||
if (unitType === 1 || unitType === 5) {
|
||||
// OPTI !!! if IDR/NDR unit, consider it is last NALu
|
||||
i = len;
|
||||
}
|
||||
state = 0;
|
||||
} else {
|
||||
state = 0;
|
||||
|
|
|
@ -33,6 +33,8 @@ module.exports = {
|
|||
FRAG_LOADED: 'hlsFragLoaded',
|
||||
// fired when Init Segment has been extracted from fragment - data: { moov : moov MP4 box, codecs : codecs found while parsing fragment}
|
||||
FRAG_PARSING_INIT_SEGMENT: 'hlsFragParsingInitSegment',
|
||||
// fired when parsing sei text is completed - data: { samples : [ sei samples pes ] }
|
||||
FRAG_PARSING_USERDATA: 'hlsFragParsingUserdata',
|
||||
// fired when parsing id3 is completed - data: { samples : [ id3 samples pes ] }
|
||||
FRAG_PARSING_METADATA: 'hlsFragParsingMetadata',
|
||||
// fired when moof/mdat have been extracted from fragment - data: { moof : moof MP4 box, mdat : mdat MP4 box}
|
||||
|
|
|
@ -10,6 +10,7 @@ import FragmentLoader from './loader/fragment-loader';
|
|||
import AbrController from './controller/abr-controller';
|
||||
import MSEMediaController from './controller/mse-media-controller';
|
||||
import LevelController from './controller/level-controller';
|
||||
import TimelineController from './controller/timeline-controller';
|
||||
//import FPSController from './controller/fps-controller';
|
||||
import {logger, enableLogs} from './utils/logger';
|
||||
import XhrLoader from './utils/xhr-loader';
|
||||
|
@ -65,7 +66,9 @@ class Hls {
|
|||
fLoader: undefined,
|
||||
pLoader: undefined,
|
||||
abrController : AbrController,
|
||||
mediaController: MSEMediaController
|
||||
mediaController: MSEMediaController,
|
||||
timelineController: TimelineController,
|
||||
enableCEA708Captions: true
|
||||
};
|
||||
}
|
||||
return Hls.defaultConfig;
|
||||
|
@ -105,6 +108,7 @@ class Hls {
|
|||
this.levelController = new LevelController(this);
|
||||
this.abrController = new config.abrController(this);
|
||||
this.mediaController = new config.mediaController(this);
|
||||
this.timelineController = new config.timelineController(this);
|
||||
this.keyLoader = new KeyLoader(this);
|
||||
//this.fpsController = new FPSController(this);
|
||||
}
|
||||
|
@ -117,6 +121,7 @@ class Hls {
|
|||
this.fragmentLoader.destroy();
|
||||
this.levelController.destroy();
|
||||
this.mediaController.destroy();
|
||||
this.timelineController.destroy();
|
||||
this.keyLoader.destroy();
|
||||
//this.fpsController.destroy();
|
||||
this.url = null;
|
||||
|
|
|
@ -18,10 +18,11 @@ class DummyRemuxer {
|
|||
insertDiscontinuity() {
|
||||
}
|
||||
|
||||
remux(audioTrack,videoTrack,id3Track,timeOffset) {
|
||||
remux(audioTrack,videoTrack,id3Track,textTrack,timeOffset) {
|
||||
this._remuxAACSamples(audioTrack,timeOffset);
|
||||
this._remuxAVCSamples(videoTrack,timeOffset);
|
||||
this._remuxID3Samples(id3Track,timeOffset);
|
||||
this._remuxTextSamples(textTrack,timeOffset);
|
||||
}
|
||||
|
||||
_remuxAVCSamples(track, timeOffset) {
|
||||
|
@ -59,6 +60,17 @@ class DummyRemuxer {
|
|||
//please lint
|
||||
timeOffset = timeOffset;
|
||||
}
|
||||
|
||||
_remuxTextSamples(track,timeOffset) {
|
||||
var textSample,bytes;
|
||||
// loop through track.samples
|
||||
while (track.samples.length) {
|
||||
textSample = track.samples.shift();
|
||||
bytes = textSample.bytes;
|
||||
}
|
||||
//please lint
|
||||
timeOffset = timeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
export default DummyRemuxer;
|
||||
|
|
|
@ -355,16 +355,16 @@ class MP4 {
|
|||
0x00, 0x48, 0x00, 0x00, // vertresolution
|
||||
0x00, 0x00, 0x00, 0x00, // reserved
|
||||
0x00, 0x01, // frame_count
|
||||
0x13,
|
||||
0x76, 0x69, 0x64, 0x65,
|
||||
0x6f, 0x6a, 0x73, 0x2d,
|
||||
0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x69, 0x62, 0x2d,
|
||||
0x68, 0x6c, 0x73, 0x00,
|
||||
0x12,
|
||||
0x64, 0x61, 0x69, 0x6C, //dailymotion/hls.js
|
||||
0x79, 0x6D, 0x6F, 0x74,
|
||||
0x69, 0x6F, 0x6E, 0x2F,
|
||||
0x68, 0x6C, 0x73, 0x2E,
|
||||
0x6A, 0x73, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, // compressorname
|
||||
0x00, 0x18, // depth = 24
|
||||
0x00, 0x18, // depth = 24
|
||||
0x11, 0x11]), // pre_defined = -1
|
||||
avcc,
|
||||
MP4.box(MP4.types.btrt, new Uint8Array([
|
||||
|
|
|
@ -32,7 +32,7 @@ class MP4Remuxer {
|
|||
this.ISGenerated = false;
|
||||
}
|
||||
|
||||
remux(audioTrack,videoTrack,id3Track,timeOffset, contiguous) {
|
||||
remux(audioTrack,videoTrack,id3Track,textTrack,timeOffset, contiguous) {
|
||||
// generate Init Segment if needed
|
||||
if (!this.ISGenerated) {
|
||||
this.generateIS(audioTrack,videoTrack,timeOffset);
|
||||
|
@ -49,6 +49,10 @@ class MP4Remuxer {
|
|||
if (id3Track.samples.length) {
|
||||
this.remuxID3(id3Track,timeOffset);
|
||||
}
|
||||
//logger.log('nb ID3 samples:' + audioTrack.samples.length);
|
||||
if (textTrack.samples.length) {
|
||||
this.remuxText(textTrack,timeOffset);
|
||||
}
|
||||
//notify end of parsing
|
||||
this.observer.trigger(Event.FRAG_PARSED);
|
||||
}
|
||||
|
@ -264,6 +268,7 @@ class MP4Remuxer {
|
|||
pts = aacSample.pts;
|
||||
} else {
|
||||
logger.warn('dropping past audio frame');
|
||||
track.len -= aacSample.unit.byteLength;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -309,12 +314,17 @@ class MP4Remuxer {
|
|||
// remember first PTS of our aacSamples, ensure value is positive
|
||||
firstPTS = Math.max(0, ptsnorm);
|
||||
firstDTS = Math.max(0, dtsnorm);
|
||||
/* concatenate the audio data and construct the mdat in place
|
||||
(need 8 more bytes to fill length and mdat type) */
|
||||
mdat = new Uint8Array(track.len + 8);
|
||||
view = new DataView(mdat.buffer);
|
||||
view.setUint32(0, mdat.byteLength);
|
||||
mdat.set(MP4.types.mdat, 4);
|
||||
if(track.len > 0) {
|
||||
/* concatenate the audio data and construct the mdat in place
|
||||
(need 8 more bytes to fill length and mdat type) */
|
||||
mdat = new Uint8Array(track.len + 8);
|
||||
view = new DataView(mdat.buffer);
|
||||
view.setUint32(0, mdat.byteLength);
|
||||
mdat.set(MP4.types.mdat, 4);
|
||||
} else {
|
||||
// no audio samples
|
||||
return;
|
||||
}
|
||||
}
|
||||
mdat.set(unit, offset);
|
||||
offset += unit.byteLength;
|
||||
|
@ -382,6 +392,29 @@ class MP4Remuxer {
|
|||
timeOffset = timeOffset;
|
||||
}
|
||||
|
||||
remuxText(track,timeOffset) {
|
||||
track.samples.sort(function(a, b) {
|
||||
return (a.pts-b.pts);
|
||||
});
|
||||
|
||||
var length = track.samples.length, sample;
|
||||
// consume samples
|
||||
if(length) {
|
||||
for(var index = 0; index < length; index++) {
|
||||
sample = track.samples[index];
|
||||
// setting text pts, dts to relative time
|
||||
// using this._initPTS and this._initDTS to calculate relative time
|
||||
sample.pts = ((sample.pts - this._initPTS) / this.PES_TIMESCALE);
|
||||
}
|
||||
this.observer.trigger(Event.FRAG_PARSING_USERDATA, {
|
||||
samples:track.samples
|
||||
});
|
||||
}
|
||||
|
||||
track.samples = [];
|
||||
timeOffset = timeOffset;
|
||||
}
|
||||
|
||||
_PTSNormalize(value, reference) {
|
||||
var offset;
|
||||
if (reference === undefined) {
|
||||
|
|
380
dashboard-ui/bower_components/hls.js/src/utils/cea-708-interpreter.js
vendored
Normal file
380
dashboard-ui/bower_components/hls.js/src/utils/cea-708-interpreter.js
vendored
Normal file
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* CEA-708 interpreter
|
||||
*/
|
||||
|
||||
class CEA708Interpreter {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
attach(media) {
|
||||
this.media = media;
|
||||
this.display = [];
|
||||
this.memory = [];
|
||||
}
|
||||
|
||||
detach()
|
||||
{
|
||||
this.clear();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
}
|
||||
|
||||
_createCue()
|
||||
{
|
||||
var VTTCue = window.VTTCue || window.TextTrackCue;
|
||||
|
||||
this.cue = new VTTCue(-1, -1, '');
|
||||
this.cue.text = '';
|
||||
this.cue.pauseOnExit = false;
|
||||
|
||||
// make sure it doesn't show up before it's ready
|
||||
this.startTime = Number.MAX_VALUE;
|
||||
|
||||
// show it 'forever' once we do show it
|
||||
// (we'll set the end time once we know it later)
|
||||
this.cue.endTime = Number.MAX_VALUE;
|
||||
|
||||
this.memory.push(this.cue);
|
||||
}
|
||||
|
||||
clear()
|
||||
{
|
||||
if (this._textTrack && this._textTrack.cues)
|
||||
{
|
||||
while (this._textTrack.cues.length > 0)
|
||||
{
|
||||
this._textTrack.removeCue(this._textTrack.cues[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
push(timestamp, bytes)
|
||||
{
|
||||
if (!this.cue)
|
||||
{
|
||||
this._createCue();
|
||||
}
|
||||
|
||||
var count = bytes[0] & 31;
|
||||
var position = 2;
|
||||
var byte, ccbyte1, ccbyte2, ccValid, ccType;
|
||||
|
||||
for (var j=0; j<count; j++)
|
||||
{
|
||||
byte = bytes[position++];
|
||||
ccbyte1 = 0x7F & bytes[position++];
|
||||
ccbyte2 = 0x7F & bytes[position++];
|
||||
ccValid = ((4 & byte) === 0 ? false : true);
|
||||
ccType = (3 & byte);
|
||||
|
||||
if (ccbyte1 === 0 && ccbyte2 === 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ccValid)
|
||||
{
|
||||
if (ccType === 0) // || ccType === 1
|
||||
{
|
||||
// Standard Characters
|
||||
if (0x20 & ccbyte1 || 0x40 & ccbyte1)
|
||||
{
|
||||
this.cue.text += this._fromCharCode(ccbyte1) + this._fromCharCode(ccbyte2);
|
||||
}
|
||||
// Special Characters
|
||||
else if ((ccbyte1 === 0x11 || ccbyte1 === 0x19) && ccbyte2 >= 0x30 && ccbyte2 <= 0x3F)
|
||||
{
|
||||
// extended chars, e.g. musical note, accents
|
||||
switch (ccbyte2)
|
||||
{
|
||||
case 48:
|
||||
this.cue.text += '®';
|
||||
break;
|
||||
case 49:
|
||||
this.cue.text += '°';
|
||||
break;
|
||||
case 50:
|
||||
this.cue.text += '½';
|
||||
break;
|
||||
case 51:
|
||||
this.cue.text += '¿';
|
||||
break;
|
||||
case 52:
|
||||
this.cue.text += '™';
|
||||
break;
|
||||
case 53:
|
||||
this.cue.text += '¢';
|
||||
break;
|
||||
case 54:
|
||||
this.cue.text += '';
|
||||
break;
|
||||
case 55:
|
||||
this.cue.text += '£';
|
||||
break;
|
||||
case 56:
|
||||
this.cue.text += '♪';
|
||||
break;
|
||||
case 57:
|
||||
this.cue.text += ' ';
|
||||
break;
|
||||
case 58:
|
||||
this.cue.text += 'è';
|
||||
break;
|
||||
case 59:
|
||||
this.cue.text += 'â';
|
||||
break;
|
||||
case 60:
|
||||
this.cue.text += 'ê';
|
||||
break;
|
||||
case 61:
|
||||
this.cue.text += 'î';
|
||||
break;
|
||||
case 62:
|
||||
this.cue.text += 'ô';
|
||||
break;
|
||||
case 63:
|
||||
this.cue.text += 'û';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((ccbyte1 === 0x11 || ccbyte1 === 0x19) && ccbyte2 >= 0x20 && ccbyte2 <= 0x2F)
|
||||
{
|
||||
// Mid-row codes: color/underline
|
||||
switch (ccbyte2)
|
||||
{
|
||||
case 0x20:
|
||||
// White
|
||||
break;
|
||||
case 0x21:
|
||||
// White Underline
|
||||
break;
|
||||
case 0x22:
|
||||
// Green
|
||||
break;
|
||||
case 0x23:
|
||||
// Green Underline
|
||||
break;
|
||||
case 0x24:
|
||||
// Blue
|
||||
break;
|
||||
case 0x25:
|
||||
// Blue Underline
|
||||
break;
|
||||
case 0x26:
|
||||
// Cyan
|
||||
break;
|
||||
case 0x27:
|
||||
// Cyan Underline
|
||||
break;
|
||||
case 0x28:
|
||||
// Red
|
||||
break;
|
||||
case 0x29:
|
||||
// Red Underline
|
||||
break;
|
||||
case 0x2A:
|
||||
// Yellow
|
||||
break;
|
||||
case 0x2B:
|
||||
// Yellow Underline
|
||||
break;
|
||||
case 0x2C:
|
||||
// Magenta
|
||||
break;
|
||||
case 0x2D:
|
||||
// Magenta Underline
|
||||
break;
|
||||
case 0x2E:
|
||||
// Italics
|
||||
break;
|
||||
case 0x2F:
|
||||
// Italics Underline
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((ccbyte1 === 0x14 || ccbyte1 === 0x1C) && ccbyte2 >= 0x20 && ccbyte2 <= 0x2F)
|
||||
{
|
||||
// Mid-row codes: color/underline
|
||||
switch (ccbyte2)
|
||||
{
|
||||
case 0x20:
|
||||
// TODO: shouldn't affect roll-ups...
|
||||
this._clearActiveCues(timestamp);
|
||||
// RCL: Resume Caption Loading
|
||||
// begin pop on
|
||||
break;
|
||||
case 0x21:
|
||||
// BS: Backspace
|
||||
this.cue.text = this.cue.text.substr(0, this.cue.text.length-1);
|
||||
break;
|
||||
case 0x22:
|
||||
// AOF: reserved (formerly alarm off)
|
||||
break;
|
||||
case 0x23:
|
||||
// AON: reserved (formerly alarm on)
|
||||
break;
|
||||
case 0x24:
|
||||
// DER: Delete to end of row
|
||||
break;
|
||||
case 0x25:
|
||||
// RU2: roll-up 2 rows
|
||||
//this._rollup(2);
|
||||
break;
|
||||
case 0x26:
|
||||
// RU3: roll-up 3 rows
|
||||
//this._rollup(3);
|
||||
break;
|
||||
case 0x27:
|
||||
// RU4: roll-up 4 rows
|
||||
//this._rollup(4);
|
||||
break;
|
||||
case 0x28:
|
||||
// FON: Flash on
|
||||
break;
|
||||
case 0x29:
|
||||
// RDC: Resume direct captioning
|
||||
this._clearActiveCues(timestamp);
|
||||
break;
|
||||
case 0x2A:
|
||||
// TR: Text Restart
|
||||
break;
|
||||
case 0x2B:
|
||||
// RTD: Resume Text Display
|
||||
break;
|
||||
case 0x2C:
|
||||
// EDM: Erase Displayed Memory
|
||||
this._clearActiveCues(timestamp);
|
||||
break;
|
||||
case 0x2D:
|
||||
// CR: Carriage Return
|
||||
// only affects roll-up
|
||||
//this._rollup(1);
|
||||
break;
|
||||
case 0x2E:
|
||||
// ENM: Erase non-displayed memory
|
||||
this._text = '';
|
||||
break;
|
||||
case 0x2F:
|
||||
this._flipMemory(timestamp);
|
||||
// EOC: End of caption
|
||||
// hide any displayed captions and show any hidden one
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((ccbyte1 === 0x17 || ccbyte1 === 0x1F) && ccbyte2 >= 0x21 && ccbyte2 <= 0x23)
|
||||
{
|
||||
// Mid-row codes: color/underline
|
||||
switch (ccbyte2)
|
||||
{
|
||||
case 0x21:
|
||||
// TO1: tab offset 1 column
|
||||
break;
|
||||
case 0x22:
|
||||
// TO1: tab offset 2 column
|
||||
break;
|
||||
case 0x23:
|
||||
// TO1: tab offset 3 column
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Probably a pre-amble address code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_fromCharCode(byte)
|
||||
{
|
||||
switch (byte)
|
||||
{
|
||||
case 42:
|
||||
return 'á';
|
||||
|
||||
case 2:
|
||||
return 'á';
|
||||
|
||||
case 2:
|
||||
return 'é';
|
||||
|
||||
case 4:
|
||||
return 'í';
|
||||
|
||||
case 5:
|
||||
return 'ó';
|
||||
|
||||
case 6:
|
||||
return 'ú';
|
||||
|
||||
case 3:
|
||||
return 'ç';
|
||||
|
||||
case 4:
|
||||
return '÷';
|
||||
|
||||
case 5:
|
||||
return 'Ñ';
|
||||
|
||||
case 6:
|
||||
return 'ñ';
|
||||
|
||||
case 7:
|
||||
return '█';
|
||||
|
||||
default:
|
||||
return String.fromCharCode(byte);
|
||||
}
|
||||
}
|
||||
|
||||
_flipMemory(timestamp)
|
||||
{
|
||||
this._clearActiveCues(timestamp);
|
||||
this._flushCaptions(timestamp);
|
||||
}
|
||||
|
||||
_flushCaptions(timestamp)
|
||||
{
|
||||
if (!this._has708)
|
||||
{
|
||||
this._textTrack = this.media.addTextTrack('captions', 'English', 'en');
|
||||
this._has708 = true;
|
||||
}
|
||||
|
||||
for (var i=0; i<this.memory.length; i++)
|
||||
{
|
||||
this.memory[i].startTime = timestamp;
|
||||
this._textTrack.addCue(this.memory[i]);
|
||||
this.display.push(this.memory[i]);
|
||||
}
|
||||
|
||||
this.memory = [];
|
||||
this.cue = null;
|
||||
}
|
||||
|
||||
_clearActiveCues(timestamp)
|
||||
{
|
||||
for (var i=0; i<this.display.length; i++)
|
||||
{
|
||||
this.display[i].endTime = timestamp;
|
||||
}
|
||||
|
||||
this.display = [];
|
||||
}
|
||||
|
||||
/* _rollUp(n)
|
||||
{
|
||||
// TODO: implement roll-up captions
|
||||
}
|
||||
*/
|
||||
_clearBufferedCues()
|
||||
{
|
||||
//remove them all...
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CEA708Interpreter;
|
||||
|
|
@ -46,8 +46,7 @@ var URLHelper = {
|
|||
builtURL = baseURLDomain+URLHelper.buildAbsolutePath('', relativeURL.substring(1));
|
||||
}
|
||||
else {
|
||||
var newPath = URLHelper.buildAbsolutePath(baseURLPath, relativeURL);
|
||||
builtURL = baseURLDomain + newPath;
|
||||
builtURL = URLHelper.buildAbsolutePath(baseURLDomain+baseURLPath, relativeURL);
|
||||
}
|
||||
|
||||
// put the query and hash parts back
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue