I am merging videos using FFmpegKIT. I don't think there is anything wrong with the library but when I try to display the merged video in the video component it won't work. But when I reload the app and go to the process of merging videos again, the video component displays the merged video but only because I didn't change the name of the file (which already existed from the previous merging when it failed). I am using the FileSystem lib from expo to "store" the merged video then display it.The path of this new file is then updated into a hook which I pass for the source of the video component. My guess is the video compoenent doesnt have access to the file until I reload (not CTRL + S) the entire app but I don't know how to fix this. I am planning on creating a different file for each merge but I can't go further until I fix this. I am running on a android emulator using npx expo run:android
update : I logged the video component from expo-av and I have the error : Loading finished before preparation is complete. I don't know what it means.
here is the code I am using right now :
import { FFmpegKit} from 'ffmpeg-kit-react-native';
import { launchImageLibraryAsync } from 'expo-image-picker';
import { useState, useEffect } from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
import { Video as ExpoVideo } from 'expo-av';
import * as FileSystem from 'expo-file-system';
import * as ImagePicker from 'expo-image-picker';
import * as MediaLibrary from 'expo-media-library';
const VideoEditor = () => {
const [selectedVideos, setSelectedVideos] = useState([]);
const [mergedVideo, setMergedVideo] = useState(null);
const pickVideos = async () => {
try {
console.log('Picking videos...');
const result = await launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Videos,
allowsMultipleSelection: false,
});
console.log('Result:', result);
if (!result.canceled) {
const selectedVideo = result.assets[0] || result.selectedItems[0];
if (selectedVideo) {
const videoUri = selectedVideo.uri;
console.log('Selected video URI:', videoUri);
setSelectedVideos(prevVideos => [...prevVideos, videoUri]);
} else {
console.log('No video selected.');
}
} else {
console.log('Video picking cancelled.');
}
} catch (error) {
console.error('Error picking video:', error);
}
};
useEffect(() => {
console.log('UseEffectlog:', mergedVideo);
}, [mergedVideo]);
const mergeVideos = async () => {
if (selectedVideos.length === 0) {
console.error('No videos selected for merging.');
return;
}
//const timestamp = new Date().getTime();
const outputVideo = `${FileSystem.cacheDirectory}mergedVideo2.mp4`;
const inputFiles = selectedVideos.map(uri => `-i ${uri}`).join(' ');
const filterComplex = `concat=n=${selectedVideos.length}:v=1:a=1[outv][outa]`;
const ffmpegCommand = `${inputFiles} -filter_complex ${filterComplex} -map [outv] -map [outa] ${outputVideo}`;
try {
const result = await FFmpegKit.executeAsync(ffmpegCommand);
console.log('Merged video URI:', outputVideo);
setMergedVideo(outputVideo);
} catch (error) {
console.error('Error merging videos:', error);
}
};
return (
<View>
<TouchableOpacity onPress={pickVideos}>
<Text style={{ fontSize: 20, color: 'blue', textAlign: 'center', margin: 10 }}>
Pick Videos
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={mergeVideos}>
<Text style={{ fontSize: 20, color: 'blue', textAlign: 'center', margin: 10 }}>
Merge Videos
</Text>
</TouchableOpacity>
{ mergedVideo && (
<View>
<Text style={{ fontSize: 40, color: 'blue', textAlign: 'center', margin: 10 }}>
Merged Video:
</Text>
<ExpoVideo
source={{uri: `${mergedVideo}` }}
style={{ width: 300, height: 300 }}
isMuted={true}
resizeMode="cover"
shouldPlay={true}
useNativeControls
/>
</View>
)}
</View>
);
};
export default VideoEditor;
I also know for sure the state of the mergedVideo hook is not null thanks to the useEffect.
Below is a run of the logs of the whole process :
LOG Picking videos...
LOG Selected video URI: file:///data/user/0/com.anakinn.ffpmegEditor/cache/ImagePicker/fa07339a-5bbd-4b8d-8969-811b287c6c97.mp4
LOG Picking videos...
LOG Selected video URI: file:///data/user/0/com.anakinn.ffpmegEditor/cache/ImagePicker/618753e6-71f3-4294-8a0e-dad7ed6e148f.mp4
LOG Loading ffmpeg-kit-react-native.
LOG Loaded ffmpeg-kit-react-native-android-video-x86_64-6.0.2.
LOG Merged video URI: file:///data/user/0/com.anakinn.ffpmegEditor/cache/mergedVideo2.mp4
LOG UseEffectlog: file:///data/user/0/com.anakinn.ffpmegEditor/cache/mergedVideo2.mp4
LOG ffmpeg version n6.0
LOG Copyright (c) 2000-2023 the FFmpeg developers
LOG
LOG Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'file:///data/user/0/com.anakinn.ffpmegEditor/cache/ImagePicker/fa07339a-5bbd-4b8d-8969-811b287c6c97.mp4':
LOG Input #1, mov,mp4,m4a,3gp,3g2,mj2, from 'file:///data/user/0/com.anakinn.ffpmegEditor/cache/ImagePicker/618753e6-71f3-4294-8a0e-dad7ed6e148f.mp4':
LOG Output #0, mp4, to 'file:///data/user/0/com.anakinn.ffpmegEditor/cache/mergedVideo2.mp4':
LOG UseEffectlog: file:///data/user/0/com.anakinn.ffpmegEditor/cache/mergedVideo2.mp4
can you share the output of when you console log result
const result = await FFmpegKit.executeAsync(ffmpegCommand);