Commit dcc2f9bd by tonihei Committed by Oliver Woodman

Add meta data class for AbstractConcatenatedTimeline.

(Preparation for GitHub issue #1706)

AbstractConcatenatedTimeline repeatly calls methods of its implementation to
query a specific child timeline. This may be inefficient if the implementation
repeatly executes the same code to find the timeline.

Changed the class such that it now queries all information at once using a meta
data class. As all methods need at least two of four variables anyway, this
doesn't generate unnecessary overhead.

Also generified the UID for the child indices to allow new implementations to
use some other UID besides the index.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=158711979
parent 629edc2b
...@@ -25,55 +25,87 @@ import com.google.android.exoplayer2.Timeline; ...@@ -25,55 +25,87 @@ import com.google.android.exoplayer2.Timeline;
*/ */
/* package */ abstract class AbstractConcatenatedTimeline extends Timeline { /* package */ abstract class AbstractConcatenatedTimeline extends Timeline {
/**
* Meta data of a child timeline.
*/
protected static class ChildDataHolder {
/**
* Child timeline.
*/
public Timeline timeline;
/**
* First period index belonging to the child timeline.
*/
public int firstPeriodIndexInChild;
/**
* First window index belonging to the child timeline.
*/
public int firstWindowIndexInChild;
/**
* UID of child timeline.
*/
public Object uid;
}
private final ChildDataHolder childDataHolder;
public AbstractConcatenatedTimeline() {
childDataHolder = new ChildDataHolder();
}
@Override @Override
public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) {
int childIndex = getChildIndexForWindow(windowIndex); getChildDataByWindowIndex(windowIndex, childDataHolder);
int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild;
int nextWindowIndexInChild = getChild(childIndex).getNextWindowIndex( int nextWindowIndexInChild = childDataHolder.timeline.getNextWindowIndex(
windowIndex - firstWindowIndexInChild, windowIndex - firstWindowIndexInChild,
repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode); repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode);
if (nextWindowIndexInChild == C.INDEX_UNSET) { if (nextWindowIndexInChild != C.INDEX_UNSET) {
if (childIndex < getChildCount() - 1) { return firstWindowIndexInChild + nextWindowIndexInChild;
childIndex++; } else {
firstWindowIndexInChild += childDataHolder.timeline.getWindowCount();
if (firstWindowIndexInChild < getWindowCount()) {
return firstWindowIndexInChild;
} else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) { } else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) {
childIndex = 0; return 0;
} else { } else {
return C.INDEX_UNSET; return C.INDEX_UNSET;
} }
firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex);
nextWindowIndexInChild = 0;
} }
return firstWindowIndexInChild + nextWindowIndexInChild;
} }
@Override @Override
public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) {
int childIndex = getChildIndexForWindow(windowIndex); getChildDataByWindowIndex(windowIndex, childDataHolder);
int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild;
int previousWindowIndexInChild = getChild(childIndex).getPreviousWindowIndex( int previousWindowIndexInChild = childDataHolder.timeline.getPreviousWindowIndex(
windowIndex - firstWindowIndexInChild, windowIndex - firstWindowIndexInChild,
repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode); repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode);
if (previousWindowIndexInChild == C.INDEX_UNSET) { if (previousWindowIndexInChild != C.INDEX_UNSET) {
if (childIndex > 0) { return firstWindowIndexInChild + previousWindowIndexInChild;
childIndex--; } else {
if (firstWindowIndexInChild > 0) {
return firstWindowIndexInChild - 1;
} else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) { } else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) {
childIndex = getChildCount() - 1; return getWindowCount() - 1;
} else { } else {
return C.INDEX_UNSET; return C.INDEX_UNSET;
} }
firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex);
previousWindowIndexInChild = getChild(childIndex).getWindowCount() - 1;
} }
return firstWindowIndexInChild + previousWindowIndexInChild;
} }
@Override @Override
public final Window getWindow(int windowIndex, Window window, boolean setIds, public final Window getWindow(int windowIndex, Window window, boolean setIds,
long defaultPositionProjectionUs) { long defaultPositionProjectionUs) {
int childIndex = getChildIndexForWindow(windowIndex); getChildDataByWindowIndex(windowIndex, childDataHolder);
int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild;
int firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex); int firstPeriodIndexInChild = childDataHolder.firstPeriodIndexInChild;
getChild(childIndex).getWindow(windowIndex - firstWindowIndexInChild, window, setIds, childDataHolder.timeline.getWindow(windowIndex - firstWindowIndexInChild, window, setIds,
defaultPositionProjectionUs); defaultPositionProjectionUs);
window.firstPeriodIndex += firstPeriodIndexInChild; window.firstPeriodIndex += firstPeriodIndexInChild;
window.lastPeriodIndex += firstPeriodIndexInChild; window.lastPeriodIndex += firstPeriodIndexInChild;
...@@ -82,13 +114,13 @@ import com.google.android.exoplayer2.Timeline; ...@@ -82,13 +114,13 @@ import com.google.android.exoplayer2.Timeline;
@Override @Override
public final Period getPeriod(int periodIndex, Period period, boolean setIds) { public final Period getPeriod(int periodIndex, Period period, boolean setIds) {
int childIndex = getChildIndexForPeriod(periodIndex); getChildDataByPeriodIndex(periodIndex, childDataHolder);
int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild;
int firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex); int firstPeriodIndexInChild = childDataHolder.firstPeriodIndexInChild;
getChild(childIndex).getPeriod(periodIndex - firstPeriodIndexInChild, period, setIds); childDataHolder.timeline.getPeriod(periodIndex - firstPeriodIndexInChild, period, setIds);
period.windowIndex += firstWindowIndexInChild; period.windowIndex += firstWindowIndexInChild;
if (setIds) { if (setIds) {
period.uid = Pair.create(childIndex, period.uid); period.uid = Pair.create(childDataHolder.uid, period.uid);
} }
return period; return period;
} }
...@@ -98,48 +130,40 @@ import com.google.android.exoplayer2.Timeline; ...@@ -98,48 +130,40 @@ import com.google.android.exoplayer2.Timeline;
if (!(uid instanceof Pair)) { if (!(uid instanceof Pair)) {
return C.INDEX_UNSET; return C.INDEX_UNSET;
} }
Pair<?, ?> childIndexAndPeriodId = (Pair<?, ?>) uid; Pair<?, ?> childUidAndPeriodUid = (Pair<?, ?>) uid;
if (!(childIndexAndPeriodId.first instanceof Integer)) { Object childUid = childUidAndPeriodUid.first;
Object periodUid = childUidAndPeriodUid.second;
if (!getChildDataByChildUid(childUid, childDataHolder)) {
return C.INDEX_UNSET; return C.INDEX_UNSET;
} }
int childIndex = (Integer) childIndexAndPeriodId.first; int periodIndexInChild = childDataHolder.timeline.getIndexOfPeriod(periodUid);
Object periodId = childIndexAndPeriodId.second;
if (childIndex < 0 || childIndex >= getChildCount()) {
return C.INDEX_UNSET;
}
int periodIndexInChild = getChild(childIndex).getIndexOfPeriod(periodId);
return periodIndexInChild == C.INDEX_UNSET ? C.INDEX_UNSET return periodIndexInChild == C.INDEX_UNSET ? C.INDEX_UNSET
: getFirstPeriodIndexInChild(childIndex) + periodIndexInChild; : childDataHolder.firstPeriodIndexInChild + periodIndexInChild;
} }
/** /**
* Returns the number of concatenated child timelines. * Populates {@link ChildDataHolder} for the child timeline containing the given period index.
*/ *
protected abstract int getChildCount(); * @param periodIndex A valid period index within the bounds of the timeline.
* @param childData A data holder to be populated.
/**
* Returns a child timeline by index.
*/
protected abstract Timeline getChild(int childIndex);
/**
* Returns the index of the child timeline to which the period with the given index belongs.
*/
protected abstract int getChildIndexForPeriod(int periodIndex);
/**
* Returns the first period index belonging to the child timeline with the given index.
*/ */
protected abstract int getFirstPeriodIndexInChild(int childIndex); protected abstract void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData);
/** /**
* Returns the index of the child timeline to which the window with the given index belongs. * Populates {@link ChildDataHolder} for the child timeline containing the given window index.
*
* @param windowIndex A valid window index within the bounds of the timeline.
* @param childData A data holder to be populated.
*/ */
protected abstract int getChildIndexForWindow(int windowIndex); protected abstract void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData);
/** /**
* Returns the first window index belonging to the child timeline with the given index. * Populates {@link ChildDataHolder} for the child timeline with the given UID.
*
* @param childUid A child UID.
* @param childData A data holder to be populated.
* @return Whether a child with the given UID was found.
*/ */
protected abstract int getFirstWindowIndexInChild(int childIndex); protected abstract boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData);
} }
...@@ -92,7 +92,7 @@ public final class ConcatenatingMediaSource implements MediaSource { ...@@ -92,7 +92,7 @@ public final class ConcatenatingMediaSource implements MediaSource {
@Override @Override
public MediaPeriod createPeriod(int index, Allocator allocator) { public MediaPeriod createPeriod(int index, Allocator allocator) {
int sourceIndex = timeline.getChildIndexForPeriod(index); int sourceIndex = timeline.getChildIndexByPeriodIndex(index);
int periodIndexInSource = index - timeline.getFirstPeriodIndexInChild(sourceIndex); int periodIndexInSource = index - timeline.getFirstPeriodIndexInChild(sourceIndex);
MediaPeriod mediaPeriod = MediaPeriod mediaPeriod =
mediaSources[sourceIndex].createPeriod(periodIndexInSource, allocator); mediaSources[sourceIndex].createPeriod(periodIndexInSource, allocator);
...@@ -209,32 +209,43 @@ public final class ConcatenatingMediaSource implements MediaSource { ...@@ -209,32 +209,43 @@ public final class ConcatenatingMediaSource implements MediaSource {
} }
@Override @Override
protected int getChildCount() { protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData) {
return timelines.length; int childIndex = getChildIndexByPeriodIndex(periodIndex);
getChildDataByChildIndex(childIndex, childData);
} }
@Override @Override
protected Timeline getChild(int childIndex) { protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData) {
return timelines[childIndex]; int childIndex = Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1;
getChildDataByChildIndex(childIndex, childData);
} }
@Override @Override
protected int getChildIndexForPeriod(int periodIndex) { protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData) {
return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1; if (!(childUid instanceof Integer)) {
return false;
}
int childIndex = (Integer) childUid;
getChildDataByChildIndex(childIndex, childData);
return true;
} }
@Override private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) {
protected int getFirstPeriodIndexInChild(int childIndex) { childData.timeline = timelines[childIndex];
return childIndex == 0 ? 0 : sourcePeriodOffsets[childIndex - 1]; childData.firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex);
childData.firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex);
childData.uid = childIndex;
} }
@Override private int getChildIndexByPeriodIndex(int periodIndex) {
protected int getChildIndexForWindow(int windowIndex) { return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1;
return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1;
} }
@Override private int getFirstPeriodIndexInChild(int childIndex) {
protected int getFirstWindowIndexInChild(int childIndex) { return childIndex == 0 ? 0 : sourcePeriodOffsets[childIndex - 1];
}
private int getFirstWindowIndexInChild(int childIndex) {
return childIndex == 0 ? 0 : sourceWindowOffsets[childIndex - 1]; return childIndex == 0 ? 0 : sourceWindowOffsets[childIndex - 1];
} }
......
...@@ -119,34 +119,34 @@ public final class LoopingMediaSource implements MediaSource { ...@@ -119,34 +119,34 @@ public final class LoopingMediaSource implements MediaSource {
} }
@Override @Override
protected Timeline getChild(int childIndex) { protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData) {
return childTimeline; int childIndex = periodIndex / childPeriodCount;
getChildDataByChildIndex(childIndex, childData);
} }
@Override @Override
protected int getChildCount() { protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData) {
return loopCount; int childIndex = windowIndex / childWindowCount;
getChildDataByChildIndex(childIndex, childData);
} }
@Override @Override
protected int getChildIndexForPeriod(int periodIndex) { protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData) {
return periodIndex / childPeriodCount; if (!(childUid instanceof Integer)) {
} return false;
}
@Override int childIndex = (Integer) childUid;
protected int getFirstPeriodIndexInChild(int childIndex) { getChildDataByChildIndex(childIndex, childData);
return childIndex * childPeriodCount; return true;
} }
@Override private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) {
protected int getChildIndexForWindow(int windowIndex) { childData.timeline = childTimeline;
return windowIndex / childWindowCount; childData.firstPeriodIndexInChild = childIndex * childPeriodCount;
childData.firstWindowIndexInChild = childIndex * childWindowCount;
childData.uid = childIndex;
} }
@Override
protected int getFirstWindowIndexInChild(int childIndex) {
return childIndex * childWindowCount;
}
} }
private static final class InfinitelyLoopingTimeline extends Timeline { private static final class InfinitelyLoopingTimeline extends Timeline {
...@@ -195,5 +195,7 @@ public final class LoopingMediaSource implements MediaSource { ...@@ -195,5 +195,7 @@ public final class LoopingMediaSource implements MediaSource {
public int getIndexOfPeriod(Object uid) { public int getIndexOfPeriod(Object uid) {
return childTimeline.getIndexOfPeriod(uid); return childTimeline.getIndexOfPeriod(uid);
} }
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment