Skip to content

Commit

Permalink
Merge branch 'master' of github.com:react-native-video/react-native-v…
Browse files Browse the repository at this point in the history
…ideo
  • Loading branch information
freeboub committed Apr 16, 2024
2 parents 52b8ec1 + 2285eba commit 5ca679d
Show file tree
Hide file tree
Showing 18 changed files with 212 additions and 53 deletions.
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"no-trailing-spaces": 1
},
"parserOptions": {
"requireConfigFile": false
}
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,14 @@ var styles = StyleSheet.create({
});
```

## Supported by
## Community support
We have an discord server where you can ask questions and get help. [Join the discord server](https://discord.gg/WXuM4Tgb9X)

## Enterprise Support
<p>
📱 TWG provides both free and commercial support for this project. Feel free to contact us 🤝 to build something awesome together! 🚀
📱 <i>react-native-video</i> is provided <i>as it is</i>. For enterprise support or other business inquiries, <a href="https://www.thewidlarzgroup.com/">please contact us 🤝</a>. We can help you with the integration, customization and maintenance. We are providing both free and commercial support for this project. let's build something awesome together! 🚀
</p>
<a href="https://thewidlarzgroup.com/">
<a href="https://www.thewidlarzgroup.com/">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./docs/assets/baners/twg-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="./docs/assets/baners/twg-light.png" />
Expand Down
2 changes: 2 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ dependencies {
implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
// For HLS playback support with ExoPlayer
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"

implementation "androidx.media3:media3-exoplayer-rtsp:$media3_version"
// For ad insertion using the Interactive Media Ads SDK with ExoPlayer
if (useExoplayerIMA) {
implementation "androidx.media3:media3-exoplayer-ima:$media3_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static androidx.media3.common.C.CONTENT_TYPE_DASH;
import static androidx.media3.common.C.CONTENT_TYPE_HLS;
import static androidx.media3.common.C.CONTENT_TYPE_OTHER;
import static androidx.media3.common.C.CONTENT_TYPE_RTSP;
import static androidx.media3.common.C.CONTENT_TYPE_SS;
import static androidx.media3.common.C.TIME_END_OF_SOURCE;

Expand Down Expand Up @@ -68,6 +69,7 @@
import androidx.media3.exoplayer.ima.ImaAdsLoader;
import androidx.media3.exoplayer.mediacodec.MediaCodecInfo;
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
import androidx.media3.exoplayer.rtsp.RtspMediaSource;
import androidx.media3.exoplayer.smoothstreaming.DefaultSsChunkSource;
import androidx.media3.exoplayer.smoothstreaming.SsMediaSource;
import androidx.media3.exoplayer.source.ClippingMediaSource;
Expand Down Expand Up @@ -792,8 +794,13 @@ private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessi
if (uri == null) {
throw new IllegalStateException("Invalid video uri");
}
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
: uri.getLastPathSegment());
int type;
if ("rtsp".equals(overrideExtension)) {
type = C.TYPE_RTSP;
} else {
type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
: uri.getLastPathSegment());
}
config.setDisableDisconnectError(this.disableDisconnectError);

MediaItem.Builder mediaItemBuilder = new MediaItem.Builder().setUri(uri);
Expand Down Expand Up @@ -836,6 +843,9 @@ private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessi
mediaDataSourceFactory
);
break;
case CONTENT_TYPE_RTSP:
mediaSourceFactory = new RtspMediaSource.Factory();
break;
default: {
throw new IllegalStateException("Unsupported type: " + type);
}
Expand Down Expand Up @@ -1326,7 +1336,7 @@ private Track exoplayerTrackToGenericTrack(Format format, int trackIndex, TrackS
track.setIndex(trackIndex);
if (format.sampleMimeType != null) track.setMimeType(format.sampleMimeType);
if (format.language != null) track.setLanguage(format.language);
if (format.id != null) track.setTitle(format.id);
if (format.label != null) track.setTitle(format.label);
track.setSelected(isTrackSelected(selection, group, 0));
return track;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ private boolean startsWithValidScheme(String uriString) {
|| lowerCaseUri.startsWith("https://")
|| lowerCaseUri.startsWith("content://")
|| lowerCaseUri.startsWith("file://")
|| lowerCaseUri.startsWith("rtsp://")
|| lowerCaseUri.startsWith("asset://");
}
}
11 changes: 0 additions & 11 deletions docs/pages/component/props.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,6 @@ Indicates whether the player allows switching to external playback mode such as
- **true (default)** - allow switching to external playback mode
- **false** - Don't allow switching to external playback mode

### `audioOnly`

<PlatformsList types={['All']} />

Indicates whether the player should only play the audio track and instead of displaying the video track, show the poster instead.

- **false (default)** - Display the video as normal
- **true** - Show the poster and play the audio

For this to work, the poster prop must be set.

### `audioOutput`

<PlatformsList types={['Android', 'iOS', 'visionOS']} />
Expand Down
13 changes: 13 additions & 0 deletions docs/pages/other/debug.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Debugging

This page describe usefull tips for debugging and investigating issue in the package or in your application.

## Using the sample app
This repository contains multiple a sample implementation in example folder.
It is always preferable to test behavior on a sample app than in a full app implementation.
The basic sample allow to test a lot of feature.
To use the sample you will need to do steps:
- Clone this repository: ``` git clone git@github.com:react-native-video/react-native-video.git```
- Go to root folder and build it. It will generate a transpiled version of the package in lib folder: ```cd react-native-video && yarn && yarn build```
- Go to the sample and install it: ```cd example/basic && yarn install```
- Build it ! for android ```yarn android``` for ios ```cd ios && pod install && cd .. && yarn ios```


## HTTP playback doesn't work or Black Screen on Release build (Android)
If your video work on Debug mode, but on Release you see only black screen, please, check the link to your video. If you use 'http' protocol there, you will need to add next string to your AndroidManifest.xml file. [Details here](https://developer.android.com/guide/topics/manifest/application-element#usesCleartextTraffic)

Expand Down
12 changes: 12 additions & 0 deletions examples/basic/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ android {
configurations.all {
resolutionStrategy { force 'androidx.core:core:1.9.0' }
}

packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
exclude("META-INF/*.kotlin_module")
}
}


Expand Down
2 changes: 1 addition & 1 deletion examples/basic/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
Expand Down
2 changes: 2 additions & 0 deletions examples/basic/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Without this file, the example will not build on physical devices
import './src/index';
46 changes: 42 additions & 4 deletions examples/basic/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -935,11 +935,49 @@ PODS:
- React-Mapbuffer (0.74.0-rc.4):
- glog
- React-debug
- react-native-video (6.0.0-beta.6):
- react-native-video (6.0.0-beta.8):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React-Codegen
- React-Core
- react-native-video/Video (= 6.0.0-beta.6)
- react-native-video/Video (6.0.0-beta.6):
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- react-native-video/Video (= 6.0.0-beta.8)
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-video/Video (6.0.0-beta.8):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React-Codegen
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- React-nativeconfig (0.74.0-rc.4)
- React-NativeModulesApple (0.74.0-rc.4):
- glog
Expand Down Expand Up @@ -1383,7 +1421,7 @@ SPEC CHECKSUMS:
React-jsitracing: 50e3ea936a199a2a7fcab922f156507c97f0b88c
React-logger: 6004e0cf41b7e9714ca26b1648e5d76fcfd638b5
React-Mapbuffer: 9b163fa28e549d5f36f89a39a1145fcaf262d0d0
react-native-video: d340c162bf7974c2935fbeec0c5dea362f9dd74a
react-native-video: 64df5d2bc3bbc028cb97d87b53e42583127a9b9e
React-nativeconfig: 3948d6fb6acfec364625cffbb1cf420346fb37c0
React-NativeModulesApple: 46745aba687c1019983d56b6d5fa39265152f64f
React-perflogger: 0d62c0261b6fd3920605850de91abc8135dd3ee9
Expand Down
44 changes: 40 additions & 4 deletions examples/basic/src/VideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import Video, {
OnTextTrackDataChangedData,
TextTrackType,
ISO639_1,
OnSeekData,
OnPlaybackStateChangedData,
OnPlaybackRateChangeData,
} from 'react-native-video';
Expand Down Expand Up @@ -68,6 +69,7 @@ interface StateType {
srcListId: number;
loop: boolean;
showRNVControls: boolean;
poster?: string;
}

class VideoPlayer extends Component {
Expand Down Expand Up @@ -95,6 +97,7 @@ class VideoPlayer extends Component {
srcListId: 0,
loop: false,
showRNVControls: false,
poster: undefined,
};

seekerWidth = 0;
Expand Down Expand Up @@ -140,7 +143,7 @@ class VideoPlayer extends Component {
type: TextTrackType.VTT,
uri: 'https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_en.vtt',
},
]
],
},
];

Expand Down Expand Up @@ -188,8 +191,17 @@ class VideoPlayer extends Component {
'https://proxy.uat.widevine.com/proxy?provider=widevine_test',
},
},
{
description: 'rtsp big bug bunny',
uri: 'rtsp://rtspstream:3cfa3c36a9c00f4aa38f3cd35816b287@zephyr.rtsp.stream/movie',
type: 'rtsp',
}
];

// poster which can be displayed
samplePoster =
'https://upload.wikimedia.org/wikipedia/commons/1/18/React_Native_Logo.png';

srcList = this.srcAllPlatformList.concat(
Platform.OS === 'android' ? this.srcAndroidList : this.srcIosList,
);
Expand Down Expand Up @@ -223,14 +235,26 @@ class VideoPlayer extends Component {
this.onTextTracks(data);
};

onProgress = (data: OnProgressData) => {
if (!this.state.seeking) {
updateSeeker = () => {
// put this code in timeout as because it may be put just after a setState
setTimeout(()=> {
const position = this.calculateSeekerPosition();
this.setSeekerPosition(position);
}
}, 1)
}

onProgress = (data: OnProgressData) => {
this.setState({currentTime: data.currentTime});
if (!this.state.seeking) {
this.updateSeeker()
}
};

onSeek = (data: OnSeekData) => {
this.setState({currentTime: data.currentTime});
this.updateSeeker()
}

onVideoLoadStart = () => {
console.log('onVideoLoadStart');
this.setState({isLoading: true});
Expand Down Expand Up @@ -662,6 +686,16 @@ class VideoPlayer extends Component {
}}
text="decoration"
/>
<ToggleControl
isSelected={!!this.state.poster}
onPress={() => {
this.setState({
poster: this.state.poster ? undefined : this.samplePoster,
});
}}
selectedText="poster"
unselectedText="no poster"
/>
</View>
<View style={styles.generalControls}>
{/* shall be replaced by slider */}
Expand Down Expand Up @@ -812,11 +846,13 @@ class VideoPlayer extends Component {
onAspectRatio={this.onAspectRatio}
onReadyForDisplay={this.onReadyForDisplay}
onBuffer={this.onVideoBuffer}
onSeek={this.onSeek}
repeat={this.state.loop}
selectedTextTrack={this.state.selectedTextTrack}
selectedAudioTrack={this.state.selectedAudioTrack}
playInBackground={false}
preventsDisplaySleepDuringVideoPlayback={true}
poster={this.state.poster}
onPlaybackRateChange={this.onPlaybackRateChange}
onPlaybackStateChanged={this.onPlaybackStateChanged}
/>
Expand Down
4 changes: 4 additions & 0 deletions ios/Video/Features/RCTPictureInPicture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ import React
_pipController?.delegate = self
}

func deinitPipController() {
_pipController = nil
}

func setPictureInPicture(_ isActive: Bool) {
if _isActive == isActive {
return
Expand Down
Loading

0 comments on commit 5ca679d

Please sign in to comment.