Tweak recently merged pull requests

This commit is contained in:
Oliver Woodman 2017-10-13 20:40:08 +01:00
parent e6d8e5b096
commit 12513e9898
9 changed files with 54 additions and 119 deletions

View File

@ -349,7 +349,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
// If there is no scheme information, assume patternless AES-CTR. // If there is no scheme information, assume patternless AES-CTR.
return true; return true;
} else if (C.CENC_TYPE_cbc1.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType) } else if (C.CENC_TYPE_cbc1.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType)
|| C.CENC_TYPE_cens.equals(schemeType)) { || C.CENC_TYPE_cens.equals(schemeType)) {
// AES-CBC and pattern encryption are supported on API 24 onwards. // AES-CBC and pattern encryption are supported on API 24 onwards.
return Util.SDK_INT >= 24; return Util.SDK_INT >= 24;
} }
@ -357,7 +357,6 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
return true; return true;
} }
@Override @Override
public DrmSession<T> acquireSession(Looper playbackLooper, DrmInitData drmInitData) { public DrmSession<T> acquireSession(Looper playbackLooper, DrmInitData drmInitData) {
Assertions.checkState(this.playbackLooper == null || this.playbackLooper == playbackLooper); Assertions.checkState(this.playbackLooper == null || this.playbackLooper == playbackLooper);
@ -462,34 +461,35 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* @return The extracted {@link SchemeData}, or null if no suitable data is present. * @return The extracted {@link SchemeData}, or null if no suitable data is present.
*/ */
private static SchemeData getSchemeData(DrmInitData drmInitData, UUID uuid) { private static SchemeData getSchemeData(DrmInitData drmInitData, UUID uuid) {
List<SchemeData> schemeDatas = new ArrayList<>(); // Look for matching scheme data (matching the Common PSSH box for ClearKey).
// Look for matching PSSH boxes, or the common box in the case of ClearKey List<SchemeData> matchingSchemeDatas = new ArrayList<>(drmInitData.schemeDataCount);
for (int i = 0; i < drmInitData.schemeDataCount; ++i) { for (int i = 0; i < drmInitData.schemeDataCount; i++) {
SchemeData schemeData = drmInitData.get(i); SchemeData schemeData = drmInitData.get(i);
if (schemeData.matches(uuid) if (schemeData.matches(uuid)
|| (C.CLEARKEY_UUID.equals(uuid) && schemeData.matches(C.COMMON_PSSH_UUID))) { || (C.CLEARKEY_UUID.equals(uuid) && schemeData.matches(C.COMMON_PSSH_UUID))) {
schemeDatas.add(schemeData); matchingSchemeDatas.add(schemeData);
} }
} }
if (schemeDatas.isEmpty()) { if (matchingSchemeDatas.isEmpty()) {
return null; return null;
} }
// For Widevine, we prefer v1 init data on M and higher, v0 for lower // For Widevine PSSH boxes, prefer V1 boxes from API 23 and V0 before.
if (C.WIDEVINE_UUID.equals(uuid)) { if (C.WIDEVINE_UUID.equals(uuid)) {
for (SchemeData schemeData : schemeDatas ) { for (int i = 0; i < matchingSchemeDatas.size(); i++) {
int version = PsshAtomUtil.parseVersion(schemeData.data); SchemeData matchingSchemeData = matchingSchemeDatas.get(i);
int version = PsshAtomUtil.parseVersion(matchingSchemeData.data);
if (Util.SDK_INT < 23 && version == 0) { if (Util.SDK_INT < 23 && version == 0) {
return schemeData; return matchingSchemeData;
} else if (Util.SDK_INT >= 23 && version == 1) { } else if (Util.SDK_INT >= 23 && version == 1) {
return schemeData; return matchingSchemeData;
} }
} }
} }
// If we don't have any special handling for this system, we take the first scheme data found // If we don't have any special handling, prefer the first matching scheme data.
return schemeDatas.get(0); return matchingSchemeDatas.get(0);
} }
private static byte[] getSchemeInitData(SchemeData data, UUID uuid) { private static byte[] getSchemeInitData(SchemeData data, UUID uuid) {

View File

@ -22,8 +22,6 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@ -80,7 +78,6 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
// Sorting ensures that universal scheme data (i.e. data that applies to all schemes) is matched // Sorting ensures that universal scheme data (i.e. data that applies to all schemes) is matched
// last. It's also required by the equals and hashcode implementations. // last. It's also required by the equals and hashcode implementations.
Arrays.sort(schemeDatas, this); Arrays.sort(schemeDatas, this);
this.schemeDatas = schemeDatas; this.schemeDatas = schemeDatas;
schemeDataCount = schemeDatas.length; schemeDataCount = schemeDatas.length;
} }
@ -94,7 +91,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
/** /**
* Retrieves data for a given DRM scheme, specified by its UUID. * Retrieves data for a given DRM scheme, specified by its UUID.
* *
* @deprecated This will only get the first data found for the scheme. * @deprecated Use {@link #get(int)} and {@link SchemeData#matches(UUID)} instead.
* @param uuid The DRM scheme's UUID. * @param uuid The DRM scheme's UUID.
* @return The initialization data for the scheme, or null if the scheme is not supported. * @return The initialization data for the scheme, or null if the scheme is not supported.
*/ */
@ -111,8 +108,8 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
/** /**
* Retrieves the {@link SchemeData} at a given index. * Retrieves the {@link SchemeData} at a given index.
* *
* @param index index of the scheme to return. Must not exceed {@link #schemeDataCount}. * @param index The index of the scheme to return. Must not exceed {@link #schemeDataCount}.
* @return The {@link SchemeData} at the index. * @return The {@link SchemeData} at the specified index.
*/ */
public SchemeData get(int index) { public SchemeData get(int index) {
return schemeDatas[index]; return schemeDatas[index];

View File

@ -16,7 +16,6 @@
package com.google.android.exoplayer2.extractor.mp4; package com.google.android.exoplayer2.extractor.mp4;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.UUID; import java.util.UUID;
@ -96,10 +95,10 @@ public final class PsshAtomUtil {
/** /**
* Parses the version from a PSSH atom. Version 0 and 1 PSSH atoms are supported. * Parses the version from a PSSH atom. Version 0 and 1 PSSH atoms are supported.
* <p> * <p>
* The UUID is only parsed if the data is a valid PSSH atom. * The version is only parsed if the data is a valid PSSH atom.
* *
* @param atom The atom to parse. * @param atom The atom to parse.
* @return The parsed UUID. -1 if the input is not a valid PSSH atom, or if the PSSH atom has * @return The parsed version. -1 if the input is not a valid PSSH atom, or if the PSSH atom has
* an unsupported version. * an unsupported version.
*/ */
public static int parseVersion(byte[] atom) { public static int parseVersion(byte[] atom) {
@ -130,16 +129,15 @@ public final class PsshAtomUtil {
Log.w(TAG, "UUID mismatch. Expected: " + uuid + ", got: " + parsedAtom.uuid + "."); Log.w(TAG, "UUID mismatch. Expected: " + uuid + ", got: " + parsedAtom.uuid + ".");
return null; return null;
} }
return parsedAtom.data; return parsedAtom.schemeData;
} }
/** /**
* Parses the UUID and scheme specific data from a PSSH atom. Version 0 and 1 PSSH atoms are * Parses a PSSH atom. Version 0 and 1 PSSH atoms are supported.
* supported.
* *
* @param atom The atom to parse. * @param atom The atom to parse.
* @return A pair consisting of the parsed UUID and scheme specific data. Null if the input is * @return The parsed PSSH atom. Null if the input is not a valid PSSH atom, or if the PSSH atom
* not a valid PSSH atom, or if the PSSH atom has an unsupported version. * has an unsupported version.
*/ */
// TODO: Support parsing of the key ids for version 1 PSSH atoms. // TODO: Support parsing of the key ids for version 1 PSSH atoms.
private static PsshAtom parsePsshAtom(byte[] atom) { private static PsshAtom parsePsshAtom(byte[] atom) {
@ -179,15 +177,19 @@ public final class PsshAtomUtil {
return new PsshAtom(uuid, atomVersion, data); return new PsshAtom(uuid, atomVersion, data);
} }
// TODO: Consider exposing this and making parsePsshAtom public.
private static class PsshAtom { private static class PsshAtom {
final UUID uuid;
final int version;
final byte[] data;
PsshAtom(final UUID uuid, final int version, final byte[] data) { private final UUID uuid;
private final int version;
private final byte[] schemeData;
public PsshAtom(UUID uuid, int version, byte[] schemeData) {
this.uuid = uuid; this.uuid = uuid;
this.version = version; this.version = version;
this.data = data; this.schemeData = schemeData;
} }
} }
} }

View File

@ -20,20 +20,18 @@ import static com.google.android.exoplayer2.C.UUID_NIL;
import static com.google.android.exoplayer2.C.WIDEVINE_UUID; import static com.google.android.exoplayer2.C.WIDEVINE_UUID;
import static com.google.android.exoplayer2.util.MimeTypes.VIDEO_MP4; import static com.google.android.exoplayer2.util.MimeTypes.VIDEO_MP4;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.os.Parcel; import android.os.Parcel;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
/** /**
* Unit test for {@link DrmInitData}. * Unit test for {@link DrmInitData}.
*/ */
@ -101,7 +99,7 @@ public class DrmInitDataTest {
@Test @Test
@Deprecated @Deprecated
public void testGet() { public void testGetByUuid() {
// Basic matching. // Basic matching.
DrmInitData testInitData = new DrmInitData(DATA_1, DATA_2); DrmInitData testInitData = new DrmInitData(DATA_1, DATA_2);
assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1); assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1);
@ -134,16 +132,14 @@ public class DrmInitDataTest {
} }
@Test @Test
public void testDuplicateSchemeData() { public void testSchemeDatasWithSameUuid() {
DrmInitData testInitData = new DrmInitData(DATA_1, DATA_1); DrmInitData testInitData = new DrmInitData(DATA_1, DATA_1B);
assertThat(testInitData.schemeDataCount).isEqualTo(2); assertThat(testInitData.schemeDataCount).isEqualTo(2);
// Deprecated get method should return first entry.
testInitData = new DrmInitData(DATA_1, DATA_2, DATA_1B);
assertThat(testInitData.schemeDataCount).isEqualTo(3);
assertThat(getAllSchemeData(testInitData)).containsAllOf(DATA_1, DATA_1B, DATA_2);
// Deprecated get method should return first entry
assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1); assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1);
assertThat(testInitData.get(PLAYREADY_UUID)).isEqualTo(DATA_2); // Test retrieval of first and second entry.
assertThat(testInitData.get(0)).isEqualTo(DATA_1);
assertThat(testInitData.get(1)).isEqualTo(DATA_1B);
} }
@Test @Test

View File

@ -16,23 +16,19 @@
package com.google.android.exoplayer2.source.hls.playlist; package com.google.android.exoplayer2.source.hls.playlist;
import android.net.Uri; import android.net.Uri;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import junit.framework.TestCase;
/** /**
* Test for {@link HlsMasterPlaylistParserTest} * Test for {@link HlsMasterPlaylistParserTest}.
*/ */
public class HlsMasterPlaylistParserTest extends TestCase { public class HlsMasterPlaylistParserTest extends TestCase {
@ -151,44 +147,6 @@ public class HlsMasterPlaylistParserTest extends TestCase {
assertEquals(Collections.emptyList(), playlist.muxedCaptionFormats); assertEquals(Collections.emptyList(), playlist.muxedCaptionFormats);
} }
public void testReorderedVariantCopy() throws IOException {
HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, MASTER_PLAYLIST);
HlsMasterPlaylist nonReorderedPlaylist =
playlist.copyWithReorderedVariants(new Comparator<HlsMasterPlaylist.HlsUrl>() {
@Override
public int compare(HlsMasterPlaylist.HlsUrl url1, HlsMasterPlaylist.HlsUrl url2) {
return 0;
}
});
assertEquals(playlist.variants, nonReorderedPlaylist.variants);
HlsMasterPlaylist.HlsUrl preferred = null;
for (HlsMasterPlaylist.HlsUrl url : playlist.variants) {
if (preferred == null || url.format.bitrate > preferred.format.bitrate) {
preferred = url;
}
}
assertNotNull(preferred);
final Comparator comparator = Collections.reverseOrder(new Comparator<HlsMasterPlaylist.HlsUrl>() {
@Override
public int compare(HlsMasterPlaylist.HlsUrl url1, HlsMasterPlaylist.HlsUrl url2) {
if (url1.format.bitrate > url2.format.bitrate) {
return 1;
}
if (url2.format.bitrate > url1.format.bitrate) {
return -1;
}
return 0;
}
});
HlsMasterPlaylist reorderedPlaylist = playlist.copyWithReorderedVariants(comparator);
assertEquals(reorderedPlaylist.variants.get(0), preferred);
}
private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString) private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString)
throws IOException { throws IOException {
Uri playlistUri = Uri.parse(uri); Uri playlistUri = Uri.parse(uri);

View File

@ -27,7 +27,7 @@ import java.util.Locale;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
* Test for {@link HlsMediaPlaylistParserTest} * Test for {@link HlsMediaPlaylistParserTest}.
*/ */
public class HlsMediaPlaylistParserTest extends TestCase { public class HlsMediaPlaylistParserTest extends TestCase {

View File

@ -76,13 +76,14 @@ public final class HlsMediaSource implements MediaSource,
public HlsMediaSource(Uri manifestUri, HlsDataSourceFactory dataSourceFactory, public HlsMediaSource(Uri manifestUri, HlsDataSourceFactory dataSourceFactory,
int minLoadableRetryCount, Handler eventHandler, int minLoadableRetryCount, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener) { AdaptiveMediaSourceEventListener eventListener) {
this(manifestUri, dataSourceFactory, minLoadableRetryCount, eventHandler, eventListener, new HlsPlaylistParser()); this(manifestUri, dataSourceFactory, minLoadableRetryCount, eventHandler, eventListener,
new HlsPlaylistParser());
} }
public HlsMediaSource(Uri manifestUri, HlsDataSourceFactory dataSourceFactory, public HlsMediaSource(Uri manifestUri, HlsDataSourceFactory dataSourceFactory,
int minLoadableRetryCount, Handler eventHandler, int minLoadableRetryCount, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener, AdaptiveMediaSourceEventListener eventListener,
ParsingLoadable.Parser<HlsPlaylist> playlistParser) { ParsingLoadable.Parser<HlsPlaylist> playlistParser) {
this.manifestUri = manifestUri; this.manifestUri = manifestUri;
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;

View File

@ -19,7 +19,6 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
/** /**
@ -124,25 +123,6 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
muxedAudioFormat, muxedCaptionFormats); muxedAudioFormat, muxedCaptionFormats);
} }
/**
* Returns a copy of this playlist which includes the variants sorted using the passed comparator. NOTE: the variants
* will be sorted in ascending order by default. If you wish to use descending order, you can wrap your comparator in
* {@link Collections#reverseOrder(Comparator)}.
*
* @param variantComparator the comparator to use to sort the variant list.
* @return a copy of this playlist which includes the variants sorted using the passed comparator.
*/
public HlsMasterPlaylist copyWithReorderedVariants(Comparator<HlsUrl> variantComparator) {
return new HlsMasterPlaylist(baseUri, tags, filterVariants(variants, variantComparator), audios,
subtitles, muxedAudioFormat, muxedCaptionFormats);
}
private List<HlsUrl> filterVariants(List<HlsUrl> variants, Comparator<HlsUrl> variantComparator) {
List<HlsUrl> reorderedList = new ArrayList<>(variants);
Collections.sort(reorderedList, variantComparator);
return reorderedList;
}
/** /**
* Creates a playlist with a single variant. * Creates a playlist with a single variant.
* *

View File

@ -140,15 +140,16 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
*/ */
public HlsPlaylistTracker(Uri initialPlaylistUri, HlsDataSourceFactory dataSourceFactory, public HlsPlaylistTracker(Uri initialPlaylistUri, HlsDataSourceFactory dataSourceFactory,
EventDispatcher eventDispatcher, int minRetryCount, EventDispatcher eventDispatcher, int minRetryCount,
PrimaryPlaylistListener primaryPlaylistListener, ParsingLoadable.Parser<HlsPlaylist> playlistParser) { PrimaryPlaylistListener primaryPlaylistListener,
ParsingLoadable.Parser<HlsPlaylist> playlistParser) {
this.initialPlaylistUri = initialPlaylistUri; this.initialPlaylistUri = initialPlaylistUri;
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
this.minRetryCount = minRetryCount; this.minRetryCount = minRetryCount;
this.primaryPlaylistListener = primaryPlaylistListener; this.primaryPlaylistListener = primaryPlaylistListener;
this.playlistParser = playlistParser;
listeners = new ArrayList<>(); listeners = new ArrayList<>();
initialPlaylistLoader = new Loader("HlsPlaylistTracker:MasterPlaylist"); initialPlaylistLoader = new Loader("HlsPlaylistTracker:MasterPlaylist");
this.playlistParser = playlistParser;
playlistBundles = new IdentityHashMap<>(); playlistBundles = new IdentityHashMap<>();
playlistRefreshHandler = new Handler(); playlistRefreshHandler = new Handler();
} }