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

feat: setup EME key systems for HLS as well as DASH #629

Merged
merged 5 commits into from
Sep 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 45 additions & 8 deletions src/videojs-http-streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
import { version } from '../package.json';
// import needed to register middleware
import './middleware-set-current-time';
import { isAudioCodec, isVideoCodec, parseContentType } from './util/codecs';

const Hls = {
PlaylistLoader,
Expand Down Expand Up @@ -140,18 +141,54 @@ Hls.canPlaySource = function() {
'your player\'s techOrder.');
};

const emeKeySystems = (keySystemOptions, videoPlaylist, audioPlaylist) => {
const emeKeySystems = (keySystemOptions, mainSegmentLoader, audioSegmentLoader) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since mainSegmentLoader and audioSegmentLoader are only used for their mimeType_ properties and the mainSegmentLoader's playlist for contentProtection, it might simplify the function to just accept those as parameters (audioMimeType, videoMimeType, and contentProtection). Can even make a function with the first part of this function's logic to do the initial work of getting the mime types from the loaders and then pass the result in directly.

if (!keySystemOptions) {
return keySystemOptions;
}

let videoMimeType;
let audioMimeType;

// if there is a mimeType associated with the audioSegmentLoader, then the audio
// and video mimeType and codec strings are already in the format we need to
// pass with the other key systems
if (audioSegmentLoader.mimeType_) {
videoMimeType = mainSegmentLoader.mimeType_;
gkatsev marked this conversation as resolved.
Show resolved Hide resolved
audioMimeType = audioSegmentLoader.mimeType_;

// if there is no audioSegmentLoader mimeType, then we have to create the
// the audio and video mimeType/codec strings from information extrapolated
// from the mainSegmentLoader mimeType (ex. 'video/mp4; codecs="mp4, avc1"' -->
// 'video/mp4; codecs="avc1"' and 'audio/mp4; codecs="mp4"')
} else {
const parsedMimeType = parseContentType(mainSegmentLoader.mimeType_);
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if we will see this behavior in the wild, but it is possible that, with setupEmeOptions called on selectedinitialmedia, if the source buffer's readyState is not yet open, then the mime types for the loaders will not be configured, and we may get an exception.

const codecs = parsedMimeType.parameters.codecs.split(',');

let audioCodec;
let videoCodec;

codecs.forEach(codec => {
codec = codec.trim();

if (isAudioCodec(codec)) {
brandonocasey marked this conversation as resolved.
Show resolved Hide resolved
audioCodec = codec;
} else if (isVideoCodec(codec)) {
videoCodec = codec;
}
});

videoMimeType = `${parsedMimeType.type}; codecs="${videoCodec}"`;
audioMimeType = `${parsedMimeType.type.replace('video', 'audio')}; codecs="${audioCodec}"`;
Copy link
Contributor

Choose a reason for hiding this comment

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

We must have gotten away with it before because we haven't seen DRM protected audio/video only streams, but we may want to consider that possibility.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, we did just recently get a question about that. I think, for now, we can continue not supporting it, but definitely something we should fix eventually.

}

// upsert the content types based on the selected playlist
const keySystemContentTypes = {};
const videoPlaylist = mainSegmentLoader.playlist_;

for (let keySystem in keySystemOptions) {
keySystemContentTypes[keySystem] = {
audioContentType: `audio/mp4; codecs="${audioPlaylist.attributes.CODECS}"`,
videoContentType: `video/mp4; codecs="${videoPlaylist.attributes.CODECS}"`
audioContentType: audioMimeType,
videoContentType: videoMimeType
};

if (videoPlaylist.contentProtection &&
Expand All @@ -172,16 +209,16 @@ const emeKeySystems = (keySystemOptions, videoPlaylist, audioPlaylist) => {
};

const setupEmeOptions = (hlsHandler) => {
if (hlsHandler.options_.sourceType !== 'dash') {
return;
}
const mainSegmentLoader = hlsHandler.masterPlaylistController_.mainSegmentLoader_;
const audioSegmentLoader = hlsHandler.masterPlaylistController_.audioSegmentLoader_;
Copy link
Member

Choose a reason for hiding this comment

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

Does this work for both muxed and umuxed content?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean by "this"?

Copy link
Member

Choose a reason for hiding this comment

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

The current changes really. Specifically, with muxed audio, we don't have a separate audio segment loader. We should make sure that this works in either case, or at least, doesn't break existing streams.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I guess it's unlikely to break existing streams because dash is always unmuxed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the content is muxed, then audioSegmentLoader is null and emeKeySystems() will pull the relevant audio/video codec info from the mainSegmentLoader.mimeType_ and format it into separate audio/video mime types accordingly. If it is unmuxed, then the audio/video codec info has already separated out and formatted by configureLoaderMimeTypes_() into the exact format we need to setup eme.


const player = videojs.players[hlsHandler.tech_.options_.playerId];

if (player.eme) {
const sourceOptions = emeKeySystems(
hlsHandler.source_.keySystems,
hlsHandler.playlists.media(),
hlsHandler.masterPlaylistController_.mediaTypes_.AUDIO.activePlaylistLoader.media()
mainSegmentLoader,
audioSegmentLoader
);

if (sourceOptions) {
Expand Down
Loading