Skip to content

Commit

Permalink
Fix transition from unencrypted to encrypted periods (#4383)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsilhavy committed Feb 6, 2024
1 parent deb8bf1 commit 86917b6
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 89 deletions.
2 changes: 1 addition & 1 deletion src/dash/DashAdapter.js
Expand Up @@ -996,7 +996,6 @@ function DashAdapter() {

mediaInfo.isFragmented = dashManifestModel.getIsFragmented(realAdaptation);
mediaInfo.isEmbedded = false;
mediaInfo.hasProtectedRepresentations = dashManifestModel.getAdaptationHasProtectedRepresentations(realAdaptation);
mediaInfo.adaptationSetSwitchingCompatibleIds = _getAdaptationSetSwitchingCompatibleIds(mediaInfo);

return mediaInfo;
Expand Down Expand Up @@ -1099,6 +1098,7 @@ function DashAdapter() {
streamInfo.duration = period.duration;
streamInfo.manifestInfo = convertMpdToManifestInfo(period.mpd);
streamInfo.isLast = period.mpd.manifest.Period.length === 1 || Math.abs((streamInfo.start + streamInfo.duration) - streamInfo.manifestInfo.duration) < THRESHOLD;
streamInfo.isEncrypted = period.isEncrypted;

return streamInfo;
}
Expand Down
133 changes: 69 additions & 64 deletions src/dash/models/DashManifestModel.js
Expand Up @@ -421,6 +421,11 @@ function DashManifestModel() {
return labelArray;
}

function isPeriodEncrypted(period) {
const contentProtectionElements = getContentProtectionByPeriod(period);

return contentProtectionElements && contentProtectionElements.length > 0;
}

function getContentProtectionByManifest(manifest) {
let protectionElements = [];
Expand All @@ -434,21 +439,33 @@ function DashManifestModel() {

if (manifest.hasOwnProperty(DashConstants.PERIOD) && manifest[DashConstants.PERIOD].length > 0) {
manifest[DashConstants.PERIOD].forEach((period) => {
const curr = _getContentProtectionFromElement(period);
const curr = getContentProtectionByPeriod(period)
protectionElements = protectionElements.concat(curr);

if (period.hasOwnProperty(DashConstants.ADAPTATION_SET) && period[DashConstants.ADAPTATION_SET].length > 0) {
period[DashConstants.ADAPTATION_SET].forEach((as) => {
const curr = _getContentProtectionFromElement(as);
protectionElements = protectionElements.concat(curr);
})
}
})
}

return protectionElements
}

function getContentProtectionByPeriod(period) {
let protectionElements = [];

if (!period) {
return protectionElements
}

const periodProtectionElements = _getContentProtectionFromElement(period);
protectionElements = protectionElements.concat(periodProtectionElements);

if (period.hasOwnProperty(DashConstants.ADAPTATION_SET) && period[DashConstants.ADAPTATION_SET].length > 0) {
period[DashConstants.ADAPTATION_SET].forEach((as) => {
const curr = _getContentProtectionFromElement(as);
protectionElements = protectionElements.concat(curr);
})
}

return protectionElements
}

function getContentProtectionByAdaptation(adaptation) {
return _getContentProtectionFromElement(adaptation);
Expand All @@ -460,25 +477,11 @@ function DashManifestModel() {
}

return element[DashConstants.CONTENT_PROTECTION].map(contentProtectionData => {
const cp = new ContentProtection();
cp.init(contentProtectionData);
return cp
});
}

function getAdaptationHasProtectedRepresentations(adaptation) {
if (adaptation && adaptation.hasOwnProperty(DashConstants.CONTENT_PROTECTION) && adaptation.ContentProtection.length > 0) {
return true;
}

let encryptedRepresentations = [];
if (adaptation.Representation && adaptation.Representation.length > 0) {
encryptedRepresentations = adaptation.Representation.some((rep) => {
return rep.hasOwnProperty(DashConstants.CONTENT_PROTECTION) && rep.ContentProtection.length > 0
})
}
const contentProtection = new ContentProtection();
contentProtection.init(contentProtectionData);

return encryptedRepresentations.length > 0;
return contentProtection
});
}

function getIsDynamic(manifest) {
Expand Down Expand Up @@ -842,6 +845,7 @@ function DashManifestModel() {
voPeriod.id = getPeriodId(realPeriod, i);
voPeriod.index = i;
voPeriod.mpd = mpd;
voPeriod.isEncrypted = isPeriodEncrypted(realPeriod);

if (realPeriod.hasOwnProperty(DashConstants.DURATION)) {
voPeriod.duration = realPeriod.duration;
Expand Down Expand Up @@ -1378,60 +1382,61 @@ function DashManifestModel() {
}

instance = {
getIsTypeOf,
getIsText,
getIsFragmented,
getProducerReferenceTimesForAdaptation,
getLanguageForAdaptation,
getViewpointForAdaptation,
getRolesForAdaptation,
getAccessibilityForAdaptation,
getAudioChannelConfigurationForAdaptation,
getAudioChannelConfigurationForRepresentation,
getAdaptationForIndex,
getAdaptationHasProtectedRepresentations,
getIndexForAdaptation,
getAdaptationForId,
getAdaptationForIndex,
getAdaptationsForPeriod,
getAdaptationsForType,
getRealPeriods,
getRealPeriodForIndex,
getAudioChannelConfigurationForAdaptation,
getAudioChannelConfigurationForRepresentation,
getAvailabilityStartTime,
getBandwidth,
getBaseURLsFromElement,
getBitrateListForAdaptation,
getCodec,
getSelectionPriority,
getMimeType,
getLabelsForAdaptation,
getContentProtectionByAdaptation,
getContentProtectionByManifest,
getIsDynamic,
getId,
hasProfile,
getContentProtectionByPeriod,
getContentSteering,
getDuration,
getBandwidth,
getManifestUpdatePeriod,
getPublishTime,
getRepresentationCount,
getBitrateListForAdaptation,
getRepresentationFor,
getRepresentationsForAdaptation,
getAdaptationsForPeriod,
getRegularPeriods,
getMpd,
getEventsForPeriod,
getEssentialPropertiesForRepresentation,
getEventStreamForAdaptationSet,
getEventStreamForRepresentation,
getUTCTimingSources,
getBaseURLsFromElement,
getRepresentationSortFunction,
getContentSteering,
getEventsForPeriod,
getId,
getIndexForAdaptation,
getIsDynamic,
getIsFragmented,
getIsText,
getIsTypeOf,
getLabelsForAdaptation,
getLanguageForAdaptation,
getLocation,
getManifestUpdatePeriod,
getMimeType,
getMpd,
getPatchLocation,
getSuggestedPresentationDelay,
getAvailabilityStartTime,
getServiceDescriptions,
getProducerReferenceTimesForAdaptation,
getPublishTime,
getRealPeriodForIndex,
getRealPeriods,
getRegularPeriods,
getRepresentationCount,
getRepresentationFor,
getRepresentationSortFunction,
getRepresentationsForAdaptation,
getRolesForAdaptation,
getSegmentAlignment,
getSelectionPriority,
getServiceDescriptions,
getSubSegmentAlignment,
getSuggestedPresentationDelay,
getSupplementalPropertiesForAdaptation,
getSupplementalPropertiesForRepresentation,
getUTCTimingSources,
getViewpointForAdaptation,
hasProfile,
isPeriodEncrypted,
setConfig
};

Expand Down
1 change: 0 additions & 1 deletion src/dash/vo/MediaInfo.js
Expand Up @@ -45,7 +45,6 @@ class MediaInfo {
this.index = null;
this.isEmbedded = null;
this.isFragmented = null;
this.hasProtectedRepresentations = false;
this.isText = false;
this.labels = null;
this.lang = null;
Expand Down
1 change: 1 addition & 0 deletions src/dash/vo/Period.js
Expand Up @@ -40,6 +40,7 @@ class Period {
this.start = NaN;
this.mpd = null;
this.nextPeriodId = null;
this.isEncrypted = false;
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/dash/vo/StreamInfo.js
Expand Up @@ -40,7 +40,8 @@ class StreamInfo {
this.duration = NaN;
this.manifestInfo = null;
this.isLast = true;
this.isEncrypted = false;
}
}

export default StreamInfo;
export default StreamInfo;
2 changes: 1 addition & 1 deletion src/streaming/controllers/StreamController.js
Expand Up @@ -654,7 +654,7 @@ function StreamController() {
// - none of the periods uses contentProtection.
// - AND changeType method is implemented
return (settings.get().streaming.buffer.reuseExistingSourceBuffers
&& (capabilities.isProtectionCompatible(previousStream, nextStream) || firstLicenseIsFetched)
&& (capabilities.isProtectionCompatible(previousStream.getStreamInfo(), nextStream.getStreamInfo()) || firstLicenseIsFetched)
&& (supportsChangeType && settings.get().streaming.buffer.useChangeTypeForTrackSwitch));
} catch (e) {
return false;
Expand Down
18 changes: 3 additions & 15 deletions src/streaming/utils/Capabilities.js
Expand Up @@ -59,23 +59,11 @@ function Capabilities() {
}
}

function isProtectionCompatible(previousStream, newStream) {
if (!newStream) {
function isProtectionCompatible(previousStreamInfo, newStreamInfo) {
if (!newStreamInfo) {
return true;
}
return _compareProtectionConfig(Constants.VIDEO, previousStream, newStream) && _compareProtectionConfig(Constants.AUDIO, previousStream, newStream);
}

function _compareProtectionConfig(type, previousStream, newStream) {
const previousMediaInfo = previousStream.getCurrentMediaInfoForType(type);
const newMediaInfo = newStream.getCurrentMediaInfoForType(type);

if (!previousMediaInfo || !newMediaInfo) {
return true;
}

// If the current period is unencrypted and the upcoming one is encrypted we need to reset sourcebuffers.
return !(!previousMediaInfo.hasProtectedRepresentations && newMediaInfo.hasProtectedRepresentations);
return !(!previousStreamInfo.isEncrypted && newStreamInfo.isEncrypted);
}

/**
Expand Down

0 comments on commit 86917b6

Please sign in to comment.