Giter VIP home page Giter VIP logo

hls-parser's Introduction

HLS parser tests Coverage Status Known Vulnerabilities npm Downloads XO code style

hls-parser

Provides synchronous functions to read/write HLS playlists (conforms to the HLS spec rev.23, the Apple Low-Latency Spec rev. 2020/02/05, and HLS.js's Low-Latency spec)

Install

NPM

Usage

import { parse, types, stringify } from 'hls-parser';

// Parse the playlist
const playlist = parse(textData);
// You can access the playlist as a JS object
if (playlist.isMasterPlaylist) {
  // Master playlist
} else {
  // Media playlist
}
// Create a new playlist
const {MediaPlaylist, Segment} = types;
const obj = new MediaPlaylist({
  targetDuration: 9,
  playlistType: 'VOD',
  segments: [
    new Segment({
      uri: 'low/1.m3u8',
      duration: 9
    })
  ]
});
// Convert the object into a text
stringify(obj);
/*
#EXTM3U
#EXT-X-TARGETDURATION:9
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:9,
low/1.m3u8
*/

API

HLS.parse(str)

Converts a text playlist into a structured JS object

params

Name Type Required Default Description
str string Yes N/A A text data that conforms to the HLS playlist spec

return value

An instance of either MasterPlaylist or MediaPlaylist (See Data format below.)

HLS.stringify(obj, postProcess)

Converts a JS object into a plain text playlist

params

Name Type Required Default Description
obj MasterPlaylist or MediaPlaylist (See Data format below.) Yes N/A An object returned by HLS.parse() or a manually created object
postProcess PostProcess No undefined A function to be called for each segment or variant to manipulate the output.
PostProcess
Property Type Required Default Description
segmentProcessor (lines: string[], start: number, end: number, segment: Segment, i: number) => void No undefined A function to manipulate the segment output.
variantProcessor (lines: string[], start: number, end: number, variant: Variant, i: number) => void No undefined A function to manipulate the variant output.

return value

A text data that conforms to the HLS playlist spec

HLS.setOptions(obj)

Updates the option values

params

Name Type Required Default Description
obj Object Yes {} An object holding option values which will be used to overwrite the internal option values.
supported options
Name Type Default Description
strictMode boolean false If true, the function throws an error when parse/stringify failed. If false, the function just logs the error and continues to run.
allowClosedCaptionsNone boolean false If true, CLOSED-CAPTIONS attribute on the EXT-X-STREAM-INF tag will be set to the enumerated-string value NONE when there are no closed-captions. See CLOSED-CAPTIONS
silent boolean false If true, console.error will be suppressed.

HLS.getOptions()

Retrieves the current option values

return value

A cloned object containing the current option values

HLS.types

An object that holds all the classes described below.

Data format

This section describes the structure of the object returned by parse() method.

data structure

Data

Property Type Required Default Description
type string Yes N/A Either playlist or segment or part}

Playlist (extends Data)

Property Type Required Default Description
isMasterPlaylist boolean Yes N/A true if this playlist is a master playlist
uri string No undefined Playlist URL
version number No undefined See EXT-X-VERSION
independentSegments boolean No false See EXT-X-INDEPENDENT-SEGMENTS
start object({offset: number, precise: boolean}) No undefined See EXT-X-START
source string No undefined The unprocessed text of the playlist

MasterPlaylist (extends Playlist)

Property Type Required Default Description
variants [Variant] No [] See EXT-X-STREAM-INF and EXT-X-I-FRAME-STREAM-INF
currentVariant number No undefined Array index that points to the chosen item in variants
sessionDataList [SessionData] No [] See EXT-X-SESSION-DATA
sessionKeyList [Key] No [] See EXT-X-SESSION-KEY

Variant

Property Type Required Default Description
uri string Yes N/A URI of the variant playlist
isIFrameOnly boolean No undefined true if the variant is an I-frame media playlist. See EXT-X-I-FRAME-STREAM-INF
bandwidth number Yes N/A See BANDWIDTH attribute in EXT-X-STREAM-INF
averageBandwidth number No undefined See AVERAGE-BANDWIDTH attribute in EXT-X-STREAM-INF
score number No undefined See SCORE attribute in EXT-X-STREAM-INF
codecs string No undefined See CODECS attribute in EXT-X-STREAM-INF
resolution object ({width: number, height: number}) No undefined See RESOLUTION attribute in EXT-X-STREAM-INF
frameRate number No undefined See FRAME-RATE attribute in EXT-X-STREAM-INF
hdcpLevel string No undefined See HDCP-LEVEL attribute in EXT-X-STREAM-INF
allowedCpc [object ({format: string, cpcList: [string]})] No undefined See ALLOWED-CPC attribute in EXT-X-STREAM-INF
videoRange string {"SDR","HLG","PQ"} No undefined See VIDEO-RANGE attribute in EXT-X-STREAM-INF
stableVariantId string No undefined See STABLE-VARIANT-ID attribute in EXT-X-STREAM-INF
audio [Rendition(type='AUDIO')] No [] See AUDIO attribute in EXT-X-STREAM-INF
video [Rendition(type='VIDEO')] No [] See VIDEO attribute in EXT-X-STREAM-INF
subtitles [Rendition(type='SUBTITLES')] No [] See SUBTITLES attribute in EXT-X-STREAM-INF
closedCaptions [Rendition(type='CLOSED-CAPTIONS')] No [] See CLOSED-CAPTIONS attribute in EXT-X-STREAM-INF
currentRenditions object ({audio: number, video: number, subtitles: number, closedCaptions: number}) No {} A hash object that contains array indices that points to the chosen Rendition for each type

Rendition

Property Type Required Default Description
type string Yes N/A See TYPE attribute in EXT-X-MEDIA
uri string No undefined See URI attribute in EXT-X-MEDIA
groupId string Yes N/A See GROUP-ID attribute in EXT-X-MEDIA
language string No undefined See LANGUAGE attribute in EXT-X-MEDIA
assocLanguage string No undefined See ASSOC-LANGUAGE attribute in EXT-X-MEDIA
name string Yes N/A See NAME attribute in EXT-X-MEDIA
isDefault boolean No false See DEFAULT attribute in EXT-X-MEDIA
autoselect boolean No false See AUTOSELECT attribute in EXT-X-MEDIA
forced boolean No false See FORCED attribute in EXT-X-MEDIA
instreamId string No undefined See INSTREAM-ID attribute in EXT-X-MEDIA
characteristics string No undefined See CHARACTERISTICS attribute in EXT-X-MEDIA
channels string No undefined See CHANNELS attribute in EXT-X-MEDIA

SessionData

Property Type Required Default Description
id string Yes N/A See DATA-ID attribute in EXT-X-SESSION-DATA
value string No undefined See VALUE attribute in EXT-X-SESSION-DATA
uri string No undefined See URI attribute in EXT-X-SESSION-DATA
language string No undefined See LANGUAGE attribute in EXT-X-SESSION-DATA

MediaPlaylist (extends Playlist)

Property Type Required Default Description
targetDuration number Yes N/A See EXT-X-TARGETDURATION
mediaSequenceBase number No 0 See EXT-X-MEDIA-SEQUENCE
discontinuitySequenceBase number No 0 See EXT-X-DISCONTINUITY-SEQUENCE
endlist boolean No false See EXT-X-ENDLIST
playlistType string No undefined See EXT-X-PLAYLIST-TYPE
isIFrame boolean No undefined See EXT-X-I-FRAMES-ONLY
segments [Segment] No [] A list of available segments
prefetchSegments [PrefetchSegment] No [] A list of available prefetch segments
lowLatencyCompatibility object ({canBlockReload: boolean, canSkipUntil: number, holdBack: number, partHoldBack: number}) No undefined See CAN-BLOCK-RELOAD, CAN-SKIP-UNTIL, HOLD-BACK, and PART-HOLD-BACK attributes in EXT-X-SERVER-CONTROL
partTargetDuration number No* undefined *Required if the playlist contains one or more EXT-X-PART tags. See EXT-X-PART-INF
renditionReports [RenditionReport] No [] Update status of the associated renditions
skip number No 0 See EXT-X-SKIP

Segment (extends Data)

Property Type Required Default Description
uri string Yes* N/A URI of the media segment. *Not required if the segment contains EXT-X-PRELOAD-HINT tag
duration number Yes* N/A See EXTINF *Not required if the segment contains EXT-X-PRELOAD-HINT tag
title string No undefined See EXTINF
byterange object ({length: number, offset: number}) No undefined See EXT-X-BYTERANGE
discontinuity boolean No undefined See EXT-X-DISCONTINUITY
mediaSequenceNumber number No 0 See the description about 'Media Sequence Number' in 3. Media Segments
discontinuitySequence number No 0 See the description about 'Discontinuity Sequence Number' in 6.2.1. General Server Responsibilities
key Key No undefined See EXT-X-KEY
map MediaInitializationSection No undefined See EXT-X-MAP
programDateTime Date No undefined See EXT-X-PROGRAM-DATE-TIME
dateRange DateRange No undefined See EXT-X-DATERANGE
markers [SpliceInfo] No [] SCTE-35 messages associated with this segment
parts [PartialSegment] No [] Partial Segments that constitute this segment

PartialSegment (extends Data)

Property Type Required Default Description
hint boolean No false true indicates a hinted resource (TYPE=PART) See EXT-X-PRELOAD-HINT
uri string Yes N/A See URI attribute in EXT-X-PART
duration number Yes* N/A See DURATION attribute in EXT-X-PART *Not required if hint is true
independent boolean No undefined See INDEPENDENT attribute in EXT-X-PART
byterange object ({length: number, offset: number}) No undefined See BYTERANGE attribute in EXT-X-PART
gap boolean No undefined See GAP attribute in EXT-X-PART

PrefetchSegment (extends Data)

Property Type Required Default Description
uri string Yes N/A See value of EXT-X-PREFETCH
discontinuity boolean No undefined See EXT-X-PREFETCH-DISCONTINUITY
mediaSequenceNumber number No 0 See the description about 'Media Sequence Number' in 3. Media Segments
discontinuitySequence number No 0 See the description about 'Discontinuity Sequence Number' in 6.2.1. General Server Responsibilities

Key

Property Type Required Default Description
method string Yes N/A See METHOD attribute in EXT-X-KEY
uri string No undefined See URI attribute in EXT-X-KEY
iv ArrayBuffer(length=16) No undefined See IV attribute in EXT-X-KEY
format string No undefined See KEYFORMAT attribute in EXT-X-KEY
formatVersion string No undefined See KEYFORMATVERSIONS attribute in EXT-X-KEY

MediaInitializationSection

Property Type Required Default Description
hint boolean No false true indicates a hinted resource (TYPE=MAP) See EXT-X-PRELOAD-HINT
uri string Yes N/A See URI attribute in EXT-X-MAP
byterange object ({length: number, offset: number}) No undefined See BYTERANGE attribute in EXT-X-MAP

DateRange

Property Type Required Default Description
id string Yes N/A See ID attribute in EXT-X-DATERANGE
classId string No undefined See CLASS attribute in EXT-X-DATERANGE
start Date No undefined See START-DATE attribute in EXT-X-DATERANGE
end Date No undefined See END-DATE attribute in EXT-X-DATERANGE
duration number No undefined See DURATION attribute in EXT-X-DATERANGE
plannedDuration number No undefined See PLANNED-DURATION attribute in EXT-X-DATERANGE
endOnNext boolean No undefined See END-ON-NEXT attribute in EXT-X-DATERANGE
attributes object No {} A hash object that holds SCTE35 attributes and user defined attributes. See SCTE35-* and X- attributes in EXT-X-DATERANGE

SpliceInfo

Only EXT-X-CUE-OUT and EXT-X-CUE-IN tags are supported. Other SCTE-35-related tags are stored as raw (string) values.

Property Type Required Default Description
type string Yes N/A {'OUT', 'IN', 'RAW'}
duration number No undefined Required if the type is 'OUT'
tagName string No undefined Holds the tag name if any unsupported tag are found. Required if the type is 'RAW'
value string No undefined Holds a raw (string) value for the unsupported tag.

RenditionReport

Property Type Required Default Description
uri string Yes N/A See URI attribute in EXT-X-RENDITION-REPORT
lastMSN number No undefined See LAST-MSN attribute in EXT-X-RENDITION-REPORT
lastPart number No undefined See LAST-PART attribute in EXT-X-RENDITION-REPORT

hls-parser's People

Contributors

calling avatar dependabot[bot] avatar gtebbutt avatar harrietwaters avatar hsume2 avatar jacobley avatar jhen0409 avatar jkruse14 avatar joeflateau avatar kot-lex avatar kuu avatar murilozilli avatar nahularenasq avatar pepoirot avatar ruddell avatar salmoro avatar tachibana-shin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

hls-parser's Issues

Issue with hls.stringify for cloned hls object

When an HLS object is cloned via JSON.parse(JSON.stringify(manifest)), the resulting object cannot be stringified. The issue lies in

  1. programDateTime field - This gets converted into string. Need to be converted back to Date before stringify
  2. IV - The buffer gets converted to object. Should be converted back to buffer before stringify
    It would be great if the stringify function can handle this internally more efficiently

Here is the sample code to demonstrate this

const hls   =  require("hls-parser")
var input = "#EXTM3U \n" + 
            "#EXT-X-VERSION:5 \n" + 
            "#EXT-X-MEDIA-SEQUENCE:0 \n" + 
            "#EXT-X-TARGETDURATION:4 \n" + 
            "#EXT-X-PROGRAM-DATE-TIME:2021-08-02T07:24:22.997000+00:00 \n" + 
            "#EXT-X-KEY:METHOD=AES-128,URI=\"enc.key\"" + ",IV=0x0000000000000000000000000000044A \n" + 
            "#EXTINF:4, \n" + 
            "0.ts \n" + 
            "#EXTINF:4, \n" + 
            "1.ts \n" + 
            "#EXTINF:4, \n" + 
            "2.ts";
var manifest  = hls.parse(input);
var manifest2 = JSON.parse(JSON.stringify(manifest));
var output = hls.stringify(manifest2);

Stop using WHATWG URL

so that we can do parse()/stringify() only with relative URIs that should not be resolved in parse/stringfy time but in download time.

Multiple markers is unsupported

The multiple markers are unsupported when stringify try to write an m3u8 file.
Redundant item will be thrown.
You should add the #EXT-X-CUE-OUT & #EXT-X-CUE-IN in ALLOW_REDUNDANCY array.

The library doesn't parse EXT-X-PART tag

Below is an example

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:109791
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3.12
#EXT-X-PART-INF:PART-TARGET=1.04
#EXTINF:3.96,
l_5797_63028341_109791.ts
#EXT-X-PART:DURATION=1,URI="l_5797_63032301_109792_0.ts"
#EXT-X-PART:DURATION=1,URI="l_5797_63032301_109792_1.ts"
#EXT-X-PART:DURATION=1,URI="l_5797_63032301_109792_2.ts"
#EXT-X-PART:DURATION=1.04,URI="l_5797_63032301_109792_3.ts"
#EXTINF:3.96,
l_5797_63032301_109792.ts
#EXT-X-PART:DURATION=1,URI="l_5797_63036261_109793_0.ts"
#EXT-X-PART:DURATION=1,URI="l_5797_63036261_109793_1.ts"
#EXT-X-PART:DURATION=1,URI="l_5797_63036261_109793_2.ts"
#EXT-X-PART:DURATION=1.04,URI="l_5797_63036261_109793_3.ts"

support buffered input for hls.parse & buffered output for hls.stringify

HLS.parse takes a text input, however for very large playlists having to load the entire playlist to memory (a string variable) can be very memory intensive. It would be great to support a buffered input so that not the entire playlist has to be loaded to memory all at once. Supporting buffered output for hls.stringify will also allow to have a buffered reader/writer for the entire parse & stringify pipeline.

HLS parser fails to parse 'hello, world' m3u8 & m3u files

The hls-parser is somewhat opinionated about constructs which turn up in 'real world' scenario's, such as the BipBop hello world HLS stream. To demonstrate:

/*
 * videojs-contrib-hls project suggests the following 'Hello, world' type HLS example:
 * https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8
 *
 * It's essentially the NTSC test signal with a few tracks of varying qualities,
 * a few audio tracks, subtitles and so on
 *
 * Note the main tracks are loops of the test signal to get to a 30min duration.
 *
 * ...
 *
 * hls-parser *should* be able to parse & stringify this
 */

const fetch = require('node-fetch');
const HLSParser = require('hls-parser');

// test the master playlist
/*
 * It fails because, it turns out subtitles *can* be forced
 */
const masterPlaylist = fetch('https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8')
    .then(response => response.text())
    .then(HLSParser.parse)
    .then(HLSParser.stringify)
    .then(() => console.log('Master playlist: PASS'))
    .catch(error => console.log('Master playlist: FAIL\n', error));

// test the gear1 variant referenced from the master playlist
/*
 * It fails becasue it is a loop of a segment and hls-parser is opinionated about this
 * ... similarly it does not like re-used keys/IVs in sequences such as IV_A, IV_B, IV_A (which is admittedly strange but still 'valid')
 */
const gear1 = fetch('https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/gear1/prog_index.m3u8')
    .then(response => response.text())
    .then(HLSParser.parse)
    .then(HLSParser.stringify)
    .then(() => console.log('Gear1 channel playlist: PASS'))
    .catch(error => console.log('Gear1 channel playlist: FAIL\n', error));

I guess the question is: should hls-parser relax some of its assertions to cope with this?

Stringify : Manifest malformation with multiple rendition (group-id)

When I've multiple rendition (for example multiple codec for the same language) stringify return the manifest with a EXT-X-STREAM-INF between EXT-X-MEDIA.

For example :

#EXTM3U
#EXT-X-VERSION:4
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio_aacl",NAME="English",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="eng",CHANNELS="2",URI="eng_aacl.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=8277095,AVERAGE-BANDWIDTH=6670088,CODECS="avc1.640028,mp4a.40.5",RESOLUTION=1920x1080,FRAME-RATE=29.970,AUDIO="audio_aacl"
1080p.m3u8
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio_aac",NAME="English",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="eng",CHANNELS="2",URI="eng_aac.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=8417895,AVERAGE-BANDWIDTH=6810888,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=29.970,AUDIO="eng_aac"
1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5235630,AVERAGE-BANDWIDTH=3951068,CODECS="avc1.4D401F,mp4a.40.2",RESOLUTION=1280x720,FRAME-RATE=29.970,AUDIO="audio_aacl"
720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5094830,AVERAGE-BANDWIDTH=3810268,CODECS="avc1.4D401F,mp4a.40.5",RESOLUTION=1280x720,FRAME-RATE=29.970,AUDIO="eng_aac"
720p.m3u8

It's appear to be a design issue in the code : https://github.com/kuu/hls-parser/blob/3d37ad8ef3a4836357e30764c8c43010cb8ed0a4/stringify.ts#L126C1-L126C1

You should first create the renditions and then the EXT-X-STREAM-INF

Not working in the browser?

I tried to use the parser in the browser, but I get errors about Buffer not being available (ReferenceError ...)
Is this library intended to be only used with ode.js?

Issue in maintaining segment key when splicing the segment

When I replace an existing segment with a new segment with a different key parameters, the replaced segment has correct key information. However, the original segments which follow replaced segment have wrong keys.

Sample code to reproduce this issue

const hls   =  require("hls-parser")
const axios = require("axios")
axios.get("https://k7q5a5e5.ssl.hwcdn.net/files/company/5e2f4a02199f0c33444d9403/assets/videos/5e311e889ba3f225c86c0b52/vod/5e311e889ba3f225c86c0b52_Layer_1.m3u8")
.then(function(manifest_data) {
   var media_manifest = hls.parse(manifest_data.data);
   var temp = JSON.parse(JSON.stringify(media_manifest.segments[100]));
   temp.key.uri="dummy.enc";
   media_manifest.segments.splice(100, 1, temp);
   console.log(hls.stringify(media_manifest))
});

EXT-X-MAP Needs to be added to ALLOW_REDUNDANCY list in utils.js

Per the revision 23 of the HLS spec, multiple EXT-X-MAP's can be contained in a media playlist as long as it comes after a DISCONTINUITY tag.

This effects fragmented mp4s or fmp4 when you are compositing different videos together. A new map file containing the videos PMT data needs to be inserted after the DISCONTINUITY flag.

As of right now hls-parser throws an error for Redundant Item which prevents these composited playlists from being loaded.

'#EXT-X-MAP' needs to be added to the end of the ALLOW_REDUNDANCY constant in utils.js.

If you try to output a playlist in HLS-V4 format, an error will occur.

When trying to output in HLS-V4 format, executing the following code causes an error.

const HLS = require('hls-parser');

const { MediaPlaylist, Segment } = HLS.types;
const segments = [];
Items.forEach((item) => {
  segments.push(
    new Segment({
      uri: item.uri,
      duration: item.duration,
      byterange: {
        length: item.byterangeLength,
        offset: item.byterangeOffset
      },
      mediaSequenceNumber: item.mediaSequenceNumber,
      discontinuitySequence: 0
    })
  )
});

const playlist = new MediaPlaylist({
  version: 4,
  targetDuration: 10,
  mediaSequenceBase: 0,
  playlistType: 'VOD',
  segments: segments
});

console.log(HLS.stringify(playlist))

-----error log-----

{
    "errorMessage": "Invalid Playlist : Redundant item (test01.ts)",
    "errorType": "Error",
    "stackTrace": [
        "Object.INVALIDPLAYLIST (/var/task/node_modules/hls-parser/utils.js:44:9)",
        "LineArray.push (/var/task/node_modules/hls-parser/stringify.js:34:15)",
        "buildSegment (/var/task/node_modules/hls-parser/stringify.js:218:9)",
        "buildMediaPlaylist (/var/task/node_modules/hls-parser/stringify.js:191:5)",
        "Object.stringify (/var/task/node_modules/hls-parser/stringify.js:280:5)",
        "module.exports.handler (/var/task/index.js:89:19)",
        "<anonymous>",
        "process._tickDomainCallback (internal/process/next_tick.js:228:7)"
    ]
}

I do not know if coding is bad or hls-parser is faulty. Please tell me how to resolve.
If byterange is not written, no error occurs and it works normally.

EXT-X-BYTERANGE should come after other segment information

Hello this library has been a life-saver for me generating M3U8 files, but I've noticed they sometimes fail depending on the consumer, namely iOS/Safari based viewers.
Not that I believe this library's implementation that betrays the spec, but rather Apple is strict in ways they do not advertise (i.e. it is Apple who is wrong, but we can accommodate)

The problem

Take two example M3U8 files:

(These files are slight modifications of sample files provided here: https://ottverse.com/free-hls-m3u8-test-urls/ -> http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/.m3u8)

success.m3u8

#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:5
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:4
http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/tears-of-steel-audio_eng=128002-video_eng=1001000-1.ts
#EXT-X-DISCONTINUITY
#EXTINF:4
#EXT-X-BYTERANGE:126712@0
http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/tears-of-steel-audio_eng=128002-video_eng=1001000-2.ts
#EXTINF:4
http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/tears-of-steel-audio_eng=128002-video_eng=1001000-3.ts
#EXT-X-ENDLIST

and fail.m3u8

#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:5
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:4
http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/tears-of-steel-audio_eng=128002-video_eng=1001000-1.ts
#EXT-X-BYTERANGE:126712@0
#EXT-X-DISCONTINUITY
#EXTINF:4
http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/tears-of-steel-audio_eng=128002-video_eng=1001000-2.ts
#EXTINF:4
http://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/tears-of-steel-audio_eng=128002-video_eng=1001000-3.ts
#EXT-X-ENDLIST

Notice that:

  1. The second segment has both a byte range (this is really the whole file, but proves a point here) and a discontinuity (again not actually necessary but proves a point).
  2. The second file is supposedly exactly the same, but the byte range is now at the start of the segment

Try loading the files in Safari (note Safari actually matters, I am not able to reproduce on Chrome, or other players like hls.js who are probably less strict)
A local serving package like https://www.npmjs.com/package/serve could come in handy

The first file is successful and plays a 12 second snippet, the second fails to load.

From my testing, it is the positioning of EXT-X-BYTERANGE before EXT-X-DISCONTINUITY (and potentially before EXTINF) that causes this issue

How it impacts this package

The current stringify logic writes EXT-X-BYTERANGE before anything else https://github.com/kuu/hls-parser/blob/master/stringify.js#L296 recreating the issue discussed above.

As stated before I believe this is allowed by spec, but some interpreters do not handle it well, so it is easy enough to move that render to later in the buildSegment method.

I'm happy to submit a PR with this suggested change as well, but wanted to open the discussion for what the real problem is, and potential ways to fix it.

Correctly stringify bytrange of EXT-X-MAP

If you parse and then stringify the following

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:5
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="high_1.mp4",BYTERANGE="824@0"
#EXTINF:4.805,
#EXT-X-BYTERANGE:1531172@976
high_1.mp4
#EXT-X-ENDLIST

Instead of getting the same as the above, you'd get something like

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:5
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="high_1.mp4",BYTERANGE=[object Object]
#EXTINF:4.805,
#EXT-X-BYTERANGE:1531172@976
high_1.mp4
#EXT-X-ENDLIST

Notice the JS objects as [object Object]

This is because the code doesn't try to stringy the byterange object of a map item:

attrs.push(`BYTERANGE=${map.byterange}`);

in the same way it does for a segment item
lines.push(`#EXT-X-BYTERANGE:${segment.byterange.length}@${segment.byterange.offset}`);

Should probably be abstracted into a function and reused by both.

CLOSED-CAPTIONS attribute doesn't honor spec

Hi,

I've experienced the following issue during parse:
CLOSED-CAPTIONS attribute MUST match the value of the GROUP-ID attribute of an EXT-X-MEDIA tag

The playlist has the following variant:
#EXT-X-STREAM-INF:BANDWIDTH=202000,AVERAGE-BANDWIDTH=184000,CODECS="mp4a.40.2,avc1.42C01E",RESOLUTION=192x108,FRAME-RATE=25,AUDIO="audio-aacl-64",CLOSED-CAPTIONS=NONE

But there's no closed caption group provided in the playlist.

However, I then checked the specification and found this:
The value can be either a quoted-string or an enumerated-string with the value NONE.

So it seems that the parse method does not honor that

License

Hello. I see "license": "MIT", in package.json but I can't find any actual license file in the project. The one condition in the MIT License is:

The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

But there are no copyright notices in the project, and the permission notice is not included in any portion of the software.

Handling ad markers SCTE-35

Hi,
What about parsing and dealing with ad markers segments ?
i.e.

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:8.008,
1.ts
#EXT-X-CUE-OUT:15.000
#EXTINF:8.008,
2.ts
#EXTINF:8.008,
3.ts
#EXT-X-CUE-IN
#EXTINF:8.008,
4.ts
#EXT-X-ENDLIST

Thanks

Can't add Redundant Streams to playlist variants

Just have to say great library so far! Been using it to generate playlist.
I don't have a fix right off the top of my head after glancing at the code but I noticed that I can't add Redundant Streams to the playlist variants when I call HLS.stringify(). My quick fix was to comment out https://github.com/kuu/hls-parser/blob/master/stringify.js#L18 but I'm pretty sure this would cause more problems then it would fix.

Let me know if their is any way I can help.

Great work though, thanks!

Release the last version

Hi,

thanks for this awesome library. I want to use it for a new project I have but it seems that the last version published on NPM isn't that actual state of the lib.

In my project I need both Typescript and marker support. I found that @types/hls-parser project doesn't includes markers and if I use npm install [email protected]:kuu/hls-parser.git I get the right types for typescript but I can't compile anymore.

Let me know if I can help in any way.

Thanks

Invalid Playlist: The EXT-X-MEDIA-SEQUENCE tag MUST appear before the first Media Segment in the Playlist

Hi @kuu,

I came across the following issue but I can't see what's wrong with parsing the playlist:

Error: Invalid Playlist : The EXT-X-MEDIA-SEQUENCE tag MUST appear before the first Media Segment in the Playlist.

#EXTM3U
# NeuLion Adaptive Streaming Server Version: 4.2.20181107.22941 
#EXT-X-PROGRAM-DATE-TIME:2018-12-05T23:41:56Z
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1116587
#EXTINF:10,
3y7ZyvdpWu_hd_800_20181205234156_042.ts
#EXTINF:10,
3y7ZyvdpWu_hd_800_20181205234206_042.ts
#EXTINF:10,
3y7ZyvdpWu_hd_800_20181205234216_042.ts
#EXTINF:10,
3y7ZyvdpWu_hd_800_20181205234226_042.ts
#EXTINF:10,
3y7ZyvdpWu_hd_800_20181205234236_042.ts
#EXTINF:10,
3y7ZyvdpWu_hd_800_20181205234246_042.ts

As far as i can tell the EXT-X-MEDIA-SEQUENCE appears before the first segment.

EXT-X-DATERANGE tags with no START-DATE attribute are not ignored with strictMode disabled

if (dateRange) {

Might need an additional check for dateRange.start on this line for parsing EXT-X-DATERANGE tags with no START-DATE attribute.

Although this is a required field based on the RFC, I would expect these invalid tags to be skipped rather than throw an error if strictMode is disabled

The RFC is slightly ambiguous as it includes an example of the tag without this attribute https://tools.ietf.org/html/rfc8216#section-8.10

Currently we're seeing TypeError: Cannot read property 'getTime' of undefined errors for tags without START-DATE

Property name cannot contain "-"

object ({AUDIO: number, VIDEO: number, SUBTITLES: number, CLOSED-CAPTIONS: number})

This is a build problem with TypeScript (when trying to add types) and will be an exception in run time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.