
Recherche avancée
Médias (91)
-
Valkaama DVD Cover Outside
4 octobre 2011, par
Mis à jour : Octobre 2011
Langue : English
Type : Image
-
Valkaama DVD Label
4 octobre 2011, par
Mis à jour : Février 2013
Langue : English
Type : Image
-
Valkaama DVD Cover Inside
4 octobre 2011, par
Mis à jour : Octobre 2011
Langue : English
Type : Image
-
1,000,000
27 septembre 2011, par
Mis à jour : Septembre 2011
Langue : English
Type : Audio
-
Demon Seed
26 septembre 2011, par
Mis à jour : Septembre 2011
Langue : English
Type : Audio
-
The Four of Us are Dying
26 septembre 2011, par
Mis à jour : Septembre 2011
Langue : English
Type : Audio
Autres articles (63)
-
Websites made with MediaSPIP
2 mai 2011, parThis page lists some websites based on MediaSPIP.
-
Creating farms of unique websites
13 avril 2011, parMediaSPIP platforms can be installed as a farm, with a single "core" hosted on a dedicated server and used by multiple websites.
This allows (among other things) : implementation costs to be shared between several different projects / individuals rapid deployment of multiple unique sites creation of groups of like-minded sites, making it possible to browse media in a more controlled and selective environment than the major "open" (...) -
Les autorisations surchargées par les plugins
27 avril 2010, parMediaspip core
autoriser_auteur_modifier() afin que les visiteurs soient capables de modifier leurs informations sur la page d’auteurs
Sur d’autres sites (10540)
-
dcaenc : Implementation of Huffman codes for DCA encoder
7 janvier 2017, par Daniil Cherednikdcaenc : Implementation of Huffman codes for DCA encoder
Reviewed-by : Rostislav Pehlivanov <atomnuker@gmail.com>
-
Revision 28930 : on bouge
31 mai 2009, par ben.spip@… — Logon bouge
-
FFmpeg WASM writeFile Stalls and Doesn't Complete in React App with Ant Design
26 février, par raiyan khanI'm using FFmpeg WebAssembly (WASM) in a React app to process and convert a video file before uploading it. The goal is to resize the video to 720p using FFmpeg before sending it to the backend.


Problem :


Everything works up to fetching the file and confirming it's loaded into memory, but FFmpeg hangs at ffmpeg.writeFile() and does not proceed further. No errors are thrown.


Code Snippet :


- 

-
Loading FFmpeg


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()
 }, [])



-
Fetching and Writing File


const convertVideoTo720p = async (videoFile) => {
 console.log("Starting video 
 conversion...");



 const { height } = await getVideoMetadata(videoFile);
 console.log(`Video height: ${height}`);

 if (height <= 720) {
 console.log("No conversion needed.");
 return videoFile;
 }

 const ffmpeg = ffmpegRef.current;
 console.log("FFmpeg instance loaded. Writing file to memory...");

 const fetchedFile = await fetchFile(videoFile);
 console.log("File fetched successfully:", fetchedFile);

 console.log("Checking FFmpeg memory before writing...");
 console.log(`File size: ${fetchedFile.length} bytes (~${(fetchedFile.length / 1024 / 1024).toFixed(2)} MB)`);

 if (!ffmpeg.isLoaded()) {
 console.error("FFmpeg is not fully loaded yet!");
 return;
 }

 console.log("Memory seems okay. Writing file to FFmpeg...");
 await ffmpeg.writeFile('input.mp4', fetchedFile); // ❌ This line hangs, nothing after runs
 console.log("File successfully written to FFmpeg memory.");
 };









Debugging Steps I've Tried :


- 

- Ensured FFmpeg is fully loaded before calling
writeFile()

✅ffmpeg.isLoaded()
returnstrue
. - Checked file fetch process :
✅
fetchFile(videoFile)
successfully returns aUint8Array
. - Tried renaming the file to prevent caching issues
✅ Used a unique file name like
video_${Date.now()}.mp4
, but no change - Checked browser console for errors :
❌ No errors are displayed.
- Tried skipping FFmpeg and uploading the raw file instead :
✅ Upload works fine without FFmpeg, so the issue is specific to FFmpeg.












Expected Behavior


- 

ffmpeg.writeFile('input.mp4', fetchedFile);
should complete and allow FFmpeg to process the video.




Actual Behavior


- 

- Execution stops at
writeFile
, and no errors are thrown.




Environment :


- 

- React : 18.x
- FFmpeg WASM Version : @ffmpeg/ffmpeg@0.12.15
- Browser : Chrome 121, Edge 120
- Operating System : Windows 11










Question :
Why is FFmpeg's
writeFile()
stalling and never completing ?
How can I fix or further debug this issue ?

Here is my full code :




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 <= 720) {
 // // No conversion needed
 // return videoFile;
 // }
 // const ffmpeg = ffmpegRef.current;
 // // Load ffmpeg if not already loaded
 // // await ffmpeg.load({
 // // coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
 // // wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
 // // });
 // // Write the input file to the ffmpeg virtual FS
 // await ffmpeg.writeFile('input.mp4', await fetchFile(videoFile));
 // // Convert video to 720p (scale filter maintains aspect ratio)
 // await ffmpeg.exec(['-i', 'input.mp4', '-vf', 'scale=-1:720', 'output.mp4']);
 // // Read the output file
 // const data = await ffmpeg.readFile('output.mp4');
 // console.log(data, 'data from convertVideoTo720p');
 // const videoBlob = new Blob([data.buffer], { type: 'video/mp4' });
 // return new File([videoBlob], 'output.mp4', { type: 'video/mp4' });
 // };
 const convertVideoTo720p = async (videoFile) => {
 console.log("Starting video conversion...");

 // Check the video resolution first
 const { height } = await getVideoMetadata(videoFile);
 console.log(`Video height: ${height}`);

 if (height <= 720) {
 console.log("No conversion needed. Returning original file.");
 return videoFile;
 }

 const ffmpeg = ffmpegRef.current;
 console.log("FFmpeg instance loaded. Writing file to memory...");

 // await ffmpeg.writeFile('input.mp4', await fetchFile(videoFile));
 // console.log("File written. Starting conversion...");
 console.log("Fetching file for FFmpeg:", videoFile);
 const fetchedFile = await fetchFile(videoFile);
 console.log("File fetched successfully:", fetchedFile);
 console.log("Checking FFmpeg memory before writing...");
 console.log(`File size: ${fetchedFile.length} bytes (~${(fetchedFile.length / 1024 / 1024).toFixed(2)} MB)`);

 if (fetchedFile.length > 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 (
 <>
 <div classname="flex items-center gap-2 text-xl cursor-pointer">
 <faangleleft></faangleleft>
 <h1 classname="font-semibold">Add Video</h1>
 </div>
 <div classname="rounded-lg py-4 border-[#79CDFF] border-2 shadow-lg mt-8 bg-white">
 <div classname="space-y-[24px] min-h-[83vh] bg-light-gray rounded-2xl">
 <h3 classname="text-2xl text-[#174C6B] mb-4 border-b border-[#79CDFF]/50 pb-3 pl-16 font-semibold">
 Adding Video
 </h3>
 <div classname="w-full px-16">
 / style={{ maxWidth: 600, margin: '0 auto' }}
 >
 {/* Section 1 */}
 {/* <space direction="vertical" style="{{"> */}
 {/* <space size="large" direction="horizontal" classname="responsive-space"> */}
 <div classname="grid grid-cols-2 gap-8 mt-8">
 <div>
 <space size="large" direction="horizontal" classname="responsive-space-section-2">

 {/* Video */}
 Upload Video}
 name="media"
 className="responsive-form-item"
 // rules={[{ required: true, message: 'Please enter the package amount!' }]}
 >
 <upload maxcount="{1}">
 <button style="{{" solid="solid">
 <span style="{{" 600="600">Select a video</span>
 <iovideocamoutline size="{20}" color="#174C6B"></iovideocamoutline>
 </button>
 </upload>
 

 {/* Thumbnail */}
 Upload Image}
 name="image"
 className="responsive-form-item"
 // rules={[{ required: true, message: 'Please enter the package amount!' }]}
 >
 <upload maxcount="{1}">
 <button style="{{" solid="solid">
 <span style="{{" 600="600">Select an image</span>
 <cicamera size="{25}" color="#174C6B"></cicamera>
 </button>
 </upload>
 

 {/* Title */}
 Video Title}
 name="name"
 className="responsive-form-item-section-2"
 >
 <input type="text" placeholder="Enter video title" style="{{&#xA;" solid="solid" />
 
 </space>
 </div>
 </div>

 {/* </space> */}
 {/* </space> */}


 {/* Submit Button */}
 
 <div classname="p-4 mt-10 text-center mx-auto flex items-center justify-center">
 
 <span classname="text-white font-semibold">{isLoading ? 'Uploading...' : 'Upload'}</span>
 
 </div>
 
 
 </div>
 </div>
 </div>
 >
 )
}

export default AddWorkoutVideo







Would appreciate any insights or suggestions. Thanks !


-