Skip to content

Commit

Permalink
Change filterNewPeriod to help with debugging
Browse files Browse the repository at this point in the history
While working on #1505 I made some changes to |filterNewPeriod|
to make it easier to see which streams were getting rejected
at a high-level.

This helped by making it easier to see which streams would
get rejected and which streams were accepted. This made it
easier to see the differences between which streams were
playable and not playable.

Change-Id: I0558de50552a614692488a6c78d46b5ea345bc7b
  • Loading branch information
vaage committed Aug 20, 2018
1 parent d2b727d commit c8a0959
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 96 deletions.
26 changes: 24 additions & 2 deletions lib/media/drm_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -1605,8 +1605,30 @@ shaka.media.DrmEngine.prototype.onPlay_ = function() {
* @param {!shaka.extern.Variant} variant
* @return {boolean}
**/
shaka.media.DrmEngine.prototype.isSupportedByKeySystem = function(variant) {
let keySystem = this.keySystem();
shaka.media.DrmEngine.prototype.supportsVariant = function(variant) {
/** @type {function (shaka.extern.Stream):boolean} */
const supportsStream = (stream) => {
// When null it means it supports everything - because we don't actually
// know what is supported.
if (this.supportedTypes_ == null) {
return true;
}

const streamType = shaka.util.MimeUtils.getFullType(
stream.mimeType, stream.codecs);

return this.supportedTypes_.some((type) => type == streamType);
};

if (variant.audio && !supportsStream(variant.audio)) {
return false;
}

if (variant.video && !supportsStream(variant.video)) {
return false;
}

const keySystem = this.keySystem();
return variant.drmInfos.length == 0 ||
variant.drmInfos.some((drmInfo) => drmInfo.keySystem == keySystem);
};
Expand Down
164 changes: 82 additions & 82 deletions lib/util/stream_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,31 +123,63 @@ shaka.util.StreamUtils.filterNewPeriod = function(
const StreamUtils = shaka.util.StreamUtils;

if (activeAudio) {
goog.asserts.assert(
shaka.util.StreamUtils.isAudio(activeAudio),
'Audio streams must have the audio type.');
goog.asserts.assert(StreamUtils.isAudio(activeAudio),
'Audio streams must have the audio type.');
}

if (activeVideo) {
goog.asserts.assert(
shaka.util.StreamUtils.isVideo(activeVideo),
'Video streams must have the video type.');
goog.asserts.assert(StreamUtils.isVideo(activeVideo),
'Video streams must have the video type.');
}

// Filter variants.
period.variants = period.variants.filter(function(variant) {
let keep = StreamUtils.isVariantCompatible_(
variant,
drmEngine,
activeAudio,
activeVideo);
period.variants = period.variants.filter((variant) => {
if (drmEngine && drmEngine.initialized()) {
if (!drmEngine.supportsVariant(variant)) {
shaka.log.debug('Dropping variant - not compatible with key system',
variant);
return false;
}
}

if (!keep) {
shaka.log.debug('Dropping Variant (not compatible with key system, ' +
'platform, or active Variant)', variant);
const audio = variant.audio;
const video = variant.video;

if (audio && !shaka.media.MediaSourceEngine.isStreamSupported(audio)) {
shaka.log.debug('Dropping variant - audio not compatible with platform',
StreamUtils.getStreamSummaryString_(audio));
return false;
}

return keep;
if (video && !shaka.media.MediaSourceEngine.isStreamSupported(video)) {
shaka.log.debug('Dropping variant - video not compatible with platform',
StreamUtils.getStreamSummaryString_(video));
return false;
}

if (audio && activeAudio) {
if (!StreamUtils.areStreamsCompatible_(audio, activeAudio)) {
shaka.log.debug('Droping variant - not compatible with active audio',
'active audio',
StreamUtils.getStreamSummaryString_(activeAudio),
'variant.audio',
StreamUtils.getStreamSummaryString_(audio));
return false;
}
}

if (video && activeVideo) {
if (!StreamUtils.areStreamsCompatible_(video, activeVideo)) {
shaka.log.debug('Droping variant - not compatible with active video',
'active video',
StreamUtils.getStreamSummaryString_(activeVideo),
'variant.video',
StreamUtils.getStreamSummaryString_(video));
return false;
}
}

return true;
});

// Filter text streams.
Expand All @@ -167,83 +199,25 @@ shaka.util.StreamUtils.filterNewPeriod = function(


/**
* Checks if a stream is compatible with the key system, platform,
* and active stream.
* This does not check if the stream is supported by the chosen key system.
*
* @param {?shaka.extern.Stream} stream A non-text stream to check.
* @param {shaka.media.DrmEngine} drmEngine
* @param {?shaka.extern.Stream} activeStream
* @param {shaka.extern.Stream} s0
* @param {shaka.extern.Stream} s1
* @return {boolean}
* @private
*/
shaka.util.StreamUtils.isStreamCompatible_ =
function(stream, drmEngine, activeStream) {
if (!stream) return true;

const ContentType = shaka.util.ManifestParserUtils.ContentType;
goog.asserts.assert(stream.type != ContentType.TEXT,
'Should not be called on a text stream!');

let drmSupportedMimeTypes = null;
if (drmEngine && drmEngine.initialized()) {
drmSupportedMimeTypes = drmEngine.getSupportedTypes();
}

// Check if the stream can be played by the platform.
let fullMimeType = shaka.util.MimeUtils.getFullType(
stream.mimeType, stream.codecs);

if (!shaka.media.MediaSourceEngine.isStreamSupported(stream)) {
return false;
}

// Check if the stream can be handled by the key system.
// There's no need to check that the stream is supported by the
// chosen key system since the caller has already verified that.
if (drmSupportedMimeTypes && stream.encrypted &&
drmSupportedMimeTypes.indexOf(fullMimeType) < 0) {
return false;
}

// Lastly, check if the active stream can switch to the stream.
shaka.util.StreamUtils.areStreamsCompatible_ = function(s0, s1) {
// Basic mime types and basic codecs need to match.
// For example, we can't adapt between WebM and MP4,
// nor can we adapt between mp4a.* to ec-3.
// We can switch between text types on the fly,
// so don't run this check on text.
if (activeStream) {
if (stream.mimeType != activeStream.mimeType ||
stream.codecs.split('.')[0] != activeStream.codecs.split('.')[0]) {
return false;
}
if (s0.mimeType != s1.mimeType) {
return false;
}

return true;
};


/**
* Checks if a variant is compatible with the key system, platform,
* and active stream.
*
* @param {!shaka.extern.Variant} variant
* @param {shaka.media.DrmEngine} drmEngine
* @param {?shaka.extern.Stream} activeAudio
* @param {?shaka.extern.Stream} activeVideo
* @return {boolean}
* @private
*/
shaka.util.StreamUtils.isVariantCompatible_ =
function(variant, drmEngine, activeAudio, activeVideo) {
if (drmEngine && drmEngine.initialized()) {
if (!drmEngine.isSupportedByKeySystem(variant)) return false;
if (s0.codecs.split('.')[0] != s1.codecs.split('.')[0]) {
return false;
}

let isStreamCompatible = shaka.util.StreamUtils.isStreamCompatible_;

return isStreamCompatible(variant.audio, drmEngine, activeAudio) &&
isStreamCompatible(variant.video, drmEngine, activeVideo);
return true;
};


Expand Down Expand Up @@ -978,3 +952,29 @@ shaka.util.StreamUtils.getVariantStreams = function(variant) {

return streams;
};


/**
* @param {shaka.extern.Stream} stream
* @return {string}
* @private
*/
shaka.util.StreamUtils.getStreamSummaryString_ = function(stream) {
if (shaka.util.StreamUtils.isAudio(stream)) {
return 'type=audio' +
' codecs=' + stream.codecs +
' bandwidth='+ stream.bandwidth +
' channelsCount=' + stream.channelsCount;
}

if (shaka.util.StreamUtils.isVideo(stream)) {
return 'type=video' +
' codecs=' + stream.codecs +
' bandwidth=' + stream.bandwidth +
' frameRate=' + stream.frameRate +
' width=' + stream.width +
' height=' + stream.height;
}

return 'unexpected stream type';
};
7 changes: 6 additions & 1 deletion test/player_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2724,7 +2724,12 @@ describe('Player', function() {
// because of MSE support. We are specifically testing EME-based
// filtering of codecs.
expect(MediaSource.isTypeSupported('video/unsupported')).toBe(true);
// FakeDrmEngine's getSupportedTypes() returns video/mp4 by default.

// Make sure that drm engine will reject the variant with an unsupported
// video mime type.
drmEngine.supportsVariant.and.callFake((variant) => {
return variant.video.mimeType != 'video/unsupported';
});

await setupPlayer();
let tracks = player.getVariantTracks();
Expand Down
15 changes: 4 additions & 11 deletions test/test/util/fake_drm_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@ shaka.test.FakeDrmEngine = class {
this.getSessionIds = jasmine.createSpy('getSessionIds');
this.getSessionIds.and.callFake(() => this.offlineSessions_);

/**
* See |shaka.test.ManifestGenerator.protototype.createStream|.
* @type {!jasmine.Spy}
*/
this.getSupportedTypes = jasmine.createSpy('getSupportedTypes');
this.getSupportedTypes.and.returnValue(['video/mp4; codecs="avc1.4d401f"']);

/** @type {!jasmine.Spy} */
this.init = jasmine.createSpy('init');
this.init.and.returnValue(resolved);
Expand All @@ -80,13 +73,13 @@ shaka.test.FakeDrmEngine = class {
this.initialized = jasmine.createSpy('initialized');
this.initialized.and.returnValue(true);

/** @type {!jasmine.Spy} */
this.isSupportedByKeySystem = jasmine.createSpy('isSupportedByKeySystem');
this.isSupportedByKeySystem.and.returnValue(true);

/** @type {!jasmine.Spy} */
this.keySystem = jasmine.createSpy('keySystem');
this.keySystem.and.returnValue('com.example.fake');

/** @type {!jasmine.Spy} */
this.supportsVariant = jasmine.createSpy('supportsVariant');
this.supportsVariant.and.returnValue(true);
}

/**
Expand Down

0 comments on commit c8a0959

Please sign in to comment.