Skip to content

Commit

Permalink
Merge pull request #7784 from google/dev-v2-r2.11.8
Browse files Browse the repository at this point in the history
r2.11.8
  • Loading branch information
ojw28 authored Aug 24, 2020
2 parents 5bfad37 + 1475f78 commit e822196
Show file tree
Hide file tree
Showing 19 changed files with 233 additions and 89 deletions.
26 changes: 26 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# Release notes #

### 2.11.8 (2020-08-25) ###

* Fix distorted playback of floating point audio when samples exceed the
`[-1, 1]` nominal range.
* MP4:
* Add support for `piff` and `isml` brands
([#7584](https://github.com/google/ExoPlayer/issues/7584)).
* Fix playback of very short MP4 files.
* FMP4:
* Fix `saiz` and `senc` sample count checks, resolving a "length
mismatch" `ParserException` when playing certain protected FMP4 streams
([#7592](https://github.com/google/ExoPlayer/issues/7592)).
* Fix handling of `traf` boxes containing multiple `sbgp` or `sgpd`
boxes.
* FLV: Ignore `SCRIPTDATA` segments with invalid name types, rather than
failing playback ([#7675](https://github.com/google/ExoPlayer/issues/7675)).
* Better infer the content type of `.ism` and `.isml` streaming URLs.
* Workaround an issue on Broadcom based devices where playbacks would not
transition to `STATE_ENDED` when using video tunneling mode
([#7647](https://github.com/google/ExoPlayer/issues/7647)).
* IMA extension: Upgrade to IMA SDK 3.19.4, bringing in a fix for setting the
media load timeout
([#7170](https://github.com/google/ExoPlayer/issues/7170)).
* Demo app: Fix playback of ClearKey protected content on API level 26 and
earlier ([#7735](https://github.com/google/ExoPlayer/issues/7735)).

### 2.11.7 (2020-06-29) ###

* IMA extension: Fix the way postroll "content complete" notifications are
Expand Down
4 changes: 2 additions & 2 deletions constants.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
// limitations under the License.
project.ext {
// ExoPlayer version and version code.
releaseVersion = '2.11.7'
releaseVersionCode = 2011007
releaseVersion = '2.11.8'
releaseVersionCode = 2011008
minSdkVersion = 16
appTargetSdkVersion = 29
targetSdkVersion = 28 // TODO: Bump once b/143232359 is resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.MediaDrm;
import android.net.Uri;
import android.os.Bundle;
import android.util.Pair;
Expand Down Expand Up @@ -47,6 +46,7 @@
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.MediaDrmCallback;
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.offline.DownloadHelper;
Expand Down Expand Up @@ -485,7 +485,7 @@ private MediaSource createLeafMediaSource(UriSample parameters) {
drmSessionManager = DrmSessionManager.getDummyDrmSessionManager();
} else if (Util.SDK_INT < 18) {
errorStringId = R.string.error_drm_unsupported_before_api_18;
} else if (!MediaDrm.isCryptoSchemeSupported(drmInfo.drmScheme)) {
} else if (!FrameworkMediaDrm.isCryptoSchemeSupported(drmInfo.drmScheme)) {
errorStringId = R.string.error_drm_unsupported_scheme;
} else {
MediaDrmCallback mediaDrmCallback =
Expand Down
2 changes: 1 addition & 1 deletion extensions/ima/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ android {
}

dependencies {
api 'com.google.ads.interactivemedia.v3:interactivemedia:3.19.0'
api 'com.google.ads.interactivemedia.v3:interactivemedia:3.19.4'
implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
implementation 'com.google.android.gms:play-services-ads-identifier:17.0.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {

/** The version of the library expressed as a string, for example "1.2.3". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public static final String VERSION = "2.11.7";
public static final String VERSION = "2.11.8";

/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final String VERSION_SLASHY = "ExoPlayerLib/2.11.7";
public static final String VERSION_SLASHY = "ExoPlayerLib/2.11.8";

/**
* The version of the library expressed as an integer, for example 1002003.
Expand All @@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
* integer version 123045006 (123-045-006).
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final int VERSION_INT = 2011007;
public static final int VERSION_INT = 2011008;

/**
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer;

/**
Expand Down Expand Up @@ -115,9 +116,13 @@ public void queueInput(ByteBuffer inputBuffer) {
// 32 bit floating point -> 16 bit resampling. Floating point values are in the range
// [-1.0, 1.0], so need to be scaled by Short.MAX_VALUE.
for (int i = position; i < limit; i += 4) {
short value = (short) (inputBuffer.getFloat(i) * Short.MAX_VALUE);
buffer.put((byte) (value & 0xFF));
buffer.put((byte) ((value >> 8) & 0xFF));
// Clamp to avoid integer overflow if the floating point values exceed their nominal range
// [Internal ref: b/161204847].
float floatValue =
Util.constrainValue(inputBuffer.getFloat(i), /* min= */ -1, /* max= */ 1);
short shortValue = (short) (floatValue * Short.MAX_VALUE);
buffer.put((byte) (shortValue & 0xFF));
buffer.put((byte) ((shortValue >> 8) & 0xFF));
}
break;
case C.ENCODING_PCM_16BIT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
private final MediaDrm mediaDrm;
private int referenceCount;

/**
* Returns whether the DRM scheme with the given UUID is supported on this device.
*
* @see MediaDrm#isCryptoSchemeSupported(UUID)
*/
public static boolean isCryptoSchemeSupported(UUID uuid) {
return MediaDrm.isCryptoSchemeSupported(adjustUuid(uuid));
}

/**
* Creates an instance with an initial reference count of 1. {@link #release()} must be called on
* the instance when it's no longer required.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.extractor.DummyTrackOutput;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.util.ArrayList;
Expand Down Expand Up @@ -65,11 +64,11 @@ protected boolean parseHeader(ParsableByteArray data) {
}

@Override
protected boolean parsePayload(ParsableByteArray data, long timeUs) throws ParserException {
protected boolean parsePayload(ParsableByteArray data, long timeUs) {
int nameType = readAmfType(data);
if (nameType != AMF_TYPE_STRING) {
// Should never happen.
throw new ParserException();
// Ignore segments with unexpected name type.
return false;
}
String name = readAmfString(data);
if (!NAME_METADATA.equals(name)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -735,12 +735,7 @@ private static void parseTraf(ContainerAtom traf, SparseArray<TrackBundle> track
parseSenc(senc.data, fragment);
}

LeafAtom sbgp = traf.getLeafAtomOfType(Atom.TYPE_sbgp);
LeafAtom sgpd = traf.getLeafAtomOfType(Atom.TYPE_sgpd);
if (sbgp != null && sgpd != null) {
parseSgpd(sbgp.data, sgpd.data, encryptionBox != null ? encryptionBox.schemeType : null,
fragment);
}
parseSampleGroups(traf, encryptionBox != null ? encryptionBox.schemeType : null, fragment);

int leafChildrenSize = traf.leafChildren.size();
for (int i = 0; i < leafChildrenSize; i++) {
Expand Down Expand Up @@ -798,8 +793,12 @@ private static void parseSaiz(TrackEncryptionBox encryptionBox, ParsableByteArra
int defaultSampleInfoSize = saiz.readUnsignedByte();

int sampleCount = saiz.readUnsignedIntToInt();
if (sampleCount != out.sampleCount) {
throw new ParserException("Length mismatch: " + sampleCount + ", " + out.sampleCount);
if (sampleCount > out.sampleCount) {
throw new ParserException(
"Saiz sample count "
+ sampleCount
+ " is greater than fragment sample count"
+ out.sampleCount);
}

int totalSize = 0;
Expand All @@ -815,7 +814,10 @@ private static void parseSaiz(TrackEncryptionBox encryptionBox, ParsableByteArra
totalSize += defaultSampleInfoSize * sampleCount;
Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, sampleCount, subsampleEncryption);
}
out.initEncryptionData(totalSize);
Arrays.fill(out.sampleHasSubsampleEncryptionTable, sampleCount, out.sampleCount, false);
if (totalSize > 0) {
out.initEncryptionData(totalSize);
}
}

/**
Expand Down Expand Up @@ -990,8 +992,10 @@ private static int parseTrun(
checkNonNegative(sampleDurationsPresent ? trun.readInt() : defaultSampleValues.duration);
int sampleSize =
checkNonNegative(sampleSizesPresent ? trun.readInt() : defaultSampleValues.size);
int sampleFlags = (i == 0 && firstSampleFlagsPresent) ? firstSampleFlags
: sampleFlagsPresent ? trun.readInt() : defaultSampleValues.flags;
int sampleFlags =
sampleFlagsPresent
? trun.readInt()
: (i == 0 && firstSampleFlagsPresent) ? firstSampleFlags : defaultSampleValues.flags;
if (sampleCompositionTimeOffsetsPresent) {
// The BMFF spec (ISO 14496-12) states that sample offsets should be unsigned integers in
// version 0 trun boxes, however a significant number of streams violate the spec and use
Expand Down Expand Up @@ -1055,37 +1059,60 @@ private static void parseSenc(ParsableByteArray senc, int offset, TrackFragment

boolean subsampleEncryption = (flags & 0x02 /* use_subsample_encryption */) != 0;
int sampleCount = senc.readUnsignedIntToInt();
if (sampleCount != out.sampleCount) {
throw new ParserException("Length mismatch: " + sampleCount + ", " + out.sampleCount);
if (sampleCount == 0) {
// Samples are unencrypted.
Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, out.sampleCount, false);
return;
} else if (sampleCount != out.sampleCount) {
throw new ParserException(
"Senc sample count "
+ sampleCount
+ " is different from fragment sample count"
+ out.sampleCount);
}

Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, sampleCount, subsampleEncryption);
out.initEncryptionData(senc.bytesLeft());
out.fillEncryptionData(senc);
}

private static void parseSgpd(ParsableByteArray sbgp, ParsableByteArray sgpd, String schemeType,
TrackFragment out) throws ParserException {
sbgp.setPosition(Atom.HEADER_SIZE);
int sbgpFullAtom = sbgp.readInt();
if (sbgp.readInt() != SAMPLE_GROUP_TYPE_seig) {
// Only seig grouping type is supported.
private static void parseSampleGroups(
ContainerAtom traf, @Nullable String schemeType, TrackFragment out) throws ParserException {
// Find sbgp and sgpd boxes with grouping_type == seig.
@Nullable ParsableByteArray sbgp = null;
@Nullable ParsableByteArray sgpd = null;
for (int i = 0; i < traf.leafChildren.size(); i++) {
LeafAtom leafAtom = traf.leafChildren.get(i);
ParsableByteArray leafAtomData = leafAtom.data;
if (leafAtom.type == Atom.TYPE_sbgp) {
leafAtomData.setPosition(Atom.FULL_HEADER_SIZE);
if (leafAtomData.readInt() == SAMPLE_GROUP_TYPE_seig) {
sbgp = leafAtomData;
}
} else if (leafAtom.type == Atom.TYPE_sgpd) {
leafAtomData.setPosition(Atom.FULL_HEADER_SIZE);
if (leafAtomData.readInt() == SAMPLE_GROUP_TYPE_seig) {
sgpd = leafAtomData;
}
}
}
if (sbgp == null || sgpd == null) {
return;
}
if (Atom.parseFullAtomVersion(sbgpFullAtom) == 1) {
sbgp.skipBytes(4); // default_length.

sbgp.setPosition(Atom.HEADER_SIZE);
int sbgpVersion = Atom.parseFullAtomVersion(sbgp.readInt());
sbgp.skipBytes(4); // grouping_type == seig.
if (sbgpVersion == 1) {
sbgp.skipBytes(4); // grouping_type_parameter.
}
if (sbgp.readInt() != 1) { // entry_count.
throw new ParserException("Entry count in sbgp != 1 (unsupported).");
}

sgpd.setPosition(Atom.HEADER_SIZE);
int sgpdFullAtom = sgpd.readInt();
if (sgpd.readInt() != SAMPLE_GROUP_TYPE_seig) {
// Only seig grouping type is supported.
return;
}
int sgpdVersion = Atom.parseFullAtomVersion(sgpdFullAtom);
int sgpdVersion = Atom.parseFullAtomVersion(sgpd.readInt());
sgpd.skipBytes(4); // grouping_type == seig.
if (sgpdVersion == 1) {
if (sgpd.readUnsignedInt() == 0) {
throw new ParserException("Variable length description in sgpd found (unsupported)");
Expand All @@ -1096,6 +1123,7 @@ private static void parseSgpd(ParsableByteArray sbgp, ParsableByteArray sgpd, St
if (sgpd.readUnsignedInt() != 1) { // entry_count.
throw new ParserException("Entry count in sgpd != 1 (unsupported).");
}

// CencSampleEncryptionInformationGroupEntry
sgpd.skipBytes(1); // reserved = 0.
int patternByte = sgpd.readUnsignedByte();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
0x71742020, // qt[space][space], Apple QuickTime
0x4d534e56, // MSNV, Sony PSP
0x64627931, // dby1, Dolby Vision
0x69736d6c, // isml
0x70696666, // piff
};

/**
Expand Down Expand Up @@ -101,7 +103,12 @@ private static boolean sniffInternal(ExtractorInput input, boolean fragmented)
// Read an atom header.
int headerSize = Atom.HEADER_SIZE;
buffer.reset(headerSize);
input.peekFully(buffer.data, 0, headerSize);
boolean success =
input.peekFully(buffer.data, 0, headerSize, /* allowEndOfInput= */ true);
if (!success) {
// We've reached the end of the file.
break;
}
long atomSize = buffer.readUnsignedInt();
int atomType = buffer.readInt();
if (atomSize == Atom.DEFINES_LARGE_SIZE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,10 @@ private EsInfo readEsInfo(ParsableByteArray data, int length) {
int descriptorTag = data.readUnsignedByte();
int descriptorLength = data.readUnsignedByte();
int positionOfNextDescriptor = data.getPosition() + descriptorLength;
if (positionOfNextDescriptor > descriptorsEndPosition) {
// Descriptor claims to extend past the end position. Skip it.
break;
}
if (descriptorTag == TS_PMT_DESC_REGISTRATION) { // registration_descriptor
long formatIdentifier = data.readUnsignedInt();
if (formatIdentifier == AC3_FORMAT_IDENTIFIER) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1937,6 +1937,9 @@ private static boolean codecNeedsEosPropagationWorkaround(MediaCodecInfo codecIn
String name = codecInfo.name;
return (Util.SDK_INT <= 25 && "OMX.rk.video_decoder.avc".equals(name))
|| (Util.SDK_INT <= 17 && "OMX.allwinner.video.decoder.avc".equals(name))
|| (Util.SDK_INT <= 29
&& ("OMX.broadcom.video_decoder.tunnel".equals(name)
|| "OMX.broadcom.video_decoder.tunnel.secure".equals(name)))
|| ("Amazon".equals(Util.MANUFACTURER) && "AFTS".equals(Util.MODEL) && codecInfo.secure);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public static void maybeSetFloat(MediaFormat format, String key, float value) {
*
* @param format The {@link MediaFormat} being configured.
* @param key The key to set.
* @param value The {@link byte[]} that will be wrapped to obtain the value.
* @param value The byte array that will be wrapped to obtain the value.
*/
public static void maybeSetByteBuffer(MediaFormat format, String key, @Nullable byte[] value) {
if (value != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public ConditionVariable() {
}

/**
* Creates an instance.
* Creates an instance, which starts closed.
*
* @param clock The {@link Clock} whose {@link Clock#elapsedRealtime()} method is used to
* determine when {@link #block(long)} should time out.
Expand Down
Loading

0 comments on commit e822196

Please sign in to comment.