mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Publish SurfaceControl demo
Issue: #677 Issue: #5428 PiperOrigin-RevId: 270466031
This commit is contained in:
parent
18b9304f25
commit
258fff422a
@ -13,7 +13,7 @@
|
|||||||
* Bypass sniffing in `ProgressiveMediaPeriod` in case a single extractor is
|
* Bypass sniffing in `ProgressiveMediaPeriod` in case a single extractor is
|
||||||
provided ([#6325](https://github.com/google/ExoPlayer/issues/6325)).
|
provided ([#6325](https://github.com/google/ExoPlayer/issues/6325)).
|
||||||
* Surface information provided by methods `isHardwareAccelerated`,
|
* Surface information provided by methods `isHardwareAccelerated`,
|
||||||
`isSoftwareOnly` and `isVendor` added in Android Q in `MediaCodecInfo` class
|
`isSoftwareOnly` and `isVendor` added in Android 10 in `MediaCodecInfo` class
|
||||||
([#5839](https://github.com/google/ExoPlayer/issues/5839)).
|
([#5839](https://github.com/google/ExoPlayer/issues/5839)).
|
||||||
* Update `DefaultTrackSelector` to apply a viewport constraint for the default
|
* Update `DefaultTrackSelector` to apply a viewport constraint for the default
|
||||||
display by default.
|
display by default.
|
||||||
@ -33,7 +33,7 @@
|
|||||||
`SourceInfoRefreshListener` anymore. Instead make it accessible through
|
`SourceInfoRefreshListener` anymore. Instead make it accessible through
|
||||||
`Player.getCurrentManifest()` and `Timeline.Window.manifest`. Also rename
|
`Player.getCurrentManifest()` and `Timeline.Window.manifest`. Also rename
|
||||||
`SourceInfoRefreshListener` to `MediaSourceCaller`.
|
`SourceInfoRefreshListener` to `MediaSourceCaller`.
|
||||||
* Set `compileSdkVersion` to 29 to use Android Q APIs.
|
* Set `compileSdkVersion` to 29 to use Android 10 APIs.
|
||||||
* Add `enable` and `disable` methods to `MediaSource` to improve resource
|
* Add `enable` and `disable` methods to `MediaSource` to improve resource
|
||||||
management in playlists.
|
management in playlists.
|
||||||
* Text selection logic:
|
* Text selection logic:
|
||||||
@ -59,6 +59,8 @@
|
|||||||
* Fix Dolby Vision fallback to AVC and HEVC.
|
* Fix Dolby Vision fallback to AVC and HEVC.
|
||||||
* Add top-level playlist API
|
* Add top-level playlist API
|
||||||
([#6161](https://github.com/google/ExoPlayer/issues/6161)).
|
([#6161](https://github.com/google/ExoPlayer/issues/6161)).
|
||||||
|
* Add demo app to show how to use the Android 10 `SurfaceControl` API with
|
||||||
|
ExoPlayer ([#677](https://github.com/google/ExoPlayer/issues/677)).
|
||||||
|
|
||||||
### 2.10.5 (2019-09-20) ###
|
### 2.10.5 (2019-09-20) ###
|
||||||
|
|
||||||
|
21
demos/surface/README.md
Normal file
21
demos/surface/README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# ExoPlayer SurfaceControl demo
|
||||||
|
|
||||||
|
This app demonstrates how to use the [SurfaceControl][] API to redirect video
|
||||||
|
output from ExoPlayer between different views or off-screen. `SurfaceControl`
|
||||||
|
is new in Android 10, so the app requires `minSdkVersion` 29.
|
||||||
|
|
||||||
|
The app layout has a grid of `SurfaceViews`. Initially video is output to one
|
||||||
|
of the views. Tap a `SurfaceView` to move video output to it. You can also tap
|
||||||
|
the buttons at the top of the activity to move video output off-screen, to a
|
||||||
|
full-screen `SurfaceView` or to a new activity.
|
||||||
|
|
||||||
|
When using `SurfaceControl`, the `MediaCodec` always has the same surface
|
||||||
|
attached to it, which can be freely 'reparented' to any `SurfaceView` (or
|
||||||
|
off-screen) without any interruptions to playback. This works better than
|
||||||
|
calling `MediaCodec.setOutputSurface` to change the output surface of the codec
|
||||||
|
because `MediaCodec` does not re-render its last frame when that method is
|
||||||
|
called, and because you can move output off-screen easily (`setOutputSurface`
|
||||||
|
can't take a `null` surface, so the player has to use a `DummySurface`, which
|
||||||
|
doesn't handle protected output on all devices).
|
||||||
|
|
||||||
|
[SurfaceControl]: https://developer.android.com/reference/android/view/SurfaceControl
|
51
demos/surface/build.gradle
Normal file
51
demos/surface/build.gradle
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (C) 2019 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
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 29
|
||||||
|
targetSdkVersion 29
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
shrinkResources true
|
||||||
|
minifyEnabled true
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
// This demo app does not have translations.
|
||||||
|
disable 'MissingTranslation'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(modulePrefix + 'library-core')
|
||||||
|
implementation project(modulePrefix + 'library-ui')
|
||||||
|
implementation project(modulePrefix + 'library-dash')
|
||||||
|
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
||||||
|
}
|
41
demos/surface/src/main/AndroidManifest.xml
Normal file
41
demos/surface/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2019 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.google.android.exoplayer2.surfacedemo">
|
||||||
|
<uses-sdk/>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<application
|
||||||
|
android:allowBackup="false"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/application_name">
|
||||||
|
<activity android:name=".MainActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.android.exoplayer.surfacedemo.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>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.surfacedemo;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Surface;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.SurfaceView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.GridLayout;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.Player;
|
||||||
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
|
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
||||||
|
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||||
|
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||||
|
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
|
||||||
|
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
|
||||||
|
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||||
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||||
|
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/** Activity that demonstrates use of {@link SurfaceControl} with ExoPlayer. */
|
||||||
|
public final class MainActivity extends Activity {
|
||||||
|
|
||||||
|
private static final String TAG = "MainActivity";
|
||||||
|
private static final String DEFAULT_MEDIA_URI =
|
||||||
|
"https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv";
|
||||||
|
private static final String SURFACE_CONTROL_NAME = "surfacedemo";
|
||||||
|
|
||||||
|
private static final String ACTION_VIEW = "com.google.android.exoplayer.surfacedemo.action.VIEW";
|
||||||
|
private static final String EXTENSION_EXTRA = "extension";
|
||||||
|
private static final String DRM_SCHEME_EXTRA = "drm_scheme";
|
||||||
|
private static final String DRM_LICENSE_URL_EXTRA = "drm_license_url";
|
||||||
|
private static final String OWNER_EXTRA = "owner";
|
||||||
|
|
||||||
|
private boolean isOwner;
|
||||||
|
private PlayerControlView playerControlView;
|
||||||
|
private SurfaceView fullScreenView;
|
||||||
|
private SurfaceView nonFullScreenView;
|
||||||
|
@Nullable private SurfaceView currentOutputView;
|
||||||
|
|
||||||
|
private static SimpleExoPlayer player;
|
||||||
|
private static FrameworkMediaDrm mediaDrm;
|
||||||
|
private static SurfaceControl surfaceControl;
|
||||||
|
private static Surface videoSurface;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.main_activity);
|
||||||
|
playerControlView = findViewById(R.id.player_control_view);
|
||||||
|
fullScreenView = findViewById(R.id.full_screen_view);
|
||||||
|
fullScreenView.setOnClickListener(
|
||||||
|
v -> {
|
||||||
|
setCurrentOutputView(nonFullScreenView);
|
||||||
|
fullScreenView.setVisibility(View.GONE);
|
||||||
|
});
|
||||||
|
attachSurfaceListener(fullScreenView);
|
||||||
|
isOwner = getIntent().getBooleanExtra(OWNER_EXTRA, /* defaultValue= */ true);
|
||||||
|
GridLayout gridLayout = findViewById(R.id.grid_layout);
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
View view;
|
||||||
|
if (i == 0) {
|
||||||
|
Button button = new Button(/* context= */ this);
|
||||||
|
view = button;
|
||||||
|
button.setText(getString(R.string.no_output_label));
|
||||||
|
button.setOnClickListener(v -> reparent(null));
|
||||||
|
} else if (i == 1) {
|
||||||
|
Button button = new Button(/* context= */ this);
|
||||||
|
view = button;
|
||||||
|
button.setText(getString(R.string.full_screen_label));
|
||||||
|
button.setOnClickListener(
|
||||||
|
v -> {
|
||||||
|
setCurrentOutputView(fullScreenView);
|
||||||
|
fullScreenView.setVisibility(View.VISIBLE);
|
||||||
|
});
|
||||||
|
} else if (i == 2) {
|
||||||
|
Button button = new Button(/* context= */ this);
|
||||||
|
view = button;
|
||||||
|
button.setText(getString(R.string.new_activity_label));
|
||||||
|
button.setOnClickListener(
|
||||||
|
v -> {
|
||||||
|
startActivity(
|
||||||
|
new Intent(MainActivity.this, MainActivity.class)
|
||||||
|
.putExtra(OWNER_EXTRA, /* value= */ false));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
SurfaceView surfaceView = new SurfaceView(this);
|
||||||
|
view = surfaceView;
|
||||||
|
attachSurfaceListener(surfaceView);
|
||||||
|
surfaceView.setOnClickListener(
|
||||||
|
v -> {
|
||||||
|
setCurrentOutputView(surfaceView);
|
||||||
|
nonFullScreenView = surfaceView;
|
||||||
|
});
|
||||||
|
if (nonFullScreenView == null) {
|
||||||
|
nonFullScreenView = surfaceView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gridLayout.addView(view);
|
||||||
|
GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
|
||||||
|
layoutParams.width = 400;
|
||||||
|
layoutParams.height = 400;
|
||||||
|
layoutParams.columnSpec = GridLayout.spec(i % 3);
|
||||||
|
layoutParams.rowSpec = GridLayout.spec(i / 3);
|
||||||
|
layoutParams.bottomMargin = 10;
|
||||||
|
layoutParams.leftMargin = 10;
|
||||||
|
layoutParams.topMargin = 10;
|
||||||
|
layoutParams.rightMargin = 10;
|
||||||
|
view.setLayoutParams(layoutParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (isOwner && player == null) {
|
||||||
|
initializePlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentOutputView(nonFullScreenView);
|
||||||
|
playerControlView.setPlayer(player);
|
||||||
|
playerControlView.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
playerControlView.setPlayer(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (isOwner && isFinishing()) {
|
||||||
|
if (surfaceControl != null) {
|
||||||
|
surfaceControl.release();
|
||||||
|
surfaceControl = null;
|
||||||
|
videoSurface.release();
|
||||||
|
}
|
||||||
|
if (player != null) {
|
||||||
|
player.release();
|
||||||
|
player = null;
|
||||||
|
}
|
||||||
|
if (mediaDrm != null) {
|
||||||
|
mediaDrm.release();
|
||||||
|
mediaDrm = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializePlayer() {
|
||||||
|
Intent intent = getIntent();
|
||||||
|
String action = intent.getAction();
|
||||||
|
Uri uri = ACTION_VIEW.equals(action) ? intent.getData() : Uri.parse(DEFAULT_MEDIA_URI);
|
||||||
|
String userAgent = Util.getUserAgent(this, getString(R.string.application_name));
|
||||||
|
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager =
|
||||||
|
DrmSessionManager.getDummyDrmSessionManager();
|
||||||
|
if (intent.hasExtra(DRM_SCHEME_EXTRA)) {
|
||||||
|
String drmLicenseUrl = intent.getStringExtra(DRM_LICENSE_URL_EXTRA);
|
||||||
|
try {
|
||||||
|
UUID drmSchemeUuid = Util.getDrmUuid(intent.getStringExtra(DRM_SCHEME_EXTRA));
|
||||||
|
HttpDataSource.Factory licenseDataSourceFactory =
|
||||||
|
new DefaultHttpDataSourceFactory(userAgent);
|
||||||
|
HttpMediaDrmCallback drmCallback =
|
||||||
|
new HttpMediaDrmCallback(drmLicenseUrl, licenseDataSourceFactory);
|
||||||
|
mediaDrm = FrameworkMediaDrm.newInstance(drmSchemeUuid);
|
||||||
|
drmSessionManager =
|
||||||
|
new DefaultDrmSessionManager<>(
|
||||||
|
drmSchemeUuid, mediaDrm, drmCallback, /* optionalKeyRequestParameters= */ null);
|
||||||
|
} catch (UnsupportedDrmException e) {
|
||||||
|
Log.e(TAG, "Unsupported DRM scheme", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSource.Factory dataSourceFactory =
|
||||||
|
new DefaultDataSourceFactory(
|
||||||
|
this, Util.getUserAgent(this, getString(R.string.application_name)));
|
||||||
|
MediaSource mediaSource;
|
||||||
|
@C.ContentType int type = Util.inferContentType(uri, intent.getStringExtra(EXTENSION_EXTRA));
|
||||||
|
if (type == C.TYPE_DASH) {
|
||||||
|
mediaSource =
|
||||||
|
new DashMediaSource.Factory(dataSourceFactory)
|
||||||
|
.setDrmSessionManager(drmSessionManager)
|
||||||
|
.createMediaSource(uri);
|
||||||
|
} else if (type == C.TYPE_OTHER) {
|
||||||
|
mediaSource =
|
||||||
|
new ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||||
|
.setDrmSessionManager(drmSessionManager)
|
||||||
|
.createMediaSource(uri);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
player = new SimpleExoPlayer.Builder(getApplicationContext()).build();
|
||||||
|
player.setMediaItem(mediaSource);
|
||||||
|
player.prepare();
|
||||||
|
player.setPlayWhenReady(true);
|
||||||
|
player.setRepeatMode(Player.REPEAT_MODE_ALL);
|
||||||
|
|
||||||
|
surfaceControl =
|
||||||
|
new SurfaceControl.Builder()
|
||||||
|
.setName(SURFACE_CONTROL_NAME)
|
||||||
|
.setBufferSize(/* width= */ 0, /* height= */ 0)
|
||||||
|
.build();
|
||||||
|
videoSurface = new Surface(surfaceControl);
|
||||||
|
player.setVideoSurface(videoSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCurrentOutputView(@Nullable SurfaceView surfaceView) {
|
||||||
|
currentOutputView = surfaceView;
|
||||||
|
if (surfaceView != null && surfaceView.getHolder().getSurface() != null) {
|
||||||
|
reparent(surfaceView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachSurfaceListener(SurfaceView surfaceView) {
|
||||||
|
surfaceView
|
||||||
|
.getHolder()
|
||||||
|
.addCallback(
|
||||||
|
new SurfaceHolder.Callback() {
|
||||||
|
@Override
|
||||||
|
public void surfaceCreated(SurfaceHolder surfaceHolder) {
|
||||||
|
if (surfaceView == currentOutputView) {
|
||||||
|
reparent(surfaceView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceChanged(
|
||||||
|
SurfaceHolder surfaceHolder, int format, int width, int height) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reparent(@Nullable SurfaceView surfaceView) {
|
||||||
|
if (surfaceView == null) {
|
||||||
|
new SurfaceControl.Transaction()
|
||||||
|
.reparent(surfaceControl, /* newParent= */ null)
|
||||||
|
.setBufferSize(surfaceControl, /* w= */ 0, /* h= */ 0)
|
||||||
|
.setVisibility(surfaceControl, /* visible= */ false)
|
||||||
|
.apply();
|
||||||
|
} else {
|
||||||
|
SurfaceControl newParentSurfaceControl = surfaceView.getSurfaceControl();
|
||||||
|
new SurfaceControl.Transaction()
|
||||||
|
.reparent(surfaceControl, newParentSurfaceControl)
|
||||||
|
.setBufferSize(surfaceControl, surfaceView.getWidth(), surfaceView.getHeight())
|
||||||
|
.setVisibility(surfaceControl, /* visible= */ true)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
demos/surface/src/main/res/layout/main_activity.xml
Normal file
43
demos/surface/src/main/res/layout/main_activity.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2019 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:keepScreenOn="true">
|
||||||
|
|
||||||
|
<GridLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/grid_layout"
|
||||||
|
android:columnCount="3" />
|
||||||
|
|
||||||
|
<SurfaceView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/full_screen_view"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<com.google.android.exoplayer2.ui.PlayerControlView
|
||||||
|
android:id="@+id/player_control_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
app:show_timeout="0" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
BIN
demos/surface/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
demos/surface/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
demos/surface/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
demos/surface/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
demos/surface/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
demos/surface/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
demos/surface/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
demos/surface/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
BIN
demos/surface/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
demos/surface/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
23
demos/surface/src/main/res/values/strings.xml
Normal file
23
demos/surface/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2019 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<string name="application_name">ExoPlayer SurfaceControl demo</string>
|
||||||
|
<string name="no_output_label">No output</string>
|
||||||
|
<string name="full_screen_label">Full screen</string>
|
||||||
|
<string name="new_activity_label">New activity</string>
|
||||||
|
|
||||||
|
</resources>
|
23
demos/surface/src/main/res/values/styles.xml
Normal file
23
demos/surface/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2019 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<style name="PlayerTheme" parent="android:Theme.Holo">
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="android:windowBackground">@android:color/black</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
@ -22,11 +22,13 @@ include modulePrefix + 'demo'
|
|||||||
include modulePrefix + 'demo-cast'
|
include modulePrefix + 'demo-cast'
|
||||||
include modulePrefix + 'demo-ima'
|
include modulePrefix + 'demo-ima'
|
||||||
include modulePrefix + 'demo-gvr'
|
include modulePrefix + 'demo-gvr'
|
||||||
|
include modulePrefix + 'demo-surface'
|
||||||
include modulePrefix + 'playbacktests'
|
include modulePrefix + 'playbacktests'
|
||||||
project(modulePrefix + 'demo').projectDir = new File(rootDir, 'demos/main')
|
project(modulePrefix + 'demo').projectDir = new File(rootDir, 'demos/main')
|
||||||
project(modulePrefix + 'demo-cast').projectDir = new File(rootDir, 'demos/cast')
|
project(modulePrefix + 'demo-cast').projectDir = new File(rootDir, 'demos/cast')
|
||||||
project(modulePrefix + 'demo-ima').projectDir = new File(rootDir, 'demos/ima')
|
project(modulePrefix + 'demo-ima').projectDir = new File(rootDir, 'demos/ima')
|
||||||
project(modulePrefix + 'demo-gvr').projectDir = new File(rootDir, 'demos/gvr')
|
project(modulePrefix + 'demo-gvr').projectDir = new File(rootDir, 'demos/gvr')
|
||||||
|
project(modulePrefix + 'demo-surface').projectDir = new File(rootDir, 'demos/surface')
|
||||||
project(modulePrefix + 'playbacktests').projectDir = new File(rootDir, 'playbacktests')
|
project(modulePrefix + 'playbacktests').projectDir = new File(rootDir, 'playbacktests')
|
||||||
|
|
||||||
apply from: 'core_settings.gradle'
|
apply from: 'core_settings.gradle'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user