Skip to content

Commit

Permalink
feat: add support for #EXT-X-I-FRAMES-ONLY
Browse files Browse the repository at this point in the history
Handles I-frames-only `segments`, providing a basis for the creation of trick-play functionality.

**parse-stream.js**

- add match statement for parsing the `EXT-X-I-FRAMES-ONLY` tag
- add test case

**parser.js**

- add a property `iFramesOnly` to the `manifest`
- add a function to validate the minimum version required
- trigger a `warn` event if the minimum version required is not supported or undefined, as required by the specification
- add test case

https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.6

- update `README.md` documentation
  • Loading branch information
amtins committed Jul 25, 2023
1 parent a673efc commit fd9c5e6
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ Manifest {
* [EXT-X-MAP](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.5)
* [EXT-X-PROGRAM-DATE-TIME](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.6)
* [EXT-X-DATERANGE](https://datatracker.ietf.org/doc/html/draft-pantos-http-live-streaming-23#section-4.3.2.7)
* [EXT-X-I-FRAMES-ONLY](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.6)

### Media Playlist Tags

Expand Down Expand Up @@ -240,7 +241,6 @@ Example media playlist using `EXT-X-CUE-` tags.

### Not Yet Supported

* [EXT-X-I-FRAMES-ONLY](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.6)
* [EXT-X-I-FRAME-STREAM-INF](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.3)
* [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)
Expand Down
8 changes: 8 additions & 0 deletions src/parse-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,14 @@ export default class ParseStream extends Stream {
});
return;
}
match = (/^#EXT-X-I-FRAMES-ONLY/).exec(newLine);
if (match) {
this.trigger('data', {
type: 'tag',
tagType: 'i-frames-only'
});
return;
}

// unknown tag type
this.trigger('data', {
Expand Down
13 changes: 13 additions & 0 deletions src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,11 @@ export default class Parser extends Stream {
},
'independent-segments'() {
this.manifest.independentSegments = true;
},
'i-frames-only'() {
this.manifest.iFramesOnly = true;

this.requiredCompatibilityversion(this.manifest.version, 4);
}
})[entry.tagType] || noop).call(self);
},
Expand Down Expand Up @@ -758,6 +763,14 @@ export default class Parser extends Stream {
});
}

requiredCompatibilityversion(currentVersion, targetVersion) {
if (currentVersion < targetVersion || !currentVersion) {
this.trigger('warn', {
message: `manifest must be at least version ${targetVersion}`
});
}
}

warnOnMissingAttributes_(identifier, attributes, required) {
const missing = [];

Expand Down
44 changes: 44 additions & 0 deletions test/fixtures/integration/iFramesOnly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramesOnly: true,
mediaSequence: 0,
playlistType: 'VOD',
segments: [
{
duration: 2.002,
timeline: 0,
uri: '001.ts'
},
{
duration: 2.002,
timeline: 0,
uri: '002.ts'
},
{
duration: 2.002,
timeline: 0,
uri: '003.ts'
},
{
duration: 2.002,
timeline: 0,
uri: '004.ts'
},
{
duration: 2.002,
timeline: 0,
uri: '005.ts'
},
{
duration: 2.002,
timeline: 0,
uri: '006.ts'
}
],
targetDuration: 3,
endList: true,
discontinuitySequence: 0,
discontinuityStarts: [],
version: 4
};
19 changes: 19 additions & 0 deletions test/fixtures/integration/iFramesOnly.m3u8
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:3
#EXT-X-I-FRAMES-ONLY
#EXTINF:2.002,
001.ts
#EXTINF:2.002,
002.ts
#EXTINF:2.002,
003.ts
#EXTINF:2.002,
004.ts
#EXTINF:2.002,
005.ts
#EXTINF:2.002,
006.ts
#EXT-X-ENDLIST
14 changes: 14 additions & 0 deletions test/parse-stream.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -981,3 +981,17 @@ QUnit.test('ignores empty lines', function(assert) {

assert.ok(!event, 'no event is triggered');
});

QUnit.test('parses #EXT-X-I-FRAMES-ONLY', function(assert) {
const manifest = '#EXT-X-I-FRAMES-ONLY\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, 'i-frames-only', 'the tag type is i-frames-only');
});
69 changes: 69 additions & 0 deletions test/parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,75 @@ QUnit.module('m3u8s', function(hooks) {
assert.equal(this.parser.manifest.independentSegments, true);
});

QUnit.test('warns when #EXT-X-I-FRAMES-ONLY the minimum version required is not supported', function(assert) {
this.parser.push([
'#EXTM3U',
'#EXT-X-VERSION:3',
'#EXT-X-PLAYLIST-TYPE:VOD',
'#EXT-X-MEDIA-SEQUENCE:0',
'#EXT-X-TARGETDURATION:3',
'#EXT-X-I-FRAMES-ONLY',
'#EXTINF:2.002,',
'001.ts',
'#EXTINF:2.002,',
'002.ts',
'#EXTINF:2.002,',
'003.ts',
'#EXTINF:2.002,',
'004.ts',
'#EXTINF:2.002,',
'005.ts',
'#EXTINF:2.002,',
'006.ts',
'#EXT-X-ENDLIST'
].join('\n'));
this.parser.end();

const warnings = [
'manifest must be at least version 4'
];

assert.deepEqual(
this.warnings,
warnings,
'warnings as expected'
);
});

QUnit.test('warns when #EXT-X-I-FRAMES-ONLY does not contain a version number', function(assert) {
this.parser.push([
'#EXTM3U',
'#EXT-X-PLAYLIST-TYPE:VOD',
'#EXT-X-MEDIA-SEQUENCE:0',
'#EXT-X-TARGETDURATION:3',
'#EXT-X-I-FRAMES-ONLY',
'#EXTINF:2.002,',
'001.ts',
'#EXTINF:2.002,',
'002.ts',
'#EXTINF:2.002,',
'003.ts',
'#EXTINF:2.002,',
'004.ts',
'#EXTINF:2.002,',
'005.ts',
'#EXTINF:2.002,',
'006.ts',
'#EXT-X-ENDLIST'
].join('\n'));
this.parser.end();

const warnings = [
'manifest must be at least version 4'
];

assert.deepEqual(
this.warnings,
warnings,
'warnings as expected'
);
});

QUnit.module('integration');

for (const key in testDataExpected) {
Expand Down

0 comments on commit fd9c5e6

Please sign in to comment.