Introduce TrackGroupArray.

This change replaces TrackGroup[] with TrackGroupArray. This is
to allow equality based hashCode and equals implementations.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=115563146
This commit is contained in:
olly 2016-02-25 08:06:53 -08:00 committed by Oliver Woodman
parent d1cb4bc1af
commit 73400907fc
13 changed files with 175 additions and 55 deletions

View File

@ -299,13 +299,13 @@ import java.util.concurrent.atomic.AtomicInteger;
durationUs = source.getDurationUs();
bufferedPositionUs = source.getBufferedPositionUs();
TrackGroup[] trackGroups = source.getTrackGroups();
TrackGroupArray trackGroups = source.getTrackGroups();
// The maximum number of tracks that one renderer can support is the total number of tracks in
// all groups, plus possibly one adaptive track per group.
int maxTrackCount = trackGroups.length;
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
maxTrackCount += trackGroups[groupIndex].length;
maxTrackCount += trackGroups.get(groupIndex).length;
}
// Construct tracks for each renderer.
Format[][] externalTrackFormats = new Format[renderers.length][];
@ -316,7 +316,7 @@ import java.util.concurrent.atomic.AtomicInteger;
TrackSelection[] rendererTrackSelections = new TrackSelection[maxTrackCount];
Format[][] rendererTrackFormats = new Format[maxTrackCount][];
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
TrackGroup trackGroup = trackGroups[groupIndex];
TrackGroup trackGroup = trackGroups.get(groupIndex);
// TODO[REFACTOR]: This should check that the renderer is capable of adaptive playback, in
// addition to checking that the group is adaptive.
if (trackGroup.adaptive) {

View File

@ -143,7 +143,7 @@ public final class Format {
*/
public final String language;
// Lazy-initialized hashcode and framework media format.
// Lazily initialized hashcode and framework media format.
private int hashCode;
private MediaFormat frameworkMediaFormat;

View File

@ -75,7 +75,7 @@ public final class FrameworkSampleSource implements SampleSource {
private boolean prepared;
private long durationUs;
private MediaExtractor extractor;
private TrackGroup[] tracks;
private TrackGroupArray tracks;
private int[] trackStates;
private boolean[] pendingResets;
@ -133,7 +133,7 @@ public final class FrameworkSampleSource implements SampleSource {
durationUs = C.UNKNOWN_TIME_US;
trackStates = new int[extractor.getTrackCount()];
pendingResets = new boolean[trackStates.length];
tracks = new TrackGroup[trackStates.length];
TrackGroup[] tracks = new TrackGroup[trackStates.length];
for (int i = 0; i < trackStates.length; i++) {
MediaFormat format = extractor.getTrackFormat(i);
if (format.containsKey(MediaFormat.KEY_DURATION)) {
@ -141,6 +141,7 @@ public final class FrameworkSampleSource implements SampleSource {
}
tracks[i] = new TrackGroup(createFormat(i, format));
}
this.tracks = new TrackGroupArray(tracks);
prepared = true;
return true;
}
@ -156,7 +157,7 @@ public final class FrameworkSampleSource implements SampleSource {
}
@Override
public TrackGroup[] getTrackGroups() {
public TrackGroupArray getTrackGroups() {
return tracks;
}
@ -194,7 +195,7 @@ public final class FrameworkSampleSource implements SampleSource {
return TrackStream.NOTHING_READ;
}
if (trackStates[track] != TRACK_STATE_FORMAT_SENT) {
formatHolder.format = tracks[track].getFormat(0);
formatHolder.format = tracks.get(track).getFormat(0);
formatHolder.drmInitData = Util.SDK_INT >= 18 ? getDrmInitDataV18() : null;
trackStates[track] = TRACK_STATE_FORMAT_SENT;
return TrackStream.FORMAT_READ;

View File

@ -28,7 +28,7 @@ public class MultiSampleSource implements SampleSource {
private boolean prepared;
private long durationUs;
private TrackGroup[] tracks;
private TrackGroupArray trackGroups;
public MultiSampleSource(SampleSource... sources) {
this.sources = sources;
@ -53,14 +53,15 @@ public class MultiSampleSource implements SampleSource {
durationUs = sources[i].getDurationUs();
}
}
tracks = new TrackGroup[totalTrackGroupCount];
TrackGroup[] trackGroups = new TrackGroup[totalTrackGroupCount];
int trackGroupIndex = 0;
for (int i = 0; i < sources.length; i++) {
int sourceTrackGroupCount = sources[i].getTrackGroups().length;
for (int j = 0; j < sourceTrackGroupCount; j++) {
tracks[trackGroupIndex++] = sources[i].getTrackGroups()[j];
trackGroups[trackGroupIndex++] = sources[i].getTrackGroups().get(j);
}
}
this.trackGroups = new TrackGroupArray(trackGroups);
}
return prepared;
}
@ -71,8 +72,8 @@ public class MultiSampleSource implements SampleSource {
}
@Override
public TrackGroup[] getTrackGroups() {
return tracks;
public TrackGroupArray getTrackGroups() {
return trackGroups;
}
@Override

View File

@ -58,7 +58,7 @@ public interface SampleSource {
*
* @return The {@link TrackGroup}s.
*/
public TrackGroup[] getTrackGroups();
public TrackGroupArray getTrackGroups();
/**
* Indicates to the source that it should continue buffering data for its enabled tracks.

View File

@ -52,7 +52,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
private final Format format;
private final long durationUs;
private final int minLoadableRetryCount;
private final TrackGroup[] trackGroups;
private final TrackGroupArray tracks;
private int state;
private byte[] sampleData;
@ -75,7 +75,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
this.format = format;
this.durationUs = durationUs;
this.minLoadableRetryCount = minLoadableRetryCount;
trackGroups = new TrackGroup[] {new TrackGroup(format)};
tracks = new TrackGroupArray(new TrackGroup(format));
sampleData = new byte[INITIAL_SAMPLE_SIZE];
}
@ -105,8 +105,8 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
}
@Override
public TrackGroup[] getTrackGroups() {
return trackGroups;
public TrackGroupArray getTrackGroups() {
return tracks;
}
@Override

View File

@ -15,6 +15,10 @@
*/
package com.google.android.exoplayer;
import com.google.android.exoplayer.util.Assertions;
import java.util.Arrays;
/**
* Defines a group of tracks exposed by a {@link SampleSource}.
* <p>
@ -26,7 +30,7 @@ package com.google.android.exoplayer;
public final class TrackGroup {
/**
* The number of tracks in the group.
* The number of tracks in the group. Always greater than zero.
*/
public final int length;
/**
@ -36,18 +40,22 @@ public final class TrackGroup {
private final Format[] formats;
// Lazily initialized hashcode.
private int hashCode;
/**
* @param format The format of the single track.
*/
public TrackGroup(Format format) {
this(false, format);
this(false, Assertions.checkNotNull(format));
}
/**
* @param adaptive Whether it's possible to adapt between multiple tracks in the group.
* @param formats The track formats.
* @param formats The track formats. Must not be null or empty. Must not contain null elements.
*/
public TrackGroup(boolean adaptive, Format... formats) {
Assertions.checkState(formats.length > 0);
this.adaptive = adaptive;
this.formats = formats;
length = formats.length;
@ -63,4 +71,29 @@ public final class TrackGroup {
return formats[index];
}
@Override
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 31 * result + (adaptive ? 1231 : 1237);
result = 31 * result + Arrays.hashCode(formats);
result = 31 * result + length;
hashCode = result;
}
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
TrackGroup other = (TrackGroup) obj;
return adaptive == other.adaptive && length == other.length
&& Arrays.equals(formats, other.formats);
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer;
import java.util.Arrays;
/**
* An array of {@link TrackGroup}s exposed by a {@link SampleSource}.
*/
public final class TrackGroupArray {
/**
* The number of groups in the list. Greater than or equal to zero.
*/
public final int length;
private final TrackGroup[] trackGroups;
// Lazily initialized hashcode.
private int hashCode;
/**
* @param trackGroups The groups. Must not be null or contain null elements, but may be empty.
*/
public TrackGroupArray(TrackGroup... trackGroups) {
this.trackGroups = trackGroups;
this.length = trackGroups.length;
}
/**
* Gets the group at a given index.
*
* @param index The index of the group.
* @return The group.
*/
public TrackGroup get(int index) {
return trackGroups[index];
}
@Override
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 31 * result + Arrays.hashCode(trackGroups);
result = 31 * result + length;
hashCode = result;
}
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
TrackGroupArray other = (TrackGroupArray) obj;
return length == other.length && Arrays.equals(trackGroups, other.trackGroups);
}
}

View File

@ -22,6 +22,7 @@ import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.TrackSelection;
import com.google.android.exoplayer.TrackStream;
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
@ -78,7 +79,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
private long lastPerformedBufferOperation;
private boolean pendingReset;
private TrackGroup[] trackGroups;
private TrackGroupArray trackGroups;
private long durationUs;
private Loader loader;
private boolean loadingFinished;
@ -156,11 +157,11 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
}
durationUs = chunkSource.getDurationUs();
TrackGroup trackGroup = chunkSource.getTracks();
if (trackGroup.length > 0) {
if (trackGroup != null) {
loader = new Loader("Loader:" + trackGroup.getFormat(0).containerMimeType);
trackGroups = new TrackGroup[] {trackGroup};
trackGroups = new TrackGroupArray(trackGroup);
} else {
trackGroups = new TrackGroup[0];
trackGroups = new TrackGroupArray();
}
state = STATE_PREPARED;
return true;
@ -177,7 +178,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
}
@Override
public TrackGroup[] getTrackGroups() {
public TrackGroupArray getTrackGroups() {
Assertions.checkState(state != STATE_IDLE);
return trackGroups;
}

View File

@ -495,18 +495,20 @@ public class DashChunkSource implements ChunkSource {
for (int i = 0; i < period.adaptationSets.size(); i++) {
AdaptationSet adaptationSet = period.adaptationSets.get(i);
if (adaptationSet.type == adaptationSetType) {
// We've found an adaptation set of the exposed type.
adaptationSetIndex = i;
List<Representation> representations = adaptationSet.representations;
Format[] trackFormats = new Format[representations.size()];
for (int j = 0; j < trackFormats.length; j++) {
trackFormats[j] = representations.get(j).format;
if (!representations.isEmpty()) {
// We've found a non-empty adaptation set of the exposed type.
Format[] trackFormats = new Format[representations.size()];
for (int j = 0; j < trackFormats.length; j++) {
trackFormats[j] = representations.get(j).format;
}
trackGroup = new TrackGroup(adaptiveFormatEvaluator != null, trackFormats);
return;
}
trackGroup = new TrackGroup(adaptiveFormatEvaluator != null, trackFormats);
return;
}
}
trackGroup = new TrackGroup(adaptiveFormatEvaluator != null);
trackGroup = null;
}
// Visible for testing.

View File

@ -21,6 +21,7 @@ import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.TrackSelection;
import com.google.android.exoplayer.TrackStream;
import com.google.android.exoplayer.drm.DrmInitData;
@ -176,7 +177,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
private boolean prepared;
private int enabledTrackCount;
private TrackGroup[] tracks;
private TrackGroupArray tracks;
private long durationUs;
private boolean[] pendingMediaFormat;
private boolean[] pendingResets;
@ -264,7 +265,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
if (seekMap != null && tracksBuilt && haveFormatsForAllTracks()) {
int trackCount = sampleQueues.size();
tracks = new TrackGroup[trackCount];
TrackGroup[] tracks = new TrackGroup[trackCount];
trackEnabledStates = new boolean[trackCount];
pendingResets = new boolean[trackCount];
pendingMediaFormat = new boolean[trackCount];
@ -272,6 +273,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
for (int i = 0; i < trackCount; i++) {
tracks[i] = new TrackGroup(sampleQueues.valueAt(i).getFormat());
}
this.tracks = new TrackGroupArray(tracks);
prepared = true;
return true;
}
@ -290,7 +292,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
}
@Override
public TrackGroup[] getTrackGroups() {
public TrackGroupArray getTrackGroups() {
return tracks;
}

View File

@ -22,6 +22,7 @@ import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.TrackSelection;
import com.google.android.exoplayer.TrackStream;
import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener;
@ -79,7 +80,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
// Tracks are complicated in HLS. See documentation of buildTracks for details.
// Indexed by track (as exposed by this source).
private TrackGroup[] trackGroups;
private TrackGroupArray trackGroups;
private int primaryTrackGroupIndex;
private int[] primarySelectedTracks;
// Indexed by group.
@ -181,7 +182,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
}
@Override
public TrackGroup[] getTrackGroups() {
public TrackGroupArray getTrackGroups() {
Assertions.checkState(prepared);
return trackGroups;
}
@ -506,12 +507,12 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
// Instantiate the necessary internal data-structures.
primaryTrackGroupIndex = -1;
trackGroups = new TrackGroup[extractorTrackCount];
groupEnabledStates = new boolean[extractorTrackCount];
pendingResets = new boolean[extractorTrackCount];
downstreamSampleFormats = new Format[extractorTrackCount];
// Construct the set of exposed track groups.
TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount];
for (int i = 0; i < extractorTrackCount; i++) {
Format sampleFormat = extractor.getSampleFormat(i);
if (i == primaryExtractorTrackIndex) {
@ -525,6 +526,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
trackGroups[i] = new TrackGroup(sampleFormat);
}
}
this.trackGroups = new TrackGroupArray(trackGroups);
}
/**

View File

@ -328,27 +328,29 @@ public class SmoothStreamingChunkSource implements ChunkSource {
private void initForManifest(SmoothStreamingManifest manifest) {
for (int i = 0; i < manifest.streamElements.length; i++) {
if (manifest.streamElements[i].type == streamElementType) {
// We've found an element of the desired type.
elementIndex = i;
long timescale = manifest.streamElements[i].timescale;
Format[] formats = manifest.streamElements[i].formats;
extractorWrappers = new ChunkExtractorWrapper[formats.length];
for (int j = 0; j < formats.length; j++) {
int nalUnitLengthFieldLength = streamElementType == StreamElement.TYPE_VIDEO ? 4 : -1;
Track track = new Track(j, streamElementType, timescale, C.UNKNOWN_TIME_US, durationUs,
formats[j], trackEncryptionBoxes, nalUnitLengthFieldLength, null, null);
FragmentedMp4Extractor extractor = new FragmentedMp4Extractor(
FragmentedMp4Extractor.WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
| FragmentedMp4Extractor.WORKAROUND_IGNORE_TFDT_BOX);
extractor.setTrack(track);
extractorWrappers[j] = new ChunkExtractorWrapper(extractor);
if (formats.length > 0) {
// We've found an element of the desired type.
long timescale = manifest.streamElements[i].timescale;
extractorWrappers = new ChunkExtractorWrapper[formats.length];
for (int j = 0; j < formats.length; j++) {
int nalUnitLengthFieldLength = streamElementType == StreamElement.TYPE_VIDEO ? 4 : -1;
Track track = new Track(j, streamElementType, timescale, C.UNKNOWN_TIME_US, durationUs,
formats[j], trackEncryptionBoxes, nalUnitLengthFieldLength, null, null);
FragmentedMp4Extractor extractor = new FragmentedMp4Extractor(
FragmentedMp4Extractor.WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
| FragmentedMp4Extractor.WORKAROUND_IGNORE_TFDT_BOX);
extractor.setTrack(track);
extractorWrappers[j] = new ChunkExtractorWrapper(extractor);
}
elementIndex = i;
trackGroup = new TrackGroup(adaptiveFormatEvaluator != null, formats);
return;
}
trackGroup = new TrackGroup(adaptiveFormatEvaluator != null, formats);
return;
}
}
extractorWrappers = null;
trackGroup = new TrackGroup(adaptiveFormatEvaluator != null);
trackGroup = null;
}
/**