mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Assume that encrypted content requires secure decoders in renderer support checks
Issue:#5568 PiperOrigin-RevId: 247973411
This commit is contained in:
parent
15688e3e6f
commit
50c9ae0efc
6 changed files with 21 additions and 70 deletions
|
|
@ -6,6 +6,8 @@
|
||||||
([#5868](https://github.com/google/ExoPlayer/issues/5868)).
|
([#5868](https://github.com/google/ExoPlayer/issues/5868)).
|
||||||
* Fix handling of line terminators in SHOUTcast ICY metadata
|
* Fix handling of line terminators in SHOUTcast ICY metadata
|
||||||
([#5876](https://github.com/google/ExoPlayer/issues/5876)).
|
([#5876](https://github.com/google/ExoPlayer/issues/5876)).
|
||||||
|
* Assume that encrypted content requires secure decoders in renderer support
|
||||||
|
checks ([#5568](https://github.com/google/ExoPlayer/issues/5568)).
|
||||||
* Offline: Add option to remove all downloads.
|
* Offline: Add option to remove all downloads.
|
||||||
* Decoders:
|
* Decoders:
|
||||||
* Prefer codecs that advertise format support over ones that do not, even if
|
* Prefer codecs that advertise format support over ones that do not, even if
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.PlayerMessage.Target;
|
import com.google.android.exoplayer2.PlayerMessage.Target;
|
||||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
|
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
|
||||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||||
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||||
|
|
@ -283,25 +282,10 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||||
// Assume the decoder outputs 16-bit PCM, unless the input is raw.
|
// Assume the decoder outputs 16-bit PCM, unless the input is raw.
|
||||||
return FORMAT_UNSUPPORTED_SUBTYPE;
|
return FORMAT_UNSUPPORTED_SUBTYPE;
|
||||||
}
|
}
|
||||||
boolean requiresSecureDecryption = false;
|
|
||||||
DrmInitData drmInitData = format.drmInitData;
|
|
||||||
if (drmInitData != null) {
|
|
||||||
for (int i = 0; i < drmInitData.schemeDataCount; i++) {
|
|
||||||
requiresSecureDecryption |= drmInitData.get(i).requiresSecureDecryption;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<MediaCodecInfo> decoderInfos =
|
List<MediaCodecInfo> decoderInfos =
|
||||||
getDecoderInfos(mediaCodecSelector, format, requiresSecureDecryption);
|
getDecoderInfos(mediaCodecSelector, format, /* requiresSecureDecoder= */ false);
|
||||||
if (decoderInfos.isEmpty()) {
|
if (decoderInfos.isEmpty()) {
|
||||||
return requiresSecureDecryption
|
return FORMAT_UNSUPPORTED_SUBTYPE;
|
||||||
&& !mediaCodecSelector
|
|
||||||
.getDecoderInfos(
|
|
||||||
format.sampleMimeType,
|
|
||||||
/* requiresSecureDecoder= */ false,
|
|
||||||
/* requiresTunnelingDecoder= */ false)
|
|
||||||
.isEmpty()
|
|
||||||
? FORMAT_UNSUPPORTED_DRM
|
|
||||||
: FORMAT_UNSUPPORTED_SUBTYPE;
|
|
||||||
}
|
}
|
||||||
if (!supportsFormatDrm) {
|
if (!supportsFormatDrm) {
|
||||||
return FORMAT_UNSUPPORTED_DRM;
|
return FORMAT_UNSUPPORTED_DRM;
|
||||||
|
|
|
||||||
|
|
@ -291,10 +291,6 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
||||||
public final String mimeType;
|
public final String mimeType;
|
||||||
/** The initialization data. May be null for scheme support checks only. */
|
/** The initialization data. May be null for scheme support checks only. */
|
||||||
public final @Nullable byte[] data;
|
public final @Nullable byte[] data;
|
||||||
/**
|
|
||||||
* Whether secure decryption is required.
|
|
||||||
*/
|
|
||||||
public final boolean requiresSecureDecryption;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param uuid The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is
|
* @param uuid The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is
|
||||||
|
|
@ -303,19 +299,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
||||||
* @param data See {@link #data}.
|
* @param data See {@link #data}.
|
||||||
*/
|
*/
|
||||||
public SchemeData(UUID uuid, String mimeType, @Nullable byte[] data) {
|
public SchemeData(UUID uuid, String mimeType, @Nullable byte[] data) {
|
||||||
this(uuid, mimeType, data, false);
|
this(uuid, /* licenseServerUrl= */ null, mimeType, data);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param uuid The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is
|
|
||||||
* universal (i.e. applies to all schemes).
|
|
||||||
* @param mimeType See {@link #mimeType}.
|
|
||||||
* @param data See {@link #data}.
|
|
||||||
* @param requiresSecureDecryption See {@link #requiresSecureDecryption}.
|
|
||||||
*/
|
|
||||||
public SchemeData(
|
|
||||||
UUID uuid, String mimeType, @Nullable byte[] data, boolean requiresSecureDecryption) {
|
|
||||||
this(uuid, /* licenseServerUrl= */ null, mimeType, data, requiresSecureDecryption);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -324,19 +308,13 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
||||||
* @param licenseServerUrl See {@link #licenseServerUrl}.
|
* @param licenseServerUrl See {@link #licenseServerUrl}.
|
||||||
* @param mimeType See {@link #mimeType}.
|
* @param mimeType See {@link #mimeType}.
|
||||||
* @param data See {@link #data}.
|
* @param data See {@link #data}.
|
||||||
* @param requiresSecureDecryption See {@link #requiresSecureDecryption}.
|
|
||||||
*/
|
*/
|
||||||
public SchemeData(
|
public SchemeData(
|
||||||
UUID uuid,
|
UUID uuid, @Nullable String licenseServerUrl, String mimeType, @Nullable byte[] data) {
|
||||||
@Nullable String licenseServerUrl,
|
|
||||||
String mimeType,
|
|
||||||
@Nullable byte[] data,
|
|
||||||
boolean requiresSecureDecryption) {
|
|
||||||
this.uuid = Assertions.checkNotNull(uuid);
|
this.uuid = Assertions.checkNotNull(uuid);
|
||||||
this.licenseServerUrl = licenseServerUrl;
|
this.licenseServerUrl = licenseServerUrl;
|
||||||
this.mimeType = Assertions.checkNotNull(mimeType);
|
this.mimeType = Assertions.checkNotNull(mimeType);
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.requiresSecureDecryption = requiresSecureDecryption;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ SchemeData(Parcel in) {
|
/* package */ SchemeData(Parcel in) {
|
||||||
|
|
@ -344,7 +322,6 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
||||||
licenseServerUrl = in.readString();
|
licenseServerUrl = in.readString();
|
||||||
mimeType = Util.castNonNull(in.readString());
|
mimeType = Util.castNonNull(in.readString());
|
||||||
data = in.createByteArray();
|
data = in.createByteArray();
|
||||||
requiresSecureDecryption = in.readByte() != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -381,7 +358,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
||||||
* @return The new instance.
|
* @return The new instance.
|
||||||
*/
|
*/
|
||||||
public SchemeData copyWithData(@Nullable byte[] data) {
|
public SchemeData copyWithData(@Nullable byte[] data) {
|
||||||
return new SchemeData(uuid, licenseServerUrl, mimeType, data, requiresSecureDecryption);
|
return new SchemeData(uuid, licenseServerUrl, mimeType, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -425,7 +402,6 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
|
||||||
dest.writeString(licenseServerUrl);
|
dest.writeString(licenseServerUrl);
|
||||||
dest.writeString(mimeType);
|
dest.writeString(mimeType);
|
||||||
dest.writeByteArray(data);
|
dest.writeByteArray(data);
|
||||||
dest.writeByte((byte) (requiresSecureDecryption ? 1 : 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<SchemeData> CREATOR =
|
public static final Parcelable.Creator<SchemeData> CREATOR =
|
||||||
|
|
|
||||||
|
|
@ -242,8 +242,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
|
||||||
for (int i = 0; i < schemeDatas.size(); i++) {
|
for (int i = 0; i < schemeDatas.size(); i++) {
|
||||||
SchemeData schemeData = schemeDatas.get(i);
|
SchemeData schemeData = schemeDatas.get(i);
|
||||||
byte[] schemeDataData = Util.castNonNull(schemeData.data);
|
byte[] schemeDataData = Util.castNonNull(schemeData.data);
|
||||||
if (schemeData.requiresSecureDecryption == firstSchemeData.requiresSecureDecryption
|
if (Util.areEqual(schemeData.mimeType, firstSchemeData.mimeType)
|
||||||
&& Util.areEqual(schemeData.mimeType, firstSchemeData.mimeType)
|
|
||||||
&& Util.areEqual(schemeData.licenseServerUrl, firstSchemeData.licenseServerUrl)
|
&& Util.areEqual(schemeData.licenseServerUrl, firstSchemeData.licenseServerUrl)
|
||||||
&& PsshAtomUtil.isPsshAtom(schemeDataData)) {
|
&& PsshAtomUtil.isPsshAtom(schemeDataData)) {
|
||||||
concatenatedDataLength += schemeDataData.length;
|
concatenatedDataLength += schemeDataData.length;
|
||||||
|
|
|
||||||
|
|
@ -298,29 +298,26 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
||||||
if (!MimeTypes.isVideo(mimeType)) {
|
if (!MimeTypes.isVideo(mimeType)) {
|
||||||
return FORMAT_UNSUPPORTED_TYPE;
|
return FORMAT_UNSUPPORTED_TYPE;
|
||||||
}
|
}
|
||||||
boolean requiresSecureDecryption = false;
|
|
||||||
DrmInitData drmInitData = format.drmInitData;
|
DrmInitData drmInitData = format.drmInitData;
|
||||||
if (drmInitData != null) {
|
// Assume encrypted content requires secure decoders.
|
||||||
for (int i = 0; i < drmInitData.schemeDataCount; i++) {
|
boolean requiresSecureDecryption = drmInitData != null;
|
||||||
requiresSecureDecryption |= drmInitData.get(i).requiresSecureDecryption;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<MediaCodecInfo> decoderInfos =
|
List<MediaCodecInfo> decoderInfos =
|
||||||
getDecoderInfos(
|
getDecoderInfos(
|
||||||
mediaCodecSelector,
|
mediaCodecSelector,
|
||||||
format,
|
format,
|
||||||
requiresSecureDecryption,
|
requiresSecureDecryption,
|
||||||
/* requiresTunnelingDecoder= */ false);
|
/* requiresTunnelingDecoder= */ false);
|
||||||
if (decoderInfos.isEmpty()) {
|
if (requiresSecureDecryption && decoderInfos.isEmpty()) {
|
||||||
return requiresSecureDecryption
|
// No secure decoders are available. Fall back to non-secure decoders.
|
||||||
&& !getDecoderInfos(
|
decoderInfos =
|
||||||
|
getDecoderInfos(
|
||||||
mediaCodecSelector,
|
mediaCodecSelector,
|
||||||
format,
|
format,
|
||||||
/* requiresSecureDecoder= */ false,
|
/* requiresSecureDecoder= */ false,
|
||||||
/* requiresTunnelingDecoder= */ false)
|
/* requiresTunnelingDecoder= */ false);
|
||||||
.isEmpty()
|
}
|
||||||
? FORMAT_UNSUPPORTED_DRM
|
if (decoderInfos.isEmpty()) {
|
||||||
: FORMAT_UNSUPPORTED_SUBTYPE;
|
return FORMAT_UNSUPPORTED_SUBTYPE;
|
||||||
}
|
}
|
||||||
if (!supportsFormatDrm(drmSessionManager, drmInitData)) {
|
if (!supportsFormatDrm(drmSessionManager, drmInitData)) {
|
||||||
return FORMAT_UNSUPPORTED_DRM;
|
return FORMAT_UNSUPPORTED_DRM;
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,6 @@ public class DashManifestParser extends DefaultHandler
|
||||||
String licenseServerUrl = null;
|
String licenseServerUrl = null;
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
UUID uuid = null;
|
UUID uuid = null;
|
||||||
boolean requiresSecureDecoder = false;
|
|
||||||
|
|
||||||
String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri");
|
String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri");
|
||||||
if (schemeIdUri != null) {
|
if (schemeIdUri != null) {
|
||||||
|
|
@ -431,9 +430,6 @@ public class DashManifestParser extends DefaultHandler
|
||||||
xpp.next();
|
xpp.next();
|
||||||
if (XmlPullParserUtil.isStartTag(xpp, "ms:laurl")) {
|
if (XmlPullParserUtil.isStartTag(xpp, "ms:laurl")) {
|
||||||
licenseServerUrl = xpp.getAttributeValue(null, "licenseUrl");
|
licenseServerUrl = xpp.getAttributeValue(null, "licenseUrl");
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "widevine:license")) {
|
|
||||||
String robustnessLevel = xpp.getAttributeValue(null, "robustness_level");
|
|
||||||
requiresSecureDecoder = robustnessLevel != null && robustnessLevel.startsWith("HW");
|
|
||||||
} else if (data == null
|
} else if (data == null
|
||||||
&& XmlPullParserUtil.isStartTagIgnorePrefix(xpp, "pssh")
|
&& XmlPullParserUtil.isStartTagIgnorePrefix(xpp, "pssh")
|
||||||
&& xpp.next() == XmlPullParser.TEXT) {
|
&& xpp.next() == XmlPullParser.TEXT) {
|
||||||
|
|
@ -457,10 +453,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
}
|
}
|
||||||
} while (!XmlPullParserUtil.isEndTag(xpp, "ContentProtection"));
|
} while (!XmlPullParserUtil.isEndTag(xpp, "ContentProtection"));
|
||||||
SchemeData schemeData =
|
SchemeData schemeData =
|
||||||
uuid != null
|
uuid != null ? new SchemeData(uuid, licenseServerUrl, MimeTypes.VIDEO_MP4, data) : null;
|
||||||
? new SchemeData(
|
|
||||||
uuid, licenseServerUrl, MimeTypes.VIDEO_MP4, data, requiresSecureDecoder)
|
|
||||||
: null;
|
|
||||||
return Pair.create(schemeType, schemeData);
|
return Pair.create(schemeType, schemeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue