Skip to content

Commit

Permalink
EXT-X-START tag support (#31)
Browse files Browse the repository at this point in the history
* add support for EXT-X-START tags

* warns about improper START tags
  • Loading branch information
masterful authored and gesinger committed Nov 20, 2017
1 parent 98b9aa5 commit 31b6d0b
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## HEAD

* added ability to parse EXT-X-START tags

<a name="3.0.0"></a>
# 3.0.0 (2017-06-09)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Manifest {
* [EXT-X-DISCONTINUITY-SEQUENCE](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.3)
* [EXT-X-ENDLIST](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.4)
* [EXT-X-PLAYLIST-TYPE](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.5)
* [EXT-X-START](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.5.2)

### Master Playlist Tags

Expand Down Expand Up @@ -235,7 +236,6 @@ Example media playlist using `EXT-X-CUE-` tags.
* [EXT-X-SESSION-DATA](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.4)
* [EXT-X-SESSION-KEY](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.5)
* [EXT-X-INDEPENDENT-SEGMENTS](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.5.1)
* [EXT-X-START](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.5.2)

## Including the Parser

Expand Down
15 changes: 15 additions & 0 deletions src/parse-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,21 @@ export default class ParseStream extends Stream {
this.trigger('data', event);
return;
}
match = (/^#EXT-X-START:?(.*)$/).exec(line);
if (match) {
event = {
type: 'tag',
tagType: 'start'
};
if (match[1]) {
event.attributes = parseAttributes(match[1]);

event.attributes['TIME-OFFSET'] = parseFloat(event.attributes['TIME-OFFSET']);
event.attributes.PRECISE = (/YES/).test(event.attributes.PRECISE);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-CUE-OUT-CONT:?(.*)?$/).exec(line);
if (match) {
event = {
Expand Down
12 changes: 12 additions & 0 deletions src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,18 @@ export default class Parser extends Stream {
}
this.manifest.totalDuration = entry.duration;
},
start() {
if (!entry.attributes || isNaN(entry.attributes['TIME-OFFSET'])) {
this.trigger('warn', {
message: 'ignoring start declaration without appropriate attribute list'
});
return;
}
this.manifest.start = {
timeOffset: entry.attributes['TIME-OFFSET'],
precise: entry.attributes.PRECISE
};
},
'cue-out'() {
currentUri.cueOut = entry.data;
},
Expand Down
35 changes: 35 additions & 0 deletions test/fixtures/m3u8/start.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"allowCache": true,
"mediaSequence": 0,
"playlistType": "VOD",
"segments": [
{
"duration": 10,
"timeline": 0,
"uri": "media-00001.ts"
},
{
"duration": 10,
"timeline": 0,
"uri": "media-00002.ts"
},
{
"duration": 10,
"timeline": 0,
"uri": "media-00003.ts"
},
{
"duration": 10,
"timeline": 0,
"uri": "media-00004.ts"
}
],
"targetDuration": 10,
"endList": true,
"discontinuitySequence": 0,
"discontinuityStarts": [],
"start": {
"timeOffset": 10.3,
"precise": false
}
}
13 changes: 13 additions & 0 deletions test/fixtures/m3u8/start.m3u8
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#EXT-X-VERSION:3
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXT-X-START:TIME-OFFSET=10.3
#EXTINF:10,
media-00001.ts
#EXTINF:10,
media-00002.ts
#EXTINF:10,
media-00003.ts
#EXTINF:10,
media-00004.ts
#EXT-X-ENDLIST
53 changes: 53 additions & 0 deletions test/m3u8.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,59 @@ QUnit.test('parses prefixed with 0x or 0X #EXT-X-KEY:IV tags', function(assert)
0x90abcdef
]), 'parsed an IV value with 0X');
});
// #EXT-X-START
QUnit.test('parses EXT-X-START tags', function(assert) {
const manifest = '#EXT-X-START:TIME-OFFSET=1.1\n';
let element;

this.parseStream.on('data', function(elem) {
element = elem;
});
this.lineStream.push(manifest);

assert.ok(element, 'an event was triggered');
assert.strictEqual(element.type, 'tag', 'the line type is tag');
assert.strictEqual(element.tagType, 'start', 'the tag type is start');
assert.strictEqual(element.attributes['TIME-OFFSET'], 1.1, 'parses time offset');
assert.strictEqual(element.attributes.PRECISE, false, 'precise defaults to false');
});
QUnit.test('parses EXT-X-START PRECISE attribute', function(assert) {
const manifest = '#EXT-X-START:TIME-OFFSET=1.4,PRECISE=YES\n';
let element;

this.parseStream.on('data', function(elem) {
element = elem;
});
this.lineStream.push(manifest);

assert.ok(element, 'an event was triggered');
assert.strictEqual(element.type, 'tag', 'the line type is tag');
assert.strictEqual(element.tagType, 'start', 'the tag type is start');
assert.strictEqual(element.attributes['TIME-OFFSET'], 1.4, 'parses time offset');
assert.strictEqual(element.attributes.PRECISE, true, 'parses precise attribute');
});
QUnit.test('flags missing EXT-X-START TIME-OFFSET attribute', function(assert) {
const parser = new Parser();

const manifest = [
'#EXT-X-VERSION:3',
'#EXT-X-TARGETDURATION:10',
'#EXT-X-START:PRECISE=YES',
'#EXTINF:10,',
'media-00001.ts',
'#EXT-X-ENDLIST'
].join('\n');
let warning;

parser.on('warn', function(warn) {
warning = warn;
});
parser.push(manifest);

assert.ok(warning, 'a warning was triggered');
assert.ok((/ignoring start/).test(warning.message), 'message is about start tag');
assert.strictEqual(typeof parser.manifest.start, 'undefined', 'does not parse start');
});

QUnit.test('ignores empty lines', function(assert) {
const manifest = '\n';
Expand Down

0 comments on commit 31b6d0b

Please sign in to comment.