diff --git a/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java b/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java index 70a7535683..9607f77c5c 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java +++ b/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java @@ -1,12 +1,18 @@ package com.brentvatne.exoplayer; +import android.net.Uri; + +import androidx.annotation.NonNull; import androidx.media3.common.util.Util; +import androidx.media3.datasource.AssetDataSource; import androidx.media3.datasource.DataSource; +import androidx.media3.datasource.DataSpec; import androidx.media3.datasource.DefaultDataSource; import androidx.media3.datasource.HttpDataSource; import androidx.media3.datasource.okhttp.OkHttpDataSource; import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter; +import com.brentvatne.common.toolbox.DebugLog; import com.facebook.react.bridge.ReactContext; import com.facebook.react.modules.network.CookieJarContainer; import com.facebook.react.modules.network.ForwardingCookieHandler; @@ -23,7 +29,6 @@ public class DataSourceUtil { private DataSourceUtil() { } - private static DataSource.Factory rawDataSourceFactory = null; private static DataSource.Factory defaultDataSourceFactory = null; private static HttpDataSource.Factory defaultHttpDataSourceFactory = null; private static String userAgent = null; @@ -39,18 +44,6 @@ public static String getUserAgent(ReactContext context) { return userAgent; } - public static DataSource.Factory getRawDataSourceFactory(ReactContext context) { - if (rawDataSourceFactory == null) { - rawDataSourceFactory = buildRawDataSourceFactory(context); - } - return rawDataSourceFactory; - } - - public static void setRawDataSourceFactory(DataSource.Factory factory) { - DataSourceUtil.rawDataSourceFactory = factory; - } - - public static DataSource.Factory getDefaultDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { if (defaultDataSourceFactory == null || (requestHeaders != null && !requestHeaders.isEmpty())) { defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders); @@ -58,10 +51,6 @@ public static DataSource.Factory getDefaultDataSourceFactory(ReactContext contex return defaultDataSourceFactory; } - public static void setDefaultDataSourceFactory(DataSource.Factory factory) { - DataSourceUtil.defaultDataSourceFactory = factory; - } - public static HttpDataSource.Factory getDefaultHttpDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { if (defaultHttpDataSourceFactory == null || (requestHeaders != null && !requestHeaders.isEmpty())) { defaultHttpDataSourceFactory = buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders); @@ -69,14 +58,6 @@ public static HttpDataSource.Factory getDefaultHttpDataSourceFactory(ReactContex return defaultHttpDataSourceFactory; } - public static void setDefaultHttpDataSourceFactory(HttpDataSource.Factory factory) { - DataSourceUtil.defaultHttpDataSourceFactory = factory; - } - - private static DataSource.Factory buildRawDataSourceFactory(ReactContext context) { - return new RawResourceDataSourceFactory(context.getApplicationContext()); - } - private static DataSource.Factory buildDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { return new DefaultDataSource.Factory(context, buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders)); } @@ -100,4 +81,17 @@ private static HttpDataSource.Factory buildHttpDataSourceFactory(ReactContext co return okHttpDataSourceFactory; } + + public static DataSource.Factory buildAssetDataSourceFactory(ReactContext context, Uri srcUri) throws AssetDataSource.AssetDataSourceException { + DataSpec dataSpec = new DataSpec(srcUri); + final AssetDataSource rawResourceDataSource = new AssetDataSource(context); + rawResourceDataSource.open(dataSpec); + return new DataSource.Factory() { + @NonNull + @Override + public DataSource createDataSource() { + return rawResourceDataSource; + } + }; + } } diff --git a/android/src/main/java/com/brentvatne/exoplayer/RawResourceDataSourceFactory.java b/android/src/main/java/com/brentvatne/exoplayer/RawResourceDataSourceFactory.java deleted file mode 100644 index abdb42f50c..0000000000 --- a/android/src/main/java/com/brentvatne/exoplayer/RawResourceDataSourceFactory.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.brentvatne.exoplayer; - -import android.content.Context; - -import androidx.media3.datasource.DataSource; -import androidx.media3.datasource.RawResourceDataSource; - -class RawResourceDataSourceFactory implements DataSource.Factory { - - private final Context context; - - RawResourceDataSourceFactory(Context context) { - this.context = context; - } - - @Override - public DataSource createDataSource() { - return new RawResourceDataSource(context); - } -} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index ba4142454f..d453cb5af7 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -7,6 +7,8 @@ import static androidx.media3.common.C.CONTENT_TYPE_SS; import static androidx.media3.common.C.TIME_END_OF_SOURCE; +import static com.brentvatne.exoplayer.DataSourceUtil.buildAssetDataSourceFactory; + import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; @@ -841,7 +843,14 @@ private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessi ); break; case CONTENT_TYPE_OTHER: - if (uri.toString().startsWith("file://") || + if ("asset".equals(srcUri.getScheme())) { + try { + DataSource.Factory assetDataSourceFactory = buildAssetDataSourceFactory(themedReactContext, srcUri); + mediaSourceFactory = new ProgressiveMediaSource.Factory(assetDataSourceFactory); + } catch (Exception e) { + throw new IllegalStateException("cannot open input file" + srcUri); + } + } else if ("file".equals(srcUri.getScheme()) || cacheDataSourceFactory == null) { mediaSourceFactory = new ProgressiveMediaSource.Factory( mediaDataSourceFactory diff --git a/android/src/main/java/com/brentvatne/react/VideoManagerModule.kt b/android/src/main/java/com/brentvatne/react/VideoManagerModule.kt index 58c75985c3..69f028dcae 100644 --- a/android/src/main/java/com/brentvatne/react/VideoManagerModule.kt +++ b/android/src/main/java/com/brentvatne/react/VideoManagerModule.kt @@ -12,9 +12,7 @@ import com.facebook.react.uimanager.common.UIManagerType import kotlin.math.roundToInt class VideoManagerModule(reactContext: ReactApplicationContext?) : ReactContextBaseJavaModule(reactContext) { - override fun getName(): String { - return REACT_CLASS - } + override fun getName(): String = REACT_CLASS private fun performOnPlayerView(reactTag: Int, callback: (ReactExoplayerView?) -> Unit) { UiThreadUtil.runOnUiThread { diff --git a/docs/pages/component/props.mdx b/docs/pages/component/props.mdx index d8232ffa9d..945d10e2dc 100644 --- a/docs/pages/component/props.mdx +++ b/docs/pages/component/props.mdx @@ -638,6 +638,18 @@ source={{ uri: 'file:///sdcard/Movies/sintel.mp4' }} Note: Your app will need to request permission to read external storage if you're accessing a file outside your app. +##### File from asset folder (asset://) + + + +Allows to play a video file from the asset folder from the application + +Example: + +```javascript +source={{ uri: 'asset:///sintel.mp4' }} +``` + ##### iPod Library (ipod-library://) diff --git a/examples/basic/android/app/src/main/assets/broadchurch.mp4 b/examples/basic/android/app/src/main/assets/broadchurch.mp4 new file mode 100644 index 0000000000..7a7a49495d Binary files /dev/null and b/examples/basic/android/app/src/main/assets/broadchurch.mp4 differ diff --git a/examples/basic/src/VideoPlayer.tsx b/examples/basic/src/VideoPlayer.tsx index c44ee37253..6baefccb55 100644 --- a/examples/basic/src/VideoPlayer.tsx +++ b/examples/basic/src/VideoPlayer.tsx @@ -170,6 +170,10 @@ class VideoPlayer extends Component { description: 'Another live sample', uri: 'https://live.forstreet.cl/live/livestream.m3u8', }, + { + description: 'asset file', + uri: 'asset:///broadchurch.mp4', + }, { description: '(dash) sintel subtitles', uri: 'https://bitmovin-a.akamaihd.net/content/sintel/sintel.mpd',