diff --git a/.yarn/patches/react-native-video-npm-6.19.1-2c06079fd0.patch b/.yarn/patches/react-native-video-npm-6.19.1-2c06079fd0.patch new file mode 100644 index 0000000..ebba5d8 --- /dev/null +++ b/.yarn/patches/react-native-video-npm-6.19.1-2c06079fd0.patch @@ -0,0 +1,64 @@ +diff --git a/lib/Video.js b/lib/Video.js +index 3ec75c5d3176f4c96cbcb9f99cb01ff7e6ea23ce..fcd7fc70e08ddf5a60b2b62db29240a1a756bcc4 100644 +--- a/lib/Video.js ++++ b/lib/Video.js +@@ -483,10 +483,12 @@ const Video = (0, react_1.forwardRef)(({ source, style, resizeMode, poster, post + _posterResizeMode = posterResizeMode; + } + // poster style +- const baseStyle = { +- ...react_native_1.StyleSheet.absoluteFillObject, +- resizeMode: _posterResizeMode, +- }; ++ const baseStyle = [ ++ react_native_1.StyleSheet.absoluteFill, ++ { ++ resizeMode: _posterResizeMode, ++ }, ++ ]; + let posterStyle = baseStyle; + if (!isPosterDeprecated && poster?.style) { + const styles = Array.isArray(poster.style) +@@ -517,9 +519,7 @@ const Video = (0, react_1.forwardRef)(({ source, style, resizeMode, poster, post + source, + resizeMode, + ]); +- const _style = (0, react_1.useMemo)(() => ({ +- ...react_native_1.StyleSheet.absoluteFillObject, +- }), []); ++ const _style = (0, react_1.useMemo)(() => react_native_1.StyleSheet.absoluteFill, []); + return (react_1.default.createElement(react_native_1.View, { style: style }, + react_1.default.createElement(VideoNativeComponent_1.default, { ref: nativeRef, ...rest, src: src, style: _style, resizeMode: resizeMode, restoreUserInterfaceForPIPStopCompletionHandler: _restoreUserInterfaceForPIPStopCompletionHandler, selectedTextTrack: _selectedTextTrack, selectedAudioTrack: _selectedAudioTrack, selectedVideoTrack: _selectedVideoTrack, shutterColor: _shutterColor, onGetLicense: usingExternalGetLicense ? onGetLicense : undefined, onVideoLoad: onLoad || hasPoster + ? onVideoLoad +diff --git a/src/Video.tsx b/src/Video.tsx +index 82b73abdc2b11be2a067dbab8ae1e014b995f77e..765dd33bbece0731d5eacebe515d33bff72bbce8 100644 +--- a/src/Video.tsx ++++ b/src/Video.tsx +@@ -813,10 +813,12 @@ const Video = forwardRef( + } + + // poster style +- const baseStyle: StyleProp = { +- ...StyleSheet.absoluteFillObject, +- resizeMode: _posterResizeMode, +- }; ++ const baseStyle: StyleProp = [ ++ StyleSheet.absoluteFill, ++ { ++ resizeMode: _posterResizeMode, ++ }, ++ ]; + + let posterStyle: StyleProp = baseStyle; + +@@ -866,9 +868,7 @@ const Video = forwardRef( + ]); + + const _style: StyleProp = useMemo( +- () => ({ +- ...StyleSheet.absoluteFillObject, +- }), ++ () => StyleSheet.absoluteFill, + [], + ); + diff --git a/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt b/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt index 7d76ced..2c7c1fd 100644 --- a/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt +++ b/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt @@ -29,12 +29,12 @@ object Utils { } @JvmStatic - fun compressVideo(srcPath: String, destinationPath: String, resultWidth: Int, resultHeight: Int, videoBitRate: Float, frameRate: Int, uuid: String,progressDivider:Int, promise: Promise, reactContext: ReactApplicationContext) { + fun compressVideo(srcPath: String, destinationPath: String, resultWidth: Int, resultHeight: Int, videoBitRate: Float, frameRate: Int, uuid: String,progressDivider:Int, stripAudio: Boolean = false, promise: Promise, reactContext: ReactApplicationContext) { val currentVideoCompression = intArrayOf(0) val videoCompressorClass: VideoCompressorClass? = VideoCompressorClass(reactContext); compressorExports[uuid] = videoCompressorClass videoCompressorClass?.start( - srcPath, destinationPath, resultWidth, resultHeight, videoBitRate.toInt(), frameRate, + srcPath, destinationPath, resultWidth, resultHeight, videoBitRate.toInt(), frameRate, stripAudio, listener = object : CompressionListener { override fun onProgress(index: Int, percent: Float) { if (percent <= 100) { diff --git a/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt b/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt index 222bedf..d8ff8a1 100644 --- a/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt +++ b/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt @@ -45,6 +45,7 @@ object AutoVideoCompression { profile.frameRate, options.uuid!!, options.progressDivider!!, + options.stripAudio, promise, reactContext, ) diff --git a/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/VideoCompressorClass.kt b/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/VideoCompressorClass.kt index 5b7c7f0..7a20b15 100644 --- a/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/VideoCompressorClass.kt +++ b/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/VideoCompressorClass.kt @@ -25,6 +25,7 @@ class VideoCompressorClass(private val context: ReactApplicationContext) { outputHeight: Int, bitrate: Int, frameRate: Int, + stripAudio: Boolean = false, listener: CompressionListener, ) { val uris = mutableListOf() @@ -38,6 +39,7 @@ class VideoCompressorClass(private val context: ReactApplicationContext) { outputHeight, bitrate, frameRate, + stripAudio, listener, destPath ) @@ -55,6 +57,7 @@ class VideoCompressorClass(private val context: ReactApplicationContext) { outputHeight: Int, bitrate: Int, frameRate: Int, + stripAudio: Boolean, listener: CompressionListener, destPath: String ) { @@ -78,6 +81,7 @@ class VideoCompressorClass(private val context: ReactApplicationContext) { outputHeight, bitrate, frameRate, + stripAudio, listener, ) @@ -101,6 +105,7 @@ class VideoCompressorClass(private val context: ReactApplicationContext) { outputHeight: Int, bitrate: Int, frameRate: Int, + disableAudio: Boolean = false, listener: CompressionListener, ): Result = withContext(Dispatchers.Default) { return@withContext compressVideo( @@ -113,6 +118,7 @@ class VideoCompressorClass(private val context: ReactApplicationContext) { outputHeight, bitrate, frameRate, + disableAudio, object : CompressionProgressListener { override fun onProgressChanged(index: Int, percent: Float) { listener.onProgress(index, percent) diff --git a/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/compressor/Compressor.kt b/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/compressor/Compressor.kt index 2d31006..6aa4116 100644 --- a/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/compressor/Compressor.kt +++ b/android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/compressor/Compressor.kt @@ -55,6 +55,7 @@ object Compressor { outputHeight: Int, outputBitrate: Int, outputFrameRate: Int, + disableAudio: Boolean = false, listener: CompressionProgressListener, ): Result = withContext(Dispatchers.Default) { @@ -126,7 +127,7 @@ object Compressor { newBitrate, outputFrameRate, streamableFile, - false, + disableAudio, extractor, listener, duration, diff --git a/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt b/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt index d3e3bad..cfa5622 100644 --- a/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt +++ b/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt @@ -27,6 +27,7 @@ class VideoCompressorHelper { var maxSize = 640.0f var progressDivider: Int? = 0 var minimumFileSizeForCompress = 0.0f + var stripAudio = false companion object { private var _reactContext: ReactApplicationContext? = null @@ -84,6 +85,7 @@ class VideoCompressorHelper { "minimumFileSizeForCompress" -> options.minimumFileSizeForCompress = map.getDouble(key).toFloat() "bitrate" -> options.bitrate = map.getDouble(key).toFloat() "progressDivider" -> options.progressDivider = map.getInt(key) + "stripAudio" -> options.stripAudio = map.getBoolean(key) } } return options @@ -130,6 +132,7 @@ class VideoCompressorHelper { profile.frameRate, options.uuid!!, options.progressDivider!!, + options.stripAudio, promise, reactContext, ) diff --git a/examples/bare/android/gradle/gradle-daemon-jvm.properties b/examples/bare/android/gradle/gradle-daemon-jvm.properties new file mode 100644 index 0000000..0519d5d --- /dev/null +++ b/examples/bare/android/gradle/gradle-daemon-jvm.properties @@ -0,0 +1,12 @@ +#This file is generated by updateDaemonJvm +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect +toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect +toolchainVersion=17 diff --git a/examples/bare/ios/Podfile.lock b/examples/bare/ios/Podfile.lock index 0659207..04aec5b 100644 --- a/examples/bare/ios/Podfile.lock +++ b/examples/bare/ios/Podfile.lock @@ -1384,7 +1384,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - react-native-compressor (1.16.0): + - react-native-compressor (1.16.2): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1541,6 +1541,74 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga + - react-native-video (6.19.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - react-native-video/Video (= 6.19.1) + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - react-native-video/Fabric (6.19.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - react-native-video/Video (6.19.1): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - react-native-video/Fabric + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga - React-NativeModulesApple (0.85.2): - hermes-engine - React-callinvoker @@ -2255,6 +2323,7 @@ DEPENDENCIES: - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) - react-native-image-picker (from `../node_modules/react-native-image-picker`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) + - react-native-video (from `../node_modules/react-native-video`) - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-networking (from `../node_modules/react-native/ReactCommon/react/networking`) - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`) @@ -2387,6 +2456,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-image-picker" react-native-safe-area-context: :path: "../node_modules/react-native-safe-area-context" + react-native-video: + :path: "../node_modules/react-native-video" React-NativeModulesApple: :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" React-networking: @@ -2510,11 +2581,12 @@ SPEC CHECKSUMS: React-Mapbuffer: 1fc10d873f00aa895836c316a9737ce7d43875ce React-microtasksnativemodule: 85ac7286ff84e8fc8e1956233748b8d4b2a6dcea react-native-cameraroll: 4d4fcff8a057235ce7a9f57d4566409207216a86 - react-native-compressor: 893ee6d39e9df8de6c2b332f300f2cfc4e57caac + react-native-compressor: e98e8f94c6fd8598b38f29a152c4cc3bb07cb41c react-native-document-picker: 15cca2d1a6bfb6d0d3ff0283bd9b903e57cb028b react-native-get-random-values: 68792987aef40e8aa72dc448d97e009d1f440c88 react-native-image-picker: 23540feacc79c63c60857f318fdfa8477c26e70a react-native-safe-area-context: 6b4966397ada0f7dd481e4486a2ef936834861a1 + react-native-video: 82fc4acb1b62f7fd8b3c0e6b88b691510bd92ab3 React-NativeModulesApple: 993744f42aab769eb02bf5d256b6767c546d0bb5 React-networking: 251bfddc651caca5e3039d1afa1d2eca890d0c56 React-oscompat: ed8fa636665935e962d4091180ba6f07dcad7ea9 @@ -2559,4 +2631,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 8b6aa5135b91f56aaf82cda5788ba89799309b83 -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/examples/bare/package.json b/examples/bare/package.json index 64611e5..ad78541 100644 --- a/examples/bare/package.json +++ b/examples/bare/package.json @@ -27,6 +27,7 @@ "react-native-safe-area-context": "^5.7.0", "react-native-screens": "^4.24.0", "react-native-svg": "^15.15.4", + "react-native-video": "patch:react-native-video@npm%3A6.19.1#~/.yarn/patches/react-native-video-npm-6.19.1-2c06079fd0.patch", "react-native-worklets": "^0.8.1" }, "devDependencies": { diff --git a/examples/bare/src/Screens/StripAudio/index.tsx b/examples/bare/src/Screens/StripAudio/index.tsx new file mode 100644 index 0000000..3e0466f --- /dev/null +++ b/examples/bare/src/Screens/StripAudio/index.tsx @@ -0,0 +1,258 @@ +import { useState, useRef, useCallback } from 'react'; +import { + View, + Text, + Button, + Alert, + Platform, + ScrollView, + StyleSheet, +} from 'react-native'; +import { Video, getRealPath } from 'react-native-compressor'; +import VideoPlayer from 'react-native-video'; +import * as ImagePicker from 'react-native-image-picker'; +import prettyBytes from 'pretty-bytes'; +import { getFileInfo } from '../../Utils'; +import ProgressBar from '../../Components/ProgressBar'; +import type { ProgressBarRafType } from '../../Components/ProgressBar'; + +export default function StripAudioScreen() { + const progressRef = useRef(null); + const cancellationIdRef = useRef(''); + + const [sourceVideo, setSourceVideo] = useState(); + const [sourceSize, setSourceSize] = useState(); + const [compressedVideo, setCompressedVideo] = useState(); + const [compressedSize, setCompressedSize] = useState(); + const [isCompressing, setIsCompressing] = useState(false); + const [playerKey, setPlayerKey] = useState(0); + + const selectVideo = async () => { + try { + ImagePicker.launchImageLibrary( + { mediaType: 'video' }, + async (result: ImagePicker.ImagePickerResponse) => { + if (result.didCancel) return; + if (result.errorCode) { + Alert.alert('Failed selecting video'); + return; + } + if (result.assets) { + let uri = result.assets[0]?.uri; + if (!uri) return; + if (Platform.OS === 'android' && uri.includes('content://')) { + const realPath = await getRealPath(uri, 'video'); + uri = 'file://' + realPath; + console.log('realPath ==>', realPath); + } + setSourceVideo(uri); + setCompressedVideo(undefined); + setCompressedSize(undefined); + setPlayerKey((k) => k + 1); + const detail: any = await getFileInfo(uri); + setSourceSize(prettyBytes(parseInt(detail.size, 10))); + } + }, + ); + } catch (error) { + console.log('Failed to select video', error); + } + }; + + const compressWithStripAudio = async () => { + if (!sourceVideo) return; + setIsCompressing(true); + try { + const dstUrl = await Video.compress( + sourceVideo, + { + compressionMethod: 'auto', + progressDivider: 10, + stripAudio: true, + getCancellationId: (id) => (cancellationIdRef.current = id), + }, + (progress) => { + console.log('Compression Progress: ', progress); + progressRef.current?.setProgress(progress); + }, + ); + console.log('Compressed (stripAudio):', dstUrl); + setCompressedVideo(dstUrl); + setPlayerKey((k) => k + 1); + const detail: any = await getFileInfo(dstUrl); + setCompressedSize(prettyBytes(parseInt(detail.size, 10))); + progressRef.current?.setProgress(0); + } catch (error) { + console.log('Compression error:', error); + Alert.alert('Compression Failed', String(error)); + progressRef.current?.setProgress(0); + } finally { + setIsCompressing(false); + } + }; + + const compressWithAudio = async () => { + if (!sourceVideo) return; + setIsCompressing(true); + try { + const dstUrl = await Video.compress( + sourceVideo, + { + compressionMethod: 'auto', + progressDivider: 10, + getCancellationId: (id) => (cancellationIdRef.current = id), + }, + (progress) => { + console.log('Compression Progress: ', progress); + progressRef.current?.setProgress(progress); + }, + ); + console.log('Compressed (with audio):', dstUrl); + setCompressedVideo(dstUrl); + setPlayerKey((k) => k + 1); + const detail: any = await getFileInfo(dstUrl); + setCompressedSize(prettyBytes(parseInt(detail.size, 10))); + progressRef.current?.setProgress(0); + } catch (error) { + console.log('Compression error:', error); + Alert.alert('Compression Failed', String(error)); + progressRef.current?.setProgress(0); + } finally { + setIsCompressing(false); + } + }; + + const cancelCompression = () => { + Video.cancelCompression(cancellationIdRef.current); + }; + + const onVideoError = useCallback((error: any) => { + console.log('Video playback error:', JSON.stringify(error)); + }, []); + + const onVideoLoad = useCallback((data: any) => { + console.log('Video loaded:', JSON.stringify(data)); + }, []); + + return ( + + + + +