Skip to content

Commit

Permalink
VTTCue creation is decoupled from timeline manager, cc2 support
Browse files Browse the repository at this point in the history
  • Loading branch information
jlacivita authored and mangui committed May 10, 2016
1 parent 3ddaa4c commit 20907f0
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 47 deletions.
100 changes: 53 additions & 47 deletions src/controller/timeline-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import Event from '../events';
import EventHandler from '../event-handler';
import Cea608Parser from '../utils/cea-608-parser';
import Cues from '../utils/cues';

class TimelineController extends EventHandler {

Expand All @@ -13,74 +14,63 @@ class TimelineController extends EventHandler {
Event.MEDIA_DETACHING,
Event.FRAG_PARSING_USERDATA,
Event.MANIFEST_LOADING,
Event.FRAG_LOADED);
Event.FRAG_LOADED,
Event.LEVEL_SWITCH);

this.hls = hls;
this.config = hls.config;
this.enabled = true;

if (this.config.enableCEA708Captions)
{
this.cea608Parser = new Cea608Parser(0, {'newCue': this.newCue.bind(this)}, null);
}
}

newCue(startTime, endTime, captionScreen) {
var row;
var cue;
var indenting;
var indent;
var text;
var VTTCue = window.VTTCue || window.TextTrackCue;

this.createTextTrack();

for (var r=0; r<captionScreen.rows.length; r++)
{
row = captionScreen.rows[r];
indenting = true;
indent = 0;
text = '';
var self = this;

if (!row.isEmpty())
var channel1 =
{
for (var c=0; c<row.chars.length; c++)
'newCue': function(startTime, endTime, screen)
{
if (row.chars[c].uchar.match(/\s/) && indenting)
if (!self.textTrack1)
{
indent++;
self.textTrack1 = self.createTextTrack('captions', 'Unknown CC1', 'en');
// self.textTrack1.mode = 'showing';
}
else

Cues.newCue(self.textTrack1, startTime, endTime, screen);
}
};

var channel2 =
{
'newCue': function(startTime, endTime, screen)
{
if (!self.textTrack2)
{
text += row.chars[c].uchar;
indenting = false;
self.textTrack2 = self.createTextTrack('captions', 'Unknown CC2', 'es');
}
}
cue = new VTTCue(startTime, endTime, text.trim());
cue.line = r;
cue.align = 'left';
cue.position = 100 * (indent / 32) + (navigator.userAgent.match(/Firefox\//) ? 50 : 0);
this.textTrack.addCue(cue);
}

Cues.newCue(self.textTrack2, startTime, endTime, screen); }
};

this.cea608Parser = new Cea608Parser(0, channel1, channel2);
}
}

clearCurrentCues()
clearCurrentCues(track)
{
if (this.textTrack)
if (track && track.cues)
{
while (this.textTrack.cues.length > 0)
while (track.cues.length > 0)
{
this.textTrack.removeCue(this.textTrack.cues[0]);
track.removeCue(track.cues[0]);
}
}
}

createTextTrack()
createTextTrack(kind, label, lang)
{
if (this.media && !this.textTrack)
if (this.media)
{
this.textTrack = this.media.addTextTrack('captions', 'English', 'en');
this.textTrack.mode = 'showing';
return this.media.addTextTrack(kind, label, lang);
}
}

Expand All @@ -100,6 +90,18 @@ class TimelineController extends EventHandler {
this.lastPts = Number.NEGATIVE_INFINITY;
}

onLevelSwitch()
{
if (this.hls.currentLevel.closedCaptions === 'NONE')
{
this.enabled = false;
}
else
{
this.enabled = true;
}
}

onFragLoaded(data)
{
var pts = data.frag.start;
Expand All @@ -108,7 +110,8 @@ class TimelineController extends EventHandler {
// TODO: consider just removing captions for the timerange
if (pts <= this.lastPts)
{
this.clearCurrentCues();
this.clearCurrentCues(this.textTrack1);
this.clearCurrentCues(this.textTrack2);
}

this.lastPts = pts;
Expand All @@ -117,10 +120,13 @@ class TimelineController extends EventHandler {
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++)
if (this.enabled)
{
var ccdatas = this.extractCea608Data(data.samples[i].bytes);
this.cea608Parser.addData(data.samples[i].pts, ccdatas);
for (var i=0; i<data.samples.length; i++)
{
var ccdatas = this.extractCea608Data(data.samples[i].bytes);
this.cea608Parser.addData(data.samples[i].pts, ccdatas);
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/hls.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {logger, enableLogs} from './utils/logger';
import XhrLoader from './utils/xhr-loader';
import EventEmitter from 'events';
import KeyLoader from './loader/key-loader';
import Cues from './utils/cues';

class Hls {

Expand Down Expand Up @@ -86,6 +87,7 @@ class Hls {
fpsController: FPSController,
streamController: StreamController,
timelineController: TimelineController,
cueHandler: Cues,
enableCEA708Captions: true,
enableMP2TPassThrough : false
};
Expand Down
6 changes: 6 additions & 0 deletions src/loader/playlist-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ class PlaylistLoader extends EventHandler {
level.bitrate = attrs.decimalInteger('AVERAGE-BANDWIDTH') || attrs.decimalInteger('BANDWIDTH');
level.name = attrs.NAME;

var closedCaptions = attrs.enumeratedString('CLOSED-CAPTIONS');

if (closedCaptions) {
level.closedCaptions = closedCaptions;
}

var codecs = attrs.CODECS;
if(codecs) {
codecs = codecs.split(',');
Expand Down
1 change: 1 addition & 0 deletions src/utils/cea-608-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*
* This code was ported from the dash.js project at:
* https://github.com/Dash-Industry-Forum/dash.js/blob/development/externals/cea608-parser.js
* https://github.com/Dash-Industry-Forum/dash.js/commit/8269b26a761e0853bb21d78780ed945144ecdd4d#diff-71bc295a2d6b6b7093a1d3290d53a4b2
*
* The original copyright appears below:
*
Expand Down
62 changes: 62 additions & 0 deletions src/utils/cues.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
var Cues = {

newCue: function(track, startTime, endTime, captionScreen) {
var row;
var cue;
var indenting;
var indent;
var text;
var VTTCue = window.VTTCue || window.TextTrackCue;

for (var r=0; r<captionScreen.rows.length; r++)
{
row = captionScreen.rows[r];
indenting = true;
indent = 0;
text = '';

if (!row.isEmpty())
{
for (var c=0; c<row.chars.length; c++)
{
if (row.chars[c].uchar.match(/\s/) && indenting)
{
indent++;
}
else
{
text += row.chars[c].uchar;
indenting = false;
}
}
cue = new VTTCue(startTime, endTime, text.trim());

if (indent >= 16)
{
indent--;
}
else
{
indent++;
}

// VTTCue.line get's flakey when using controls, so let's now include line 13&14
// also, drop line 1 since it's to close to the top
if (navigator.userAgent.match(/Firefox\//))
{
cue.line = r + 1;
}
else
{
cue.line = (r > 7 ? r - 2 : r + 1);
}
cue.align = 'left';
cue.position = 100 * (indent / 32) + (navigator.userAgent.match(/Firefox\//) ? 50 : 0);
track.addCue(cue);
}
}
}

};

module.exports = Cues;

0 comments on commit 20907f0

Please sign in to comment.