Commit 057771ae by tonihei Committed by Oliver Woodman

Fix calculation for isSegmentAvailableAtFullNetworkSpeed.

The current caluclation was comparing Unix time with period time.
Fix it by always comparing against period time.

Issue: #4904
PiperOrigin-RevId: 338235754
parent e52a044e
......@@ -277,6 +277,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
}
long nowUnixTimeUs = C.msToUs(Util.getNowUnixTimeMs(elapsedRealtimeOffsetMs));
long nowPeriodTimeUs = getNowPeriodTimeUs(nowUnixTimeUs);
MediaChunk previous = queue.isEmpty() ? null : queue.get(queue.size() - 1);
MediaChunkIterator[] chunkIterators = new MediaChunkIterator[trackSelection.length()];
for (int i = 0; i < chunkIterators.length; i++) {
......@@ -300,7 +301,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
} else {
chunkIterators[i] =
new RepresentationSegmentIterator(
representationHolder, segmentNum, lastAvailableSegmentNum, nowUnixTimeUs);
representationHolder, segmentNum, lastAvailableSegmentNum, nowPeriodTimeUs);
}
}
}
......@@ -391,7 +392,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
segmentNum,
maxSegmentCount,
seekTimeUs,
nowUnixTimeUs);
nowPeriodTimeUs);
}
@Override
......@@ -488,13 +489,16 @@ public class DefaultDashChunkSource implements DashChunkSource {
}
long lastSegmentNum = representationHolders[0].getLastAvailableSegmentNum(nowUnixTimeUs);
long lastSegmentEndTimeUs = representationHolders[0].getSegmentEndTimeUs(lastSegmentNum);
long nowPeriodTimeUs =
nowUnixTimeUs
- C.msToUs(manifest.availabilityStartTimeMs + manifest.getPeriod(periodIndex).startMs);
long nowPeriodTimeUs = getNowPeriodTimeUs(nowUnixTimeUs);
long availabilityEndTimeUs = min(nowPeriodTimeUs, lastSegmentEndTimeUs);
return max(0, availabilityEndTimeUs - playbackPositionUs);
}
private long getNowPeriodTimeUs(long nowUnixTimeUs) {
return nowUnixTimeUs
- C.msToUs(manifest.availabilityStartTimeMs + manifest.getPeriod(periodIndex).startMs);
}
protected Chunk newInitializationChunk(
RepresentationHolder representationHolder,
DataSource dataSource,
......@@ -535,7 +539,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
long firstSegmentNum,
int maxSegmentCount,
long seekTimeUs,
long nowUnixTimeUs) {
long nowPeriodTimeUs) {
Representation representation = representationHolder.representation;
long startTimeUs = representationHolder.getSegmentStartTimeUs(firstSegmentNum);
RangedUri segmentUri = representationHolder.getSegmentUrl(firstSegmentNum);
......@@ -543,7 +547,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
if (representationHolder.chunkExtractor == null) {
long endTimeUs = representationHolder.getSegmentEndTimeUs(firstSegmentNum);
int flags =
representationHolder.isSegmentAvailableAtFullNetworkSpeed(firstSegmentNum, nowUnixTimeUs)
representationHolder.isSegmentAvailableAtFullNetworkSpeed(
firstSegmentNum, nowPeriodTimeUs)
? 0
: DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED;
DataSpec dataSpec = DashUtil.buildDataSpec(representation, segmentUri, flags);
......@@ -569,7 +574,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
? periodDurationUs
: C.TIME_UNSET;
int flags =
representationHolder.isSegmentAvailableAtFullNetworkSpeed(segmentNum, nowUnixTimeUs)
representationHolder.isSegmentAvailableAtFullNetworkSpeed(segmentNum, nowPeriodTimeUs)
? 0
: DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED;
DataSpec dataSpec = DashUtil.buildDataSpec(representation, segmentUri, flags);
......@@ -597,7 +602,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
protected static final class RepresentationSegmentIterator extends BaseMediaChunkIterator {
private final RepresentationHolder representationHolder;
private final long currentUnixTimeUs;
private final long nowPeriodTimeUs;
/**
* Creates iterator.
......@@ -605,17 +610,17 @@ public class DefaultDashChunkSource implements DashChunkSource {
* @param representation The {@link RepresentationHolder} to wrap.
* @param firstAvailableSegmentNum The number of the first available segment.
* @param lastAvailableSegmentNum The number of the last available segment.
* @param currentUnixTimeUs The current time in microseconds since the epoch used for
* calculating if segments are available at full network speed.
* @param nowPeriodTimeUs The current time in microseconds since the start of the period used
* for calculating if segments are available at full network speed.
*/
public RepresentationSegmentIterator(
RepresentationHolder representation,
long firstAvailableSegmentNum,
long lastAvailableSegmentNum,
long currentUnixTimeUs) {
long nowPeriodTimeUs) {
super(/* fromIndex= */ firstAvailableSegmentNum, /* toIndex= */ lastAvailableSegmentNum);
this.representationHolder = representation;
this.currentUnixTimeUs = currentUnixTimeUs;
this.nowPeriodTimeUs = nowPeriodTimeUs;
}
@Override
......@@ -624,7 +629,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
long currentIndex = getCurrentIndex();
RangedUri segmentUri = representationHolder.getSegmentUrl(currentIndex);
int flags =
representationHolder.isSegmentAvailableAtFullNetworkSpeed(currentIndex, currentUnixTimeUs)
representationHolder.isSegmentAvailableAtFullNetworkSpeed(currentIndex, nowPeriodTimeUs)
? 0
: DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED;
return DashUtil.buildDataSpec(representationHolder.representation, segmentUri, flags);
......@@ -787,8 +792,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
- 1;
}
public boolean isSegmentAvailableAtFullNetworkSpeed(long segmentNum, long nowUnixTimeUs) {
return getSegmentEndTimeUs(segmentNum) <= nowUnixTimeUs;
public boolean isSegmentAvailableAtFullNetworkSpeed(long segmentNum, long nowPeriodTimeUs) {
return getSegmentEndTimeUs(segmentNum) <= nowPeriodTimeUs;
}
@Nullable
......
/*
* Copyright (C) 2020 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.exoplayer2.source.dash;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import android.os.SystemClock;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.ChunkHolder;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit test for {@link DefaultDashChunkSource}. */
@RunWith(AndroidJUnit4.class)
public class DefaultDashChunkSourceTest {
private static final String SAMPLE_MPD_LIVE_WITH_OFFSET_INSIDE_WINDOW =
"media/mpd/sample_mpd_live_with_offset_inside_window";
@Test
public void getNextChunk_forLowLatencyManifest_setsCorrectMayNotLoadAtFullNetworkSpeedFlag()
throws Exception {
long nowMs = 2_000_000_000_000L;
SystemClock.setCurrentTimeMillis(nowMs);
DashManifest manifest =
new DashManifestParser()
.parse(
Uri.parse("https://example.com/test.mpd"),
TestUtil.getInputStream(
ApplicationProvider.getApplicationContext(),
SAMPLE_MPD_LIVE_WITH_OFFSET_INSIDE_WINDOW));
DefaultDashChunkSource chunkSource =
new DefaultDashChunkSource(
new LoaderErrorThrower.Dummy(),
manifest,
/* periodIndex= */ 0,
/* adaptationSetIndices= */ new int[] {0},
new FixedTrackSelection(new TrackGroup(new Format.Builder().build()), /* track= */ 0),
C.TRACK_TYPE_VIDEO,
new FakeDataSource(),
/* elapsedRealtimeOffsetMs= */ 0,
/* maxSegmentsPerLoad= */ 1,
/* enableEventMessageTrack= */ false,
/* closedCaptionFormats */ ImmutableList.of(),
/* playerTrackEmsgHandler= */ null);
long nowInPeriodUs = C.msToUs(nowMs - manifest.availabilityStartTimeMs);
ChunkHolder output = new ChunkHolder();
chunkSource.getNextChunk(
/* playbackPositionUs= */ nowInPeriodUs - 5 * C.MICROS_PER_SECOND,
/* loadPositionUs= */ nowInPeriodUs - 5 * C.MICROS_PER_SECOND,
/* queue= */ ImmutableList.of(),
output);
assertThat(output.chunk.dataSpec.flags & DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED)
.isEqualTo(0);
chunkSource.getNextChunk(
/* playbackPositionUs= */ nowInPeriodUs,
/* loadPositionUs= */ nowInPeriodUs,
/* queue= */ ImmutableList.of(),
output);
assertThat(output.chunk.dataSpec.flags & DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED)
.isNotEqualTo(0);
}
}
......@@ -17,7 +17,8 @@
timescale="1000000"
duration="2000000"
availabilityTimeOffset="2"
startNumber="1"/>
startNumber="1"
media="chunk-$Number%05d$.mp4"/>
</Representation>
</AdaptationSet>
</Period>
......
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