Skip to content

Commit

Permalink
Merge pull request #8816 from google/dev-v2-r2.13.3
Browse files Browse the repository at this point in the history
r2.13.3
  • Loading branch information
marcbaechinger authored Apr 14, 2021
2 parents 4364b91 + b34e0b2 commit 0ba317b
Show file tree
Hide file tree
Showing 102 changed files with 3,581 additions and 620 deletions.
42 changes: 17 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,26 @@ and extend, and can be updated through Play Store application updates.

## Using ExoPlayer ##

ExoPlayer modules can be obtained from JCenter. It's also possible to clone the
repository and depend on the modules locally.
ExoPlayer modules can be obtained from [the Google Maven repository][]. It's
also possible to clone the repository and depend on the modules locally.

### From JCenter ###
### From the Google Maven repository

#### 1. Add repositories ####
#### 1. Add ExoPlayer module dependencies ####

The easiest way to get started using ExoPlayer is to add it as a gradle
dependency. You need to make sure you have the Google and JCenter repositories
included in the `build.gradle` file in the root of your project:

```gradle
repositories {
google()
jcenter()
}
```

#### 2. Add ExoPlayer module dependencies ####

Next add a dependency in the `build.gradle` file of your app module. The
following will add a dependency to the full library:
dependency in the `build.gradle` file of your app module. The following will add
a dependency to the full library:

```gradle
implementation 'com.google.android.exoplayer:exoplayer:2.X.X'
```

where `2.X.X` is your preferred version.

Note: old versions of ExoPlayer are available via JCenter. To use them, you need
to add `jcenter()` to your project's root build.gradle `repositories` block.

As an alternative to the full library, you can depend on only the library
modules that you actually need. For example the following will add dependencies
on the Core, DASH and UI library modules, as might be required for an app that
Expand All @@ -72,18 +63,19 @@ individually.
* `exoplayer-smoothstreaming`: Support for SmoothStreaming content.
* `exoplayer-ui`: UI components and resources for use with ExoPlayer.

In addition to library modules, ExoPlayer has multiple extension modules that
depend on external libraries to provide additional functionality. Some
extensions are available from JCenter, whereas others must be built manually.
In addition to library modules, ExoPlayer has extension modules that depend on
external libraries to provide additional functionality. Some extensions are
available from the Maven repository, whereas others must be built manually.
Browse the [extensions directory][] and their individual READMEs for details.

More information on the library and extension modules that are available from
JCenter can be found on [Bintray][].
More information on the library and extension modules that are available can be
found on the [Google Maven ExoPlayer page][].

[extensions directory]: https://github.com/google/ExoPlayer/tree/release-v2/extensions/
[Bintray]: https://bintray.com/google/exoplayer
[the Google Maven repository]: https://developer.android.com/studio/build/dependencies#google-maven
[Google Maven ExoPlayer page]: https://maven.google.com/web/index.html#com.google.android.exoplayer

#### 3. Turn on Java 8 support ####
#### 2. Turn on Java 8 support ####

If not enabled already, you also need to turn on Java 8 support in all
`build.gradle` files depending on ExoPlayer, by adding the following to the
Expand Down
74 changes: 74 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,79 @@
# Release notes

### 2.13.3 (2021-04-14)

* Published via the Google Maven repository (i.e., google()) rather than JCenter.
* Core:
* Reset playback speed when live playback speed control becomes unused
([#8664](https://github.com/google/ExoPlayer/issues/8664)).
* Fix playback position issue when re-preparing playback after a
BehindLiveWindowException
([#8675](https://github.com/google/ExoPlayer/issues/8675)).
* Assume Dolby Vision content is encoded as H264 when calculating maximum
codec input size
([#8705](https://github.com/google/ExoPlayer/issues/8705)).
* UI:
* Fix `StyledPlayerView` scrubber not reappearing correctly in some cases
([#8646](https://github.com/google/ExoPlayer/issues/8646)).
* Fix measurement of `StyledPlayerView` and `StyledPlayerControlView` when
`wrap_content` is used
([#8726](https://github.com/google/ExoPlayer/issues/8726)).
* Fix `StyledPlayerControlView` to stay in full mode (rather than minimal
mode) when possible
([#8763](https://github.com/google/ExoPlayer/issues/8763)).
* DASH:
* Parse `forced_subtitle` role from DASH manifests
([#8781](https://github.com/google/ExoPlayer/issues/8781)).
* HLS:
* Fix bug of ignoring `EXT-X-START` when setting the live target offset
([#8764](https://github.com/google/ExoPlayer/pull/8764)).
* Fix incorrect application of byte ranges to `EXT-X-MAP` tags
([#8783](https://github.com/google/ExoPlayer/issues/8783)).
* Fix issue that could cause playback to become stuck if corresponding
`EXT-X-DISCONTINUITY` tags in different media playlists occur at
different positions in time
([#8372](https://github.com/google/ExoPlayer/issues/8372)).
* Fix issue that could cause playback of on-demand content to not start in
cases where the media playlists referenced by the master playlist have
different starting `EXT-X-PROGRAM-DATE-TIME` tags.
* Fix container type detection for segments with incorrect file extension
or HTTP Content-Type
([#8733](https://github.com/google/ExoPlayer/issues/8733)).
* Extractors:
* Add support for `GContainer` and `GContainerItem` XMP namespace prefixes
in JPEG motion photo parsing.
* Allow JFIF APP0 marker segment preceding Exif APP1 segment in
`JpegExtractor`.
* Text:
* Parse SSA/ASS bold & italic info in `Style:` lines
([#8435](https://github.com/google/ExoPlayer/issues/8435)).
* Don't display subtitles after the end position of the current media
period (if known). This ensures sideloaded subtitles respect the end
point of `ClippingMediaPeriod` and prevents content subtitles from
continuing to be displayed over mid-roll ads
([#5317](https://github.com/google/ExoPlayer/issues/5317),
[#8456](https://github.com/google/ExoPlayer/issues/8456)).
* Fix CEA-708 priority handling to sort cues in the order defined by the
spec ([#8704](https://github.com/google/ExoPlayer/issues/8704)).
* Support TTML `textEmphasis` attributes, used for Japanese boutens.
* Support TTML `shear` attributes.
* Metadata:
* Ensure that timed metadata near the end of a period is not dropped
([#8710](https://github.com/google/ExoPlayer/issues/8710)).
* Cast extension:
* Fix `onPositionDiscontinuity` event so that it is not triggered with
reason `DISCONTINUITY_REASON_PERIOD_TRANSITION` after a seek to another
media item and so that it is not triggered after a timeline change.
* IMA extension:
* Fix error caused by `AdPlaybackState` ad group times being cleared,
which can occur if the `ImaAdsLoader` is released while an ad is pending
loading ([#8693](https://github.com/google/ExoPlayer/issues/8693)).
* Upgrade IMA SDK dependency to 3.23.0, fixing an issue with
`NullPointerExceptions` within `WebView` callbacks
([#8447](https://github.com/google/ExoPlayer/issues/8447)).
* FFmpeg extension: Fix playback failure when switching to TrueHD tracks
during playback ([#8616](https://github.com/google/ExoPlayer/issues/8616)).

### 2.13.2 (2021-02-25)

* Extractors:
Expand Down
4 changes: 0 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath 'com.novoda:bintray-release:0.9.1'
classpath 'com.google.android.gms:strict-version-matcher-plugin:1.2.1'
}
}
Expand All @@ -27,9 +26,6 @@ allprojects {
google()
jcenter()
}
project.ext {
exoplayerPublishEnabled = false
}
if (it.hasProperty('externalBuildDir')) {
if (!new File(externalBuildDir).isAbsolute()) {
externalBuildDir = new File(rootDir, externalBuildDir)
Expand Down
4 changes: 2 additions & 2 deletions constants.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
// limitations under the License.
project.ext {
// ExoPlayer version and version code.
releaseVersion = '2.13.2'
releaseVersionCode = 2013002
releaseVersion = '2.13.3'
releaseVersionCode = 2013003
minSdkVersion = 16
appTargetSdkVersion = 29
targetSdkVersion = 28 // TODO: Bump once b/143232359 is resolved. Also fix TODOs in UtilTest.
Expand Down
1 change: 1 addition & 0 deletions demos/cast/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ android {
"proguard-rules.txt",
getDefaultProguardFile('proguard-android.txt')
]
signingConfig signingConfigs.debug
}
debug {
jniDebuggable = true
Expand Down
1 change: 1 addition & 0 deletions demos/gl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ android {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt')
signingConfig signingConfigs.debug
}
}

Expand Down
1 change: 1 addition & 0 deletions demos/main/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ android {
"proguard-rules.txt",
getDefaultProguardFile('proguard-android.txt')
]
signingConfig signingConfigs.debug
}
debug {
jniDebuggable = true
Expand Down
7 changes: 7 additions & 0 deletions demos/main/src/main/assets/media.exolist.json
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,13 @@
"subtitle_mime_type": "application/ttml+xml",
"subtitle_language": "ja"
},
{
"name": "TTML Netflix Japanese examples (IMSC1.1)",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/video-avc-baseline-480.mp4",
"subtitle_uri": "https://storage.googleapis.com/exoplayer-test-media-1/ttml/netflix_japanese_ttml.xml",
"subtitle_mime_type": "application/ttml+xml",
"subtitle_language": "ja"
},
{
"name": "WebVTT positioning",
"uri": "https://html5demos.com/assets/dizzy.mp4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
Expand All @@ -42,12 +43,12 @@ public class IntentUtil {
"com.google.android.exoplayer.demo.action.VIEW_LIST";

// Activity extras.

public static final String PREFER_EXTENSION_DECODERS_EXTRA = "prefer_extension_decoders";

// Media item configuration extras.

public static final String URI_EXTRA = "uri";
public static final String TITLE_EXTRA = "title";
public static final String MIME_TYPE_EXTRA = "mime_type";
public static final String CLIP_START_POSITION_MS_EXTRA = "clip_start_position_ms";
public static final String CLIP_END_POSITION_MS_EXTRA = "clip_end_position_ms";
Expand Down Expand Up @@ -89,6 +90,9 @@ public static void addToIntent(List<MediaItem> mediaItems, Intent intent) {
MediaItem mediaItem = mediaItems.get(0);
MediaItem.PlaybackProperties playbackProperties = checkNotNull(mediaItem.playbackProperties);
intent.setAction(ACTION_VIEW).setData(mediaItem.playbackProperties.uri);
if (mediaItem.mediaMetadata.title != null) {
intent.putExtra(TITLE_EXTRA, mediaItem.mediaMetadata.title);
}
addPlaybackPropertiesToIntent(playbackProperties, intent, /* extrasKeySuffix= */ "");
addClippingPropertiesToIntent(
mediaItem.clippingProperties, intent, /* extrasKeySuffix= */ "");
Expand All @@ -102,17 +106,22 @@ public static void addToIntent(List<MediaItem> mediaItems, Intent intent) {
addPlaybackPropertiesToIntent(playbackProperties, intent, /* extrasKeySuffix= */ "_" + i);
addClippingPropertiesToIntent(
mediaItem.clippingProperties, intent, /* extrasKeySuffix= */ "_" + i);
if (mediaItem.mediaMetadata.title != null) {
intent.putExtra(TITLE_EXTRA + ("_" + i), mediaItem.mediaMetadata.title);
}
}
}
}

private static MediaItem createMediaItemFromIntent(
Uri uri, Intent intent, String extrasKeySuffix) {
@Nullable String mimeType = intent.getStringExtra(MIME_TYPE_EXTRA + extrasKeySuffix);
@Nullable String title = intent.getStringExtra(TITLE_EXTRA + extrasKeySuffix);
MediaItem.Builder builder =
new MediaItem.Builder()
.setUri(uri)
.setMimeType(mimeType)
.setMediaMetadata(new MediaMetadata.Builder().setTitle(title).build())
.setAdTagUri(intent.getStringExtra(AD_TAG_URI_EXTRA + extrasKeySuffix))
.setSubtitles(createSubtitlesFromIntent(intent, extrasKeySuffix))
.setClipStartPositionMs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,8 @@ public void onPlaybackStateChanged(@Player.State int playbackState) {
@Override
public void onPlayerError(@NonNull ExoPlaybackException e) {
if (isBehindLiveWindow(e)) {
clearStartPosition();
initializePlayer();
player.seekToDefaultPosition();
player.prepare();
} else {
updateButtonVisibility();
showControls();
Expand Down
1 change: 1 addition & 0 deletions demos/surface/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ android {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt')
signingConfig signingConfigs.debug
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -653,15 +653,7 @@ private void updateInternalStateAndNotifyIfChanged() {
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null);
updateTimelineAndNotifyIfChanged();

int currentWindowIndex = C.INDEX_UNSET;
MediaQueueItem currentItem = remoteMediaClient.getCurrentItem();
if (currentItem != null) {
currentWindowIndex = currentTimeline.getIndexOfPeriod(currentItem.getItemId());
}
if (currentWindowIndex == C.INDEX_UNSET) {
// The timeline is empty. Fall back to index 0, which is what ExoPlayer would do.
currentWindowIndex = 0;
}
int currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
if (this.currentWindowIndex != currentWindowIndex && pendingSeekCount == 0) {
this.currentWindowIndex = currentWindowIndex;
listeners.queueEvent(
Expand Down Expand Up @@ -721,7 +713,9 @@ private void updateTimelineAndNotifyIfChanged() {
}

/**
* Updates the current timeline and returns whether it has changed.
* Updates the current timeline. The current window index may change as a result.
*
* @return Whether the current timeline has changed.
*/
private boolean updateTimeline() {
CastTimeline oldTimeline = currentTimeline;
Expand All @@ -730,7 +724,11 @@ private boolean updateTimeline() {
status != null
? timelineTracker.getCastTimeline(remoteMediaClient)
: CastTimeline.EMPTY_CAST_TIMELINE;
return !oldTimeline.equals(currentTimeline);
boolean timelineChanged = !oldTimeline.equals(currentTimeline);
if (timelineChanged) {
currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
}
return timelineChanged;
}

/** Updates the internal tracks and selection and returns whether they have changed. */
Expand Down Expand Up @@ -940,6 +938,24 @@ private static int fetchRepeatMode(RemoteMediaClient remoteMediaClient) {
}
}

private static int fetchCurrentWindowIndex(
@Nullable RemoteMediaClient remoteMediaClient, Timeline timeline) {
if (remoteMediaClient == null) {
return 0;
}

int currentWindowIndex = C.INDEX_UNSET;
@Nullable MediaQueueItem currentItem = remoteMediaClient.getCurrentItem();
if (currentItem != null) {
currentWindowIndex = timeline.getIndexOfPeriod(currentItem.getItemId());
}
if (currentWindowIndex == C.INDEX_UNSET) {
// The timeline is empty. Fall back to index 0, which is what ExoPlayer would do.
currentWindowIndex = 0;
}
return currentWindowIndex;
}

private static boolean isTrackActive(long id, long[] activeTrackIds) {
for (long activeTrackId : activeTrackIds) {
if (activeTrackId == id) {
Expand Down Expand Up @@ -1078,6 +1094,7 @@ public void onResult(MediaChannelResult result) {
+ CastUtils.getLogString(statusCode));
}
if (--pendingSeekCount == 0) {
currentWindowIndex = pendingSeekWindowIndex;
pendingSeekWindowIndex = C.INDEX_UNSET;
pendingSeekPositionMs = C.TIME_UNSET;
listeners.sendEvent(/* eventFlag= */ C.INDEX_UNSET, EventListener::onSeekProcessed);
Expand Down
4 changes: 2 additions & 2 deletions extensions/ffmpeg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ more external libraries as described below. These are licensed separately.

To use this extension you need to clone the ExoPlayer repository and depend on
its modules locally. Instructions for doing this can be found in ExoPlayer's
[top level README][]. The extension is not provided via JCenter (see [#2781][]
for more information).
[top level README][]. The extension is not provided via Google's Maven
repository (see [#2781][] for more information).

In addition, it's necessary to manually build the FFmpeg library, so that gradle
can bundle the FFmpeg binaries in the APK:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,18 @@ protected FfmpegDecoderException createUnexpectedDecodeException(Throwable error
int inputSize = inputData.limit();
ByteBuffer outputData = outputBuffer.init(inputBuffer.timeUs, outputBufferSize);
int result = ffmpegDecode(nativeContext, inputData, inputSize, outputData, outputBufferSize);
if (result == AUDIO_DECODER_ERROR_INVALID_DATA) {
if (result == AUDIO_DECODER_ERROR_OTHER) {
return new FfmpegDecoderException("Error decoding (see logcat).");
} else if (result == AUDIO_DECODER_ERROR_INVALID_DATA) {
// Treat invalid data errors as non-fatal to match the behavior of MediaCodec. No output will
// be produced for this buffer, so mark it as decode-only to ensure that the audio sink's
// position is reset when more audio is produced.
outputBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
return null;
} else if (result == AUDIO_DECODER_ERROR_OTHER) {
return new FfmpegDecoderException("Error decoding (see logcat).");
} else if (result == 0) {
// There's no need to output empty buffers.
outputBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
return null;
}
if (!hasOutputFormat) {
channelCount = ffmpegGetChannelCount(nativeContext);
Expand Down
Loading

0 comments on commit 0ba317b

Please sign in to comment.