From 8509e3a9304f993f808912ba9982b2970730beec Mon Sep 17 00:00:00 2001 From: Devon Sams <60831712+devon-whil@users.noreply.github.com> Date: Mon, 13 Jun 2022 11:26:40 -0400 Subject: [PATCH 01/21] Replace Image.propTypes with ImagePropTypes. --- Video.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Video.js b/Video.js index ddd7d508..d398763a 100644 --- a/Video.js +++ b/Video.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { StyleSheet, requireNativeComponent, NativeModules, UIManager, View, Image, Platform, findNodeHandle } from 'react-native'; -import { ViewPropTypes } from 'deprecated-react-native-prop-types'; +import { ViewPropTypes, ImagePropTypes } from 'deprecated-react-native-prop-types'; import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'; import TextTrackType from './TextTrackType'; import FilterType from './FilterType'; @@ -426,7 +426,7 @@ Video.propTypes = { maxBitRate: PropTypes.number, resizeMode: PropTypes.string, poster: PropTypes.string, - posterResizeMode: Image.propTypes.resizeMode, + posterResizeMode: ImagePropTypes.resizeMode, repeat: PropTypes.bool, automaticallyWaitsToMinimizeStalling: PropTypes.bool, allowsExternalPlayback: PropTypes.bool, From 537d36cf60f2681079fcc9ddf9bdeb39c95cfc58 Mon Sep 17 00:00:00 2001 From: Igor Tironi Date: Tue, 14 Jun 2022 15:50:22 -0700 Subject: [PATCH 02/21] type _eventDispatcher as RCTEventDispatcherProtocol --- ios/Video/RCTVideo.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index 76701229..fb5270ab 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -21,7 +21,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH private var _localSourceEncryptionKeyScheme:String? /* Required to publish events */ - private var _eventDispatcher:RCTEventDispatcher? + private var _eventDispatcher:RCTEventDispatcherProtocol? private var _videoLoadStarted:Bool = false private var _pendingSeek:Bool = false @@ -95,7 +95,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH @objc var onRestoreUserInterfaceForPictureInPictureStop: RCTDirectEventBlock? @objc var onGetLicense: RCTDirectEventBlock? - init(eventDispatcher:RCTEventDispatcher!) { + init(eventDispatcher:RCTEventDispatcherProtocol!) { super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) _eventDispatcher = eventDispatcher From ecab687cb205de788c19168ad58e484a3c4cc685 Mon Sep 17 00:00:00 2001 From: Igor Tironi Date: Tue, 14 Jun 2022 15:51:19 -0700 Subject: [PATCH 03/21] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36f9a78c..d251364e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Fix volume reset issue in exoPlayer [#2371](https://github.com/react-native-video/react-native-video/pull/2371) - Change WindowsTargetPlatformVersion to 10.0 [#2706](https://github.com/react-native-video/react-native-video/pull/2706) - Fixed Android seeking bug [#2712](https://github.com/react-native-video/react-native-video/pull/2712) +- Fix type of `_eventDispatcher` on iOS target to match `bridge.eventDispatcher()` ### Version 5.2.0 From e5d81bf1930de2321ed9c81043fce82aeeab254e Mon Sep 17 00:00:00 2001 From: Igor Tironi Date: Tue, 14 Jun 2022 16:05:42 -0700 Subject: [PATCH 04/21] include PR link to changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d251364e..c7cba52c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,7 @@ - Fix volume reset issue in exoPlayer [#2371](https://github.com/react-native-video/react-native-video/pull/2371) - Change WindowsTargetPlatformVersion to 10.0 [#2706](https://github.com/react-native-video/react-native-video/pull/2706) - Fixed Android seeking bug [#2712](https://github.com/react-native-video/react-native-video/pull/2712) -- Fix type of `_eventDispatcher` on iOS target to match `bridge.eventDispatcher()` +- Fix type of `_eventDispatcher` on iOS target to match `bridge.eventDispatcher()` [#2720](https://github.com/react-native-video/react-native-video/pull/2720) ### Version 5.2.0 From 32718be95130f0c15c1932d86687bff9a5f61f19 Mon Sep 17 00:00:00 2001 From: olivier bouillet Date: Wed, 15 Jun 2022 22:29:46 +0200 Subject: [PATCH 05/21] chore: remove MediaPlayer source --- android/build.gradle | 26 - android/src/main/AndroidManifest.xml | 3 - .../expansion/zipfile/APEZProvider.java | 287 ------- .../zipfile/APKExpansionSupport.java | 81 -- .../expansion/zipfile/ZipResourceFile.java | 428 ---------- .../brentvatne/react/ReactVideoPackage.java | 30 - .../com/brentvatne/react/ReactVideoView.java | 796 ------------------ .../react/ReactVideoViewManager.java | 172 ---- 8 files changed, 1823 deletions(-) delete mode 100644 android/build.gradle delete mode 100644 android/src/main/AndroidManifest.xml delete mode 100644 android/src/main/java/com/android/vending/expansion/zipfile/APEZProvider.java delete mode 100644 android/src/main/java/com/android/vending/expansion/zipfile/APKExpansionSupport.java delete mode 100644 android/src/main/java/com/android/vending/expansion/zipfile/ZipResourceFile.java delete mode 100644 android/src/main/java/com/brentvatne/react/ReactVideoPackage.java delete mode 100644 android/src/main/java/com/brentvatne/react/ReactVideoView.java delete mode 100644 android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index b382a85f..00000000 --- a/android/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -apply plugin: 'com.android.library' - -def safeExtGet(prop, fallback) { - rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback -} - -android { - compileSdkVersion safeExtGet('compileSdkVersion', 31) - buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2') - - defaultConfig { - minSdkVersion safeExtGet('minSdkVersion', 21) - targetSdkVersion safeExtGet('targetSdkVersion', 28) - versionCode 1 - versionName "1.0" - ndk { - abiFilters "armeabi-v7a", "x86" - } - } -} - -dependencies { - //noinspection GradleDynamicVersion - implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" - implementation 'com.github.thang2162:Android-ScalableVideoView:v1.1.1' -} diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml deleted file mode 100644 index 3535ad44..00000000 --- a/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/android/src/main/java/com/android/vending/expansion/zipfile/APEZProvider.java b/android/src/main/java/com/android/vending/expansion/zipfile/APEZProvider.java deleted file mode 100644 index 1ba910bf..00000000 --- a/android/src/main/java/com/android/vending/expansion/zipfile/APEZProvider.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.android.vending.expansion.zipfile; - -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//To implement APEZProvider in your application, you'll want to change -//the AUTHORITY to match what you define in the manifest. - -import com.android.vending.expansion.zipfile.ZipResourceFile.ZipEntryRO; - -import android.content.ContentProvider; -import android.content.ContentProviderOperation; -import android.content.ContentProviderResult; -import android.content.ContentValues; -import android.content.Context; -import android.content.OperationApplicationException; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ProviderInfo; -import android.content.res.AssetFileDescriptor; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.provider.BaseColumns; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; - -/** - * This content provider is an optional part of the library. - * - *

Most apps don't need to use this class. This defines a - * ContentProvider that marshalls the data from the ZIP files through a - * content provider Uri in order to provide file access for certain Android APIs - * that expect Uri access to media files. - * - */ -public abstract class APEZProvider extends ContentProvider { - - private ZipResourceFile mAPKExtensionFile; - private boolean mInit; - - public static final String FILEID = BaseColumns._ID; - public static final String FILENAME = "ZPFN"; - public static final String ZIPFILE = "ZFIL"; - public static final String MODIFICATION = "ZMOD"; - public static final String CRC32 = "ZCRC"; - public static final String COMPRESSEDLEN = "ZCOL"; - public static final String UNCOMPRESSEDLEN = "ZUNL"; - public static final String COMPRESSIONTYPE = "ZTYP"; - - public static final String[] ALL_FIELDS = { - FILEID, - FILENAME, - ZIPFILE, - MODIFICATION, - CRC32, - COMPRESSEDLEN, - UNCOMPRESSEDLEN, - COMPRESSIONTYPE - }; - - public static final int FILEID_IDX = 0; - public static final int FILENAME_IDX = 1; - public static final int ZIPFILE_IDX = 2; - public static final int MOD_IDX = 3; - public static final int CRC_IDX = 4; - public static final int COMPLEN_IDX = 5; - public static final int UNCOMPLEN_IDX = 6; - public static final int COMPTYPE_IDX = 7; - - public static final int[] ALL_FIELDS_INT = { - FILEID_IDX, - FILENAME_IDX, - ZIPFILE_IDX, - MOD_IDX, - CRC_IDX, - COMPLEN_IDX, - UNCOMPLEN_IDX, - COMPTYPE_IDX - }; - - /** - * This needs to match the authority in your manifest - */ - public abstract String getAuthority(); - - @Override - public int delete(Uri arg0, String arg1, String[] arg2) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public String getType(Uri uri) { - return "vnd.android.cursor.item/asset"; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - // TODO Auto-generated method stub - return null; - } - - static private final String NO_FILE = "N"; - - private boolean initIfNecessary() { - if ( !mInit ) { - Context ctx = getContext(); - PackageManager pm = ctx.getPackageManager(); - ProviderInfo pi = pm.resolveContentProvider(getAuthority(), PackageManager.GET_META_DATA); - PackageInfo packInfo; - try { - packInfo = pm.getPackageInfo(ctx.getPackageName(), 0); - } catch (NameNotFoundException e1) { - e1.printStackTrace(); - return false; - } - int patchFileVersion; - int mainFileVersion; - int appVersionCode = packInfo.versionCode; - String[] resourceFiles = null; - if ( null != pi.metaData ) { - mainFileVersion = pi.metaData.getInt("mainVersion", appVersionCode); - patchFileVersion = pi.metaData.getInt("patchVersion", appVersionCode); - String mainFileName = pi.metaData.getString("mainFilename", NO_FILE); - if ( NO_FILE != mainFileName ) { - String patchFileName = pi.metaData.getString("patchFilename", NO_FILE); - if ( NO_FILE != patchFileName ) { - resourceFiles = new String[] { mainFileName, patchFileName }; - } else { - resourceFiles = new String[] { mainFileName }; - } - } - } else { - mainFileVersion = patchFileVersion = appVersionCode; - } - try { - if ( null == resourceFiles ) { - mAPKExtensionFile = APKExpansionSupport.getAPKExpansionZipFile(ctx, mainFileVersion, patchFileVersion); - } else { - mAPKExtensionFile = APKExpansionSupport.getResourceZipFile(resourceFiles); - } - mInit = true; - return true; - } catch (IOException e) { - e.printStackTrace(); - } - } - return false; - } - - @Override - public boolean onCreate() { - return true; - } - - @Override - public AssetFileDescriptor openAssetFile(Uri uri, String mode) - throws FileNotFoundException { - initIfNecessary(); - String path = uri.getEncodedPath(); - if ( path.startsWith("/") ) { - path = path.substring(1); - } - return mAPKExtensionFile.getAssetFileDescriptor(path); - } - - @Override - public ContentProviderResult[] applyBatch( - ArrayList operations) - throws OperationApplicationException { - initIfNecessary(); - return super.applyBatch(operations); - } - - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) - throws FileNotFoundException { - initIfNecessary(); - AssetFileDescriptor af = openAssetFile(uri, mode); - if ( null != af ) { - return af.getParcelFileDescriptor(); - } - return null; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - initIfNecessary(); - // lists all of the items in the file that match - ZipEntryRO[] zipEntries; - if ( null == mAPKExtensionFile ) { - zipEntries = new ZipEntryRO[0]; - } else { - zipEntries = mAPKExtensionFile.getAllEntries(); - } - int[] intProjection; - if ( null == projection ) { - intProjection = ALL_FIELDS_INT; - projection = ALL_FIELDS; - } else { - int len = projection.length; - intProjection = new int[len]; - for ( int i = 0; i < len; i++ ) { - if ( projection[i].equals(FILEID) ) { - intProjection[i] = FILEID_IDX; - } else if ( projection[i].equals(FILENAME) ) { - intProjection[i] = FILENAME_IDX; - } else if ( projection[i].equals(ZIPFILE) ) { - intProjection[i] = ZIPFILE_IDX; - } else if ( projection[i].equals(MODIFICATION) ) { - intProjection[i] = MOD_IDX; - } else if ( projection[i].equals(CRC32) ) { - intProjection[i] = CRC_IDX; - } else if ( projection[i].equals(COMPRESSEDLEN) ) { - intProjection[i] = COMPLEN_IDX; - } else if ( projection[i].equals(UNCOMPRESSEDLEN) ) { - intProjection[i] = UNCOMPLEN_IDX; - } else if ( projection[i].equals(COMPRESSIONTYPE) ) { - intProjection[i] = COMPTYPE_IDX; - } else { - throw new RuntimeException(); - } - } - } - MatrixCursor mc = new MatrixCursor(projection, zipEntries.length); - int len = intProjection.length; - for ( ZipEntryRO zer : zipEntries ) { - MatrixCursor.RowBuilder rb = mc.newRow(); - for ( int i = 0; i < len; i++ ) { - switch (intProjection[i]) { - case FILEID_IDX: - rb.add(i); - break; - case FILENAME_IDX: - rb.add(zer.mFileName); - break; - case ZIPFILE_IDX: - rb.add(zer.getZipFileName()); - break; - case MOD_IDX: - rb.add(zer.mWhenModified); - break; - case CRC_IDX: - rb.add(zer.mCRC32); - break; - case COMPLEN_IDX: - rb.add(zer.mCompressedLength); - break; - case UNCOMPLEN_IDX: - rb.add(zer.mUncompressedLength); - break; - case COMPTYPE_IDX: - rb.add(zer.mMethod); - break; - } - } - } - return mc; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - // TODO Auto-generated method stub - return 0; - } - -} diff --git a/android/src/main/java/com/android/vending/expansion/zipfile/APKExpansionSupport.java b/android/src/main/java/com/android/vending/expansion/zipfile/APKExpansionSupport.java deleted file mode 100644 index 34669c1d..00000000 --- a/android/src/main/java/com/android/vending/expansion/zipfile/APKExpansionSupport.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.android.vending.expansion.zipfile; -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.util.Vector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import android.content.Context; -import android.os.Environment; -import android.util.Log; - -public class APKExpansionSupport { - // The shared path to all app expansion files - private final static String EXP_PATH = "/Android/obb/"; - - static String[] getAPKExpansionFiles(Context ctx, int mainVersion, int patchVersion) { - String packageName = ctx.getPackageName(); - Vector ret = new Vector(); - if (Environment.getExternalStorageState().equals( - Environment.MEDIA_MOUNTED)) { - // Build the full path to the app's expansion files - File root = Environment.getExternalStorageDirectory(); - File expPath = new File(root.toString() + EXP_PATH + packageName); - - // Check that expansion file path exists - if (expPath.exists()) { - if ( mainVersion > 0 ) { - String strMainPath = expPath + File.separator + "main." + mainVersion + "." + packageName + ".obb"; -// Log.d("APKEXPANSION", strMainPath); - File main = new File(strMainPath); - if ( main.isFile() ) { - ret.add(strMainPath); - } - } - if ( patchVersion > 0 ) { - String strPatchPath = expPath + File.separator + "patch." + patchVersion + "." + packageName + ".obb"; - File main = new File(strPatchPath); - if ( main.isFile() ) { - ret.add(strPatchPath); - } - } - } - } - String[] retArray = new String[ret.size()]; - ret.toArray(retArray); - return retArray; - } - - static public ZipResourceFile getResourceZipFile(String[] expansionFiles) throws IOException { - ZipResourceFile apkExpansionFile = null; - for (String expansionFilePath : expansionFiles) { - if ( null == apkExpansionFile ) { - apkExpansionFile = new ZipResourceFile(expansionFilePath); - } else { - apkExpansionFile.addPatchFile(expansionFilePath); - } - } - return apkExpansionFile; - } - - static public ZipResourceFile getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion) throws IOException{ - String[] expansionFiles = getAPKExpansionFiles(ctx, mainVersion, patchVersion); - return getResourceZipFile(expansionFiles); - } -} diff --git a/android/src/main/java/com/android/vending/expansion/zipfile/ZipResourceFile.java b/android/src/main/java/com/android/vending/expansion/zipfile/ZipResourceFile.java deleted file mode 100644 index 902af3c4..00000000 --- a/android/src/main/java/com/android/vending/expansion/zipfile/ZipResourceFile.java +++ /dev/null @@ -1,428 +0,0 @@ - -package com.android.vending.expansion.zipfile; - -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import android.content.res.AssetFileDescriptor; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -import java.io.EOFException; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; -import java.util.Collection; -import java.util.HashMap; -import java.util.Vector; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -public class ZipResourceFile { - - // - // Read-only access to Zip archives, with minimal heap allocation. - // - static final String LOG_TAG = "zipro"; - static final boolean LOGV = false; - - // 4-byte number - static private int swapEndian(int i) - { - return ((i & 0xff) << 24) + ((i & 0xff00) << 8) + ((i & 0xff0000) >>> 8) - + ((i >>> 24) & 0xff); - } - - // 2-byte number - static private int swapEndian(short i) - { - return ((i & 0x00FF) << 8 | (i & 0xFF00) >>> 8); - } - - /* - * Zip file constants. - */ - static final int kEOCDSignature = 0x06054b50; - static final int kEOCDLen = 22; - static final int kEOCDNumEntries = 8; // offset to #of entries in file - static final int kEOCDSize = 12; // size of the central directory - static final int kEOCDFileOffset = 16; // offset to central directory - - static final int kMaxCommentLen = 65535; // longest possible in ushort - static final int kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen); - - static final int kLFHSignature = 0x04034b50; - static final int kLFHLen = 30; // excluding variable-len fields - static final int kLFHNameLen = 26; // offset to filename length - static final int kLFHExtraLen = 28; // offset to extra length - - static final int kCDESignature = 0x02014b50; - static final int kCDELen = 46; // excluding variable-len fields - static final int kCDEMethod = 10; // offset to compression method - static final int kCDEModWhen = 12; // offset to modification timestamp - static final int kCDECRC = 16; // offset to entry CRC - static final int kCDECompLen = 20; // offset to compressed length - static final int kCDEUncompLen = 24; // offset to uncompressed length - static final int kCDENameLen = 28; // offset to filename length - static final int kCDEExtraLen = 30; // offset to extra length - static final int kCDECommentLen = 32; // offset to comment length - static final int kCDELocalOffset = 42; // offset to local hdr - - static final int kCompressStored = 0; // no compression - static final int kCompressDeflated = 8; // standard deflate - - /* - * The values we return for ZipEntryRO use 0 as an invalid value, so we want - * to adjust the hash table index by a fixed amount. Using a large value - * helps insure that people don't mix & match arguments, e.g. to - * findEntryByIndex(). - */ - static final int kZipEntryAdj = 10000; - - static public final class ZipEntryRO { - public ZipEntryRO(final String zipFileName, final File file, final String fileName) { - mFileName = fileName; - mZipFileName = zipFileName; - mFile = file; - } - - public final File mFile; - public final String mFileName; - public final String mZipFileName; - public long mLocalHdrOffset; // offset of local file header - - /* useful stuff from the directory entry */ - public int mMethod; - public long mWhenModified; - public long mCRC32; - public long mCompressedLength; - public long mUncompressedLength; - - public long mOffset = -1; - - public void setOffsetFromFile(RandomAccessFile f, ByteBuffer buf) throws IOException { - long localHdrOffset = mLocalHdrOffset; - try { - f.seek(localHdrOffset); - f.readFully(buf.array()); - if (buf.getInt(0) != kLFHSignature) { - Log.w(LOG_TAG, "didn't find signature at start of lfh"); - throw new IOException(); - } - int nameLen = buf.getShort(kLFHNameLen) & 0xFFFF; - int extraLen = buf.getShort(kLFHExtraLen) & 0xFFFF; - mOffset = localHdrOffset + kLFHLen + nameLen + extraLen; - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } - - /** - * Calculates the offset of the start of the Zip file entry within the - * Zip file. - * - * @return the offset, in bytes from the start of the file of the entry - */ - public long getOffset() { - return mOffset; - } - - /** - * isUncompressed - * - * @return true if the file is stored in uncompressed form - */ - public boolean isUncompressed() { - return mMethod == kCompressStored; - } - - public AssetFileDescriptor getAssetFileDescriptor() { - if (mMethod == kCompressStored) { - ParcelFileDescriptor pfd; - try { - pfd = ParcelFileDescriptor.open(mFile, ParcelFileDescriptor.MODE_READ_ONLY); - return new AssetFileDescriptor(pfd, getOffset(), mUncompressedLength); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - return null; - } - - public String getZipFileName() { - return mZipFileName; - } - - public File getZipFile() { - return mFile; - } - - } - - private HashMap mHashMap = new HashMap(); - - /* for reading compressed files */ - public HashMap mZipFiles = new HashMap(); - - public ZipResourceFile(String zipFileName) throws IOException { - addPatchFile(zipFileName); - } - - ZipEntryRO[] getEntriesAt(String path) { - Vector zev = new Vector(); - Collection values = mHashMap.values(); - if (null == path) - path = ""; - int length = path.length(); - for (ZipEntryRO ze : values) { - if (ze.mFileName.startsWith(path)) { - if (-1 == ze.mFileName.indexOf('/', length)) { - zev.add(ze); - } - } - } - ZipEntryRO[] entries = new ZipEntryRO[zev.size()]; - return zev.toArray(entries); - } - - public ZipEntryRO[] getAllEntries() { - Collection values = mHashMap.values(); - return values.toArray(new ZipEntryRO[values.size()]); - } - - /** - * getAssetFileDescriptor allows for ZipResourceFile to directly feed - * Android API's that want an fd, offset, and length such as the - * MediaPlayer. It also allows for the class to be used in a content - * provider that can feed video players. The file must be stored - * (non-compressed) in the Zip file for this to work. - * - * @param assetPath - * @return the asset file descriptor for the file, or null if the file isn't - * present or is stored compressed - */ - public AssetFileDescriptor getAssetFileDescriptor(String assetPath) { - ZipEntryRO entry = mHashMap.get(assetPath); - if (null != entry) { - return entry.getAssetFileDescriptor(); - } - return null; - } - - /** - * getInputStream returns an AssetFileDescriptor.AutoCloseInputStream - * associated with the asset that is contained in the Zip file, or a - * standard ZipInputStream if necessary to uncompress the file - * - * @param assetPath - * @return an input stream for the named asset path, or null if not found - * @throws IOException - */ - public InputStream getInputStream(String assetPath) throws IOException { - ZipEntryRO entry = mHashMap.get(assetPath); - if (null != entry) { - if (entry.isUncompressed()) { - return entry.getAssetFileDescriptor().createInputStream(); - } else { - ZipFile zf = mZipFiles.get(entry.getZipFile()); - /** read compressed files **/ - if (null == zf) { - zf = new ZipFile(entry.getZipFile(), ZipFile.OPEN_READ); - mZipFiles.put(entry.getZipFile(), zf); - } - ZipEntry zi = zf.getEntry(assetPath); - if (null != zi) - return zf.getInputStream(zi); - } - } - return null; - } - - ByteBuffer mLEByteBuffer = ByteBuffer.allocate(4); - - static private int read4LE(RandomAccessFile f) throws EOFException, IOException { - return swapEndian(f.readInt()); - } - - /* - * Opens the specified file read-only. We memory-map the entire thing and - * close the file before returning. - */ - void addPatchFile(String zipFileName) throws IOException - { - File file = new File(zipFileName); - RandomAccessFile f = new RandomAccessFile(file, "r"); - long fileLength = f.length(); - - if (fileLength < kEOCDLen) { - throw new java.io.IOException(); - } - - long readAmount = kMaxEOCDSearch; - if (readAmount > fileLength) - readAmount = fileLength; - - /* - * Make sure this is a Zip archive. - */ - f.seek(0); - - int header = read4LE(f); - if (header == kEOCDSignature) { - Log.i(LOG_TAG, "Found Zip archive, but it looks empty"); - throw new IOException(); - } else if (header != kLFHSignature) { - Log.v(LOG_TAG, "Not a Zip archive"); - throw new IOException(); - } - - /* - * Perform the traditional EOCD snipe hunt. We're searching for the End - * of Central Directory magic number, which appears at the start of the - * EOCD block. It's followed by 18 bytes of EOCD stuff and up to 64KB of - * archive comment. We need to read the last part of the file into a - * buffer, dig through it to find the magic number, parse some values - * out, and use those to determine the extent of the CD. We start by - * pulling in the last part of the file. - */ - long searchStart = fileLength - readAmount; - - f.seek(searchStart); - ByteBuffer bbuf = ByteBuffer.allocate((int) readAmount); - byte[] buffer = bbuf.array(); - f.readFully(buffer); - bbuf.order(ByteOrder.LITTLE_ENDIAN); - - /* - * Scan backward for the EOCD magic. In an archive without a trailing - * comment, we'll find it on the first try. (We may want to consider - * doing an initial minimal read; if we don't find it, retry with a - * second read as above.) - */ - - // EOCD == 0x50, 0x4b, 0x05, 0x06 - int eocdIdx; - for (eocdIdx = buffer.length - kEOCDLen; eocdIdx >= 0; eocdIdx--) { - if (buffer[eocdIdx] == 0x50 && bbuf.getInt(eocdIdx) == kEOCDSignature) - { - if (LOGV) { - Log.v(LOG_TAG, "+++ Found EOCD at index: " + eocdIdx); - } - break; - } - } - - if (eocdIdx < 0) { - Log.d(LOG_TAG, "Zip: EOCD not found, " + zipFileName + " is not zip"); - } - - /* - * Grab the CD offset and size, and the number of entries in the - * archive. After that, we can release our EOCD hunt buffer. - */ - - int numEntries = bbuf.getShort(eocdIdx + kEOCDNumEntries); - long dirSize = bbuf.getInt(eocdIdx + kEOCDSize) & 0xffffffffL; - long dirOffset = bbuf.getInt(eocdIdx + kEOCDFileOffset) & 0xffffffffL; - - // Verify that they look reasonable. - if (dirOffset + dirSize > fileLength) { - Log.w(LOG_TAG, "bad offsets (dir " + dirOffset + ", size " + dirSize + ", eocd " - + eocdIdx + ")"); - throw new IOException(); - } - if (numEntries == 0) { - Log.w(LOG_TAG, "empty archive?"); - throw new IOException(); - } - - if (LOGV) { - Log.v(LOG_TAG, "+++ numEntries=" + numEntries + " dirSize=" + dirSize + " dirOffset=" - + dirOffset); - } - - MappedByteBuffer directoryMap = f.getChannel() - .map(FileChannel.MapMode.READ_ONLY, dirOffset, dirSize); - directoryMap.order(ByteOrder.LITTLE_ENDIAN); - - byte[] tempBuf = new byte[0xffff]; - - /* - * Walk through the central directory, adding entries to the hash table. - */ - - int currentOffset = 0; - - /* - * Allocate the local directory information - */ - ByteBuffer buf = ByteBuffer.allocate(kLFHLen); - buf.order(ByteOrder.LITTLE_ENDIAN); - - for (int i = 0; i < numEntries; i++) { - if (directoryMap.getInt(currentOffset) != kCDESignature) { - Log.w(LOG_TAG, "Missed a central dir sig (at " + currentOffset + ")"); - throw new IOException(); - } - - /* useful stuff from the directory entry */ - int fileNameLen = directoryMap.getShort(currentOffset + kCDENameLen) & 0xffff; - int extraLen = directoryMap.getShort(currentOffset + kCDEExtraLen) & 0xffff; - int commentLen = directoryMap.getShort(currentOffset + kCDECommentLen) & 0xffff; - - /* get the CDE filename */ - - directoryMap.position(currentOffset + kCDELen); - directoryMap.get(tempBuf, 0, fileNameLen); - directoryMap.position(0); - - /* UTF-8 on Android */ - String str = new String(tempBuf, 0, fileNameLen); - if (LOGV) { - Log.v(LOG_TAG, "Filename: " + str); - } - - ZipEntryRO ze = new ZipEntryRO(zipFileName, file, str); - ze.mMethod = directoryMap.getShort(currentOffset + kCDEMethod) & 0xffff; - ze.mWhenModified = directoryMap.getInt(currentOffset + kCDEModWhen) & 0xffffffffL; - ze.mCRC32 = directoryMap.getLong(currentOffset + kCDECRC) & 0xffffffffL; - ze.mCompressedLength = directoryMap.getLong(currentOffset + kCDECompLen) & 0xffffffffL; - ze.mUncompressedLength = directoryMap.getLong(currentOffset + kCDEUncompLen) & 0xffffffffL; - ze.mLocalHdrOffset = directoryMap.getInt(currentOffset + kCDELocalOffset) & 0xffffffffL; - - // set the offsets - buf.clear(); - ze.setOffsetFromFile(f, buf); - - // put file into hash - mHashMap.put(str, ze); - - // go to next directory entry - currentOffset += kCDELen + fileNameLen + extraLen + commentLen; - } - if (LOGV) { - Log.v(LOG_TAG, "+++ zip good scan " + numEntries + " entries"); - } - } -} diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java b/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java deleted file mode 100644 index b09e9414..00000000 --- a/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.brentvatne.react; - -import android.app.Activity; -import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.uimanager.ViewManager; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class ReactVideoPackage implements ReactPackage { - - @Override - public List createNativeModules(ReactApplicationContext reactContext) { - return Collections.emptyList(); - } - - // Deprecated RN 0.47 - public List> createJSModules() { - return Collections.emptyList(); - } - - @Override - public List createViewManagers(ReactApplicationContext reactContext) { - return Arrays.asList(new ReactVideoViewManager()); - } -} diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java deleted file mode 100644 index 09285fb7..00000000 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ /dev/null @@ -1,796 +0,0 @@ -package com.brentvatne.react; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.res.AssetFileDescriptor; -import android.graphics.Matrix; -import android.media.MediaPlayer; -import android.media.TimedMetaData; -import android.net.Uri; -import android.os.Build; -import android.os.Handler; -import android.util.Log; -import android.view.MotionEvent; -import android.view.WindowManager; -import android.view.View; -import android.view.Window; -import android.webkit.CookieManager; -import android.widget.MediaController; - -import com.android.vending.expansion.zipfile.APKExpansionSupport; -import com.android.vending.expansion.zipfile.ZipResourceFile; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableArray; -import com.facebook.react.bridge.WritableNativeArray; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.events.RCTEventEmitter; -import com.yqritc.scalablevideoview.ScalableType; -import com.yqritc.scalablevideoview.ScalableVideoView; -import com.yqritc.scalablevideoview.ScaleManager; -import com.yqritc.scalablevideoview.Size; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.Map; -import java.lang.Math; -import java.math.BigDecimal; - -import javax.annotation.Nullable; - -@SuppressLint("ViewConstructor") -public class ReactVideoView extends ScalableVideoView implements - MediaPlayer.OnPreparedListener, - MediaPlayer.OnErrorListener, - MediaPlayer.OnBufferingUpdateListener, - MediaPlayer.OnSeekCompleteListener, - MediaPlayer.OnCompletionListener, - MediaPlayer.OnInfoListener, - LifecycleEventListener, - MediaController.MediaPlayerControl { - - public enum Events { - EVENT_LOAD_START("onVideoLoadStart"), - EVENT_LOAD("onVideoLoad"), - EVENT_ERROR("onVideoError"), - EVENT_PROGRESS("onVideoProgress"), - EVENT_TIMED_METADATA("onTimedMetadata"), - EVENT_SEEK("onVideoSeek"), - EVENT_END("onVideoEnd"), - EVENT_STALLED("onPlaybackStalled"), - EVENT_RESUME("onPlaybackResume"), - EVENT_READY_FOR_DISPLAY("onReadyForDisplay"), - EVENT_FULLSCREEN_WILL_PRESENT("onVideoFullscreenPlayerWillPresent"), - EVENT_FULLSCREEN_DID_PRESENT("onVideoFullscreenPlayerDidPresent"), - EVENT_FULLSCREEN_WILL_DISMISS("onVideoFullscreenPlayerWillDismiss"), - EVENT_FULLSCREEN_DID_DISMISS("onVideoFullscreenPlayerDidDismiss"); - - private final String mName; - - Events(final String name) { - mName = name; - } - - @Override - public String toString() { - return mName; - } - } - - public static final String EVENT_PROP_FAST_FORWARD = "canPlayFastForward"; - public static final String EVENT_PROP_SLOW_FORWARD = "canPlaySlowForward"; - public static final String EVENT_PROP_SLOW_REVERSE = "canPlaySlowReverse"; - public static final String EVENT_PROP_REVERSE = "canPlayReverse"; - public static final String EVENT_PROP_STEP_FORWARD = "canStepForward"; - public static final String EVENT_PROP_STEP_BACKWARD = "canStepBackward"; - - public static final String EVENT_PROP_DURATION = "duration"; - public static final String EVENT_PROP_PLAYABLE_DURATION = "playableDuration"; - public static final String EVENT_PROP_SEEKABLE_DURATION = "seekableDuration"; - public static final String EVENT_PROP_CURRENT_TIME = "currentTime"; - public static final String EVENT_PROP_SEEK_TIME = "seekTime"; - public static final String EVENT_PROP_NATURALSIZE = "naturalSize"; - public static final String EVENT_PROP_WIDTH = "width"; - public static final String EVENT_PROP_HEIGHT = "height"; - public static final String EVENT_PROP_ORIENTATION = "orientation"; - public static final String EVENT_PROP_METADATA = "metadata"; - public static final String EVENT_PROP_TARGET = "target"; - public static final String EVENT_PROP_METADATA_IDENTIFIER = "identifier"; - public static final String EVENT_PROP_METADATA_VALUE = "value"; - - public static final String EVENT_PROP_ERROR = "error"; - public static final String EVENT_PROP_WHAT = "what"; - public static final String EVENT_PROP_EXTRA = "extra"; - - private ThemedReactContext mThemedReactContext; - private RCTEventEmitter mEventEmitter; - - private Handler mProgressUpdateHandler = new Handler(); - private Runnable mProgressUpdateRunnable = null; - private Handler videoControlHandler = new Handler(); - private MediaController mediaController; - - private String mSrcUriString = null; - private String mSrcType = "mp4"; - private ReadableMap mRequestHeaders = null; - private boolean mSrcIsNetwork = false; - private boolean mSrcIsAsset = false; - private ScalableType mResizeMode = ScalableType.LEFT_TOP; - private boolean mRepeat = false; - private boolean mPaused = false; - private boolean mMuted = false; - private boolean mPreventsDisplaySleepDuringVideoPlayback = true; - private float mVolume = 1.0f; - private float mStereoPan = 0.0f; - private float mProgressUpdateInterval = 250.0f; - private float mRate = 1.0f; - private float mActiveRate = 1.0f; - private long mSeekTime = 0; - private boolean mPlayInBackground = false; - private boolean mBackgroundPaused = false; - private boolean mIsFullscreen = false; - - private int mMainVer = 0; - private int mPatchVer = 0; - - private boolean mMediaPlayerValid = false; // True if mMediaPlayer is in prepared, started, paused or completed state. - - private int mVideoDuration = 0; - private int mVideoBufferedDuration = 0; - private boolean isCompleted = false; - private boolean mUseNativeControls = false; - - public ReactVideoView(ThemedReactContext themedReactContext) { - super(themedReactContext); - - mThemedReactContext = themedReactContext; - mEventEmitter = themedReactContext.getJSModule(RCTEventEmitter.class); - themedReactContext.addLifecycleEventListener(this); - - initializeMediaPlayerIfNeeded(); - setSurfaceTextureListener(this); - - mProgressUpdateRunnable = new Runnable() { - @Override - public void run() { - - if (mMediaPlayerValid && !isCompleted && !mPaused && !mBackgroundPaused) { - WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_CURRENT_TIME, mMediaPlayer.getCurrentPosition() / 1000.0); - event.putDouble(EVENT_PROP_PLAYABLE_DURATION, mVideoBufferedDuration / 1000.0); //TODO:mBufferUpdateRunnable - event.putDouble(EVENT_PROP_SEEKABLE_DURATION, mVideoDuration / 1000.0); - mEventEmitter.receiveEvent(getId(), Events.EVENT_PROGRESS.toString(), event); - - // Check for update after an interval - mProgressUpdateHandler.postDelayed(mProgressUpdateRunnable, Math.round(mProgressUpdateInterval)); - } - } - }; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (mUseNativeControls) { - initializeMediaControllerIfNeeded(); - mediaController.show(); - } - - return super.onTouchEvent(event); - } - - @Override - @SuppressLint("DrawAllocation") - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - - if (!changed || !mMediaPlayerValid) { - return; - } - - int videoWidth = getVideoWidth(); - int videoHeight = getVideoHeight(); - - if (videoWidth == 0 || videoHeight == 0) { - return; - } - - Size viewSize = new Size(getWidth(), getHeight()); - Size videoSize = new Size(videoWidth, videoHeight); - ScaleManager scaleManager = new ScaleManager(viewSize, videoSize); - Matrix matrix = scaleManager.getScaleMatrix(mScalableType); - if (matrix != null) { - setTransform(matrix); - } - } - - private void initializeMediaPlayerIfNeeded() { - if (mMediaPlayer == null) { - mMediaPlayerValid = false; - mMediaPlayer = new MediaPlayer(); - mMediaPlayer.setOnVideoSizeChangedListener(this); - mMediaPlayer.setOnErrorListener(this); - mMediaPlayer.setOnPreparedListener(this); - mMediaPlayer.setOnBufferingUpdateListener(this); - mMediaPlayer.setOnSeekCompleteListener(this); - mMediaPlayer.setOnCompletionListener(this); - mMediaPlayer.setOnInfoListener(this); - if (Build.VERSION.SDK_INT >= 23) { - mMediaPlayer.setOnTimedMetaDataAvailableListener(new TimedMetaDataAvailableListener()); - } - } - } - - private void initializeMediaControllerIfNeeded() { - if (mediaController == null) { - mediaController = new MediaController(this.getContext()); - } - } - - public void cleanupMediaPlayerResources() { - if ( mediaController != null ) { - mediaController.hide(); - } - if ( mMediaPlayer != null ) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - mMediaPlayer.setOnTimedMetaDataAvailableListener(null); - } - mMediaPlayerValid = false; - release(); - } - if (mIsFullscreen) { - setFullscreen(false); - } - if (mThemedReactContext != null) { - mThemedReactContext.removeLifecycleEventListener(this); - mThemedReactContext = null; - } - } - - public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders) { - setSrc(uriString, type, isNetwork, isAsset, requestHeaders, 0, 0); - } - - public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders, final int expansionMainVersion, final int expansionPatchVersion) { - - mSrcUriString = uriString; - mSrcType = type; - mSrcIsNetwork = isNetwork; - mSrcIsAsset = isAsset; - mRequestHeaders = requestHeaders; - mMainVer = expansionMainVersion; - mPatchVer = expansionPatchVersion; - - - mMediaPlayerValid = false; - mVideoDuration = 0; - mVideoBufferedDuration = 0; - - initializeMediaPlayerIfNeeded(); - mMediaPlayer.reset(); - - try { - if (isNetwork) { - // Use the shared CookieManager to access the cookies - // set by WebViews inside the same app - CookieManager cookieManager = CookieManager.getInstance(); - - Uri parsedUrl = Uri.parse(uriString); - Uri.Builder builtUrl = parsedUrl.buildUpon(); - - String cookie = cookieManager.getCookie(builtUrl.build().toString()); - - Map headers = new HashMap(); - - if (cookie != null) { - headers.put("Cookie", cookie); - } - - if (mRequestHeaders != null) { - headers.putAll(toStringMap(mRequestHeaders)); - } - - /* According to https://github.com/react-native-community/react-native-video/pull/537 - * there is an issue with this where it can cause a IOException. - * TODO: diagnose this exception and fix it - */ - setDataSource(mThemedReactContext, parsedUrl, headers); - } else if (isAsset) { - if (uriString.startsWith("content://")) { - Uri parsedUrl = Uri.parse(uriString); - setDataSource(mThemedReactContext, parsedUrl); - } else { - setDataSource(uriString); - } - } else { - ZipResourceFile expansionFile= null; - AssetFileDescriptor fd= null; - if(mMainVer>0) { - try { - expansionFile = APKExpansionSupport.getAPKExpansionZipFile(mThemedReactContext, mMainVer, mPatchVer); - fd = expansionFile.getAssetFileDescriptor(uriString.replace(".mp4","") + ".mp4"); - } catch (IOException e) { - e.printStackTrace(); - } catch (NullPointerException e) { - e.printStackTrace(); - } - } - if(fd==null) { - int identifier = mThemedReactContext.getResources().getIdentifier( - uriString, - "drawable", - mThemedReactContext.getPackageName() - ); - if (identifier == 0) { - identifier = mThemedReactContext.getResources().getIdentifier( - uriString, - "raw", - mThemedReactContext.getPackageName() - ); - } - setRawData(identifier); - } - else { - setDataSource(fd.getFileDescriptor(), fd.getStartOffset(),fd.getLength()); - } - } - } catch (Exception e) { - e.printStackTrace(); - return; - } - - WritableMap src = Arguments.createMap(); - - WritableMap wRequestHeaders = Arguments.createMap(); - wRequestHeaders.merge(mRequestHeaders); - - src.putString(ReactVideoViewManager.PROP_SRC_URI, uriString); - src.putString(ReactVideoViewManager.PROP_SRC_TYPE, type); - src.putMap(ReactVideoViewManager.PROP_SRC_HEADERS, wRequestHeaders); - src.putBoolean(ReactVideoViewManager.PROP_SRC_IS_NETWORK, isNetwork); - if(mMainVer>0) { - src.putInt(ReactVideoViewManager.PROP_SRC_MAINVER, mMainVer); - if(mPatchVer>0) { - src.putInt(ReactVideoViewManager.PROP_SRC_PATCHVER, mPatchVer); - } - } - WritableMap event = Arguments.createMap(); - event.putMap(ReactVideoViewManager.PROP_SRC, src); - mEventEmitter.receiveEvent(getId(), Events.EVENT_LOAD_START.toString(), event); - isCompleted = false; - - try { - prepareAsync(this); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void setResizeModeModifier(final ScalableType resizeMode) { - mResizeMode = resizeMode; - - if (mMediaPlayerValid) { - setScalableType(resizeMode); - invalidate(); - } - } - - public void setRepeatModifier(final boolean repeat) { - - mRepeat = repeat; - - if (mMediaPlayerValid) { - setLooping(repeat); - } - } - - public void setPausedModifier(final boolean paused) { - mPaused = paused; - - if (!mMediaPlayerValid) { - return; - } - - if (mPaused) { - if (mMediaPlayer.isPlaying()) { - pause(); - } - } else { - if (!mMediaPlayer.isPlaying()) { - start(); - // Setting the rate unpauses, so we have to wait for an unpause - if (mRate != mActiveRate) { - setRateModifier(mRate); - } - - // Also Start the Progress Update Handler - mProgressUpdateHandler.post(mProgressUpdateRunnable); - } - } - setKeepScreenOn(!mPaused && mPreventsDisplaySleepDuringVideoPlayback); - } - - // reduces the volume based on stereoPan - private float calulateRelativeVolume() { - float relativeVolume = (mVolume * (1 - Math.abs(mStereoPan))); - // only one decimal allowed - BigDecimal roundRelativeVolume = new BigDecimal(relativeVolume).setScale(1, BigDecimal.ROUND_HALF_UP); - return roundRelativeVolume.floatValue(); - } - - public void setPreventsDisplaySleepDuringVideoPlaybackModifier(final boolean preventsDisplaySleepDuringVideoPlayback) { - mPreventsDisplaySleepDuringVideoPlayback = preventsDisplaySleepDuringVideoPlayback; - - if (!mMediaPlayerValid) { - return; - } - - mMediaPlayer.setScreenOnWhilePlaying(mPreventsDisplaySleepDuringVideoPlayback); - setKeepScreenOn(mPreventsDisplaySleepDuringVideoPlayback); - } - - public void setMutedModifier(final boolean muted) { - mMuted = muted; - - if (!mMediaPlayerValid) { - return; - } - - if (mMuted) { - setVolume(0, 0); - } else if (mStereoPan < 0) { - // louder on the left channel - setVolume(mVolume, calulateRelativeVolume()); - } else if (mStereoPan > 0) { - // louder on the right channel - setVolume(calulateRelativeVolume(), mVolume); - } else { - // same volume on both channels - setVolume(mVolume, mVolume); - } - } - - public void setVolumeModifier(final float volume) { - mVolume = volume; - setMutedModifier(mMuted); - } - - public void setStereoPan(final float stereoPan) { - mStereoPan = stereoPan; - setMutedModifier(mMuted); - } - - public void setProgressUpdateInterval(final float progressUpdateInterval) { - mProgressUpdateInterval = progressUpdateInterval; - } - - public void setRateModifier(final float rate) { - mRate = rate; - - if (mMediaPlayerValid) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (!mPaused) { // Applying the rate while paused will cause the video to start - /* Per https://stackoverflow.com/questions/39442522/setplaybackparams-causes-illegalstateexception - * Some devices throw an IllegalStateException if you set the rate without first calling reset() - * TODO: Call reset() then reinitialize the player - */ - try { - mMediaPlayer.setPlaybackParams(mMediaPlayer.getPlaybackParams().setSpeed(rate)); - mActiveRate = rate; - } catch (Exception e) { - Log.e(ReactVideoViewManager.REACT_CLASS, "Unable to set rate, unsupported on this device"); - } - } - } else { - Log.e(ReactVideoViewManager.REACT_CLASS, "Setting playback rate is not yet supported on Android versions below 6.0"); - } - } - } - - public void setFullscreen(boolean isFullscreen) { - if (isFullscreen == mIsFullscreen) { - return; // Avoid generating events when nothing is changing - } - mIsFullscreen = isFullscreen; - - Activity activity = mThemedReactContext.getCurrentActivity(); - if (activity == null) { - return; - } - Window window = activity.getWindow(); - View decorView = window.getDecorView(); - int uiOptions; - if (mIsFullscreen) { - if (Build.VERSION.SDK_INT >= 19) { // 4.4+ - uiOptions = SYSTEM_UI_FLAG_HIDE_NAVIGATION - | SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | SYSTEM_UI_FLAG_FULLSCREEN; - } else { - uiOptions = SYSTEM_UI_FLAG_HIDE_NAVIGATION - | SYSTEM_UI_FLAG_FULLSCREEN; - } - mEventEmitter.receiveEvent(getId(), Events.EVENT_FULLSCREEN_WILL_PRESENT.toString(), null); - decorView.setSystemUiVisibility(uiOptions); - mEventEmitter.receiveEvent(getId(), Events.EVENT_FULLSCREEN_DID_PRESENT.toString(), null); - } else { - uiOptions = View.SYSTEM_UI_FLAG_VISIBLE; - mEventEmitter.receiveEvent(getId(), Events.EVENT_FULLSCREEN_WILL_DISMISS.toString(), null); - decorView.setSystemUiVisibility(uiOptions); - mEventEmitter.receiveEvent(getId(), Events.EVENT_FULLSCREEN_DID_DISMISS.toString(), null); - } - } - - public void applyModifiers() { - setResizeModeModifier(mResizeMode); - setRepeatModifier(mRepeat); - setPausedModifier(mPaused); - setMutedModifier(mMuted); - setPreventsDisplaySleepDuringVideoPlaybackModifier(mPreventsDisplaySleepDuringVideoPlayback); - setProgressUpdateInterval(mProgressUpdateInterval); - setRateModifier(mRate); - } - - public void setPlayInBackground(final boolean playInBackground) { - - mPlayInBackground = playInBackground; - } - - public void setControls(boolean controls) { - this.mUseNativeControls = controls; - } - - @Override - public void onPrepared(MediaPlayer mp) { - - mMediaPlayerValid = true; - mVideoDuration = mp.getDuration(); - - WritableMap naturalSize = Arguments.createMap(); - naturalSize.putInt(EVENT_PROP_WIDTH, mp.getVideoWidth()); - naturalSize.putInt(EVENT_PROP_HEIGHT, mp.getVideoHeight()); - if (mp.getVideoWidth() > mp.getVideoHeight()) - naturalSize.putString(EVENT_PROP_ORIENTATION, "landscape"); - else - naturalSize.putString(EVENT_PROP_ORIENTATION, "portrait"); - - WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_DURATION, mVideoDuration / 1000.0); - event.putDouble(EVENT_PROP_CURRENT_TIME, mp.getCurrentPosition() / 1000.0); - event.putMap(EVENT_PROP_NATURALSIZE, naturalSize); - // TODO: Actually check if you can. - event.putBoolean(EVENT_PROP_FAST_FORWARD, true); - event.putBoolean(EVENT_PROP_SLOW_FORWARD, true); - event.putBoolean(EVENT_PROP_SLOW_REVERSE, true); - event.putBoolean(EVENT_PROP_REVERSE, true); - event.putBoolean(EVENT_PROP_FAST_FORWARD, true); - event.putBoolean(EVENT_PROP_STEP_BACKWARD, true); - event.putBoolean(EVENT_PROP_STEP_FORWARD, true); - mEventEmitter.receiveEvent(getId(), Events.EVENT_LOAD.toString(), event); - - applyModifiers(); - - if (mUseNativeControls) { - initializeMediaControllerIfNeeded(); - mediaController.setMediaPlayer(this); - mediaController.setAnchorView(this); - - videoControlHandler.post(new Runnable() { - @Override - public void run() { - mediaController.setEnabled(true); - mediaController.show(); - } - }); - } - - selectTimedMetadataTrack(mp); - } - - @Override - public boolean onError(MediaPlayer mp, int what, int extra) { - - WritableMap error = Arguments.createMap(); - error.putInt(EVENT_PROP_WHAT, what); - error.putInt(EVENT_PROP_EXTRA, extra); - WritableMap event = Arguments.createMap(); - event.putMap(EVENT_PROP_ERROR, error); - mEventEmitter.receiveEvent(getId(), Events.EVENT_ERROR.toString(), event); - return true; - } - - @Override - public boolean onInfo(MediaPlayer mp, int what, int extra) { - switch (what) { - case MediaPlayer.MEDIA_INFO_BUFFERING_START: - mEventEmitter.receiveEvent(getId(), Events.EVENT_STALLED.toString(), Arguments.createMap()); - break; - case MediaPlayer.MEDIA_INFO_BUFFERING_END: - mEventEmitter.receiveEvent(getId(), Events.EVENT_RESUME.toString(), Arguments.createMap()); - break; - case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: - mEventEmitter.receiveEvent(getId(), Events.EVENT_READY_FOR_DISPLAY.toString(), Arguments.createMap()); - break; - - default: - } - return false; - } - - @Override - public void onBufferingUpdate(MediaPlayer mp, int percent) { - selectTimedMetadataTrack(mp); - mVideoBufferedDuration = (int) Math.round((double) (mVideoDuration * percent) / 100.0); - } - - public void onSeekComplete(MediaPlayer mp) { - WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_CURRENT_TIME, getCurrentPosition() / 1000.0); - event.putDouble(EVENT_PROP_SEEK_TIME, mSeekTime / 1000.0); - mEventEmitter.receiveEvent(getId(), Events.EVENT_SEEK.toString(), event); - mSeekTime = 0; - } - - @Override - public void seekTo(int msec) { - if (mMediaPlayerValid) { - mSeekTime = msec; - mMediaPlayer.seekTo(msec, MediaPlayer.SEEK_CLOSEST); - if (isCompleted && mVideoDuration != 0 && msec < mVideoDuration) { - isCompleted = false; - } - } - } - - @Override - public int getBufferPercentage() { - return 0; - } - - @Override - public boolean canPause() { - return true; - } - - @Override - public boolean canSeekBackward() { - return true; - } - - @Override - public boolean canSeekForward() { - return true; - } - - @Override - public int getAudioSessionId() { - return 0; - } - - @Override - public void onCompletion(MediaPlayer mp) { - isCompleted = true; - mEventEmitter.receiveEvent(getId(), Events.EVENT_END.toString(), null); - if (!mRepeat) { - setKeepScreenOn(false); - } - } - - // This is not fully tested and does not work for all forms of timed metadata - @TargetApi(23) // 6.0 - public class TimedMetaDataAvailableListener - implements MediaPlayer.OnTimedMetaDataAvailableListener - { - public void onTimedMetaDataAvailable(MediaPlayer mp, TimedMetaData data) { - WritableMap event = Arguments.createMap(); - - try { - String rawMeta = new String(data.getMetaData(), "UTF-8"); - WritableMap id3 = Arguments.createMap(); - - id3.putString(EVENT_PROP_METADATA_VALUE, rawMeta.substring(rawMeta.lastIndexOf("\u0003") + 1)); - id3.putString(EVENT_PROP_METADATA_IDENTIFIER, "id3/TDEN"); - - WritableArray metadata = new WritableNativeArray(); - - metadata.pushMap(id3); - - event.putArray(EVENT_PROP_METADATA, metadata); - event.putDouble(EVENT_PROP_TARGET, getId()); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - - mEventEmitter.receiveEvent(getId(), Events.EVENT_TIMED_METADATA.toString(), event); - } - } - - @Override - protected void onDetachedFromWindow() { - mMediaPlayerValid = false; - super.onDetachedFromWindow(); - setKeepScreenOn(false); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - if(mMainVer>0) { - setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders, mMainVer, mPatchVer); - } - else { - setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders); - } - setKeepScreenOn(mPreventsDisplaySleepDuringVideoPlayback); - } - - @Override - public void onHostPause() { - if (mMediaPlayerValid && !mPaused && !mPlayInBackground) { - /* Pause the video in background - * Don't update the paused prop, developers should be able to update it on background - * so that when you return to the app the video is paused - */ - mBackgroundPaused = true; - mMediaPlayer.pause(); - } - } - - @Override - public void onHostResume() { - mBackgroundPaused = false; - if (mMediaPlayerValid && !mPlayInBackground && !mPaused) { - new Handler().post(new Runnable() { - @Override - public void run() { - // Restore original state - setPausedModifier(false); - } - }); - } - } - - @Override - public void onHostDestroy() { - } - - /** - * toStringMap converts a {@link ReadableMap} into a HashMap. - * - * @param readableMap The ReadableMap to be conveted. - * @return A HashMap containing the data that was in the ReadableMap. - * @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java' - */ - public static Map toStringMap(@Nullable ReadableMap readableMap) { - Map result = new HashMap<>(); - if (readableMap == null) - return result; - - com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); - while (iterator.hasNextKey()) { - String key = iterator.nextKey(); - result.put(key, readableMap.getString(key)); - } - - return result; - } - - // Select track (so we can use it to listen to timed meta data updates) - private void selectTimedMetadataTrack(MediaPlayer mp) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return; - } - try { // It's possible this could throw an exception if the framework doesn't support getting track info - MediaPlayer.TrackInfo[] trackInfo = mp.getTrackInfo(); - for (int i = 0; i < trackInfo.length; ++i) { - if (trackInfo[i].getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) { - mp.selectTrack(i); - break; - } - } - } catch (Exception e) {} - } -} diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java b/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java deleted file mode 100644 index 59efab49..00000000 --- a/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.brentvatne.react; - -import com.brentvatne.react.ReactVideoView.Events; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.SimpleViewManager; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.events.RCTEventEmitter; -import com.yqritc.scalablevideoview.ScalableType; - -import javax.annotation.Nullable; -import java.util.Map; - -public class ReactVideoViewManager extends SimpleViewManager { - - public static final String REACT_CLASS = "RCTVideo"; - - public static final String PROP_SRC = "src"; - public static final String PROP_SRC_URI = "uri"; - public static final String PROP_SRC_TYPE = "type"; - public static final String PROP_SRC_HEADERS = "requestHeaders"; - public static final String PROP_SRC_IS_NETWORK = "isNetwork"; - public static final String PROP_SRC_MAINVER = "mainVer"; - public static final String PROP_SRC_PATCHVER = "patchVer"; - public static final String PROP_SRC_IS_ASSET = "isAsset"; - public static final String PROP_RESIZE_MODE = "resizeMode"; - public static final String PROP_REPEAT = "repeat"; - public static final String PROP_PAUSED = "paused"; - public static final String PROP_MUTED = "muted"; - public static final String PROP_PREVENTS_DISPLAY_SLEEP_DURING_VIDEO_PLAYBACK = "preventsDisplaySleepDuringVideoPlayback"; - public static final String PROP_VOLUME = "volume"; - public static final String PROP_STEREO_PAN = "stereoPan"; - public static final String PROP_PROGRESS_UPDATE_INTERVAL = "progressUpdateInterval"; - public static final String PROP_SEEK = "seek"; - public static final String PROP_RATE = "rate"; - public static final String PROP_FULLSCREEN = "fullscreen"; - public static final String PROP_PLAY_IN_BACKGROUND = "playInBackground"; - public static final String PROP_CONTROLS = "controls"; - - @Override - public String getName() { - return REACT_CLASS; - } - - @Override - protected ReactVideoView createViewInstance(ThemedReactContext themedReactContext) { - return new ReactVideoView(themedReactContext); - } - - @Override - public void onDropViewInstance(ReactVideoView view) { - super.onDropViewInstance(view); - view.cleanupMediaPlayerResources(); - } - - @Override - @Nullable - public Map getExportedCustomDirectEventTypeConstants() { - MapBuilder.Builder builder = MapBuilder.builder(); - for (Events event : Events.values()) { - builder.put(event.toString(), MapBuilder.of("registrationName", event.toString())); - } - return builder.build(); - } - - @Override - @Nullable - public Map getExportedViewConstants() { - return MapBuilder.of( - "ScaleNone", Integer.toString(ScalableType.LEFT_TOP.ordinal()), - "ScaleToFill", Integer.toString(ScalableType.FIT_XY.ordinal()), - "ScaleAspectFit", Integer.toString(ScalableType.FIT_CENTER.ordinal()), - "ScaleAspectFill", Integer.toString(ScalableType.CENTER_CROP.ordinal()) - ); - } - - @ReactProp(name = PROP_SRC) - public void setSrc(final ReactVideoView videoView, @Nullable ReadableMap src) { - int mainVer = src.getInt(PROP_SRC_MAINVER); - int patchVer = src.getInt(PROP_SRC_PATCHVER); - if(mainVer<0) { mainVer = 0; } - if(patchVer<0) { patchVer = 0; } - if(mainVer>0) { - videoView.setSrc( - src.getString(PROP_SRC_URI), - src.getString(PROP_SRC_TYPE), - src.getBoolean(PROP_SRC_IS_NETWORK), - src.getBoolean(PROP_SRC_IS_ASSET), - src.getMap(PROP_SRC_HEADERS), - mainVer, - patchVer - ); - } - else { - videoView.setSrc( - src.getString(PROP_SRC_URI), - src.getString(PROP_SRC_TYPE), - src.getBoolean(PROP_SRC_IS_NETWORK), - src.getBoolean(PROP_SRC_IS_ASSET), - src.getMap(PROP_SRC_HEADERS) - ); - } - } - - @ReactProp(name = PROP_PREVENTS_DISPLAY_SLEEP_DURING_VIDEO_PLAYBACK) - public void setPropPreventsDisplaySleepDuringVideoPlayback(final ReactVideoView videoView, final boolean doPreventSleep) { - videoView.setPreventsDisplaySleepDuringVideoPlaybackModifier(doPreventSleep); - } - - @ReactProp(name = PROP_RESIZE_MODE) - public void setResizeMode(final ReactVideoView videoView, final String resizeModeOrdinalString) { - videoView.setResizeModeModifier(ScalableType.values()[Integer.parseInt(resizeModeOrdinalString)]); - } - - @ReactProp(name = PROP_REPEAT, defaultBoolean = false) - public void setRepeat(final ReactVideoView videoView, final boolean repeat) { - videoView.setRepeatModifier(repeat); - } - - @ReactProp(name = PROP_PAUSED, defaultBoolean = false) - public void setPaused(final ReactVideoView videoView, final boolean paused) { - videoView.setPausedModifier(paused); - } - - @ReactProp(name = PROP_MUTED, defaultBoolean = false) - public void setMuted(final ReactVideoView videoView, final boolean muted) { - videoView.setMutedModifier(muted); - } - - @ReactProp(name = PROP_VOLUME, defaultFloat = 1.0f) - public void setVolume(final ReactVideoView videoView, final float volume) { - videoView.setVolumeModifier(volume); - } - - @ReactProp(name = PROP_STEREO_PAN) - public void setStereoPan(final ReactVideoView videoView, final float stereoPan) { - videoView.setStereoPan(stereoPan); - } - - @ReactProp(name = PROP_PROGRESS_UPDATE_INTERVAL, defaultFloat = 250.0f) - public void setProgressUpdateInterval(final ReactVideoView videoView, final float progressUpdateInterval) { - videoView.setProgressUpdateInterval(progressUpdateInterval); - } - - @ReactProp(name = PROP_SEEK) - public void setSeek(final ReactVideoView videoView, final float seek) { - videoView.seekTo(Math.round(seek * 1000.0f)); - } - - @ReactProp(name = PROP_RATE) - public void setRate(final ReactVideoView videoView, final float rate) { - videoView.setRateModifier(rate); - } - - @ReactProp(name = PROP_FULLSCREEN, defaultBoolean = false) - public void setFullscreen(final ReactVideoView videoView, final boolean fullscreen) { - videoView.setFullscreen(fullscreen); - } - - @ReactProp(name = PROP_PLAY_IN_BACKGROUND, defaultBoolean = false) - public void setPlayInBackground(final ReactVideoView videoView, final boolean playInBackground) { - videoView.setPlayInBackground(playInBackground); - } - - @ReactProp(name = PROP_CONTROLS, defaultBoolean = false) - public void setControls(final ReactVideoView videoView, final boolean controls) { - videoView.setControls(controls); - } -} From de2c4a552429137319e805b90b79c4286afbf986 Mon Sep 17 00:00:00 2001 From: olivier bouillet Date: Wed, 15 Jun 2022 22:30:24 +0200 Subject: [PATCH 06/21] chore: move android-exoplayer to android folder --- {android-exoplayer => android}/README.md | 0 {android-exoplayer => android}/build.gradle | 0 {android-exoplayer => android}/src/main/AndroidManifest.xml | 0 .../java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java | 0 .../src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java | 0 .../com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java | 0 .../src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java | 0 .../com/brentvatne/exoplayer/RawResourceDataSourceFactory.java | 0 .../main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java | 0 .../exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java | 0 .../main/java/com/brentvatne/exoplayer/ReactExoplayerView.java | 0 .../java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java | 0 .../src/main/java/com/brentvatne/exoplayer/ResizeMode.java | 0 .../src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java | 0 .../src/main/java/com/brentvatne/react/ReactVideoPackage.java | 0 .../java/com/brentvatne/receiver/AudioBecomingNoisyReceiver.java | 0 .../main/java/com/brentvatne/receiver/BecomingNoisyListener.java | 0 .../src/main/res/layout/exo_player_control_view.xml | 0 {android-exoplayer => android}/src/main/res/values/strings.xml | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename {android-exoplayer => android}/README.md (100%) rename {android-exoplayer => android}/build.gradle (100%) rename {android-exoplayer => android}/src/main/AndroidManifest.xml (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/RawResourceDataSourceFactory.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/ResizeMode.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/react/ReactVideoPackage.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/receiver/AudioBecomingNoisyReceiver.java (100%) rename {android-exoplayer => android}/src/main/java/com/brentvatne/receiver/BecomingNoisyListener.java (100%) rename {android-exoplayer => android}/src/main/res/layout/exo_player_control_view.xml (100%) rename {android-exoplayer => android}/src/main/res/values/strings.xml (100%) diff --git a/android-exoplayer/README.md b/android/README.md similarity index 100% rename from android-exoplayer/README.md rename to android/README.md diff --git a/android-exoplayer/build.gradle b/android/build.gradle similarity index 100% rename from android-exoplayer/build.gradle rename to android/build.gradle diff --git a/android-exoplayer/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml similarity index 100% rename from android-exoplayer/src/main/AndroidManifest.xml rename to android/src/main/AndroidManifest.xml diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java b/android/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java rename to android/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java b/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java rename to android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java b/android/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java rename to android/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java rename to android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/RawResourceDataSourceFactory.java b/android/src/main/java/com/brentvatne/exoplayer/RawResourceDataSourceFactory.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/RawResourceDataSourceFactory.java rename to android/src/main/java/com/brentvatne/exoplayer/RawResourceDataSourceFactory.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java rename to android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java rename to android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java rename to android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java rename to android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ResizeMode.java b/android/src/main/java/com/brentvatne/exoplayer/ResizeMode.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/ResizeMode.java rename to android/src/main/java/com/brentvatne/exoplayer/ResizeMode.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java b/android/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java rename to android/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/react/ReactVideoPackage.java b/android/src/main/java/com/brentvatne/react/ReactVideoPackage.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/react/ReactVideoPackage.java rename to android/src/main/java/com/brentvatne/react/ReactVideoPackage.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/receiver/AudioBecomingNoisyReceiver.java b/android/src/main/java/com/brentvatne/receiver/AudioBecomingNoisyReceiver.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/receiver/AudioBecomingNoisyReceiver.java rename to android/src/main/java/com/brentvatne/receiver/AudioBecomingNoisyReceiver.java diff --git a/android-exoplayer/src/main/java/com/brentvatne/receiver/BecomingNoisyListener.java b/android/src/main/java/com/brentvatne/receiver/BecomingNoisyListener.java similarity index 100% rename from android-exoplayer/src/main/java/com/brentvatne/receiver/BecomingNoisyListener.java rename to android/src/main/java/com/brentvatne/receiver/BecomingNoisyListener.java diff --git a/android-exoplayer/src/main/res/layout/exo_player_control_view.xml b/android/src/main/res/layout/exo_player_control_view.xml similarity index 100% rename from android-exoplayer/src/main/res/layout/exo_player_control_view.xml rename to android/src/main/res/layout/exo_player_control_view.xml diff --git a/android-exoplayer/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml similarity index 100% rename from android-exoplayer/src/main/res/values/strings.xml rename to android/src/main/res/values/strings.xml From 466d7c31702a038c0fab8b059f315fcf87019ef5 Mon Sep 17 00:00:00 2001 From: olivier bouillet Date: Wed, 15 Jun 2022 22:51:04 +0200 Subject: [PATCH 07/21] chore: cleanup documentation --- .github/ISSUE_TEMPLATE.md | 3 +- .github/ISSUE_TEMPLATE/bug_report.md | 5 +- API.md | 173 +++++++++++-------------- Video.js | 1 - examples/basic/android/settings.gradle | 2 +- package.json | 1 - 6 files changed, 79 insertions(+), 106 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index b0312b30..9284cecf 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -10,8 +10,7 @@ Describe what you wanted to happen ### Platform Which player are you experiencing the problem on: * iOS -* Android ExoPlayer -* Android MediaPlayer +* Android * Windows UWP * Windows WPF diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ac2d1e3e..54296c23 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -18,12 +18,11 @@ assignees: '' ## Platform Which player are you experiencing the problem on: * iOS -* Android ExoPlayer -* Android MediaPlayer +* Android * Windows UWP * Windows WPF diff --git a/API.md b/API.md index 13eb89c0..46053502 100644 --- a/API.md +++ b/API.md @@ -111,14 +111,7 @@ Or if you have trouble, make the following additions to the given files manually #### **android/settings.gradle** -The newer ExoPlayer library will work for most people. - -```gradle -include ':react-native-video' -project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer') -``` - -If you need to use the old Android MediaPlayer based player, use the following instead: +Add player source in build configuration ```gradle include ':react-native-video' @@ -302,29 +295,29 @@ var styles = StyleSheet.create({ |[allowsExternalPlayback](#allowsexternalplayback) |iOS | |[audioOnly](#audioonly)|All | |[automaticallyWaitsToMinimizeStalling](#automaticallyWaitsToMinimizeStalling) | iOS|\ -|[backBufferDurationMs](#backBufferDurationMs)| Android Exoplayer| -|[bufferConfig](#bufferconfig)|Android ExoPlayer| -|[contentStartTime](#contentStartTime)| Android Exoplayer| -|[controls](#controls)|Android ExoPlayer, iOS, react-native-dom| -|[currentPlaybackTime](#currentPlaybackTime)|Android Exoplayer| -|[disableFocus](#disableFocus)|Android Exoplayer, iOS| -|[disableDisconnectError](#disableDisconnectError)|Android Exoplayer| +|[backBufferDurationMs](#backBufferDurationMs)| Android | +|[bufferConfig](#bufferconfig)|Android| +|[contentStartTime](#contentStartTime)| Android | +|[controls](#controls)|Android, iOS, react-native-dom| +|[currentPlaybackTime](#currentPlaybackTime)|Android| +|[disableFocus](#disableFocus)|Android, iOS| +|[disableDisconnectError](#disableDisconnectError)|Android| |[filter](#filter)|iOS| |[filterEnabled](#filterEnabled)|iOS| |[fullscreen](#fullscreen)|iOS| |[fullscreenAutorotate](#fullscreenautorotate)|iOS| |[fullscreenOrientation](#fullscreenorientation)|iOS| -|[headers](#headers)|Android ExoPlayer| -|[hideShutterView](#hideshutterview)|Android ExoPlayer| +|[headers](#headers)|Android| +|[hideShutterView](#hideshutterview)|Android| |[id](#id)|react-native-dom| |[ignoreSilentSwitch](#ignoresilentswitch)|iOS| -|[maxBitRate](#maxbitrate)|Android ExoPlayer, iOS| -|[minLoadRetryCount](#minLoadRetryCount)|Android ExoPlayer| +|[maxBitRate](#maxbitrate)|Android, iOS| +|[minLoadRetryCount](#minLoadRetryCount)|Android| |[mixWithOthers](#mixWithOthers)|iOS| |[muted](#muted)|All| |[paused](#paused)|All| |[pictureInPicture](#pictureinpicture)|iOS| -|[playInBackground](#playinbackground)|Android ExoPlayer, Android MediaPlayer, iOS| +|[playInBackground](#playinbackground)|Android, iOS| |[playWhenInactive](#playwheninactive)|iOS| |[poster](#poster)|All| |[posterResizeMode](#posterresizemode)|All| @@ -333,17 +326,16 @@ var styles = StyleSheet.create({ |[progressUpdateInterval](#progressupdateinterval)|All| |[rate](#rate)|All| |[repeat](#repeat)|All| -|[reportBandwidth](#reportbandwidth)|Android ExoPlayer| -|[resizeMode](#resizemode)|Android ExoPlayer, Android MediaPlayer, iOS, Windows UWP| -|[selectedAudioTrack](#selectedaudiotrack)|Android ExoPlayer, iOS| -|[selectedTextTrack](#selectedtexttrack)|Android ExoPlayer, iOS| -|[selectedVideoTrack](#selectedvideotrack)|Android ExoPlayer| +|[reportBandwidth](#reportbandwidth)|Android| +|[resizeMode](#resizemode)|Android, iOS, Windows UWP| +|[selectedAudioTrack](#selectedaudiotrack)|Android, iOS| +|[selectedTextTrack](#selectedtexttrack)|Android, iOS| +|[selectedVideoTrack](#selectedvideotrack)|Android| |[source](#source)|All| -|[stereoPan](#stereopan)|Android MediaPlayer| -|[textTracks](#texttracks)|Android ExoPlayer, iOS| -|[trackId](#trackId)|Android ExoPlayer| -|[useTextureView](#usetextureview)|Android ExoPlayer| -|[useSecureView](#useSecureView)|Android Exoplayer| +|[textTracks](#texttracks)|Android, iOS| +|[trackId](#trackId)|Android| +|[useTextureView](#usetextureview)|Android| +|[useSecureView](#useSecureView)|Android| |[volume](#volume)|All| |[localSourceEncryptionKeyScheme](#localSourceEncryptionKeyScheme)|All| @@ -351,31 +343,31 @@ var styles = StyleSheet.create({ ### Event props | Name |Plateforms Support | |--|--| -|[onAudioBecomingNoisy](#onaudiobecomingnoisy)|Android ExoPlayer, iOS| -|[onBandwidthUpdate](#onbandwidthupdate)|Android ExoPlayer| -|[onBuffer](#onbuffer)|Android ExoPlayer, iOS| +|[onAudioBecomingNoisy](#onaudiobecomingnoisy)|Android, iOS| +|[onBandwidthUpdate](#onbandwidthupdate)|Android| +|[onBuffer](#onbuffer)|Android, iOS| |[onEnd](#onend)|All| |[onExternalPlaybackChange](#onexternalplaybackchange)|iOS| -|[onFullscreenPlayerWillPresent](#onfullscreenplayerwillpresent)|Android ExoPlayer, Android MediaPlayer, iOS| -|[onFullscreenPlayerDidPresent](#onfullscreenplayerdidpresent)|Android ExoPlayer, Android MediaPlayer, iOS| -|[onFullscreenPlayerWillDismiss](#onfullscreenplayerwilldismiss)|Android ExoPlayer, Android MediaPlayer, iOS| -|[onFullscreenPlayerDidDismiss](#onfullscreenplayerdiddismiss)|Android ExoPlayer, Android MediaPlayer, iOS| +|[onFullscreenPlayerWillPresent](#onfullscreenplayerwillpresent)|Android, iOS| +|[onFullscreenPlayerDidPresent](#onfullscreenplayerdidpresent)|Android, iOS| +|[onFullscreenPlayerWillDismiss](#onfullscreenplayerwilldismiss)|Android, iOS| +|[onFullscreenPlayerDidDismiss](#onfullscreenplayerdiddismiss)|Android, iOS| |[onLoad](#onload)|All| |[onLoadStart](#onloadstart)|All| -|[onReadyForDisplay](#onreadyfordisplay)|Android ExoPlayer, Android MediaPlayer, iOS, Web| +|[onReadyForDisplay](#onreadyfordisplay)|Android, iOS, Web| |[onPictureInPictureStatusChanged](#onpictureinpicturestatuschanged)|iOS| |[onPlaybackRateChange](#onplaybackratechange)|All| |[onProgress](#onprogress)|All| -|[onSeek](#onseek)|Android ExoPlayer, Android MediaPlayer, iOS, Windows UWP| +|[onSeek](#onseek)|Android, iOS, Windows UWP| |[onRestoreUserInterfaceForPictureInPictureStop](#onrestoreuserinterfaceforpictureinpicturestop)|iOS| -|[onTimedMetadata](#ontimedmetadata)|Android ExoPlayer, Android MediaPlayer, iOS| +|[onTimedMetadata](#ontimedmetadata)|Android, iOS| ### Methods | Name |Plateforms Support | |--|--| -|[dismissFullscreenPlayer](#dismissfullscreenplayer)|Android ExoPlayer, Android MediaPlayer, iOS| -|[presentFullscreenPlayer](#presentfullscreenplayer)|Android ExoPlayer, Android MediaPlayer, iOS| +|[dismissFullscreenPlayer](#dismissfullscreenplayer)|Android, iOS| +|[presentFullscreenPlayer](#presentfullscreenplayer)|Android, iOS| |[save](#save)|iOS| |[restoreUserInterfaceForPictureInPictureStop](#restoreuserinterfaceforpictureinpicturestop)|iOS| |[seek](#seek)|All| @@ -409,7 +401,7 @@ Platforms: iOS #### backBufferDurationMs The number of milliseconds of buffer to keep before the current position. This allows rewinding without rebuffering within that duration. -Platforms: Android ExoPlayer +Platforms: Android #### bufferConfig Adjust the buffer settings. This prop takes an object with one or more of the properties listed below. @@ -436,12 +428,12 @@ bufferConfig={{ }} ``` -Platforms: Android ExoPlayer +Platforms: Android #### currentPlaybackTime When playing an HLS live stream with a `EXT-X-PROGRAM-DATE-TIME` tag configured, then this property will contain the epoch value in msec. -Platforms: Android ExoPlayer, iOS +Platforms: Android, iOS #### controls Determines whether to show player controls. @@ -453,30 +445,28 @@ Note on iOS, controls are always shown when in fullscreen mode. ### contentStartTime The start time in ms for SSAI content. This determines at what time to load the video info like resolutions. Use this only when you have SSAI stream where ads resolution is not the same as content resolution. -For Android MediaPlayer, you will need to build your own controls or use a package like [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls) or [react-native-video-player](https://github.com/cornedor/react-native-video-player). +Note on Android, native controls are available by default. If needed, you can also add your controls or use a package like [react-native-video-controls]. -Note on Android ExoPlayer, native controls are available by default. If needed, you can also add your controls or use a package like [react-native-video-controls]. - -Platforms: Android ExoPlayer, iOS, react-native-dom +Platforms: Android, iOS, react-native-dom #### disableFocus Determines whether video audio should override background music/audio in Android devices. * ** false (default)** - Override background audio/music * **true** - Let background audio/music from other apps play -Platforms: Android Exoplayer +Platforms: Android #### disableDisconnectError Determines if the player needs to throw an error when connection is lost or not * **false (default)** - Player will throw an error when connection is lost * **true** - Player will keep trying to buffer when network connect is lost -Platforms: Android Exoplayer +Platforms: Android ### DRM To setup DRM please follow [this guide](./DRM.md) -Platforms: Android Exoplayer, iOS +Platforms: Android, iOS #### filter Add video filter @@ -548,7 +538,7 @@ source={{ }} ``` -Platforms: Android ExoPlayer +Platforms: Android #### hideShutterView Controls whether the ExoPlayer shutter view (black screen while loading) is enabled. @@ -556,7 +546,7 @@ Controls whether the ExoPlayer shutter view (black screen while loading) is enab * **false (default)** - Show shutter view * **true** - Hide shutter view -Platforms: Android ExoPlayer +Platforms: Android #### id Set the DOM id element so you can use document.getElementById on web platforms. Accepts string values. @@ -586,7 +576,7 @@ Example: maxBitRate={2000000} // 2 megabits ``` -Platforms: Android ExoPlayer, iOS +Platforms: Android, iOS #### minLoadRetryCount Sets the minimum number of times to retry loading data before failing and reporting an error to the application. Useful to recover from transient internet failures. @@ -598,7 +588,7 @@ Example: minLoadRetryCount={5} // retry 5 times ``` -Platforms: Android ExoPlayer +Platforms: Android #### mixWithOthers Controls how Audio mix with other apps. @@ -638,7 +628,7 @@ To use this feature on iOS, you must: * [Enable Background Audio](https://developer.apple.com/library/archive/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/AudioSessionBasics/AudioSessionBasics.html#//apple_ref/doc/uid/TP40007875-CH3-SW3) in your Xcode project * Set the ignoreSilentSwitch prop to "ignore" -Platforms: Android ExoPlayer, Android MediaPlayer, iOS +Platforms: Android, iOS #### playWhenInactive Determine whether the media should continue playing when notifications or the Control Center are in front of the video. @@ -693,8 +683,6 @@ Speed at which the media should play. Platforms: all -Note: For Android MediaPlayer, rate is only supported on Android 6.0 and higher devices. - #### repeat Determine whether to repeat the video when the end is reached * **false (default)** - Don't repeat the video @@ -708,7 +696,7 @@ Determine whether to generate onBandwidthUpdate events. This is needed due to th * **false (default)** - Don't generate onBandwidthUpdate events * **true** - Generate onBandwidthUpdate events -Platforms: Android ExoPlayer +Platforms: Android #### resizeMode Determines how to resize the video when the frame doesn't match the raw video dimensions. @@ -717,7 +705,7 @@ Determines how to resize the video when the frame doesn't match the raw video di * **"cover"** - Scale the video uniformly (maintain the video's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding). * **"stretch"** - Scale width and height independently, This may change the aspect ratio of the src. -Platforms: Android ExoPlayer, Android MediaPlayer, iOS, Windows UWP +Platforms: Android, iOS, Windows UWP #### selectedAudioTrack Configure which audio track, if any, is played. @@ -747,7 +735,7 @@ Type | Value | Description If a track matching the specified Type (and Value if appropriate) is unavailable, the first audio track will be played. If multiple tracks match the criteria, the first match will be used. -Platforms: Android ExoPlayer, iOS +Platforms: Android, iOS #### selectedTextTrack Configure which text track (caption or subtitle), if any, is shown. @@ -779,7 +767,7 @@ Both iOS & Android (only 4.4 and higher) offer Settings to enable Captions for h If a track matching the specified Type (and Value if appropriate) is unavailable, no text track will be displayed. If multiple tracks match the criteria, the first match will be used. -Platforms: Android ExoPlayer, iOS +Platforms: Android, iOS #### selectedVideoTrack Configure which video track should be played. By default, the player uses Adaptive Bitrate Streaming to automatically select the stream it thinks will perform best based on available bandwidth. @@ -808,7 +796,7 @@ Type | Value | Description If a track matching the specified Type (and Value if appropriate) is unavailable, ABR will be used. -Platforms: Android ExoPlayer +Platforms: Android #### source Sets the media source. You can pass an asset loaded via require or an object with a uri. @@ -853,7 +841,7 @@ 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. -Platforms: Android ExoPlayer, Android MediaPlayer, possibly others +Platforms: Android, possibly others ###### iPod Library (ipod-library://) @@ -885,14 +873,6 @@ The following other types are supported on some platforms, but aren't fully docu `content://, ms-appx://, ms-appdata://, assets-library://` -#### stereoPan -Adjust the balance of the left and right audio channels. Any value between –1.0 and 1.0 is accepted. -* **-1.0** - Full left -* **0.0 (default)** - Center -* **1.0** - Full right - -Platforms: Android MediaPlayer - #### textTracks Load one or more "sidecar" text tracks. This takes an array of objects representing each track. Each object should have the format: @@ -900,7 +880,7 @@ Property | Description --- | --- title | Descriptive name for the track language | 2 letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) representing the language -type | Mime type of the track
* TextTrackType.SRT - SubRip (.srt)
* TextTrackType.TTML - TTML (.ttml)
* TextTrackType.VTT - WebVTT (.vtt)
iOS only supports VTT, Android ExoPlayer supports all 3 +type | Mime type of the track
* TextTrackType.SRT - SubRip (.srt)
* TextTrackType.TTML - TTML (.ttml)
* TextTrackType.VTT - WebVTT (.vtt)
iOS only supports VTT, Android supports all 3 uri | URL for the text track. Currently, only tracks hosted on a webserver are supported On iOS, sidecar text tracks are only supported for individual files, not HLS playlists. For HLS, you should include the text tracks as part of the playlist. @@ -928,12 +908,12 @@ textTracks={[ ``` -Platforms: Android ExoPlayer, iOS +Platforms: Android, iOS #### trackId Configure an identifier for the video stream to link the playback context to the events emitted. -Platforms: Android ExoPlayer +Platforms: Android #### useTextureView Controls whether to output to a TextureView or SurfaceView. @@ -947,7 +927,7 @@ useTextureView can only be set at same time you're setting the source. * **true (default)** - Use a TextureView * **false** - Use a SurfaceView -Platforms: Android ExoPlayer +Platforms: Android #### useSecureView Force the output to a SurfaceView and enables the secure surface. @@ -959,7 +939,7 @@ SurfaceView is is the only one that can be labeled as secure. * **true** - Use security * **false (default)** - Do not use security -Platforms: Android ExoPlayer +Platforms: Android #### volume Adjust the volume. @@ -989,7 +969,7 @@ Callback function that is called when the audio is about to become 'noisy' due t Payload: none -Platforms: Android ExoPlayer, iOS +Platforms: Android, iOS #### onBandwidthUpdate Callback function that is called when the available bandwidth changes. @@ -1007,9 +987,9 @@ Example: } ``` -Note: On Android ExoPlayer, you must set the [reportBandwidth](#reportbandwidth) prop to enable this event. This is due to the high volume of events generated. +Note: On Android, you must set the [reportBandwidth](#reportbandwidth) prop to enable this event. This is due to the high volume of events generated. -Platforms: Android ExoPlayer +Platforms: Android #### onBuffer Callback function that is called when the player buffers. @@ -1027,7 +1007,7 @@ Example: } ``` -Platforms: Android ExoPlayer, iOS +Platforms: Android, iOS #### onEnd Callback function that is called when the player reaches the end of the media. @@ -1059,28 +1039,28 @@ Callback function that is called when the player is about to enter fullscreen mo Payload: none -Platforms: Android ExoPlayer, Android MediaPlayer, iOS +Platforms: Android, iOS #### onFullscreenPlayerDidPresent Callback function that is called when the player has entered fullscreen mode. Payload: none -Platforms: Android ExoPlayer, Android MediaPlayer, iOS +Platforms: Android, iOS #### onFullscreenPlayerWillDismiss Callback function that is called when the player is about to exit fullscreen mode. Payload: none -Platforms: Android ExoPlayer, Android MediaPlayer, iOS +Platforms: Android, iOS #### onFullscreenPlayerDidDismiss Callback function that is called when the player has exited fullscreen mode. Payload: none -Platforms: Android ExoPlayer, Android MediaPlayer, iOS +Platforms: Android, iOS #### onLoad Callback function that is called when the media is loaded and ready to play. @@ -1169,7 +1149,7 @@ Example: } ``` -Platforms: Android ExoPlayer +Platforms: Android #### onReadyForDisplay Callback function that is called when the first video frame is ready for display. This is when the poster is removed. @@ -1177,10 +1157,9 @@ Callback function that is called when the first video frame is ready for display Payload: none * iOS: [readyForDisplay](https://developer.apple.com/documentation/avkit/avplayerviewcontroller/1615830-readyfordisplay?language=objc) -* Android: [MEDIA_INFO_VIDEO_RENDERING_START](https://developer.android.com/reference/android/media/MediaPlayer#MEDIA_INFO_VIDEO_RENDERING_START) -* Android ExoPlayer [STATE_READY](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/Player.html#STATE_READY) +* Android [STATE_READY](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/Player.html#STATE_READY) -Platforms: Android ExoPlayer, Android MediaPlayer, iOS, Web +Platforms: Android, iOS, Web #### onPictureInPictureStatusChanged Callback function that is called when picture in picture becomes active or inactive. @@ -1256,7 +1235,7 @@ Example: Both the currentTime & seekTime are reported because the video player may not seek to the exact requested position in order to improve seek performance. -Platforms: Android ExoPlayer, Android MediaPlayer, iOS, Windows UWP +Platforms: Android, iOS, Windows UWP #### onRestoreUserInterfaceForPictureInPictureStop Callback function that corresponds to Apple's [`restoreUserInterfaceForPictureInPictureStopWithCompletionHandler`](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). Call `restoreUserInterfaceForPictureInPictureStopCompleted` inside of this function when done restoring the user interface. @@ -1285,9 +1264,7 @@ Example: } ``` -Support for timed metadata on Android MediaPlayer is limited at best and only compatible with some videos. It requires a target SDK of 23 or higher. - -Platforms: Android ExoPlayer, Android MediaPlayer, iOS +Platforms: Android, iOS ### Methods Methods operate on a ref to the Video element. You can create a ref using code like: @@ -1308,7 +1285,7 @@ Example: this.player.dismissFullscreenPlayer(); ``` -Platforms: Android ExoPlayer, Android MediaPlayer, iOS +Platforms: Android, iOS #### presentFullscreenPlayer `presentFullscreenPlayer()` @@ -1317,14 +1294,14 @@ Put the player in fullscreen mode. On iOS, this displays the video in a fullscreen view controller with controls. -On Android ExoPlayer & MediaPlayer, this puts the navigation controls in fullscreen mode. It is not a complete fullscreen implementation, so you will still need to apply a style that makes the width and height match your screen dimensions to get a fullscreen video. +On Android, this puts the navigation controls in fullscreen mode. It is not a complete fullscreen implementation, so you will still need to apply a style that makes the width and height match your screen dimensions to get a fullscreen video. Example: ``` this.player.presentFullscreenPlayer(); ``` -Platforms: Android ExoPlayer, Android MediaPlayer, iOS +Platforms: Android, iOS #### save `save(): Promise` @@ -1539,7 +1516,7 @@ android { ``` #### ExoPlayer no longer detaches -When using a router like the react-navigation TabNavigator, switching between tab routes would previously cause ExoPlayer to detach causing the video player to pause. We now don't detach the view, allowing the video to continue playing in a background tab. This matches the behavior for iOS. Android MediaPlayer will crash if it detaches when switching routes, so its behavior has not been changed. +When using a router like the react-navigation TabNavigator, switching between tab routes would previously cause ExoPlayer to detach causing the video player to pause. We now don't detach the view, allowing the video to continue playing in a background tab. This matches the behavior for iOS. #### useTextureView now defaults to true The SurfaceView, which ExoPlayer has been using by default has a number of quirks that people are unaware of and often cause issues. This includes not supporting animations or scaling. It also causes strange behavior if you overlay two videos on top of each other, because the SurfaceView will [punch a hole](https://developer.android.com/reference/android/view/SurfaceView) through other views. Since TextureView doesn't have these issues and behaves in the way most developers expect, it makes sense to make it the default. diff --git a/Video.js b/Video.js index ddd7d508..c1a05f79 100644 --- a/Video.js +++ b/Video.js @@ -473,7 +473,6 @@ Video.propTypes = { bufferForPlaybackAfterRebufferMs: PropTypes.number, maxHeapAllocationPercent: PropTypes.number, }), - stereoPan: PropTypes.number, rate: PropTypes.number, pictureInPicture: PropTypes.bool, playInBackground: PropTypes.bool, diff --git a/examples/basic/android/settings.gradle b/examples/basic/android/settings.gradle index 29cf817a..a78bc672 100644 --- a/examples/basic/android/settings.gradle +++ b/examples/basic/android/settings.gradle @@ -1,5 +1,5 @@ rootProject.name = 'VideoPlayer' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':react-native-video' -project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer') +project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android') include ':app' diff --git a/package.json b/package.json index a309f21e..40c3f72c 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "xbasic": "yarn --cwd examples/basic" }, "files": [ - "android-exoplayer", "android", "dom", "ios", From df70900c8ff91bf8f1010c7f571314c84f850c68 Mon Sep 17 00:00:00 2001 From: olivier bouillet Date: Wed, 15 Jun 2022 22:54:34 +0200 Subject: [PATCH 08/21] chore: update changeLog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16f1b9a7..d10bf80b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Changelog ### Version 6.0.0-alpha1 +- Remove Android MediaPlayer support [#2724](https://github.com/react-native-video/react-native-video/pull/2724) - Support disabling buffering [#2689](https://github.com/react-native-video/react-native-video/pull/2689) - Fix AudioFocus bug that could cause the player to stop responding to play/pause in some instances. [#2689](https://github.com/react-native-video/react-native-video/pull/2689) - Fix player crashing when it is being cleared. [#2689](https://github.com/react-native-video/react-native-video/pull/2689) From cf4987f00c430b5e013f4bf0410fcdc4d7876d00 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 15 Jun 2022 16:54:36 -0700 Subject: [PATCH 09/21] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16f1b9a7..c5511cc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## Changelog -### Version 6.0.0-alpha1 +### Version 6.0.0-alpha.1 + +### Version 6.0.0-alpha.0 - Support disabling buffering [#2689](https://github.com/react-native-video/react-native-video/pull/2689) - Fix AudioFocus bug that could cause the player to stop responding to play/pause in some instances. [#2689](https://github.com/react-native-video/react-native-video/pull/2689) - Fix player crashing when it is being cleared. [#2689](https://github.com/react-native-video/react-native-video/pull/2689) From 2fdbc4bc97bb3b9af321f9e3f92df5b2be8a5c9d Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 15 Jun 2022 16:57:04 -0700 Subject: [PATCH 10/21] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5511cc8..d71097a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Version 6.0.0-alpha.1 +- Replace Image.propTypes with ImagePropTypes. [#2718](https://github.com/react-native-video/react-native-video/pull/2718) +- ### Version 6.0.0-alpha.0 - Support disabling buffering [#2689](https://github.com/react-native-video/react-native-video/pull/2689) - Fix AudioFocus bug that could cause the player to stop responding to play/pause in some instances. [#2689](https://github.com/react-native-video/react-native-video/pull/2689) From 2e508865f56e344bdbd1419f4f070d458d44d685 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Tue, 21 Jun 2022 23:26:27 -0700 Subject: [PATCH 11/21] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5f342bb..5b0ea9db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ ## Changelog +### Version 6.0.0-alpha2 + ### Version 6.0.0-alpha1 - Remove Android MediaPlayer support [#2724](https://github.com/react-native-video/react-native-video/pull/2724) - Replace Image.propTypes with ImagePropTypes. [#2718](https://github.com/react-native-video/react-native-video/pull/2718) +- Fix iOS build caused by type mismatch [#2720](https://github.com/react-native-video/react-native-video/pull/2720) +- ERROR TypeError: undefined is not an object (evaluating '_reactNative.Image.propTypes.resizeMode') [#2714](https://github.com/react-native-video/react-native-video/pull/2714) ### Version 6.0.0-alpha.0 - Support disabling buffering [#2689](https://github.com/react-native-video/react-native-video/pull/2689) From 553e51c63945931e2a5ce3a1665dbaa5c1f2f67e Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Tue, 21 Jun 2022 23:30:55 -0700 Subject: [PATCH 12/21] Port of #2329 --- ios/Video/RCTVideo.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index fb5270ab..59973a36 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -1043,6 +1043,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH item.seek(to: CMTime.zero) self.applyModifiers() } else { + self.setPaused(true); _playerObserver.removePlayerTimeObserver() } } From 58e0c854a430ec1125e33968b9993870894cc026 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Tue, 21 Jun 2022 23:31:46 -0700 Subject: [PATCH 13/21] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b0ea9db..2bc2ce8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Replace Image.propTypes with ImagePropTypes. [#2718](https://github.com/react-native-video/react-native-video/pull/2718) - Fix iOS build caused by type mismatch [#2720](https://github.com/react-native-video/react-native-video/pull/2720) - ERROR TypeError: undefined is not an object (evaluating '_reactNative.Image.propTypes.resizeMode') [#2714](https://github.com/react-native-video/react-native-video/pull/2714) +- Fix video endless loop when repeat set to false or not specified. #2329 ### Version 6.0.0-alpha.0 - Support disabling buffering [#2689](https://github.com/react-native-video/react-native-video/pull/2689) From d144a2f27c4e673a370ff06d4be9b32cd70128eb Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Tue, 21 Jun 2022 23:32:11 -0700 Subject: [PATCH 14/21] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bc2ce8b..66ee8d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ - Replace Image.propTypes with ImagePropTypes. [#2718](https://github.com/react-native-video/react-native-video/pull/2718) - Fix iOS build caused by type mismatch [#2720](https://github.com/react-native-video/react-native-video/pull/2720) - ERROR TypeError: undefined is not an object (evaluating '_reactNative.Image.propTypes.resizeMode') [#2714](https://github.com/react-native-video/react-native-video/pull/2714) -- Fix video endless loop when repeat set to false or not specified. #2329 +- Fix video endless loop when repeat set to false or not specified. [#2329](https://github.com/react-native-video/react-native-video/pull/2329) ### Version 6.0.0-alpha.0 - Support disabling buffering [#2689](https://github.com/react-native-video/react-native-video/pull/2689) From 1d34de4f9b662cd96e0855df4c2822875a1024ba Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 22 Jun 2022 06:35:04 +0000 Subject: [PATCH 15/21] Update copyright --- LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/LICENSE b/LICENSE index dc7f43c8..297b2cbe 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ MIT License +Copyright (c) 2016-2022 Project contributors Copyright (c) 2016 Brent Vatne, Baris Sencan Permission is hereby granted, free of charge, to any person obtaining a copy From 10f7e9701a6a79a92a5197f5f84a6770d7c3b4a6 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 22 Jun 2022 06:35:56 +0000 Subject: [PATCH 16/21] 6.0.0-alpha.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 40c3f72c..d0170412 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-video", - "version": "6.0.0-alpha.0", + "version": "6.0.0-alpha.1", "description": "A

- react-native-dom details - -Make the following additions to the given files manually: - -#### **dom/bootstrap.js** - -Import RCTVideoManager and add it to the list of nativeModules: - -```javascript -import { RNDomInstance } from "react-native-dom"; -import { name as appName } from "../app.json"; -import RCTVideoManager from 'react-native-video/dom/RCTVideoManager'; // Add this - -// Path to RN Bundle Entrypoint ================================================ -const rnBundlePath = "./entry.bundle?platform=dom&dev=true"; - -// React Native DOM Runtime Options ============================================= -const ReactNativeDomOptions = { - enableHotReload: false, - nativeModules: [RCTVideoManager] // Add this -}; -``` -
- ## Examples Run `yarn xbasic install` before running any of the examples. @@ -298,7 +269,7 @@ var styles = StyleSheet.create({ |[backBufferDurationMs](#backBufferDurationMs)| Android | |[bufferConfig](#bufferconfig)|Android| |[contentStartTime](#contentStartTime)| Android | -|[controls](#controls)|Android, iOS, react-native-dom| +|[controls](#controls)|Android, iOS| |[currentPlaybackTime](#currentPlaybackTime)|Android| |[disableFocus](#disableFocus)|Android, iOS| |[disableDisconnectError](#disableDisconnectError)|Android| @@ -309,7 +280,6 @@ var styles = StyleSheet.create({ |[fullscreenOrientation](#fullscreenorientation)|iOS| |[headers](#headers)|Android| |[hideShutterView](#hideshutterview)|Android| -|[id](#id)|react-native-dom| |[ignoreSilentSwitch](#ignoresilentswitch)|iOS| |[maxBitRate](#maxbitrate)|Android, iOS| |[minLoadRetryCount](#minLoadRetryCount)|Android| @@ -447,7 +417,7 @@ The start time in ms for SSAI content. This determines at what time to load the Note on Android, native controls are available by default. If needed, you can also add your controls or use a package like [react-native-video-controls]. -Platforms: Android, iOS, react-native-dom +Platforms: Android, iOS #### disableFocus Determines whether video audio should override background music/audio in Android devices. @@ -548,16 +518,6 @@ Controls whether the ExoPlayer shutter view (black screen while loading) is enab Platforms: Android -#### id -Set the DOM id element so you can use document.getElementById on web platforms. Accepts string values. - -Example: -``` -id="video" -``` - -Platforms: react-native-dom - #### ignoreSilentSwitch Controls the iOS silent switch behavior * **"inherit" (default)** - Use the default AVPlayer behavior diff --git a/dom/RCTVideo.js b/dom/RCTVideo.js deleted file mode 100644 index 77e9dc88..00000000 --- a/dom/RCTVideo.js +++ /dev/null @@ -1,280 +0,0 @@ -// @flow - -/* eslint-env browser */ - -import { RCTView, type RCTBridge } from 'react-native-dom'; -import shaka from 'shaka-player'; - -import resizeModes from './resizeModes'; -import type { VideoSource } from './types'; -import RCTVideoEvent from './RCTVideoEvent'; - -class RCTVideo extends RCTView { - playPromise: Promise = Promise.resolve(); - progressTimer: number; - videoElement: HTMLVideoElement; - - onEnd: boolean = false; - onLoad: boolean = false; - onLoadStart: boolean = false; - onProgress: boolean = false; - - _paused: boolean = false; - _progressUpdateInterval: number = 250.0; - _savedVolume: number = 1.0; - - constructor(bridge: RCTBridge) { - super(bridge); - - this.eventDispatcher = bridge.getModuleByName('EventDispatcher'); - - shaka.polyfill.installAll(); - - this.onEnd = this.onEnd.bind(this); - this.onLoad = this.onLoad.bind(this); - this.onLoadStart = this.onLoadStart.bind(this); - this.onPlay = this.onPlay.bind(this); - this.onProgress = this.onProgress.bind(this); - - this.videoElement = this.initializeVideoElement(); - this.videoElement.addEventListener('ended', this.onEnd); - this.videoElement.addEventListener('loadeddata', this.onLoad); - this.videoElement.addEventListener('canplay', this.onReadyForDisplay); - this.videoElement.addEventListener('loadstart', this.onLoadStart); - this.videoElement.addEventListener('pause', this.onPause); - this.videoElement.addEventListener('play', this.onPlay); - this.player = new shaka.Player(this.videoElement); - - this.muted = false; - this.rate = 1.0; - this.volume = 1.0; - this.childContainer.appendChild(this.videoElement); - } - - detachFromView(view: UIView) { - this.videoElement.removeEventListener('ended', this.onEnd); - this.videoElement.removeEventListener('loadeddata', this.onLoad); - this.videoElement.removeEventListener('canplay', this.onReadyForDisplay); - this.videoElement.removeEventListener('loadstart', this.onLoadStart); - this.videoElement.removeEventListener('pause', this.onPause); - this.videoElement.removeEventListener('play', this.onPlay); - - this.stopProgressTimer(); - } - - initializeVideoElement() { - const elem = document.createElement('video'); - - Object.assign(elem.style, { - display: 'block', - position: 'absolute', - top: '0', - left: '0', - width: '100%', - height: '100%', - }); - - return elem; - } - - presentFullscreenPlayer() { - this.videoElement.webkitRequestFullScreen(); - } - - set controls(value: boolean) { - this.videoElement.controls = value; - this.videoElement.style.pointerEvents = value ? 'auto' : ''; - } - - set id(value: string) { - this.videoElement.id = value; - } - - set muted(value: boolean) { - this.videoElement.muted = true; - } - - set paused(value: boolean) { - if (value) { - this.videoElement.pause(); - } else { - this.requestPlay(); - } - this._paused = value; - } - - set progressUpdateInterval(value: number) { - this._progressUpdateInterval = value; - this.stopProgressTimer(); - if (!this._paused) { - this.startProgressTimer(); - } - } - - set rate(value: number) { - this.videoElement.defaultPlaybackRate = value; // playbackRate doesn't work on Chrome - this.videoElement.playbackRate = value; - } - - set repeat(value: boolean) { - this.videoElement.loop = value; - } - - set resizeMode(value: number) { - switch (value) { - case resizeModes.ScaleNone: { - this.videoElement.style.objectFit = 'none'; - break; - } - case resizeModes.ScaleToFill: { - this.videoElement.style.objectFit = 'fill'; - break; - } - case resizeModes.ScaleAspectFit: { - this.videoElement.style.objectFit = 'contain'; - break; - } - case resizeModes.ScaleAspectFill: { - this.videoElement.style.objectFit = 'cover'; - break; - } - } - } - - set seek(value: number) { - this.videoElement.currentTime = value; - } - - set source(value: VideoSource) { - let uri = value.uri; - - if (uri.startsWith('blob:')) { - let blob = this.bridge.blobManager.resolveURL(uri); - if (blob.type === 'text/xml') { - blob = new Blob([blob], { type: 'video/mp4' }); - } - uri = URL.createObjectURL(blob); - } - - if (!shaka.Player.isBrowserSupported()) { // primarily iOS WebKit - this.videoElement.setAttribute('src', uri); - if (!this._paused) { - this.requestPlay(); - } - } else { - this.player.load(uri) - .then(() => { - if (!this._paused) { - this.requestPlay(); - } - }) - .catch(this.onError); - } - } - - set volume(value: number) { - if (value === 0) { - this.muted = true; - } else { - this.videoElement.volume = value; - this.muted = false; - } - } - - onEnd = () => { - this.onProgress(); - this.sendEvent('topVideoEnd', null); - this.stopProgressTimer(); - } - - onError = error => { - console.warn('topVideoError', error); - } - - onLoad = () => { - // height & width are safe with audio, will be 0 - const height = this.videoElement.videoHeight; - const width = this.videoElement.videoWidth; - const payload = { - currentPosition: this.videoElement.currentTime, - duration: this.videoElement.duration, - naturalSize: { - width, - height, - orientation: width >= height ? 'landscape' : 'portrait', - }, - }; - this.sendEvent('topVideoLoad', payload); - } - - onReadyForDisplay = () => { - this.sendEvent('onReadyForDisplay'); - } - - onLoadStart = () => { - const src = this.videoElement.currentSrc; - const payload = { - isNetwork: !src.match(/^https?:\/\/localhost/), // require is served from localhost - uri: this.videoElement.currentSrc, - }; - this.sendEvent('topVideoLoadStart', payload); - } - - onPause = () => { - this.stopProgressTimer(); - } - - onPlay = () => { - this.startProgressTimer(); - } - - onProgress = () => { - const payload = { - currentTime: this.videoElement.currentTime, - seekableDuration: this.videoElement.duration, - }; - this.sendEvent('topVideoProgress', payload); - } - - onRejectedAutoplay = () => { - this.sendEvent('topVideoRejectedAutoplay', null); - } - - requestPlay() { - const playPromise = this.videoElement.play(); - if (playPromise) { - playPromise - .then(() => {}) - .catch(e => { - /* This is likely one of: - * name: NotAllowedError - autoplay is not supported - * name: NotSupportedError - format is not supported - */ - this.onError({ code: e.name, message: e.message }); - }); - } - } - - sendEvent(eventName, payload) { - const event = new RCTVideoEvent(eventName, this.reactTag, 0, payload); - this.eventDispatcher.sendEvent(event); - } - - startProgressTimer() { - if (!this.progressTimer && this._progressUpdateInterval) { - this.onProgress(); - this.progressTimer = setInterval(this.onProgress, this._progressUpdateInterval); - } - } - - stopProgressTimer() { - if (this.progressTimer) { - clearInterval(this.progressTimer); - this.progressTimer = null; - } - } -} - -customElements.define('rct-video', RCTVideo); - -export default RCTVideo; diff --git a/dom/RCTVideoEvent.js b/dom/RCTVideoEvent.js deleted file mode 100644 index 4a772cf5..00000000 --- a/dom/RCTVideoEvent.js +++ /dev/null @@ -1,56 +0,0 @@ -// import { RCTEvent } from "react-native-dom"; - -interface RCTEvent { - viewTag: number; - eventName: string; - coalescingKey: number; - - canCoalesce(): boolean; - coalesceWithEvent(event: RCTEvent): RCTEvent; - - moduleDotMethod(): string; - arguments(): Array; - } - -export default class RCTVideoEvent implements RCTEvent { - viewTag: number; - eventName: string; - coalescingKey: number; - - constructor( - eventName: string, - reactTag: number, - coalescingKey: number, - data: ?Object - ) { - this.viewTag = reactTag; - this.eventName = eventName; - this.coalescingKey = coalescingKey; - this.data = data; - } - - canCoalesce(): boolean { - return false; - } - - coalesceWithEvent(event: RCTEvent): RCTEvent { - return; - } - - moduleDotMethod(): string { - return 'RCTEventEmitter.receiveEvent'; - } - - arguments(): Array { - const args = [ - this.viewTag, - this.eventName, - this.data, - ]; - return args; - } - - coalescingKey(): number { - return this.coalescingKey; - } -} diff --git a/dom/RCTVideoManager.js b/dom/RCTVideoManager.js deleted file mode 100644 index efeb4ae0..00000000 --- a/dom/RCTVideoManager.js +++ /dev/null @@ -1,87 +0,0 @@ -// @flow - -import { RCTViewManager } from 'react-native-dom'; - -import RCTVideo from './RCTVideo'; -import resizeModes from './resizeModes'; - -import type { VideoSource } from './types'; - -class RCTVideoManager extends RCTViewManager { - static moduleName = 'RCTVideoManager'; - - view() { - return new RCTVideo(this.bridge); - } - - describeProps() { - return super - .describeProps() - .addBooleanProp('controls', this.setControls) - .addStringProp('id', this.setId) - .addBooleanProp('muted', this.setMuted) - .addBooleanProp('paused', this.setPaused) - .addNumberProp('progressUpdateInterval', this.setProgressUpdateInterval) - .addBooleanProp('rate', this.setRate) - .addBooleanProp('repeat', this.setRepeat) - .addNumberProp('resizeMode', this.setResizeMode) - .addNumberProp('seek', this.setSeek) - .addObjectProp('src', this.setSource) - .addNumberProp('volume', this.setVolume) - .addDirectEvent('onVideoEnd') - .addDirectEvent('onVideoError') - .addDirectEvent('onVideoLoad') - .addDirectEvent('onVideoLoadStart') - .addDirectEvent('onVideoProgress'); - } - - dismissFullscreenPlayer() { - // not currently working - } - - presentFullscreenPlayer() { - // not currently working - } - - setControls(view: RCTVideo, value: boolean) { - view.controls = value; - } - - setId(view: RCTVideo, value: string) { - view.id = value; - } - - setMuted(view: RCTVideo, value: boolean) { - view.muted = value; - } - - setPaused(view: RCTVideo, value: boolean) { - view.paused = value; - } - - setRate(view: RCTVideo, value: number) { - view.rate = value; - } - - setRepeat(view: RCTVideo, value: boolean) { - view.repeat = value; - } - - setResizeMode(view: RCTVideo, value: number) { - view.resizeMode = value; - } - - setSeek(view: RCTVideo, value: number) { - view.seek = value; - } - - setSource(view: RCTVideo, value: VideoSource) { - view.source = value; - } - - constantsToExport() { - return { ...resizeModes }; - } -} - -export default RCTVideoManager; diff --git a/dom/index.js b/dom/index.js deleted file mode 100644 index e097d5fb..00000000 --- a/dom/index.js +++ /dev/null @@ -1,3 +0,0 @@ -// @flow - -module.exports = require('./RCTVideoManager'); diff --git a/dom/resizeModes.js b/dom/resizeModes.js deleted file mode 100644 index 5f569e0d..00000000 --- a/dom/resizeModes.js +++ /dev/null @@ -1,8 +0,0 @@ -// @flow - -export default { - ScaleNone: 0, - ScaleToFill: 1, - ScaleAspectFit: 2, - ScaleAspectFill: 3, -}; diff --git a/dom/types.js b/dom/types.js deleted file mode 100644 index fe1d1a15..00000000 --- a/dom/types.js +++ /dev/null @@ -1,10 +0,0 @@ -// @flow - -export type VideoSource = { - uri: string, - type: string, - mainVer: number, - patchVer: number, - isNetwork: boolean, - isAsset: boolean, -}; diff --git a/package.json b/package.json index d0170412..9168a673 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,8 @@ "@react-native-community/eslint-config": "^0.0.5", "eslint": "^6.5.1", "react": "16.9.0", - "react-dom": "16.9.0", "react-hot-loader": "^4.12.19", "react-native": "0.61.5", - "react-native-dom": "^0.5.0", "react-native-windows": "^0.61.0-0" }, "dependencies": { @@ -31,7 +29,6 @@ }, "files": [ "android", - "dom", "ios", "windows", "FilterType.js", From b8d68a844cbf76c417363b0290d51c338075a63e Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 22 Jun 2022 18:09:01 +0000 Subject: [PATCH 19/21] Remove unused dep --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 9168a673..f6879af9 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,7 @@ "dependencies": { "deprecated-react-native-prop-types": "^2.2.0", "keymirror": "^0.1.1", - "prop-types": "^15.7.2", - "shaka-player": "^3.3.2" + "prop-types": "^15.7.2" }, "scripts": { "lint": "yarn eslint .", From d4a735880a975bca30c8d683a596717db7576187 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Wed, 22 Jun 2022 20:40:48 +0000 Subject: [PATCH 20/21] Remove unused dep --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index f6879af9..1f2490c6 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "@react-native-community/eslint-config": "^0.0.5", "eslint": "^6.5.1", "react": "16.9.0", - "react-hot-loader": "^4.12.19", "react-native": "0.61.5", "react-native-windows": "^0.61.0-0" }, From 8234fade963ea71871a68d72b22ee34e96820e72 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Thu, 23 Jun 2022 12:44:57 -0700 Subject: [PATCH 21/21] Update API.md --- API.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/API.md b/API.md index ebcd6172..9ac52616 100644 --- a/API.md +++ b/API.md @@ -210,6 +210,8 @@ Add `PackageProviders().Append(winrt::ReactNativeVideoCPP::ReactPackageProvider( Follow the manual linking instuctions for React Native Windows 0.62 above, but substitute _ReactNativeVideoCPP61_ for _ReactNativeVideoCPP_. + + ## Examples Run `yarn xbasic install` before running any of the examples.