Skip to content

Commit

Permalink
Merge branch 'main' into feat-ext-x-define
Browse files Browse the repository at this point in the history
  • Loading branch information
mister-ben authored Aug 20, 2024
2 parents 71a952a + e5dbdb6 commit 1dea558
Show file tree
Hide file tree
Showing 67 changed files with 795 additions and 13 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,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 All @@ -195,6 +196,7 @@ Manifest {

* [EXT-X-MEDIA](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.1)
* [EXT-X-STREAM-INF](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.2)
* [EXT-X-I-FRAME-STREAM-INF](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.3)
* [EXT-X-CONTENT-STEERING](https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.6.6)
* [EXT-X-DEFINE](https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.2.3)

Expand Down Expand Up @@ -261,8 +263,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
81 changes: 70 additions & 11 deletions src/parse-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,29 @@ const parseAttributes = function(attributes) {
return result;
};

/**
* Converts a string into a resolution object
*
* @param {string} resolution a string such as 3840x2160
*
* @return {Object} An object representing the resolution
*
*/
const parseResolution = (resolution) => {
const split = resolution.split('x');
const result = {};

if (split[0]) {
result.width = parseInt(split[0], 10);
}

if (split[1]) {
result.height = parseInt(split[1], 10);
}

return result;
};

/**
* A line-level M3U8 parser event stream. It expects to receive input one
* line at a time and performs a context-free parse of its contents. A stream
Expand Down Expand Up @@ -296,16 +319,7 @@ export default class ParseStream extends Stream {
event.attributes = parseAttributes(match[1]);

if (event.attributes.RESOLUTION) {
const split = event.attributes.RESOLUTION.split('x');
const resolution = {};

if (split[0]) {
resolution.width = parseInt(split[0], 10);
}
if (split[1]) {
resolution.height = parseInt(split[1], 10);
}
event.attributes.RESOLUTION = resolution;
event.attributes.RESOLUTION = parseResolution(event.attributes.RESOLUTION);
}
if (event.attributes.BANDWIDTH) {
event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10);
Expand Down Expand Up @@ -429,7 +443,7 @@ export default class ParseStream extends Stream {
this.trigger('data', event);
return;
}
match = (/^#EXT-X-CUE-IN:(.*)?$/).exec(newLine);
match = (/^#EXT-X-CUE-IN:?(.*)?$/).exec(newLine);
if (match) {
event = {
type: 'tag',
Expand Down Expand Up @@ -624,6 +638,16 @@ 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;
}

match = (/^#EXT-X-CONTENT-STEERING:(.*)$/).exec(newLine);
if (match) {
event = {
Expand All @@ -632,6 +656,41 @@ export default class ParseStream extends Stream {
};
event.attributes = parseAttributes(match[1]);
this.trigger('data', event);

return;
}

match = (/^#EXT-X-I-FRAME-STREAM-INF:(.*)$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'i-frame-playlist'
};

event.attributes = parseAttributes(match[1]);

if (event.attributes.URI) {
event.uri = event.attributes.URI;
}

if (event.attributes.BANDWIDTH) {
event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10);
}

if (event.attributes.RESOLUTION) {
event.attributes.RESOLUTION = parseResolution(event.attributes.RESOLUTION);
}

if (event.attributes['AVERAGE-BANDWIDTH']) {
event.attributes['AVERAGE-BANDWIDTH'] = parseInt(event.attributes['AVERAGE-BANDWIDTH'], 10);
}

if (event.attributes['FRAME-RATE']) {
event.attributes['FRAME-RATE'] = parseFloat(event.attributes['FRAME-RATE']);
}

this.trigger('data', event);

return;
}
match = (/^#EXT-X-DEFINE:(.*)$/).exec(newLine);
Expand Down
29 changes: 29 additions & 0 deletions src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export default class Parser extends Stream {
allowCache: true,
discontinuityStarts: [],
dateRanges: [],
iFramePlaylists: [],
segments: []
};
// keep track of the last seen segment's byte range end, as segments are not required
Expand Down Expand Up @@ -743,6 +744,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);
},
'content-steering'() {
this.manifest.contentSteering = camelCaseKeys(entry.attributes);
this.warnOnMissingAttributes_(
Expand All @@ -751,6 +757,7 @@ export default class Parser extends Stream {
['SERVER-URI']
);
},

/** @this {Parser} */
define() {
this.manifest.definitions = this.manifest.definitions || { };
Expand Down Expand Up @@ -842,6 +849,20 @@ export default class Parser extends Stream {
this.trigger('error', {
message: 'EXT-X-DEFINE: No attribute'
});
},

'i-frame-playlist'() {
this.manifest.iFramePlaylists.push({
attributes: entry.attributes,
uri: entry.uri,
timeline: currentTimeline
});

this.warnOnMissingAttributes_(
'#EXT-X-I-FRAME-STREAM-INF',
entry.attributes,
['BANDWIDTH', 'URI']
);
}

})[entry.tagType] || noop).call(self);
Expand Down Expand Up @@ -897,6 +918,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
1 change: 1 addition & 0 deletions test/fixtures/integration/absoluteUris.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
playlistType: 'VOD',
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/allowCache.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
allowCache: true,
iFramePlaylists: [],
mediaSequence: 0,
dateRanges: [],
playlistType: 'VOD',
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/allowCacheInvalid.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
allowCache: true,
iFramePlaylists: [],
mediaSequence: 0,
dateRanges: [],
playlistType: 'VOD',
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/alternateAudio.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = {
allowCache: true,
discontinuityStarts: [],
dateRanges: [],
iFramePlaylists: [],
mediaGroups: {
// TYPE
'AUDIO': {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/alternateVideo.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = {
allowCache: true,
discontinuityStarts: [],
dateRanges: [],
iFramePlaylists: [],
mediaGroups: {
'AUDIO': {
aac: {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/brightcove.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
allowCache: true,
iFramePlaylists: [],
dateRanges: [],
playlists: [
{
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/byteRange.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
playlistType: 'VOD',
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/dateTime.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
allowCache: false,
iFramePlaylists: [],
mediaSequence: 0,
dateRanges: [],
playlistType: 'VOD',
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/diff-init-key.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = {
discontinuitySequence: 0,
discontinuityStarts: [],
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 7794,
segments: [
{
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/disallowCache.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: false,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
playlistType: 'VOD',
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/disc-sequence.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
discontinuitySequence: 3,
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/discontinuity.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
discontinuitySequence: 0,
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/domainUris.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
playlistType: 'VOD',
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/empty.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ module.exports = {
allowCache: true,
dateRanges: [],
discontinuityStarts: [],
iFramePlaylists: [],
segments: []
};
1 change: 1 addition & 0 deletions test/fixtures/integration/emptyAllowCache.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
playlistType: 'VOD',
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/emptyMediaSequence.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
playlistType: 'VOD',
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/emptyPlaylistType.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
segments: [
{
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/emptyTargetDuration.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
playlists: [
{
attributes: {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/encrypted.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 7794,
discontinuitySequence: 0,
discontinuityStarts: [],
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/event.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
playlistType: 'EVENT',
segments: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 1,
segments: [
{
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/extinf.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 0,
playlistType: 'VOD',
segments: [
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/fmp4.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
allowCache: true,
dateRanges: [],
iFramePlaylists: [],
mediaSequence: 1,
playlistType: 'VOD',
targetDuration: 6,
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/integration/headerOnly.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ module.exports = {
allowCache: true,
dateRanges: [],
discontinuityStarts: [],
iFramePlaylists: [],
segments: []
};
Loading

0 comments on commit 1dea558

Please sign in to comment.