Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue #1179 with playlist parse #1180

Merged
merged 6 commits into from
Jun 3, 2017

Conversation

stevemayhew
Copy link
Contributor

@stevemayhew stevemayhew commented May 30, 2017

Description of the Changes

This fixes issue #1179.

For encrypted playlist that use the SN as the initialization vector the content will not play at all. This is because the playlist regex skips the first N segments and sets the SN to 0 for the Nth segment.
For unencrypted content it simply skips segments.

The problem was with the regex, it does not deal with segment URL that is one character or less.

See checkin/pull comments for why.

CheckLists

  • changes have been done against master branch, and PR does not conflict
  • no commits have been done in dist folder (we will take care of updating it)
  • new unit / functional tests have been added (whenever applicable)
  • Travis tests are passing (or test results are not worse than on master branch :))
  • API or design changes are documented in API.md

@@ -12,7 +12,17 @@ import {logger} from '../utils/logger';
// https://regex101.com is your friend
const MASTER_PLAYLIST_REGEX = /#EXT-X-STREAM-INF:([^\n\r]*)[\r\n]+([^\r\n]+)/g;
const MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
const LEVEL_PLAYLIST_REGEX_FAST = /#EXTINF:(\d*(?:\.\d+)?)(?:,(.*))?|(?!#)(\S.+)|#EXT-X-BYTERANGE: *(.+)|#EXT-X-PROGRAM-DATE-TIME:(.+)|#.*/g;
//const LEVEL_PLAYLIST_REGEX_FAST = /#EXTINF:(\d*(?:\.\d+)?)(?:,(.*)\s+)?|(?!#)(\S+)|#EXT-X-BYTERANGE:*(.+)|#EXT-X-PROGRAM-DATE-TIME:(.+)|#.*/g;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left the original format for the RegEx commented out so the exact changes are easy to see

  1. The second capture group (the title) has an explicit match for the trailing space (line termination)
  2. Third capture group (the URI) matches one or more non whitespace
  3. Space removed on the BYTERANGE regex

/|#EXT-X-PROGRAM-DATE-TIME:(.+)/.source, // next segment's program date/time group 5 => the datetime spec
/|#.*/.source // All other non-segment oriented tags will match with all groups empty
];
const LEVEL_PLAYLIST_REGEX_FAST = new RegExp(LEVEL_PLAYLIST_REGEX_PARTS.join(''), 'g');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split the regex up by alternatives, IMHO makes it easier to read and maintain. You can load the code and print LEVEL_PLAYLIST_REGEX_PARTS.join('') if one needs to paste the whole expression into something like regex101.

Otherwise the code is exactly the same as the commented out line 15 above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the regexp is complex and splitting it helps to read and maintain.
However in this case you are creating real Regexp (that are never used) , then converting them to string using Regexp.prototype.source, whereas you could directly join strings

@@ -139,8 +139,7 @@ http://proxy-21.dailymotion.com/sec(2a991e17f08fcd94f95637a6dd718ddd)/video/107/
var level = `#EXTM3U
#EXT-X-VERSION:3
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:14
#EXTINF:11.360,`;
#EXT-X-TARGETDURATION:14`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The #EXTINF without the required segment (or at least any space character or other tag) following it will not parse with the updated regex. If there is some real code that generates this invalid playlist then we can work on the regex to deal with this explicitly.

assert.strictEqual(result.fragments[1].sn, 1);
assert.strictEqual(result.fragments[1].relurl, '1');
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new test case, that fails with the old code.

@stevemayhew
Copy link
Contributor Author

This dependency is causing travisci to fail... I'll look at fixing it tomorrow.


├─┬ live-reload@1.1.0
...
│ ├─┬ reconnect@0.1.5
│ │ ├── backoff@1.0.0
│ │ ├── h@0.1.0
│ │ └─┬ shoe@0.0.15
│ │   ├─┬ sockjs@0.3.7
│ │   │ ├── faye-websocket@0.4.4
│ │   │ └── node-uuid@1.3.3 deduped
│ │   └── sockjs-client@0.0.0-unreleasable
│ ├─┬ shoe@0.0.5
│ │ ├── sockjs-client@0.0.0-unreleasable (git://github.com/substack/sockjs-client.git#40d48d06b4dba884416bf88a051f76ca3c8ffcae)

The sockjs-client is the issue. Suggest removing watchify and live-reload for travis builds.

Copy link
Member

@mangui mangui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @stevemayhew !
you might optimize the regexp array using plain string

/|#EXT-X-PROGRAM-DATE-TIME:(.+)/.source, // next segment's program date/time group 5 => the datetime spec
/|#.*/.source // All other non-segment oriented tags will match with all groups empty
];
const LEVEL_PLAYLIST_REGEX_FAST = new RegExp(LEVEL_PLAYLIST_REGEX_PARTS.join(''), 'g');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the regexp is complex and splitting it helps to read and maintain.
However in this case you are creating real Regexp (that are never used) , then converting them to string using Regexp.prototype.source, whereas you could directly join strings

@mangui
Copy link
Member

mangui commented Jun 1, 2017

277fb1c should address the build issue. you should be able to revert your Travis related commits

@stevemayhew
Copy link
Contributor Author

stevemayhew commented Jun 1, 2017

Thanks.. The const LEVEL_PLAYLIST_REGEX_FAST = new RegExp(LEVEL_PLAYLIST_REGEX_PARTS.join('') is the one actually being used. The old one is just a comment so you can see the diffs.

Your call, I think it makes it clearer to split it up into multiple // literal regex then join the string source in the end.

If you do the regex as a string and make it multi-line it's a real mess cause you need to escape all the \'s

So for example something nice like this:

  /#EXTINF:(\d*(?:\.\d+)?)(?:,(.*))?|/

Has to be:

    '#EXTINF:(\\d*(?:\\.\\d+)?)(?:,(.*))?|'

And you can't paste that into RegEx101 ;-)

Again, your call. If you like it split up I'll delete the commented out code in the final commit

@stevemayhew
Copy link
Contributor Author

PS thanks for fixing live-reload.. I'll merge again with mainline and update the pull

@mangui
Copy link
Member

mangui commented Jun 3, 2017

looks good, thanks !
merging

@mangui mangui merged commit 3a3dd20 into video-dev:master Jun 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants