Код: Выделить всё
const loadFFmpeg = async () => {
if (loaded) return; // Avoid reloading if
already loaded
const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd';
const ffmpeg = ffmpegRef.current;
ffmpeg.on('log', ({ message }) => {
messageRef.current.innerHTML = message;
console.log(message);
});
await ffmpeg.load({
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
});
setLoaded(true);
};
useEffect(() => {
loadFFmpeg()
}, [])
< /code>
< /li>
[*] Извлечение и написание файла < /p>
const convertVideoTo720p = async (videoFile) => {
console.log("Starting video
conversion...");
const { height } = await getVideoMetadata(videoFile);
console.log(`Video height: ${height}`);
if (height
[*] Обеспечить полностью загрузку ffmpeg перед вызовом writefile ()
✅ ffmpeg.isloaded () Возвращает true .
[*] Проверенный процесс избрания файлов:
✅ fetchfile (Videofile) успешно возвращает uint8array .
[*] Пробовал переименовать файл, чтобы предотвратить кэширование Проблемы
✅ Используют уникальное имя файла, например, видео _ $ {date.now ()}. mp4 , но без изменения
[*] Проверенная консоль браузера для ошибок:
❌ Ошибки не отображаются. Без ffmpeg, поэтому проблема специфична для ffmpeg. < /li>
< /ul>
[b] ожидается Поведение < /strong> < /p>
[list]
[code]ffmpeg.writeFile('input.mp4', fetchedFile);Остановка выполнения в writefile , и ошибки не допускаются.
[/list]
среда: < /strong> < /p>
- React: 18.x < /li>
ffmpeg wasm Версия: @ffmpeg/ffmpeg @0.12.15 - Браузер: Chrome 121, Edge 120
- Операционная система: Windows 11
Почему ffmpeg's writefile () задерживается и никогда не завершается?
Как я могу исправить или отладить эту проблему? />
import { useNavigate } from "react-router-dom";
import { useEffect, useRef, useState } from 'react';
import { Form, Input, Button, Select, Space } from 'antd';
const { Option } = Select;
import { FaAngleLeft } from "react-icons/fa6";
import { message, Upload } from 'antd';
import { CiCamera } from "react-icons/ci";
import { IoVideocamOutline } from "react-icons/io5";
import { useCreateWorkoutVideoMutation } from "../../../redux/features/workoutVideo/workoutVideoApi";
import { convertVideoTo720p } from "../../../utils/ffmpegHelper";
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { fetchFile, toBlobURL } from '@ffmpeg/util';
const AddWorkoutVideo = () => {
const [videoFile, setVideoFile] = useState(null);
const [imageFile, setImageFile] = useState(null);
const [loaded, setLoaded] = useState(false);
const ffmpegRef = useRef(new FFmpeg());
const videoRef = useRef(null);
const messageRef = useRef(null);
const [form] = Form.useForm();
const [createWorkoutVideo, { isLoading }] = useCreateWorkoutVideoMutation()
const navigate = useNavigate();
const videoFileRef = useRef(null); // Use a ref instead of state
// Handle Video Upload
const handleVideoChange = ({ file }) => {
setVideoFile(file.originFileObj);
};
// Handle Image Upload
const handleImageChange = ({ file }) => {
setImageFile(file.originFileObj);
};
// Load FFmpeg core if needed (optional if you want to preload)
const loadFFmpeg = async () => {
if (loaded) return; // Avoid reloading if already loaded
const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd';
const ffmpeg = ffmpegRef.current;
ffmpeg.on('log', ({ message }) => {
messageRef.current.innerHTML = message;
console.log(message);
});
await ffmpeg.load({
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
});
setLoaded(true);
};
useEffect(() => {
loadFFmpeg()
}, [])
// Helper: Get video metadata (width and height)
const getVideoMetadata = (file) => {
return new Promise((resolve, reject) => {
const video = document.createElement('video');
video.preload = 'metadata';
video.onloadedmetadata = () => {
resolve({ width: video.videoWidth, height: video.videoHeight });
};
video.onerror = () => reject(new Error('Could not load video metadata'));
video.src = URL.createObjectURL(file);
});
};
// Inline conversion helper function
// const convertVideoTo720p = async (videoFile) => {
// // Check the video resolution first
// const { height } = await getVideoMetadata(videoFile);
// if (height {
console.log("Starting video conversion...");
// Check the video resolution first
const { height } = await getVideoMetadata(videoFile);
console.log(`Video height: ${height}`);
if (height 50 * 1024 * 1024) { // 50MB limit
console.error("File is too large for FFmpeg WebAssembly!");
message.error("File too large. Try a smaller video.");
return;
}
console.log("Memory seems okay. Writing file to FFmpeg...");
const fileName = `video_${Date.now()}.mp4`; // Generate a unique name
console.log(`Using filename: ${fileName}`);
await ffmpeg.writeFile(fileName, fetchedFile);
console.log(`File successfully written to FFmpeg memory as ${fileName}.`);
await ffmpeg.exec(['-i', 'input.mp4', '-vf', 'scale=-1:720', 'output.mp4']);
console.log("Conversion completed. Reading output file...");
const data = await ffmpeg.readFile('output.mp4');
console.log("File read successful. Creating new File object.");
const videoBlob = new Blob([data.buffer], { type: 'video/mp4' });
const convertedFile = new File([videoBlob], 'output.mp4', { type: 'video/mp4' });
console.log(convertedFile, "converted video from convertVideoTo720p");
return convertedFile;
};
const onFinish = async (values) => {
// Ensure a video is selected
if (!videoFileRef.current) {
message.error("Please select a video file.");
return;
}
// Create FormData
const formData = new FormData();
if (imageFile) {
formData.append("image", imageFile);
}
try {
message.info("Processing video. Please wait...");
// Convert the video to 720p only if needed
const convertedVideo = await convertVideoTo720p(videoFileRef.current);
console.log(convertedVideo, 'convertedVideo from onFinish');
formData.append("media", videoFileRef.current);
formData.append("data", JSON.stringify(values));
// Upload manually to the backend
const response = await createWorkoutVideo(formData).unwrap();
console.log(response, 'response from add video');
message.success("Video added successfully!");
form.resetFields(); // Reset form
setVideoFile(null); // Clear file
} catch (error) {
message.error(error.data?.message || "Failed to add video.");
}
// if (videoFile) {
// message.info("Processing video. Please wait...");
// try {
// // Convert the video to 720p only if needed
// const convertedVideo = await convertVideoTo720p(videoFile);
// formData.append("media", convertedVideo);
// } catch (conversionError) {
// message.error("Video conversion failed.");
// return;
// }
// }
// formData.append("data", JSON.stringify(values)); // Convert text fields to JSON
// try {
// const response = await createWorkoutVideo(formData).unwrap();
// console.log(response, 'response from add video');
// message.success("Video added successfully!");
// form.resetFields(); // Reset form
// setFile(null); // Clear file
// } catch (error) {
// message.error(error.data?.message || "Failed to add video.");
// }
};
const handleBackButtonClick = () => {
navigate(-1); // This takes the user back to the previous page
};
const videoUploadProps = {
name: 'video',
// action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload',
// headers: {
// authorization: 'authorization-text',
// },
// beforeUpload: (file) => {
// const isVideo = file.type.startsWith('video/');
// if (!isVideo) {
// message.error('You can only upload video files!');
// }
// return isVideo;
// },
// onChange(info) {
// if (info.file.status === 'done') {
// message.success(`${info.file.name} video uploaded successfully`);
// } else if (info.file.status === 'error') {
// message.error(`${info.file.name} video upload failed.`);
// }
// },
beforeUpload: (file) => {
const isVideo = file.type.startsWith('video/');
if (!isVideo) {
message.error('You can only upload video files!');
return Upload.LIST_IGNORE; // Prevents the file from being added to the list
}
videoFileRef.current = file; // Store file in ref
// setVideoFile(file); // Store the file in state instead of uploading it automatically
return false; // Prevent auto-upload
},
};
const imageUploadProps = {
name: 'image',
action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload',
headers: {
authorization: 'authorization-text',
},
beforeUpload: (file) => {
const isImage = file.type.startsWith('image/');
if (!isImage) {
message.error('You can only upload image files!');
}
return isImage;
},
onChange(info) {
if (info.file.status === 'done') {
message.success(`${info.file.name} image uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} image upload failed.`);
}
},
};
return (
Add Video
Adding Video
{/* Section 1 */}
{/* */}
{/* */}
{/* Video */}
Select a video
{/* Thumbnail */}
Select an image
{/* Title */}
{/* */}
{/* */}
{/* Submit Button */}
{isLoading ? 'Uploading...' : 'Upload'}
)
}
export default AddWorkoutVideo< /code>
< /div>
< /div>
< /p>
оценил бы любые идеи или предложения. Спасибо!
Подробнее здесь: https://stackoverflow.com/questions/794 ... ant-design
Мобильная версия