Commit 706d5ac2 by manisha_jajoo Committed by GitHub

Merge branch 'main' into rtp-mpeg4

parents e7567d20 4b72335d
Showing with 1376 additions and 358 deletions
......@@ -37,6 +37,7 @@ project.ext {
androidxAnnotationExperimentalVersion = '1.2.0'
androidxAppCompatVersion = '1.3.1'
androidxCollectionVersion = '1.1.0'
androidxConstraintLayoutVersion = '2.0.4'
androidxCoreVersion = '1.7.0'
androidxFuturesVersion = '1.1.0'
androidxMediaVersion = '1.4.3'
......
......@@ -36,7 +36,7 @@ import androidx.media3.common.MediaItem;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.ui.StyledPlayerView;
import androidx.media3.ui.PlayerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
......@@ -52,7 +52,7 @@ import com.google.android.gms.dynamite.DynamiteModule;
public class MainActivity extends AppCompatActivity
implements OnClickListener, PlayerManager.Listener {
private StyledPlayerView playerView;
private PlayerView playerView;
private PlayerManager playerManager;
private RecyclerView mediaQueueList;
private MediaQueueListAdapter mediaQueueListAdapter;
......
......@@ -28,8 +28,8 @@ import androidx.media3.common.Player.TimelineChangeReason;
import androidx.media3.common.Timeline;
import androidx.media3.common.TracksInfo;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.ui.StyledPlayerControlView;
import androidx.media3.ui.StyledPlayerView;
import androidx.media3.ui.PlayerControlView;
import androidx.media3.ui.PlayerView;
import com.google.android.gms.cast.framework.CastContext;
import java.util.ArrayList;
......@@ -51,7 +51,7 @@ import java.util.ArrayList;
}
private final Context context;
private final StyledPlayerView playerView;
private final PlayerView playerView;
private final Player localPlayer;
private final CastPlayer castPlayer;
private final ArrayList<MediaItem> mediaQueue;
......@@ -66,11 +66,11 @@ import java.util.ArrayList;
*
* @param context A {@link Context}.
* @param listener A {@link Listener} for queue position changes.
* @param playerView The {@link StyledPlayerView} for playback.
* @param playerView The {@link PlayerView} for playback.
* @param castContext The {@link CastContext}.
*/
public PlayerManager(
Context context, Listener listener, StyledPlayerView playerView, CastContext castContext) {
Context context, Listener listener, PlayerView playerView, CastContext castContext) {
this.context = context;
this.listener = listener;
this.playerView = playerView;
......@@ -223,10 +223,12 @@ import java.util.ArrayList;
if (currentPlayer != localPlayer || tracksInfo == lastSeenTrackGroupInfo) {
return;
}
if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_VIDEO)) {
if (tracksInfo.containsType(C.TRACK_TYPE_VIDEO)
&& !tracksInfo.isTypeSupported(C.TRACK_TYPE_VIDEO, /* allowExceedsCapabilities= */ true)) {
listener.onUnsupportedTrack(C.TRACK_TYPE_VIDEO);
}
if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)) {
if (tracksInfo.containsType(C.TRACK_TYPE_AUDIO)
&& !tracksInfo.isTypeSupported(C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true)) {
listener.onUnsupportedTrack(C.TRACK_TYPE_AUDIO);
}
lastSeenTrackGroupInfo = tracksInfo;
......@@ -270,7 +272,7 @@ import java.util.ArrayList;
R.drawable.ic_baseline_cast_connected_400,
/* theme= */ null));
} else { // currentPlayer == localPlayer
playerView.setControllerShowTimeoutMs(StyledPlayerControlView.DEFAULT_SHOW_TIMEOUT_MS);
playerView.setControllerShowTimeoutMs(PlayerControlView.DEFAULT_SHOW_TIMEOUT_MS);
playerView.setDefaultArtwork(null);
}
......
......@@ -20,7 +20,7 @@
android:layout_height="match_parent"
android:keepScreenOn="true">
<androidx.media3.ui.StyledPlayerView android:id="@+id/player_view"
<androidx.media3.ui.PlayerView android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
......
......@@ -15,19 +15,19 @@
#extension GL_OES_EGL_image_external : require
precision mediump float;
// External texture containing video decoder output.
uniform samplerExternalOES tex_sampler_0;
uniform samplerExternalOES uTexSampler0;
// Texture containing the overlap bitmap.
uniform sampler2D tex_sampler_1;
uniform sampler2D uTexSampler1;
// Horizontal scaling factor for the overlap bitmap.
uniform float scaleX;
uniform float uScaleX;
// Vertical scaling factory for the overlap bitmap.
uniform float scaleY;
varying vec2 v_texcoord;
uniform float uScaleY;
varying vec2 vTexCoords;
void main() {
vec4 videoColor = texture2D(tex_sampler_0, v_texcoord);
vec4 overlayColor = texture2D(tex_sampler_1,
vec2(v_texcoord.x * scaleX,
v_texcoord.y * scaleY));
vec4 videoColor = texture2D(uTexSampler0, vTexCoords);
vec4 overlayColor = texture2D(uTexSampler1,
vec2(vTexCoords.x * uScaleX,
vTexCoords.y * uScaleY));
// Blend the video decoder output and the overlay bitmap.
gl_FragColor = videoColor * (1.0 - overlayColor.a)
+ overlayColor * overlayColor.a;
......
......@@ -11,11 +11,11 @@
// 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.
attribute vec4 a_position;
attribute vec4 a_texcoord;
uniform mat4 tex_transform;
varying vec2 v_texcoord;
attribute vec4 aFramePosition;
attribute vec4 aTexCoords;
uniform mat4 uTexTransform;
varying vec2 vTexCoords;
void main() {
gl_Position = a_position;
v_texcoord = (tex_transform * a_texcoord).xy;
gl_Position = aFramePosition;
vTexCoords = (uTexTransform * aTexCoords).xy;
}
......@@ -27,6 +27,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import androidx.media3.common.C;
import androidx.media3.common.util.GlProgram;
import androidx.media3.common.util.GlUtil;
import java.io.IOException;
import java.util.Locale;
......@@ -50,7 +51,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final Bitmap logoBitmap;
private final Canvas overlayCanvas;
private GlUtil.@MonotonicNonNull Program program;
private @MonotonicNonNull GlProgram program;
private float bitmapScaleX;
private float bitmapScaleY;
......@@ -78,7 +79,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public void initialize() {
try {
program =
new GlUtil.Program(
new GlProgram(
context,
/* vertexShaderFilePath= */ "bitmap_overlay_video_processor_vertex.glsl",
/* fragmentShaderFilePath= */ "bitmap_overlay_video_processor_fragment.glsl");
......@@ -86,23 +87,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
throw new IllegalStateException(e);
}
program.setBufferAttribute(
"a_position",
new float[] {
-1, -1, 0, 1,
1, -1, 0, 1,
-1, 1, 0, 1,
1, 1, 0, 1
},
4);
"aFramePosition", GlUtil.getNormalizedCoordinateBounds(), GlUtil.RECTANGLE_VERTICES_COUNT);
program.setBufferAttribute(
"a_texcoord",
new float[] {
0, 0, 0, 1,
1, 0, 0, 1,
0, 1, 0, 1,
1, 1, 0, 1
},
4);
"aTexCoords", GlUtil.getTextureCoordinateBounds(), GlUtil.RECTANGLE_VERTICES_COUNT);
GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
......@@ -131,12 +118,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
GlUtil.checkGlError();
// Run the shader program.
GlUtil.Program program = checkNotNull(this.program);
program.setSamplerTexIdUniform("tex_sampler_0", frameTexture, /* unit= */ 0);
program.setSamplerTexIdUniform("tex_sampler_1", textures[0], /* unit= */ 1);
program.setFloatUniform("scaleX", bitmapScaleX);
program.setFloatUniform("scaleY", bitmapScaleY);
program.setFloatsUniform("tex_transform", transformMatrix);
GlProgram program = checkNotNull(this.program);
program.setSamplerTexIdUniform("uTexSampler0", frameTexture, /* unit= */ 0);
program.setSamplerTexIdUniform("uTexSampler1", textures[0], /* unit= */ 1);
program.setFloatUniform("uScaleX", bitmapScaleX);
program.setFloatUniform("uScaleY", bitmapScaleY);
program.setFloatsUniform("uTexTransform", transformMatrix);
program.bindAttributesAndUniforms();
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /* first= */ 0, /* count= */ 4);
......
......@@ -42,7 +42,7 @@ import androidx.media3.exoplayer.drm.HttpMediaDrmCallback;
import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.exoplayer.source.ProgressiveMediaSource;
import androidx.media3.exoplayer.util.EventLogger;
import androidx.media3.ui.StyledPlayerView;
import androidx.media3.ui.PlayerView;
import java.util.UUID;
/**
......@@ -61,7 +61,7 @@ public final class MainActivity extends Activity {
private static final String DRM_SCHEME_EXTRA = "drm_scheme";
private static final String DRM_LICENSE_URL_EXTRA = "drm_license_url";
@Nullable private StyledPlayerView playerView;
@Nullable private PlayerView playerView;
@Nullable private VideoProcessingGLSurfaceView videoProcessingGLSurfaceView;
@Nullable private ExoPlayer player;
......@@ -181,7 +181,7 @@ public final class MainActivity extends Activity {
Assertions.checkNotNull(this.videoProcessingGLSurfaceView);
videoProcessingGLSurfaceView.setPlayer(player);
Assertions.checkNotNull(playerView).setPlayer(player);
player.addAnalyticsListener(new EventLogger(/* trackSelector= */ null));
player.addAnalyticsListener(new EventLogger());
this.player = player;
}
......
......@@ -20,7 +20,7 @@
android:layout_height="match_parent"
android:keepScreenOn="true">
<androidx.media3.ui.StyledPlayerView
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
......
......@@ -76,6 +76,7 @@
<data android:scheme="content"/>
<data android:scheme="asset"/>
<data android:scheme="file"/>
<data android:scheme="ssai"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.media3.demo.main.action.VIEW_LIST"/>
......
......@@ -35,31 +35,31 @@
"name": "HD (cenc)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
},
{
"name": "UHD (cenc)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_uhd.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
},
{
"name": "HD (cbcs)",
"uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
},
{
"name": "UHD (cbcs)",
"uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs_uhd.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
},
{
"name": "Secure -> Clear -> Secure (cenc)",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/widevine/tears_enc_clear_enc.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test",
"drm_session_for_clear_content": true
}
]
......@@ -71,25 +71,25 @@
"name": "HD (cenc, full-sample)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
},
{
"name": "UHD (cenc, full-sample)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears_uhd.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
},
{
"name": "HD (cenc, sub-sample)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/subsample/24fps/tears/tears.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
},
{
"name": "UHD (cenc, sub-sample)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/subsample/24fps/tears/tears_uhd.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
}
]
},
......@@ -100,13 +100,13 @@
"name": "HD (cenc)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/hevc/tears/tears.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
},
{
"name": "UHD (cenc)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/hevc/tears/tears_uhd.mpd",
"drm_scheme": "widevine",
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
"drm_license_uri": "https://proxy.uat.widevine.com/proxy?video_id=2015_tears&provider=widevine_test"
}
]
},
......@@ -388,6 +388,98 @@
]
},
{
"name": "IMA DAI streams",
"samples": [
{
"name": "HLS VOD: Demo (skippable pre/post), single ads [30 s]",
"uri": "ssai://dai.google.com/?contentSourceId=2483977&videoId=ima-vod-skippable-test&format=2&adsId=1"
},
{
"name": "HLS VOD: Tears of Steel (pre/mid/mid/mid/post), single ads [10s]",
"uri": "ssai://dai.google.com/?contentSourceId=2528370&videoId=tears-of-steel&format=2&adsId=1"
},
{
"name": "HLS Live: Big Buck Bunny (mid), 3 ads each [10 s]",
"uri": "ssai://dai.google.com/?assetKey=sN_IYUG8STe1ZzhIIE_ksA&format=2&adsId=3"
},
{
"name": "DASH VOD: Tears of Steel (11 periods, pre/mid/post), 2/5/2 ads [5/10s]",
"uri": "ssai://dai.google.com/?contentSourceId=2559737&videoId=tos-dash&format=0&adsId=1"
},
{
"name": "Playlist: No ads - HLS VOD: Demo (skippable pre/post) - No ads",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "ssai://dai.google.com/?contentSourceId=2483977&videoId=ima-vod-skippable-test&format=2&adsId=1"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
},
{
"name": "Playlist: No ads - HLS VOD: Tears of steel (pre/mid/mid/mid/post) - No ads",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "ssai://dai.google.com/?contentSourceId=2528370&videoId=tears-of-steel&format=2&adsId=1"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
},
{
"name": "Playlist: No ads - HLS Live: Big Buck Bunny (mid) - No ads",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "ssai://dai.google.com/?assetKey=sN_IYUG8STe1ZzhIIE_ksA&format=2&adsId=3"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
},
{
"name": "Playlist: No ads - DASH VOD: Tears of Steel (11 periods, pre/mid/post) - No ads",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "ssai://dai.google.com/?contentSourceId=2559737&videoId=tos-dash&format=0&adsId=1"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
},
{
"name": "Playlist: Client-side Ads - DASH VOD: Tears of Steel (11 periods, pre/mid/post) - No ads",
"playlist": [
{
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
"ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&cmsid=496&vid=short_onecue&correlator="
},
{
"uri": "ssai://dai.google.com/?contentSourceId=2559737&videoId=tos-dash&format=0&adsId=1"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
}
]
},
{
"name": "Playlists",
"samples": [
{
......
......@@ -16,7 +16,6 @@
package androidx.media3.demo.main;
import android.content.Context;
import androidx.media3.common.util.Log;
import androidx.media3.database.DatabaseProvider;
import androidx.media3.database.StandaloneDatabaseProvider;
import androidx.media3.datasource.DataSource;
......@@ -31,12 +30,9 @@ import androidx.media3.datasource.cronet.CronetDataSource;
import androidx.media3.datasource.cronet.CronetUtil;
import androidx.media3.exoplayer.DefaultRenderersFactory;
import androidx.media3.exoplayer.RenderersFactory;
import androidx.media3.exoplayer.offline.ActionFileUpgradeUtil;
import androidx.media3.exoplayer.offline.DefaultDownloadIndex;
import androidx.media3.exoplayer.offline.DownloadManager;
import androidx.media3.exoplayer.offline.DownloadNotificationHelper;
import java.io.File;
import java.io.IOException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
......@@ -60,8 +56,6 @@ public final class DemoUtil {
private static final boolean USE_CRONET_FOR_NETWORKING = true;
private static final String TAG = "DemoUtil";
private static final String DOWNLOAD_ACTION_FILE = "actions";
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
private static DataSource.@MonotonicNonNull Factory dataSourceFactory;
......@@ -155,14 +149,6 @@ public final class DemoUtil {
private static synchronized void ensureDownloadManagerInitialized(Context context) {
if (downloadManager == null) {
DefaultDownloadIndex downloadIndex = new DefaultDownloadIndex(getDatabaseProvider(context));
upgradeActionFile(
context, DOWNLOAD_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ false);
upgradeActionFile(
context,
DOWNLOAD_TRACKER_ACTION_FILE,
downloadIndex,
/* addNewDownloadsAsCompleted= */ true);
downloadManager =
new DownloadManager(
context,
......@@ -175,23 +161,6 @@ public final class DemoUtil {
}
}
private static synchronized void upgradeActionFile(
Context context,
String fileName,
DefaultDownloadIndex downloadIndex,
boolean addNewDownloadsAsCompleted) {
try {
ActionFileUpgradeUtil.upgradeAndDelete(
new File(getDownloadDirectory(context), fileName),
/* downloadIdProvider= */ null,
downloadIndex,
/* deleteOnFailure= */ true,
addNewDownloadsAsCompleted);
} catch (IOException e) {
Log.e(TAG, "Failed to upgrade action file: " + fileName, e);
}
}
private static synchronized DatabaseProvider getDatabaseProvider(Context context) {
if (databaseProvider == null) {
databaseProvider = new StandaloneDatabaseProvider(context);
......
......@@ -21,7 +21,7 @@
android:layout_height="match_parent"
android:keepScreenOn="true">
<androidx.media3.ui.StyledPlayerView android:id="@+id/player_view"
<androidx.media3.ui.PlayerView android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:show_shuffle_button="true"
......
......@@ -61,9 +61,9 @@ dependencies {
implementation 'androidx.appcompat:appcompat:' + androidxAppCompatVersion
implementation 'androidx.multidex:multidex:' + androidxMultidexVersion
implementation 'com.google.android.material:material:' + androidxMaterialVersion
implementation project(modulePrefix + ':lib-exoplayer')
implementation project(modulePrefix + ':lib-exoplayer-dash')
implementation project(modulePrefix + ':lib-exoplayer-hls')
implementation project(modulePrefix + ':lib-ui')
implementation project(modulePrefix + ':lib-session')
implementation project(modulePrefix + 'lib-exoplayer')
implementation project(modulePrefix + 'lib-exoplayer-dash')
implementation project(modulePrefix + 'lib-exoplayer-hls')
implementation project(modulePrefix + 'lib-ui')
implementation project(modulePrefix + 'lib-session')
}
......@@ -21,15 +21,14 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Media3Demo">
<activity
android:name=".MainActivity"
android:exported="true">
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
......@@ -37,18 +36,16 @@
</activity>
<activity
android:name=".PlayerActivity"
android:exported="true">
</activity>
android:name=".PlayerActivity"
android:exported="true"/>
<activity
android:name=".PlayableFolderActivity"
android:exported="true">
</activity>
android:name=".PlayableFolderActivity"
android:exported="true"/>
<service
android:name=".PlaybackService"
android:exported="true">
android:name=".PlaybackService"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
......
......@@ -2,7 +2,7 @@
"media": [
{
"id": "video_01",
"title": "Future Scenerio",
"title": "Future Scenario",
"album": "Mango Open Movie project",
"artist": "Blender Foundation",
"genre": "Video",
......@@ -488,4 +488,4 @@
"site": "https://www.youtube.com/audiolibrary/music"
}
]
}
\ No newline at end of file
}
......@@ -34,7 +34,7 @@ import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player
import androidx.media3.session.MediaController
import androidx.media3.session.SessionToken
import androidx.media3.ui.StyledPlayerView
import androidx.media3.ui.PlayerView
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.MoreExecutors
......@@ -43,7 +43,7 @@ class PlayerActivity : AppCompatActivity() {
private val controller: MediaController?
get() = if (controllerFuture.isDone) controllerFuture.get() else null
private lateinit var playerView: StyledPlayerView
private lateinit var playerView: PlayerView
private lateinit var mediaList: ListView
private lateinit var mediaListAdapter: PlayingMediaItemArrayAdapter
private val subItemMediaList: MutableList<MediaItem> = mutableListOf()
......
......@@ -26,7 +26,7 @@
android:layout_height="300dp"
android:layout_width="match_parent"
>
<androidx.media3.ui.StyledPlayerView
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
......
......@@ -34,7 +34,7 @@
android:layout_width="50dp"
android:layout_height="match_parent"
android:id="@+id/add_button"
android:background="@android:drawable/ic_input_add"
android:background="@drawable/baseline_playlist_add_white_48"
/>
</LinearLayout>
......@@ -35,7 +35,7 @@
android:layout_width="50dp"
android:layout_height="match_parent"
android:id="@+id/delete_button"
android:background="@android:drawable/ic_menu_close_clear_cancel"
android:background="@drawable/baseline_playlist_remove_white_48"
/>
</LinearLayout>
......@@ -22,12 +22,14 @@
<uses-sdk/>
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/application_name"
android:exported="true">
<activity android:name=".MainActivity">
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/application_name"
android:exported="true">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
......
# Transformer demo
This app demonstrates how to use the [Transformer][] API to modify videos, for
example by removing audio or video.
See the [demos README](../README.md) for instructions on how to build and run
this demo.
[Transformer]: https://exoplayer.dev/transforming-media.html
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
apply from: '../../constants.gradle'
apply plugin: 'com.android.application'
android {
compileSdkVersion project.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
versionName project.ext.releaseVersion
versionCode project.ext.releaseVersionCode
minSdkVersion 21
targetSdkVersion project.ext.appTargetSdkVersion
multiDexEnabled true
}
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt')
signingConfig signingConfigs.debug
}
}
lintOptions {
// This demo app isn't indexed and doesn't have translations.
disable 'GoogleAppIndexingWarning','MissingTranslation'
}
}
dependencies {
implementation 'androidx.core:core:' + androidxCoreVersion
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
implementation 'androidx.appcompat:appcompat:' + androidxAppCompatVersion
implementation 'androidx.constraintlayout:constraintlayout:' + androidxConstraintLayoutVersion
implementation 'androidx.multidex:multidex:' + androidxMultidexVersion
implementation 'com.google.android.material:material:' + androidxMaterialVersion
implementation project(modulePrefix + 'lib-exoplayer')
implementation project(modulePrefix + 'lib-transformer')
implementation project(modulePrefix + 'lib-ui')
}
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2021 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="androidx.media3.demo.transformer">
<uses-sdk />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat"
android:taskAffinity=""
tools:targetApi="29">
<activity android:name=".ConfigurationActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:launchMode="singleTop"
android:label="@string/app_name"
android:exported="true"
android:theme="@style/Theme.MaterialComponents.DayNight.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.media3.demo.transformer.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:scheme="content"/>
<data android:scheme="asset"/>
<data android:scheme="file"/>
</intent-filter>
</activity>
<activity android:name=".TransformerActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:launchMode="singleTop"
android:label="@string/app_name"
android:exported="true"
android:theme="@style/Theme.MaterialComponents.DayNight.NoActionBar"/>
</application>
</manifest>
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package androidx.media3.demo.transformer;
import androidx.media3.common.util.NonNullApi;
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2021 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.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ConfigurationActivity">
<TextView
android:id="@+id/configuration_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:text="@string/configuration"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/choose_file_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:text="@string/choose_file_title"
app:layout_constraintTop_toBottomOf="@+id/configuration_text_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/chosen_file_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:textSize="12sp"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/choose_file_button" />
<androidx.core.widget.NestedScrollView
android:layout_width="fill_parent"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/chosen_file_text_view"
app:layout_constraintBottom_toTopOf="@+id/transform_button">
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"
android:layout_marginTop="32dp"
android:measureWithLargestChild="true"
android:paddingLeft="24dp"
android:paddingRight="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:text="@string/remove_audio" />
<CheckBox
android:id="@+id/remove_audio_checkbox"
android:layout_gravity="right"/>
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:text="@string/remove_video"/>
<CheckBox
android:id="@+id/remove_video_checkbox"
android:layout_gravity="right" />
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:text="@string/flatten_for_slow_motion"/>
<CheckBox
android:id="@+id/flatten_for_slow_motion_checkbox"
android:layout_gravity="right" />
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:id="@+id/audio_mime_text_view"
android:text="@string/audio_mime"/>
<Spinner
android:id="@+id/audio_mime_spinner"
android:layout_gravity="right|center_vertical"
android:gravity="right" />
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:id="@+id/video_mime_text_view"
android:text="@string/video_mime"/>
<Spinner
android:id="@+id/video_mime_spinner"
android:layout_gravity="right|center_vertical"
android:gravity="right" />
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:id="@+id/resolution_height_text_view"
android:text="@string/resolution_height"/>
<Spinner
android:id="@+id/resolution_height_spinner"
android:layout_gravity="right|center_vertical"
android:gravity="right" />
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:id="@+id/translate"
android:text="@string/translate"/>
<Spinner
android:id="@+id/translate_spinner"
android:layout_gravity="right|center_vertical"
android:gravity="right" />
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:id="@+id/scale"
android:text="@string/scale"/>
<Spinner
android:id="@+id/scale_spinner"
android:layout_gravity="right|center_vertical"
android:gravity="right" />
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:id="@+id/rotate"
android:text="@string/rotate"/>
<Spinner
android:id="@+id/rotate_spinner"
android:layout_gravity="right|center_vertical"
android:gravity="right" />
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:text="@string/enable_fallback" />
<CheckBox
android:id="@+id/enable_fallback_checkbox"
android:layout_gravity="right"
android:checked="true"/>
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center_vertical" >
<TextView
android:id="@+id/hdr_editing"
android:text="@string/hdr_editing" />
<CheckBox
android:id="@+id/hdr_editing_checkbox"
android:layout_gravity="right" />
</TableRow>
</TableLayout>
</androidx.core.widget.NestedScrollView>
<Button
android:id="@+id/transform_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="28dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:text="@string/transform"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 The Android Open Source Project
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2021 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.
......@@ -13,11 +13,14 @@
~ 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.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="default_notification_channel_name" msgid="7213672915724563695">"এতিয়া প্লে’ হৈ আছে"</string>
<string name="play_button_content_description" msgid="963503759453979404">"প্লে’ কৰক"</string>
<string name="media3_controls_pause_description" msgid="3510124037191104584">"পজ কৰক"</string>
</resources>
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:gravity="left|center_vertical"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:textIsSelectable="false" />
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2021 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:keepScreenOn="true"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:layout_margin="8dp"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:cardCornerRadius="4dp"
app:cardElevation="2dp"
android:gravity="center_vertical" >
<TextView
android:id="@+id/information_text_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="8dp" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="16dp"
app:cardCornerRadius="4dp"
app:cardElevation="2dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/debug_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="10sp"
tools:ignore="SmallSp"/>
<LinearLayout
android:id="@+id/progress_view_group"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:padding="8dp"
android:orientation="vertical">
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress_indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_gravity="center" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="@string/debug_preview" />
<androidx.media3.ui.AspectRatioFrameLayout
android:id="@+id/debug_aspect_ratio_frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/debug_preview_not_available" />
</androidx.media3.ui.AspectRatioFrameLayout>
</LinearLayout>
</FrameLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2021 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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" translatable="false">Transformer Demo</string>
<string name="configuration" translatable="false">Configuration</string>
<string name="choose_file_title" translatable="false">Choose file</string>
<string name="remove_audio" translatable="false">Remove audio</string>
<string name="remove_video" translatable="false">Remove video</string>
<string name="flatten_for_slow_motion" translatable="false">Flatten for slow motion</string>
<string name="audio_mime" translatable="false">Output audio MIME type</string>
<string name="video_mime" translatable="false">Output video MIME type</string>
<string name="resolution_height" translatable="false">Output video resolution</string>
<string name="translate" translatable="false">Translate video</string>
<string name="scale" translatable="false">Scale video</string>
<string name="rotate" translatable="false">Rotate video (degrees)</string>
<string name="enable_fallback" translatable="false">Enable fallback</string>
<string name="transform" translatable="false">Transform</string>
<string name="hdr_editing" translatable="false">[Experimental] HDR editing</string>
<string name="debug_preview" translatable="false">Debug preview:</string>
<string name="debug_preview_not_available" translatable="false">No debug preview available.</string>
<string name="transformation_started" translatable="false">Transformation started</string>
<string name="transformation_timer" translatable="false">Transformation started %d seconds ago.</string>
<string name="transformation_completed" translatable="false">Transformation completed in %d seconds.</string>
<string name="transformation_error" translatable="false">Transformation error</string>
</resources>
......@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https://services.gradle.org/distributions/gradle-7.0.2-all.zip
distributionUrl=https://services.gradle.org/distributions/gradle-7.3.3-all.zip
......@@ -14,7 +14,7 @@
apply from: "$gradle.ext.androidxMediaSettingsDir/common_library_config.gradle"
dependencies {
api 'com.google.android.gms:play-services-cast-framework:20.1.0'
api 'com.google.android.gms:play-services-cast-framework:21.0.1'
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
implementation project(modulePrefix + 'lib-common')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
......
......@@ -137,7 +137,7 @@ public final class CastPlayer extends BasePlayer {
private final SeekResultCallback seekResultCallback;
// Listeners and notification.
private final ListenerSet<Player.EventListener> listeners;
private final ListenerSet<Listener> listeners;
@Nullable private SessionAvailabilityListener sessionAvailabilityListener;
// Internal state.
......@@ -150,7 +150,7 @@ public final class CastPlayer extends BasePlayer {
private TrackSelectionArray currentTrackSelection;
private TracksInfo currentTracksInfo;
private Commands availableCommands;
@Player.State private int playbackState;
private @Player.State int playbackState;
private int currentWindowIndex;
private long lastReportedPositionMs;
private int pendingSeekCount;
......@@ -280,41 +280,11 @@ public final class CastPlayer extends BasePlayer {
@Override
public void addListener(Listener listener) {
EventListener eventListener = listener;
addListener(eventListener);
}
/**
* Registers a listener to receive events from the player.
*
* <p>The listener's methods will be called on the thread associated with {@link
* #getApplicationLooper()}.
*
* @param listener The listener to register.
* @deprecated Use {@link #addListener(Listener)} and {@link #removeListener(Listener)} instead.
*/
@Deprecated
@SuppressWarnings("deprecation")
public void addListener(EventListener listener) {
listeners.add(listener);
}
@Override
public void removeListener(Listener listener) {
EventListener eventListener = listener;
removeListener(eventListener);
}
/**
* Unregister a listener registered through {@link #addListener(EventListener)}. The listener will
* no longer receive events from the player.
*
* @param listener The listener to unregister.
* @deprecated Use {@link #addListener(Listener)} and {@link #removeListener(Listener)} instead.
*/
@Deprecated
@SuppressWarnings("deprecation")
public void removeListener(EventListener listener) {
listeners.remove(listener);
}
......@@ -387,14 +357,12 @@ public final class CastPlayer extends BasePlayer {
}
@Override
@Player.State
public int getPlaybackState() {
public @Player.State int getPlaybackState() {
return playbackState;
}
@Override
@PlaybackSuppressionReason
public int getPlaybackSuppressionReason() {
public @PlaybackSuppressionReason int getPlaybackSuppressionReason() {
return Player.PLAYBACK_SUPPRESSION_REASON_NONE;
}
......@@ -475,7 +443,7 @@ public final class CastPlayer extends BasePlayer {
}
updateAvailableCommandsAndNotifyIfChanged();
} else if (pendingSeekCount == 0) {
listeners.queueEvent(/* eventFlag= */ C.INDEX_UNSET, EventListener::onSeekProcessed);
listeners.queueEvent(/* eventFlag= */ C.INDEX_UNSET, Listener::onSeekProcessed);
}
listeners.flushEvents();
}
......@@ -559,7 +527,7 @@ public final class CastPlayer extends BasePlayer {
setRepeatModeAndNotifyIfChanged(repeatMode);
listeners.flushEvents();
PendingResult<MediaChannelResult> pendingResult =
remoteMediaClient.queueSetRepeatMode(getCastRepeatMode(repeatMode), /* jsonObject= */ null);
remoteMediaClient.queueSetRepeatMode(getCastRepeatMode(repeatMode), /* customData= */ null);
this.repeatMode.pendingResultCallback =
new ResultCallback<MediaChannelResult>() {
@Override
......@@ -574,8 +542,7 @@ public final class CastPlayer extends BasePlayer {
}
@Override
@RepeatMode
public int getRepeatMode() {
public @RepeatMode int getRepeatMode() {
return repeatMode.value;
}
......@@ -1070,7 +1037,8 @@ public final class CastPlayer extends BasePlayer {
int[] trackSupport = new int[] {supported ? C.FORMAT_HANDLED : C.FORMAT_UNSUPPORTED_TYPE};
final boolean[] trackSelected = new boolean[] {selected};
trackGroupInfos[i] =
new TracksInfo.TrackGroupInfo(trackGroups[i], trackSupport, trackType, trackSelected);
new TracksInfo.TrackGroupInfo(
trackGroups[i], /* adaptiveSupported= */ false, trackSupport, trackSelected);
}
TrackGroupArray newTrackGroups = new TrackGroupArray(trackGroups);
TrackSelectionArray newTrackSelections = new TrackSelectionArray(trackSelections);
......@@ -1292,8 +1260,7 @@ public final class CastPlayer extends BasePlayer {
* Retrieves the repeat mode from {@code remoteMediaClient} and maps it into a {@link
* Player.RepeatMode}.
*/
@RepeatMode
private static int fetchRepeatMode(RemoteMediaClient remoteMediaClient) {
private static @RepeatMode int fetchRepeatMode(RemoteMediaClient remoteMediaClient) {
MediaStatus mediaStatus = remoteMediaClient.getMediaStatus();
if (mediaStatus == null) {
// No media session active, yet.
......@@ -1481,7 +1448,7 @@ public final class CastPlayer extends BasePlayer {
currentWindowIndex = pendingSeekWindowIndex;
pendingSeekWindowIndex = C.INDEX_UNSET;
pendingSeekPositionMs = C.TIME_UNSET;
listeners.sendEvent(/* eventFlag= */ C.INDEX_UNSET, EventListener::onSeekProcessed);
listeners.sendEvent(/* eventFlag= */ C.INDEX_UNSET, Listener::onSeekProcessed);
}
}
}
......
......@@ -31,7 +31,9 @@ import androidx.media3.common.util.Assertions;
private final TrackGroup trackGroup;
/** @param trackGroup The {@link TrackGroup} from which the first track will only be selected. */
/**
* @param trackGroup The {@link TrackGroup} from which the first track will only be selected.
*/
public CastTrackSelection(TrackGroup trackGroup) {
this.trackGroup = trackGroup;
}
......
......@@ -19,11 +19,13 @@ import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi;
import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.MediaMetadata;
import com.google.android.gms.cast.MediaQueueItem;
import com.google.android.gms.common.images.WebImage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.UUID;
......@@ -47,10 +49,43 @@ public final class DefaultMediaItemConverter implements MediaItemConverter {
@Override
public MediaItem toMediaItem(MediaQueueItem mediaQueueItem) {
// `item` came from `toMediaQueueItem()` so the custom JSON data must be set.
MediaInfo mediaInfo = mediaQueueItem.getMedia();
@Nullable MediaInfo mediaInfo = mediaQueueItem.getMedia();
Assertions.checkNotNull(mediaInfo);
return getMediaItem(Assertions.checkNotNull(mediaInfo.getCustomData()));
androidx.media3.common.MediaMetadata.Builder metadataBuilder =
new androidx.media3.common.MediaMetadata.Builder();
@Nullable MediaMetadata metadata = mediaInfo.getMetadata();
if (metadata != null) {
if (metadata.containsKey(MediaMetadata.KEY_TITLE)) {
metadataBuilder.setTitle(metadata.getString(MediaMetadata.KEY_TITLE));
}
if (metadata.containsKey(MediaMetadata.KEY_SUBTITLE)) {
metadataBuilder.setSubtitle(metadata.getString(MediaMetadata.KEY_SUBTITLE));
}
if (metadata.containsKey(MediaMetadata.KEY_ARTIST)) {
metadataBuilder.setArtist(metadata.getString(MediaMetadata.KEY_ARTIST));
}
if (metadata.containsKey(MediaMetadata.KEY_ALBUM_ARTIST)) {
metadataBuilder.setAlbumArtist(metadata.getString(MediaMetadata.KEY_ALBUM_ARTIST));
}
if (metadata.containsKey(MediaMetadata.KEY_ALBUM_TITLE)) {
metadataBuilder.setArtist(metadata.getString(MediaMetadata.KEY_ALBUM_TITLE));
}
if (!metadata.getImages().isEmpty()) {
metadataBuilder.setArtworkUri(metadata.getImages().get(0).getUrl());
}
if (metadata.containsKey(MediaMetadata.KEY_COMPOSER)) {
metadataBuilder.setComposer(metadata.getString(MediaMetadata.KEY_COMPOSER));
}
if (metadata.containsKey(MediaMetadata.KEY_DISC_NUMBER)) {
metadataBuilder.setDiscNumber(metadata.getInt(MediaMetadata.KEY_DISC_NUMBER));
}
if (metadata.containsKey(MediaMetadata.KEY_TRACK_NUMBER)) {
metadataBuilder.setTrackNumber(metadata.getInt(MediaMetadata.KEY_TRACK_NUMBER));
}
}
// `mediaQueueItem` came from `toMediaQueueItem()` so the custom JSON data must be set.
return getMediaItem(
Assertions.checkNotNull(mediaInfo.getCustomData()), metadataBuilder.build());
}
@Override
......@@ -59,10 +94,41 @@ public final class DefaultMediaItemConverter implements MediaItemConverter {
if (mediaItem.localConfiguration.mimeType == null) {
throw new IllegalArgumentException("The item must specify its mimeType");
}
MediaMetadata metadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
MediaMetadata metadata =
new MediaMetadata(
MimeTypes.isAudio(mediaItem.localConfiguration.mimeType)
? MediaMetadata.MEDIA_TYPE_MUSIC_TRACK
: MediaMetadata.MEDIA_TYPE_MOVIE);
if (mediaItem.mediaMetadata.title != null) {
metadata.putString(MediaMetadata.KEY_TITLE, mediaItem.mediaMetadata.title.toString());
}
if (mediaItem.mediaMetadata.subtitle != null) {
metadata.putString(MediaMetadata.KEY_SUBTITLE, mediaItem.mediaMetadata.subtitle.toString());
}
if (mediaItem.mediaMetadata.artist != null) {
metadata.putString(MediaMetadata.KEY_ARTIST, mediaItem.mediaMetadata.artist.toString());
}
if (mediaItem.mediaMetadata.albumArtist != null) {
metadata.putString(
MediaMetadata.KEY_ALBUM_ARTIST, mediaItem.mediaMetadata.albumArtist.toString());
}
if (mediaItem.mediaMetadata.albumTitle != null) {
metadata.putString(
MediaMetadata.KEY_ALBUM_TITLE, mediaItem.mediaMetadata.albumTitle.toString());
}
if (mediaItem.mediaMetadata.artworkUri != null) {
metadata.addImage(new WebImage(mediaItem.mediaMetadata.artworkUri));
}
if (mediaItem.mediaMetadata.composer != null) {
metadata.putString(MediaMetadata.KEY_COMPOSER, mediaItem.mediaMetadata.composer.toString());
}
if (mediaItem.mediaMetadata.discNumber != null) {
metadata.putInt(MediaMetadata.KEY_DISC_NUMBER, mediaItem.mediaMetadata.discNumber);
}
if (mediaItem.mediaMetadata.trackNumber != null) {
metadata.putInt(MediaMetadata.KEY_TRACK_NUMBER, mediaItem.mediaMetadata.trackNumber);
}
MediaInfo mediaInfo =
new MediaInfo.Builder(mediaItem.localConfiguration.uri.toString())
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
......@@ -75,19 +141,15 @@ public final class DefaultMediaItemConverter implements MediaItemConverter {
// Deserialization.
private static MediaItem getMediaItem(JSONObject customData) {
private static MediaItem getMediaItem(
JSONObject customData, androidx.media3.common.MediaMetadata mediaMetadata) {
try {
JSONObject mediaItemJson = customData.getJSONObject(KEY_MEDIA_ITEM);
MediaItem.Builder builder = new MediaItem.Builder();
builder.setUri(Uri.parse(mediaItemJson.getString(KEY_URI)));
builder.setMediaId(mediaItemJson.getString(KEY_MEDIA_ID));
if (mediaItemJson.has(KEY_TITLE)) {
androidx.media3.common.MediaMetadata mediaMetadata =
new androidx.media3.common.MediaMetadata.Builder()
.setTitle(mediaItemJson.getString(KEY_TITLE))
.build();
builder.setMediaMetadata(mediaMetadata);
}
MediaItem.Builder builder =
new MediaItem.Builder()
.setUri(Uri.parse(mediaItemJson.getString(KEY_URI)))
.setMediaId(mediaItemJson.getString(KEY_MEDIA_ID))
.setMediaMetadata(mediaMetadata);
if (mediaItemJson.has(KEY_MIME_TYPE)) {
builder.setMimeType(mediaItemJson.getString(KEY_MIME_TYPE));
}
......
......@@ -17,9 +17,10 @@ apply from: "$gradle.ext.androidxMediaSettingsDir/common_library_config.gradle"
// the Gradle properties of each library are populated and we can automatically
// check if a 'releaseArtifactId' exists.
rootProject.allprojects.forEach {
if ((it.name.contains('lib-') || it.name.contains('test-'))
if ((it.name.startsWith(modulePrefix.replace(':', '') + 'lib-')
|| it.name.startsWith(modulePrefix.replace(':', '') + 'test-'))
&& !it.name.endsWith('-common')) {
evaluationDependsOn(modulePrefix + it.name)
evaluationDependsOn(':' + it.name)
}
}
// copybara:media3-only
......@@ -36,8 +37,9 @@ dependencies {
// List all released targets as constraints. This ensures they are all
// resolved to the same version.
rootProject.allprojects.forEach {
if (it.hasProperty('releaseArtifactId')) {
implementation project(modulePrefix + it.name)
if (it.hasProperty('releaseArtifactId')
&& it.releaseArtifactId.startsWith('media3-')) {
implementation project(':' + it.name)
}
}
}
......
......@@ -37,6 +37,8 @@ public final class AdOverlayInfo {
* The purpose of the overlay. One of {@link #PURPOSE_CONTROLS}, {@link #PURPOSE_CLOSE_AD}, {@link
* #PURPOSE_OTHER} or {@link #PURPOSE_NOT_VISIBLE}.
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
......@@ -95,14 +97,18 @@ public final class AdOverlayInfo {
/** An optional, detailed reason that the overlay view is needed. */
@Nullable public final String reasonDetail;
/** @deprecated Use {@link Builder} instead. */
/**
* @deprecated Use {@link Builder} instead.
*/
@UnstableApi
@Deprecated
public AdOverlayInfo(View view, @Purpose int purpose) {
this(view, purpose, /* detailedReason= */ null);
}
/** @deprecated Use {@link Builder} instead. */
/**
* @deprecated Use {@link Builder} instead.
*/
@UnstableApi
@Deprecated
public AdOverlayInfo(View view, @Purpose int purpose, @Nullable String detailedReason) {
......
......@@ -18,6 +18,11 @@ package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkState;
import static java.lang.Math.max;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.net.Uri;
import android.os.Bundle;
......@@ -30,6 +35,7 @@ import androidx.media3.common.util.Util;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import org.checkerframework.checker.nullness.compatqual.NullableType;
......@@ -61,7 +67,7 @@ public final class AdPlaybackState implements Bundleable {
/** The URI of each ad in the ad group. */
public final @NullableType Uri[] uris;
/** The state of each ad in the ad group. */
@AdState public final int[] states;
public final @AdState int[] states;
/** The durations of each ad in the ad group, in microseconds. */
public final long[] durationsUs;
/**
......@@ -343,6 +349,7 @@ public final class AdPlaybackState implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_TIME_US,
FIELD_COUNT,
......@@ -414,8 +421,11 @@ public final class AdPlaybackState implements Bundleable {
* #AD_STATE_AVAILABLE}, {@link #AD_STATE_SKIPPED}, {@link #AD_STATE_PLAYED} or {@link
* #AD_STATE_ERROR}.
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
AD_STATE_UNAVAILABLE,
AD_STATE_AVAILABLE,
......@@ -913,6 +923,7 @@ public final class AdPlaybackState implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_AD_GROUPS,
FIELD_AD_RESUME_POSITION_US,
......
......@@ -15,6 +15,8 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.DoNotInline;
import androidx.annotation.IntDef;
......@@ -25,6 +27,7 @@ import androidx.media3.common.util.Util;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
/**
......@@ -40,6 +43,11 @@ import java.lang.reflect.Method;
*/
public final class AudioAttributes implements Bundleable {
/**
* The default audio attributes, where the content type is {@link C#CONTENT_TYPE_UNKNOWN}, usage
* is {@link C#USAGE_MEDIA}, capture policy is {@link C#ALLOW_CAPTURE_BY_ALL} and no flags are
* set.
*/
public static final AudioAttributes DEFAULT = new Builder().build();
/** Builder for {@link AudioAttributes}. */
......@@ -65,19 +73,19 @@ public final class AudioAttributes implements Bundleable {
spatializationBehavior = C.SPATIALIZATION_BEHAVIOR_AUTO;
}
/** @see android.media.AudioAttributes.Builder#setContentType(int) */
/** See {@link android.media.AudioAttributes.Builder#setContentType(int)} */
public Builder setContentType(@C.AudioContentType int contentType) {
this.contentType = contentType;
return this;
}
/** @see android.media.AudioAttributes.Builder#setFlags(int) */
/** See {@link android.media.AudioAttributes.Builder#setFlags(int)} */
public Builder setFlags(@C.AudioFlags int flags) {
this.flags = flags;
return this;
}
/** @see android.media.AudioAttributes.Builder#setUsage(int) */
/** See {@link android.media.AudioAttributes.Builder#setUsage(int)} */
public Builder setUsage(@C.AudioUsage int usage) {
this.usage = usage;
return this;
......@@ -91,7 +99,7 @@ public final class AudioAttributes implements Bundleable {
// TODO[b/190759307] Update javadoc to link to AudioAttributes.Builder#setSpatializationBehavior
// once compile SDK target is set to 32.
/** See AudioAttributes.Builder#setSpatializationBehavior(int). */
/** See {@code android.media.AudioAttributes.Builder.setSpatializationBehavior(int)}. */
public Builder setSpatializationBehavior(@C.SpatializationBehavior int spatializationBehavior) {
this.spatializationBehavior = spatializationBehavior;
return this;
......@@ -104,10 +112,15 @@ public final class AudioAttributes implements Bundleable {
}
}
/** The {@link C.AudioContentType}. */
public final @C.AudioContentType int contentType;
/** The {@link C.AudioFlags}. */
public final @C.AudioFlags int flags;
/** The {@link C.AudioUsage}. */
public final @C.AudioUsage int usage;
/** The {@link C.AudioAllowedCapturePolicy}. */
public final @C.AudioAllowedCapturePolicy int allowedCapturePolicy;
/** The {@link C.SpatializationBehavior}. */
public final @C.SpatializationBehavior int spatializationBehavior;
@Nullable private android.media.AudioAttributes audioAttributesV21;
......@@ -180,6 +193,7 @@ public final class AudioAttributes implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_CONTENT_TYPE,
FIELD_FLAGS,
......
......@@ -384,8 +384,7 @@ public abstract class BasePlayer implements Player {
: timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs();
}
@RepeatMode
private int getRepeatModeForNavigation() {
private @RepeatMode int getRepeatModeForNavigation() {
@RepeatMode int repeatMode = getRepeatMode();
return repeatMode == REPEAT_MODE_ONE ? REPEAT_MODE_OFF : repeatMode;
}
......
......@@ -15,6 +15,8 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
......@@ -22,6 +24,7 @@ import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import org.checkerframework.dataflow.qual.Pure;
......@@ -35,8 +38,7 @@ public final class ColorInfo implements Bundleable {
* made.
*/
@Pure
@C.ColorSpace
public static int isoColorPrimariesToColorSpace(int isoColorPrimaries) {
public static @C.ColorSpace int isoColorPrimariesToColorSpace(int isoColorPrimaries) {
switch (isoColorPrimaries) {
case 1:
return C.COLOR_SPACE_BT709;
......@@ -58,8 +60,8 @@ public final class ColorInfo implements Bundleable {
* mapping can be made.
*/
@Pure
@C.ColorTransfer
public static int isoTransferCharacteristicsToColorTransfer(int isoTransferCharacteristics) {
public static @C.ColorTransfer int isoTransferCharacteristicsToColorTransfer(
int isoTransferCharacteristics) {
switch (isoTransferCharacteristics) {
case 1: // BT.709.
case 6: // SMPTE 170M.
......@@ -78,20 +80,20 @@ public final class ColorInfo implements Bundleable {
* The color space of the video. Valid values are {@link C#COLOR_SPACE_BT601}, {@link
* C#COLOR_SPACE_BT709}, {@link C#COLOR_SPACE_BT2020} or {@link Format#NO_VALUE} if unknown.
*/
@C.ColorSpace public final int colorSpace;
public final @C.ColorSpace int colorSpace;
/**
* The color range of the video. Valid values are {@link C#COLOR_RANGE_LIMITED}, {@link
* C#COLOR_RANGE_FULL} or {@link Format#NO_VALUE} if unknown.
*/
@C.ColorRange public final int colorRange;
public final @C.ColorRange int colorRange;
/**
* The color transfer characteristics of the video. Valid values are {@link C#COLOR_TRANSFER_HLG},
* {@link C#COLOR_TRANSFER_ST2084}, {@link C#COLOR_TRANSFER_SDR} or {@link Format#NO_VALUE} if
* unknown.
*/
@C.ColorTransfer public final int colorTransfer;
public final @C.ColorTransfer int colorTransfer;
/** HdrStaticInfo as defined in CTA-861.3, or null if none specified. */
@Nullable public final byte[] hdrStaticInfo;
......@@ -163,6 +165,7 @@ public final class ColorInfo implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_COLOR_SPACE,
FIELD_COLOR_RANGE,
......
......@@ -15,12 +15,13 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
......@@ -31,7 +32,7 @@ public final class DeviceInfo implements Bundleable {
/** Types of playback. One of {@link #PLAYBACK_TYPE_LOCAL} or {@link #PLAYBACK_TYPE_REMOTE}. */
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_USE})
@Target(TYPE_USE)
@IntDef({
PLAYBACK_TYPE_LOCAL,
PLAYBACK_TYPE_REMOTE,
......@@ -88,6 +89,7 @@ public final class DeviceInfo implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_PLAYBACK_TYPE, FIELD_MIN_VOLUME, FIELD_MAX_VOLUME})
private @interface FieldNumber {}
......
......@@ -52,7 +52,8 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
* @param mediaData DRM session acquisition data obtained from the media.
* @return A {@link DrmInitData} obtained from merging a media manifest and a media stream.
*/
public static @Nullable DrmInitData createSessionCreationData(
@Nullable
public static DrmInitData createSessionCreationData(
@Nullable DrmInitData manifestData, @Nullable DrmInitData mediaData) {
ArrayList<SchemeData> result = new ArrayList<>();
String schemeType = null;
......@@ -91,7 +92,9 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
/** Number of {@link SchemeData}s. */
public final int schemeDataCount;
/** @param schemeDatas Scheme initialization data for possibly multiple DRM schemes. */
/**
* @param schemeDatas Scheme initialization data for possibly multiple DRM schemes.
*/
public DrmInitData(List<SchemeData> schemeDatas) {
this(null, false, schemeDatas.toArray(new SchemeData[0]));
}
......@@ -104,7 +107,9 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
this(schemeType, false, schemeDatas.toArray(new SchemeData[0]));
}
/** @param schemeDatas Scheme initialization data for possibly multiple DRM schemes. */
/**
* @param schemeDatas Scheme initialization data for possibly multiple DRM schemes.
*/
public DrmInitData(SchemeData... schemeDatas) {
this(null, schemeDatas);
}
......
......@@ -16,6 +16,7 @@
package androidx.media3.common;
import static androidx.media3.common.MimeTypes.normalizeMimeType;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.net.Uri;
import androidx.annotation.IntDef;
......@@ -25,6 +26,7 @@ import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
import java.util.Map;
......@@ -39,6 +41,7 @@ public final class FileTypes {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
UNKNOWN, AC3, AC4, ADTS, AMR, FLAC, FLV, MATROSKA, MP3, MP4, OGG, PS, TS, WAV, WEBVTT, JPEG
})
......@@ -111,8 +114,8 @@ public final class FileTypes {
private FileTypes() {}
/** Returns the {@link Type} corresponding to the response headers provided. */
@FileTypes.Type
public static int inferFileTypeFromResponseHeaders(Map<String, List<String>> responseHeaders) {
public static @FileTypes.Type int inferFileTypeFromResponseHeaders(
Map<String, List<String>> responseHeaders) {
@Nullable List<String> contentTypes = responseHeaders.get(HEADER_CONTENT_TYPE);
@Nullable
String mimeType = contentTypes == null || contentTypes.isEmpty() ? null : contentTypes.get(0);
......@@ -124,8 +127,7 @@ public final class FileTypes {
*
* <p>Returns {@link #UNKNOWN} if the mime type is {@code null}.
*/
@FileTypes.Type
public static int inferFileTypeFromMimeType(@Nullable String mimeType) {
public static @FileTypes.Type int inferFileTypeFromMimeType(@Nullable String mimeType) {
if (mimeType == null) {
return FileTypes.UNKNOWN;
}
......@@ -175,8 +177,7 @@ public final class FileTypes {
}
/** Returns the {@link Type} corresponding to the {@link Uri} provided. */
@FileTypes.Type
public static int inferFileTypeFromUri(Uri uri) {
public static @FileTypes.Type int inferFileTypeFromUri(Uri uri) {
@Nullable String filename = uri.getLastPathSegment();
if (filename == null) {
return FileTypes.UNKNOWN;
......
......@@ -15,6 +15,8 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
......@@ -25,6 +27,7 @@ import com.google.common.base.Joiner;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -153,14 +156,14 @@ public final class Format implements Bundleable {
private int rotationDegrees;
private float pixelWidthHeightRatio;
@Nullable private byte[] projectionData;
@C.StereoMode private int stereoMode;
private @C.StereoMode int stereoMode;
@Nullable private ColorInfo colorInfo;
// Audio specific.
private int channelCount;
private int sampleRate;
@C.PcmEncoding private int pcmEncoding;
private @C.PcmEncoding int pcmEncoding;
private int encoderDelay;
private int encoderPadding;
......@@ -170,7 +173,7 @@ public final class Format implements Bundleable {
// Provided by the source.
@C.CryptoType private int cryptoType;
private @C.CryptoType int cryptoType;
/** Creates a new instance with default values. */
public Builder() {
......@@ -724,7 +727,7 @@ public final class Format implements Bundleable {
* modes are {@link C#STEREO_MODE_MONO}, {@link C#STEREO_MODE_TOP_BOTTOM}, {@link
* C#STEREO_MODE_LEFT_RIGHT}, {@link C#STEREO_MODE_STEREO_MESH}.
*/
@UnstableApi @C.StereoMode public final int stereoMode;
@UnstableApi public final @C.StereoMode int stereoMode;
/** The color metadata associated with the video, or null if not applicable. */
@UnstableApi @Nullable public final ColorInfo colorInfo;
......@@ -735,7 +738,7 @@ public final class Format implements Bundleable {
/** The audio sampling rate in Hz, or {@link #NO_VALUE} if unknown or not applicable. */
public final int sampleRate;
/** The {@link C.PcmEncoding} for PCM audio. Set to {@link #NO_VALUE} for other media types. */
@UnstableApi @C.PcmEncoding public final int pcmEncoding;
@UnstableApi public final @C.PcmEncoding int pcmEncoding;
/**
* The number of frames to trim from the start of the decoded audio stream, or 0 if not
* applicable.
......@@ -759,14 +762,16 @@ public final class Format implements Bundleable {
* {@link #drmInitData} is non-null, but may be {@link C#CRYPTO_TYPE_UNSUPPORTED} to indicate that
* the samples are encrypted using an unsupported crypto type.
*/
@UnstableApi @C.CryptoType public final int cryptoType;
@UnstableApi public final @C.CryptoType int cryptoType;
// Lazily initialized hashcode.
private int hashCode;
// Video.
/** @deprecated Use {@link Format.Builder}. */
/**
* @deprecated Use {@link Format.Builder}.
*/
@UnstableApi
@Deprecated
public static Format createVideoSampleFormat(
......@@ -795,7 +800,9 @@ public final class Format implements Bundleable {
.build();
}
/** @deprecated Use {@link Format.Builder}. */
/**
* @deprecated Use {@link Format.Builder}.
*/
@UnstableApi
@Deprecated
public static Format createVideoSampleFormat(
......@@ -830,7 +837,9 @@ public final class Format implements Bundleable {
// Audio.
/** @deprecated Use {@link Format.Builder}. */
/**
* @deprecated Use {@link Format.Builder}.
*/
@UnstableApi
@Deprecated
public static Format createAudioSampleFormat(
......@@ -861,7 +870,9 @@ public final class Format implements Bundleable {
.build();
}
/** @deprecated Use {@link Format.Builder}. */
/**
* @deprecated Use {@link Format.Builder}.
*/
@UnstableApi
@Deprecated
public static Format createAudioSampleFormat(
......@@ -896,7 +907,9 @@ public final class Format implements Bundleable {
// Generic.
/** @deprecated Use {@link Format.Builder}. */
/**
* @deprecated Use {@link Format.Builder}.
*/
@UnstableApi
@Deprecated
public static Format createContainerFormat(
......@@ -923,7 +936,9 @@ public final class Format implements Bundleable {
.build();
}
/** @deprecated Use {@link Format.Builder}. */
/**
* @deprecated Use {@link Format.Builder}.
*/
@UnstableApi
@Deprecated
public static Format createSampleFormat(@Nullable String id, @Nullable String sampleMimeType) {
......@@ -983,28 +998,36 @@ public final class Format implements Bundleable {
return new Builder(this);
}
/** @deprecated Use {@link #buildUpon()} and {@link Builder#setMaxInputSize(int)}. */
/**
* @deprecated Use {@link #buildUpon()} and {@link Builder#setMaxInputSize(int)}.
*/
@UnstableApi
@Deprecated
public Format copyWithMaxInputSize(int maxInputSize) {
return buildUpon().setMaxInputSize(maxInputSize).build();
}
/** @deprecated Use {@link #buildUpon()} and {@link Builder#setSubsampleOffsetUs(long)}. */
/**
* @deprecated Use {@link #buildUpon()} and {@link Builder#setSubsampleOffsetUs(long)}.
*/
@UnstableApi
@Deprecated
public Format copyWithSubsampleOffsetUs(long subsampleOffsetUs) {
return buildUpon().setSubsampleOffsetUs(subsampleOffsetUs).build();
}
/** @deprecated Use {@link #buildUpon()} and {@link Builder#setLabel(String)} . */
/**
* @deprecated Use {@link #buildUpon()} and {@link Builder#setLabel(String)} .
*/
@UnstableApi
@Deprecated
public Format copyWithLabel(@Nullable String label) {
return buildUpon().setLabel(label).build();
}
/** @deprecated Use {@link #withManifestFormatInfo(Format)}. */
/**
* @deprecated Use {@link #withManifestFormatInfo(Format)}.
*/
@UnstableApi
@Deprecated
public Format copyWithManifestFormatInfo(Format manifestFormat) {
......@@ -1089,21 +1112,27 @@ public final class Format implements Bundleable {
return buildUpon().setEncoderDelay(encoderDelay).setEncoderPadding(encoderPadding).build();
}
/** @deprecated Use {@link #buildUpon()} and {@link Builder#setFrameRate(float)}. */
/**
* @deprecated Use {@link #buildUpon()} and {@link Builder#setFrameRate(float)}.
*/
@UnstableApi
@Deprecated
public Format copyWithFrameRate(float frameRate) {
return buildUpon().setFrameRate(frameRate).build();
}
/** @deprecated Use {@link #buildUpon()} and {@link Builder#setDrmInitData(DrmInitData)}. */
/**
* @deprecated Use {@link #buildUpon()} and {@link Builder#setDrmInitData(DrmInitData)}.
*/
@UnstableApi
@Deprecated
public Format copyWithDrmInitData(@Nullable DrmInitData drmInitData) {
return buildUpon().setDrmInitData(drmInitData).build();
}
/** @deprecated Use {@link #buildUpon()} and {@link Builder#setMetadata(Metadata)}. */
/**
* @deprecated Use {@link #buildUpon()} and {@link Builder#setMetadata(Metadata)}.
*/
@UnstableApi
@Deprecated
public Format copyWithMetadata(@Nullable Metadata metadata) {
......@@ -1417,6 +1446,7 @@ public final class Format implements Bundleable {
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_ID,
FIELD_LABEL,
......
......@@ -16,6 +16,7 @@
package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.IntDef;
......@@ -25,6 +26,7 @@ import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A rating expressed as "heart" or "no heart". It can be used to indicate whether the content is a
......@@ -77,10 +79,11 @@ public final class HeartRating extends Rating {
// Bundleable implementation.
@RatingType private static final int TYPE = RATING_TYPE_HEART;
private static final @RatingType int TYPE = RATING_TYPE_HEART;
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE, FIELD_RATED, FIELD_IS_HEART})
private @interface FieldNumber {}
......@@ -102,7 +105,7 @@ public final class HeartRating extends Rating {
private static HeartRating fromBundle(Bundle bundle) {
checkArgument(
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET)
== TYPE);
boolean isRated = bundle.getBoolean(keyForField(FIELD_RATED), /* defaultValue= */ false);
return isRated
......
......@@ -17,6 +17,7 @@ package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.net.Uri;
import android.os.Bundle;
......@@ -31,6 +32,7 @@ import com.google.common.collect.ImmutableMap;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -710,7 +712,9 @@ public final class MediaItem implements Bundleable {
/** The UUID of the protection scheme. */
public final UUID scheme;
/** @deprecated Use {@link #scheme} instead. */
/**
* @deprecated Use {@link #scheme} instead.
*/
@UnstableApi @Deprecated public final UUID uuid;
/**
......@@ -719,7 +723,9 @@ public final class MediaItem implements Bundleable {
*/
@Nullable public final Uri licenseUri;
/** @deprecated Use {@link #licenseRequestHeaders} instead. */
/**
* @deprecated Use {@link #licenseRequestHeaders} instead.
*/
@UnstableApi @Deprecated public final ImmutableMap<String, String> requestHeaders;
/** The headers to attach to requests sent to the DRM license server. */
......@@ -740,7 +746,9 @@ public final class MediaItem implements Bundleable {
*/
public final boolean forceDefaultLicenseUri;
/** @deprecated Use {@link #forcedSessionTrackTypes}. */
/**
* @deprecated Use {@link #forcedSessionTrackTypes}.
*/
@UnstableApi @Deprecated public final ImmutableList<@C.TrackType Integer> sessionForClearTypes;
/**
* The types of tracks for which to always use a DRM session even if the content is unencrypted.
......@@ -927,7 +935,9 @@ public final class MediaItem implements Bundleable {
/** Optional subtitles to be sideloaded. */
public final ImmutableList<SubtitleConfiguration> subtitleConfigurations;
/** @deprecated Use {@link #subtitleConfigurations} instead. */
/**
* @deprecated Use {@link #subtitleConfigurations} instead.
*/
@UnstableApi @Deprecated public final List<Subtitle> subtitles;
/**
......@@ -996,7 +1006,9 @@ public final class MediaItem implements Bundleable {
}
}
/** @deprecated Use {@link LocalConfiguration}. */
/**
* @deprecated Use {@link LocalConfiguration}.
*/
@UnstableApi
@Deprecated
public static final class PlaybackProperties extends LocalConfiguration {
......@@ -1158,7 +1170,9 @@ public final class MediaItem implements Bundleable {
builder.maxPlaybackSpeed);
}
/** @deprecated Use {@link Builder} instead. */
/**
* @deprecated Use {@link Builder} instead.
*/
@UnstableApi
@Deprecated
public LiveConfiguration(
......@@ -1210,6 +1224,7 @@ public final class MediaItem implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_TARGET_OFFSET_MS,
FIELD_MIN_OFFSET_MS,
......@@ -1424,19 +1439,25 @@ public final class MediaItem implements Bundleable {
}
}
/** @deprecated Use {@link MediaItem.SubtitleConfiguration} instead */
/**
* @deprecated Use {@link MediaItem.SubtitleConfiguration} instead
*/
@UnstableApi
@Deprecated
public static final class Subtitle extends SubtitleConfiguration {
/** @deprecated Use {@link Builder} instead. */
/**
* @deprecated Use {@link Builder} instead.
*/
@UnstableApi
@Deprecated
public Subtitle(Uri uri, String mimeType, @Nullable String language) {
this(uri, mimeType, language, /* selectionFlags= */ 0);
}
/** @deprecated Use {@link Builder} instead. */
/**
* @deprecated Use {@link Builder} instead.
*/
@UnstableApi
@Deprecated
public Subtitle(
......@@ -1444,7 +1465,9 @@ public final class MediaItem implements Bundleable {
this(uri, mimeType, language, selectionFlags, /* roleFlags= */ 0, /* label= */ null);
}
/** @deprecated Use {@link Builder} instead. */
/**
* @deprecated Use {@link Builder} instead.
*/
@UnstableApi
@Deprecated
public Subtitle(
......@@ -1547,7 +1570,9 @@ public final class MediaItem implements Bundleable {
return buildClippingProperties();
}
/** @deprecated Use {@link #build()} instead. */
/**
* @deprecated Use {@link #build()} instead.
*/
@UnstableApi
@Deprecated
public ClippingProperties buildClippingProperties() {
......@@ -1625,6 +1650,7 @@ public final class MediaItem implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_START_POSITION_MS,
FIELD_END_POSITION_MS,
......@@ -1676,7 +1702,9 @@ public final class MediaItem implements Bundleable {
}
}
/** @deprecated Use {@link ClippingConfiguration} instead. */
/**
* @deprecated Use {@link ClippingConfiguration} instead.
*/
@UnstableApi
@Deprecated
public static final class ClippingProperties extends ClippingConfiguration {
......@@ -1705,7 +1733,9 @@ public final class MediaItem implements Bundleable {
* boundaries.
*/
@Nullable public final LocalConfiguration localConfiguration;
/** @deprecated Use {@link #localConfiguration} instead. */
/**
* @deprecated Use {@link #localConfiguration} instead.
*/
@UnstableApi @Deprecated @Nullable public final PlaybackProperties playbackProperties;
/** The live playback configuration. */
......@@ -1716,7 +1746,9 @@ public final class MediaItem implements Bundleable {
/** The clipping properties. */
public final ClippingConfiguration clippingConfiguration;
/** @deprecated Use {@link #clippingConfiguration} instead. */
/**
* @deprecated Use {@link #clippingConfiguration} instead.
*/
@UnstableApi @Deprecated public final ClippingProperties clippingProperties;
// Using PlaybackProperties and ClippingProperties until they're deleted.
......@@ -1773,6 +1805,7 @@ public final class MediaItem implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_MEDIA_ID,
FIELD_LIVE_CONFIGURATION,
......@@ -1839,7 +1872,7 @@ public final class MediaItem implements Bundleable {
return new MediaItem(
mediaId,
clippingConfiguration,
/* playbackProperties= */ null,
/* localConfiguration= */ null,
liveConfiguration,
mediaMetadata);
}
......
......@@ -56,11 +56,11 @@ public final class MediaMetadata implements Bundleable {
@Nullable private Rating userRating;
@Nullable private Rating overallRating;
@Nullable private byte[] artworkData;
@Nullable @PictureType private Integer artworkDataType;
@Nullable private @PictureType Integer artworkDataType;
@Nullable private Uri artworkUri;
@Nullable private Integer trackNumber;
@Nullable private Integer totalTrackCount;
@Nullable @FolderType private Integer folderType;
@Nullable private @FolderType Integer folderType;
@Nullable private Boolean isPlayable;
@Nullable private Integer recordingYear;
@Nullable private Integer recordingMonth;
......@@ -248,7 +248,9 @@ public final class MediaMetadata implements Bundleable {
return this;
}
/** @deprecated Use {@link #setRecordingYear(Integer)} instead. */
/**
* @deprecated Use {@link #setRecordingYear(Integer)} instead.
*/
@UnstableApi
@Deprecated
public Builder setYear(@Nullable Integer year) {
......@@ -521,6 +523,8 @@ public final class MediaMetadata implements Bundleable {
* href="https://www.bluetooth.com/specifications/specs/a-v-remote-control-profile-1-6-2/">Bluetooth
* AVRCP 1.6.2</a>).
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
......@@ -559,6 +563,8 @@ public final class MediaMetadata implements Bundleable {
* <p>Values sourced from the ID3 v2.4 specification (See section 4.14 of
* https://id3.org/id3v2.4.0-frames).
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
......@@ -650,7 +656,9 @@ public final class MediaMetadata implements Bundleable {
@Nullable public final @FolderType Integer folderType;
/** Optional boolean for media playability. */
@Nullable public final Boolean isPlayable;
/** @deprecated Use {@link #recordingYear} instead. */
/**
* @deprecated Use {@link #recordingYear} instead.
*/
@UnstableApi @Deprecated @Nullable public final Integer year;
/** Optional year of the recording date. */
@Nullable public final Integer recordingYear;
......@@ -829,6 +837,7 @@ public final class MediaMetadata implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_TITLE,
FIELD_ARTIST,
......
......@@ -62,12 +62,16 @@ public final class Metadata implements Parcelable {
private final Entry[] entries;
/** @param entries The metadata entries. */
/**
* @param entries The metadata entries.
*/
public Metadata(Entry... entries) {
this.entries = entries;
}
/** @param entries The metadata entries. */
/**
* @param entries The metadata entries.
*/
public Metadata(List<? extends Entry> entries) {
this.entries = entries.toArray(new Entry[0]);
}
......
......@@ -552,8 +552,7 @@ public final class MimeTypes {
* @return The corresponding {@link C.Encoding}, or {@link C#ENCODING_INVALID}.
*/
@UnstableApi
@C.Encoding
public static int getEncoding(String mimeType, @Nullable String codec) {
public static @C.Encoding int getEncoding(String mimeType, @Nullable String codec) {
switch (mimeType) {
case MimeTypes.AUDIO_MPEG:
return C.ENCODING_MP3;
......@@ -728,8 +727,7 @@ public final class MimeTypes {
}
/** Returns the encoding for {@link #audioObjectTypeIndication}. */
@C.Encoding
public int getEncoding() {
public @C.Encoding int getEncoding() {
// See AUDIO_OBJECT_TYPE_AAC_* constants in AacUtil.
switch (audioObjectTypeIndication) {
case 2:
......
......@@ -16,6 +16,7 @@
package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.FloatRange;
......@@ -26,6 +27,7 @@ import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** A rating expressed as a percentage. */
public final class PercentageRating extends Rating {
......@@ -75,10 +77,11 @@ public final class PercentageRating extends Rating {
// Bundleable implementation.
@RatingType private static final int TYPE = RATING_TYPE_PERCENTAGE;
private static final @RatingType int TYPE = RATING_TYPE_PERCENTAGE;
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE, FIELD_PERCENT})
private @interface FieldNumber {}
......@@ -98,7 +101,7 @@ public final class PercentageRating extends Rating {
private static PercentageRating fromBundle(Bundle bundle) {
checkArgument(
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET)
== TYPE);
float percent = bundle.getFloat(keyForField(FIELD_PERCENT), /* defaultValue= */ RATING_UNSET);
return percent == RATING_UNSET ? new PercentageRating() : new PercentageRating(percent);
......
......@@ -46,6 +46,8 @@ public class PlaybackException extends Exception implements Bundleable {
* <p>This list of errors may be extended in future versions, and {@link Player} implementations
* may define custom error codes.
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
......@@ -408,6 +410,7 @@ public class PlaybackException extends Exception implements Bundleable {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef(
open = true,
value = {
......
......@@ -15,6 +15,8 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.CheckResult;
import androidx.annotation.FloatRange;
......@@ -26,6 +28,7 @@ import androidx.media3.common.util.Util;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Parameters that apply to playback, including speed setting. */
public final class PlaybackParameters implements Bundleable {
......@@ -121,6 +124,7 @@ public final class PlaybackParameters implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_SPEED, FIELD_PITCH})
private @interface FieldNumber {}
......
......@@ -15,12 +15,15 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A rating for media content. The style of a rating can be one of {@link HeartRating}, {@link
......@@ -41,8 +44,9 @@ public abstract class Rating implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
RATING_TYPE_DEFAULT,
RATING_TYPE_UNSET,
RATING_TYPE_HEART,
RATING_TYPE_PERCENTAGE,
RATING_TYPE_STAR,
......@@ -50,7 +54,7 @@ public abstract class Rating implements Bundleable {
})
/* package */ @interface RatingType {}
/* package */ static final int RATING_TYPE_DEFAULT = -1;
/* package */ static final int RATING_TYPE_UNSET = -1;
/* package */ static final int RATING_TYPE_HEART = 0;
/* package */ static final int RATING_TYPE_PERCENTAGE = 1;
/* package */ static final int RATING_TYPE_STAR = 2;
......@@ -58,6 +62,7 @@ public abstract class Rating implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE})
private @interface FieldNumber {}
......@@ -69,7 +74,7 @@ public abstract class Rating implements Bundleable {
private static Rating fromBundle(Bundle bundle) {
@RatingType
int ratingType =
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT);
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET);
switch (ratingType) {
case RATING_TYPE_HEART:
return HeartRating.CREATOR.fromBundle(bundle);
......@@ -79,8 +84,9 @@ public abstract class Rating implements Bundleable {
return StarRating.CREATOR.fromBundle(bundle);
case RATING_TYPE_THUMB:
return ThumbRating.CREATOR.fromBundle(bundle);
case RATING_TYPE_UNSET:
default:
throw new IllegalArgumentException("Encountered unknown rating type: " + ratingType);
throw new IllegalArgumentException("Unknown RatingType: " + ratingType);
}
}
......
......@@ -16,6 +16,7 @@
package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.FloatRange;
......@@ -27,6 +28,7 @@ import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** A rating expressed as a fractional number of stars. */
public final class StarRating extends Rating {
......@@ -101,11 +103,12 @@ public final class StarRating extends Rating {
// Bundleable implementation.
@RatingType private static final int TYPE = RATING_TYPE_STAR;
private static final @RatingType int TYPE = RATING_TYPE_STAR;
private static final int MAX_STARS_DEFAULT = 5;
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE, FIELD_MAX_STARS, FIELD_STAR_RATING})
private @interface FieldNumber {}
......@@ -127,7 +130,7 @@ public final class StarRating extends Rating {
private static StarRating fromBundle(Bundle bundle) {
checkArgument(
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET)
== TYPE);
int maxStars =
bundle.getInt(keyForField(FIELD_MAX_STARS), /* defaultValue= */ MAX_STARS_DEFAULT);
......
......@@ -44,7 +44,9 @@ public final class StreamKey implements Comparable<StreamKey>, Parcelable {
/** The stream index. */
public final int streamIndex;
/** @deprecated Use {@link #streamIndex}. */
/**
* @deprecated Use {@link #streamIndex}.
*/
@Deprecated public final int trackIndex;
/**
......
......@@ -16,6 +16,7 @@
package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.IntDef;
......@@ -25,6 +26,7 @@ import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** A rating expressed as "thumbs up" or "thumbs down". */
public final class ThumbRating extends Rating {
......@@ -74,10 +76,11 @@ public final class ThumbRating extends Rating {
// Bundleable implementation.
@RatingType private static final int TYPE = RATING_TYPE_THUMB;
private static final @RatingType int TYPE = RATING_TYPE_THUMB;
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE, FIELD_RATED, FIELD_IS_THUMBS_UP})
private @interface FieldNumber {}
......@@ -99,7 +102,7 @@ public final class ThumbRating extends Rating {
private static ThumbRating fromBundle(Bundle bundle) {
checkArgument(
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET)
== TYPE);
boolean rated = bundle.getBoolean(keyForField(FIELD_RATED), /* defaultValue= */ false);
return rated
......
......@@ -20,6 +20,7 @@ import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkState;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.net.Uri;
import android.os.Bundle;
......@@ -37,6 +38,7 @@ import com.google.errorprone.annotations.InlineMe;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
......@@ -167,7 +169,9 @@ public abstract class Timeline implements Bundleable {
*/
public Object uid;
/** @deprecated Use {@link #mediaItem} instead. */
/**
* @deprecated Use {@link #mediaItem} instead.
*/
@UnstableApi @Deprecated @Nullable public Object tag;
/** The {@link MediaItem} associated to the window. Not necessarily unique. */
......@@ -210,7 +214,9 @@ public abstract class Timeline implements Bundleable {
/** Whether this window may change when the timeline is updated. */
public boolean isDynamic;
/** @deprecated Use {@link #isLive()} instead. */
/**
* @deprecated Use {@link #isLive()} instead.
*/
@UnstableApi @Deprecated public boolean isLive;
/**
......@@ -414,6 +420,7 @@ public abstract class Timeline implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_MEDIA_ITEM,
FIELD_PRESENTATION_START_TIME_MS,
......@@ -903,6 +910,7 @@ public abstract class Timeline implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_WINDOW_INDEX,
FIELD_DURATION_US,
......@@ -1174,7 +1182,9 @@ public abstract class Timeline implements Bundleable {
== C.INDEX_UNSET;
}
/** @deprecated Use {@link #getPeriodPositionUs(Window, Period, int, long)} instead. */
/**
* @deprecated Use {@link #getPeriodPositionUs(Window, Period, int, long)} instead.
*/
@UnstableApi
@Deprecated
@InlineMe(replacement = "this.getPeriodPositionUs(window, period, windowIndex, windowPositionUs)")
......@@ -1182,7 +1192,9 @@ public abstract class Timeline implements Bundleable {
Window window, Period period, int windowIndex, long windowPositionUs) {
return getPeriodPositionUs(window, period, windowIndex, windowPositionUs);
}
/** @deprecated Use {@link #getPeriodPositionUs(Window, Period, int, long, long)} instead. */
/**
* @deprecated Use {@link #getPeriodPositionUs(Window, Period, int, long, long)} instead.
*/
@UnstableApi
@Deprecated
@Nullable
......@@ -1362,6 +1374,7 @@ public abstract class Timeline implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_WINDOWS,
FIELD_PERIODS,
......
......@@ -16,6 +16,7 @@
package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.CheckResult;
......@@ -29,6 +30,7 @@ import com.google.common.collect.Lists;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
......@@ -41,6 +43,8 @@ public final class TrackGroup implements Bundleable {
public final int length;
/** An identifier for the track group. */
public final String id;
/** The type of tracks in the group. */
public final @C.TrackType int type;
private final Format[] formats;
......@@ -69,6 +73,11 @@ public final class TrackGroup implements Bundleable {
this.id = id;
this.formats = formats;
this.length = formats.length;
@C.TrackType int type = MimeTypes.getTrackType(formats[0].sampleMimeType);
if (type == C.TRACK_TYPE_UNKNOWN) {
type = MimeTypes.getTrackType(formats[0].containerMimeType);
}
this.type = type;
verifyCorrectness();
}
......@@ -132,13 +141,14 @@ public final class TrackGroup implements Bundleable {
return false;
}
TrackGroup other = (TrackGroup) obj;
return length == other.length && id.equals(other.id) && Arrays.equals(formats, other.formats);
return id.equals(other.id) && Arrays.equals(formats, other.formats);
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_FORMATS, FIELD_ID})
private @interface FieldNumber {}
......@@ -204,8 +214,7 @@ public final class TrackGroup implements Bundleable {
return language == null || language.equals(C.LANGUAGE_UNDETERMINED) ? "" : language;
}
@C.RoleFlags
private static int normalizeRoleFlags(@C.RoleFlags int roleFlags) {
private static @C.RoleFlags int normalizeRoleFlags(@C.RoleFlags int roleFlags) {
// Treat trick-play and non-trick-play formats as compatible.
return roleFlags | C.ROLE_FLAG_TRICK_PLAY;
}
......
......@@ -15,6 +15,8 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
......@@ -25,6 +27,7 @@ import com.google.common.collect.ImmutableList;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
/** An immutable array of {@link TrackGroup}s. */
......@@ -105,6 +108,7 @@ public final class TrackGroupArray implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_TRACK_GROUPS,
})
......
......@@ -15,10 +15,11 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import androidx.annotation.IntDef;
import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
......@@ -38,7 +39,7 @@ public interface TrackSelection {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_USE})
@Target(TYPE_USE)
@IntDef(
open = true,
value = {TYPE_UNSET})
......
......@@ -32,7 +32,9 @@ public final class TrackSelectionArray {
// Lazily initialized hashcode.
private int hashCode;
/** @param trackSelections The selections. Must not be null, but may contain null elements. */
/**
* @param trackSelections The selections. Must not be null, but may contain null elements.
*/
public TrackSelectionArray(@NullableType TrackSelection... trackSelections) {
this.trackSelections = trackSelections;
this.length = trackSelections.length;
......
/*
* Copyright (C) 2021 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 androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.util.Collections.max;
import static java.util.Collections.min;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
* Forces the selection of {@link #trackIndices} for a {@link TrackGroup}.
*
* <p>If multiple tracks in {@link #trackGroup} are overridden, as many as possible will be selected
* depending on the player capabilities.
*
* <p>If {@link #trackIndices} is empty, no tracks from {@link #trackGroup} will be played. This is
* similar to {@link TrackSelectionParameters#disabledTrackTypes}, except it will only affect the
* playback of the associated {@link TrackGroup}. For example, if the only {@link
* C#TRACK_TYPE_VIDEO} {@link TrackGroup} is associated with no tracks, no video will play until the
* next video starts.
*/
public final class TrackSelectionOverride implements Bundleable {
/** The {@link TrackGroup} whose {@link #trackIndices} are forced to be selected. */
public final TrackGroup trackGroup;
/** The indices of tracks in a {@link TrackGroup} to be selected. */
public final ImmutableList<Integer> trackIndices;
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
FIELD_TRACK_GROUP,
FIELD_TRACKS,
})
private @interface FieldNumber {}
private static final int FIELD_TRACK_GROUP = 0;
private static final int FIELD_TRACKS = 1;
/** Constructs an instance to force all tracks in {@code trackGroup} to be selected. */
public TrackSelectionOverride(TrackGroup trackGroup) {
this.trackGroup = trackGroup;
ImmutableList.Builder<Integer> builder = new ImmutableList.Builder<>();
for (int i = 0; i < trackGroup.length; i++) {
builder.add(i);
}
this.trackIndices = builder.build();
}
/**
* Constructs an instance to force {@code trackIndices} in {@code trackGroup} to be selected.
*
* @param trackGroup The {@link TrackGroup} for which to override the track selection.
* @param trackIndices The indices of the tracks in the {@link TrackGroup} to select.
*/
public TrackSelectionOverride(TrackGroup trackGroup, List<Integer> trackIndices) {
if (!trackIndices.isEmpty()) {
if (min(trackIndices) < 0 || max(trackIndices) >= trackGroup.length) {
throw new IndexOutOfBoundsException();
}
}
this.trackGroup = trackGroup;
this.trackIndices = ImmutableList.copyOf(trackIndices);
}
/** Returns the {@link C.TrackType} of the overridden track group. */
public @C.TrackType int getTrackType() {
return trackGroup.type;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
TrackSelectionOverride that = (TrackSelectionOverride) obj;
return trackGroup.equals(that.trackGroup) && trackIndices.equals(that.trackIndices);
}
@Override
public int hashCode() {
return trackGroup.hashCode() + 31 * trackIndices.hashCode();
}
// Bundleable implementation
@UnstableApi
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putBundle(keyForField(FIELD_TRACK_GROUP), trackGroup.toBundle());
bundle.putIntArray(keyForField(FIELD_TRACKS), Ints.toArray(trackIndices));
return bundle;
}
/** Object that can restore {@code TrackSelectionOverride} from a {@link Bundle}. */
@UnstableApi
public static final Creator<TrackSelectionOverride> CREATOR =
bundle -> {
@Nullable Bundle trackGroupBundle = bundle.getBundle(keyForField(FIELD_TRACK_GROUP));
checkNotNull(trackGroupBundle); // Mandatory as there are no reasonable defaults.
TrackGroup trackGroup = TrackGroup.CREATOR.fromBundle(trackGroupBundle);
@Nullable int[] tracks = bundle.getIntArray(keyForField(FIELD_TRACKS));
if (tracks == null) {
return new TrackSelectionOverride(trackGroup);
}
return new TrackSelectionOverride(trackGroup, Ints.asList(tracks));
};
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}
......@@ -16,7 +16,8 @@
package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.BundleableUtil.fromNullableBundle;
import static androidx.media3.common.util.BundleableUtil.fromBundleNullableList;
import static androidx.media3.common.util.BundleableUtil.toBundleArrayList;
import static com.google.common.base.MoreObjects.firstNonNull;
import android.content.Context;
......@@ -30,11 +31,15 @@ import androidx.annotation.RequiresApi;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
......@@ -93,7 +98,7 @@ public class TrackSelectionParameters implements Bundleable {
// General
private boolean forceLowestBitrate;
private boolean forceHighestSupportedBitrate;
private TrackSelectionOverrides trackSelectionOverrides;
private HashMap<TrackGroup, TrackSelectionOverride> overrides;
private ImmutableSet<@C.TrackType Integer> disabledTrackTypes;
/**
......@@ -126,7 +131,7 @@ public class TrackSelectionParameters implements Bundleable {
// General
forceLowestBitrate = false;
forceHighestSupportedBitrate = false;
trackSelectionOverrides = TrackSelectionOverrides.EMPTY;
overrides = new HashMap<>();
disabledTrackTypes = ImmutableSet.of();
}
......@@ -234,11 +239,16 @@ public class TrackSelectionParameters implements Bundleable {
bundle.getBoolean(
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE),
DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate);
trackSelectionOverrides =
fromNullableBundle(
TrackSelectionOverrides.CREATOR,
bundle.getBundle(keyForField(FIELD_SELECTION_OVERRIDE_KEYS)),
TrackSelectionOverrides.EMPTY);
overrides = new HashMap<>();
List<TrackSelectionOverride> overrideList =
fromBundleNullableList(
TrackSelectionOverride.CREATOR,
bundle.getParcelableArrayList(keyForField(FIELD_SELECTION_OVERRIDES)),
ImmutableList.of());
for (int i = 0; i < overrideList.size(); i++) {
TrackSelectionOverride override = overrideList.get(i);
overrides.put(override.trackGroup, override);
}
disabledTrackTypes =
ImmutableSet.copyOf(
Ints.asList(
......@@ -252,7 +262,7 @@ public class TrackSelectionParameters implements Bundleable {
"preferredAudioLanguages",
"preferredAudioMimeTypes",
"preferredTextLanguages",
"trackSelectionOverrides",
"overrides",
"disabledTrackTypes",
})
private void init(@UnknownInitialization Builder this, TrackSelectionParameters parameters) {
......@@ -283,8 +293,8 @@ public class TrackSelectionParameters implements Bundleable {
// General
forceLowestBitrate = parameters.forceLowestBitrate;
forceHighestSupportedBitrate = parameters.forceHighestSupportedBitrate;
trackSelectionOverrides = parameters.trackSelectionOverrides;
disabledTrackTypes = parameters.disabledTrackTypes;
overrides = new HashMap<>(parameters.overrides);
}
/** Overrides the value of the builder with the value of {@link TrackSelectionParameters}. */
......@@ -644,14 +654,42 @@ public class TrackSelectionParameters implements Bundleable {
return this;
}
/** Adds an override for the provided {@link TrackGroup}. */
public Builder addOverride(TrackSelectionOverride override) {
overrides.put(override.trackGroup, override);
return this;
}
/** Removes the override associated with the provided {@link TrackGroup} if present. */
public Builder clearOverride(TrackGroup trackGroup) {
overrides.remove(trackGroup);
return this;
}
/** Set the override for the type of the provided {@link TrackGroup}. */
public Builder setOverrideForType(TrackSelectionOverride override) {
clearOverridesOfType(override.getTrackType());
overrides.put(override.trackGroup, override);
return this;
}
/**
* Sets the selection overrides.
*
* @param trackSelectionOverrides The track selection overrides.
* @return This builder.
* Remove any override associated with {@link TrackGroup TrackGroups} of type {@code trackType}.
*/
public Builder setTrackSelectionOverrides(TrackSelectionOverrides trackSelectionOverrides) {
this.trackSelectionOverrides = trackSelectionOverrides;
public Builder clearOverridesOfType(@C.TrackType int trackType) {
Iterator<TrackSelectionOverride> it = overrides.values().iterator();
while (it.hasNext()) {
TrackSelectionOverride override = it.next();
if (override.getTrackType() == trackType) {
it.remove();
}
}
return this;
}
/** Removes all track overrides. */
public Builder clearOverrides() {
overrides.clear();
return this;
}
......@@ -858,8 +896,9 @@ public class TrackSelectionParameters implements Bundleable {
*/
public final boolean forceHighestSupportedBitrate;
/** Overrides to force tracks to be selected. */
public final TrackSelectionOverrides trackSelectionOverrides;
/** Overrides to force selection of specific tracks. */
public final ImmutableMap<TrackGroup, TrackSelectionOverride> overrides;
/**
* The track types that are disabled. No track of a disabled type will be selected, thus no track
* type contained in the set will be played. The default value is that no track type is disabled
......@@ -896,7 +935,7 @@ public class TrackSelectionParameters implements Bundleable {
// General
this.forceLowestBitrate = builder.forceLowestBitrate;
this.forceHighestSupportedBitrate = builder.forceHighestSupportedBitrate;
this.trackSelectionOverrides = builder.trackSelectionOverrides;
this.overrides = ImmutableMap.copyOf(builder.overrides);
this.disabledTrackTypes = builder.disabledTrackTypes;
}
......@@ -941,7 +980,7 @@ public class TrackSelectionParameters implements Bundleable {
// General
&& forceLowestBitrate == other.forceLowestBitrate
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
&& trackSelectionOverrides.equals(other.trackSelectionOverrides)
&& overrides.equals(other.overrides)
&& disabledTrackTypes.equals(other.disabledTrackTypes);
}
......@@ -975,7 +1014,7 @@ public class TrackSelectionParameters implements Bundleable {
// General
result = 31 * result + (forceLowestBitrate ? 1 : 0);
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
result = 31 * result + trackSelectionOverrides.hashCode();
result = 31 * result + overrides.hashCode();
result = 31 * result + disabledTrackTypes.hashCode();
return result;
}
......@@ -1007,8 +1046,7 @@ public class TrackSelectionParameters implements Bundleable {
FIELD_PREFERRED_AUDIO_MIME_TYPES,
FIELD_FORCE_LOWEST_BITRATE,
FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE,
FIELD_SELECTION_OVERRIDE_KEYS,
FIELD_SELECTION_OVERRIDE_VALUES,
FIELD_SELECTION_OVERRIDES,
FIELD_DISABLED_TRACK_TYPE,
FIELD_PREFERRED_VIDEO_ROLE_FLAGS
})
......@@ -1036,10 +1074,9 @@ public class TrackSelectionParameters implements Bundleable {
private static final int FIELD_PREFERRED_AUDIO_MIME_TYPES = 20;
private static final int FIELD_FORCE_LOWEST_BITRATE = 21;
private static final int FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE = 22;
private static final int FIELD_SELECTION_OVERRIDE_KEYS = 23;
private static final int FIELD_SELECTION_OVERRIDE_VALUES = 24;
private static final int FIELD_DISABLED_TRACK_TYPE = 25;
private static final int FIELD_PREFERRED_VIDEO_ROLE_FLAGS = 26;
private static final int FIELD_SELECTION_OVERRIDES = 23;
private static final int FIELD_DISABLED_TRACK_TYPE = 24;
private static final int FIELD_PREFERRED_VIDEO_ROLE_FLAGS = 25;
@UnstableApi
@Override
......@@ -1083,8 +1120,8 @@ public class TrackSelectionParameters implements Bundleable {
bundle.putBoolean(keyForField(FIELD_FORCE_LOWEST_BITRATE), forceLowestBitrate);
bundle.putBoolean(
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), forceHighestSupportedBitrate);
bundle.putBundle(
keyForField(FIELD_SELECTION_OVERRIDE_KEYS), trackSelectionOverrides.toBundle());
bundle.putParcelableArrayList(
keyForField(FIELD_SELECTION_OVERRIDES), toBundleArrayList(overrides.values()));
bundle.putIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE), Ints.toArray(disabledTrackTypes));
return bundle;
......
......@@ -15,6 +15,8 @@
*/
package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
......@@ -24,6 +26,7 @@ import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Represents the video size. */
public final class VideoSize implements Bundleable {
......@@ -131,6 +134,7 @@ public final class VideoSize implements Bundleable {
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_WIDTH,
FIELD_HEIGHT,
......
......@@ -59,6 +59,8 @@ public final class Cue implements Bundleable {
* The type of anchor, which may be unset. One of {@link #TYPE_UNSET}, {@link #ANCHOR_TYPE_START},
* {@link #ANCHOR_TYPE_MIDDLE} or {@link #ANCHOR_TYPE_END}.
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
......@@ -87,6 +89,8 @@ public final class Cue implements Bundleable {
* The type of line, which may be unset. One of {@link #TYPE_UNSET}, {@link #LINE_TYPE_FRACTION}
* or {@link #LINE_TYPE_NUMBER}.
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
......@@ -104,6 +108,8 @@ public final class Cue implements Bundleable {
* {@link #TEXT_SIZE_TYPE_FRACTIONAL}, {@link #TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING} or {@link
* #TEXT_SIZE_TYPE_ABSOLUTE}.
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
......@@ -128,6 +134,8 @@ public final class Cue implements Bundleable {
* The type of vertical layout for this cue, which may be unset (i.e. horizontal). One of {@link
* #TYPE_UNSET}, {@link #VERTICAL_TYPE_RL} or {@link #VERTICAL_TYPE_LR}.
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
......@@ -561,7 +569,7 @@ public final class Cue implements Bundleable {
@Nullable private Alignment textAlignment;
@Nullable private Alignment multiRowAlignment;
private float line;
@LineType private int lineType;
private @LineType int lineType;
private @AnchorType int lineAnchor;
private float position;
private @AnchorType int positionAnchor;
......@@ -722,8 +730,7 @@ public final class Cue implements Bundleable {
* @see Cue#lineType
*/
@Pure
@LineType
public int getLineType() {
public @LineType int getLineType() {
return lineType;
}
......@@ -743,8 +750,7 @@ public final class Cue implements Bundleable {
* @see Cue#lineAnchor
*/
@Pure
@AnchorType
public int getLineAnchor() {
public @AnchorType int getLineAnchor() {
return lineAnchor;
}
......@@ -786,8 +792,7 @@ public final class Cue implements Bundleable {
* @see Cue#positionAnchor
*/
@Pure
@AnchorType
public int getPositionAnchor() {
public @AnchorType int getPositionAnchor() {
return positionAnchor;
}
......@@ -809,8 +814,7 @@ public final class Cue implements Bundleable {
* @see Cue#textSizeType
*/
@Pure
@TextSizeType
public int getTextSizeType() {
public @TextSizeType int getTextSizeType() {
return textSizeType;
}
......@@ -928,8 +932,7 @@ public final class Cue implements Bundleable {
* @see Cue#verticalType
*/
@Pure
@VerticalType
public int getVerticalType() {
public @VerticalType int getVerticalType() {
return verticalType;
}
......@@ -960,6 +963,7 @@ public final class Cue implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_TEXT,
FIELD_TEXT_ALIGNMENT,
......
......@@ -39,7 +39,7 @@ public final class RubySpan implements LanguageFeatureSpan {
public final String rubyText;
/** The position of the ruby text relative to the base text. */
@TextAnnotation.Position public final int position;
public final @TextAnnotation.Position int position;
public RubySpan(String rubyText, @TextAnnotation.Position int position) {
this.rubyText = rubyText;
......
......@@ -15,12 +15,14 @@
*/
package androidx.media3.common.text;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import androidx.annotation.IntDef;
import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/** Properties of a text annotation (i.e. ruby, text emphasis marks). */
@UnstableApi
......@@ -57,6 +59,7 @@ public final class TextAnnotation {
*/
@Documented
@Retention(SOURCE)
@Target(TYPE_USE)
@IntDef({POSITION_UNKNOWN, POSITION_BEFORE, POSITION_AFTER})
public @interface Position {}
......
......@@ -15,12 +15,14 @@
*/
package androidx.media3.common.text;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import androidx.annotation.IntDef;
import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* A styling span for text emphasis marks.
......@@ -50,6 +52,7 @@ public final class TextEmphasisSpan implements LanguageFeatureSpan {
*/
@Documented
@Retention(SOURCE)
@Target(TYPE_USE)
@IntDef({MARK_SHAPE_NONE, MARK_SHAPE_CIRCLE, MARK_SHAPE_DOT, MARK_SHAPE_SESAME})
public @interface MarkShape {}
......@@ -71,6 +74,7 @@ public final class TextEmphasisSpan implements LanguageFeatureSpan {
*/
@Documented
@Retention(SOURCE)
@Target(TYPE_USE)
@IntDef({MARK_FILL_UNKNOWN, MARK_FILL_FILLED, MARK_FILL_OPEN})
public @interface MarkFill {}
......@@ -79,13 +83,13 @@ public final class TextEmphasisSpan implements LanguageFeatureSpan {
public static final int MARK_FILL_OPEN = 2;
/** The mark shape used for text emphasis. */
@MarkShape public int markShape;
public @MarkShape int markShape;
/** The mark fill for the text emphasis mark. */
@MarkShape public int markFill;
public @MarkShape int markFill;
/** The position of the text emphasis relative to the base text. */
@TextAnnotation.Position public final int position;
public final @TextAnnotation.Position int position;
public TextEmphasisSpan(
@MarkShape int shape, @MarkFill int fill, @TextAnnotation.Position int position) {
......
......@@ -36,10 +36,14 @@ public interface Clock {
*/
long currentTimeMillis();
/** @see android.os.SystemClock#elapsedRealtime() */
/**
* @see android.os.SystemClock#elapsedRealtime()
*/
long elapsedRealtime();
/** @see android.os.SystemClock#uptimeMillis() */
/**
* @see android.os.SystemClock#uptimeMillis()
*/
long uptimeMillis();
/**
......
......@@ -15,6 +15,8 @@
*/
package androidx.media3.common.util;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.opengl.EGLConfig;
......@@ -29,6 +31,7 @@ import androidx.annotation.RequiresApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Generates a {@link SurfaceTexture} using EGL/GLES functions. */
@RequiresApi(17)
......@@ -47,6 +50,7 @@ public final class EGLSurfaceTexture implements SurfaceTexture.OnFrameAvailableL
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({SECURE_MODE_NONE, SECURE_MODE_SURFACELESS_CONTEXT, SECURE_MODE_PROTECTED_PBUFFER})
public @interface SecureMode {}
......
......@@ -19,7 +19,7 @@ import java.util.Arrays;
/** Configurable loader for native libraries. */
@UnstableApi
public final class LibraryLoader {
public abstract class LibraryLoader {
private static final String TAG = "LibraryLoader";
......@@ -27,7 +27,9 @@ public final class LibraryLoader {
private boolean loadAttempted;
private boolean isAvailable;
/** @param libraries The names of the libraries to load. */
/**
* @param libraries The names of the libraries to load.
*/
public LibraryLoader(String... libraries) {
nativeLibraries = libraries;
}
......@@ -49,7 +51,7 @@ public final class LibraryLoader {
loadAttempted = true;
try {
for (String lib : nativeLibraries) {
System.loadLibrary(lib);
loadLibrary(lib);
}
isAvailable = true;
} catch (UnsatisfiedLinkError exception) {
......@@ -59,4 +61,17 @@ public final class LibraryLoader {
}
return isAvailable;
}
/**
* Should be implemented to call {@code System.loadLibrary(name)}.
*
* <p>It's necessary for each subclass to implement this method because {@link
* System#loadLibrary(String)} uses reflection to obtain the calling class, which is then used to
* obtain the class loader to use when loading the native library. If this class were to implement
* the method directly, and if a subclass were to have a different class loader, then loading of
* the native library would fail.
*
* @param name The name of the library to load.
*/
protected abstract void loadLibrary(String name);
}
......@@ -118,6 +118,21 @@ public final class ListenerSet<T extends @NonNull Object> {
*/
@CheckResult
public ListenerSet<T> copy(Looper looper, IterationFinishedEvent<T> iterationFinishedEvent) {
return copy(looper, clock, iterationFinishedEvent);
}
/**
* Copies the listener set.
*
* @param looper The new {@link Looper} for the copied listener set.
* @param clock The new {@link Clock} for the copied listener set.
* @param iterationFinishedEvent The new {@link IterationFinishedEvent} sent when all other events
* sent during one {@link Looper} message queue iteration were handled by the listeners.
* @return The copied listener set.
*/
@CheckResult
public ListenerSet<T> copy(
Looper looper, Clock clock, IterationFinishedEvent<T> iterationFinishedEvent) {
return new ListenerSet<>(listeners, looper, clock, iterationFinishedEvent);
}
......@@ -152,6 +167,11 @@ public final class ListenerSet<T extends @NonNull Object> {
}
}
/** Removes all listeners from the set. */
public void clear() {
listeners.clear();
}
/** Returns the number of added listeners. */
public int size() {
return listeners.size();
......
......@@ -15,6 +15,8 @@
*/
package androidx.media3.common.util;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.text.TextUtils;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
......@@ -22,6 +24,7 @@ import androidx.annotation.Size;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.UnknownHostException;
import org.checkerframework.dataflow.qual.Pure;
......@@ -35,8 +38,9 @@ public final class Log {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({LOG_LEVEL_ALL, LOG_LEVEL_INFO, LOG_LEVEL_WARNING, LOG_LEVEL_ERROR, LOG_LEVEL_OFF})
@interface LogLevel {}
public @interface LogLevel {}
/** Log level to log all messages. */
public static final int LOG_LEVEL_ALL = 0;
/** Log level to only log informative, warning and error messages. */
......@@ -78,7 +82,9 @@ public final class Log {
Log.logStackTraces = logStackTraces;
}
/** @see android.util.Log#d(String, String) */
/**
* @see android.util.Log#d(String, String)
*/
@Pure
public static void d(@Size(max = 23) String tag, String message) {
if (logLevel == LOG_LEVEL_ALL) {
......@@ -86,13 +92,17 @@ public final class Log {
}
}
/** @see android.util.Log#d(String, String, Throwable) */
/**
* @see android.util.Log#d(String, String, Throwable)
*/
@Pure
public static void d(@Size(max = 23) String tag, String message, @Nullable Throwable throwable) {
d(tag, appendThrowableString(message, throwable));
}
/** @see android.util.Log#i(String, String) */
/**
* @see android.util.Log#i(String, String)
*/
@Pure
public static void i(@Size(max = 23) String tag, String message) {
if (logLevel <= LOG_LEVEL_INFO) {
......@@ -100,13 +110,17 @@ public final class Log {
}
}
/** @see android.util.Log#i(String, String, Throwable) */
/**
* @see android.util.Log#i(String, String, Throwable)
*/
@Pure
public static void i(@Size(max = 23) String tag, String message, @Nullable Throwable throwable) {
i(tag, appendThrowableString(message, throwable));
}
/** @see android.util.Log#w(String, String) */
/**
* @see android.util.Log#w(String, String)
*/
@Pure
public static void w(@Size(max = 23) String tag, String message) {
if (logLevel <= LOG_LEVEL_WARNING) {
......@@ -114,13 +128,17 @@ public final class Log {
}
}
/** @see android.util.Log#w(String, String, Throwable) */
/**
* @see android.util.Log#w(String, String, Throwable)
*/
@Pure
public static void w(@Size(max = 23) String tag, String message, @Nullable Throwable throwable) {
w(tag, appendThrowableString(message, throwable));
}
/** @see android.util.Log#e(String, String) */
/**
* @see android.util.Log#e(String, String)
*/
@Pure
public static void e(@Size(max = 23) String tag, String message) {
if (logLevel <= LOG_LEVEL_ERROR) {
......@@ -128,7 +146,9 @@ public final class Log {
}
}
/** @see android.util.Log#e(String, String, Throwable) */
/**
* @see android.util.Log#e(String, String, Throwable)
*/
@Pure
public static void e(@Size(max = 23) String tag, String message, @Nullable Throwable throwable) {
e(tag, appendThrowableString(message, throwable));
......
......@@ -30,7 +30,9 @@ public final class LongArray {
this(DEFAULT_INITIAL_CAPACITY);
}
/** @param initialCapacity The initial capacity of the array. */
/**
* @param initialCapacity The initial capacity of the array.
*/
public LongArray(int initialCapacity) {
values = new long[initialCapacity];
}
......
......@@ -221,6 +221,17 @@ public final class MediaFormatUtil {
case C.ENCODING_PCM_FLOAT:
mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_FLOAT;
break;
case C.ENCODING_PCM_24BIT:
mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_24BIT_PACKED;
break;
case C.ENCODING_PCM_32BIT:
mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_32BIT;
break;
case C.ENCODING_INVALID:
mediaFormatPcmEncoding = AudioFormat.ENCODING_INVALID;
break;
case Format.NO_VALUE:
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
default:
// No matching value. Do nothing.
return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment