Merge branch 'dev-v2' into release-v2

This commit is contained in:
Oliver Woodman 2017-04-26 16:23:48 +01:00
commit d979469659
784 changed files with 9047 additions and 2419 deletions

View File

@ -30,17 +30,39 @@ repositories {
} }
``` ```
Next, include the following in your module's `build.gradle` file: Next add a gradle compile dependency to the `build.gradle` file of your app
module. The following will add a dependency to the full ExoPlayer library:
```gradle ```gradle
compile 'com.google.android.exoplayer:exoplayer:rX.X.X' compile 'com.google.android.exoplayer:exoplayer:r2.X.X'
``` ```
where `rX.X.X` is the your preferred version. For the latest version, see the where `r2.X.X` is your preferred version. Alternatively, you can depend on only
project's [Releases][]. For more details, see the project on [Bintray][]. 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 plays DASH content:
[Releases]: https://github.com/google/ExoPlayer/releases ```gradle
[Bintray]: https://bintray.com/google/exoplayer/exoplayer/view compile 'com.google.android.exoplayer:exoplayer-core:r2.X.X'
compile 'com.google.android.exoplayer:exoplayer-dash:r2.X.X'
compile 'com.google.android.exoplayer:exoplayer-ui:r2.X.X'
```
The available modules are listed below. Adding a dependency to the full
ExoPlayer library is equivalent to adding dependencies on all of the modules
individually.
* `exoplayer-core`: Core functionality (required).
* `exoplayer-dash`: Support for DASH content.
* `exoplayer-hls`: Support for HLS content.
* `exoplayer-smoothstreaming`: Support for SmoothStreaming content.
* `exoplayer-ui`: UI components and resources for use with ExoPlayer.
For more details, see the project on [Bintray][]. For information about the
latest versions, see the [Release notes][].
[Bintray]: https://bintray.com/google/exoplayer
[Release notes]: https://github.com/google/ExoPlayer/blob/release-v2/RELEASENOTES.md
## Developing ExoPlayer ## ## Developing ExoPlayer ##

View File

@ -1,5 +1,38 @@
# Release notes # # Release notes #
### r2.4.0 ###
* New modular library structure. You can read more about depending on individual
library modules
[here](https://medium.com/google-exoplayer/exoplayers-new-modular-structure-a916c0874907).
* Variable speed playback support on API level 16+. You can read more about
changing the playback speed
[here](https://medium.com/google-exoplayer/variable-speed-playback-with-exoplayer-e6e6a71e0343)
([#26](https://github.com/google/ExoPlayer/issues/26)).
* New time bar view, including support for displaying ad break markers.
* Support DVB subtitles in MPEG-TS and MKV.
* Support adaptive playback for audio only DASH, HLS and SmoothStreaming
([#1975](https://github.com/google/ExoPlayer/issues/1975)).
* Support for setting extractor flags on DefaultExtractorsFactory
([#2657](https://github.com/google/ExoPlayer/issues/2657)).
* Support injecting custom renderers into SimpleExoPlayer using a new
RenderersFactory interface.
* Correctly set ExoPlayer's internal thread priority to `THREAD_PRIORITY_AUDIO`.
* TX3G: Support styling and positioning.
* FLV:
* Support MP3 in FLV.
* Skip unhandled metadata rather than failing
([#2634](https://github.com/google/ExoPlayer/issues/2634)).
* Fix potential OutOfMemory errors.
* ID3: Better handle malformed ID3 data
([#2604](https://github.com/google/ExoPlayer/issues/2604),
[#2663](https://github.com/google/ExoPlayer/issues/2663)).
* FFmpeg extension: Fixed build instructions
([#2561](https://github.com/google/ExoPlayer/issues/2561)).
* VP9 extension: Reduced binary size.
* FLAC extension: Enabled 64 bit targets.
* Misc bugfixes.
### r2.3.1 ### ### r2.3.1 ###
* Fix NPE enabling WebVTT subtitles in DASH streams * Fix NPE enabling WebVTT subtitles in DASH streams
@ -26,9 +59,8 @@
* HLS improvements: * HLS improvements:
* Respect initial track selection * Respect initial track selection
([#2353](https://github.com/google/ExoPlayer/issues/2353)). ([#2353](https://github.com/google/ExoPlayer/issues/2353)).
* Reduced frequency of media playlist requests when playback position is * Reduced frequency of media playlist requests when playback position is close
close to the live edge to the live edge ([#2548](https://github.com/google/ExoPlayer/issues/2548)).
([#2548](https://github.com/google/ExoPlayer/issues/2548)).
* Exposed the master playlist through ExoPlayer.getCurrentManifest() * Exposed the master playlist through ExoPlayer.getCurrentManifest()
([#2537](https://github.com/google/ExoPlayer/issues/2537)). ([#2537](https://github.com/google/ExoPlayer/issues/2537)).
* Support CLOSED-CAPTIONS #EXT-X-MEDIA type * Support CLOSED-CAPTIONS #EXT-X-MEDIA type
@ -237,25 +269,25 @@ some of the motivations behind ExoPlayer 2.x
structure and class names have also been sanitized. Read more structure and class names have also been sanitized. Read more
[here](https://medium.com/google-exoplayer/exoplayer-2-x-new-package-and-class-names-ef8e1d9ba96f#.lv8sd4nez). [here](https://medium.com/google-exoplayer/exoplayer-2-x-new-package-and-class-names-ef8e1d9ba96f#.lv8sd4nez).
* Key architectural changes: * Key architectural changes:
* Late binding between rendering and media source components. Allows the * Late binding between rendering and media source components. Allows the same
same rendering components to be re-used from one playback to another. rendering components to be re-used from one playback to another. Enables
Enables features such as gapless playback through playlists and DASH features such as gapless playback through playlists and DASH multi-period
multi-period support. support.
* Improved track selection design. More details can be found * Improved track selection design. More details can be found
[here](https://medium.com/google-exoplayer/exoplayer-2-x-track-selection-2b62ff712cc9#.n00zo76b6). [here](https://medium.com/google-exoplayer/exoplayer-2-x-track-selection-2b62ff712cc9#.n00zo76b6).
* LoadControl now used to control buffering and loading across all playback * LoadControl now used to control buffering and loading across all playback
types. types.
* Media source components given additional structure. A new MediaSource * Media source components given additional structure. A new MediaSource class
class has been introduced. MediaSources expose Timelines that describe the has been introduced. MediaSources expose Timelines that describe the media
media they expose, and can consist of multiple MediaPeriods. This enables they expose, and can consist of multiple MediaPeriods. This enables features
features such as seeking in live playbacks and DASH multi-period support. such as seeking in live playbacks and DASH multi-period support.
* Responsibility for loading the initial DASH/SmoothStreaming/HLS manifest * Responsibility for loading the initial DASH/SmoothStreaming/HLS manifest is
is promoted to the corresponding MediaSource components and is no longer promoted to the corresponding MediaSource components and is no longer the
the application's responsibility. application's responsibility.
* Higher level abstractions such as SimpleExoPlayer have been added to the * Higher level abstractions such as SimpleExoPlayer have been added to the
library. These make the library easier to use for common use cases. The library. These make the library easier to use for common use cases. The demo
demo app is halved in size as a result, whilst at the same time gaining app is halved in size as a result, whilst at the same time gaining more
more functionality. Read more functionality. Read more
[here](https://medium.com/google-exoplayer/exoplayer-2-x-improved-demo-app-d97171aaaaa1). [here](https://medium.com/google-exoplayer/exoplayer-2-x-improved-demo-app-d97171aaaaa1).
* Enhanced library support for implementing audio extensions. Read more * Enhanced library support for implementing audio extensions. Read more
[here](https://medium.com/google-exoplayer/exoplayer-2-x-new-audio-features-cfb26c2883a#.ua75vu4s3). [here](https://medium.com/google-exoplayer/exoplayer-2-x-new-audio-features-cfb26c2883a#.ua75vu4s3).
@ -274,20 +306,19 @@ some of the motivations behind ExoPlayer 2.x
[here](https://medium.com/google-exoplayer/exoplayer-2-x-mediasource-composition-6c285fcbca1f#.zfha8qupz). [here](https://medium.com/google-exoplayer/exoplayer-2-x-mediasource-composition-6c285fcbca1f#.zfha8qupz).
* Looping support (see above) * Looping support (see above)
([#490](https://github.com/google/ExoPlayer/issues/490)). ([#490](https://github.com/google/ExoPlayer/issues/490)).
* Ability to query information about all tracks in a piece of media * Ability to query information about all tracks in a piece of media (including
(including those not supported by the device) those not supported by the device)
([#1121](https://github.com/google/ExoPlayer/issues/1121)). ([#1121](https://github.com/google/ExoPlayer/issues/1121)).
* Improved player controls. * Improved player controls.
* Support for PSSH in fMP4 moof atoms * Support for PSSH in fMP4 moof atoms
([#1143](https://github.com/google/ExoPlayer/issues/1143)). ([#1143](https://github.com/google/ExoPlayer/issues/1143)).
* Support for Opus in Ogg * Support for Opus in Ogg
([#1447](https://github.com/google/ExoPlayer/issues/1447)). ([#1447](https://github.com/google/ExoPlayer/issues/1447)).
* CacheDataSource support for standalone media file playbacks (mp3, mp4 * CacheDataSource support for standalone media file playbacks (mp3, mp4 etc).
etc).
* FFMPEG extension (for audio only). * FFMPEG extension (for audio only).
* Key bug fixes: * Key bug fixes:
* Removed unnecessary secondary requests when playing standalone media * Removed unnecessary secondary requests when playing standalone media files
files ([#1041](https://github.com/google/ExoPlayer/issues/1041)). ([#1041](https://github.com/google/ExoPlayer/issues/1041)).
* Fixed playback of video only (i.e. no audio) live streams * Fixed playback of video only (i.e. no audio) live streams
([#758](https://github.com/google/ExoPlayer/issues/758)). ([#758](https://github.com/google/ExoPlayer/issues/758)).
* Fixed silent failure when media buffer is too small * Fixed silent failure when media buffer is too small
@ -304,6 +335,12 @@ in all V2 releases. This cannot be assumed for changes in r1.5.12 and later,
however it can be assumed that all such changes are included in the most recent however it can be assumed that all such changes are included in the most recent
V2 release. V2 release.
### r1.5.16 ###
* VP9 extension: Reduced binary size.
* FLAC extension: Enabled 64 bit targets and fixed proguard config.
* Misc bugfixes.
### r1.5.15 ### ### r1.5.15 ###
* SmoothStreaming: Fixed handling of start_time placeholder * SmoothStreaming: Fixed handling of start_time placeholder

View File

@ -19,8 +19,15 @@ buildscript {
classpath 'com.android.tools.build:gradle:2.3.0' classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.novoda:bintray-release:0.4.0' classpath 'com.novoda:bintray-release:0.4.0'
} }
// Workaround for the following test coverage issue. Remove when fixed:
// https://code.google.com/p/android/issues/detail?id=226070
configurations.all {
resolutionStrategy {
force 'org.jacoco:org.jacoco.report:0.7.4.201502262128'
force 'org.jacoco:org.jacoco.core:0.7.4.201502262128'
}
}
} }
allprojects { allprojects {
repositories { repositories {
jcenter() jcenter()
@ -30,16 +37,26 @@ allprojects {
// components provided by the library may be of use on older devices. // components provided by the library may be of use on older devices.
// However, please note that the core media playback functionality // However, please note that the core media playback functionality
// provided by the library requires API level 16 or greater. // provided by the library requires API level 16 or greater.
minSdkVersion=9 minSdkVersion = 9
compileSdkVersion=25 compileSdkVersion = 25
targetSdkVersion=25 targetSdkVersion = 25
buildToolsVersion='25' buildToolsVersion = '25'
testSupportLibraryVersion = '0.5'
supportLibraryVersion = '25.3.1'
dexmakerVersion = '1.2'
mockitoVersion = '1.9.5'
releaseRepoName = getBintrayRepo() releaseRepoName = getBintrayRepo()
releaseUserOrg = 'google' releaseUserOrg = 'google'
releaseGroupId = 'com.google.android.exoplayer' releaseGroupId = 'com.google.android.exoplayer'
releaseVersion = 'r2.3.1' releaseVersion = 'r2.4.0'
releaseWebsite = 'https://github.com/google/ExoPlayer' releaseWebsite = 'https://github.com/google/ExoPlayer'
} }
if (it.hasProperty('externalBuildDir')) {
if (!new File(externalBuildDir).isAbsolute()) {
externalBuildDir = new File(rootDir, externalBuildDir)
}
buildDir = "${externalBuildDir}/${project.name}"
}
} }
def getBintrayRepo() { def getBintrayRepo() {
@ -47,3 +64,5 @@ def getBintrayRepo() {
property('publicRepo').toBoolean() property('publicRepo').toBoolean()
return publicRepo ? 'exoplayer' : 'exoplayer-test' return publicRepo ? 'exoplayer' : 'exoplayer-test'
} }
apply from: 'javadoc_combined.gradle'

View File

@ -45,7 +45,11 @@ android {
} }
dependencies { dependencies {
compile project(':library') compile project(':library-core')
compile project(':library-dash')
compile project(':library-hls')
compile project(':library-smoothstreaming')
compile project(':library-ui')
withExtensionsCompile project(path: ':extension-ffmpeg') withExtensionsCompile project(path: ':extension-ffmpeg')
withExtensionsCompile project(path: ':extension-flac') withExtensionsCompile project(path: ':extension-flac')
withExtensionsCompile project(path: ':extension-opus') withExtensionsCompile project(path: ':extension-opus')

View File

@ -16,8 +16,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.exoplayer2.demo" package="com.google.android.exoplayer2.demo"
android:versionCode="2301" android:versionCode="2400"
android:versionName="2.3.1"> android:versionName="2.4.0">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

View File

@ -416,13 +416,16 @@
] ]
}, },
{ {
"name": "Audio -> Video", "name": "Audio -> Video -> Audio",
"playlist": [ "playlist": [
{ {
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/audio-141.mp4" "uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/audio-141.mp4"
}, },
{ {
"uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv" "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv"
},
{
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/audio-141.mp4"
} }
] ]
}, },

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.demo;
import android.text.TextUtils;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.util.MimeTypes;
import java.util.Locale;
/**
* Utility methods for demo application.
*/
/*package*/ final class DemoUtil {
/**
* Builds a track name for display.
*
* @param format {@link Format} of the track.
* @return a generated name specific to the track.
*/
public static String buildTrackName(Format format) {
String trackName;
if (MimeTypes.isVideo(format.sampleMimeType)) {
trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(
buildResolutionString(format), buildBitrateString(format)), buildTrackIdString(format)),
buildSampleMimeTypeString(format));
} else if (MimeTypes.isAudio(format.sampleMimeType)) {
trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(joinWithSeparator(
buildLanguageString(format), buildAudioPropertyString(format)),
buildBitrateString(format)), buildTrackIdString(format)),
buildSampleMimeTypeString(format));
} else {
trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(buildLanguageString(format),
buildBitrateString(format)), buildTrackIdString(format)),
buildSampleMimeTypeString(format));
}
return trackName.length() == 0 ? "unknown" : trackName;
}
private static String buildResolutionString(Format format) {
return format.width == Format.NO_VALUE || format.height == Format.NO_VALUE
? "" : format.width + "x" + format.height;
}
private static String buildAudioPropertyString(Format format) {
return format.channelCount == Format.NO_VALUE || format.sampleRate == Format.NO_VALUE
? "" : format.channelCount + "ch, " + format.sampleRate + "Hz";
}
private static String buildLanguageString(Format format) {
return TextUtils.isEmpty(format.language) || "und".equals(format.language) ? ""
: format.language;
}
private static String buildBitrateString(Format format) {
return format.bitrate == Format.NO_VALUE ? ""
: String.format(Locale.US, "%.2fMbit", format.bitrate / 1000000f);
}
private static String joinWithSeparator(String first, String second) {
return first.length() == 0 ? second : (second.length() == 0 ? first : first + ", " + second);
}
private static String buildTrackIdString(Format format) {
return format.id == null ? "" : ("id:" + format.id);
}
private static String buildSampleMimeTypeString(Format format) {
return format.sampleMimeType == null ? "" : format.sampleMimeType;
}
private DemoUtil() {}
}

View File

@ -22,6 +22,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
@ -99,6 +100,12 @@ import java.util.Locale;
Log.d(TAG, "positionDiscontinuity"); Log.d(TAG, "positionDiscontinuity");
} }
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
Log.d(TAG, "playbackParameters " + String.format(
"[speed=%.2f, pitch=%.2f]", playbackParameters.speed, playbackParameters.pitch));
}
@Override @Override
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
int periodCount = timeline.getPeriodCount(); int periodCount = timeline.getPeriodCount();
@ -274,7 +281,7 @@ import java.util.Locale;
@Override @Override
public void onRenderedFirstFrame(Surface surface) { public void onRenderedFirstFrame(Surface surface) {
// Do nothing. Log.d(TAG, "renderedFirstFrame [" + surface + "]");
} }
// DefaultDrmSessionManager.EventListener // DefaultDrmSessionManager.EventListener

View File

@ -21,6 +21,7 @@ import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
@ -30,10 +31,11 @@ import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
@ -111,6 +113,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
private TrackSelectionHelper trackSelectionHelper; private TrackSelectionHelper trackSelectionHelper;
private DebugTextViewHelper debugViewHelper; private DebugTextViewHelper debugViewHelper;
private boolean needRetrySource; private boolean needRetrySource;
private TrackGroupArray lastSeenTrackGroupArray;
private boolean shouldAutoPlay; private boolean shouldAutoPlay;
private int resumeWindow; private int resumeWindow;
@ -183,8 +186,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
} }
@Override @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
int[] grantResults) { @NonNull int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initializePlayer(); initializePlayer();
} else { } else {
@ -250,17 +253,21 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
} }
} }
@SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode = @DefaultRenderersFactory.ExtensionRendererMode int extensionRendererMode =
((DemoApplication) getApplication()).useExtensionRenderers() ((DemoApplication) getApplication()).useExtensionRenderers()
? (preferExtensionDecoders ? SimpleExoPlayer.EXTENSION_RENDERER_MODE_PREFER ? (preferExtensionDecoders ? DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER
: SimpleExoPlayer.EXTENSION_RENDERER_MODE_ON) : DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)
: SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF; : DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF;
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this,
drmSessionManager, extensionRendererMode);
TrackSelection.Factory videoTrackSelectionFactory = TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
trackSelectionHelper = new TrackSelectionHelper(trackSelector, videoTrackSelectionFactory); trackSelectionHelper = new TrackSelectionHelper(trackSelector, videoTrackSelectionFactory);
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, new DefaultLoadControl(), lastSeenTrackGroupArray = null;
drmSessionManager, extensionRendererMode);
player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector);
player.addListener(this); player.addListener(this);
eventLogger = new EventLogger(trackSelector); eventLogger = new EventLogger(trackSelector);
@ -427,6 +434,11 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
} }
} }
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
// Do nothing.
}
@Override @Override
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
// Do nothing. // Do nothing.
@ -472,8 +484,10 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
} }
@Override @Override
@SuppressWarnings("ReferenceEquality")
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
updateButtonVisibilities(); updateButtonVisibilities();
if (trackGroups != lastSeenTrackGroupArray) {
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo(); MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
if (mappedTrackInfo != null) { if (mappedTrackInfo != null) {
if (mappedTrackInfo.getTrackTypeRendererSupport(C.TRACK_TYPE_VIDEO) if (mappedTrackInfo.getTrackTypeRendererSupport(C.TRACK_TYPE_VIDEO)
@ -485,6 +499,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
showToast(R.string.error_unsupported_audio); showToast(R.string.error_unsupported_audio);
} }
} }
lastSeenTrackGroupArray = trackGroups;
}
} }
// User controls // User controls

View File

@ -21,13 +21,11 @@ import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckedTextView; import android.widget.CheckedTextView;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
@ -37,9 +35,7 @@ import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedT
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.SelectionOverride; import com.google.android.exoplayer2.trackselection.MappingTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.RandomTrackSelection; import com.google.android.exoplayer2.trackselection.RandomTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.util.MimeTypes;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale;
/** /**
* Helper class for displaying track selection dialogs. * Helper class for displaying track selection dialogs.
@ -157,7 +153,7 @@ import java.util.Locale;
CheckedTextView trackView = (CheckedTextView) inflater.inflate( CheckedTextView trackView = (CheckedTextView) inflater.inflate(
trackViewLayoutId, root, false); trackViewLayoutId, root, false);
trackView.setBackgroundResource(selectableItemBackgroundResourceId); trackView.setBackgroundResource(selectableItemBackgroundResourceId);
trackView.setText(buildTrackName(group.getFormat(trackIndex))); trackView.setText(DemoUtil.buildTrackName(group.getFormat(trackIndex)));
if (trackInfo.getTrackFormatSupport(rendererIndex, groupIndex, trackIndex) if (trackInfo.getTrackFormatSupport(rendererIndex, groupIndex, trackIndex)
== RendererCapabilities.FORMAT_HANDLED) { == RendererCapabilities.FORMAT_HANDLED) {
trackView.setFocusable(true); trackView.setFocusable(true);
@ -296,57 +292,4 @@ import java.util.Locale;
return tracks; return tracks;
} }
// Track name construction.
private static String buildTrackName(Format format) {
String trackName;
if (MimeTypes.isVideo(format.sampleMimeType)) {
trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(
buildResolutionString(format), buildBitrateString(format)), buildTrackIdString(format)),
buildSampleMimeTypeString(format));
} else if (MimeTypes.isAudio(format.sampleMimeType)) {
trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(joinWithSeparator(
buildLanguageString(format), buildAudioPropertyString(format)),
buildBitrateString(format)), buildTrackIdString(format)),
buildSampleMimeTypeString(format));
} else {
trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(buildLanguageString(format),
buildBitrateString(format)), buildTrackIdString(format)),
buildSampleMimeTypeString(format));
}
return trackName.length() == 0 ? "unknown" : trackName;
}
private static String buildResolutionString(Format format) {
return format.width == Format.NO_VALUE || format.height == Format.NO_VALUE
? "" : format.width + "x" + format.height;
}
private static String buildAudioPropertyString(Format format) {
return format.channelCount == Format.NO_VALUE || format.sampleRate == Format.NO_VALUE
? "" : format.channelCount + "ch, " + format.sampleRate + "Hz";
}
private static String buildLanguageString(Format format) {
return TextUtils.isEmpty(format.language) || "und".equals(format.language) ? ""
: format.language;
}
private static String buildBitrateString(Format format) {
return format.bitrate == Format.NO_VALUE ? ""
: String.format(Locale.US, "%.2fMbit", format.bitrate / 1000000f);
}
private static String joinWithSeparator(String first, String second) {
return first.length() == 0 ? second : (second.length() == 0 ? first : first + ", " + second);
}
private static String buildTrackIdString(Format format) {
return format.id == null ? "" : ("id:" + format.id);
}
private static String buildSampleMimeTypeString(Format format) {
return format.sampleMimeType == null ? "" : format.sampleMimeType;
}
} }

View File

@ -29,13 +29,18 @@ android {
} }
dependencies { dependencies {
compile project(':library') compile project(':library-core')
compile files('libs/cronet_api.jar') compile files('libs/cronet_api.jar')
compile files('libs/cronet_impl_common_java.jar') compile files('libs/cronet_impl_common_java.jar')
compile files('libs/cronet_impl_native_java.jar') compile files('libs/cronet_impl_native_java.jar')
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestCompile 'org.mockito:mockito-core:1.9.5'
androidTestCompile project(':library') androidTestCompile project(':library')
androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion
androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion
androidTestCompile 'com.android.support.test:runner:' + testSupportLibraryVersion
} }
ext {
javadocTitle = 'Cronet extension'
}
apply from: '../../javadoc_library.gradle'

View File

@ -72,7 +72,7 @@ public final class CronetDataSourceFactory extends BaseFactory {
protected CronetDataSource createDataSourceInternal(HttpDataSource.RequestProperties protected CronetDataSource createDataSourceInternal(HttpDataSource.RequestProperties
defaultRequestProperties) { defaultRequestProperties) {
return new CronetDataSource(cronetEngine, executor, contentTypePredicate, transferListener, return new CronetDataSource(cronetEngine, executor, contentTypePredicate, transferListener,
connectTimeoutMs, readTimeoutMs, resetTimeoutOnRedirects, null, defaultRequestProperties); connectTimeoutMs, readTimeoutMs, resetTimeoutOnRedirects, defaultRequestProperties);
} }
} }

View File

@ -31,21 +31,18 @@ FFMPEG_EXT_PATH="${EXOPLAYER_ROOT}/extensions/ffmpeg/src/main"
NDK_PATH="<path to Android NDK>" NDK_PATH="<path to Android NDK>"
``` ```
* Fetch and build FFmpeg. For example, to fetch and build for armv7a: * Set up host platform ("darwin-x86_64" for Mac OS X):
``` ```
cd "${FFMPEG_EXT_PATH}/jni" && \ HOST_PLATFORM="linux-x86_64"
git clone git://source.ffmpeg.org/ffmpeg ffmpeg && cd ffmpeg && \ ```
./configure \
--libdir=android-libs/armeabi-v7a \ * Fetch and build FFmpeg. For example, to fetch and build for armeabi-v7a,
--arch=arm \ arm64-v8a and x86 on Linux x86_64:
--cpu=armv7-a \
--cross-prefix="${NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-" \ ```
COMMON_OPTIONS="\
--target-os=android \ --target-os=android \
--sysroot="${NDK_PATH}/platforms/android-9/arch-arm/" \
--extra-cflags="-march=armv7-a -mfloat-abi=softfp" \
--extra-ldflags="-Wl,--fix-cortex-a8" \
--extra-ldexeflags=-pie \
--disable-static \ --disable-static \
--enable-shared \ --enable-shared \
--disable-doc \ --disable-doc \
@ -57,22 +54,56 @@ git clone git://source.ffmpeg.org/ffmpeg ffmpeg && cd ffmpeg && \
--disable-postproc \ --disable-postproc \
--disable-avfilter \ --disable-avfilter \
--disable-symver \ --disable-symver \
--disable-swresample \
--enable-avresample \ --enable-avresample \
--enable-decoder=vorbis \ --enable-decoder=vorbis \
--enable-decoder=opus \ --enable-decoder=opus \
--enable-decoder=flac \ --enable-decoder=flac \
--enable-decoder=alac \ " && \
cd "${FFMPEG_EXT_PATH}/jni" && \
git clone git://source.ffmpeg.org/ffmpeg ffmpeg && cd ffmpeg && \
./configure \
--libdir=android-libs/armeabi-v7a \
--arch=arm \
--cpu=armv7-a \
--cross-prefix="${NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/${HOST_PLATFORM}/bin/arm-linux-androideabi-" \
--sysroot="${NDK_PATH}/platforms/android-9/arch-arm/" \
--extra-cflags="-march=armv7-a -mfloat-abi=softfp" \
--extra-ldflags="-Wl,--fix-cortex-a8" \
--extra-ldexeflags=-pie \
${COMMON_OPTIONS} \
&& \ && \
make -j4 && \ make -j4 && make install-libs && \
make install-libs make clean && ./configure \
--libdir=android-libs/arm64-v8a \
--arch=aarch64 \
--cpu=armv8-a \
--cross-prefix="${NDK_PATH}/toolchains/aarch64-linux-android-4.9/prebuilt/${HOST_PLATFORM}/bin/aarch64-linux-android-" \
--sysroot="${NDK_PATH}/platforms/android-21/arch-arm64/" \
--extra-ldexeflags=-pie \
${COMMON_OPTIONS} \
&& \
make -j4 && make install-libs && \
make clean && ./configure \
--libdir=android-libs/x86 \
--arch=x86 \
--cpu=i686 \
--cross-prefix="${NDK_PATH}/toolchains/x86-4.9/prebuilt/${HOST_PLATFORM}/bin/i686-linux-android-" \
--sysroot="${NDK_PATH}/platforms/android-9/arch-x86/" \
--extra-ldexeflags=-pie \
--disable-asm \
${COMMON_OPTIONS} \
&& \
make -j4 && make install-libs && \
make clean
``` ```
* Build the JNI native libraries. Repeat this step for any other architectures * Build the JNI native libraries, setting `APP_ABI` to include the architectures
you need to support. built in the previous step. For example:
``` ```
cd "${FFMPEG_EXT_PATH}"/jni && \ cd "${FFMPEG_EXT_PATH}"/jni && \
${NDK_PATH}/ndk-build APP_ABI=armeabi-v7a -j4 ${NDK_PATH}/ndk-build APP_ABI="armeabi-v7a arm64-v8a x86" -j4
``` ```
* In your project, you can add a dependency on the extension by using a rule * In your project, you can add a dependency on the extension by using a rule

View File

@ -30,5 +30,10 @@ android {
} }
dependencies { dependencies {
compile project(':library') compile project(':library-core')
} }
ext {
javadocTitle = 'FFmpeg extension'
}
apply from: '../../javadoc_library.gradle'

View File

@ -31,15 +31,10 @@ LOCAL_MODULE := libavresample
LOCAL_SRC_FILES := ffmpeg/android-libs/$(TARGET_ARCH_ABI)/$(LOCAL_MODULE).so LOCAL_SRC_FILES := ffmpeg/android-libs/$(TARGET_ARCH_ABI)/$(LOCAL_MODULE).so
include $(PREBUILT_SHARED_LIBRARY) include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libswresample
LOCAL_SRC_FILES := ffmpeg/android-libs/$(TARGET_ARCH_ABI)/$(LOCAL_MODULE).so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := ffmpeg_jni.cc LOCAL_SRC_FILES := ffmpeg_jni.cc
LOCAL_C_INCLUDES := ffmpeg LOCAL_C_INCLUDES := ffmpeg
LOCAL_SHARED_LIBRARIES := libavcodec libavresample libavutil libswresample LOCAL_SHARED_LIBRARIES := libavcodec libavresample libavutil
LOCAL_LDLIBS := -Lffmpeg/android-libs/$(TARGET_ARCH_ABI) -llog LOCAL_LDLIBS := -Lffmpeg/android-libs/$(TARGET_ARCH_ABI) -llog
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)

View File

@ -30,7 +30,11 @@ android {
} }
dependencies { dependencies {
compile project(':library') compile project(':library-core')
androidTestCompile project(':testutils') androidTestCompile project(':testutils')
} }
ext {
javadocTitle = 'FLAC extension'
}
apply from: '../../javadoc_library.gradle'

View File

@ -22,6 +22,7 @@ import android.test.InstrumentationTestCase;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
@ -102,6 +103,11 @@ public class FlacPlaybackTest extends InstrumentationTestCase {
// Do nothing. // Do nothing.
} }
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
// Do nothing.
}
@Override @Override
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
// Do nothing. // Do nothing.

View File

@ -24,10 +24,15 @@ android {
} }
dependencies { dependencies {
compile project(':library') compile project(':library-core')
compile 'com.google.vr:sdk-audio:1.30.0' compile 'com.google.vr:sdk-audio:1.30.0'
} }
ext {
javadocTitle = 'GVR extension'
}
apply from: '../../javadoc_library.gradle'
ext { ext {
releaseArtifact = 'extension-gvr' releaseArtifact = 'extension-gvr'
releaseDescription = 'Google VR extension for ExoPlayer.' releaseDescription = 'Google VR extension for ExoPlayer.'

View File

@ -152,14 +152,19 @@ public final class GvrAudioProcessor implements AudioProcessor {
@Override @Override
public void flush() { public void flush() {
if (gvrAudioSurround != null) {
gvrAudioSurround.flush(); gvrAudioSurround.flush();
}
inputEnded = false; inputEnded = false;
} }
@Override @Override
public synchronized void release() { public synchronized void reset() {
buffer = null;
maybeReleaseGvrAudioSurround(); maybeReleaseGvrAudioSurround();
inputEnded = false;
buffer = null;
sampleRateHz = Format.NO_VALUE;
channelCount = Format.NO_VALUE;
} }
private void maybeReleaseGvrAudioSurround() { private void maybeReleaseGvrAudioSurround() {

View File

@ -29,12 +29,17 @@ android {
} }
dependencies { dependencies {
compile project(':library') compile project(':library-core')
compile('com.squareup.okhttp3:okhttp:3.6.0') { compile('com.squareup.okhttp3:okhttp:3.6.0') {
exclude group: 'org.json' exclude group: 'org.json'
} }
} }
ext {
javadocTitle = 'OkHttp extension'
}
apply from: '../../javadoc_library.gradle'
ext { ext {
releaseArtifact = 'extension-okhttp' releaseArtifact = 'extension-okhttp'
releaseDescription = 'OkHttp extension for ExoPlayer.' releaseDescription = 'OkHttp extension for ExoPlayer.'

View File

@ -30,5 +30,10 @@ android {
} }
dependencies { dependencies {
compile project(':library') compile project(':library-core')
} }
ext {
javadocTitle = 'Opus extension'
}
apply from: '../../javadoc_library.gradle'

View File

@ -22,6 +22,7 @@ import android.test.InstrumentationTestCase;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
@ -102,6 +103,11 @@ public class OpusPlaybackTest extends InstrumentationTestCase {
// Do nothing. // Do nothing.
} }
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
// Do nothing.
}
@Override @Override
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
// Do nothing. // Do nothing.

View File

@ -161,7 +161,7 @@ import java.util.List;
cryptoInfo.key, cryptoInfo.iv, cryptoInfo.numSubSamples, cryptoInfo.key, cryptoInfo.iv, cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData, cryptoInfo.numBytesOfEncryptedData) cryptoInfo.numBytesOfClearData, cryptoInfo.numBytesOfEncryptedData)
: opusDecode(nativeDecoderContext, inputBuffer.timeUs, inputData, inputData.limit(), : opusDecode(nativeDecoderContext, inputBuffer.timeUs, inputData, inputData.limit(),
outputBuffer, SAMPLE_RATE); outputBuffer);
if (result < 0) { if (result < 0) {
if (result == DRM_ERROR) { if (result == DRM_ERROR) {
String message = "Drm error: " + opusGetErrorMessage(nativeDecoderContext); String message = "Drm error: " + opusGetErrorMessage(nativeDecoderContext);
@ -210,7 +210,7 @@ import java.util.List;
private native long opusInit(int sampleRate, int channelCount, int numStreams, int numCoupled, private native long opusInit(int sampleRate, int channelCount, int numStreams, int numCoupled,
int gain, byte[] streamMap); int gain, byte[] streamMap);
private native int opusDecode(long decoder, long timeUs, ByteBuffer inputBuffer, int inputSize, private native int opusDecode(long decoder, long timeUs, ByteBuffer inputBuffer, int inputSize,
SimpleOutputBuffer outputBuffer, int sampleRate); SimpleOutputBuffer outputBuffer);
private native int opusSecureDecode(long decoder, long timeUs, ByteBuffer inputBuffer, private native int opusSecureDecode(long decoder, long timeUs, ByteBuffer inputBuffer,
int inputSize, SimpleOutputBuffer outputBuffer, int sampleRate, int inputSize, SimpleOutputBuffer outputBuffer, int sampleRate,
ExoMediaCrypto mediaCrypto, int inputMode, byte[] key, byte[] iv, ExoMediaCrypto mediaCrypto, int inputMode, byte[] key, byte[] iv,

View File

@ -59,6 +59,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
} }
static const int kBytesPerSample = 2; // opus fixed point uses 16 bit samples. static const int kBytesPerSample = 2; // opus fixed point uses 16 bit samples.
static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
static int channelCount; static int channelCount;
static int errorCode; static int errorCode;
@ -92,16 +93,14 @@ DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
} }
DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs, DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs,
jobject jInputBuffer, jint inputSize, jobject jOutputBuffer, jobject jInputBuffer, jint inputSize, jobject jOutputBuffer) {
jint sampleRate) {
OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder); OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
const uint8_t* inputBuffer = const uint8_t* inputBuffer =
reinterpret_cast<const uint8_t*>( reinterpret_cast<const uint8_t*>(
env->GetDirectBufferAddress(jInputBuffer)); env->GetDirectBufferAddress(jInputBuffer));
const int32_t inputSampleCount = const jint outputSize =
opus_packet_get_nb_samples(inputBuffer, inputSize, sampleRate); kMaxOpusOutputPacketSizeSamples * kBytesPerSample * channelCount;
const jint outputSize = inputSampleCount * kBytesPerSample * channelCount;
env->CallObjectMethod(jOutputBuffer, outputBufferInit, jTimeUs, outputSize); env->CallObjectMethod(jOutputBuffer, outputBufferInit, jTimeUs, outputSize);
const jobject jOutputBufferData = env->CallObjectMethod(jOutputBuffer, const jobject jOutputBufferData = env->CallObjectMethod(jOutputBuffer,
@ -110,7 +109,7 @@ DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs,
int16_t* outputBufferData = reinterpret_cast<int16_t*>( int16_t* outputBufferData = reinterpret_cast<int16_t*>(
env->GetDirectBufferAddress(jOutputBufferData)); env->GetDirectBufferAddress(jOutputBufferData));
int sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize, int sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize,
outputBufferData, outputSize, 0); outputBufferData, kMaxOpusOutputPacketSizeSamples, 0);
// record error code // record error code
errorCode = (sampleCount < 0) ? sampleCount : 0; errorCode = (sampleCount < 0) ? sampleCount : 0;
return (sampleCount < 0) ? sampleCount return (sampleCount < 0) ? sampleCount

View File

@ -49,7 +49,7 @@ git clone https://chromium.googlesource.com/libyuv/libyuv libyuv
cd "${VP9_EXT_PATH}/jni/libvpx" && \ cd "${VP9_EXT_PATH}/jni/libvpx" && \
git checkout tags/v1.6.1 -b v1.6.1 && \ git checkout tags/v1.6.1 -b v1.6.1 && \
cd "${VP9_EXT_PATH}/jni/libyuv" && \ cd "${VP9_EXT_PATH}/jni/libyuv" && \
git checkout e2611a73 git checkout 996a2bbd
``` ```
* Run a script that generates necessary configuration files for libvpx: * Run a script that generates necessary configuration files for libvpx:

View File

@ -30,6 +30,10 @@ android {
} }
dependencies { dependencies {
compile project(':library') compile project(':library-core')
} }
ext {
javadocTitle = 'VP9 extension'
}
apply from: '../../javadoc_library.gradle'

View File

@ -23,6 +23,7 @@ import android.util.Log;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
@ -134,6 +135,11 @@ public class VpxPlaybackTest extends InstrumentationTestCase {
// Do nothing. // Do nothing.
} }
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
// Do nothing.
}
@Override @Override
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
// Do nothing. // Do nothing.

View File

@ -87,8 +87,8 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
private boolean inputStreamEnded; private boolean inputStreamEnded;
private boolean outputStreamEnded; private boolean outputStreamEnded;
private int lastReportedWidth; private int reportedWidth;
private int lastReportedHeight; private int reportedHeight;
private long droppedFrameAccumulationStartTimeMs; private long droppedFrameAccumulationStartTimeMs;
private int droppedFrames; private int droppedFrames;
@ -147,10 +147,10 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys; this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
joiningDeadlineMs = -1; joiningDeadlineMs = C.TIME_UNSET;
clearLastReportedVideoSize(); clearReportedVideoSize();
formatHolder = new FormatHolder(); formatHolder = new FormatHolder();
flagsOnlyBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
outputMode = VpxDecoder.OUTPUT_MODE_NONE; outputMode = VpxDecoder.OUTPUT_MODE_NONE;
} }
@ -185,7 +185,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
} }
if (isRendererAvailable()) { // We have a format.
drmSession = pendingDrmSession; drmSession = pendingDrmSession;
ExoMediaCrypto mediaCrypto = null; ExoMediaCrypto mediaCrypto = null;
if (drmSession != null) { if (drmSession != null) {
@ -205,8 +205,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
// If we don't have a decoder yet, we need to instantiate one. // If we don't have a decoder yet, we need to instantiate one.
long codecInitializingTimestamp = SystemClock.elapsedRealtime(); long codecInitializingTimestamp = SystemClock.elapsedRealtime();
TraceUtil.beginSection("createVpxDecoder"); TraceUtil.beginSection("createVpxDecoder");
decoder = new VpxDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, decoder = new VpxDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, mediaCrypto);
mediaCrypto);
decoder.setOutputMode(outputMode); decoder.setOutputMode(outputMode);
TraceUtil.endSection(); TraceUtil.endSection();
long codecInitializedTimestamp = SystemClock.elapsedRealtime(); long codecInitializedTimestamp = SystemClock.elapsedRealtime();
@ -221,9 +220,6 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} catch (VpxDecoderException e) { } catch (VpxDecoderException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw ExoPlaybackException.createForRenderer(e, getIndex());
} }
} else {
skipToKeyframeBefore(positionUs);
}
decoderCounters.ensureUpdated(); decoderCounters.ensureUpdated();
} }
@ -257,27 +253,26 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
return false; return false;
} }
// Drop the frame if we're joining and are more than 30ms late, or if we have the next frame if (outputMode == VpxDecoder.OUTPUT_MODE_NONE) {
// and that's also late. Else we'll render what we have. // Skip frames in sync with playback, so we'll be at the right frame if the mode changes.
if ((joiningDeadlineMs != -1 && outputBuffer.timeUs < positionUs - 30000) if (outputBuffer.timeUs <= positionUs) {
|| (nextOutputBuffer != null && !nextOutputBuffer.isEndOfStream() skipBuffer();
&& nextOutputBuffer.timeUs < positionUs)) { return true;
decoderCounters.droppedOutputBufferCount++;
droppedFrames++;
consecutiveDroppedFrameCount++;
decoderCounters.maxConsecutiveDroppedOutputBufferCount = Math.max(
consecutiveDroppedFrameCount,
decoderCounters.maxConsecutiveDroppedOutputBufferCount);
if (droppedFrames == maxDroppedFramesToNotify) {
maybeNotifyDroppedFrames();
} }
outputBuffer.release(); return false;
outputBuffer = null; }
final long nextOutputBufferTimeUs =
nextOutputBuffer != null && !nextOutputBuffer.isEndOfStream()
? nextOutputBuffer.timeUs : C.TIME_UNSET;
if (shouldDropOutputBuffer(
outputBuffer.timeUs, nextOutputBufferTimeUs, positionUs, joiningDeadlineMs)) {
dropBuffer();
return true; return true;
} }
// If we have not rendered any frame so far (either initially or immediately following a seek), // If we have yet to render a frame to the current output (either initially or immediately
// render one frame irrespective of the state or current position. // following a seek), render one irrespective of the state or current position.
if (!renderedFirstFrame if (!renderedFirstFrame
|| (getState() == STATE_STARTED && outputBuffer.timeUs <= positionUs + 30000)) { || (getState() == STATE_STARTED && outputBuffer.timeUs <= positionUs + 30000)) {
renderBuffer(); renderBuffer();
@ -285,28 +280,64 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
return false; return false;
} }
/**
* Returns whether the current frame should be dropped.
*
* @param outputBufferTimeUs The timestamp of the current output buffer.
* @param nextOutputBufferTimeUs The timestamp of the next output buffer or
* {@link TIME_UNSET} if the next output buffer is unavailable.
* @param positionUs The current playback position.
* @param joiningDeadlineMs The joining deadline.
* @return Returns whether to drop the current output buffer.
*/
protected boolean shouldDropOutputBuffer(long outputBufferTimeUs, long nextOutputBufferTimeUs,
long positionUs, long joiningDeadlineMs) {
// Drop the frame if we're joining and are more than 30ms late, or if we have the next frame
// and that's also late. Else we'll render what we have.
return (joiningDeadlineMs != C.TIME_UNSET && outputBufferTimeUs < positionUs - 30000)
|| (nextOutputBufferTimeUs != C.TIME_UNSET && nextOutputBufferTimeUs < positionUs);
}
private void renderBuffer() { private void renderBuffer() {
decoderCounters.renderedOutputBufferCount++; int bufferMode = outputBuffer.mode;
consecutiveDroppedFrameCount = 0; boolean renderRgb = bufferMode == VpxDecoder.OUTPUT_MODE_RGB && surface != null;
maybeNotifyVideoSizeChanged(outputBuffer.width, outputBuffer.height); boolean renderYuv = bufferMode == VpxDecoder.OUTPUT_MODE_YUV && outputBufferRenderer != null;
if (outputBuffer.mode == VpxDecoder.OUTPUT_MODE_RGB && surface != null) { if (!renderRgb && !renderYuv) {
renderRgbFrame(outputBuffer, scaleToFit); dropBuffer();
if (!renderedFirstFrame) {
renderedFirstFrame = true;
eventDispatcher.renderedFirstFrame(surface);
}
outputBuffer.release();
} else if (outputBuffer.mode == VpxDecoder.OUTPUT_MODE_YUV && outputBufferRenderer != null) {
// The renderer will release the buffer.
outputBufferRenderer.setOutputBuffer(outputBuffer);
if (!renderedFirstFrame) {
renderedFirstFrame = true;
eventDispatcher.renderedFirstFrame(null);
}
} else { } else {
maybeNotifyVideoSizeChanged(outputBuffer.width, outputBuffer.height);
if (renderRgb) {
renderRgbFrame(outputBuffer, scaleToFit);
outputBuffer.release(); outputBuffer.release();
} else /* renderYuv */ {
outputBufferRenderer.setOutputBuffer(outputBuffer);
// The renderer will release the buffer.
} }
outputBuffer = null; outputBuffer = null;
consecutiveDroppedFrameCount = 0;
decoderCounters.renderedOutputBufferCount++;
maybeNotifyRenderedFirstFrame();
}
}
private void dropBuffer() {
decoderCounters.droppedOutputBufferCount++;
droppedFrames++;
consecutiveDroppedFrameCount++;
decoderCounters.maxConsecutiveDroppedOutputBufferCount = Math.max(
consecutiveDroppedFrameCount, decoderCounters.maxConsecutiveDroppedOutputBufferCount);
if (droppedFrames == maxDroppedFramesToNotify) {
maybeNotifyDroppedFrames();
}
outputBuffer.release();
outputBuffer = null;
}
private void skipBuffer() {
decoderCounters.skippedOutputBufferCount++;
outputBuffer.release();
outputBuffer = null;
} }
private void renderRgbFrame(VpxOutputBuffer outputBuffer, boolean scale) { private void renderRgbFrame(VpxOutputBuffer outputBuffer, boolean scale) {
@ -406,11 +437,11 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
return false; return false;
} }
if (format != null && (isSourceReady() || outputBuffer != null) if (format != null && (isSourceReady() || outputBuffer != null)
&& (renderedFirstFrame || !isRendererAvailable())) { && (renderedFirstFrame || outputMode == VpxDecoder.OUTPUT_MODE_NONE)) {
// Ready. If we were joining then we've now joined, so clear the joining deadline. // Ready. If we were joining then we've now joined, so clear the joining deadline.
joiningDeadlineMs = -1; joiningDeadlineMs = C.TIME_UNSET;
return true; return true;
} else if (joiningDeadlineMs == -1) { } else if (joiningDeadlineMs == C.TIME_UNSET) {
// Not joining. // Not joining.
return false; return false;
} else if (SystemClock.elapsedRealtime() < joiningDeadlineMs) { } else if (SystemClock.elapsedRealtime() < joiningDeadlineMs) {
@ -418,7 +449,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
return true; return true;
} else { } else {
// The joining deadline has been exceeded. Give up and clear the deadline. // The joining deadline has been exceeded. Give up and clear the deadline.
joiningDeadlineMs = -1; joiningDeadlineMs = C.TIME_UNSET;
return false; return false;
} }
} }
@ -433,24 +464,27 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
protected void onPositionReset(long positionUs, boolean joining) { protected void onPositionReset(long positionUs, boolean joining) {
inputStreamEnded = false; inputStreamEnded = false;
outputStreamEnded = false; outputStreamEnded = false;
renderedFirstFrame = false; clearRenderedFirstFrame();
consecutiveDroppedFrameCount = 0; consecutiveDroppedFrameCount = 0;
if (decoder != null) { if (decoder != null) {
flushDecoder(); flushDecoder();
} }
joiningDeadlineMs = joining && allowedJoiningTimeMs > 0 if (joining) {
? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : -1; setJoiningDeadlineMs();
} else {
joiningDeadlineMs = C.TIME_UNSET;
}
} }
@Override @Override
protected void onStarted() { protected void onStarted() {
droppedFrames = 0; droppedFrames = 0;
droppedFrameAccumulationStartTimeMs = SystemClock.elapsedRealtime(); droppedFrameAccumulationStartTimeMs = SystemClock.elapsedRealtime();
joiningDeadlineMs = C.TIME_UNSET;
} }
@Override @Override
protected void onStopped() { protected void onStopped() {
joiningDeadlineMs = -1;
maybeNotifyDroppedFrames(); maybeNotifyDroppedFrames();
} }
@ -460,7 +494,8 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
outputBuffer = null; outputBuffer = null;
format = null; format = null;
waitingForKeys = false; waitingForKeys = false;
clearLastReportedVideoSize(); clearReportedVideoSize();
clearRenderedFirstFrame();
try { try {
releaseDecoder(); releaseDecoder();
} finally { } finally {
@ -537,47 +572,78 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
private void setOutput(Surface surface, VpxOutputBufferRenderer outputBufferRenderer) { private void setOutput(Surface surface, VpxOutputBufferRenderer outputBufferRenderer) {
// At most one output may be non-null. Both may be null if the output is being cleared. // At most one output may be non-null. Both may be null if the output is being cleared.
Assertions.checkState(surface == null || outputBufferRenderer == null); Assertions.checkState(surface == null || outputBufferRenderer == null);
// Clear state so that we always call the event listener with the video size and when a frame
// is rendered, even if the output hasn't changed.
renderedFirstFrame = false;
clearLastReportedVideoSize();
// We only need to update the decoder if the output has changed.
if (this.surface != surface || this.outputBufferRenderer != outputBufferRenderer) { if (this.surface != surface || this.outputBufferRenderer != outputBufferRenderer) {
// The output has changed.
this.surface = surface; this.surface = surface;
this.outputBufferRenderer = outputBufferRenderer; this.outputBufferRenderer = outputBufferRenderer;
outputMode = outputBufferRenderer != null ? VpxDecoder.OUTPUT_MODE_YUV outputMode = outputBufferRenderer != null ? VpxDecoder.OUTPUT_MODE_YUV
: surface != null ? VpxDecoder.OUTPUT_MODE_RGB : VpxDecoder.OUTPUT_MODE_NONE; : surface != null ? VpxDecoder.OUTPUT_MODE_RGB : VpxDecoder.OUTPUT_MODE_NONE;
updateDecoder(); if (outputMode != VpxDecoder.OUTPUT_MODE_NONE) {
}
}
private void updateDecoder() {
if (decoder != null) { if (decoder != null) {
if (outputMode == VpxDecoder.OUTPUT_MODE_NONE) {
releaseDecoder();
} else {
decoder.setOutputMode(outputMode); decoder.setOutputMode(outputMode);
} }
// If we know the video size, report it again immediately.
maybeRenotifyVideoSizeChanged();
// We haven't rendered to the new output yet.
clearRenderedFirstFrame();
if (getState() == STATE_STARTED) {
setJoiningDeadlineMs();
}
} else {
// The output has been removed. We leave the outputMode of the underlying decoder unchanged
// in anticipation that a subsequent output will likely be of the same type.
clearReportedVideoSize();
clearRenderedFirstFrame();
}
} else if (outputMode != VpxDecoder.OUTPUT_MODE_NONE) {
// The output is unchanged and non-null. If we know the video size and/or have already
// rendered to the output, report these again immediately.
maybeRenotifyVideoSizeChanged();
maybeRenotifyRenderedFirstFrame();
} }
} }
private boolean isRendererAvailable() { private void setJoiningDeadlineMs() {
return surface != null || outputBufferRenderer != null; joiningDeadlineMs = allowedJoiningTimeMs > 0
? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET;
} }
private void clearLastReportedVideoSize() { private void clearRenderedFirstFrame() {
lastReportedWidth = Format.NO_VALUE; renderedFirstFrame = false;
lastReportedHeight = Format.NO_VALUE; }
private void maybeNotifyRenderedFirstFrame() {
if (!renderedFirstFrame) {
renderedFirstFrame = true;
eventDispatcher.renderedFirstFrame(surface);
}
}
private void maybeRenotifyRenderedFirstFrame() {
if (renderedFirstFrame) {
eventDispatcher.renderedFirstFrame(surface);
}
}
private void clearReportedVideoSize() {
reportedWidth = Format.NO_VALUE;
reportedHeight = Format.NO_VALUE;
} }
private void maybeNotifyVideoSizeChanged(int width, int height) { private void maybeNotifyVideoSizeChanged(int width, int height) {
if (lastReportedWidth != width || lastReportedHeight != height) { if (reportedWidth != width || reportedHeight != height) {
lastReportedWidth = width; reportedWidth = width;
lastReportedHeight = height; reportedHeight = height;
eventDispatcher.videoSizeChanged(width, height, 0, 1); eventDispatcher.videoSizeChanged(width, height, 0, 1);
} }
} }
private void maybeRenotifyVideoSizeChanged() {
if (reportedWidth != Format.NO_VALUE || reportedHeight != Format.NO_VALUE) {
eventDispatcher.videoSizeChanged(reportedWidth, reportedHeight, 0, 1);
}
}
private void maybeNotifyDroppedFrames() { private void maybeNotifyDroppedFrames() {
if (droppedFrames > 0) { if (droppedFrames > 0) {
long now = SystemClock.elapsedRealtime(); long now = SystemClock.elapsedRealtime();

View File

@ -21,6 +21,7 @@ LIBYUV_ROOT := $(WORKING_DIR)/libyuv
# build libyuv_static.a # build libyuv_static.a
LOCAL_PATH := $(WORKING_DIR) LOCAL_PATH := $(WORKING_DIR)
LIBYUV_DISABLE_JPEG := "yes"
include $(LIBYUV_ROOT)/Android.mk include $(LIBYUV_ROOT)/Android.mk
# build libvpx.so # build libvpx.so

View File

@ -68,7 +68,7 @@ limit=$((${#arch[@]} - 1))
# everything else will be removed. # everything else will be removed.
allowed_files="libvpx_srcs.txt vpx_config.c vpx_config.h vpx_scale_rtcd.h" allowed_files="libvpx_srcs.txt vpx_config.c vpx_config.h vpx_scale_rtcd.h"
allowed_files+=" vp8_rtcd.h vp9_rtcd.h vpx_version.h vpx_config.asm" allowed_files+=" vp8_rtcd.h vp9_rtcd.h vpx_version.h vpx_config.asm"
allowed_files+=" vpx_dsp_rtcd.h" allowed_files+=" vpx_dsp_rtcd.h libvpx.ver"
remove_trailing_whitespace() { remove_trailing_whitespace() {
perl -pi -e 's/\s\+$//' "$@" perl -pi -e 's/\s\+$//' "$@"

View File

@ -37,9 +37,7 @@ LOCAL_SRC_FILES += $(addprefix libvpx/, $(filter-out vpx_config.c, \
# include assembly files if they exist # include assembly files if they exist
# "%.asm.[sS]" covers neon assembly and "%.asm" covers x86 assembly # "%.asm.[sS]" covers neon assembly and "%.asm" covers x86 assembly
LOCAL_SRC_FILES += $(addprefix libvpx/, \ LOCAL_SRC_FILES += $(addprefix libvpx/, \
$(filter %.asm.s %.asm, $(libvpx_codec_srcs))) $(filter %.asm.s %.asm.S %.asm, $(libvpx_codec_srcs)))
LOCAL_SRC_FILES += $(addprefix libvpx/, \
$(filter %.asm.S %.asm, $(libvpx_codec_srcs)))
ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),) ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),)
# append .neon to *_neon.c and *.[sS] # append .neon to *_neon.c and *.[sS]
@ -48,10 +46,8 @@ LOCAL_SRC_FILES := $(subst .s,.s.neon,$(LOCAL_SRC_FILES))
LOCAL_SRC_FILES := $(subst .S,.S.neon,$(LOCAL_SRC_FILES)) LOCAL_SRC_FILES := $(subst .S,.S.neon,$(LOCAL_SRC_FILES))
endif endif
# remove duplicates
LOCAL_SRC_FILES := $(sort $(LOCAL_SRC_FILES))
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/libvpx \ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/libvpx \
$(LOCAL_PATH)/libvpx/vpx $(LOCAL_PATH)/libvpx/vpx
LOCAL_LDFLAGS := -Wl,--version-script=$(CONFIG_DIR)/libvpx.ver
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)

View File

@ -20,8 +20,9 @@
#include <android/log.h> #include <android/log.h>
#include <algorithm> #include <algorithm>
#include <cstdlib>
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <new> #include <new>
#include "libyuv.h" // NOLINT #include "libyuv.h" // NOLINT

68
javadoc_combined.gradle Normal file
View File

@ -0,0 +1,68 @@
// Copyright (C) 2017 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.
class CombinedJavadocPlugin implements Plugin<Project> {
static final String TASK_NAME = "generateCombinedJavadoc"
@Override
void apply(Project project) {
project.gradle.projectsEvaluated {
Set<Project> libraryModules = getLibraryModules(project)
if (!libraryModules.isEmpty()) {
String sdkDirectory = getSdkDirectory(libraryModules)
project.task(TASK_NAME, type: Javadoc) {
description = "Generates combined Javadoc."
title = "ExoPlayer library"
source = libraryModules.generateJavadoc.source
classpath = project.files(libraryModules.generateJavadoc.classpath)
destinationDir = project.file("$project.buildDir/docs/javadoc")
options {
links "http://docs.oracle.com/javase/7/docs/api/"
linksOffline "https://developer.android.com/reference",
"${sdkDirectory}/docs/reference"
encoding = "UTF-8"
}
exclude "**/BuildConfig.java"
exclude "**/R.java"
destinationDir project.file("$project.buildDir/docs/javadoc")
doLast {
libraryModules.each { libraryModule ->
project.copy {
from "${libraryModule.projectDir}/src/main/javadoc"
into "${project.buildDir}/docs/javadoc"
}
}
}
}
}
}
}
// Returns Android library modules that declare a generateJavadoc task.
private Set<Project> getLibraryModules(Project project) {
project.subprojects.findAll {
it.plugins.findPlugin("com.android.library") &&
it.tasks.findByName("generateJavadoc")
}
}
// Returns the Android SDK directory given a set of Android library modules.
private String getSdkDirectory(Set<Project> libraryModules) {
// We can retrieve the Android SDK directory from any module.
return libraryModules.iterator().next().android.sdkDirectory
}
}
apply plugin: CombinedJavadocPlugin

40
javadoc_library.gradle Normal file
View File

@ -0,0 +1,40 @@
// Copyright (C) 2017 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.
android.libraryVariants.all { variant ->
def name = variant.buildType.name
if (!name.equals("release")) {
return; // Skip non-release builds.
}
task("generateJavadoc", type: Javadoc) {
description = "Generates Javadoc for the ${javadocTitle}."
title = "ExoPlayer ${javadocTitle}"
source = variant.javaCompile.source
classpath = files(variant.javaCompile.classpath.files,
project.android.getBootClasspath())
options {
links "http://docs.oracle.com/javase/7/docs/api/"
linksOffline "https://developer.android.com/reference",
"${android.sdkDirectory}/docs/reference"
encoding = "UTF-8"
}
exclude "**/BuildConfig.java"
exclude "**/R.java"
doLast {
copy {
from "src/main/javadoc"
into "$buildDir/docs/javadoc"
}
}
}
}

38
library/all/build.gradle Normal file
View File

@ -0,0 +1,38 @@
// Copyright (C) 2016 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 plugin: 'com.android.library'
android {
compileSdkVersion project.ext.compileSdkVersion
buildToolsVersion project.ext.buildToolsVersion
defaultConfig {
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.targetSdkVersion
}
}
dependencies {
compile project(':library-core')
compile project(':library-dash')
compile project(':library-hls')
compile project(':library-smoothstreaming')
compile project(':library-ui')
}
ext {
releaseArtifact = 'exoplayer'
releaseDescription = 'The ExoPlayer library (all modules).'
}
apply from: '../../publish.gradle'

View File

@ -1,87 +0,0 @@
// Copyright (C) 2016 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.
import com.android.builder.core.BuilderConstants
apply plugin: 'com.android.library'
android {
compileSdkVersion project.ext.compileSdkVersion
buildToolsVersion project.ext.buildToolsVersion
defaultConfig {
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.targetSdkVersion
consumerProguardFiles 'proguard-rules.txt'
}
buildTypes {
// Re-enable test coverage when the following issue is fixed:
// https://code.google.com/p/android/issues/detail?id=226070
// debug {
// testCoverageEnabled = true
// }
}
sourceSets {
androidTest {
java.srcDirs += "../testutils/src/main/java/"
}
}
}
dependencies {
compile 'com.android.support:support-annotations:25.2.0'
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestCompile 'org.mockito:mockito-core:1.9.5'
}
android.libraryVariants.all { variant ->
def name = variant.buildType.name
if (name.equals(BuilderConstants.DEBUG)) {
return; // Skip debug builds.
}
def task = project.tasks.create "jar${name.capitalize()}", Jar
task.dependsOn variant.javaCompile
task.from variant.javaCompile.destinationDir
artifacts.add('archives', task);
}
android.libraryVariants.all { variant ->
task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
title = "ExoPlayer library"
description "Generates Javadoc for $variant.name."
source = variant.javaCompile.source
classpath = files(variant.javaCompile.classpath.files, project.android.getBootClasspath())
options {
links "http://docs.oracle.com/javase/7/docs/api/"
linksOffline "https://developer.android.com/reference","${android.sdkDirectory}/docs/reference"
encoding = 'UTF-8'
}
exclude '**/BuildConfig.java'
exclude '**/R.java'
doLast {
copy {
from "src/main/javadoc"
into "$buildDir/docs/javadoc"
}
}
}
}
ext {
releaseArtifact = 'exoplayer'
releaseDescription = 'The ExoPlayer library.'
}
apply from: '../publish.gradle'

54
library/core/build.gradle Normal file
View File

@ -0,0 +1,54 @@
// Copyright (C) 2016 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 plugin: 'com.android.library'
android {
compileSdkVersion project.ext.compileSdkVersion
buildToolsVersion project.ext.buildToolsVersion
defaultConfig {
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.targetSdkVersion
}
sourceSets {
androidTest {
java.srcDirs += "../../testutils/src/main/java/"
}
}
buildTypes {
debug {
testCoverageEnabled = true
}
}
}
dependencies {
compile 'com.android.support:support-annotations:' + supportLibraryVersion
androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion
androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion
}
ext {
javadocTitle = 'Core module'
}
apply from: '../../javadoc_library.gradle'
ext {
releaseArtifact = 'exoplayer-core'
releaseDescription = 'The ExoPlayer library core module.'
}
apply from: '../../publish.gradle'

View File

@ -16,7 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.google.android.exoplayer2.test"> package="com.google.android.exoplayer2.core.test">
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/> <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/>
@ -27,7 +27,7 @@
</application> </application>
<instrumentation <instrumentation
android:targetPackage="com.google.android.exoplayer2.test" android:targetPackage="com.google.android.exoplayer2.core.test"
android:name="android.test.InstrumentationTestRunner" android:name="android.test.InstrumentationTestRunner"
tools:replace="android:targetPackage"/> tools:replace="android:targetPackage"/>

Some files were not shown because too many files have changed in this diff Show More