Clarify timebase of media times in MediaLoadData.

Also fix unncessary adjustment done in ClippingMediaSource.

#minor-release

PiperOrigin-RevId: 372080724
This commit is contained in:
tonihei 2021-05-05 09:56:34 +01:00 committed by bachinger
parent 837826c735
commit b71c47f0dd
6 changed files with 21 additions and 171 deletions

View File

@ -87,7 +87,7 @@ public abstract class BaseMediaSource implements MediaSource {
/**
* Returns a {@link MediaSourceEventListener.EventDispatcher} which dispatches all events to the
* registered listeners with the specified media period id.
* registered listeners with the specified {@link MediaPeriodId}.
*
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events. May be null, if
* the events do not belong to a specific media period.
@ -101,7 +101,7 @@ public abstract class BaseMediaSource implements MediaSource {
/**
* Returns a {@link MediaSourceEventListener.EventDispatcher} which dispatches all events to the
* registered listeners with the specified media period id and time offset.
* registered listeners with the specified {@link MediaPeriodId} and time offset.
*
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events.
* @param mediaTimeOffsetMs The offset to be added to all media times, in milliseconds.
@ -115,7 +115,7 @@ public abstract class BaseMediaSource implements MediaSource {
/**
* Returns a {@link MediaSourceEventListener.EventDispatcher} which dispatches all events to the
* registered listeners with the specified window index, media period id and time offset.
* registered listeners with the specified window index, {@link MediaPeriodId} and time offset.
*
* @param windowIndex The timeline window index to be reported with the events.
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events. May be null, if
@ -130,7 +130,7 @@ public abstract class BaseMediaSource implements MediaSource {
/**
* Returns a {@link DrmSessionEventListener.EventDispatcher} which dispatches all events to the
* registered listeners with the specified media period id.
* registered listeners with the specified {@link MediaPeriodId}
*
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events. May be null, if
* the events do not belong to a specific media period.
@ -143,7 +143,7 @@ public abstract class BaseMediaSource implements MediaSource {
/**
* Returns a {@link DrmSessionEventListener.EventDispatcher} which dispatches all events to the
* registered listeners with the specified window index and media period id.
* registered listeners with the specified window index and {@link MediaPeriodId}.
*
* @param windowIndex The timeline window index to be reported with the events.
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events. May be null, if

View File

@ -293,19 +293,6 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
refreshSourceInfo(clippingTimeline);
}
@Override
protected long getMediaTimeForChildMediaTime(Void id, long mediaTimeMs) {
if (mediaTimeMs == C.TIME_UNSET) {
return C.TIME_UNSET;
}
long startMs = C.usToMs(startUs);
long clippedTimeMs = max(0, mediaTimeMs - startMs);
if (endUs != C.TIME_END_OF_SOURCE) {
clippedTimeMs = min(C.usToMs(endUs) - startMs, clippedTimeMs);
}
return clippedTimeMs;
}
/**
* Provides a clipped view of a specified timeline.
*/

View File

@ -184,12 +184,15 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
}
/**
* Returns the media time in the composite source corresponding to the specified media time in a
* child source. The default implementation does not change the media time.
* Returns the media time in the {@link MediaPeriod} of the composite source corresponding to the
* specified media time in the {@link MediaPeriod} of the child source. The default implementation
* does not change the media time.
*
* @param id The unique id used to prepare the child source.
* @param mediaTimeMs A media time of the child source, in milliseconds.
* @return The corresponding media time in the composite source, in milliseconds.
* @param mediaTimeMs A media time in the {@link MediaPeriod} of the child source, in
* milliseconds.
* @return The corresponding media time in the {@link MediaPeriod} of the composite source, in
* milliseconds.
*/
protected long getMediaTimeForChildMediaTime(@UnknownNull T id, long mediaTimeMs) {
return mediaTimeMs;

View File

@ -19,7 +19,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
/** Descriptor for data being loaded or selected by a media source. */
/** Descriptor for data being loaded or selected by a {@link MediaSource}. */
public final class MediaLoadData {
/** One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data. */
@ -45,13 +45,13 @@ public final class MediaLoadData {
*/
@Nullable public final Object trackSelectionData;
/**
* The start time of the media, or {@link C#TIME_UNSET} if the data does not belong to a specific
* media period.
* The start time of the media in the {@link MediaPeriod}, or {@link C#TIME_UNSET} if the data
* does not belong to a specific {@link MediaPeriod}.
*/
public final long mediaStartTimeMs;
/**
* The end time of the media, or {@link C#TIME_UNSET} if the data does not belong to a specific
* media period or the end time is unknown.
* The end time of the media in the {@link MediaPeriod}, or {@link C#TIME_UNSET} if the data does
* not belong to a specific {@link MediaPeriod} or the end time is unknown.
*/
public final long mediaEndTimeMs;

View File

@ -94,9 +94,9 @@ public interface MediaSourceEventListener {
* <p>This method being called does not indicate that playback has failed, or that it will fail.
* The player may be able to recover from the error. Hence applications should <em>not</em>
* implement this method to display a user visible error or initiate an application level retry.
* {@link Player.EventListener#onPlayerError} is the appropriate place to implement such behavior.
* This method is called to provide the application with an opportunity to log the error if it
* wishes to do so.
* {@link Player.Listener#onPlayerError} is the appropriate place to implement such behavior. This
* method is called to provide the application with an opportunity to log the error if it wishes
* to do so.
*
* @param windowIndex The window index in the timeline of the media source this load belongs to.
* @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not

View File

@ -19,7 +19,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
@ -27,8 +26,6 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.ClippingMediaSource.IllegalClippingException;
import com.google.android.exoplayer2.source.MaskingMediaSource.PlaceholderTimeline;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
@ -37,9 +34,6 @@ import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.MediaSourceTestRunner;
import com.google.android.exoplayer2.testutil.TimelineAsserts;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
@ -56,7 +50,7 @@ public final class ClippingMediaSourceTest {
private Period period;
@Before
public void setUp() throws Exception {
public void setUp() {
window = new Timeline.Window();
period = new Timeline.Period();
}
@ -485,140 +479,6 @@ public final class ClippingMediaSourceTest {
TimelineAsserts.assertNextWindowIndices(clippedTimeline, Player.REPEAT_MODE_ALL, false, 0);
}
@Test
public void eventTimeWithinClippedRange() throws IOException {
MediaLoadData mediaLoadData =
getClippingMediaSourceMediaLoadData(
/* clippingStartUs= */ TEST_CLIP_AMOUNT_US,
/* clippingEndUs= */ TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US,
/* eventStartUs= */ TEST_CLIP_AMOUNT_US + 1000,
/* eventEndUs= */ TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US - 1000);
assertThat(C.msToUs(mediaLoadData.mediaStartTimeMs)).isEqualTo(1000);
assertThat(C.msToUs(mediaLoadData.mediaEndTimeMs))
.isEqualTo(TEST_PERIOD_DURATION_US - 2 * TEST_CLIP_AMOUNT_US - 1000);
}
@Test
public void eventTimeOutsideClippedRange() throws IOException {
MediaLoadData mediaLoadData =
getClippingMediaSourceMediaLoadData(
/* clippingStartUs= */ TEST_CLIP_AMOUNT_US,
/* clippingEndUs= */ TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US,
/* eventStartUs= */ TEST_CLIP_AMOUNT_US - 1000,
/* eventEndUs= */ TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US + 1000);
assertThat(C.msToUs(mediaLoadData.mediaStartTimeMs)).isEqualTo(0);
assertThat(C.msToUs(mediaLoadData.mediaEndTimeMs))
.isEqualTo(TEST_PERIOD_DURATION_US - 2 * TEST_CLIP_AMOUNT_US);
}
@Test
public void unsetEventTime() throws IOException {
MediaLoadData mediaLoadData =
getClippingMediaSourceMediaLoadData(
/* clippingStartUs= */ TEST_CLIP_AMOUNT_US,
/* clippingEndUs= */ TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US,
/* eventStartUs= */ C.TIME_UNSET,
/* eventEndUs= */ C.TIME_UNSET);
assertThat(C.msToUs(mediaLoadData.mediaStartTimeMs)).isEqualTo(C.TIME_UNSET);
assertThat(C.msToUs(mediaLoadData.mediaEndTimeMs)).isEqualTo(C.TIME_UNSET);
}
@Test
public void eventTimeWithUnsetDuration() throws IOException {
MediaLoadData mediaLoadData =
getClippingMediaSourceMediaLoadData(
/* clippingStartUs= */ TEST_CLIP_AMOUNT_US,
/* clippingEndUs= */ C.TIME_END_OF_SOURCE,
/* eventStartUs= */ TEST_CLIP_AMOUNT_US,
/* eventEndUs= */ TEST_CLIP_AMOUNT_US + 1_000_000);
assertThat(C.msToUs(mediaLoadData.mediaStartTimeMs)).isEqualTo(0);
assertThat(C.msToUs(mediaLoadData.mediaEndTimeMs)).isEqualTo(1_000_000);
}
/**
* Wraps a timeline of duration {@link #TEST_PERIOD_DURATION_US} in a {@link ClippingMediaSource},
* sends a media source event from the child source and returns the reported {@link MediaLoadData}
* for the clipping media source.
*
* @param clippingStartUs The start time of the media source clipping, in microseconds.
* @param clippingEndUs The end time of the media source clipping, in microseconds.
* @param eventStartUs The start time of the media source event (before clipping), in
* microseconds.
* @param eventEndUs The end time of the media source event (before clipping), in microseconds.
* @return The reported {@link MediaLoadData} for that event.
*/
private static MediaLoadData getClippingMediaSourceMediaLoadData(
long clippingStartUs, long clippingEndUs, final long eventStartUs, final long eventEndUs)
throws IOException {
Timeline timeline =
new SinglePeriodTimeline(
TEST_PERIOD_DURATION_US,
/* isSeekable= */ true,
/* isDynamic= */ false,
/* useLiveConfiguration= */ false,
/* manifest= */ null,
MediaItem.fromUri(Uri.EMPTY));
FakeMediaSource fakeMediaSource =
new FakeMediaSource(timeline) {
@Override
protected MediaPeriod createMediaPeriod(
MediaPeriodId id,
TrackGroupArray trackGroupArray,
Allocator allocator,
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
DrmSessionManager drmSessionManager,
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
@Nullable TransferListener transferListener) {
mediaSourceEventDispatcher.downstreamFormatChanged(
new MediaLoadData(
C.DATA_TYPE_MEDIA,
C.TRACK_TYPE_UNKNOWN,
/* trackFormat= */ null,
C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null,
C.usToMs(eventStartUs),
C.usToMs(eventEndUs)));
return super.createMediaPeriod(
id,
trackGroupArray,
allocator,
mediaSourceEventDispatcher,
drmSessionManager,
drmEventDispatcher,
transferListener);
}
};
final ClippingMediaSource clippingMediaSource =
new ClippingMediaSource(fakeMediaSource, clippingStartUs, clippingEndUs);
MediaSourceTestRunner testRunner =
new MediaSourceTestRunner(clippingMediaSource, /* allocator= */ null);
final MediaLoadData[] reportedMediaLoadData = new MediaLoadData[1];
try {
testRunner.runOnPlaybackThread(
() ->
clippingMediaSource.addEventListener(
Util.createHandlerForCurrentLooper(),
new MediaSourceEventListener() {
@Override
public void onDownstreamFormatChanged(
int windowIndex,
@Nullable MediaPeriodId mediaPeriodId,
MediaLoadData mediaLoadData) {
reportedMediaLoadData[0] = mediaLoadData;
}
}));
testRunner.prepareSource();
// Create period to send the test event configured above.
testRunner.createPeriod(
new MediaPeriodId(
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
assertThat(reportedMediaLoadData[0]).isNotNull();
} finally {
testRunner.release();
}
return reportedMediaLoadData[0];
}
/**
* Wraps the specified timeline in a {@link ClippingMediaSource} and returns the clipped timeline.
*/