Skip to content

Commit

Permalink
fix: support automatic configuration of audio and video only DRM sour…
Browse files Browse the repository at this point in the history
…ces (#1090)
  • Loading branch information
gesinger authored Apr 5, 2021
1 parent 99480d5 commit 9b116ce
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 28 deletions.
9 changes: 3 additions & 6 deletions docs/supported-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ not meant serve as an exhaustive list.
* Any browser supported resolution (e.g., 4k)
* Any browser supported framerate (e.g., 60fps)
* [DRM] via [videojs-contrib-eme]
* Audio only (non DRM)
* Video only (non DRM)
* Audio only (non DASH)
* Video only (non DASH)
* In-manifest [WebVTT] subtitles are automatically translated into standard HTML5 subtitle
tracks
* [AES-128] segment encryption
Expand Down Expand Up @@ -95,10 +95,6 @@ supported when packaged within [TS].
* [Dolby Digital] Audio (AC-3)
* [Dolby Digital Plus] (E-AC-3)

### General Missing Features

* Audio/video only DRM streams

### HLS Missing Features

Note: features for low latency HLS in the [2nd edition of HTTP Live Streaming] are on the
Expand Down Expand Up @@ -141,6 +137,7 @@ features in the DASH specification that are not yet implemented in VHS:
Note that many of the following are parsed by [mpd-parser] but are either not yet used, or
simply take on their default values (in the case where they have valid defaults).

* Audio and video only streams
* Audio rendition switching
* Each video rendition is paired with an audio rendition for the duration of playback.
* MPD
Expand Down
50 changes: 28 additions & 22 deletions src/videojs-http-streaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ import {
comparePlaylistBandwidth,
comparePlaylistResolution
} from './playlist-selectors.js';
import {isAudioCodec, isVideoCodec, browserSupportsCodec} from '@videojs/vhs-utils/es/codecs.js';
import {
browserSupportsCodec,
getMimeForCodec,
parseCodecs
} from '@videojs/vhs-utils/es/codecs.js';
import { unwrapCodecList } from './util/codecs.js';
import logger from './util/logger';
import {SAFE_TIME_DELTA} from './ranges';

Expand Down Expand Up @@ -127,47 +132,48 @@ Vhs.canPlaySource = function() {
'your player\'s techOrder.');
};

const emeKeySystems = (keySystemOptions, videoPlaylist, audioPlaylist) => {
const emeKeySystems = (keySystemOptions, mainPlaylist, audioPlaylist) => {
if (!keySystemOptions) {
return keySystemOptions;
}

const codecs = {
video: videoPlaylist && videoPlaylist.attributes && videoPlaylist.attributes.CODECS,
audio: audioPlaylist && audioPlaylist.attributes && audioPlaylist.attributes.CODECS
};
let codecs = {};

if (!codecs.audio && codecs.video && codecs.video.split(',').length > 1) {
codecs.video.split(',').forEach(function(codec) {
codec = codec.trim();
if (mainPlaylist && mainPlaylist.attributes && mainPlaylist.attributes.CODECS) {
codecs = unwrapCodecList(parseCodecs(mainPlaylist.attributes.CODECS));
}

if (isAudioCodec(codec)) {
codecs.audio = codec;
} else if (isVideoCodec(codec)) {
codecs.video = codec;
}
});
if (audioPlaylist && audioPlaylist.attributes && audioPlaylist.attributes.CODECS) {
codecs.audio = audioPlaylist.attributes.CODECS;
}
const videoContentType = codecs.video ? `video/mp4;codecs="${codecs.video}"` : null;
const audioContentType = codecs.audio ? `audio/mp4;codecs="${codecs.audio}"` : null;

const videoContentType = getMimeForCodec(codecs.video);
const audioContentType = getMimeForCodec(codecs.audio);

// upsert the content types based on the selected playlist
const keySystemContentTypes = {};

for (const keySystem in keySystemOptions) {
keySystemContentTypes[keySystem] = {audioContentType, videoContentType};
keySystemContentTypes[keySystem] = {};

if (audioContentType) {
keySystemContentTypes[keySystem].audioContentType = audioContentType;
}
if (videoContentType) {
keySystemContentTypes[keySystem].videoContentType = videoContentType;
}

// Default to using the video playlist's PSSH even though they may be different, as
// videojs-contrib-eme will only accept one in the options.
//
// This shouldn't be an issue for most cases as early intialization will handle all
// unique PSSH values, and if they aren't, then encrypted events should have the
// specific information needed for the unique license.
if (videoPlaylist.contentProtection &&
videoPlaylist.contentProtection[keySystem] &&
videoPlaylist.contentProtection[keySystem].pssh) {
if (mainPlaylist.contentProtection &&
mainPlaylist.contentProtection[keySystem] &&
mainPlaylist.contentProtection[keySystem].pssh) {
keySystemContentTypes[keySystem].pssh =
videoPlaylist.contentProtection[keySystem].pssh;
mainPlaylist.contentProtection[keySystem].pssh;
}

// videojs-contrib-eme accepts the option of specifying: 'com.some.cdm': 'url'
Expand Down
55 changes: 55 additions & 0 deletions test/videojs-http-streaming.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5861,6 +5861,61 @@ QUnit.test('emeKeySystems adds content types for all keySystems', function(asser
);
});

QUnit.test('emeKeySystems supports audio only', function(assert) {
assert.deepEqual(
emeKeySystems(
{ keySystem1: {}, keySystem2: {} },
{ attributes: { CODECS: 'mp4a.40.2c' } },
),
{
keySystem1: {
audioContentType: 'audio/mp4;codecs="mp4a.40.2c"'
},
keySystem2: {
audioContentType: 'audio/mp4;codecs="mp4a.40.2c"'
}
},
'added content type'
);
});

QUnit.test('emeKeySystems supports external audio only', function(assert) {
assert.deepEqual(
emeKeySystems(
{ keySystem1: {}, keySystem2: {} },
{ attributes: {} },
{ attributes: { CODECS: 'mp4a.40.2c' } },
),
{
keySystem1: {
audioContentType: 'audio/mp4;codecs="mp4a.40.2c"'
},
keySystem2: {
audioContentType: 'audio/mp4;codecs="mp4a.40.2c"'
}
},
'added content type'
);
});

QUnit.test('emeKeySystems supports video only', function(assert) {
assert.deepEqual(
emeKeySystems(
{ keySystem1: {}, keySystem2: {} },
{ attributes: { CODECS: 'avc1.420015' } },
),
{
keySystem1: {
videoContentType: 'video/mp4;codecs="avc1.420015"'
},
keySystem2: {
videoContentType: 'video/mp4;codecs="avc1.420015"'
}
},
'added content type'
);
});

QUnit.test('emeKeySystems retains non content type properties', function(assert) {
assert.deepEqual(
emeKeySystems(
Expand Down

0 comments on commit 9b116ce

Please sign in to comment.