mirror of
https://github.com/androidx/media.git
synced 2025-04-29 22:36:54 +08:00
Improve the precision of percentDownloaded in Downloaders
We don't require high precision in the calculation of `percentDownloaded` for `Downloader.ProgressListener.onProgress` though, when `byteCached == contentLength`, we hope the `percentDownloaded` to be `100f` (rather than `99.99999f`). The result of `byteCached * 100f` can be less precise as the floating-point numbers are sparser when the value is far from zero. For example, if `byteCached == 812345L`, then the `byteCached * 100f` will become `81234496` (value checked by `BigDecimal`). PiperOrigin-RevId: 741895445
This commit is contained in:
parent
c858abda5d
commit
72f5df582a
@ -1223,6 +1223,22 @@ public final class Util {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the percentage of numerator divided by denominator. Note that this may return {@link
|
||||
* Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY} or {@link Float#NaN} if the
|
||||
* denominator is zero.
|
||||
*
|
||||
* @param numerator The numerator.
|
||||
* @param denominator The denominator.
|
||||
*/
|
||||
@UnstableApi
|
||||
public static float percent(long numerator, long denominator) {
|
||||
if (denominator != 0 && numerator == denominator) {
|
||||
return 100f;
|
||||
}
|
||||
return ((float) numerator / denominator) * 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first occurrence of {@code value} in {@code array}, or {@link
|
||||
* C#INDEX_UNSET} if {@code value} is not contained in {@code array}.
|
||||
|
@ -27,6 +27,7 @@ import static androidx.media3.common.util.Util.maxValue;
|
||||
import static androidx.media3.common.util.Util.minValue;
|
||||
import static androidx.media3.common.util.Util.parseXsDateTime;
|
||||
import static androidx.media3.common.util.Util.parseXsDuration;
|
||||
import static androidx.media3.common.util.Util.percent;
|
||||
import static androidx.media3.common.util.Util.unescapeFileName;
|
||||
import static androidx.media3.test.utils.TestUtil.buildTestData;
|
||||
import static androidx.media3.test.utils.TestUtil.buildTestString;
|
||||
@ -147,6 +148,34 @@ public class UtilTest {
|
||||
assertThat(res).isEqualTo(12345);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void percent_numeratorEqualToDenominator_returnsOneHundred() {
|
||||
// With numerator and denominator both being 812345L, the percentage calculated in another way
|
||||
// (numerator * 100f / denominator) will be 99.99999f. We then use this value to verify that
|
||||
// this doesn't happen for Util.percent() method.
|
||||
assertThat(percent(812345L, 812345L)).isEqualTo(100f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void percent_numeratorNotEqualToDenominator_returnsCorrectValue() {
|
||||
assertThat(percent(500L, 2000L)).isEqualTo(25f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void percent_positiveNumeratorAndZeroDenominator_returnsPositiveInfinity() {
|
||||
assertThat(percent(1L, 0L)).isPositiveInfinity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void percent_negativeNumeratorAndZeroDenominator_returnsNegativeInfinity() {
|
||||
assertThat(percent(-1L, 0L)).isNegativeInfinity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void percent_numeratorAndDenominatorAreBothZero_returnsNaN() {
|
||||
assertThat(percent(0L, 0L)).isNaN();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inferContentType_handlesHlsIsmUris() {
|
||||
assertThat(Util.inferContentType(Uri.parse("http://a.b/c.ism/manifest(format=m3u8-aapl)")))
|
||||
|
@ -17,6 +17,7 @@ package androidx.media3.exoplayer.offline;
|
||||
|
||||
import static androidx.annotation.VisibleForTesting.PRIVATE;
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Util.percent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@ -216,7 +217,7 @@ public final class ProgressiveDownloader implements Downloader {
|
||||
float percentDownloaded =
|
||||
contentLength == C.LENGTH_UNSET || contentLength == 0
|
||||
? C.PERCENTAGE_UNSET
|
||||
: ((bytesCached * 100f) / contentLength);
|
||||
progressListener.onProgress(contentLength, bytesCached, percentDownloaded);
|
||||
: percent(bytesCached, contentLength);
|
||||
checkNotNull(progressListener).onProgress(contentLength, bytesCached, percentDownloaded);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
package androidx.media3.exoplayer.offline;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Util.percent;
|
||||
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -536,9 +537,9 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
|
||||
|
||||
private float getPercentDownloaded() {
|
||||
if (contentLength != C.LENGTH_UNSET && contentLength != 0) {
|
||||
return (bytesDownloaded * 100f) / contentLength;
|
||||
return percent(bytesDownloaded, contentLength);
|
||||
} else if (totalSegments != 0) {
|
||||
return (segmentsDownloaded * 100f) / totalSegments;
|
||||
return percent(segmentsDownloaded, totalSegments);
|
||||
} else {
|
||||
return C.PERCENTAGE_UNSET;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user