react-native-video/src/Video.tsx

623 lines
18 KiB
TypeScript
Raw Normal View History

import React, {
useState,
useCallback,
useMemo,
useRef,
forwardRef,
useImperativeHandle,
type ComponentRef,
} from 'react';
import {
View,
StyleSheet,
Image,
Platform,
type StyleProp,
type ImageStyle,
type NativeSyntheticEvent,
} from 'react-native';
import NativeVideoComponent, {
Fabric (New Architecture) codegen support (#3487) * feat: implemented codegenConfig on package.json * chore: moved directory location of Fabric component * fix: typefix FabricExample * chore: pod instaslled FabricExample iOS app * feat: implemented codegen config on package.json * feat: implemented codegen of specs/VideoNativeComponent * chore: removed not using type Filter * feat: removed unnecessary export on codegen tyepes * Revert "feat: removed unnecessary export on codegen tyepes" This reverts commit fc243b0ac5c565eda4886cd865c32ba4e812d7ff. * refactor: fixed types on Video component and modified types with codegen types * feat: modified codegenNativeComponent naming (RCTVideo) * feat: pod installed example basic app * feat: bump up react-native dev dependency version to 0.73.2 for supporting codegen array event params * feat: support array param types on event callback function codegen types * chore: pod installed ios basic example * feat: modified source prop as optional type * feat: add original src/VideoComponent.ts again * Revert "feat: add original src/VideoComponent.ts again" This reverts commit d63ac94e5330f7c7fb50374f65f8f3f4e0a225d7. * feat: add original src/VideoComponent.ts again with original file name * feat: git rm src/specs/VideoNativeComponent.ts * feat: git mv VideoNativeComponent.ts * feat: git mv src/specs/VideoNativeComponent.ts * feat: git mv src/VideoNativeComponent.ts src/specs/VideoNativeComponent.ts * feat: implemented array type handling on android JAVA * feat: updated iOS requestHeaders parsing native * feat: use safeGetArray on android, removed not using import too * feat: temporary commit - reusing enum types for remaining docs types * feat: implemented mixed type of SelectedTrack.value for JS layer
2024-03-07 03:35:17 -07:00
type OnAudioFocusChangedData,
type OnAudioTracksData,
type OnBandwidthUpdateData,
type OnBufferData,
type OnExternalPlaybackChangeData,
type OnGetLicenseData,
type OnLoadStartData,
type OnPictureInPictureStatusChangedData,
type OnPlaybackStateChangedData,
type OnProgressData,
type OnSeekData,
type OnTextTrackDataChangedData,
type OnTimedMetadataData,
type OnVideoAspectRatioData,
type OnVideoErrorData,
type OnVideoTracksData,
type VideoComponentType,
Fabric (New Architecture) codegen support (#3487) * feat: implemented codegenConfig on package.json * chore: moved directory location of Fabric component * fix: typefix FabricExample * chore: pod instaslled FabricExample iOS app * feat: implemented codegen config on package.json * feat: implemented codegen of specs/VideoNativeComponent * chore: removed not using type Filter * feat: removed unnecessary export on codegen tyepes * Revert "feat: removed unnecessary export on codegen tyepes" This reverts commit fc243b0ac5c565eda4886cd865c32ba4e812d7ff. * refactor: fixed types on Video component and modified types with codegen types * feat: modified codegenNativeComponent naming (RCTVideo) * feat: pod installed example basic app * feat: bump up react-native dev dependency version to 0.73.2 for supporting codegen array event params * feat: support array param types on event callback function codegen types * chore: pod installed ios basic example * feat: modified source prop as optional type * feat: add original src/VideoComponent.ts again * Revert "feat: add original src/VideoComponent.ts again" This reverts commit d63ac94e5330f7c7fb50374f65f8f3f4e0a225d7. * feat: add original src/VideoComponent.ts again with original file name * feat: git rm src/specs/VideoNativeComponent.ts * feat: git mv VideoNativeComponent.ts * feat: git mv src/specs/VideoNativeComponent.ts * feat: git mv src/VideoNativeComponent.ts src/specs/VideoNativeComponent.ts * feat: implemented array type handling on android JAVA * feat: updated iOS requestHeaders parsing native * feat: use safeGetArray on android, removed not using import too * feat: temporary commit - reusing enum types for remaining docs types * feat: implemented mixed type of SelectedTrack.value for JS layer
2024-03-07 03:35:17 -07:00
type VideoSrc,
} from './specs/VideoNativeComponent';
import {
generateHeaderForNative,
getReactTag,
resolveAssetSourceForVideo,
} from './utils';
import {VideoManager} from './specs/VideoNativeComponent';
import type {
OnLoadData,
OnTextTracksData,
OnReceiveAdEventData,
ReactVideoProps,
} from './types';
export type VideoSaveData = {
uri: string;
};
export interface VideoRef {
seek: (time: number, tolerance?: number) => void;
resume: () => void;
pause: () => void;
presentFullscreenPlayer: () => void;
dismissFullscreenPlayer: () => void;
restoreUserInterfaceForPictureInPictureStopCompleted: (
restore: boolean,
) => void;
save: (options: object) => Promise<VideoSaveData>;
setVolume: (volume: number) => void;
getCurrentPosition: () => Promise<number>;
}
const Video = forwardRef<VideoRef, ReactVideoProps>(
(
{
source,
style,
resizeMode,
posterResizeMode,
poster,
fullscreen,
drm,
textTracks,
2023-10-11 14:15:58 -06:00
selectedVideoTrack,
selectedAudioTrack,
selectedTextTrack,
onLoadStart,
onLoad,
onError,
onProgress,
onSeek,
onEnd,
onBuffer,
onBandwidthUpdate,
onExternalPlaybackChange,
onFullscreenPlayerWillPresent,
onFullscreenPlayerDidPresent,
onFullscreenPlayerWillDismiss,
onFullscreenPlayerDidDismiss,
onReadyForDisplay,
onPlaybackRateChange,
onVolumeChange,
onAudioBecomingNoisy,
onPictureInPictureStatusChanged,
onRestoreUserInterfaceForPictureInPictureStop,
onReceiveAdEvent,
onPlaybackStateChanged,
onAudioFocusChanged,
onIdle,
onTimedMetadata,
onAudioTracks,
onTextTracks,
onTextTrackDataChanged,
onVideoTracks,
onAspectRatio,
...rest
},
ref,
) => {
const nativeRef = useRef<ComponentRef<VideoComponentType>>(null);
const [showPoster, setShowPoster] = useState(!!poster);
const [isFullscreen, setIsFullscreen] = useState(fullscreen);
const [
_restoreUserInterfaceForPIPStopCompletionHandler,
setRestoreUserInterfaceForPIPStopCompletionHandler,
] = useState<boolean | undefined>();
const hasPoster = !!poster;
const posterStyle = useMemo<StyleProp<ImageStyle>>(
() => ({
...StyleSheet.absoluteFillObject,
resizeMode:
posterResizeMode && posterResizeMode !== 'none'
? posterResizeMode
: 'contain',
}),
[posterResizeMode],
);
Fabric (New Architecture) codegen support (#3487) * feat: implemented codegenConfig on package.json * chore: moved directory location of Fabric component * fix: typefix FabricExample * chore: pod instaslled FabricExample iOS app * feat: implemented codegen config on package.json * feat: implemented codegen of specs/VideoNativeComponent * chore: removed not using type Filter * feat: removed unnecessary export on codegen tyepes * Revert "feat: removed unnecessary export on codegen tyepes" This reverts commit fc243b0ac5c565eda4886cd865c32ba4e812d7ff. * refactor: fixed types on Video component and modified types with codegen types * feat: modified codegenNativeComponent naming (RCTVideo) * feat: pod installed example basic app * feat: bump up react-native dev dependency version to 0.73.2 for supporting codegen array event params * feat: support array param types on event callback function codegen types * chore: pod installed ios basic example * feat: modified source prop as optional type * feat: add original src/VideoComponent.ts again * Revert "feat: add original src/VideoComponent.ts again" This reverts commit d63ac94e5330f7c7fb50374f65f8f3f4e0a225d7. * feat: add original src/VideoComponent.ts again with original file name * feat: git rm src/specs/VideoNativeComponent.ts * feat: git mv VideoNativeComponent.ts * feat: git mv src/specs/VideoNativeComponent.ts * feat: git mv src/VideoNativeComponent.ts src/specs/VideoNativeComponent.ts * feat: implemented array type handling on android JAVA * feat: updated iOS requestHeaders parsing native * feat: use safeGetArray on android, removed not using import too * feat: temporary commit - reusing enum types for remaining docs types * feat: implemented mixed type of SelectedTrack.value for JS layer
2024-03-07 03:35:17 -07:00
const src = useMemo<VideoSrc | undefined>(() => {
if (!source) {
return undefined;
}
const resolvedSource = resolveAssetSourceForVideo(source);
let uri = resolvedSource.uri || '';
if (uri && uri.match(/^\//)) {
uri = `file://${uri}`;
}
if (!uri) {
console.log('Trying to load empty source');
}
const isNetwork = !!(uri && uri.match(/^(rtp|rtsp|http|https):/));
const isAsset = !!(
uri &&
uri.match(
/^(assets-library|ipod-library|file|content|ms-appx|ms-appdata):/,
)
);
return {
uri,
isNetwork,
isAsset,
shouldCache: resolvedSource.shouldCache || false,
type: resolvedSource.type || '',
mainVer: resolvedSource.mainVer || 0,
patchVer: resolvedSource.patchVer || 0,
Fabric (New Architecture) codegen support (#3487) * feat: implemented codegenConfig on package.json * chore: moved directory location of Fabric component * fix: typefix FabricExample * chore: pod instaslled FabricExample iOS app * feat: implemented codegen config on package.json * feat: implemented codegen of specs/VideoNativeComponent * chore: removed not using type Filter * feat: removed unnecessary export on codegen tyepes * Revert "feat: removed unnecessary export on codegen tyepes" This reverts commit fc243b0ac5c565eda4886cd865c32ba4e812d7ff. * refactor: fixed types on Video component and modified types with codegen types * feat: modified codegenNativeComponent naming (RCTVideo) * feat: pod installed example basic app * feat: bump up react-native dev dependency version to 0.73.2 for supporting codegen array event params * feat: support array param types on event callback function codegen types * chore: pod installed ios basic example * feat: modified source prop as optional type * feat: add original src/VideoComponent.ts again * Revert "feat: add original src/VideoComponent.ts again" This reverts commit d63ac94e5330f7c7fb50374f65f8f3f4e0a225d7. * feat: add original src/VideoComponent.ts again with original file name * feat: git rm src/specs/VideoNativeComponent.ts * feat: git mv VideoNativeComponent.ts * feat: git mv src/specs/VideoNativeComponent.ts * feat: git mv src/VideoNativeComponent.ts src/specs/VideoNativeComponent.ts * feat: implemented array type handling on android JAVA * feat: updated iOS requestHeaders parsing native * feat: use safeGetArray on android, removed not using import too * feat: temporary commit - reusing enum types for remaining docs types * feat: implemented mixed type of SelectedTrack.value for JS layer
2024-03-07 03:35:17 -07:00
requestHeaders: generateHeaderForNative(resolvedSource.headers),
startPosition: resolvedSource.startPosition ?? -1,
cropStart: resolvedSource.cropStart || 0,
cropEnd: resolvedSource.cropEnd,
metadata: resolvedSource.metadata,
};
}, [source]);
const _drm = useMemo(() => {
if (!drm) {
return;
}
2023-10-11 14:15:58 -06:00
return {
2023-10-11 14:15:58 -06:00
type: drm.type,
licenseServer: drm.licenseServer,
Fabric (New Architecture) codegen support (#3487) * feat: implemented codegenConfig on package.json * chore: moved directory location of Fabric component * fix: typefix FabricExample * chore: pod instaslled FabricExample iOS app * feat: implemented codegen config on package.json * feat: implemented codegen of specs/VideoNativeComponent * chore: removed not using type Filter * feat: removed unnecessary export on codegen tyepes * Revert "feat: removed unnecessary export on codegen tyepes" This reverts commit fc243b0ac5c565eda4886cd865c32ba4e812d7ff. * refactor: fixed types on Video component and modified types with codegen types * feat: modified codegenNativeComponent naming (RCTVideo) * feat: pod installed example basic app * feat: bump up react-native dev dependency version to 0.73.2 for supporting codegen array event params * feat: support array param types on event callback function codegen types * chore: pod installed ios basic example * feat: modified source prop as optional type * feat: add original src/VideoComponent.ts again * Revert "feat: add original src/VideoComponent.ts again" This reverts commit d63ac94e5330f7c7fb50374f65f8f3f4e0a225d7. * feat: add original src/VideoComponent.ts again with original file name * feat: git rm src/specs/VideoNativeComponent.ts * feat: git mv VideoNativeComponent.ts * feat: git mv src/specs/VideoNativeComponent.ts * feat: git mv src/VideoNativeComponent.ts src/specs/VideoNativeComponent.ts * feat: implemented array type handling on android JAVA * feat: updated iOS requestHeaders parsing native * feat: use safeGetArray on android, removed not using import too * feat: temporary commit - reusing enum types for remaining docs types * feat: implemented mixed type of SelectedTrack.value for JS layer
2024-03-07 03:35:17 -07:00
headers: generateHeaderForNative(drm.headers),
contentId: drm.contentId,
certificateUrl: drm.certificateUrl,
base64Certificate: drm.base64Certificate,
useExternalGetLicense: !!drm.getLicense,
};
}, [drm]);
const _selectedTextTrack = useMemo(() => {
if (!selectedTextTrack) {
return;
}
const type = typeof selectedTextTrack.value;
if (type !== 'number' && type !== 'string') {
console.log('invalid type provided to selectedTextTrack');
return;
}
return {
2023-10-11 14:15:58 -06:00
type: selectedTextTrack?.type,
value: `${selectedTextTrack.value}`,
};
}, [selectedTextTrack]);
const _selectedAudioTrack = useMemo(() => {
if (!selectedAudioTrack) {
return;
}
const type = typeof selectedAudioTrack.value;
if (type !== 'number' && type !== 'string') {
console.log('invalid type provided to selectedAudioTrack');
return;
}
2023-10-11 14:15:58 -06:00
return {
2023-10-11 14:15:58 -06:00
type: selectedAudioTrack?.type,
value: `${selectedAudioTrack.value}`,
};
}, [selectedAudioTrack]);
2023-10-11 14:15:58 -06:00
const _selectedVideoTrack = useMemo(() => {
if (!selectedVideoTrack) {
return;
}
const type = typeof selectedVideoTrack.value;
if (type !== 'number' && type !== 'string') {
console.log('invalid type provided to selectedVideoTrack');
return;
}
2023-10-11 14:15:58 -06:00
return {
type: selectedVideoTrack?.type,
value: `${selectedVideoTrack.value}`,
2023-10-11 14:15:58 -06:00
};
}, [selectedVideoTrack]);
const seek = useCallback(async (time: number, tolerance?: number) => {
if (isNaN(time) || time === null) {
throw new Error("Specified time is not a number: '" + time + "'");
}
if (!nativeRef.current) {
console.warn('Video Component is not mounted');
return;
}
const callSeekFunction = () => {
VideoManager.seek(
{
time,
tolerance: tolerance || 0,
},
getReactTag(nativeRef),
);
};
Platform.select({
ios: callSeekFunction,
android: callSeekFunction,
default: () => {
// TODO: Implement VideoManager.seek for windows
nativeRef.current?.setNativeProps({seek: time});
},
})();
}, []);
const presentFullscreenPlayer = useCallback(() => {
setIsFullscreen(true);
}, [setIsFullscreen]);
const dismissFullscreenPlayer = useCallback(() => {
setIsFullscreen(false);
}, [setIsFullscreen]);
const save = useCallback((options: object) => {
// VideoManager.save can be null on android & windows
return VideoManager.save?.(options, getReactTag(nativeRef));
}, []);
const pause = useCallback(() => {
return VideoManager.setPlayerPauseState(true, getReactTag(nativeRef));
}, []);
const resume = useCallback(() => {
return VideoManager.setPlayerPauseState(false, getReactTag(nativeRef));
}, []);
const restoreUserInterfaceForPictureInPictureStopCompleted = useCallback(
(restored: boolean) => {
setRestoreUserInterfaceForPIPStopCompletionHandler(restored);
},
[setRestoreUserInterfaceForPIPStopCompletionHandler],
);
const setVolume = useCallback((volume: number) => {
return VideoManager.setVolume(volume, getReactTag(nativeRef));
}, []);
const getCurrentPosition = useCallback(() => {
return VideoManager.getCurrentPosition(getReactTag(nativeRef));
}, []);
const onVideoLoadStart = useCallback(
(e: NativeSyntheticEvent<OnLoadStartData>) => {
hasPoster && setShowPoster(true);
onLoadStart?.(e.nativeEvent);
},
[hasPoster, onLoadStart],
);
const onVideoLoad = useCallback(
(e: NativeSyntheticEvent<OnLoadData>) => {
if (Platform.OS === 'windows') {
hasPoster && setShowPoster(false);
}
onLoad?.(e.nativeEvent);
},
[onLoad, hasPoster, setShowPoster],
);
const onVideoError = useCallback(
(e: NativeSyntheticEvent<OnVideoErrorData>) => {
onError?.(e.nativeEvent);
},
[onError],
);
const onVideoProgress = useCallback(
(e: NativeSyntheticEvent<OnProgressData>) => {
onProgress?.(e.nativeEvent);
},
[onProgress],
);
const onVideoSeek = useCallback(
(e: NativeSyntheticEvent<OnSeekData>) => {
onSeek?.(e.nativeEvent);
},
[onSeek],
);
const onVideoPlaybackStateChanged = useCallback(
(e: NativeSyntheticEvent<OnPlaybackStateChangedData>) => {
onPlaybackStateChanged?.(e.nativeEvent);
},
[onPlaybackStateChanged],
);
// android only
const _onTimedMetadata = useCallback(
(e: NativeSyntheticEvent<OnTimedMetadataData>) => {
onTimedMetadata?.(e.nativeEvent);
},
[onTimedMetadata],
);
const _onAudioTracks = useCallback(
(e: NativeSyntheticEvent<OnAudioTracksData>) => {
onAudioTracks?.(e.nativeEvent);
},
[onAudioTracks],
);
const _onTextTracks = useCallback(
(e: NativeSyntheticEvent<OnTextTracksData>) => {
onTextTracks?.(e.nativeEvent);
},
[onTextTracks],
);
const _onTextTrackDataChanged = useCallback(
(
e: NativeSyntheticEvent<OnTextTrackDataChangedData & {target?: number}>,
) => {
const {...eventData} = e.nativeEvent;
delete eventData.target;
onTextTrackDataChanged?.(eventData as OnTextTrackDataChangedData);
},
[onTextTrackDataChanged],
);
const _onVideoTracks = useCallback(
(e: NativeSyntheticEvent<OnVideoTracksData>) => {
onVideoTracks?.(e.nativeEvent);
},
[onVideoTracks],
);
const _onPlaybackRateChange = useCallback(
(e: NativeSyntheticEvent<Readonly<{playbackRate: number}>>) => {
onPlaybackRateChange?.(e.nativeEvent);
},
[onPlaybackRateChange],
);
const _onVolumeChange = useCallback(
(e: NativeSyntheticEvent<Readonly<{volume: number}>>) => {
onVolumeChange?.(e.nativeEvent);
},
[onVolumeChange],
);
const _onReadyForDisplay = useCallback(() => {
hasPoster && setShowPoster(false);
onReadyForDisplay?.();
}, [setShowPoster, hasPoster, onReadyForDisplay]);
const _onPictureInPictureStatusChanged = useCallback(
(e: NativeSyntheticEvent<OnPictureInPictureStatusChangedData>) => {
onPictureInPictureStatusChanged?.(e.nativeEvent);
},
[onPictureInPictureStatusChanged],
);
const _onAudioFocusChanged = useCallback(
(e: NativeSyntheticEvent<OnAudioFocusChangedData>) => {
onAudioFocusChanged?.(e.nativeEvent);
},
[onAudioFocusChanged],
);
const onVideoBuffer = useCallback(
(e: NativeSyntheticEvent<OnBufferData>) => {
onBuffer?.(e.nativeEvent);
},
[onBuffer],
);
const onVideoExternalPlaybackChange = useCallback(
(e: NativeSyntheticEvent<OnExternalPlaybackChangeData>) => {
onExternalPlaybackChange?.(e.nativeEvent);
},
[onExternalPlaybackChange],
);
const _onBandwidthUpdate = useCallback(
(e: NativeSyntheticEvent<OnBandwidthUpdateData>) => {
onBandwidthUpdate?.(e.nativeEvent);
},
[onBandwidthUpdate],
);
const _onReceiveAdEvent = useCallback(
(e: NativeSyntheticEvent<OnReceiveAdEventData>) => {
onReceiveAdEvent?.(e.nativeEvent);
},
[onReceiveAdEvent],
);
const _onVideoAspectRatio = useCallback(
(e: NativeSyntheticEvent<OnVideoAspectRatioData>) => {
onAspectRatio?.(e.nativeEvent);
},
[onAspectRatio],
);
const useExternalGetLicense = drm?.getLicense instanceof Function;
const onGetLicense = useCallback(
(event: NativeSyntheticEvent<OnGetLicenseData>) => {
if (useExternalGetLicense) {
const data = event.nativeEvent;
if (data && data.spcBase64) {
const getLicenseOverride = drm.getLicense(
data.spcBase64,
data.contentId,
data.licenseUrl,
data.loadedLicenseUrl,
);
const getLicensePromise = Promise.resolve(getLicenseOverride); // Handles both scenarios, getLicenseOverride being a promise and not.
getLicensePromise
.then((result) => {
if (result !== undefined) {
nativeRef.current &&
VideoManager.setLicenseResult(
result,
data.loadedLicenseUrl,
getReactTag(nativeRef),
);
} else {
nativeRef.current &&
VideoManager.setLicenseResultError(
'Empty license result',
data.loadedLicenseUrl,
getReactTag(nativeRef),
);
}
})
.catch(() => {
nativeRef.current &&
VideoManager.setLicenseResultError(
'fetch error',
data.loadedLicenseUrl,
getReactTag(nativeRef),
);
});
} else {
VideoManager.setLicenseResultError(
'No spc received',
data.loadedLicenseUrl,
getReactTag(nativeRef),
);
}
}
},
[drm, useExternalGetLicense],
);
useImperativeHandle(
ref,
() => ({
seek,
presentFullscreenPlayer,
dismissFullscreenPlayer,
save,
pause,
resume,
restoreUserInterfaceForPictureInPictureStopCompleted,
setVolume,
getCurrentPosition,
}),
[
seek,
presentFullscreenPlayer,
dismissFullscreenPlayer,
save,
pause,
resume,
restoreUserInterfaceForPictureInPictureStopCompleted,
setVolume,
getCurrentPosition,
],
);
return (
<View style={style}>
<NativeVideoComponent
ref={nativeRef}
{...rest}
src={src}
drm={_drm}
style={StyleSheet.absoluteFill}
resizeMode={resizeMode}
fullscreen={isFullscreen}
restoreUserInterfaceForPIPStopCompletionHandler={
_restoreUserInterfaceForPIPStopCompletionHandler
}
textTracks={textTracks}
selectedTextTrack={_selectedTextTrack}
selectedAudioTrack={_selectedAudioTrack}
2023-10-11 14:15:58 -06:00
selectedVideoTrack={_selectedVideoTrack}
onGetLicense={useExternalGetLicense ? onGetLicense : undefined}
onVideoLoad={
onLoad || hasPoster
? (onVideoLoad as (e: NativeSyntheticEvent<object>) => void)
: undefined
}
onVideoLoadStart={
onLoadStart || hasPoster ? onVideoLoadStart : undefined
}
onVideoError={onError ? onVideoError : undefined}
onVideoProgress={onProgress ? onVideoProgress : undefined}
onVideoSeek={onSeek ? onVideoSeek : undefined}
onVideoEnd={onEnd}
onVideoBuffer={onBuffer ? onVideoBuffer : undefined}
onVideoPlaybackStateChanged={
onPlaybackStateChanged ? onVideoPlaybackStateChanged : undefined
}
onVideoBandwidthUpdate={
onBandwidthUpdate ? _onBandwidthUpdate : undefined
}
onTimedMetadata={onTimedMetadata ? _onTimedMetadata : undefined}
onAudioTracks={onAudioTracks ? _onAudioTracks : undefined}
onTextTracks={onTextTracks ? _onTextTracks : undefined}
onTextTrackDataChanged={
onTextTrackDataChanged ? _onTextTrackDataChanged : undefined
}
onVideoTracks={onVideoTracks ? _onVideoTracks : undefined}
onVideoFullscreenPlayerDidDismiss={onFullscreenPlayerDidDismiss}
onVideoFullscreenPlayerDidPresent={onFullscreenPlayerDidPresent}
onVideoFullscreenPlayerWillDismiss={onFullscreenPlayerWillDismiss}
onVideoFullscreenPlayerWillPresent={onFullscreenPlayerWillPresent}
onVideoExternalPlaybackChange={
onExternalPlaybackChange ? onVideoExternalPlaybackChange : undefined
}
onVideoIdle={onIdle}
onAudioFocusChanged={
onAudioFocusChanged ? _onAudioFocusChanged : undefined
}
onReadyForDisplay={
onReadyForDisplay || hasPoster ? _onReadyForDisplay : undefined
}
onPlaybackRateChange={
onPlaybackRateChange ? _onPlaybackRateChange : undefined
}
onVolumeChange={onVolumeChange ? _onVolumeChange : undefined}
onVideoAudioBecomingNoisy={onAudioBecomingNoisy}
onPictureInPictureStatusChanged={
onPictureInPictureStatusChanged
? _onPictureInPictureStatusChanged
: undefined
}
onRestoreUserInterfaceForPictureInPictureStop={
onRestoreUserInterfaceForPictureInPictureStop
}
onVideoAspectRatio={onAspectRatio ? _onVideoAspectRatio : undefined}
onReceiveAdEvent={
onReceiveAdEvent
? (_onReceiveAdEvent as (e: NativeSyntheticEvent<object>) => void)
: undefined
}
/>
{hasPoster && showPoster ? (
<Image style={posterStyle} source={{uri: poster}} />
) : null}
</View>
);
},
);
Video.displayName = 'Video';
export default Video;