From fd803a39a3470bb9b806d7cf76594e1192ee9d28 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 6 Aug 2019 16:18:33 +0100 Subject: [PATCH 01/14] Further MediaPeriod.selectTracks documentation tweak PiperOrigin-RevId: 261917229 --- .../google/android/exoplayer2/source/MediaPeriod.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java index 847c87b077..3f306c0c8a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java @@ -113,15 +113,17 @@ public interface MediaPeriod extends SequenceableLoader { * corresponding flag in {@code streamResetFlags} will be set to true. This flag will also be set * if a new sample stream is created. * - *

Note that previously received {@link TrackSelection TrackSelections} are no longer valid and - * references need to be replaced even if the corresponding {@link SampleStream} is kept. + *

Note that previously passed {@link TrackSelection TrackSelections} are no longer valid, and + * any references to them must be updated to point to the new selections. * *

This method is only called after the period has been prepared. * * @param selections The renderer track selections. * @param mayRetainStreamFlags Flags indicating whether the existing sample stream can be retained - * for each selection. A {@code true} value indicates that the selection is unchanged, and - * that the caller does not require that the sample stream be recreated. + * for each track selection. A {@code true} value indicates that the selection is equivalent + * to the one that was previously passed, and that the caller does not require that the sample + * stream be recreated. If a retained sample stream holds any references to the track + * selection then they must be updated to point to the new selection. * @param streams The existing sample streams, which will be updated to reflect the provided * selections. * @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that From 6617862f0b3a4a829892a51f01fa914b86104122 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 6 Aug 2019 17:28:15 +0100 Subject: [PATCH 02/14] Add allowAudioMixedChannelCountAdaptiveness parameter to DefaultTrackSelector. We already allow mixed mime type and mixed sample rate adaptation on request, so for completeness, we can also allow mixed channel count adaptation. Issue:#6257 PiperOrigin-RevId: 261930046 --- RELEASENOTES.md | 4 ++ .../trackselection/DefaultTrackSelector.java | 55 ++++++++++++++++--- .../DefaultTrackSelectorTest.java | 1 + 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 06cfde8d6c..7c934c478c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -27,6 +27,10 @@ over other selection parameters. * Remove `AnalyticsCollector.Factory`. Instances can be created directly and the `Player` set later using `AnalyticsCollector.setPlayer`. +* Add `allowAudioMixedChannelCountAdaptiveness` parameter to + `DefaultTrackSelector` to allow adaptive selections of audio tracks with + different channel counts + ([#6257](https://github.com/google/ExoPlayer/issues/6257)). ### 2.10.4 ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index cc1742bb31..77a7acc9e4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -177,6 +177,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { private boolean exceedAudioConstraintsIfNecessary; private boolean allowAudioMixedMimeTypeAdaptiveness; private boolean allowAudioMixedSampleRateAdaptiveness; + private boolean allowAudioMixedChannelCountAdaptiveness; // General private boolean forceLowestBitrate; private boolean forceHighestSupportedBitrate; @@ -227,6 +228,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { exceedAudioConstraintsIfNecessary = initialValues.exceedAudioConstraintsIfNecessary; allowAudioMixedMimeTypeAdaptiveness = initialValues.allowAudioMixedMimeTypeAdaptiveness; allowAudioMixedSampleRateAdaptiveness = initialValues.allowAudioMixedSampleRateAdaptiveness; + allowAudioMixedChannelCountAdaptiveness = + initialValues.allowAudioMixedChannelCountAdaptiveness; // General forceLowestBitrate = initialValues.forceLowestBitrate; forceHighestSupportedBitrate = initialValues.forceHighestSupportedBitrate; @@ -424,6 +427,17 @@ public class DefaultTrackSelector extends MappingTrackSelector { return this; } + /** + * See {@link Parameters#allowAudioMixedChannelCountAdaptiveness}. + * + * @return This builder. + */ + public ParametersBuilder setAllowAudioMixedChannelCountAdaptiveness( + boolean allowAudioMixedChannelCountAdaptiveness) { + this.allowAudioMixedChannelCountAdaptiveness = allowAudioMixedChannelCountAdaptiveness; + return this; + } + // Text @Override @@ -640,6 +654,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { exceedAudioConstraintsIfNecessary, allowAudioMixedMimeTypeAdaptiveness, allowAudioMixedSampleRateAdaptiveness, + allowAudioMixedChannelCountAdaptiveness, // Text preferredTextLanguage, selectUndeterminedTextLanguage, @@ -775,6 +790,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { * different sample rates may not be completely seamless. The default value is {@code false}. */ public final boolean allowAudioMixedSampleRateAdaptiveness; + /** + * Whether to allow adaptive audio selections containing mixed channel counts. Adaptations + * between different channel counts may not be completely seamless. The default value is {@code + * false}. + */ + public final boolean allowAudioMixedChannelCountAdaptiveness; // General /** @@ -835,6 +856,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { /* exceedAudioConstraintsIfNecessary= */ true, /* allowAudioMixedMimeTypeAdaptiveness= */ false, /* allowAudioMixedSampleRateAdaptiveness= */ false, + /* allowAudioMixedChannelCountAdaptiveness= */ false, // Text TrackSelectionParameters.DEFAULT.preferredTextLanguage, TrackSelectionParameters.DEFAULT.selectUndeterminedTextLanguage, @@ -867,6 +889,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { boolean exceedAudioConstraintsIfNecessary, boolean allowAudioMixedMimeTypeAdaptiveness, boolean allowAudioMixedSampleRateAdaptiveness, + boolean allowAudioMixedChannelCountAdaptiveness, // Text @Nullable String preferredTextLanguage, boolean selectUndeterminedTextLanguage, @@ -901,6 +924,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { this.exceedAudioConstraintsIfNecessary = exceedAudioConstraintsIfNecessary; this.allowAudioMixedMimeTypeAdaptiveness = allowAudioMixedMimeTypeAdaptiveness; this.allowAudioMixedSampleRateAdaptiveness = allowAudioMixedSampleRateAdaptiveness; + this.allowAudioMixedChannelCountAdaptiveness = allowAudioMixedChannelCountAdaptiveness; // General this.forceLowestBitrate = forceLowestBitrate; this.forceHighestSupportedBitrate = forceHighestSupportedBitrate; @@ -934,6 +958,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { this.exceedAudioConstraintsIfNecessary = Util.readBoolean(in); this.allowAudioMixedMimeTypeAdaptiveness = Util.readBoolean(in); this.allowAudioMixedSampleRateAdaptiveness = Util.readBoolean(in); + this.allowAudioMixedChannelCountAdaptiveness = Util.readBoolean(in); // General this.forceLowestBitrate = Util.readBoolean(in); this.forceHighestSupportedBitrate = Util.readBoolean(in); @@ -1015,6 +1040,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { && exceedAudioConstraintsIfNecessary == other.exceedAudioConstraintsIfNecessary && allowAudioMixedMimeTypeAdaptiveness == other.allowAudioMixedMimeTypeAdaptiveness && allowAudioMixedSampleRateAdaptiveness == other.allowAudioMixedSampleRateAdaptiveness + && allowAudioMixedChannelCountAdaptiveness + == other.allowAudioMixedChannelCountAdaptiveness // General && forceLowestBitrate == other.forceLowestBitrate && forceHighestSupportedBitrate == other.forceHighestSupportedBitrate @@ -1045,6 +1072,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { result = 31 * result + (exceedAudioConstraintsIfNecessary ? 1 : 0); result = 31 * result + (allowAudioMixedMimeTypeAdaptiveness ? 1 : 0); result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0); + result = 31 * result + (allowAudioMixedChannelCountAdaptiveness ? 1 : 0); // General result = 31 * result + (forceLowestBitrate ? 1 : 0); result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0); @@ -1081,6 +1109,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { Util.writeBoolean(dest, exceedAudioConstraintsIfNecessary); Util.writeBoolean(dest, allowAudioMixedMimeTypeAdaptiveness); Util.writeBoolean(dest, allowAudioMixedSampleRateAdaptiveness); + Util.writeBoolean(dest, allowAudioMixedChannelCountAdaptiveness); // General Util.writeBoolean(dest, forceLowestBitrate); Util.writeBoolean(dest, forceHighestSupportedBitrate); @@ -1989,7 +2018,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { formatSupports[selectedGroupIndex], params.maxAudioBitrate, params.allowAudioMixedMimeTypeAdaptiveness, - params.allowAudioMixedSampleRateAdaptiveness); + params.allowAudioMixedSampleRateAdaptiveness, + params.allowAudioMixedChannelCountAdaptiveness); if (adaptiveTracks.length > 0) { definition = new TrackSelection.Definition(selectedGroup, adaptiveTracks); } @@ -2007,7 +2037,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { int[] formatSupport, int maxAudioBitrate, boolean allowMixedMimeTypeAdaptiveness, - boolean allowMixedSampleRateAdaptiveness) { + boolean allowMixedSampleRateAdaptiveness, + boolean allowAudioMixedChannelCountAdaptiveness) { int selectedConfigurationTrackCount = 0; AudioConfigurationTuple selectedConfiguration = null; HashSet seenConfigurationTuples = new HashSet<>(); @@ -2024,7 +2055,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { configuration, maxAudioBitrate, allowMixedMimeTypeAdaptiveness, - allowMixedSampleRateAdaptiveness); + allowMixedSampleRateAdaptiveness, + allowAudioMixedChannelCountAdaptiveness); if (configurationCount > selectedConfigurationTrackCount) { selectedConfiguration = configuration; selectedConfigurationTrackCount = configurationCount; @@ -2044,7 +2076,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { selectedConfiguration, maxAudioBitrate, allowMixedMimeTypeAdaptiveness, - allowMixedSampleRateAdaptiveness)) { + allowMixedSampleRateAdaptiveness, + allowAudioMixedChannelCountAdaptiveness)) { adaptiveIndices[index++] = i; } } @@ -2059,7 +2092,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { AudioConfigurationTuple configuration, int maxAudioBitrate, boolean allowMixedMimeTypeAdaptiveness, - boolean allowMixedSampleRateAdaptiveness) { + boolean allowMixedSampleRateAdaptiveness, + boolean allowAudioMixedChannelCountAdaptiveness) { int count = 0; for (int i = 0; i < group.length; i++) { if (isSupportedAdaptiveAudioTrack( @@ -2068,7 +2102,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { configuration, maxAudioBitrate, allowMixedMimeTypeAdaptiveness, - allowMixedSampleRateAdaptiveness)) { + allowMixedSampleRateAdaptiveness, + allowAudioMixedChannelCountAdaptiveness)) { count++; } } @@ -2081,11 +2116,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { AudioConfigurationTuple configuration, int maxAudioBitrate, boolean allowMixedMimeTypeAdaptiveness, - boolean allowMixedSampleRateAdaptiveness) { + boolean allowMixedSampleRateAdaptiveness, + boolean allowAudioMixedChannelCountAdaptiveness) { return isSupported(formatSupport, false) && (format.bitrate == Format.NO_VALUE || format.bitrate <= maxAudioBitrate) - && (format.channelCount != Format.NO_VALUE - && format.channelCount == configuration.channelCount) + && (allowAudioMixedChannelCountAdaptiveness + || (format.channelCount != Format.NO_VALUE + && format.channelCount == configuration.channelCount)) && (allowMixedMimeTypeAdaptiveness || (format.sampleMimeType != null && TextUtils.equals(format.sampleMimeType, configuration.mimeType))) diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java index 4622dc1734..0374f88bae 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java @@ -148,6 +148,7 @@ public final class DefaultTrackSelectorTest { /* exceedAudioConstraintsIfNecessary= */ false, /* allowAudioMixedMimeTypeAdaptiveness= */ true, /* allowAudioMixedSampleRateAdaptiveness= */ false, + /* allowAudioMixedChannelCountAdaptiveness= */ true, // Text /* preferredTextLanguage= */ "de", /* selectUndeterminedTextLanguage= */ true, From 113e25dc740490104c69afb454315ca210b0b23d Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 7 Aug 2019 11:36:41 +0100 Subject: [PATCH 03/14] Clean up documentation of DefaultTrackSelector.ParametersBuilder. We don't usually refer to other classes when documenting method parameters but rather duplicate the actual definition. PiperOrigin-RevId: 262102714 --- .../trackselection/DefaultTrackSelector.java | 131 +++++++++++++----- .../TrackSelectionParameters.java | 20 ++- 2 files changed, 109 insertions(+), 42 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 77a7acc9e4..8e1284f7ef 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -261,8 +261,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#maxVideoWidth} and {@link Parameters#maxVideoHeight}. + * Sets the maximum allowed video width and height. * + * @param maxVideoWidth Maximum allowed video width in pixels. + * @param maxVideoHeight Maximum allowed video height in pixels. * @return This builder. */ public ParametersBuilder setMaxVideoSize(int maxVideoWidth, int maxVideoHeight) { @@ -272,8 +274,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#maxVideoFrameRate}. + * Sets the maximum allowed video frame rate. * + * @param maxVideoFrameRate Maximum allowed video frame rate in hertz. * @return This builder. */ public ParametersBuilder setMaxVideoFrameRate(int maxVideoFrameRate) { @@ -282,8 +285,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#maxVideoBitrate}. + * Sets the maximum allowed video bitrate. * + * @param maxVideoBitrate Maximum allowed video bitrate in bits per second. * @return This builder. */ public ParametersBuilder setMaxVideoBitrate(int maxVideoBitrate) { @@ -292,8 +296,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#exceedVideoConstraintsIfNecessary}. + * Sets whether to exceed the {@link #setMaxVideoSize(int, int)} and {@link + * #setMaxAudioBitrate(int)} constraints when no selection can be made otherwise. * + * @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no + * selection can be made otherwise. * @return This builder. */ public ParametersBuilder setExceedVideoConstraintsIfNecessary( @@ -303,8 +310,14 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#allowVideoMixedMimeTypeAdaptiveness}. + * Sets whether to allow adaptive video selections containing mixed MIME types. * + *

Adaptations between different MIME types may not be completely seamless, in which case + * {@link #setAllowVideoNonSeamlessAdaptiveness(boolean)} also needs to be {@code true} for + * mixed MIME type selections to be made. + * + * @param allowVideoMixedMimeTypeAdaptiveness Whether to allow adaptive video selections + * containing mixed MIME types. * @return This builder. */ public ParametersBuilder setAllowVideoMixedMimeTypeAdaptiveness( @@ -314,8 +327,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#allowVideoNonSeamlessAdaptiveness}. + * Sets whether to allow adaptive video selections where adaptation may not be completely + * seamless. * + * @param allowVideoNonSeamlessAdaptiveness Whether to allow adaptive video selections where + * adaptation may not be completely seamless. * @return This builder. */ public ParametersBuilder setAllowVideoNonSeamlessAdaptiveness( @@ -329,7 +345,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { * obtained from {@link Util#getPhysicalDisplaySize(Context)}. * * @param context Any context. - * @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}. + * @param viewportOrientationMayChange Whether the viewport orientation may change during + * playback. * @return This builder. */ public ParametersBuilder setViewportSizeToPhysicalDisplaySize( @@ -350,12 +367,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#viewportWidth}, {@link Parameters#maxVideoHeight} and {@link - * Parameters#viewportOrientationMayChange}. + * Sets the viewport size to constrain adaptive video selections so that only tracks suitable + * for the viewport are selected. * - * @param viewportWidth See {@link Parameters#viewportWidth}. - * @param viewportHeight See {@link Parameters#viewportHeight}. - * @param viewportOrientationMayChange See {@link Parameters#viewportOrientationMayChange}. + * @param viewportWidth Viewport width in pixels. + * @param viewportHeight Viewport height in pixels. + * @param viewportOrientationMayChange Whether the viewport orientation may change during + * playback. * @return This builder. */ public ParametersBuilder setViewportSize( @@ -375,8 +393,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#maxAudioChannelCount}. + * Sets the maximum allowed audio channel count. * + * @param maxAudioChannelCount Maximum allowed audio channel count. * @return This builder. */ public ParametersBuilder setMaxAudioChannelCount(int maxAudioChannelCount) { @@ -385,8 +404,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#maxAudioBitrate}. + * Sets the maximum allowed audio bitrate. * + * @param maxAudioBitrate Maximum allowed audio bitrate in bits per second. * @return This builder. */ public ParametersBuilder setMaxAudioBitrate(int maxAudioBitrate) { @@ -395,8 +415,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#exceedAudioConstraintsIfNecessary}. + * Sets whether to exceed the {@link #setMaxAudioChannelCount(int)} and {@link + * #setMaxAudioBitrate(int)} constraints when no selection can be made otherwise. * + * @param exceedAudioConstraintsIfNecessary Whether to exceed audio constraints when no + * selection can be made otherwise. * @return This builder. */ public ParametersBuilder setExceedAudioConstraintsIfNecessary( @@ -406,8 +429,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#allowAudioMixedMimeTypeAdaptiveness}. + * Sets whether to allow adaptive audio selections containing mixed MIME types. * + *

Adaptations between different MIME types may not be completely seamless. + * + * @param allowAudioMixedMimeTypeAdaptiveness Whether to allow adaptive audio selections + * containing mixed MIME types. * @return This builder. */ public ParametersBuilder setAllowAudioMixedMimeTypeAdaptiveness( @@ -417,8 +444,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#allowAudioMixedSampleRateAdaptiveness}. + * Sets whether to allow adaptive audio selections containing mixed sample rates. * + *

Adaptations between different sample rates may not be completely seamless. + * + * @param allowAudioMixedSampleRateAdaptiveness Whether to allow adaptive audio selections + * containing mixed sample rates. * @return This builder. */ public ParametersBuilder setAllowAudioMixedSampleRateAdaptiveness( @@ -428,8 +459,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#allowAudioMixedChannelCountAdaptiveness}. + * Sets whether to allow adaptive audio selections containing mixed channel counts. * + *

Adaptations between different channel counts may not be completely seamless. + * + * @param allowAudioMixedChannelCountAdaptiveness Whether to allow adaptive audio selections + * containing mixed channel counts. * @return This builder. */ public ParametersBuilder setAllowAudioMixedChannelCountAdaptiveness( @@ -462,8 +497,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { // General /** - * See {@link Parameters#forceLowestBitrate}. + * Sets whether to force selection of the single lowest bitrate audio and video tracks that + * comply with all other constraints. * + * @param forceLowestBitrate Whether to force selection of the single lowest bitrate audio and + * video tracks. * @return This builder. */ public ParametersBuilder setForceLowestBitrate(boolean forceLowestBitrate) { @@ -472,8 +510,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#forceHighestSupportedBitrate}. + * Sets whether to force selection of the highest bitrate audio and video tracks that comply + * with all other constraints. * + * @param forceHighestSupportedBitrate Whether to force selection of the highest bitrate audio + * and video tracks. * @return This builder. */ public ParametersBuilder setForceHighestSupportedBitrate(boolean forceHighestSupportedBitrate) { @@ -499,8 +540,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#exceedRendererCapabilitiesIfNecessary}. + * Sets whether to exceed renderer capabilities when no selection can be made otherwise. * + *

This parameter applies when all of the tracks available for a renderer exceed the + * renderer's reported capabilities. If the parameter is {@code true} then the lowest quality + * track will still be selected. Playback may succeed if the renderer has under-reported its + * true capabilities. If {@code false} then no track will be selected. + * + * @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no + * selection can be made otherwise. * @return This builder. */ public ParametersBuilder setExceedRendererCapabilitiesIfNecessary( @@ -510,7 +558,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * See {@link Parameters#tunnelingAudioSessionId}. + * Sets the audio session id to use when tunneling. * *

Enables or disables tunneling. To enable tunneling, pass an audio session id to use when * in tunneling mode. Session ids can be generated using {@link @@ -520,6 +568,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { * * @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link * C#AUDIO_SESSION_ID_UNSET} to disable tunneling. + * @return This builder. */ public ParametersBuilder setTunnelingAudioSessionId(int tunnelingAudioSessionId) { this.tunnelingAudioSessionId = tunnelingAudioSessionId; @@ -534,6 +583,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { * * @param rendererIndex The renderer index. * @param disabled Whether the renderer is disabled. + * @return This builder. */ public final ParametersBuilder setRendererDisabled(int rendererIndex, boolean disabled) { if (rendererDisabledFlags.get(rendererIndex) == disabled) { @@ -570,6 +620,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { * @param rendererIndex The renderer index. * @param groups The {@link TrackGroupArray} for which the override should be applied. * @param override The override. + * @return This builder. */ public final ParametersBuilder setSelectionOverride( int rendererIndex, TrackGroupArray groups, SelectionOverride override) { @@ -591,6 +642,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { * * @param rendererIndex The renderer index. * @param groups The {@link TrackGroupArray} for which the override should be cleared. + * @return This builder. */ public final ParametersBuilder clearSelectionOverride( int rendererIndex, TrackGroupArray groups) { @@ -610,6 +662,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { * Clears all track selection overrides for the specified renderer. * * @param rendererIndex The renderer index. + * @return This builder. */ public final ParametersBuilder clearSelectionOverrides(int rendererIndex) { Map overrides = selectionOverrides.get(rendererIndex); @@ -621,7 +674,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { return this; } - /** Clears all track selection overrides for all renderers. */ + /** + * Clears all track selection overrides for all renderers. + * + * @return This builder. + */ public final ParametersBuilder clearSelectionOverrides() { if (selectionOverrides.size() == 0) { // Nothing to clear. @@ -703,8 +760,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { // Video /** - * Maximum allowed video width. The default value is {@link Integer#MAX_VALUE} (i.e. no - * constraint). + * Maximum allowed video width in pixels. The default value is {@link Integer#MAX_VALUE} (i.e. + * no constraint). * *

To constrain adaptive video track selections to be suitable for a given viewport (the * region of the display within which video will be played), use ({@link #viewportWidth}, {@link @@ -712,8 +769,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { */ public final int maxVideoWidth; /** - * Maximum allowed video height. The default value is {@link Integer#MAX_VALUE} (i.e. no - * constraint). + * Maximum allowed video height in pixels. The default value is {@link Integer#MAX_VALUE} (i.e. + * no constraint). * *

To constrain adaptive video track selections to be suitable for a given viewport (the * region of the display within which video will be played), use ({@link #viewportWidth}, {@link @@ -721,12 +778,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { */ public final int maxVideoHeight; /** - * Maximum allowed video frame rate. The default value is {@link Integer#MAX_VALUE} (i.e. no - * constraint). + * Maximum allowed video frame rate in hertz. The default value is {@link Integer#MAX_VALUE} + * (i.e. no constraint). */ public final int maxVideoFrameRate; /** - * Maximum video bitrate. The default value is {@link Integer#MAX_VALUE} (i.e. no constraint). + * Maximum allowed video bitrate in bits per second. The default value is {@link + * Integer#MAX_VALUE} (i.e. no constraint). */ public final int maxVideoBitrate; /** @@ -736,9 +794,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { */ public final boolean exceedVideoConstraintsIfNecessary; /** - * Whether to allow adaptive video selections containing mixed mime types. Adaptations between - * different mime types may not be completely seamless, in which case {@link - * #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed mime type + * Whether to allow adaptive video selections containing mixed MIME types. Adaptations between + * different MIME types may not be completely seamless, in which case {@link + * #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed MIME type * selections to be made. The default value is {@code false}. */ public final boolean allowVideoMixedMimeTypeAdaptiveness; @@ -772,7 +830,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { */ public final int maxAudioChannelCount; /** - * Maximum audio bitrate. The default value is {@link Integer#MAX_VALUE} (i.e. no constraint). + * Maximum allowed audio bitrate in bits per second. The default value is {@link + * Integer#MAX_VALUE} (i.e. no constraint). */ public final int maxAudioBitrate; /** @@ -781,8 +840,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { */ public final boolean exceedAudioConstraintsIfNecessary; /** - * Whether to allow adaptive audio selections containing mixed mime types. Adaptations between - * different mime types may not be completely seamless. The default value is {@code false}. + * Whether to allow adaptive audio selections containing mixed MIME types. Adaptations between + * different MIME types may not be completely seamless. The default value is {@code false}. */ public final boolean allowAudioMixedMimeTypeAdaptiveness; /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java index 81af551b68..c406f262d1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java @@ -53,9 +53,10 @@ public class TrackSelectionParameters implements Parcelable { } /** - * See {@link TrackSelectionParameters#preferredAudioLanguage}. + * Sets the preferred language for audio and forced text tracks. * - * @param preferredAudioLanguage Preferred audio language as an IETF BCP 47 conformant tag. + * @param preferredAudioLanguage Preferred audio language as an IETF BCP 47 conformant tag, or + * {@code null} to select the default track, or the first track if there's no default. * @return This builder. */ public Builder setPreferredAudioLanguage(@Nullable String preferredAudioLanguage) { @@ -64,9 +65,10 @@ public class TrackSelectionParameters implements Parcelable { } /** - * See {@link TrackSelectionParameters#preferredTextLanguage}. + * Sets the preferred language for text tracks. * - * @param preferredTextLanguage Preferred text language as an IETF BCP 47 conformant tag. + * @param preferredTextLanguage Preferred text language as an IETF BCP 47 conformant tag, or + * {@code null} to select the default track if there is one, or no track otherwise. * @return This builder. */ public Builder setPreferredTextLanguage(@Nullable String preferredTextLanguage) { @@ -75,8 +77,12 @@ public class TrackSelectionParameters implements Parcelable { } /** - * See {@link TrackSelectionParameters#selectUndeterminedTextLanguage}. + * Sets whether a text track with undetermined language should be selected if no track with + * {@link #setPreferredTextLanguage(String)} is available, or if the preferred language is + * unset. * + * @param selectUndeterminedTextLanguage Whether a text track with undetermined language should + * be selected if no preferred language track is available. * @return This builder. */ public Builder setSelectUndeterminedTextLanguage(boolean selectUndeterminedTextLanguage) { @@ -85,8 +91,10 @@ public class TrackSelectionParameters implements Parcelable { } /** - * See {@link TrackSelectionParameters#disabledTextTrackSelectionFlags}. + * Sets a bitmask of selection flags that are disabled for text track selections. * + * @param disabledTextTrackSelectionFlags A bitmask of {@link C.SelectionFlags} that are + * disabled for text track selections. * @return This builder. */ public Builder setDisabledTextTrackSelectionFlags( From 79e962c55a42844cde02710fec1e9644c9221cc5 Mon Sep 17 00:00:00 2001 From: ibaker Date: Wed, 7 Aug 2019 14:18:22 +0100 Subject: [PATCH 04/14] Expose a method on EventMessageDecoder that returns EventMessage directly PiperOrigin-RevId: 262121134 --- .../exoplayer2/metadata/emsg/EventMessageDecoder.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java index a49bf956b3..340b662e97 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java @@ -37,7 +37,10 @@ public final class EventMessageDecoder implements MetadataDecoder { ByteBuffer buffer = inputBuffer.data; byte[] data = buffer.array(); int size = buffer.limit(); - ParsableByteArray emsgData = new ParsableByteArray(data, size); + return new Metadata(decode(new ParsableByteArray(data, size))); + } + + public EventMessage decode(ParsableByteArray emsgData) { String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString()); String value = Assertions.checkNotNull(emsgData.readNullTerminatedString()); long timescale = emsgData.readUnsignedInt(); @@ -50,8 +53,9 @@ public final class EventMessageDecoder implements MetadataDecoder { long durationMs = Util.scaleLargeTimestamp(emsgData.readUnsignedInt(), C.MILLIS_PER_SECOND, timescale); long id = emsgData.readUnsignedInt(); - byte[] messageData = Arrays.copyOfRange(data, emsgData.getPosition(), size); - return new Metadata(new EventMessage(schemeIdUri, value, durationMs, id, messageData)); + byte[] messageData = + Arrays.copyOfRange(emsgData.data, emsgData.getPosition(), emsgData.limit()); + return new EventMessage(schemeIdUri, value, durationMs, id, messageData); } } From 074b6f8ebd14371ccfa699fadacb8b15dcdc1b57 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 7 Aug 2019 14:36:57 +0100 Subject: [PATCH 05/14] Fix DASH module API nullability issues and add package-level non-null-by-default PiperOrigin-RevId: 262123595 --- library/dash/build.gradle | 1 + .../source/dash/DashMediaPeriod.java | 9 +- .../source/dash/DashMediaSource.java | 30 +++--- .../exoplayer2/source/dash/DashUtil.java | 16 ++-- .../source/dash/DefaultDashChunkSource.java | 6 +- .../source/dash/manifest/DashManifest.java | 16 ++-- .../dash/manifest/DashManifestParser.java | 94 +++++++++++-------- .../source/dash/manifest/Descriptor.java | 12 +-- .../dash/manifest/ProgramInformation.java | 16 ++-- .../source/dash/manifest/RangedUri.java | 2 +- .../source/dash/manifest/Representation.java | 45 +++++---- .../source/dash/manifest/SegmentBase.java | 50 ++++++---- .../source/dash/manifest/package-info.java | 19 ++++ .../source/dash/offline/package-info.java | 19 ++++ .../exoplayer2/source/dash/package-info.java | 19 ++++ 15 files changed, 228 insertions(+), 126 deletions(-) create mode 100644 library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/package-info.java create mode 100644 library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/package-info.java create mode 100644 library/dash/src/main/java/com/google/android/exoplayer2/source/dash/package-info.java diff --git a/library/dash/build.gradle b/library/dash/build.gradle index 9f5775d478..c34ed8c907 100644 --- a/library/dash/build.gradle +++ b/library/dash/build.gradle @@ -41,6 +41,7 @@ android { dependencies { implementation project(modulePrefix + 'library-core') compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion + compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion implementation 'androidx.annotation:annotation:1.1.0' testImplementation project(modulePrefix + 'testutils-robolectric') } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index 5daa1a8fd5..21fd43da21 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -60,6 +60,7 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.checkerframework.checker.nullness.compatqual.NullableType; /** A DASH {@link MediaPeriod}. */ /* package */ final class DashMediaPeriod @@ -245,8 +246,12 @@ import java.util.regex.Pattern; } @Override - public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, - SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { + public long selectTracks( + @NullableType TrackSelection[] selections, + boolean[] mayRetainStreamFlags, + @NullableType SampleStream[] streams, + boolean[] streamResetFlags, + long positionUs) { int[] streamIndexToTrackGroupIndex = getStreamIndexToTrackGroupIndex(selections); releaseDisabledStreams(selections, mayRetainStreamFlags, streams); releaseOrphanEmbeddedStreams(selections, streams, streamIndexToTrackGroupIndex); diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 576491b464..890a272c5e 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -130,7 +130,7 @@ public final class DashMediaSource extends BaseMediaSource { * @return This factory, for convenience. * @throws IllegalStateException If one of the {@code create} methods has already been called. */ - public Factory setTag(Object tag) { + public Factory setTag(@Nullable Object tag) { Assertions.checkState(!isCreateCalled); this.tag = tag; return this; @@ -430,8 +430,8 @@ public final class DashMediaSource extends BaseMediaSource { public DashMediaSource( DashManifest manifest, DashChunkSource.Factory chunkSourceFactory, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( manifest, chunkSourceFactory, @@ -455,8 +455,8 @@ public final class DashMediaSource extends BaseMediaSource { DashManifest manifest, DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( manifest, /* manifestUri= */ null, @@ -492,8 +492,8 @@ public final class DashMediaSource extends BaseMediaSource { Uri manifestUri, DataSource.Factory manifestDataSourceFactory, DashChunkSource.Factory chunkSourceFactory, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( manifestUri, manifestDataSourceFactory, @@ -529,8 +529,8 @@ public final class DashMediaSource extends BaseMediaSource { DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, long livePresentationDelayMs, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( manifestUri, manifestDataSourceFactory, @@ -569,8 +569,8 @@ public final class DashMediaSource extends BaseMediaSource { DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, long livePresentationDelayMs, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( /* manifest= */ null, manifestUri, @@ -591,10 +591,10 @@ public final class DashMediaSource extends BaseMediaSource { } private DashMediaSource( - DashManifest manifest, - Uri manifestUri, - DataSource.Factory manifestDataSourceFactory, - ParsingLoadable.Parser manifestParser, + @Nullable DashManifest manifest, + @Nullable Uri manifestUri, + @Nullable DataSource.Factory manifestDataSourceFactory, + @Nullable ParsingLoadable.Parser manifestParser, DashChunkSource.Factory chunkSourceFactory, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, DrmSessionManager drmSessionManager, diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java index 6a6e08ce1d..c9433b9e41 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java @@ -66,7 +66,8 @@ public final class DashUtil { * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ - public static @Nullable DrmInitData loadDrmInitData(DataSource dataSource, Period period) + @Nullable + public static DrmInitData loadDrmInitData(DataSource dataSource, Period period) throws IOException, InterruptedException { int primaryTrackType = C.TRACK_TYPE_VIDEO; Representation representation = getFirstRepresentation(period, primaryTrackType); @@ -95,7 +96,8 @@ public final class DashUtil { * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ - public static @Nullable Format loadSampleFormat( + @Nullable + public static Format loadSampleFormat( DataSource dataSource, int trackType, Representation representation) throws IOException, InterruptedException { ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, @@ -116,7 +118,8 @@ public final class DashUtil { * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ - public static @Nullable ChunkIndex loadChunkIndex( + @Nullable + public static ChunkIndex loadChunkIndex( DataSource dataSource, int trackType, Representation representation) throws IOException, InterruptedException { ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, @@ -138,7 +141,8 @@ public final class DashUtil { * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ - private static @Nullable ChunkExtractorWrapper loadInitializationData( + @Nullable + private static ChunkExtractorWrapper loadInitializationData( DataSource dataSource, int trackType, Representation representation, boolean loadIndex) throws IOException, InterruptedException { RangedUri initializationUri = representation.getInitializationUri(); @@ -187,7 +191,8 @@ public final class DashUtil { return new ChunkExtractorWrapper(extractor, trackType, format); } - private static @Nullable Representation getFirstRepresentation(Period period, int type) { + @Nullable + private static Representation getFirstRepresentation(Period period, int type) { int index = period.getAdaptationSetIndex(type); if (index == C.INDEX_UNSET) { return null; @@ -197,5 +202,4 @@ public final class DashUtil { } private DashUtil() {} - } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index bcf0a1766a..cd39c9538a 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -67,7 +67,7 @@ public class DefaultDashChunkSource implements DashChunkSource { private final int maxSegmentsPerLoad; public Factory(DataSource.Factory dataSourceFactory) { - this(dataSourceFactory, 1); + this(dataSourceFactory, /* maxSegmentsPerLoad= */ 1); } public Factory(DataSource.Factory dataSourceFactory, int maxSegmentsPerLoad) { @@ -633,7 +633,7 @@ public class DefaultDashChunkSource implements DashChunkSource { Representation representation, boolean enableEventMessageTrack, List closedCaptionFormats, - TrackOutput playerEmsgTrackOutput) { + @Nullable TrackOutput playerEmsgTrackOutput) { this( periodDurationUs, representation, @@ -787,7 +787,7 @@ public class DefaultDashChunkSource implements DashChunkSource { Representation representation, boolean enableEventMessageTrack, List closedCaptionFormats, - TrackOutput playerEmsgTrackOutput) { + @Nullable TrackOutput playerEmsgTrackOutput) { String containerMimeType = representation.format.containerMimeType; if (mimeTypeIsRawText(containerMimeType)) { return null; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java index 0c3f641cbe..2d8909f8b4 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java @@ -80,12 +80,10 @@ public class DashManifest implements FilterableManifest { * The {@link UtcTimingElement}, or null if not present. Defined in DVB A168:7/2016, Section * 4.7.2. */ - public final UtcTimingElement utcTiming; + @Nullable public final UtcTimingElement utcTiming; - /** - * The location of this manifest. - */ - public final Uri location; + /** The location of this manifest, or null if not present. */ + @Nullable public final Uri location; /** The {@link ProgramInformation}, or null if not present. */ @Nullable public final ProgramInformation programInformation; @@ -106,8 +104,8 @@ public class DashManifest implements FilterableManifest { long timeShiftBufferDepthMs, long suggestedPresentationDelayMs, long publishTimeMs, - UtcTimingElement utcTiming, - Uri location, + @Nullable UtcTimingElement utcTiming, + @Nullable Uri location, List periods) { this( availabilityStartTimeMs, @@ -134,8 +132,8 @@ public class DashManifest implements FilterableManifest { long suggestedPresentationDelayMs, long publishTimeMs, @Nullable ProgramInformation programInformation, - UtcTimingElement utcTiming, - Uri location, + @Nullable UtcTimingElement utcTiming, + @Nullable Uri location, List periods) { this.availabilityStartTimeMs = availabilityStartTimeMs; this.durationMs = durationMs; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index 1419f8198c..8affcb27ce 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source.dash.manifest; import android.net.Uri; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.util.Base64; import android.util.Pair; @@ -47,6 +48,7 @@ import java.util.List; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.checkerframework.checker.nullness.compatqual.NullableType; import org.xml.sax.helpers.DefaultHandler; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -189,9 +191,9 @@ public class DashManifestParser extends DefaultHandler long timeShiftBufferDepthMs, long suggestedPresentationDelayMs, long publishTimeMs, - ProgramInformation programInformation, - UtcTimingElement utcTiming, - Uri location, + @Nullable ProgramInformation programInformation, + @Nullable UtcTimingElement utcTiming, + @Nullable Uri location, List periods) { return new DashManifest( availabilityStartTime, @@ -259,8 +261,9 @@ public class DashManifestParser extends DefaultHandler // AdaptationSet parsing. - protected AdaptationSet parseAdaptationSet(XmlPullParser xpp, String baseUrl, - SegmentBase segmentBase) throws XmlPullParserException, IOException { + protected AdaptationSet parseAdaptationSet( + XmlPullParser xpp, String baseUrl, @Nullable SegmentBase segmentBase) + throws XmlPullParserException, IOException { int id = parseInt(xpp, "id", AdaptationSet.ID_UNSET); int contentType = parseContentType(xpp); @@ -394,8 +397,8 @@ public class DashManifestParser extends DefaultHandler * @return The scheme type and/or {@link SchemeData} parsed from the ContentProtection element. * Either or both may be null, depending on the ContentProtection element being parsed. */ - protected Pair parseContentProtection(XmlPullParser xpp) - throws XmlPullParserException, IOException { + protected Pair<@NullableType String, @NullableType SchemeData> parseContentProtection( + XmlPullParser xpp) throws XmlPullParserException, IOException { String schemeType = null; String licenseServerUrl = null; byte[] data = null; @@ -477,19 +480,19 @@ public class DashManifestParser extends DefaultHandler protected RepresentationInfo parseRepresentation( XmlPullParser xpp, String baseUrl, - String label, - String adaptationSetMimeType, - String adaptationSetCodecs, + @Nullable String label, + @Nullable String adaptationSetMimeType, + @Nullable String adaptationSetCodecs, int adaptationSetWidth, int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels, int adaptationSetAudioSamplingRate, - String adaptationSetLanguage, + @Nullable String adaptationSetLanguage, List adaptationSetRoleDescriptors, List adaptationSetAccessibilityDescriptors, List adaptationSetSupplementalProperties, - SegmentBase segmentBase) + @Nullable SegmentBase segmentBase) throws XmlPullParserException, IOException { String id = xpp.getAttributeValue(null, "id"); int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE); @@ -564,19 +567,19 @@ public class DashManifestParser extends DefaultHandler } protected Format buildFormat( - String id, - String label, - String containerMimeType, + @Nullable String id, + @Nullable String label, + @Nullable String containerMimeType, int width, int height, float frameRate, int audioChannels, int audioSamplingRate, int bitrate, - String language, + @Nullable String language, List roleDescriptors, List accessibilityDescriptors, - String codecs, + @Nullable String codecs, List supplementalProperties) { String sampleMimeType = getSampleMimeType(containerMimeType, codecs); @C.SelectionFlags int selectionFlags = parseSelectionFlagsFromRoleDescriptors(roleDescriptors); @@ -650,7 +653,7 @@ public class DashManifestParser extends DefaultHandler protected Representation buildRepresentation( RepresentationInfo representationInfo, - String extraDrmSchemeType, + @Nullable String extraDrmSchemeType, ArrayList extraDrmSchemeDatas, ArrayList extraInbandEventStreams) { Format format = representationInfo.format; @@ -675,7 +678,8 @@ public class DashManifestParser extends DefaultHandler // SegmentBase, SegmentList and SegmentTemplate parsing. - protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, SingleSegmentBase parent) + protected SingleSegmentBase parseSegmentBase( + XmlPullParser xpp, @Nullable SingleSegmentBase parent) throws XmlPullParserException, IOException { long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); @@ -711,7 +715,7 @@ public class DashManifestParser extends DefaultHandler indexLength); } - protected SegmentList parseSegmentList(XmlPullParser xpp, SegmentList parent) + protected SegmentList parseSegmentList(XmlPullParser xpp, @Nullable SegmentList parent) throws XmlPullParserException, IOException { long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); @@ -756,15 +760,15 @@ public class DashManifestParser extends DefaultHandler long presentationTimeOffset, long startNumber, long duration, - List timeline, - List segments) { + @Nullable List timeline, + @Nullable List segments) { return new SegmentList(initialization, timescale, presentationTimeOffset, startNumber, duration, timeline, segments); } protected SegmentTemplate parseSegmentTemplate( XmlPullParser xpp, - SegmentTemplate parent, + @Nullable SegmentTemplate parent, List adaptationSetSupplementalProperties) throws XmlPullParserException, IOException { long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); @@ -819,8 +823,8 @@ public class DashManifestParser extends DefaultHandler long endNumber, long duration, List timeline, - UrlTemplate initializationTemplate, - UrlTemplate mediaTemplate) { + @Nullable UrlTemplate initializationTemplate, + @Nullable UrlTemplate mediaTemplate) { return new SegmentTemplate( initialization, timescale, @@ -1008,8 +1012,9 @@ public class DashManifestParser extends DefaultHandler return new SegmentTimelineElement(elapsedTime, duration); } - protected UrlTemplate parseUrlTemplate(XmlPullParser xpp, String name, - UrlTemplate defaultValue) { + @Nullable + protected UrlTemplate parseUrlTemplate( + XmlPullParser xpp, String name, @Nullable UrlTemplate defaultValue) { String valueString = xpp.getAttributeValue(null, name); if (valueString != null) { return UrlTemplate.compile(valueString); @@ -1126,7 +1131,7 @@ public class DashManifestParser extends DefaultHandler } @C.RoleFlags - protected int parseDashRoleSchemeValue(String value) { + protected int parseDashRoleSchemeValue(@Nullable String value) { if (value == null) { return 0; } @@ -1159,7 +1164,7 @@ public class DashManifestParser extends DefaultHandler } @C.RoleFlags - protected int parseTvaAudioPurposeCsValue(String value) { + protected int parseTvaAudioPurposeCsValue(@Nullable String value) { if (value == null) { return 0; } @@ -1230,7 +1235,9 @@ public class DashManifestParser extends DefaultHandler * @param codecs The codecs attribute. * @return The derived sample mimeType, or null if it could not be derived. */ - private static String getSampleMimeType(String containerMimeType, String codecs) { + @Nullable + private static String getSampleMimeType( + @Nullable String containerMimeType, @Nullable String codecs) { if (MimeTypes.isAudio(containerMimeType)) { return MimeTypes.getAudioMediaMimeType(codecs); } else if (MimeTypes.isVideo(containerMimeType)) { @@ -1264,7 +1271,7 @@ public class DashManifestParser extends DefaultHandler * @param mimeType The mimeType. * @return Whether the mimeType is a text sample mimeType. */ - private static boolean mimeTypeIsRawText(String mimeType) { + private static boolean mimeTypeIsRawText(@Nullable String mimeType) { return MimeTypes.isText(mimeType) || MimeTypes.APPLICATION_TTML.equals(mimeType) || MimeTypes.APPLICATION_MP4VTT.equals(mimeType) @@ -1273,16 +1280,18 @@ public class DashManifestParser extends DefaultHandler } /** - * Checks two languages for consistency, returning the consistent language, or throwing an - * {@link IllegalStateException} if the languages are inconsistent. - *

- * Two languages are consistent if they are equal, or if one is null. + * Checks two languages for consistency, returning the consistent language, or throwing an {@link + * IllegalStateException} if the languages are inconsistent. + * + *

Two languages are consistent if they are equal, or if one is null. * * @param firstLanguage The first language. * @param secondLanguage The second language. * @return The consistent language. */ - private static String checkLanguageConsistency(String firstLanguage, String secondLanguage) { + @Nullable + private static String checkLanguageConsistency( + @Nullable String firstLanguage, @Nullable String secondLanguage) { if (firstLanguage == null) { return secondLanguage; } else if (secondLanguage == null) { @@ -1485,14 +1494,19 @@ public class DashManifestParser extends DefaultHandler public final Format format; public final String baseUrl; public final SegmentBase segmentBase; - public final String drmSchemeType; + @Nullable public final String drmSchemeType; public final ArrayList drmSchemeDatas; public final ArrayList inbandEventStreams; public final long revisionId; - public RepresentationInfo(Format format, String baseUrl, SegmentBase segmentBase, - String drmSchemeType, ArrayList drmSchemeDatas, - ArrayList inbandEventStreams, long revisionId) { + public RepresentationInfo( + Format format, + String baseUrl, + SegmentBase segmentBase, + @Nullable String drmSchemeType, + ArrayList drmSchemeDatas, + ArrayList inbandEventStreams, + long revisionId) { this.format = format; this.baseUrl = baseUrl; this.segmentBase = segmentBase; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java index 493a8da09c..d68690d363 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.source.dash.manifest; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.exoplayer2.util.Util; @@ -24,10 +23,8 @@ import com.google.android.exoplayer2.util.Util; */ public final class Descriptor { - /** - * The scheme URI. - */ - @NonNull public final String schemeIdUri; + /** The scheme URI. */ + public final String schemeIdUri; /** * The value, or null. */ @@ -42,7 +39,7 @@ public final class Descriptor { * @param value The value, or null. * @param id The identifier, or null. */ - public Descriptor(@NonNull String schemeIdUri, @Nullable String value, @Nullable String id) { + public Descriptor(String schemeIdUri, @Nullable String value, @Nullable String id) { this.schemeIdUri = schemeIdUri; this.value = value; this.id = id; @@ -63,10 +60,9 @@ public final class Descriptor { @Override public int hashCode() { - int result = (schemeIdUri != null ? schemeIdUri.hashCode() : 0); + int result = schemeIdUri.hashCode(); result = 31 * result + (value != null ? value.hashCode() : 0); result = 31 * result + (id != null ? id.hashCode() : 0); return result; } - } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/ProgramInformation.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/ProgramInformation.java index 62934d7433..ac264bd2b1 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/ProgramInformation.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/ProgramInformation.java @@ -21,22 +21,26 @@ import com.google.android.exoplayer2.util.Util; /** A parsed program information element. */ public class ProgramInformation { /** The title for the media presentation. */ - public final String title; + @Nullable public final String title; /** Information about the original source of the media presentation. */ - public final String source; + @Nullable public final String source; /** A copyright statement for the media presentation. */ - public final String copyright; + @Nullable public final String copyright; /** A URL that provides more information about the media presentation. */ - public final String moreInformationURL; + @Nullable public final String moreInformationURL; /** Declares the language code(s) for this ProgramInformation. */ - public final String lang; + @Nullable public final String lang; public ProgramInformation( - String title, String source, String copyright, String moreInformationURL, String lang) { + @Nullable String title, + @Nullable String source, + @Nullable String copyright, + @Nullable String moreInformationURL, + @Nullable String lang) { this.title = title; this.source = source; this.copyright = copyright; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/RangedUri.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/RangedUri.java index 9ac1257ee2..bcd783f0cb 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/RangedUri.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/RangedUri.java @@ -83,7 +83,7 @@ public final class RangedUri { *

If {@code other} is null then the merge is considered unsuccessful, and null is returned. * * @param other The {@link RangedUri} to merge. - * @param baseUri The optional base Uri. + * @param baseUri The base Uri. * @return The merged {@link RangedUri} if the merge was successful. Null otherwise. */ @Nullable diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java index 0884bcc65c..80ad15cd8f 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source.dash.manifest; import android.net.Uri; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.source.dash.DashSegmentIndex; @@ -53,9 +54,7 @@ public abstract class Representation { * The offset of the presentation timestamps in the media stream relative to media time. */ public final long presentationTimeOffsetUs; - /** - * The in-band event streams in the representation. Never null, but may be empty. - */ + /** The in-band event streams in the representation. May be empty. */ public final List inbandEventStreams; private final RangedUri initializationUri; @@ -71,7 +70,7 @@ public abstract class Representation { */ public static Representation newInstance( long revisionId, Format format, String baseUrl, SegmentBase segmentBase) { - return newInstance(revisionId, format, baseUrl, segmentBase, null); + return newInstance(revisionId, format, baseUrl, segmentBase, /* inbandEventStreams= */ null); } /** @@ -89,8 +88,9 @@ public abstract class Representation { Format format, String baseUrl, SegmentBase segmentBase, - List inbandEventStreams) { - return newInstance(revisionId, format, baseUrl, segmentBase, inbandEventStreams, null); + @Nullable List inbandEventStreams) { + return newInstance( + revisionId, format, baseUrl, segmentBase, inbandEventStreams, /* cacheKey= */ null); } /** @@ -110,8 +110,8 @@ public abstract class Representation { Format format, String baseUrl, SegmentBase segmentBase, - List inbandEventStreams, - String cacheKey) { + @Nullable List inbandEventStreams, + @Nullable String cacheKey) { if (segmentBase instanceof SingleSegmentBase) { return new SingleSegmentRepresentation( revisionId, @@ -135,7 +135,7 @@ public abstract class Representation { Format format, String baseUrl, SegmentBase segmentBase, - List inbandEventStreams) { + @Nullable List inbandEventStreams) { this.revisionId = revisionId; this.format = format; this.baseUrl = baseUrl; @@ -151,6 +151,7 @@ public abstract class Representation { * Returns a {@link RangedUri} defining the location of the representation's initialization data, * or null if no initialization data exists. */ + @Nullable public RangedUri getInitializationUri() { return initializationUri; } @@ -159,14 +160,15 @@ public abstract class Representation { * Returns a {@link RangedUri} defining the location of the representation's segment index, or * null if the representation provides an index directly. */ + @Nullable public abstract RangedUri getIndexUri(); - /** - * Returns an index if the representation provides one directly, or null otherwise. - */ + /** Returns an index if the representation provides one directly, or null otherwise. */ + @Nullable public abstract DashSegmentIndex getIndex(); /** Returns a cache key for the representation if set, or null. */ + @Nullable public abstract String getCacheKey(); /** @@ -184,9 +186,9 @@ public abstract class Representation { */ public final long contentLength; - private final String cacheKey; - private final RangedUri indexUri; - private final SingleSegmentIndex segmentIndex; + @Nullable private final String cacheKey; + @Nullable private final RangedUri indexUri; + @Nullable private final SingleSegmentIndex segmentIndex; /** * @param revisionId Identifies the revision of the content. @@ -209,7 +211,7 @@ public abstract class Representation { long indexStart, long indexEnd, List inbandEventStreams, - String cacheKey, + @Nullable String cacheKey, long contentLength) { RangedUri rangedUri = new RangedUri(null, initializationStart, initializationEnd - initializationStart + 1); @@ -233,8 +235,8 @@ public abstract class Representation { Format format, String baseUrl, SingleSegmentBase segmentBase, - List inbandEventStreams, - String cacheKey, + @Nullable List inbandEventStreams, + @Nullable String cacheKey, long contentLength) { super(revisionId, format, baseUrl, segmentBase, inbandEventStreams); this.uri = Uri.parse(baseUrl); @@ -248,16 +250,19 @@ public abstract class Representation { } @Override + @Nullable public RangedUri getIndexUri() { return indexUri; } @Override + @Nullable public DashSegmentIndex getIndex() { return segmentIndex; } @Override + @Nullable public String getCacheKey() { return cacheKey; } @@ -284,12 +289,13 @@ public abstract class Representation { Format format, String baseUrl, MultiSegmentBase segmentBase, - List inbandEventStreams) { + @Nullable List inbandEventStreams) { super(revisionId, format, baseUrl, segmentBase, inbandEventStreams); this.segmentBase = segmentBase; } @Override + @Nullable public RangedUri getIndexUri() { return null; } @@ -300,6 +306,7 @@ public abstract class Representation { } @Override + @Nullable public String getCacheKey() { return null; } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java index ba4faafd95..a31e0329af 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.source.dash.manifest; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.source.dash.DashSegmentIndex; import com.google.android.exoplayer2.util.Util; @@ -25,7 +26,7 @@ import java.util.List; */ public abstract class SegmentBase { - /* package */ final RangedUri initialization; + /* package */ @Nullable final RangedUri initialization; /* package */ final long timescale; /* package */ final long presentationTimeOffset; @@ -36,7 +37,8 @@ public abstract class SegmentBase { * @param presentationTimeOffset The presentation time offset. The value in seconds is the * division of this value and {@code timescale}. */ - public SegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset) { + public SegmentBase( + @Nullable RangedUri initialization, long timescale, long presentationTimeOffset) { this.initialization = initialization; this.timescale = timescale; this.presentationTimeOffset = presentationTimeOffset; @@ -49,6 +51,7 @@ public abstract class SegmentBase { * @param representation The {@link Representation} for which initialization data is required. * @return A {@link RangedUri} defining the location of the initialization data, or null. */ + @Nullable public RangedUri getInitialization(Representation representation) { return initialization; } @@ -77,19 +80,31 @@ public abstract class SegmentBase { * @param indexStart The byte offset of the index data in the segment. * @param indexLength The length of the index data in bytes. */ - public SingleSegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset, - long indexStart, long indexLength) { + public SingleSegmentBase( + @Nullable RangedUri initialization, + long timescale, + long presentationTimeOffset, + long indexStart, + long indexLength) { super(initialization, timescale, presentationTimeOffset); this.indexStart = indexStart; this.indexLength = indexLength; } public SingleSegmentBase() { - this(null, 1, 0, 0, 0); + this( + /* initialization= */ null, + /* timescale= */ 1, + /* presentationTimeOffset= */ 0, + /* indexStart= */ 0, + /* indexLength= */ 0); } + @Nullable public RangedUri getIndex() { - return indexLength <= 0 ? null : new RangedUri(null, indexStart, indexLength); + return indexLength <= 0 + ? null + : new RangedUri(/* referenceUri= */ null, indexStart, indexLength); } } @@ -101,7 +116,7 @@ public abstract class SegmentBase { /* package */ final long startNumber; /* package */ final long duration; - /* package */ final List segmentTimeline; + /* package */ @Nullable final List segmentTimeline; /** * @param initialization A {@link RangedUri} corresponding to initialization data, if such data @@ -118,12 +133,12 @@ public abstract class SegmentBase { * parameter. */ public MultiSegmentBase( - RangedUri initialization, + @Nullable RangedUri initialization, long timescale, long presentationTimeOffset, long startNumber, long duration, - List segmentTimeline) { + @Nullable List segmentTimeline) { super(initialization, timescale, presentationTimeOffset); this.startNumber = startNumber; this.duration = duration; @@ -223,7 +238,7 @@ public abstract class SegmentBase { */ public static class SegmentList extends MultiSegmentBase { - /* package */ final List mediaSegments; + /* package */ @Nullable final List mediaSegments; /** * @param initialization A {@link RangedUri} corresponding to initialization data, if such data @@ -246,8 +261,8 @@ public abstract class SegmentBase { long presentationTimeOffset, long startNumber, long duration, - List segmentTimeline, - List mediaSegments) { + @Nullable List segmentTimeline, + @Nullable List mediaSegments) { super(initialization, timescale, presentationTimeOffset, startNumber, duration, segmentTimeline); this.mediaSegments = mediaSegments; @@ -275,8 +290,8 @@ public abstract class SegmentBase { */ public static class SegmentTemplate extends MultiSegmentBase { - /* package */ final UrlTemplate initializationTemplate; - /* package */ final UrlTemplate mediaTemplate; + /* package */ @Nullable final UrlTemplate initializationTemplate; + /* package */ @Nullable final UrlTemplate mediaTemplate; /* package */ final long endNumber; /** @@ -308,9 +323,9 @@ public abstract class SegmentBase { long startNumber, long endNumber, long duration, - List segmentTimeline, - UrlTemplate initializationTemplate, - UrlTemplate mediaTemplate) { + @Nullable List segmentTimeline, + @Nullable UrlTemplate initializationTemplate, + @Nullable UrlTemplate mediaTemplate) { super( initialization, timescale, @@ -324,6 +339,7 @@ public abstract class SegmentBase { } @Override + @Nullable public RangedUri getInitialization(Representation representation) { if (initializationTemplate != null) { String urlString = initializationTemplate.buildUri(representation.format.id, 0, diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/package-info.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/package-info.java new file mode 100644 index 0000000000..b7c267727c --- /dev/null +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.dash.manifest; + +import com.google.android.exoplayer2.util.NonNullApi; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/package-info.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/package-info.java new file mode 100644 index 0000000000..4eb0d8436d --- /dev/null +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.dash.offline; + +import com.google.android.exoplayer2.util.NonNullApi; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/package-info.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/package-info.java new file mode 100644 index 0000000000..f51ea4369e --- /dev/null +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.dash; + +import com.google.android.exoplayer2.util.NonNullApi; From 58d4fd93dd07d9ad7af8b76eed111be5550bb0d1 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 7 Aug 2019 14:42:47 +0100 Subject: [PATCH 06/14] Fix HLS module API nullability issues and add package-level non-null-by-default PiperOrigin-RevId: 262124441 --- library/hls/build.gradle | 1 + .../source/hls/Aes128DataSource.java | 3 ++- .../hls/DefaultHlsExtractorFactory.java | 6 +++--- .../exoplayer2/source/hls/HlsChunkSource.java | 10 ++++------ .../source/hls/HlsExtractorFactory.java | 7 ++++--- .../exoplayer2/source/hls/HlsMediaPeriod.java | 9 +++++++-- .../exoplayer2/source/hls/HlsMediaSource.java | 2 +- .../source/hls/WebvttExtractor.java | 5 +++-- .../source/hls/offline/package-info.java | 19 +++++++++++++++++++ .../exoplayer2/source/hls/package-info.java | 19 +++++++++++++++++++ .../playlist/DefaultHlsPlaylistTracker.java | 4 +++- .../hls/playlist/HlsMasterPlaylist.java | 4 ++-- .../source/hls/playlist/HlsMediaPlaylist.java | 7 +++---- .../source/hls/playlist/package-info.java | 19 +++++++++++++++++++ 14 files changed, 90 insertions(+), 25 deletions(-) create mode 100644 library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/package-info.java create mode 100644 library/hls/src/main/java/com/google/android/exoplayer2/source/hls/package-info.java create mode 100644 library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/package-info.java diff --git a/library/hls/build.gradle b/library/hls/build.gradle index 82e09ab72c..8301820e79 100644 --- a/library/hls/build.gradle +++ b/library/hls/build.gradle @@ -41,6 +41,7 @@ android { dependencies { implementation 'androidx.annotation:annotation:1.1.0' compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion + compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion implementation project(modulePrefix + 'library-core') testImplementation project(modulePrefix + 'testutils-robolectric') } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java index 022d62cbfc..fe70298dc8 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java @@ -105,7 +105,8 @@ import javax.crypto.spec.SecretKeySpec; } @Override - public final @Nullable Uri getUri() { + @Nullable + public final Uri getUri() { return upstream.getUri(); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java index 9fde54a705..6dd4ade590 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java @@ -84,11 +84,11 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { @Override public Result createExtractor( - Extractor previousExtractor, + @Nullable Extractor previousExtractor, Uri uri, Format format, - List muxedCaptionFormats, - DrmInitData drmInitData, + @Nullable List muxedCaptionFormats, + @Nullable DrmInitData drmInitData, TimestampAdjuster timestampAdjuster, Map> responseHeaders, ExtractorInput extractorInput) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index ee5a5f0809..c452a29cf9 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -59,10 +59,8 @@ import java.util.Map; clear(); } - /** - * The chunk to be loaded next. - */ - public Chunk chunk; + /** The chunk to be loaded next. */ + @Nullable public Chunk chunk; /** * Indicates that the end of the stream has been reached. @@ -70,7 +68,7 @@ import java.util.Map; public boolean endOfStream; /** Indicates that the chunk source is waiting for the referred playlist to be refreshed. */ - public Uri playlistUrl; + @Nullable public Uri playlistUrl; /** * Clears the holder. @@ -138,7 +136,7 @@ import java.util.Map; HlsDataSourceFactory dataSourceFactory, @Nullable TransferListener mediaTransferListener, TimestampAdjusterProvider timestampAdjusterProvider, - List muxedCaptionFormats) { + @Nullable List muxedCaptionFormats) { this.extractorFactory = extractorFactory; this.playlistTracker = playlistTracker; this.playlistUrls = playlistUrls; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java index 103d89188f..927b79899d 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source.hls; import android.net.Uri; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.extractor.Extractor; @@ -82,11 +83,11 @@ public interface HlsExtractorFactory { * @throws IOException If an I/O error is encountered while sniffing. */ Result createExtractor( - Extractor previousExtractor, + @Nullable Extractor previousExtractor, Uri uri, Format format, - List muxedCaptionFormats, - DrmInitData drmInitData, + @Nullable List muxedCaptionFormats, + @Nullable DrmInitData drmInitData, TimestampAdjuster timestampAdjuster, Map> responseHeaders, ExtractorInput sniffingExtractorInput) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index e21827557a..8053958c2b 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -54,6 +54,7 @@ import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import org.checkerframework.checker.nullness.compatqual.NullableType; /** * A {@link MediaPeriod} that loads an HLS stream. @@ -249,8 +250,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper } @Override - public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, - SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { + public long selectTracks( + @NullableType TrackSelection[] selections, + boolean[] mayRetainStreamFlags, + @NullableType SampleStream[] streams, + boolean[] streamResetFlags, + long positionUs) { // Map each selection and stream onto a child period index. int[] streamChildIndices = new int[selections.length]; int[] selectionChildIndices = new int[selections.length]; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 877b6d486e..f2db9541eb 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -110,7 +110,7 @@ public final class HlsMediaSource extends BaseMediaSource * @return This factory, for convenience. * @throws IllegalStateException If one of the {@code create} methods has already been called. */ - public Factory setTag(Object tag) { + public Factory setTag(@Nullable Object tag) { Assertions.checkState(!isCreateCalled); this.tag = tag; return this; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java index 665f2e0570..a89e907a37 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.source.hls; +import androidx.annotation.Nullable; import android.text.TextUtils; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; @@ -49,7 +50,7 @@ public final class WebvttExtractor implements Extractor { private static final int HEADER_MIN_LENGTH = 6 /* "WEBVTT" */; private static final int HEADER_MAX_LENGTH = 3 /* optional Byte Order Mark */ + HEADER_MIN_LENGTH; - private final String language; + @Nullable private final String language; private final TimestampAdjuster timestampAdjuster; private final ParsableByteArray sampleDataWrapper; @@ -58,7 +59,7 @@ public final class WebvttExtractor implements Extractor { private byte[] sampleData; private int sampleSize; - public WebvttExtractor(String language, TimestampAdjuster timestampAdjuster) { + public WebvttExtractor(@Nullable String language, TimestampAdjuster timestampAdjuster) { this.language = language; this.timestampAdjuster = timestampAdjuster; this.sampleDataWrapper = new ParsableByteArray(); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/package-info.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/package-info.java new file mode 100644 index 0000000000..2527553824 --- /dev/null +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.hls.offline; + +import com.google.android.exoplayer2.util.NonNullApi; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/package-info.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/package-info.java new file mode 100644 index 0000000000..55f15f5e7a --- /dev/null +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.hls; + +import com.google.android.exoplayer2.util.NonNullApi; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java index a4fd28009f..e7a072839e 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java @@ -172,6 +172,7 @@ public final class DefaultHlsPlaylistTracker } @Override + @Nullable public HlsMediaPlaylist getPlaylistSnapshot(Uri url, boolean isForPlayback) { HlsMediaPlaylist snapshot = playlistBundles.get(url).getPlaylistSnapshot(); if (snapshot != null && isForPlayback) { @@ -448,7 +449,7 @@ public final class DefaultHlsPlaylistTracker private final Loader mediaPlaylistLoader; private final ParsingLoadable mediaPlaylistLoadable; - private HlsMediaPlaylist playlistSnapshot; + @Nullable private HlsMediaPlaylist playlistSnapshot; private long lastSnapshotLoadMs; private long lastSnapshotChangeMs; private long earliestNextLoadTimeMs; @@ -467,6 +468,7 @@ public final class DefaultHlsPlaylistTracker mediaPlaylistParser); } + @Nullable public HlsMediaPlaylist getPlaylistSnapshot() { return playlistSnapshot; } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java index 0e86df8c2f..1660324a34 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java @@ -174,7 +174,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { * The format of the audio muxed in the variants. May be null if the playlist does not declare any * muxed audio. */ - public final Format muxedAudioFormat; + @Nullable public final Format muxedAudioFormat; /** * The format of the closed captions declared by the playlist. May be empty if the playlist * explicitly declares no captions are available, or null if the playlist does not declare any @@ -208,7 +208,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist { List audios, List subtitles, List closedCaptions, - Format muxedAudioFormat, + @Nullable Format muxedAudioFormat, List muxedCaptionFormats, boolean hasIndependentSegments, Map variableDefinitions, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java index 4411c9865e..58f500cf94 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java @@ -16,7 +16,6 @@ package com.google.android.exoplayer2.source.hls.playlist; import androidx.annotation.IntDef; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.drm.DrmInitData; @@ -95,8 +94,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist { String uri, long byterangeOffset, long byterangeLength, - String fullSegmentEncryptionKeyUri, - String encryptionIV) { + @Nullable String fullSegmentEncryptionKeyUri, + @Nullable String encryptionIV) { this( uri, /* initializationSegment= */ null, @@ -154,7 +153,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { } @Override - public int compareTo(@NonNull Long relativeStartTimeUs) { + public int compareTo(Long relativeStartTimeUs) { return this.relativeStartTimeUs > relativeStartTimeUs ? 1 : (this.relativeStartTimeUs < relativeStartTimeUs ? -1 : 0); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/package-info.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/package-info.java new file mode 100644 index 0000000000..61f9d77e72 --- /dev/null +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.hls.playlist; + +import com.google.android.exoplayer2.util.NonNullApi; From 79d627d441bc2f49cc1f7832a959085907953c70 Mon Sep 17 00:00:00 2001 From: ibaker Date: Wed, 7 Aug 2019 15:56:25 +0100 Subject: [PATCH 07/14] Simplify EventMessageEncoder/Decoder serialization We're no longer tied to the emsg spec, so we can skip unused fields and assume ms for duration. Also remove @Nullable annotation from EventMessageEncoder#encode, it seems the current implementation never returns null PiperOrigin-RevId: 262135009 --- .../metadata/emsg/EventMessageDecoder.java | 15 +--- .../metadata/emsg/EventMessageEncoder.java | 4 -- .../emsg/EventMessageDecoderTest.java | 19 ++--- .../emsg/EventMessageEncoderTest.java | 69 ++++++++----------- 4 files changed, 40 insertions(+), 67 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java index 340b662e97..f592a6eee7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java @@ -15,22 +15,17 @@ */ package com.google.android.exoplayer2.metadata.emsg; -import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.MetadataDecoder; import com.google.android.exoplayer2.metadata.MetadataInputBuffer; import com.google.android.exoplayer2.util.Assertions; -import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.ParsableByteArray; -import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; import java.util.Arrays; /** Decodes data encoded by {@link EventMessageEncoder}. */ public final class EventMessageDecoder implements MetadataDecoder { - private static final String TAG = "EventMessageDecoder"; - @SuppressWarnings("ByteBufferBackingArray") @Override public Metadata decode(MetadataInputBuffer inputBuffer) { @@ -43,15 +38,7 @@ public final class EventMessageDecoder implements MetadataDecoder { public EventMessage decode(ParsableByteArray emsgData) { String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString()); String value = Assertions.checkNotNull(emsgData.readNullTerminatedString()); - long timescale = emsgData.readUnsignedInt(); - long presentationTimeDelta = emsgData.readUnsignedInt(); - if (presentationTimeDelta != 0) { - // We expect the source to have accounted for presentation_time_delta by adjusting the sample - // timestamp and zeroing the field in the sample data. Log a warning if the field is non-zero. - Log.w(TAG, "Ignoring non-zero presentation_time_delta: " + presentationTimeDelta); - } - long durationMs = - Util.scaleLargeTimestamp(emsgData.readUnsignedInt(), C.MILLIS_PER_SECOND, timescale); + long durationMs = emsgData.readUnsignedInt(); long id = emsgData.readUnsignedInt(); byte[] messageData = Arrays.copyOfRange(emsgData.data, emsgData.getPosition(), emsgData.limit()); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java index dd33d591a7..4fa3f71b32 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.metadata.emsg; -import androidx.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -40,15 +39,12 @@ public final class EventMessageEncoder { * @param eventMessage The event message to be encoded. * @return The serialized byte array. */ - @Nullable public byte[] encode(EventMessage eventMessage) { byteArrayOutputStream.reset(); try { writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri); String nonNullValue = eventMessage.value != null ? eventMessage.value : ""; writeNullTerminatedString(dataOutputStream, nonNullValue); - writeUnsignedInt(dataOutputStream, 1000); // timescale - writeUnsignedInt(dataOutputStream, 0); // presentation_time_delta writeUnsignedInt(dataOutputStream, eventMessage.durationMs); writeUnsignedInt(dataOutputStream, eventMessage.id); dataOutputStream.write(eventMessage.messageData); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoderTest.java index d870afac3a..88a61d0bce 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoderTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoderTest.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.metadata.emsg; +import static com.google.android.exoplayer2.testutil.TestUtil.createByteArray; +import static com.google.android.exoplayer2.testutil.TestUtil.joinByteArrays; import static com.google.common.truth.Truth.assertThat; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -30,18 +32,19 @@ public final class EventMessageDecoderTest { @Test public void testDecodeEventMessage() { - byte[] rawEmsgBody = new byte[] { - 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test" - 49, 50, 51, 0, // value = "123" - 0, 0, -69, -128, // timescale = 48000 - 0, 0, -69, -128, // presentation_time_delta = 48000 - 0, 2, 50, -128, // event_duration = 144000 - 0, 15, 67, -45, // id = 1000403 - 0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4} + byte[] rawEmsgBody = + joinByteArrays( + createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test" + createByteArray(49, 50, 51, 0), // value = "123" + createByteArray(0, 0, 11, 184), // event_duration_ms = 3000 + createByteArray(0, 15, 67, 211), // id = 1000403 + createByteArray(0, 1, 2, 3, 4)); // message_data = {0, 1, 2, 3, 4} EventMessageDecoder decoder = new EventMessageDecoder(); MetadataInputBuffer buffer = new MetadataInputBuffer(); buffer.data = ByteBuffer.allocate(rawEmsgBody.length).put(rawEmsgBody); + Metadata metadata = decoder.decode(buffer); + assertThat(metadata.length()).isEqualTo(1); EventMessage eventMessage = (EventMessage) metadata.get(0); assertThat(eventMessage.schemeIdUri).isEqualTo("urn:test"); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoderTest.java index ca8303d3e2..56830035cc 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoderTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoderTest.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.metadata.emsg; +import static com.google.android.exoplayer2.testutil.TestUtil.createByteArray; +import static com.google.android.exoplayer2.testutil.TestUtil.joinByteArrays; import static com.google.common.truth.Truth.assertThat; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -29,67 +31,52 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public final class EventMessageEncoderTest { + private static final EventMessage DECODED_MESSAGE = + new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4}); + + private static final byte[] ENCODED_MESSAGE = + joinByteArrays( + createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test" + createByteArray(49, 50, 51, 0), // value = "123" + createByteArray(0, 0, 11, 184), // event_duration_ms = 3000 + createByteArray(0, 15, 67, 211), // id = 1000403 + createByteArray(0, 1, 2, 3, 4)); // message_data = {0, 1, 2, 3, 4} + @Test public void testEncodeEventStream() throws IOException { - EventMessage eventMessage = - new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4}); - byte[] expectedEmsgBody = - new byte[] { - 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test" - 49, 50, 51, 0, // value = "123" - 0, 0, 3, -24, // timescale = 1000 - 0, 0, 0, 0, // presentation_time_delta = 0 - 0, 0, 11, -72, // event_duration = 3000 - 0, 15, 67, -45, // id = 1000403 - 0, 1, 2, 3, 4 - }; // message_data = {0, 1, 2, 3, 4} - byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage); - assertThat(encodedByteArray).isEqualTo(expectedEmsgBody); + byte[] foo = new byte[] {1, 2, 3}; + + byte[] encodedByteArray = new EventMessageEncoder().encode(DECODED_MESSAGE); + assertThat(encodedByteArray).isEqualTo(ENCODED_MESSAGE); } @Test public void testEncodeDecodeEventStream() throws IOException { - EventMessage expectedEmsg = - new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4}); - byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg); + byte[] encodedByteArray = new EventMessageEncoder().encode(DECODED_MESSAGE); MetadataInputBuffer buffer = new MetadataInputBuffer(); buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray); EventMessageDecoder decoder = new EventMessageDecoder(); Metadata metadata = decoder.decode(buffer); assertThat(metadata.length()).isEqualTo(1); - assertThat(metadata.get(0)).isEqualTo(expectedEmsg); + assertThat(metadata.get(0)).isEqualTo(DECODED_MESSAGE); } @Test public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException { - EventMessage eventMessage = - new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4}); - byte[] expectedEmsgBody = - new byte[] { - 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test" - 49, 50, 51, 0, // value = "123" - 0, 0, 3, -24, // timescale = 1000 - 0, 0, 0, 0, // presentation_time_delta = 0 - 0, 0, 11, -72, // event_duration = 3000 - 0, 15, 67, -45, // id = 1000403 - 0, 1, 2, 3, 4 - }; // message_data = {0, 1, 2, 3, 4} EventMessage eventMessage1 = new EventMessage("urn:test", "123", 3000, 1000402, new byte[] {4, 3, 2, 1, 0}); byte[] expectedEmsgBody1 = - new byte[] { - 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test" - 49, 50, 51, 0, // value = "123" - 0, 0, 3, -24, // timescale = 1000 - 0, 0, 0, 0, // presentation_time_delta = 0 - 0, 0, 11, -72, // event_duration = 3000 - 0, 15, 67, -46, // id = 1000402 - 4, 3, 2, 1, 0 - }; // message_data = {4, 3, 2, 1, 0} + joinByteArrays( + createByteArray(117, 114, 110, 58, 116, 101, 115, 116, 0), // scheme_id_uri = "urn:test" + createByteArray(49, 50, 51, 0), // value = "123" + createByteArray(0, 0, 11, 184), // event_duration_ms = 3000 + createByteArray(0, 15, 67, 210), // id = 1000402 + createByteArray(4, 3, 2, 1, 0)); // message_data = {4, 3, 2, 1, 0} + EventMessageEncoder eventMessageEncoder = new EventMessageEncoder(); - byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage); - assertThat(encodedByteArray).isEqualTo(expectedEmsgBody); + byte[] encodedByteArray = eventMessageEncoder.encode(DECODED_MESSAGE); + assertThat(encodedByteArray).isEqualTo(ENCODED_MESSAGE); byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1); assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1); } From 70b912c23e445ce89aa8932a88ad7d149fcd52d2 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 8 Aug 2019 09:22:26 +0100 Subject: [PATCH 08/14] Fix API nullability of remaining extensions and mark them as non-null-by-default PiperOrigin-RevId: 262303610 --- .../ext/vp9/LibvpxVideoRenderer.java | 16 +++++++-------- .../exoplayer2/ext/vp9/VpxDecoder.java | 20 ++++++++++++++----- .../ext/vp9/VpxVideoSurfaceView.java | 5 +++-- .../exoplayer2/ext/vp9/package-info.java | 19 ++++++++++++++++++ 4 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/package-info.java diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index b6663ac3d7..5e9d8d0897 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -174,8 +174,8 @@ public class LibvpxVideoRenderer extends BaseRenderer { */ public LibvpxVideoRenderer( long allowedJoiningTimeMs, - Handler eventHandler, - VideoRendererEventListener eventListener, + @Nullable Handler eventHandler, + @Nullable VideoRendererEventListener eventListener, int maxDroppedFramesToNotify) { this( allowedJoiningTimeMs, @@ -206,10 +206,10 @@ public class LibvpxVideoRenderer extends BaseRenderer { */ public LibvpxVideoRenderer( long allowedJoiningTimeMs, - Handler eventHandler, - VideoRendererEventListener eventListener, + @Nullable Handler eventHandler, + @Nullable VideoRendererEventListener eventListener, int maxDroppedFramesToNotify, - DrmSessionManager drmSessionManager, + @Nullable DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys, boolean disableLoopFilter) { this( @@ -249,10 +249,10 @@ public class LibvpxVideoRenderer extends BaseRenderer { */ public LibvpxVideoRenderer( long allowedJoiningTimeMs, - Handler eventHandler, - VideoRendererEventListener eventListener, + @Nullable Handler eventHandler, + @Nullable VideoRendererEventListener eventListener, int maxDroppedFramesToNotify, - DrmSessionManager drmSessionManager, + @Nullable DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys, boolean disableLoopFilter, boolean enableRowMultiThreadMode, diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java index 93a4a2fc1f..0efd4bd0ea 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java @@ -33,7 +33,7 @@ import java.nio.ByteBuffer; private static final int DECODE_ERROR = 1; private static final int DRM_ERROR = 2; - private final ExoMediaCrypto exoMediaCrypto; + @Nullable private final ExoMediaCrypto exoMediaCrypto; private final long vpxDecContext; @C.VideoOutputMode private volatile int outputMode; @@ -55,7 +55,7 @@ import java.nio.ByteBuffer; int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, - ExoMediaCrypto exoMediaCrypto, + @Nullable ExoMediaCrypto exoMediaCrypto, boolean disableLoopFilter, boolean enableRowMultiThreadMode, int threads) @@ -170,9 +170,19 @@ import java.nio.ByteBuffer; private native long vpxClose(long context); private native long vpxDecode(long context, ByteBuffer encoded, int length); - private native long vpxSecureDecode(long context, ByteBuffer encoded, int length, - ExoMediaCrypto mediaCrypto, int inputMode, byte[] key, byte[] iv, - int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData); + + private native long vpxSecureDecode( + long context, + ByteBuffer encoded, + int length, + @Nullable ExoMediaCrypto mediaCrypto, + int inputMode, + byte[] key, + byte[] iv, + int numSubSamples, + int[] numBytesOfClearData, + int[] numBytesOfEncryptedData); + private native int vpxGetFrame(long context, VpxOutputBuffer outputBuffer); /** diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxVideoSurfaceView.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxVideoSurfaceView.java index 8c765952e7..4e983cccc7 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxVideoSurfaceView.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxVideoSurfaceView.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.vp9; import android.content.Context; import android.opengl.GLSurfaceView; +import androidx.annotation.Nullable; import android.util.AttributeSet; /** @@ -27,10 +28,10 @@ public class VpxVideoSurfaceView extends GLSurfaceView implements VpxOutputBuffe private final VpxRenderer renderer; public VpxVideoSurfaceView(Context context) { - this(context, null); + this(context, /* attrs= */ null); } - public VpxVideoSurfaceView(Context context, AttributeSet attrs) { + public VpxVideoSurfaceView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); renderer = new VpxRenderer(); setPreserveEGLContextOnPause(true); diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/package-info.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/package-info.java new file mode 100644 index 0000000000..b8725607a5 --- /dev/null +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.ext.vp9; + +import com.google.android.exoplayer2.util.NonNullApi; From 313bd109517351e758f5c0a0085b9d780a459e6e Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 8 Aug 2019 09:44:58 +0100 Subject: [PATCH 09/14] Fix SS module API nullability issues and add package-level non-null-by-default PiperOrigin-RevId: 262306255 --- library/smoothstreaming/build.gradle | 1 + .../source/smoothstreaming/SsMediaPeriod.java | 9 +++- .../source/smoothstreaming/SsMediaSource.java | 30 ++++++------ .../smoothstreaming/manifest/SsManifest.java | 46 ++++++++++++++----- .../manifest/SsManifestParser.java | 21 +++++---- .../manifest/package-info.java | 19 ++++++++ .../smoothstreaming/offline/package-info.java | 19 ++++++++ .../source/smoothstreaming/package-info.java | 19 ++++++++ 8 files changed, 127 insertions(+), 37 deletions(-) create mode 100644 library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/package-info.java create mode 100644 library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/package-info.java create mode 100644 library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/package-info.java diff --git a/library/smoothstreaming/build.gradle b/library/smoothstreaming/build.gradle index fa67ea1d01..d85ecbb1a3 100644 --- a/library/smoothstreaming/build.gradle +++ b/library/smoothstreaming/build.gradle @@ -41,6 +41,7 @@ android { dependencies { implementation project(modulePrefix + 'library-core') compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion + compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion implementation 'androidx.annotation:annotation:1.1.0' testImplementation project(modulePrefix + 'testutils-robolectric') } diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java index d103358d37..b3d950959a 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java @@ -38,6 +38,7 @@ import com.google.android.exoplayer2.upstream.TransferListener; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import org.checkerframework.checker.nullness.compatqual.NullableType; /** A SmoothStreaming {@link MediaPeriod}. */ /* package */ final class SsMediaPeriod @@ -120,8 +121,12 @@ import java.util.List; } @Override - public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, - SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { + public long selectTracks( + @NullableType TrackSelection[] selections, + boolean[] mayRetainStreamFlags, + @NullableType SampleStream[] streams, + boolean[] streamResetFlags, + long positionUs) { ArrayList> sampleStreamsList = new ArrayList<>(); for (int i = 0; i < selections.length; i++) { if (streams[i] != null) { diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index 3c0593200e..9ddc7aa0f0 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -115,7 +115,7 @@ public final class SsMediaSource extends BaseMediaSource * @return This factory, for convenience. * @throws IllegalStateException If one of the {@code create} methods has already been called. */ - public Factory setTag(Object tag) { + public Factory setTag(@Nullable Object tag) { Assertions.checkState(!isCreateCalled); this.tag = tag; return this; @@ -370,8 +370,8 @@ public final class SsMediaSource extends BaseMediaSource public SsMediaSource( SsManifest manifest, SsChunkSource.Factory chunkSourceFactory, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( manifest, chunkSourceFactory, @@ -395,8 +395,8 @@ public final class SsMediaSource extends BaseMediaSource SsManifest manifest, SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( manifest, /* manifestUri= */ null, @@ -431,8 +431,8 @@ public final class SsMediaSource extends BaseMediaSource Uri manifestUri, DataSource.Factory manifestDataSourceFactory, SsChunkSource.Factory chunkSourceFactory, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( manifestUri, manifestDataSourceFactory, @@ -466,8 +466,8 @@ public final class SsMediaSource extends BaseMediaSource SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, long livePresentationDelayMs, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this(manifestUri, manifestDataSourceFactory, new SsManifestParser(), chunkSourceFactory, minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener); } @@ -496,8 +496,8 @@ public final class SsMediaSource extends BaseMediaSource SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, long livePresentationDelayMs, - Handler eventHandler, - MediaSourceEventListener eventListener) { + @Nullable Handler eventHandler, + @Nullable MediaSourceEventListener eventListener) { this( /* manifest= */ null, manifestUri, @@ -515,10 +515,10 @@ public final class SsMediaSource extends BaseMediaSource } private SsMediaSource( - SsManifest manifest, - Uri manifestUri, - DataSource.Factory manifestDataSourceFactory, - ParsingLoadable.Parser manifestParser, + @Nullable SsManifest manifest, + @Nullable Uri manifestUri, + @Nullable DataSource.Factory manifestDataSourceFactory, + @Nullable ParsingLoadable.Parser manifestParser, SsChunkSource.Factory chunkSourceFactory, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, DrmSessionManager drmSessionManager, diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.java index cfb772a86b..b91bfc8f67 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifest.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source.smoothstreaming.manifest; import android.net.Uri; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox; @@ -69,7 +70,7 @@ public class SsManifest implements FilterableManifest { public final int maxHeight; public final int displayWidth; public final int displayHeight; - public final String language; + @Nullable public final String language; public final Format[] formats; public final int chunkCount; @@ -80,9 +81,20 @@ public class SsManifest implements FilterableManifest { private final long[] chunkStartTimesUs; private final long lastChunkDurationUs; - public StreamElement(String baseUri, String chunkTemplate, int type, String subType, - long timescale, String name, int maxWidth, int maxHeight, int displayWidth, - int displayHeight, String language, Format[] formats, List chunkStartTimes, + public StreamElement( + String baseUri, + String chunkTemplate, + int type, + String subType, + long timescale, + String name, + int maxWidth, + int maxHeight, + int displayWidth, + int displayHeight, + @Nullable String language, + Format[] formats, + List chunkStartTimes, long lastChunkDuration) { this( baseUri, @@ -102,10 +114,22 @@ public class SsManifest implements FilterableManifest { Util.scaleLargeTimestamp(lastChunkDuration, C.MICROS_PER_SECOND, timescale)); } - private StreamElement(String baseUri, String chunkTemplate, int type, String subType, - long timescale, String name, int maxWidth, int maxHeight, int displayWidth, - int displayHeight, String language, Format[] formats, List chunkStartTimes, - long[] chunkStartTimesUs, long lastChunkDurationUs) { + private StreamElement( + String baseUri, + String chunkTemplate, + int type, + String subType, + long timescale, + String name, + int maxWidth, + int maxHeight, + int displayWidth, + int displayHeight, + @Nullable String language, + Format[] formats, + List chunkStartTimes, + long[] chunkStartTimesUs, + long lastChunkDurationUs) { this.baseUri = baseUri; this.chunkTemplate = chunkTemplate; this.type = type; @@ -208,7 +232,7 @@ public class SsManifest implements FilterableManifest { public final boolean isLive; /** Content protection information, or null if the content is not protected. */ - public final ProtectionElement protectionElement; + @Nullable public final ProtectionElement protectionElement; /** The contained stream elements. */ public final StreamElement[] streamElements; @@ -249,7 +273,7 @@ public class SsManifest implements FilterableManifest { long dvrWindowLength, int lookAheadCount, boolean isLive, - ProtectionElement protectionElement, + @Nullable ProtectionElement protectionElement, StreamElement[] streamElements) { this( majorVersion, @@ -273,7 +297,7 @@ public class SsManifest implements FilterableManifest { long dvrWindowLengthUs, int lookAheadCount, boolean isLive, - ProtectionElement protectionElement, + @Nullable ProtectionElement protectionElement, StreamElement[] streamElements) { this.majorVersion = majorVersion; this.minorVersion = minorVersion; diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java index 39e22f2982..03e9e91e22 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source.smoothstreaming.manifest; import android.net.Uri; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.util.Base64; import android.util.Pair; @@ -40,6 +41,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; +import org.checkerframework.checker.nullness.compatqual.NullableType; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; @@ -94,10 +96,10 @@ public class SsManifestParser implements ParsingLoadable.Parser { private final String baseUri; private final String tag; - private final ElementParser parent; - private final List> normalizedAttributes; + @Nullable private final ElementParser parent; + private final List> normalizedAttributes; - public ElementParser(ElementParser parent, String baseUri, String tag) { + public ElementParser(@Nullable ElementParser parent, String baseUri, String tag) { this.parent = parent; this.baseUri = baseUri; this.tag = tag; @@ -174,24 +176,25 @@ public class SsManifestParser implements ParsingLoadable.Parser { * Stash an attribute that may be normalized at this level. In other words, an attribute that * may have been pulled up from the child elements because its value was the same in all * children. - *

- * Stashing an attribute allows child element parsers to retrieve the values of normalized + * + *

Stashing an attribute allows child element parsers to retrieve the values of normalized * attributes using {@link #getNormalizedAttribute(String)}. * * @param key The name of the attribute. * @param value The value of the attribute. */ - protected final void putNormalizedAttribute(String key, Object value) { + protected final void putNormalizedAttribute(String key, @Nullable Object value) { normalizedAttributes.add(Pair.create(key, value)); } /** - * Attempt to retrieve a stashed normalized attribute. If there is no stashed attribute with - * the provided name, the parent element parser will be queried, and so on up the chain. + * Attempt to retrieve a stashed normalized attribute. If there is no stashed attribute with the + * provided name, the parent element parser will be queried, and so on up the chain. * * @param key The name of the attribute. * @return The stashed value, or null if the attribute was not be found. */ + @Nullable protected final Object getNormalizedAttribute(String key) { for (int i = 0; i < normalizedAttributes.size(); i++) { Pair pair = normalizedAttributes.get(i); @@ -340,7 +343,7 @@ public class SsManifestParser implements ParsingLoadable.Parser { private long dvrWindowLength; private int lookAheadCount; private boolean isLive; - private ProtectionElement protectionElement; + @Nullable private ProtectionElement protectionElement; public SmoothStreamingMediaParser(ElementParser parent, String baseUri) { super(parent, baseUri, TAG); diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/package-info.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/package-info.java new file mode 100644 index 0000000000..b594ddc2bc --- /dev/null +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.smoothstreaming.manifest; + +import com.google.android.exoplayer2.util.NonNullApi; diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/package-info.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/package-info.java new file mode 100644 index 0000000000..f7c74f1a1e --- /dev/null +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.smoothstreaming.offline; + +import com.google.android.exoplayer2.util.NonNullApi; diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/package-info.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/package-info.java new file mode 100644 index 0000000000..23e85850c6 --- /dev/null +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. + */ +@NonNullApi +package com.google.android.exoplayer2.source.smoothstreaming; + +import com.google.android.exoplayer2.util.NonNullApi; From bbe681a904d58fe1f84f6c7c6e3390d932c86249 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 8 Aug 2019 11:09:33 +0100 Subject: [PATCH 10/14] Make Kotlin JVM annotations available and use in ExoPlayer. NoExternal PiperOrigin-RevId: 262316962 --- constants.gradle | 1 + library/core/build.gradle | 3 +-- library/core/proguard-rules.txt | 3 ++- .../com/google/android/exoplayer2/util/NonNullApi.java | 8 +++----- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/constants.gradle b/constants.gradle index b1c2c636c7..9510b8442e 100644 --- a/constants.gradle +++ b/constants.gradle @@ -25,6 +25,7 @@ project.ext { autoServiceVersion = '1.0-rc4' checkerframeworkVersion = '2.5.0' jsr305Version = '3.0.2' + kotlinAnnotationsVersion = '1.3.31' androidXTestVersion = '1.1.0' truthVersion = '0.44' modulePrefix = ':' diff --git a/library/core/build.gradle b/library/core/build.gradle index 93126d9830..8e64383638 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -62,8 +62,7 @@ dependencies { compileOnly 'com.google.code.findbugs:jsr305:' + jsr305Version compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion - // Uncomment to enable Kotlin non-null strict mode. See [internal: b/138703808]. - // compileOnly "org.jetbrains.kotlin:kotlin-annotations-jvm:1.1.60" + compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion androidTestImplementation 'androidx.test:runner:' + androidXTestVersion androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion androidTestImplementation 'com.google.truth:truth:' + truthVersion diff --git a/library/core/proguard-rules.txt b/library/core/proguard-rules.txt index 1f7a8d0ee7..ab3cc5fccd 100644 --- a/library/core/proguard-rules.txt +++ b/library/core/proguard-rules.txt @@ -58,5 +58,6 @@ (com.google.android.exoplayer2.upstream.DataSource$Factory); } -# Don't warn about checkerframework +# Don't warn about checkerframework and Kotlin annotations -dontwarn org.checkerframework.** +-dontwarn kotlin.annotations.jvm.** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/NonNullApi.java b/library/core/src/main/java/com/google/android/exoplayer2/util/NonNullApi.java index bd7a70eba0..7678710f18 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/NonNullApi.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/NonNullApi.java @@ -20,8 +20,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import javax.annotation.Nonnull; import javax.annotation.meta.TypeQualifierDefault; -// import kotlin.annotations.jvm.MigrationStatus; -// import kotlin.annotations.jvm.UnderMigration; +import kotlin.annotations.jvm.MigrationStatus; +import kotlin.annotations.jvm.UnderMigration; /** * Annotation to declare all type usages in the annotated instance as {@link Nonnull}, unless @@ -29,8 +29,6 @@ import javax.annotation.meta.TypeQualifierDefault; */ @Nonnull @TypeQualifierDefault(ElementType.TYPE_USE) -// TODO(internal: b/138703808): Uncomment to ensure Kotlin issues compiler errors when non-null -// types are used incorrectly. -// @UnderMigration(status = MigrationStatus.STRICT) +@UnderMigration(status = MigrationStatus.STRICT) @Retention(RetentionPolicy.CLASS) public @interface NonNullApi {} From 9f55045eeb07120d5c001db48ef7c7c622089cbd Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 8 Aug 2019 12:08:51 +0100 Subject: [PATCH 11/14] Rollback of https://github.com/google/ExoPlayer/commit/bbe681a904d58fe1f84f6c7c6e3390d932c86249 *** Original commit *** Make Kotlin JVM annotations available and use in ExoPlayer. NoExternal *** PiperOrigin-RevId: 262323737 --- constants.gradle | 1 - library/core/build.gradle | 3 ++- library/core/proguard-rules.txt | 3 +-- .../com/google/android/exoplayer2/util/NonNullApi.java | 8 +++++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/constants.gradle b/constants.gradle index 9510b8442e..b1c2c636c7 100644 --- a/constants.gradle +++ b/constants.gradle @@ -25,7 +25,6 @@ project.ext { autoServiceVersion = '1.0-rc4' checkerframeworkVersion = '2.5.0' jsr305Version = '3.0.2' - kotlinAnnotationsVersion = '1.3.31' androidXTestVersion = '1.1.0' truthVersion = '0.44' modulePrefix = ':' diff --git a/library/core/build.gradle b/library/core/build.gradle index 8e64383638..93126d9830 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -62,7 +62,8 @@ dependencies { compileOnly 'com.google.code.findbugs:jsr305:' + jsr305Version compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion - compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion + // Uncomment to enable Kotlin non-null strict mode. See [internal: b/138703808]. + // compileOnly "org.jetbrains.kotlin:kotlin-annotations-jvm:1.1.60" androidTestImplementation 'androidx.test:runner:' + androidXTestVersion androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion androidTestImplementation 'com.google.truth:truth:' + truthVersion diff --git a/library/core/proguard-rules.txt b/library/core/proguard-rules.txt index ab3cc5fccd..1f7a8d0ee7 100644 --- a/library/core/proguard-rules.txt +++ b/library/core/proguard-rules.txt @@ -58,6 +58,5 @@ (com.google.android.exoplayer2.upstream.DataSource$Factory); } -# Don't warn about checkerframework and Kotlin annotations +# Don't warn about checkerframework -dontwarn org.checkerframework.** --dontwarn kotlin.annotations.jvm.** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/NonNullApi.java b/library/core/src/main/java/com/google/android/exoplayer2/util/NonNullApi.java index 7678710f18..bd7a70eba0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/NonNullApi.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/NonNullApi.java @@ -20,8 +20,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import javax.annotation.Nonnull; import javax.annotation.meta.TypeQualifierDefault; -import kotlin.annotations.jvm.MigrationStatus; -import kotlin.annotations.jvm.UnderMigration; +// import kotlin.annotations.jvm.MigrationStatus; +// import kotlin.annotations.jvm.UnderMigration; /** * Annotation to declare all type usages in the annotated instance as {@link Nonnull}, unless @@ -29,6 +29,8 @@ import kotlin.annotations.jvm.UnderMigration; */ @Nonnull @TypeQualifierDefault(ElementType.TYPE_USE) -@UnderMigration(status = MigrationStatus.STRICT) +// TODO(internal: b/138703808): Uncomment to ensure Kotlin issues compiler errors when non-null +// types are used incorrectly. +// @UnderMigration(status = MigrationStatus.STRICT) @Retention(RetentionPolicy.CLASS) public @interface NonNullApi {} From a14df33dc76d628b1f7c1d90fd58128a2dae442d Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 8 Aug 2019 16:56:57 +0100 Subject: [PATCH 12/14] Only read from FormatHolder when a format has been read I think we need to start clearing the holder as part of the DRM rework. When we do this, it'll only be valid to read from the holder immediately after it's been populated. PiperOrigin-RevId: 262362725 --- .../android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java | 2 +- .../google/android/exoplayer2/metadata/MetadataRenderer.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index 5e9d8d0897..b000ea1b6b 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -847,7 +847,7 @@ public class LibvpxVideoRenderer extends BaseRenderer { pendingFormat = null; } inputBuffer.flip(); - inputBuffer.colorInfo = formatHolder.format.colorInfo; + inputBuffer.colorInfo = format.colorInfo; onQueueInputBuffer(inputBuffer); decoder.queueInputBuffer(inputBuffer); buffersInCodecCount++; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java index a775481633..0fc0a85104 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java @@ -52,6 +52,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { private int pendingMetadataCount; private MetadataDecoder decoder; private boolean inputStreamEnded; + private long subsampleOffsetUs; /** * @param output The output. @@ -120,7 +121,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { // If we ever need to support a metadata format where this is not the case, we'll need to // pass the buffer to the decoder and discard the output. } else { - buffer.subsampleOffsetUs = formatHolder.format.subsampleOffsetUs; + buffer.subsampleOffsetUs = subsampleOffsetUs; buffer.flip(); int index = (pendingMetadataIndex + pendingMetadataCount) % MAX_PENDING_METADATA_COUNT; Metadata metadata = decoder.decode(buffer); @@ -130,6 +131,8 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { pendingMetadataCount++; } } + } else if (result == C.RESULT_FORMAT_READ) { + subsampleOffsetUs = formatHolder.format.subsampleOffsetUs; } } From 389eca6e077549fbe740e5975fe93daf573aaa2d Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 8 Aug 2019 16:59:19 +0100 Subject: [PATCH 13/14] Merge robolectric_testutils into testutils. We no longer need two modules as AndroidX-Test takes care of the system abstraction and we no longer have Robolectric Handler/Looper workarounds. PiperOrigin-RevId: 262363201 --- core_settings.gradle | 2 - extensions/cast/build.gradle | 3 +- extensions/cronet/build.gradle | 3 +- extensions/ffmpeg/build.gradle | 3 +- extensions/flac/build.gradle | 3 +- extensions/ima/build.gradle | 3 +- extensions/opus/build.gradle | 3 +- extensions/rtmp/build.gradle | 3 +- extensions/vp9/build.gradle | 3 +- library/core/build.gradle | 1 - library/dash/build.gradle | 3 +- library/hls/build.gradle | 3 +- library/smoothstreaming/build.gradle | 3 +- library/ui/build.gradle | 3 +- testutils/build.gradle | 4 +- .../exoplayer2/testutil/CacheAsserts.java | 0 .../DefaultRenderersFactoryAsserts.java | 0 .../exoplayer2/testutil/FakeMediaChunk.java | 0 .../testutil/FakeMediaChunkIterator.java | 0 .../testutil/FakeMediaClockRenderer.java | 0 .../exoplayer2/testutil/FakeShuffleOrder.java | 0 .../testutil/FakeTrackSelection.java | 0 .../testutil/FakeTrackSelector.java | 0 .../testutil/MediaPeriodAsserts.java | 0 .../testutil/MediaSourceTestRunner.java | 0 .../exoplayer2/testutil/OggTestData.java | 0 .../exoplayer2/testutil/StubExoPlayer.java | 0 .../testutil/TestDownloadManagerListener.java | 0 .../exoplayer2/testutil/TimelineAsserts.java | 0 testutils_robolectric/build.gradle | 46 ------------------- .../src/main/AndroidManifest.xml | 17 ------- 31 files changed, 27 insertions(+), 79 deletions(-) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/DefaultRenderersFactoryAsserts.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunk.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/FakeShuffleOrder.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelection.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/MediaPeriodAsserts.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/OggTestData.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/TestDownloadManagerListener.java (100%) rename {testutils_robolectric => testutils}/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java (100%) delete mode 100644 testutils_robolectric/build.gradle delete mode 100644 testutils_robolectric/src/main/AndroidManifest.xml diff --git a/core_settings.gradle b/core_settings.gradle index 38889e1a21..3f6d58f777 100644 --- a/core_settings.gradle +++ b/core_settings.gradle @@ -24,7 +24,6 @@ include modulePrefix + 'library-hls' include modulePrefix + 'library-smoothstreaming' include modulePrefix + 'library-ui' include modulePrefix + 'testutils' -include modulePrefix + 'testutils-robolectric' include modulePrefix + 'extension-ffmpeg' include modulePrefix + 'extension-flac' include modulePrefix + 'extension-gvr' @@ -47,7 +46,6 @@ project(modulePrefix + 'library-hls').projectDir = new File(rootDir, 'library/hl project(modulePrefix + 'library-smoothstreaming').projectDir = new File(rootDir, 'library/smoothstreaming') project(modulePrefix + 'library-ui').projectDir = new File(rootDir, 'library/ui') project(modulePrefix + 'testutils').projectDir = new File(rootDir, 'testutils') -project(modulePrefix + 'testutils-robolectric').projectDir = new File(rootDir, 'testutils_robolectric') project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'extensions/ffmpeg') project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac') project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr') diff --git a/extensions/cast/build.gradle b/extensions/cast/build.gradle index 68a7494a3f..4af8f94c58 100644 --- a/extensions/cast/build.gradle +++ b/extensions/cast/build.gradle @@ -37,7 +37,8 @@ dependencies { implementation project(modulePrefix + 'library-ui') compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/extensions/cronet/build.gradle b/extensions/cronet/build.gradle index f7cc707fb4..9c49ba94e1 100644 --- a/extensions/cronet/build.gradle +++ b/extensions/cronet/build.gradle @@ -36,7 +36,8 @@ dependencies { implementation 'androidx.annotation:annotation:1.1.0' compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion testImplementation project(modulePrefix + 'library') - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/extensions/ffmpeg/build.gradle b/extensions/ffmpeg/build.gradle index 15952b1860..2b5a6010a9 100644 --- a/extensions/ffmpeg/build.gradle +++ b/extensions/ffmpeg/build.gradle @@ -40,7 +40,8 @@ dependencies { implementation project(modulePrefix + 'library-core') implementation 'androidx.annotation:annotation:1.1.0' compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/extensions/flac/build.gradle b/extensions/flac/build.gradle index c67de27697..dfac2e1c26 100644 --- a/extensions/flac/build.gradle +++ b/extensions/flac/build.gradle @@ -43,7 +43,8 @@ dependencies { compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion androidTestImplementation project(modulePrefix + 'testutils') androidTestImplementation 'androidx.test:runner:' + androidXTestVersion - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle index 0ef9f281c9..41d6aaf628 100644 --- a/extensions/ima/build.gradle +++ b/extensions/ima/build.gradle @@ -36,7 +36,8 @@ dependencies { implementation project(modulePrefix + 'library-core') implementation 'androidx.annotation:annotation:1.1.0' implementation 'com.google.android.gms:play-services-ads-identifier:16.0.0' - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/extensions/opus/build.gradle b/extensions/opus/build.gradle index 28f7b05465..7b621a8df9 100644 --- a/extensions/opus/build.gradle +++ b/extensions/opus/build.gradle @@ -40,7 +40,8 @@ android { dependencies { implementation project(modulePrefix + 'library-core') implementation 'androidx.annotation:annotation:1.1.0' - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion androidTestImplementation 'androidx.test:runner:' + androidXTestVersion androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion } diff --git a/extensions/rtmp/build.gradle b/extensions/rtmp/build.gradle index b74be659ee..74ef70fbf0 100644 --- a/extensions/rtmp/build.gradle +++ b/extensions/rtmp/build.gradle @@ -34,7 +34,8 @@ dependencies { implementation project(modulePrefix + 'library-core') implementation 'net.butterflytv.utils:rtmp-client:3.0.1' implementation 'androidx.annotation:annotation:1.1.0' - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/extensions/vp9/build.gradle b/extensions/vp9/build.gradle index 51b2677368..3b8271869b 100644 --- a/extensions/vp9/build.gradle +++ b/extensions/vp9/build.gradle @@ -40,7 +40,8 @@ android { dependencies { implementation project(modulePrefix + 'library-core') implementation 'androidx.annotation:annotation:1.1.0' - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion androidTestImplementation 'androidx.test:runner:' + androidXTestVersion androidTestImplementation 'androidx.test.ext:junit:' + androidXTestVersion androidTestImplementation 'com.google.truth:truth:' + truthVersion diff --git a/library/core/build.gradle b/library/core/build.gradle index 93126d9830..fda2f079de 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -42,7 +42,6 @@ android { } test { java.srcDirs += '../../testutils/src/main/java/' - java.srcDirs += '../../testutils_robolectric/src/main/java/' } } diff --git a/library/dash/build.gradle b/library/dash/build.gradle index c34ed8c907..c64da2b86d 100644 --- a/library/dash/build.gradle +++ b/library/dash/build.gradle @@ -43,7 +43,8 @@ dependencies { compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion implementation 'androidx.annotation:annotation:1.1.0' - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/library/hls/build.gradle b/library/hls/build.gradle index 8301820e79..0f685c1130 100644 --- a/library/hls/build.gradle +++ b/library/hls/build.gradle @@ -43,7 +43,8 @@ dependencies { compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion implementation project(modulePrefix + 'library-core') - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/library/smoothstreaming/build.gradle b/library/smoothstreaming/build.gradle index d85ecbb1a3..b16157f49b 100644 --- a/library/smoothstreaming/build.gradle +++ b/library/smoothstreaming/build.gradle @@ -43,7 +43,8 @@ dependencies { compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkVersion implementation 'androidx.annotation:annotation:1.1.0' - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/library/ui/build.gradle b/library/ui/build.gradle index 5182dfccf5..5b3123e302 100644 --- a/library/ui/build.gradle +++ b/library/ui/build.gradle @@ -43,7 +43,8 @@ dependencies { implementation 'androidx.media:media:1.0.1' implementation 'androidx.annotation:annotation:1.1.0' compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } ext { diff --git a/testutils/build.gradle b/testutils/build.gradle index afd2a146af..b5e68187be 100644 --- a/testutils/build.gradle +++ b/testutils/build.gradle @@ -39,11 +39,13 @@ android { dependencies { api 'org.mockito:mockito-core:' + mockitoVersion + api 'androidx.test:core:' + androidXTestVersion api 'androidx.test.ext:junit:' + androidXTestVersion api 'com.google.truth:truth:' + truthVersion implementation 'androidx.annotation:annotation:1.1.0' implementation project(modulePrefix + 'library-core') implementation 'com.google.auto.value:auto-value-annotations:' + autoValueVersion annotationProcessor 'com.google.auto.value:auto-value:' + autoValueVersion - testImplementation project(modulePrefix + 'testutils-robolectric') + testImplementation project(modulePrefix + 'testutils') + testImplementation 'org.robolectric:robolectric:' + robolectricVersion } diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/DefaultRenderersFactoryAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/DefaultRenderersFactoryAsserts.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/DefaultRenderersFactoryAsserts.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/DefaultRenderersFactoryAsserts.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunk.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunk.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunk.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunk.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeShuffleOrder.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeShuffleOrder.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeShuffleOrder.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeShuffleOrder.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelection.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelection.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelection.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelection.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/MediaPeriodAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/MediaPeriodAsserts.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/MediaPeriodAsserts.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/MediaPeriodAsserts.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/OggTestData.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/OggTestData.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/OggTestData.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/OggTestData.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/TestDownloadManagerListener.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestDownloadManagerListener.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/TestDownloadManagerListener.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/TestDownloadManagerListener.java diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java similarity index 100% rename from testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java diff --git a/testutils_robolectric/build.gradle b/testutils_robolectric/build.gradle deleted file mode 100644 index a098178429..0000000000 --- a/testutils_robolectric/build.gradle +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2018 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. -apply from: '../constants.gradle' -apply plugin: 'com.android.library' - -android { - compileSdkVersion project.ext.compileSdkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - minSdkVersion project.ext.minSdkVersion - targetSdkVersion project.ext.targetSdkVersion - } - - lintOptions { - // Robolectric depends on BouncyCastle, which depends on javax.naming, - // which is not part of Android. - disable 'InvalidPackage' - } - - testOptions.unitTests.includeAndroidResources = true -} - -dependencies { - api 'androidx.test:core:' + androidXTestVersion - api 'org.robolectric:robolectric:' + robolectricVersion - api project(modulePrefix + 'testutils') - implementation project(modulePrefix + 'library-core') - implementation 'androidx.annotation:annotation:1.1.0' - annotationProcessor 'com.google.auto.service:auto-service:' + autoServiceVersion -} diff --git a/testutils_robolectric/src/main/AndroidManifest.xml b/testutils_robolectric/src/main/AndroidManifest.xml deleted file mode 100644 index 057caad867..0000000000 --- a/testutils_robolectric/src/main/AndroidManifest.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - From 8967dd9c4c48980e433027b8dfb295b1cf99d7cd Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 9 Aug 2019 08:33:42 +0100 Subject: [PATCH 14/14] Upgrade IMA dependency version PiperOrigin-RevId: 262511088 --- extensions/ima/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle index 41d6aaf628..340e9832be 100644 --- a/extensions/ima/build.gradle +++ b/extensions/ima/build.gradle @@ -32,7 +32,7 @@ android { } dependencies { - api 'com.google.ads.interactivemedia.v3:interactivemedia:3.11.2' + api 'com.google.ads.interactivemedia.v3:interactivemedia:3.11.3' implementation project(modulePrefix + 'library-core') implementation 'androidx.annotation:annotation:1.1.0' implementation 'com.google.android.gms:play-services-ads-identifier:16.0.0'