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

Parsing and dumping of multiple EXT-X-KEYs per segment is not supported #283

Open
davemevans opened this issue Jul 5, 2022 · 3 comments · May be fixed by #313
Open

Parsing and dumping of multiple EXT-X-KEYs per segment is not supported #283

davemevans opened this issue Jul 5, 2022 · 3 comments · May be fixed by #313

Comments

@davemevans
Copy link
Contributor

davemevans commented Jul 5, 2022

The HLS spec is clear that a segment may be preceeded with multiple EXT-X-KEY tags, so long as they resolve to a single decryption key. This allows multiple DRMs to be supported using Common Encryption.

When the example playlist below is parsed, segment[0]['key'] only lists the last key that preceeded the segment. Dumping the playlist object results in only the last key preceeding the segment appearing in the output. We need to be able to have a list of keys associated with a segments, possibly manipulate these, and dump them correctly.

Note: m3u8['keys'] includes all keys, but it doesn't correctly associated keys with segments using by_key, presumably because of the above.

Usually I would knock something together, but key handling seems a bit confusing to me and am looking for a bit of direction about what might be the best way to approach this. I am tempted simply to add segment['keys'] and always return a list (or None when no keys), but it's not obvious what segment['key'] should be, or how m3u8['keys'] would operate, in this model. Does anyone else have an opinion here?

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MAP:URI="0.m4s"
#EXT-X-PROGRAM-DATE-TIME:2022-07-04T11:30:11.680150Z
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://blah",IV=0xd7c3306f79c9b7d179f5dd09e2431d6e,KEYFORMAT="com.apple.streamingkeydelivery",KEYFORMATVERSIONS="1"
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:pssh...",IV=0xd7c3306f79c9b7d179f5dd09e2431d6e,KEYFORMAT="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",KEYFORMATVERSIONS="1"
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:pssh...",IV=0xd7c3306f79c9b7d179f5dd09e2431d6e,KEYFORMAT="com.microsoft.playready",KEYFORMATVERSIONS="1"
#EXTINF:6.006,
275879823.m4s
@bbayles
Copy link
Contributor

bbayles commented Jul 13, 2022

Subscribing as an interested observer...

I am tempted simply to add segment['keys'] and always return a list (or None when no keys)

I think this is a good idea.

it's not obvious what segment['key'] should be

Documentation could be added to say that Segment.key is the one immediately preceding the media file. This would be backward compatible, I think? SegmentList.by_key could be documented such that it mentions this constraint as well.

@vevv
Copy link
Contributor

vevv commented Jul 20, 2022

I am tempted simply to add segment['keys'] and always return a list (or None when no keys)

I would go with an empty list, then it would match the main M3U8 playlist object.

@rlaphoenix
Copy link

+1. Having this issue as well.

rlaphoenix added a commit to rlaphoenix/m3u8 that referenced this issue Mar 9, 2023
This closes globocom#283 as it now follows RFC and keeps all preceding keys for the segment.

- `m3u8_obj.keys` still has the same behaviour.
- `m3u8_obj.segments[0].key` is now removed.
- `m3u8_obj.segments[0].keys` is added in it's place, which will now always be a list.
- The list will always be present, it will never be `None` anymore, and if the segment explicitly has no DRM by specifying an EXT-X-KEY of METHOD=NONE then it will be a list with that key.
- It does not check if there's a METHOD=NONE with other conflicting EXT-X-KEY information.
- It still follows the same behaviour of not duplicating the EXT-X-KEY information on future segments when dumping.

Do note that it only clears the list of Keys when it reaches an EXT-X-DISCONTINUITY, or it has reached a ts segment.

The copy() statement is used because it clears after the segment is appended to `data`, yet the .clear() to `current_keys` follows in the appended `segment` unless we copy that data in memory prior.

I don't think there's a need for `.by_key()` or `m3u8_obj.keys` anymore, but I've made sure those still work as intended in case there's a different reason those exist.
@rlaphoenix rlaphoenix linked a pull request Mar 9, 2023 that will close this issue
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 a pull request may close this issue.

4 participants