Merge branch 'master' into fix-memleak

This commit is contained in:
Olivier Bouillet 2023-08-03 20:53:12 +02:00 committed by GitHub
commit 236d17e8b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 80 additions and 72 deletions

View File

@ -10,37 +10,24 @@ assignees: ''
# Bug # Bug
<!-- <!--
Before opening a ticket Very important, before opening a ticket:
* Ensure the issue has not been already reported 1) Ensure the issue has not been already reported
* Please test using the latest release of the library, as maybe said bug has been already fixed. 2) lease test using the latest release (including 6.0.0 preRelease) of the library, as maybe the bug has been already fixed.
* Provide a clear and concise description of what the bug is. 3) please don't use emulator to reproduce issues. if you have strange or sporadic error check if this is not devices specific (understand that this library is just a binding to player).
* If the library has multiple install methods, describe installation method (e.g., pod, not pod, with jetifier etc) 4) ensure you cannot solve the issue by yourself using following guide: https://github.com/react-native-video/react-native-video/blob/master/docs/DEBUGGING.md
* Include screenshots if needed.
--> -->
## Platform ## Platform
<!--
Platform where your bug is happening.
-->
Which player are you experiencing the problem on: Which player are you experiencing the problem on:
* iOS * iOS
* Android * Android
* Windows UWP * Windows
* Windows WPF
## Environment info ## Environment info
<!-- <!-- This fields are mandatory -->
Run `react-native info` in your terminal and copy the results here. Also, include the *precise* version number of this library that you are using in the project
-->
React native info output:
```bash
// paste it here
```
Library version: x.x.x Library version: x.x.x
Device:
## Steps To Reproduce ## Steps To Reproduce

View File

@ -2,6 +2,7 @@
### Version 6.0.0-alpha.7 ### Version 6.0.0-alpha.7
- Android: Fix memory leaks from AudioManager [#3123](https://github.com/react-native-video/react-native-video/pull/3123) - Android: Fix memory leaks from AudioManager [#3123](https://github.com/react-native-video/react-native-video/pull/3123)
- Android: Fixed syntax error [#3182](https://github.com/react-native-video/react-native-video/issues/3182)
### Version 6.0.0-alpha.6 ### Version 6.0.0-alpha.6
- Feature: Video range support [#3030](https://github.com/react-native-video/react-native-video/pull/3030) - Feature: Video range support [#3030](https://github.com/react-native-video/react-native-video/pull/3030)

View File

@ -77,7 +77,7 @@ export default class Video extends Component {
this.setNativeProps({ fullscreen: false }); this.setNativeProps({ fullscreen: false });
}; };
save = async (options?) => { save = async (options) => {
return await NativeModules.VideoManager.save(options, findNodeHandle(this._root)); return await NativeModules.VideoManager.save(options, findNodeHandle(this._root));
} }
@ -416,13 +416,6 @@ Video.propTypes = {
FilterType.SEPIA, FilterType.SEPIA,
]), ]),
filterEnabled: PropTypes.bool, filterEnabled: PropTypes.bool,
/* Native only */
src: PropTypes.object,
seek: PropTypes.oneOfType([
PropTypes.number,
PropTypes.object,
]),
fullscreen: PropTypes.bool,
onVideoLoadStart: PropTypes.func, onVideoLoadStart: PropTypes.func,
onVideoLoad: PropTypes.func, onVideoLoad: PropTypes.func,
onVideoBuffer: PropTypes.func, onVideoBuffer: PropTypes.func,
@ -566,10 +559,4 @@ Video.propTypes = {
...ViewPropTypes, ...ViewPropTypes,
}; };
const RCTVideo = requireNativeComponent('RCTVideo', Video, { const RCTVideo = requireNativeComponent('RCTVideo');
nativeOnly: {
src: true,
seek: true,
fullscreen: true,
},
});

View File

@ -17,6 +17,7 @@ def configStringPath = (
).md5() ).md5()
android { android {
namespace 'com.brentvatne.react'
compileSdkVersion safeExtGet('compileSdkVersion', 31) compileSdkVersion safeExtGet('compileSdkVersion', 31)
buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2') buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')

View File

@ -14,27 +14,27 @@
android:paddingTop="4dp" android:paddingTop="4dp"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageButton android:id="@id/exo_prev" <ImageButton android:id="@+id/exo_prev"
style="@style/ExoMediaButton.Previous"/> style="@style/ExoMediaButton.Previous"/>
<ImageButton android:id="@id/exo_rew" <ImageButton android:id="@+id/exo_rew"
style="@style/ExoMediaButton.Rewind"/> style="@style/ExoMediaButton.Rewind"/>
<FrameLayout <FrameLayout
android:id="@+id/exo_play_pause_container" android:id="@+id/exo_play_pause_container"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center"> android:layout_gravity="center">
<ImageButton android:id="@id/exo_play" <ImageButton android:id="@+id/exo_play"
style="@style/ExoMediaButton.Play"/> style="@style/ExoMediaButton.Play"/>
<ImageButton android:id="@id/exo_pause" <ImageButton android:id="@+id/exo_pause"
style="@style/ExoMediaButton.Pause"/> style="@style/ExoMediaButton.Pause"/>
</FrameLayout> </FrameLayout>
<ImageButton android:id="@id/exo_ffwd" <ImageButton android:id="@+id/exo_ffwd"
style="@style/ExoMediaButton.FastForward"/> style="@style/ExoMediaButton.FastForward"/>
<ImageButton android:id="@id/exo_next" <ImageButton android:id="@+id/exo_next"
style="@style/ExoMediaButton.Next"/> style="@style/ExoMediaButton.Next"/>
</LinearLayout> </LinearLayout>
@ -46,7 +46,7 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView android:id="@id/exo_position" <TextView android:id="@+id/exo_position"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="14sp" android:textSize="14sp"
@ -57,12 +57,12 @@
android:textColor="#FFBEBEBE"/> android:textColor="#FFBEBEBE"/>
<com.google.android.exoplayer2.ui.DefaultTimeBar <com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="@id/exo_progress" android:id="@+id/exo_progress"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_weight="1" android:layout_weight="1"
android:layout_height="26dp"/> android:layout_height="26dp"/>
<TextView android:id="@id/exo_duration" <TextView android:id="@+id/exo_duration"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="14sp" android:textSize="14sp"
@ -73,7 +73,7 @@
android:textColor="#FFBEBEBE"/> android:textColor="#FFBEBEBE"/>
<ImageButton <ImageButton
android:id="@id/exo_fullscreen" android:id="@+id/exo_fullscreen"
style="@style/ExoMediaButton.FullScreen" style="@style/ExoMediaButton.FullScreen"
android:layout_width="30dp" android:layout_width="30dp"
android:layout_height="30dp" android:layout_height="30dp"

View File

@ -4,7 +4,7 @@ import GoogleInteractiveMediaAds
class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate { class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
private var _video:RCTVideo private weak var _video: RCTVideo?
/* Entry point for the SDK. Used to make ad requests. */ /* Entry point for the SDK. Used to make ad requests. */
private var adsLoader: IMAAdsLoader! private var adsLoader: IMAAdsLoader!
@ -23,6 +23,7 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
} }
func requestAds() { func requestAds() {
guard let _video = _video else {return}
// Create ad display container for ad rendering. // Create ad display container for ad rendering.
let adDisplayContainer = IMAAdDisplayContainer(adContainer: _video, viewController: _video.reactViewController()) let adDisplayContainer = IMAAdDisplayContainer(adContainer: _video, viewController: _video.reactViewController())
@ -54,6 +55,7 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
// MARK: - IMAAdsLoaderDelegate // MARK: - IMAAdsLoaderDelegate
func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) { func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
guard let _video = _video else {return}
// Grab the instance of the IMAAdsManager and set yourself as the delegate. // Grab the instance of the IMAAdsManager and set yourself as the delegate.
adsManager = adsLoadedData.adsManager adsManager = adsLoadedData.adsManager
adsManager?.delegate = self adsManager?.delegate = self
@ -71,12 +73,13 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
print("Error loading ads: " + adErrorData.adError.message!) print("Error loading ads: " + adErrorData.adError.message!)
} }
_video.setPaused(false) _video?.setPaused(false)
} }
// MARK: - IMAAdsManagerDelegate // MARK: - IMAAdsManagerDelegate
func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) { func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
guard let _video = _video else {return}
// Mute ad if the main player is muted // Mute ad if the main player is muted
if (_video.isMuted()) { if (_video.isMuted()) {
adsManager.volume = 0; adsManager.volume = 0;
@ -102,19 +105,19 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
} }
// Fall back to playing content // Fall back to playing content
_video.setPaused(false) _video?.setPaused(false)
} }
func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager) { func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager) {
// Pause the content for the SDK to play ads. // Pause the content for the SDK to play ads.
_video.setPaused(true) _video?.setPaused(true)
_video.setAdPlaying(true) _video?.setAdPlaying(true)
} }
func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager) { func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager) {
// Resume the content since the SDK is done playing ads (at least for now). // Resume the content since the SDK is done playing ads (at least for now).
_video.setAdPlaying(false) _video?.setAdPlaying(false)
_video.setPaused(false) _video?.setPaused(false)
} }
// MARK: - Helpers // MARK: - Helpers

View File

@ -25,7 +25,7 @@ protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc {
class RCTPlayerObserver: NSObject { class RCTPlayerObserver: NSObject {
var _handlers: RCTPlayerObserverHandler! weak var _handlers: RCTPlayerObserverHandler?
var player:AVPlayer? { var player:AVPlayer? {
willSet { willSet {
@ -84,11 +84,13 @@ class RCTPlayerObserver: NSObject {
private var _playerViewControllerOverlayFrameObserver:NSKeyValueObservation? private var _playerViewControllerOverlayFrameObserver:NSKeyValueObservation?
deinit { deinit {
if let _handlers = _handlers {
NotificationCenter.default.removeObserver(_handlers) NotificationCenter.default.removeObserver(_handlers)
} }
}
func addPlayerObservers() { func addPlayerObservers() {
guard let player = player else { guard let player = player, let _handlers = _handlers else {
return return
} }
@ -102,7 +104,7 @@ class RCTPlayerObserver: NSObject {
} }
func addPlayerItemObservers() { func addPlayerItemObservers() {
guard let playerItem = playerItem else { return } guard let playerItem = playerItem, let _handlers = _handlers else { return }
_playerItemStatusObserver = playerItem.observe(\.status, options: [.new, .old], changeHandler: _handlers.handlePlayerItemStatusChange) _playerItemStatusObserver = playerItem.observe(\.status, options: [.new, .old], changeHandler: _handlers.handlePlayerItemStatusChange)
_playerPlaybackBufferEmptyObserver = playerItem.observe(\.isPlaybackBufferEmpty, options: [.new, .old], changeHandler: _handlers.handlePlaybackBufferKeyEmpty) _playerPlaybackBufferEmptyObserver = playerItem.observe(\.isPlaybackBufferEmpty, options: [.new, .old], changeHandler: _handlers.handlePlaybackBufferKeyEmpty)
@ -118,7 +120,7 @@ class RCTPlayerObserver: NSObject {
} }
func addPlayerViewControllerObservers() { func addPlayerViewControllerObservers() {
guard let playerViewController = playerViewController else { return } guard let playerViewController = playerViewController, let _handlers = _handlers else { return }
_playerViewControllerReadyForDisplayObserver = playerViewController.observe(\.isReadyForDisplay, options: [.new], changeHandler: _handlers.handleReadyForDisplay) _playerViewControllerReadyForDisplayObserver = playerViewController.observe(\.isReadyForDisplay, options: [.new], changeHandler: _handlers.handleReadyForDisplay)
@ -131,6 +133,7 @@ class RCTPlayerObserver: NSObject {
} }
func addPlayerLayerObserver() { func addPlayerLayerObserver() {
guard let _handlers = _handlers else {return}
_playerLayerReadyForDisplayObserver = playerLayer?.observe(\.isReadyForDisplay, options: [.new], changeHandler: _handlers.handleReadyForDisplay) _playerLayerReadyForDisplayObserver = playerLayer?.observe(\.isReadyForDisplay, options: [.new], changeHandler: _handlers.handleReadyForDisplay)
} }
@ -139,6 +142,7 @@ class RCTPlayerObserver: NSObject {
} }
func addPlayerTimeObserver() { func addPlayerTimeObserver() {
guard let _handlers = _handlers else {return}
removePlayerTimeObserver() removePlayerTimeObserver()
let progressUpdateIntervalMS:Float64 = _progressUpdateInterval / 1000 let progressUpdateIntervalMS:Float64 = _progressUpdateInterval / 1000
// @see endScrubbing in AVPlayerDemoPlaybackViewController.m // @see endScrubbing in AVPlayerDemoPlaybackViewController.m
@ -174,6 +178,7 @@ class RCTPlayerObserver: NSObject {
} }
func attachPlayerEventListeners() { func attachPlayerEventListeners() {
guard let _handlers = _handlers else {return}
NotificationCenter.default.removeObserver(_handlers, NotificationCenter.default.removeObserver(_handlers,
name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, name:NSNotification.Name.AVPlayerItemDidPlayToEndTime,
@ -202,6 +207,8 @@ class RCTPlayerObserver: NSObject {
func clearPlayer() { func clearPlayer() {
player = nil player = nil
playerItem = nil playerItem = nil
if let _handlers = _handlers {
NotificationCenter.default.removeObserver(_handlers) NotificationCenter.default.removeObserver(_handlers)
} }
}
} }

View File

@ -1,5 +1,6 @@
#import <React/RCTViewManager.h> #import <React/RCTViewManager.h>
#import "RCTVideoSwiftLog.h" #import "RCTVideoSwiftLog.h"
#import "RCTEventDispatcher.h"
#if __has_include(<react-native-video/RCTVideoCache.h>) #if __has_include(<react-native-video/RCTVideoCache.h>)
#import "RCTVideoCache.h" #import "RCTVideoCache.h"

View File

@ -59,6 +59,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
private var _fullscreenAutorotate:Bool = true private var _fullscreenAutorotate:Bool = true
private var _fullscreenOrientation:String! = "all" private var _fullscreenOrientation:String! = "all"
private var _fullscreenPlayerPresented:Bool = false private var _fullscreenPlayerPresented:Bool = false
private var _fullscreenUncontrolPlayerPresented:Bool = false // to call events switching full screen mode from player controls
private var _filterName:String! private var _filterName:String!
private var _filterEnabled:Bool = false private var _filterEnabled:Bool = false
private var _presentingViewController:UIViewController? private var _presentingViewController:UIViewController?
@ -246,7 +247,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
// MARK: - Player and source // MARK: - Player and source
@objc @objc
func setSrc(_ source:NSDictionary!) { func setSrc(_ source:NSDictionary!) {
DispatchQueue.global(qos: .default).async { DispatchQueue.global(qos: .default).async { [weak self] in
guard let self = self else {return}
self._source = VideoSource(source) self._source = VideoSource(source)
if (self._source?.uri == nil || self._source?.uri == "") { if (self._source?.uri == nil || self._source?.uri == "") {
self._player?.replaceCurrentItem(with: nil) self._player?.replaceCurrentItem(with: nil)
@ -662,7 +664,13 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
self.onVideoFullscreenPlayerWillPresent?(["target": reactTag as Any]) self.onVideoFullscreenPlayerWillPresent?(["target": reactTag as Any])
if let playerViewController = _playerViewController { if let playerViewController = _playerViewController {
viewController.present(playerViewController, animated:true, completion:{ if(_controls) {
// prevents crash https://github.com/react-native-video/react-native-video/issues/3040
self._playerViewController?.removeFromParent()
}
viewController.present(playerViewController, animated:true, completion:{ [weak self] in
guard let self = self else {return}
self._playerViewController?.showsPlaybackControls = self._controls self._playerViewController?.showsPlaybackControls = self._controls
self._fullscreenPlayerPresented = fullscreen self._fullscreenPlayerPresented = fullscreen
self._playerViewController?.autorotate = self._fullscreenAutorotate self._playerViewController?.autorotate = self._fullscreenAutorotate
@ -674,8 +682,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
} }
} else if !fullscreen && _fullscreenPlayerPresented, let _playerViewController = _playerViewController { } else if !fullscreen && _fullscreenPlayerPresented, let _playerViewController = _playerViewController {
self.videoPlayerViewControllerWillDismiss(playerViewController: _playerViewController) self.videoPlayerViewControllerWillDismiss(playerViewController: _playerViewController)
_presentingViewController?.dismiss(animated: true, completion:{ _presentingViewController?.dismiss(animated: true, completion:{[weak self] in
self.videoPlayerViewControllerDidDismiss(playerViewController: _playerViewController) self?.videoPlayerViewControllerDidDismiss(playerViewController: _playerViewController)
}) })
} }
} }
@ -1103,12 +1111,27 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
let oldRect = change.oldValue let oldRect = change.oldValue
let newRect = change.newValue let newRect = change.newValue
if !oldRect!.equalTo(newRect!) { if !oldRect!.equalTo(newRect!) {
// https://github.com/react-native-video/react-native-video/issues/3085#issuecomment-1557293391
if newRect!.equalTo(UIScreen.main.bounds) { if newRect!.equalTo(UIScreen.main.bounds) {
RCTLog("in fullscreen") RCTLog("in fullscreen")
if (!_fullscreenUncontrolPlayerPresented) {
_fullscreenUncontrolPlayerPresented = true;
self.onVideoFullscreenPlayerWillPresent?(["target": self.reactTag as Any])
self.onVideoFullscreenPlayerDidPresent?(["target": self.reactTag as Any])
}
} else {
NSLog("not fullscreen")
if (_fullscreenUncontrolPlayerPresented) {
_fullscreenUncontrolPlayerPresented = false;
self.onVideoFullscreenPlayerWillDismiss?(["target": self.reactTag as Any])
self.onVideoFullscreenPlayerDidDismiss?(["target": self.reactTag as Any])
}
}
self.reactViewController().view.frame = UIScreen.main.bounds self.reactViewController().view.frame = UIScreen.main.bounds
self.reactViewController().view.setNeedsLayout() self.reactViewController().view.setNeedsLayout()
} else {NSLog("not fullscreen")}
} }
} }

View File

@ -2,7 +2,7 @@ import AVKit
class RCTVideoPlayerViewController: AVPlayerViewController { class RCTVideoPlayerViewController: AVPlayerViewController {
var rctDelegate:RCTVideoPlayerViewControllerDelegate! weak var rctDelegate: RCTVideoPlayerViewControllerDelegate?
// Optional paramters // Optional paramters
var preferredOrientation:String? var preferredOrientation:String?
@ -20,10 +20,8 @@ class RCTVideoPlayerViewController: AVPlayerViewController {
override func viewDidDisappear(_ animated: Bool) { override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated) super.viewDidDisappear(animated)
if rctDelegate != nil { rctDelegate?.videoPlayerViewControllerWillDismiss(playerViewController: self)
rctDelegate.videoPlayerViewControllerWillDismiss(playerViewController: self) rctDelegate?.videoPlayerViewControllerDidDismiss(playerViewController: self)
rctDelegate.videoPlayerViewControllerDidDismiss(playerViewController: self)
}
} }
#if !TARGET_OS_TV #if !TARGET_OS_TV