Fix sending negative bufferedDurationUs to CmcdData.Factory

When track is changed during playback, `playbackPositionUs` may be in middle of a chunk and `loadPositionUs` should be the start of that chunk. In this situation `loadPositionUs` can be less than the current `playbackPositionUs`, resulting into negative `bufferedDurationUs`. It translates to having no buffer and hence we should send `0` for `bufferedDurationUs` when creating new instances of `CmcdData.Factory`.

Issue: androidx/media#888

#minor-release

PiperOrigin-RevId: 591099785
This commit is contained in:
rohks 2023-12-14 17:37:16 -08:00 committed by Copybara-Service
parent 0baf777c96
commit 7f6596bab2
8 changed files with 62 additions and 4 deletions

View File

@ -36,6 +36,10 @@
* Fix issue where track selections after seek to zero in a live stream
incorrectly let the stream start at its default position
([#9347](https://github.com/google/ExoPlayer/issues/9347)).
* Fix the issue where new instances of `CmcdData.Factory` were receiving
negative values for `bufferedDurationUs` from chunk sources, resulting
in an `IllegalArgumentException`
([#888](https://github.com/androidx/media/issues/888)).
* Transformer:
* Add support for flattening H.265/HEVC SEF slow motion videos.
* Increase transmuxing speed, especially for 'remove video' edits.

View File

@ -121,7 +121,8 @@ public final class CmcdData {
* and this one, {@code false} otherwise.
* @param isBufferEmpty {@code true} if the queue of buffered chunks is empty, {@code false}
* otherwise.
* @throws IllegalArgumentException If {@code bufferedDurationUs} is negative.
* @throws IllegalArgumentException If {@code bufferedDurationUs} is negative or {@code
* playbackRate} is non-positive.
*/
public Factory(
CmcdConfiguration cmcdConfiguration,

View File

@ -410,7 +410,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
: new CmcdData.Factory(
cmcdConfiguration,
trackSelection,
bufferedDurationUs,
max(0, bufferedDurationUs),
/* playbackRate= */ loadingInfo.playbackSpeed,
/* streamingFormat= */ CmcdData.Factory.STREAMING_FORMAT_DASH,
/* isLive= */ manifest.dynamic,

View File

@ -339,6 +339,23 @@ public class DefaultDashChunkSourceTest {
"bl=1000,dl=800,mtp=1000,nor=\"..%2Fvideo_8000_700000.m4s\",nrr=\"0-\"",
"CMCD-Session",
"cid=\"mediaId\",pr=1.25,sf=d,sid=\"" + cmcdConfiguration.sessionId + "\",st=v");
// Playing mid-chunk, where loadPositionUs is less than playbackPositionUs
chunkSource.getNextChunk(
new LoadingInfo.Builder().setPlaybackPositionUs(5_000_000).setPlaybackSpeed(1.25f).build(),
/* loadPositionUs= */ 4_000_000,
/* queue= */ ImmutableList.of((MediaChunk) output.chunk),
output);
// buffer length is set to 0 when bufferedDurationUs is negative
assertThat(output.chunk.dataSpec.httpRequestHeaders)
.containsExactly(
"CMCD-Object",
"br=700,d=4000,ot=v,tb=1300",
"CMCD-Request",
"bl=0,dl=0,mtp=1000,nor=\"..%2Fvideo_12000_700000.m4s\",nrr=\"0-\"",
"CMCD-Session",
"cid=\"mediaId\",pr=1.25,sf=d,sid=\"" + cmcdConfiguration.sessionId + "\",st=v");
}
@Test

View File

@ -495,7 +495,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
new CmcdData.Factory(
cmcdConfiguration,
trackSelection,
bufferedDurationUs,
max(0, bufferedDurationUs),
/* playbackRate= */ loadingInfo.playbackSpeed,
/* streamingFormat= */ CmcdData.Factory.STREAMING_FORMAT_HLS,
/* isLive= */ !playlist.hasEndTag,

View File

@ -234,6 +234,24 @@ public class HlsChunkSourceTest {
"bl=1000,dl=800,nor=\"..%2F3.mp4\",nrr=\"0-\"",
"CMCD-Session",
"cid=\"mediaId\",pr=1.25,sf=h,sid=\"" + cmcdConfiguration.sessionId + "\",st=v");
// Playing mid-chunk, where loadPositionUs is less than playbackPositionUs
testChunkSource.getNextChunk(
new LoadingInfo.Builder().setPlaybackPositionUs(5_000_000).setPlaybackSpeed(1.25f).build(),
/* loadPositionUs= */ 4_000_000,
/* queue= */ ImmutableList.of((HlsMediaChunk) output.chunk),
/* allowEndOfStream= */ true,
output);
// buffer length is set to 0 when bufferedDurationUs is negative
assertThat(output.chunk.dataSpec.httpRequestHeaders)
.containsExactly(
"CMCD-Object",
"br=800,d=4000,ot=v,tb=800",
"CMCD-Request",
"bl=0,dl=0,nor=\"..%2F3.mp4\",nrr=\"0-\"",
"CMCD-Session",
"cid=\"mediaId\",pr=1.25,sf=h,sid=\"" + cmcdConfiguration.sessionId + "\",st=v");
}
@Test

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer.smoothstreaming;
import static androidx.media3.exoplayer.trackselection.TrackSelectionUtil.createFallbackOptions;
import static java.lang.Math.max;
import android.net.Uri;
import android.os.SystemClock;
@ -319,7 +320,7 @@ public class DefaultSsChunkSource implements SsChunkSource {
new CmcdData.Factory(
cmcdConfiguration,
trackSelection,
bufferedDurationUs,
max(0, bufferedDurationUs),
/* playbackRate= */ loadingInfo.playbackSpeed,
/* streamingFormat= */ CmcdData.Factory.STREAMING_FORMAT_SS,
/* isLive= */ manifest.isLive,

View File

@ -89,6 +89,23 @@ public class DefaultSsChunkSourceTest {
"bl=1000,dl=500,mtp=1000,nor=\"..%2FFragments(video%3D28660000)\"",
"CMCD-Session",
"cid=\"mediaId\",pr=2.00,sf=s,sid=\"" + cmcdConfiguration.sessionId + "\",st=v");
// Playing mid-chunk, where loadPositionUs is less than playbackPositionUs
chunkSource.getNextChunk(
new LoadingInfo.Builder().setPlaybackPositionUs(5_000_000).setPlaybackSpeed(2.0f).build(),
/* loadPositionUs= */ 4_000_000,
/* queue= */ ImmutableList.of((MediaChunk) output.chunk),
output);
// buffer length is set to 0 when bufferedDurationUs is negative
assertThat(output.chunk.dataSpec.httpRequestHeaders)
.containsExactly(
"CMCD-Object",
"br=308,d=898,ot=v,tb=1536",
"CMCD-Request",
"bl=0,dl=0,mtp=1000",
"CMCD-Session",
"cid=\"mediaId\",pr=2.00,sf=s,sid=\"" + cmcdConfiguration.sessionId + "\",st=v");
}
@Test