diff --git a/lib/media/video-utils.js b/lib/media/video-utils.js
--- a/lib/media/video-utils.js
+++ b/lib/media/video-utils.js
@@ -97,14 +97,15 @@
   );
   const outputPath = `${outputDirectory}${outputFilename}`;
 
-  let quality, speed, scale;
-  if (outputCodec === 'h264') {
-    const { floor, min, max, log2 } = Math;
-    const crf = floor(min(5, max(0, log2(inputDuration / 5)))) + 23;
-    quality = `-crf ${crf}`;
-    speed = '-preset ultrafast';
+  let hardwareAcceleration, quality, speed, scale, pixelFormat;
+  if (outputCodec === 'h264_mediacodec') {
+    hardwareAcceleration = 'mediacodec';
+    quality = '';
+    speed = '';
     scale = `-vf scale=${maxWidth}:${maxHeight}:force_original_aspect_ratio=decrease`;
+    pixelFormat = '';
   } else if (outputCodec === 'h264_videotoolbox') {
+    hardwareAcceleration = 'videotoolbox';
     quality = '-profile:v baseline';
     speed = '-realtime 1';
     const { width, height } = inputDimensions;
@@ -115,19 +116,21 @@
     } else if (exceedsDimensions) {
       scale = `-vf scale=-1:${maxHeight}`;
     }
+    pixelFormat = '-pix_fmt yuv420p';
   } else {
     invariant(false, `unrecognized outputCodec ${outputCodec}`);
   }
 
   const ffmpegCommand =
+    `-hwaccel ${hardwareAcceleration} ` +
     `-i ${inputPath} ` +
     `-c:a copy -c:v ${outputCodec} ` +
     `${quality} ` +
-    '-vsync 2 -r 30 ' +
+    '-fps_mode cfr -r 30 ' +
     `${scale} ` +
     `${speed} ` +
     '-movflags +faststart ' +
-    '-pix_fmt yuv420p ' +
+    `${pixelFormat} ` +
     '-v quiet ' +
     outputPath;
 
diff --git a/native/android/build.gradle b/native/android/build.gradle
--- a/native/android/build.gradle
+++ b/native/android/build.gradle
@@ -31,7 +31,7 @@
 }
 
 ext {
-  reactNativeFFmpegPackage = "min-gpl-lts"
+  ffmpegKitPackage = "min-lts"
 }
 
 allprojects {
diff --git a/native/ios/Comm.xcodeproj/project.pbxproj b/native/ios/Comm.xcodeproj/project.pbxproj
--- a/native/ios/Comm.xcodeproj/project.pbxproj
+++ b/native/ios/Comm.xcodeproj/project.pbxproj
@@ -1171,11 +1171,27 @@
 			inputPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-frameworks.sh",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL",
+				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/ffmpegkit.framework/ffmpegkit",
+				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavcodec.framework/libavcodec",
+				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavdevice.framework/libavdevice",
+				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavfilter.framework/libavfilter",
+				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavformat.framework/libavformat",
+				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavutil.framework/libavutil",
+				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libswresample.framework/libswresample",
+				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libswscale.framework/libswscale",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ffmpegkit.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavcodec.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavdevice.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavfilter.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavformat.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavutil.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libswresample.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libswscale.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -1413,7 +1429,6 @@
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-react-native\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-camera\"",
-					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-ffmpeg\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-in-app-message\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-netinfo\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-notifications\"",
@@ -1555,7 +1570,6 @@
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-react-native\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-camera\"",
-					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-ffmpeg\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-in-app-message\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-netinfo\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-notifications\"",
diff --git a/native/ios/Podfile b/native/ios/Podfile
--- a/native/ios/Podfile
+++ b/native/ios/Podfile
@@ -10,7 +10,7 @@
 def common_comm_target_pods
   pod 'SQLCipher-Amalgamation', :path => '../../node_modules/@commapp/sqlcipher-amalgamation'
   pod 'react-native-video/VideoCaching', :podspec => '../node_modules/react-native-video'
-  pod 'react-native-ffmpeg/min-lts', :podspec => '../node_modules/react-native-ffmpeg'
+  pod 'ffmpeg-kit-react-native', :subspecs => ['min'], :podspec => '../node_modules/ffmpeg-kit-react-native'
 end
 
 post_integrate do |installer|
diff --git a/native/ios/Podfile.lock b/native/ios/Podfile.lock
--- a/native/ios/Podfile.lock
+++ b/native/ios/Podfile.lock
@@ -132,6 +132,10 @@
     - React-Core (= 0.70.9)
     - React-jsi (= 0.70.9)
     - ReactCommon/turbomodule/core (= 0.70.9)
+  - ffmpeg-kit-ios-min (6.0)
+  - ffmpeg-kit-react-native/min (6.0.2):
+    - ffmpeg-kit-ios-min (= 6.0)
+    - React-Core
   - fmt (6.2.1)
   - glog (0.3.5)
   - hermes-engine (0.70.9)
@@ -163,7 +167,6 @@
   - MMKVAppExtension (1.3.5):
     - MMKVCore (~> 1.3.5)
   - MMKVCore (1.3.5)
-  - mobile-ffmpeg-min (4.3.1.LTS)
   - OLMKit (3.2.14):
     - OLMKit/olmc (= 3.2.14)
     - OLMKit/olmcpp (= 3.2.14)
@@ -404,9 +407,6 @@
     - React
   - react-native-camera/RN (3.31.0):
     - React
-  - react-native-ffmpeg/min-lts (0.4.4):
-    - mobile-ffmpeg-min (= 4.3.1.LTS)
-    - React
   - react-native-in-app-message (1.0.2):
     - React
   - react-native-netinfo (9.3.7):
@@ -605,6 +605,7 @@
   - EXUpdatesInterface (from `../../node_modules/expo-updates-interface/ios`)
   - FBLazyVector (from `../../node_modules/react-native/Libraries/FBLazyVector`)
   - FBReactNativeSpec (from `../../node_modules/react-native/React/FBReactNativeSpec`)
+  - ffmpeg-kit-react-native/min (from `../node_modules/ffmpeg-kit-react-native`)
   - glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`)
   - hermes-engine (from `../../node_modules/react-native/sdks/hermes/hermes-engine.podspec`)
   - libevent (~> 2.1.12)
@@ -629,7 +630,6 @@
   - React-jsinspector (from `../../node_modules/react-native/ReactCommon/jsinspector`)
   - React-logger (from `../../node_modules/react-native/ReactCommon/logger`)
   - react-native-camera (from `../node_modules/react-native-camera`)
-  - react-native-ffmpeg/min-lts (from `../node_modules/react-native-ffmpeg`)
   - react-native-in-app-message (from `../node_modules/react-native-in-app-message`)
   - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
   - react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
@@ -668,6 +668,7 @@
 SPEC REPOS:
   trunk:
     - DVAssetLoaderDelegate
+    - ffmpeg-kit-ios-min
     - fmt
     - libaom
     - libavif
@@ -678,7 +679,6 @@
     - MMKV
     - MMKVAppExtension
     - MMKVCore
-    - mobile-ffmpeg-min
     - OpenSSL-Universal
     - SDWebImage
     - SDWebImageAVIFCoder
@@ -744,6 +744,8 @@
     :path: "../../node_modules/react-native/Libraries/FBLazyVector"
   FBReactNativeSpec:
     :path: "../../node_modules/react-native/React/FBReactNativeSpec"
+  ffmpeg-kit-react-native:
+    :podspec: "../node_modules/ffmpeg-kit-react-native"
   glog:
     :podspec: "../../node_modules/react-native/third-party-podspecs/glog.podspec"
   hermes-engine:
@@ -784,8 +786,6 @@
     :path: "../../node_modules/react-native/ReactCommon/logger"
   react-native-camera:
     :path: "../node_modules/react-native-camera"
-  react-native-ffmpeg:
-    :podspec: "../node_modules/react-native-ffmpeg"
   react-native-in-app-message:
     :path: "../node_modules/react-native-in-app-message"
   react-native-netinfo:
@@ -885,6 +885,8 @@
   EXUpdatesInterface: bffd1ead18f0bab04fa784ca159c115607b8a23c
   FBLazyVector: bc76253beb7463b688aa6af913b822ed631de31a
   FBReactNativeSpec: 2dfdfdc025c136effd657e62879c66122718030b
+  ffmpeg-kit-ios-min: 4e9a088f4ee9629435960b9d68e54848975f1931
+  ffmpeg-kit-react-native: 3cea88c9c5cfad62e1465279ea7d800dfbba3b00
   fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
   glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
   hermes-engine: 918ec5addfbc430c9f443376d739f088b6dc96c3
@@ -898,7 +900,6 @@
   MMKV: 506311d0494023c2f7e0b62cc1f31b7370fa3cfb
   MMKVAppExtension: 0cb4ebe918cb739fea57f9ed892c050d7c4d2cf6
   MMKVCore: 9e2e5fd529b64a9fe15f1a7afb3d73b2e27b4db9
-  mobile-ffmpeg-min: d5d22dcef5c8ec56f771258f1f5be245d914f193
   OLMKit: a13e1a20579e88d03971c5821360be24949a1a09
   OpenSSL-Universal: 84efb8a29841f2764ac5403e0c4119a28b713346
   RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
@@ -917,7 +918,6 @@
   React-jsinspector: d76d32327f21d4f40dcf696231fdbbca60de4711
   React-logger: 1b3522f1e05c6360e93df3607a016c39e30a7351
   react-native-camera: b5c8c7a71feecfdd5b39f0dbbf6b64b957ed55f2
-  react-native-ffmpeg: f9a60452aaa5d478aac205b248224994f3bde416
   react-native-in-app-message: f91de5009620af01456531118264c93e249b83ec
   react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
   react-native-orientation-locker: 851f6510d8046ea2f14aa169b1e01fcd309a94ba
@@ -959,6 +959,6 @@
   Yoga: dc109b79db907f0f589fc423e991b09ec42d2295
   ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
 
-PODFILE CHECKSUM: 3ad7489a9ca814690867cca40f302b9432cebe02
+PODFILE CHECKSUM: 08ac12954526f5d7b062d36d800e1b628afe9040
 
 COCOAPODS: 1.14.3
diff --git a/native/media/ffmpeg.js b/native/media/ffmpeg.js
--- a/native/media/ffmpeg.js
+++ b/native/media/ffmpeg.js
@@ -1,6 +1,10 @@
 // @flow
 
-import { RNFFmpeg, RNFFprobe, RNFFmpegConfig } from 'react-native-ffmpeg';
+import {
+  FFmpegKit,
+  FFprobeKit,
+  FFmpegKitConfig,
+} from 'ffmpeg-kit-react-native';
 
 import { getHasMultipleFramesProbeCommand } from 'lib/media/video-utils.js';
 import type {
@@ -85,19 +89,26 @@
   ): Promise<{ rc: number, lastStats: ?FFmpegStatistics }> {
     const duration = inputVideoDuration > 0 ? inputVideoDuration : 0.001;
     const wrappedCommand = async () => {
-      RNFFmpegConfig.resetStatistics();
       let lastStats;
       if (onTranscodingProgress) {
-        RNFFmpegConfig.enableStatisticsCallback(
-          (statisticsData: FFmpegStatistics) => {
-            lastStats = statisticsData;
-            const { time } = statisticsData;
-            onTranscodingProgress(time / 1000 / duration);
-          },
-        );
+        FFmpegKitConfig.enableStatisticsCallback(statisticsObject => {
+          const time = statisticsObject.getTime();
+          onTranscodingProgress(time / 1000 / duration);
+          lastStats = {
+            speed: statisticsObject.getSpeed(),
+            time,
+            size: statisticsObject.getSize(),
+            videoQuality: statisticsObject.getVideoQuality(),
+            videoFrameNumber: statisticsObject.getVideoFrameNumber(),
+            videoFps: statisticsObject.getVideoFps(),
+            bitrate: statisticsObject.getBitrate(),
+          };
+        });
       }
-      const ffmpegResult = await RNFFmpeg.execute(ffmpegCommand);
-      return { ...ffmpegResult, lastStats };
+      const session = await FFmpegKit.execute(ffmpegCommand);
+      const returnCode = await session.getReturnCode();
+      const rc = returnCode.getValue();
+      return { rc, lastStats };
     };
     return this.queueCommand('process', wrappedCommand);
   }
@@ -112,9 +123,10 @@
     videoPath: string,
     outputPath: string,
   ): Promise<number> {
-    const thumbnailCommand = `-i ${videoPath} -frames 1 -f singlejpeg ${outputPath}`;
-    const { rc } = await RNFFmpeg.execute(thumbnailCommand);
-    return rc;
+    const thumbnailCommand = `-i ${videoPath} -frames 1 -f mjpeg ${outputPath}`;
+    const session = await FFmpegKit.execute(thumbnailCommand);
+    const returnCode = await session.getReturnCode();
+    return returnCode.getValue();
   }
 
   getVideoInfo(path: string): Promise<VideoInfo> {
@@ -123,26 +135,28 @@
   }
 
   static async innerGetVideoInfo(path: string): Promise<VideoInfo> {
-    const info = await RNFFprobe.getMediaInformation(path);
+    const session = await FFprobeKit.getMediaInformation(path);
+    const info = await session.getMediaInformation();
     const videoStreamInfo = FFmpeg.getVideoStreamInfo(info);
     const codec = videoStreamInfo?.codec;
     const dimensions = videoStreamInfo && videoStreamInfo.dimensions;
-    const format = info.format.split(',');
-    const duration = info.duration / 1000;
+    const format = info.getFormat().split(',');
+    const duration = info.getDuration();
     return { codec, format, dimensions, duration };
   }
 
   static getVideoStreamInfo(
     info: Object,
   ): ?{ +codec: string, +dimensions: Dimensions } {
-    if (!info.streams) {
+    const streams = info.getStreams();
+    if (!streams) {
       return null;
     }
-    for (const stream of info.streams) {
-      if (stream.type === 'video') {
-        const codec: string = stream.codec;
-        const width: number = stream.width;
-        const height: number = stream.height;
+    for (const stream of streams) {
+      if (stream.getType() === 'video') {
+        const codec: string = stream.getCodec();
+        const width: number = stream.getWidth();
+        const height: number = stream.getHeight();
         return { codec, dimensions: { width, height } };
       }
     }
@@ -155,9 +169,11 @@
   }
 
   static async innerHasMultipleFrames(path: string): Promise<boolean> {
-    await RNFFprobe.execute(getHasMultipleFramesProbeCommand(path));
-    const probeOutput = await RNFFmpegConfig.getLastCommandOutput();
-    const numFrames = parseInt(probeOutput.lastCommandOutput);
+    const session = await FFprobeKit.execute(
+      getHasMultipleFramesProbeCommand(path),
+    );
+    const probeOutput = await session.getOutput();
+    const numFrames = parseInt(probeOutput);
     return numFrames > 1;
   }
 }
diff --git a/native/media/video-utils.js b/native/media/video-utils.js
--- a/native/media/video-utils.js
+++ b/native/media/video-utils.js
@@ -79,12 +79,9 @@
     inputDuration: duration,
     inputDimensions: input.dimensions,
     outputDirectory: temporaryDirectoryPath,
-    // We want ffmpeg to use hardware-accelerated encoders. On iOS we can do
-    // this using VideoToolbox, but ffmpeg on Android is still missing
-    // MediaCodec encoding support: https://trac.ffmpeg.org/ticket/6407
     outputCodec: Platform.select({
       ios: 'h264_videotoolbox',
-      //android: 'h264_mediacodec',
+      android: 'h264_mediacodec',
       default: 'h264',
     }),
     clientConnectionInfo: {
diff --git a/native/package.json b/native/package.json
--- a/native/package.json
+++ b/native/package.json
@@ -84,6 +84,7 @@
     "expo-media-library": "~15.0.0",
     "expo-secure-store": "~12.0.0",
     "expo-splash-screen": "~0.17.4",
+    "ffmpeg-kit-react-native": "^6.0.2",
     "find-root": "^1.1.0",
     "invariant": "^2.2.4",
     "lib": "0.0.1",
@@ -95,7 +96,6 @@
     "react-native": "0.70.9",
     "react-native-camera": "^3.31.0",
     "react-native-device-info": "^10.3.0",
-    "react-native-ffmpeg": "^0.4.4",
     "react-native-figma-squircle": "^0.1.2",
     "react-native-floating-action": "^1.22.0",
     "react-native-fs": "^2.20.0",
diff --git a/patches/react-native-ffmpeg+0.4.4.patch b/patches/react-native-ffmpeg+0.4.4.patch
deleted file mode 100644
--- a/patches/react-native-ffmpeg+0.4.4.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/node_modules/react-native-ffmpeg/android/build.gradle b/node_modules/react-native-ffmpeg/android/build.gradle
-index 32923e4..283b63c 100644
---- a/node_modules/react-native-ffmpeg/android/build.gradle
-+++ b/node_modules/react-native-ffmpeg/android/build.gradle
-@@ -14,6 +14,7 @@ apply plugin: 'com.android.library'
- 
- buildscript {
-     repositories {
-+        gradlePluginPortal()
-         jcenter()
-         maven { url 'https://maven.google.com' }
-     }
diff --git a/yarn.lock b/yarn.lock
--- a/yarn.lock
+++ b/yarn.lock
@@ -11836,6 +11836,11 @@
     biskviit "1.0.1"
     encoding "0.1.12"
 
+ffmpeg-kit-react-native@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/ffmpeg-kit-react-native/-/ffmpeg-kit-react-native-6.0.2.tgz#9eeac96ad89367c99480bd90431391405d4eb73e"
+  integrity sha512-r9uSmahq8TeyIb7fXf3ft+uUXyoeWRFa99+khjo0TAzWO9y0z9wU7eGnab9JLw1MmCB9v64o4yojNluJhVm9nQ==
+
 figma-squircle@^0.1.2:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/figma-squircle/-/figma-squircle-0.1.2.tgz#fa97de644131d99f2c42a2d8b70d56a36783c234"
@@ -20253,11 +20258,6 @@
   resolved "https://registry.yarnpkg.com/react-native-device-info/-/react-native-device-info-10.3.0.tgz#6bab64d84d3415dd00cc446c73ec5e2e61fddbe7"
   integrity sha512-/ziZN1sA1REbJTv5mQZ4tXggcTvSbct+u5kCaze8BmN//lbxcTvWsU6NQd4IihLt89VkbX+14IGc9sVApSxd/w==
 
-react-native-ffmpeg@^0.4.4:
-  version "0.4.4"
-  resolved "https://registry.yarnpkg.com/react-native-ffmpeg/-/react-native-ffmpeg-0.4.4.tgz#9f4dbda53c96078cecbbe83a866d4b535b957131"
-  integrity sha512-MUBV3Xvto1Hl049Y9EaOZdjazkK1ixQzCzPEt1o7V2duSOrM2kJ2o/RiC4rSRgapU2uqYRHMZ6X4JJI7y40qXw==
-
 react-native-figma-squircle@^0.1.2:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/react-native-figma-squircle/-/react-native-figma-squircle-0.1.2.tgz#64973afcfb42a53cc662ac2ccfba73ced7297124"