diff --git a/android/src/main/java/com/brentvatne/common/api/ViewType.kt b/android/src/main/java/com/brentvatne/common/api/ViewType.kt new file mode 100644 index 00000000..c171a231 --- /dev/null +++ b/android/src/main/java/com/brentvatne/common/api/ViewType.kt @@ -0,0 +1,19 @@ +package com.brentvatne.common.api + +internal object ViewType { + /** + * View used will be a TextureView. + */ + const val VIEW_TYPE_TEXTURE = 0 + + /** + * View used will be a SurfaceView. + */ + const val VIEW_TYPE_SURFACE = 1 + + /** + * View used will be a SurfaceView with secure flag set. + */ + const val VIEW_TYPE_SURFACE_SECURE = 2 + annotation class ViewType +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java index e254975f..96c2f918 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java @@ -26,12 +26,14 @@ import android.widget.FrameLayout; import com.brentvatne.common.api.ResizeMode; import com.brentvatne.common.api.SubtitleStyle; +import com.brentvatne.common.api.ViewType; +import com.brentvatne.common.toolbox.DebugLog; import com.google.common.collect.ImmutableList; import java.util.List; public final class ExoPlayerView extends FrameLayout implements AdViewProvider { - + private final static String TAG = "ExoPlayerView"; private View surfaceView; private final View shutterView; private final SubtitleView subtitleLayout; @@ -42,8 +44,7 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider { private final ViewGroup.LayoutParams layoutParams; private final FrameLayout adOverlayFrameLayout; - private boolean useTextureView = true; - private boolean useSecureView = false; + private @ViewType.ViewType int viewType = ViewType.VIEW_TYPE_SURFACE; private boolean hideShutterView = false; public ExoPlayerView(Context context) { @@ -81,7 +82,7 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider { subtitleLayout.setUserDefaultStyle(); subtitleLayout.setUserDefaultTextSize(); - updateSurfaceView(); + updateSurfaceView(viewType); adOverlayFrameLayout = new FrameLayout(context); @@ -134,28 +135,36 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider { shutterView.setBackgroundColor(color); } - private void updateSurfaceView() { - View view; - if (!useTextureView || useSecureView) { - view = new SurfaceView(context); - if (useSecureView) { - ((SurfaceView)view).setSecure(true); + public void updateSurfaceView(@ViewType.ViewType int viewType) { + this.viewType = viewType; + boolean viewNeedRefresh = false; + if (viewType == ViewType.VIEW_TYPE_SURFACE || viewType == ViewType.VIEW_TYPE_SURFACE_SECURE) { + if (!(surfaceView instanceof SurfaceView)) { + surfaceView = new SurfaceView(context); + viewNeedRefresh = true; + } + ((SurfaceView)surfaceView).setSecure(viewType == ViewType.VIEW_TYPE_SURFACE_SECURE); + } else if (viewType == ViewType.VIEW_TYPE_TEXTURE) { + if (!(surfaceView instanceof TextureView)) { + surfaceView = new TextureView(context); + viewNeedRefresh = true; } - } else { - view = new TextureView(context); // Support opacity properly: - ((TextureView) view).setOpaque(false); + ((TextureView) surfaceView).setOpaque(false); + } else { + DebugLog.wtf(TAG, "wtf is this texture " + viewType); } - view.setLayoutParams(layoutParams); + if (viewNeedRefresh) { + surfaceView.setLayoutParams(layoutParams); - surfaceView = view; - if (layout.getChildAt(0) != null) { - layout.removeViewAt(0); - } - layout.addView(surfaceView, 0, layoutParams); + if (layout.getChildAt(0) != null) { + layout.removeViewAt(0); + } + layout.addView(surfaceView, 0, layoutParams); - if (this.player != null) { - setVideoView(); + if (this.player != null) { + setVideoView(); + } } } @@ -211,20 +220,6 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider { } } - public void setUseTextureView(boolean useTextureView) { - if (useTextureView != this.useTextureView) { - this.useTextureView = useTextureView; - updateSurfaceView(); - } - } - - public void useSecureView(boolean useSecureView) { - if (useSecureView != this.useSecureView) { - this.useSecureView = useSecureView; - updateSurfaceView(); - } - } - public void setHideShutterView(boolean hideShutterView) { this.hideShutterView = hideShutterView; updateShutterViewVisibility(); diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index ef6c8878..98c02ae9 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -589,6 +589,10 @@ public class ReactExoplayerView extends FrameLayout implements } } + public void setViewType(int viewType) { + exoPlayerView.updateSurfaceView(viewType); + } + private class RNVLoadControl extends DefaultLoadControl { private final int availableHeapInBytes; private final Runtime runtime; @@ -2243,15 +2247,6 @@ public class ReactExoplayerView extends FrameLayout implements updateFullScreenButtonVisibility(); } - public void setUseTextureView(boolean useTextureView) { - boolean finallyUseTextureView = useTextureView && drmProps == null; - exoPlayerView.setUseTextureView(finallyUseTextureView); - } - - public void useSecureView(boolean useSecureView) { - exoPlayerView.useSecureView(useSecureView); - } - public void setHideShutterView(boolean hideShutterView) { exoPlayerView.setHideShutterView(hideShutterView); } diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index f23ea548..af8e4a51 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -17,6 +17,7 @@ import com.brentvatne.common.api.ResizeMode; import com.brentvatne.common.api.SideLoadedTextTrackList; import com.brentvatne.common.api.Source; import com.brentvatne.common.api.SubtitleStyle; +import com.brentvatne.common.api.ViewType; import com.brentvatne.common.react.VideoEventEmitter; import com.brentvatne.common.toolbox.DebugLog; import com.brentvatne.common.toolbox.ReactBridgeUtils; @@ -69,8 +70,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager [!WARNING] +> deprecated, use viewType instead + Force the output to a SurfaceView and enables the secure surface. @@ -899,8 +902,13 @@ SurfaceView is is the only one that can be labeled as secure. - **true** - Use security - **false (default)** - Do not use security + + ### `useTextureView` +> [!WARNING] +> deprecated, use viewType instead + Controls whether to output to a TextureView or SurfaceView. @@ -915,6 +923,18 @@ useTextureView can only be set at same time you're setting the source. - **true (default)** - Use a TextureView - **false** - Use a SurfaceView +### `viewType` + + + +Allow to explicitly specify view type. +This flag replace `useSecureView` and `useTextureView` fields. +There are 3 available values: +- 'textureView': The video is rendered in a texture view. it allows mapping the view on a texture (useful for 3D). +DRM playback is not supported on textureView, if drm prop is provided, the suface will be transformed to a SurfaceView. +- 'surfaceView' (default): The video is rendered in a surface. take less resources to be rendered. +- 'secureView': The video is rendered in a surface which disallow taking screenshot of the video + ### `volume` diff --git a/src/Video.tsx b/src/Video.tsx index fbad49c5..f6a0016d 100644 --- a/src/Video.tsx +++ b/src/Video.tsx @@ -44,11 +44,12 @@ import { resolveAssetSourceForVideo, } from './utils'; import {VideoManager} from './specs/VideoNativeComponent'; -import type { - OnLoadData, - OnTextTracksData, - OnReceiveAdEventData, - ReactVideoProps, +import { + type OnLoadData, + type OnTextTracksData, + type OnReceiveAdEventData, + type ReactVideoProps, + ViewType, } from './types'; export type VideoSaveData = { @@ -84,6 +85,9 @@ const Video = forwardRef( selectedVideoTrack, selectedAudioTrack, selectedTextTrack, + useTextureView, + useSecureView, + viewType, onLoadStart, onLoad, onError, @@ -571,6 +575,37 @@ const Video = forwardRef( ], ); + const _viewType = useMemo(() => { + const hasValidDrmProp = + drm !== undefined && Object.keys(drm).length !== 0; + + const shallForceViewType = + hasValidDrmProp && (viewType === ViewType.TEXTURE || useTextureView); + + if (shallForceViewType) { + console.warn( + 'cannot use DRM on texture view. please set useTextureView={false}', + ); + } + if (useSecureView && useTextureView) { + console.warn( + 'cannot use SecureView on texture view. please set useTextureView={false}', + ); + } + + return shallForceViewType + ? useSecureView + ? ViewType.SURFACE_SECURE + : ViewType.SURFACE // check if we should force the type to Surface due to DRM + : viewType + ? viewType // else use ViewType from source + : useSecureView // else infer view type from useSecureView and useTextureView + ? ViewType.SURFACE_SECURE + : useTextureView + ? ViewType.TEXTURE + : ViewType.SURFACE; + }, [drm, useSecureView, useTextureView, viewType]); + return ( ( onControlsVisibilityChange={ onControlsVisibilityChange ? _onControlsVisibilityChange : undefined } + viewType={_viewType} /> {hasPoster && showPoster ? ( diff --git a/src/specs/VideoNativeComponent.ts b/src/specs/VideoNativeComponent.ts index a64dbb73..107b717d 100644 --- a/src/specs/VideoNativeComponent.ts +++ b/src/specs/VideoNativeComponent.ts @@ -337,8 +337,7 @@ export interface VideoNativeProps extends ViewProps { minLoadRetryCount?: Int32; // Android reportBandwidth?: boolean; //Android subtitleStyle?: SubtitleStyle; // android - useTextureView?: boolean; // Android - useSecureView?: boolean; // Android + viewType?: Int32; // Android bufferingStrategy?: BufferingStrategyType; // Android controlsStyles?: ControlsStyles; // Android onControlsVisibilityChange?: DirectEventHandler; diff --git a/src/types/ViewType.ts b/src/types/ViewType.ts new file mode 100644 index 00000000..34e6a419 --- /dev/null +++ b/src/types/ViewType.ts @@ -0,0 +1,11 @@ +/** + * Define Available view type for android + * these values shall match android spec, see ViewType.kt + */ +enum ResizeMode { + TEXTURE = 0, + SURFACE = 1, + SURFACE_SECURE = 2, +} + +export default ResizeMode; diff --git a/src/types/index.ts b/src/types/index.ts index 5742eac0..ab7cf42d 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -5,5 +5,6 @@ export * from './language'; export {default as Orientation} from './Orientation'; export {default as ResizeMode} from './ResizeMode'; export {default as TextTrackType} from './TextTrackType'; +export {default as ViewType} from './ViewType'; export * from './video'; export * from '../specs/VideoNativeComponent'; diff --git a/src/types/video.ts b/src/types/video.ts index 1128ce7b..c4805390 100644 --- a/src/types/video.ts +++ b/src/types/video.ts @@ -3,6 +3,7 @@ import type {ReactVideoEvents} from './events'; import type {StyleProp, ViewProps, ViewStyle} from 'react-native'; import type VideoResizeMode from './ResizeMode'; import type FilterType from './FilterType'; +import type ViewType from './ViewType'; export type Headers = Record; @@ -256,8 +257,9 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps { shutterColor?: string; // Android textTracks?: TextTracks; testID?: string; - useTextureView?: boolean; // Android - useSecureView?: boolean; // Android + viewType?: ViewType; + useTextureView?: boolean; // Android // deprecated + useSecureView?: boolean; // Android // deprecated volume?: number; localSourceEncryptionKeyScheme?: string; debug?: DebugConfig;