Remove child data holder helper from AbstractConcatenatedTimeline.

This helper class required a scratch instance to write on. Such a scratch
instance may violate the immuatability of the timelines if used by multiple
threads simultaneously.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=163992458
This commit is contained in:
tonihei 2017-08-02 09:26:58 -07:00 committed by Oliver Woodman
parent 412138b2ea
commit 5ca84ebfd8
4 changed files with 148 additions and 139 deletions

View File

@ -25,68 +25,25 @@ import com.google.android.exoplayer2.Timeline;
*/
/* package */ abstract class AbstractConcatenatedTimeline extends Timeline {
/**
* Meta data of a child timeline.
*/
protected static final class ChildDataHolder {
private final int childCount;
/**
* 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;
/**
* Set child holder data.
*
* @param timeline Child timeline.
* @param firstPeriodIndexInChild First period index belonging to the child timeline.
* @param firstWindowIndexInChild First window index belonging to the child timeline.
* @param uid UID of child timeline.
*/
public void setData(Timeline timeline, int firstPeriodIndexInChild, int firstWindowIndexInChild,
Object uid) {
this.timeline = timeline;
this.firstPeriodIndexInChild = firstPeriodIndexInChild;
this.firstWindowIndexInChild = firstWindowIndexInChild;
this.uid = uid;
}
}
private final ChildDataHolder childDataHolder;
public AbstractConcatenatedTimeline() {
childDataHolder = new ChildDataHolder();
public AbstractConcatenatedTimeline(int childCount) {
this.childCount = childCount;
}
@Override
public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) {
getChildDataByWindowIndex(windowIndex, childDataHolder);
int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild;
int nextWindowIndexInChild = childDataHolder.timeline.getNextWindowIndex(
int childIndex = getChildIndexByWindowIndex(windowIndex);
int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex);
int nextWindowIndexInChild = getTimelineByChildIndex(childIndex).getNextWindowIndex(
windowIndex - firstWindowIndexInChild,
repeatMode == Player.REPEAT_MODE_ALL ? Player.REPEAT_MODE_OFF : repeatMode);
if (nextWindowIndexInChild != C.INDEX_UNSET) {
return firstWindowIndexInChild + nextWindowIndexInChild;
} else {
firstWindowIndexInChild += childDataHolder.timeline.getWindowCount();
if (firstWindowIndexInChild < getWindowCount()) {
return firstWindowIndexInChild;
int nextChildIndex = childIndex + 1;
if (nextChildIndex < childCount) {
return getFirstWindowIndexByChildIndex(nextChildIndex);
} else if (repeatMode == Player.REPEAT_MODE_ALL) {
return 0;
} else {
@ -97,9 +54,9 @@ import com.google.android.exoplayer2.Timeline;
@Override
public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) {
getChildDataByWindowIndex(windowIndex, childDataHolder);
int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild;
int previousWindowIndexInChild = childDataHolder.timeline.getPreviousWindowIndex(
int childIndex = getChildIndexByWindowIndex(windowIndex);
int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex);
int previousWindowIndexInChild = getTimelineByChildIndex(childIndex).getPreviousWindowIndex(
windowIndex - firstWindowIndexInChild,
repeatMode == Player.REPEAT_MODE_ALL ? Player.REPEAT_MODE_OFF : repeatMode);
if (previousWindowIndexInChild != C.INDEX_UNSET) {
@ -118,11 +75,11 @@ import com.google.android.exoplayer2.Timeline;
@Override
public final Window getWindow(int windowIndex, Window window, boolean setIds,
long defaultPositionProjectionUs) {
getChildDataByWindowIndex(windowIndex, childDataHolder);
int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild;
int firstPeriodIndexInChild = childDataHolder.firstPeriodIndexInChild;
childDataHolder.timeline.getWindow(windowIndex - firstWindowIndexInChild, window, setIds,
defaultPositionProjectionUs);
int childIndex = getChildIndexByWindowIndex(windowIndex);
int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex);
int firstPeriodIndexInChild = getFirstPeriodIndexByChildIndex(childIndex);
getTimelineByChildIndex(childIndex).getWindow(windowIndex - firstWindowIndexInChild, window,
setIds, defaultPositionProjectionUs);
window.firstPeriodIndex += firstPeriodIndexInChild;
window.lastPeriodIndex += firstPeriodIndexInChild;
return window;
@ -130,13 +87,14 @@ import com.google.android.exoplayer2.Timeline;
@Override
public final Period getPeriod(int periodIndex, Period period, boolean setIds) {
getChildDataByPeriodIndex(periodIndex, childDataHolder);
int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild;
int firstPeriodIndexInChild = childDataHolder.firstPeriodIndexInChild;
childDataHolder.timeline.getPeriod(periodIndex - firstPeriodIndexInChild, period, setIds);
int childIndex = getChildIndexByPeriodIndex(periodIndex);
int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex);
int firstPeriodIndexInChild = getFirstPeriodIndexByChildIndex(childIndex);
getTimelineByChildIndex(childIndex).getPeriod(periodIndex - firstPeriodIndexInChild, period,
setIds);
period.windowIndex += firstWindowIndexInChild;
if (setIds) {
period.uid = Pair.create(childDataHolder.uid, period.uid);
period.uid = Pair.create(getChildUidByChildIndex(childIndex), period.uid);
}
return period;
}
@ -149,37 +107,64 @@ import com.google.android.exoplayer2.Timeline;
Pair<?, ?> childUidAndPeriodUid = (Pair<?, ?>) uid;
Object childUid = childUidAndPeriodUid.first;
Object periodUid = childUidAndPeriodUid.second;
if (!getChildDataByChildUid(childUid, childDataHolder)) {
int childIndex = getChildIndexByChildUid(childUid);
if (childIndex == C.INDEX_UNSET) {
return C.INDEX_UNSET;
}
int periodIndexInChild = childDataHolder.timeline.getIndexOfPeriod(periodUid);
int periodIndexInChild = getTimelineByChildIndex(childIndex).getIndexOfPeriod(periodUid);
return periodIndexInChild == C.INDEX_UNSET ? C.INDEX_UNSET
: childDataHolder.firstPeriodIndexInChild + periodIndexInChild;
: getFirstPeriodIndexByChildIndex(childIndex) + periodIndexInChild;
}
/**
* Populates {@link ChildDataHolder} for the child timeline containing the given period index.
* Returns the index of the child timeline containing the given period index.
*
* @param periodIndex A valid period index within the bounds of the timeline.
* @param childData A data holder to be populated.
*/
protected abstract void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData);
protected abstract int getChildIndexByPeriodIndex(int periodIndex);
/**
* Populates {@link ChildDataHolder} for the child timeline containing the given window index.
* Returns the index of 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 void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData);
protected abstract int getChildIndexByWindowIndex(int windowIndex);
/**
* Populates {@link ChildDataHolder} for the child timeline with the given UID.
* Returns the index of the child timeline with the given UID or {@link C#INDEX_UNSET} if not
* found.
*
* @param childUid A child UID.
* @param childData A data holder to be populated.
* @return Whether a child with the given UID was found.
* @return Index of child timeline or {@link C#INDEX_UNSET} if UID was not found.
*/
protected abstract boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData);
protected abstract int getChildIndexByChildUid(Object childUid);
/**
* Returns the child timeline for the child with the given index.
*
* @param childIndex A valid child index within the bounds of the timeline.
*/
protected abstract Timeline getTimelineByChildIndex(int childIndex);
/**
* Returns the first period index belonging to the child timeline with the given index.
*
* @param childIndex A valid child index within the bounds of the timeline.
*/
protected abstract int getFirstPeriodIndexByChildIndex(int childIndex);
/**
* Returns the first window index belonging to the child timeline with the given index.
*
* @param childIndex A valid child index within the bounds of the timeline.
*/
protected abstract int getFirstWindowIndexByChildIndex(int childIndex);
/**
* Returns the UID of the child timeline with the given index.
*
* @param childIndex A valid child index within the bounds of the timeline.
*/
protected abstract Object getChildUidByChildIndex(int childIndex);
}

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
@ -97,7 +98,7 @@ public final class ConcatenatingMediaSource implements MediaSource {
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
int sourceIndex = timeline.getChildIndexByPeriodIndex(id.periodIndex);
MediaPeriodId periodIdInSource =
new MediaPeriodId(id.periodIndex - timeline.getFirstPeriodIndexInChild(sourceIndex));
new MediaPeriodId(id.periodIndex - timeline.getFirstPeriodIndexByChildIndex(sourceIndex));
MediaPeriod mediaPeriod = mediaSources[sourceIndex].createPeriod(periodIdInSource, allocator);
sourceIndexByMediaPeriod.put(mediaPeriod, sourceIndex);
return mediaPeriod;
@ -166,6 +167,7 @@ public final class ConcatenatingMediaSource implements MediaSource {
private final boolean isRepeatOneAtomic;
public ConcatenatedTimeline(Timeline[] timelines, boolean isRepeatOneAtomic) {
super(timelines.length);
int[] sourcePeriodOffsets = new int[timelines.length];
int[] sourceWindowOffsets = new int[timelines.length];
long periodCount = 0;
@ -212,44 +214,43 @@ public final class ConcatenatingMediaSource implements MediaSource {
}
@Override
protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData) {
int childIndex = getChildIndexByPeriodIndex(periodIndex);
getChildDataByChildIndex(childIndex, childData);
}
@Override
protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData) {
int childIndex = Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1;
getChildDataByChildIndex(childIndex, childData);
}
@Override
protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData) {
if (!(childUid instanceof Integer)) {
return false;
}
int childIndex = (Integer) childUid;
getChildDataByChildIndex(childIndex, childData);
return true;
}
private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) {
childData.setData(timelines[childIndex], getFirstPeriodIndexInChild(childIndex),
getFirstWindowIndexInChild(childIndex), childIndex);
}
private int getChildIndexByPeriodIndex(int periodIndex) {
protected int getChildIndexByPeriodIndex(int periodIndex) {
return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1;
}
private int getFirstPeriodIndexInChild(int childIndex) {
@Override
protected int getChildIndexByWindowIndex(int windowIndex) {
return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1;
}
@Override
protected int getChildIndexByChildUid(Object childUid) {
if (!(childUid instanceof Integer)) {
return C.INDEX_UNSET;
}
return (Integer) childUid;
}
@Override
protected Timeline getTimelineByChildIndex(int childIndex) {
return timelines[childIndex];
}
@Override
protected int getFirstPeriodIndexByChildIndex(int childIndex) {
return childIndex == 0 ? 0 : sourcePeriodOffsets[childIndex - 1];
}
private int getFirstWindowIndexInChild(int childIndex) {
@Override
protected int getFirstWindowIndexByChildIndex(int childIndex) {
return childIndex == 0 ? 0 : sourceWindowOffsets[childIndex - 1];
}
@Override
protected Object getChildUidByChildIndex(int childIndex) {
return childIndex;
}
}
}

View File

@ -397,6 +397,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl
public ConcatenatedTimeline(Collection<MediaSourceHolder> mediaSourceHolders, int windowCount,
int periodCount) {
super(mediaSourceHolders.size());
this.windowCount = windowCount;
this.periodCount = periodCount;
int childCount = mediaSourceHolders.size();
@ -416,28 +417,42 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl
}
@Override
protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childDataHolder) {
int index = Util.binarySearchFloor(firstPeriodInChildIndices, periodIndex, true, false);
setChildData(index, childDataHolder);
protected int getChildIndexByPeriodIndex(int periodIndex) {
return Util.binarySearchFloor(firstPeriodInChildIndices, periodIndex, true, false);
}
@Override
protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childDataHolder) {
int index = Util.binarySearchFloor(firstWindowInChildIndices, windowIndex, true, false);
setChildData(index, childDataHolder);
protected int getChildIndexByWindowIndex(int windowIndex) {
return Util.binarySearchFloor(firstWindowInChildIndices, windowIndex, true, false);
}
@Override
protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childDataHolder) {
protected int getChildIndexByChildUid(Object childUid) {
if (!(childUid instanceof Integer)) {
return false;
return C.INDEX_UNSET;
}
int index = childIndexByUid.get((int) childUid, -1);
if (index == -1) {
return false;
}
setChildData(index, childDataHolder);
return true;
return index == -1 ? C.INDEX_UNSET : index;
}
@Override
protected Timeline getTimelineByChildIndex(int childIndex) {
return timelines[childIndex];
}
@Override
protected int getFirstPeriodIndexByChildIndex(int childIndex) {
return firstPeriodInChildIndices[childIndex];
}
@Override
protected int getFirstWindowIndexByChildIndex(int childIndex) {
return firstWindowInChildIndices[childIndex];
}
@Override
protected Object getChildUidByChildIndex(int childIndex) {
return uids[childIndex];
}
@Override
@ -450,10 +465,6 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl
return periodCount;
}
private void setChildData(int srcIndex, ChildDataHolder dest) {
dest.setData(timelines[srcIndex], firstPeriodInChildIndices[srcIndex],
firstWindowInChildIndices[srcIndex], uids[srcIndex]);
}
}
private static final class DeferredTimeline extends Timeline {

View File

@ -101,6 +101,7 @@ public final class LoopingMediaSource implements MediaSource {
private final int loopCount;
public LoopingTimeline(Timeline childTimeline, int loopCount) {
super(loopCount);
this.childTimeline = childTimeline;
childPeriodCount = childTimeline.getPeriodCount();
childWindowCount = childTimeline.getWindowCount();
@ -120,30 +121,41 @@ public final class LoopingMediaSource implements MediaSource {
}
@Override
protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData) {
int childIndex = periodIndex / childPeriodCount;
getChildDataByChildIndex(childIndex, childData);
protected int getChildIndexByPeriodIndex(int periodIndex) {
return periodIndex / childPeriodCount;
}
@Override
protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData) {
int childIndex = windowIndex / childWindowCount;
getChildDataByChildIndex(childIndex, childData);
protected int getChildIndexByWindowIndex(int windowIndex) {
return windowIndex / childWindowCount;
}
@Override
protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData) {
protected int getChildIndexByChildUid(Object childUid) {
if (!(childUid instanceof Integer)) {
return false;
return C.INDEX_UNSET;
}
int childIndex = (Integer) childUid;
getChildDataByChildIndex(childIndex, childData);
return true;
return (Integer) childUid;
}
private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) {
childData.setData(childTimeline, childIndex * childPeriodCount, childIndex * childWindowCount,
childIndex);
@Override
protected Timeline getTimelineByChildIndex(int childIndex) {
return childTimeline;
}
@Override
protected int getFirstPeriodIndexByChildIndex(int childIndex) {
return childIndex * childPeriodCount;
}
@Override
protected int getFirstWindowIndexByChildIndex(int childIndex) {
return childIndex * childWindowCount;
}
@Override
protected Object getChildUidByChildIndex(int childIndex) {
return childIndex;
}
}