
Recherche avancée
Autres articles (39)
-
Contribute to a better visual interface
13 avril 2011MediaSPIP is based on a system of themes and templates. Templates define the placement of information on the page, and can be adapted to a wide range of uses. Themes define the overall graphic appearance of the site.
Anyone can submit a new graphic theme or template and make it available to the MediaSPIP community. -
HTML5 audio and video support
13 avril 2011, parMediaSPIP uses HTML5 video and audio tags to play multimedia files, taking advantage of the latest W3C innovations supported by modern browsers.
The MediaSPIP player used has been created specifically for MediaSPIP and can be easily adapted to fit in with a specific theme.
For older browsers the Flowplayer flash fallback is used.
MediaSPIP allows for media playback on major mobile platforms with the above (...) -
Contribute to translation
13 avril 2011You can help us to improve the language used in the software interface to make MediaSPIP more accessible and user-friendly. You can also translate the interface into any language that allows it to spread to new linguistic communities.
To do this, we use the translation interface of SPIP where the all the language modules of MediaSPIP are available. Just subscribe to the mailing list and request further informantion on translation.
MediaSPIP is currently available in French and English (...)
Sur d’autres sites (3857)
-
Audio to Video Conversion using FFmpeg in React
6 octobre 2024, par YuriUpon running my code, the audio successfully gets converted into a video and saved in the bucket, however, the video size is just 9 bytes.


Here's my utility.


import { FFmpeg } from '@ffmpeg/ffmpeg';
import { fetchFile } from '@ffmpeg/util';
import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
import { storage } from '../firebase'; 

export async function generateAndStoreVideo(audioPath, imagePath, userId) {
 try {
 const ffmpeg = new FFmpeg({ log: true });
 await ffmpeg.load();

 console.log('Fetching audio and image...');
 ffmpeg.writeFile( 'input.mp3', await fetchFile(audioPath));
 ffmpeg.writeFile('input.jpg', await fetchFile(imagePath));
 
 console.log('Running FFmpeg...');
 await ffmpeg.exec(['-i', 'sound.mp3', '-i', 'image.png', 'output.mp4']
 );

 console.log('FFmpeg completed!');
 
 const data = ffmpeg.readFile( 'output.mp4');
 const videoBlob = new Blob([data.buffer], { type: 'video/mp4' });

 console.log('Uploading video to Firebase...');
 const videoRef = ref(storage, `videos/${userId}/${Date.now()}_generated_video.mp4`);
 const uploadSnapshot = await uploadBytes(videoRef, videoBlob);

 const videoURL = await getDownloadURL(uploadSnapshot.ref);

 console.log('Video uploaded successfully! URL:', videoURL);

 return videoURL;
 } catch (error) {
 console.error('Error generating or uploading video:', error);
 throw new Error('Video generation or upload failed.');
 }
}




After uploading, I also got this error :


ErrnoError: FS error
 at handleError (http://localhost:3000/static/js/bundle.js:98427:58)
 at http://localhost:3000/static/js/bundle.js:98450:7



I've made sure I'm using the new FFMPEG version and syntax, but the issues persist.


-
FFMPEG Concatenating videos with same 25fps results in output file with 3.554fps
5 juin 2024, par Kendra BroomI created an AWS Lambda function in node.js 18 that is using a static, ver 7 build of FFmpeg located in a lambda layer. Unfortunately it's just the ffmpeg build and doesn't include ffprobe.


I have an mp4 audio file in one S3 bucket and a wav audio file in a second S3 bucket. I'm uploading the output file to a third S3 bucket.


Specs on the files (please let me know if any more info is needed)


Audio :
wav, 13kbps, aac (LC), 6:28 duration


Video :
mp4, 1280x720 resolution, 25 frame rate, h264 codec, 3:27 duration


Goal :
Create blank video to fill in the duration gaps so the full audio is covered before and after the mp4 video (using timestamps and duration). Strip the mp4 audio and use the wav audio only. Output should be an mp4 video with the wav audio playing over it and blank video for 27 seconds (based on timestamp) until mp4 video plays for 3:27, and then blank video to cover the rest of the audio until 6:28.


Actual Result :
An mp4 file with 3.554 frame rate and 10:06 duration.


import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { createWriteStream, createReadStream, promises as fsPromises } from 'fs';
import { exec } from 'child_process';
import { promisify } from 'util';
import { basename } from 'path';

const execAsync = promisify(exec);

const s3 = new S3Client({ region: 'us-east-1' });

async function downloadFileFromS3(bucket, key, downloadPath) {
 const getObjectParams = { Bucket: bucket, Key: key };
 const command = new GetObjectCommand(getObjectParams);
 const { Body } = await s3.send(command);
 return new Promise((resolve, reject) => {
 const fileStream = createWriteStream(downloadPath);
 Body.pipe(fileStream);
 Body.on('error', reject);
 fileStream.on('finish', resolve);
 });
}

async function uploadFileToS3(bucket, key, filePath) {
 const fileStream = createReadStream(filePath);
 const uploadParams = { Bucket: bucket, Key: key, Body: fileStream };
 try {
 await s3.send(new PutObjectCommand(uploadParams));
 console.log(`File uploaded successfully to ${bucket}/${key}`);
 } catch (err) {
 console.error("Error uploading file: ", err);
 throw new Error('Failed to upload file to S3');
 }
}

function parseDuration(durationStr) {
 const parts = durationStr.split(':');
 return parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseFloat(parts[2]);
}

export async function handler(event) {
 const videoBucket = "video-interaction-content";
 const videoKey = event.videoKey;
 const audioBucket = "audio-call-recordings";
 const audioKey = event.audioKey;
 const outputBucket = "synched-audio-video";
 const outputKey = `combined_${basename(videoKey, '.mp4')}.mp4`;

 const audioStartSeconds = new Date(event.audioStart).getTime() / 1000;
 const videoStartSeconds = new Date(event.videoStart).getTime() / 1000;
 const audioDurationSeconds = event.audioDuration / 1000;
 const timeDifference = audioStartSeconds - videoStartSeconds;

 try {
 const videoPath = `/tmp/${basename(videoKey)}`;
 const audioPath = `/tmp/${basename(audioKey)}`;
 await downloadFileFromS3(videoBucket, videoKey, videoPath);
 await downloadFileFromS3(audioBucket, audioKey, audioPath);

 //Initialize file list with video
 let filelist = [`file '${videoPath}'`];
 let totalVideoDuration = 0; // Initialize total video duration

 // Create first blank video if needed
 if (timeDifference < 0) {
 const blankVideoDuration = Math.abs(timeDifference);
 const blankVideoPath = `/tmp/blank_video.mp4`;
 await execAsync(`/opt/bin/ffmpeg -f lavfi -i color=c=black:s=1280x720:r=25 -c:v libx264 -t ${blankVideoDuration} ${blankVideoPath}`);
 //Add first blank video first in file list
 filelist.unshift(`file '${blankVideoPath}'`);
 totalVideoDuration += blankVideoDuration;
 console.log(`First blank video created with duration: ${blankVideoDuration} seconds`);
 }
 
 const videoInfo = await execAsync(`/opt/bin/ffmpeg -i ${videoPath} -f null -`);
 const videoDurationMatch = videoInfo.stderr.match(/Duration: ([\d:.]+)/);
 const videoDuration = videoDurationMatch ? parseDuration(videoDurationMatch[1]) : 0;
 totalVideoDuration += videoDuration;

 // Calculate additional blank video duration
 const additionalBlankVideoDuration = audioDurationSeconds - totalVideoDuration;
 if (additionalBlankVideoDuration > 0) {
 const additionalBlankVideoPath = `/tmp/additional_blank_video.mp4`;
 await execAsync(`/opt/bin/ffmpeg -f lavfi -i color=c=black:s=1280x720:r=25 -c:v libx264 -t ${additionalBlankVideoDuration} ${additionalBlankVideoPath}`);
 //Add to the end of the file list
 filelist.push(`file '${additionalBlankVideoPath}'`);
 console.log(`Additional blank video created with duration: ${additionalBlankVideoDuration} seconds`);
 }

 // Create and write the file list to disk
 const concatFilePath = '/tmp/filelist.txt';
 await fsPromises.writeFile('/tmp/filelist.txt', filelist.join('\n'));

 const extendedVideoPath = `/tmp/extended_${basename(videoKey)}`;
 //await execAsync(`/opt/bin/ffmpeg -f concat -safe 0 -i /tmp/filelist.txt -c copy ${extendedVideoPath}`);
 
 // Use -vsync vfr to adjust frame timing without full re-encoding
 await execAsync(`/opt/bin/ffmpeg -f concat -safe 0 -i ${concatFilePath} -c copy -vsync vfr ${extendedVideoPath}`);

 const outputPath = `/tmp/output_${basename(videoKey, '.mp4')}.mp4`;
 //await execAsync(`/opt/bin/ffmpeg -i ${extendedVideoPath} -i ${audioPath} -map 0:v:0 -map 1:a:0 -c:v copy -c:a aac -b:a 192k -shortest ${outputPath}`);

 await execAsync(`/opt/bin/ffmpeg -i ${extendedVideoPath} -i ${audioPath} -map 0:v:0 -map 1:a:0 -c:v copy -c:a aac -b:a 192k -shortest -r 25 ${outputPath}`);
 console.log('Video and audio have been merged successfully');

 await uploadFileToS3(outputBucket, outputKey, outputPath);
 console.log('File upload complete.');

 return { statusCode: 200, body: JSON.stringify('Video and audio have been merged successfully.') };
 } catch (error) {
 console.error('Error in Lambda function:', error);
 return { statusCode: 500, body: JSON.stringify('Failed to process video and audio.') };
 }
}



Attempts :
I've tried re-encoding the concatenated file but the lambda function times out. I hoped that by creating blank video with a 25fps and all the other specs from the original mp4, I wouldn't have to re-encode the concatenated file. Obviously something is wrong, though. In the commented out code you can see I tried specifying 25 or not, and also tried -vsync and no -vsync. I'm new to FFmpeg so all tips are appreciated !


-
React Native (Android) : Download mp3 file
21 février 2024, par Batuhan FındıkI get the youtube video link from the ui. I download the video from this link and convert it to mp3. I download it to my phone as mp3. The song opens on WhatsApp on the phone. but it doesn't open on the mp3 player. The song is not broken because it opens on WhatsApp too. Why do you think the mp3 player doesn't open ? Could it be from the file information ? I tried to enter some file information but it still won't open. For example, there is from information in songs played on an mp3 player. There is no from information in my song file. I tried to add it but it wasn't added.


.net 8 api return :


[HttpPost("ConvertVideoToMp3")]
public async Task<iactionresult> ConvertVideoToMp3(Mp3 data)
{
 try
 {
 string videoId = GetYoutubeVideoId(data.VideoUrl);

 var streamInfoSet = await _youtubeClient.Videos.Streams.GetManifestAsync(videoId);
 var videoStreamInfo = streamInfoSet.GetAudioOnlyStreams().GetWithHighestBitrate();

 if (videoStreamInfo != null)
 {
 var videoStream = await _youtubeClient.Videos.Streams.GetAsync(videoStreamInfo);
 var memoryStream = new MemoryStream();

 await videoStream.CopyToAsync(memoryStream);
 memoryStream.Seek(0, SeekOrigin.Begin);

 var videoFilePath = $"{videoId}.mp4";
 await System.IO.File.WriteAllBytesAsync(videoFilePath, memoryStream.ToArray());

 var mp3FilePath = $"{videoId}.mp3";
 var ffmpegProcess = Process.Start(new ProcessStartInfo
 {
 FileName = "ffmpeg",
 Arguments = $"-i \"{videoFilePath}\" -vn -acodec libmp3lame -ab 128k -id3v2_version 3 -metadata artist=\"YourArtistName\" -metadata title=\"YourTitle\" -metadata from=\"youtube\" \"{mp3FilePath}\"",
 RedirectStandardError = true,
 UseShellExecute = false,
 CreateNoWindow = true
 });

 await ffmpegProcess.WaitForExitAsync();

 var file = TagLib.File.Create(mp3FilePath);

 
 file.Tag.Artists = new string [] { "YourArtistName"};
 file.Tag.Title = "YourTitle";
 file.Tag.Album = "YourAlbumName"; 
 file.Tag.Comment = "Source: youtube";
 

 file.Save();

 var mp3Bytes = await System.IO.File.ReadAllBytesAsync(mp3FilePath);

 System.IO.File.Delete(videoFilePath);
 System.IO.File.Delete(mp3FilePath);

 return File(mp3Bytes, "audio/mpeg", $"{videoId}.mp3");
 }
 else
 {
 return NotFound("Video stream not found");
 }
 }
 catch (Exception ex)
 {
 return StatusCode(500, $"An error occurred: {ex.Message}");
 }
}
</iactionresult>


React Native :


const handleConvertAndDownload = async () => {
 try {
 const url = 'http://192.168.1.5:8080/api/Mp3/ConvertVideoToMp3';
 const fileName = 'example';
 const newFileName = generateUniqueSongName(fileName);
 const filePath = RNFS.DownloadDirectoryPath + '/'+newFileName;

 fetch(url, {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json',
 },
 body: JSON.stringify({videoUrl:videoUrl}),
 })
 .then((response) => {
 if (!response.ok) {
 Alert.alert('Error', 'Network');
 throw new Error('Network response was not ok');
 }
 return response.blob();
 })
 .then((blob) => {
 return new Promise((resolve, reject) => {
 const reader = new FileReader();
 reader.onloadend = () => {
 resolve(reader.result.split(',')[1]); 
 };
 reader.onerror = reject;
 reader.readAsDataURL(blob);
 });
 })
 .then((base64Data) => {
 // Dosyanın varlığını kontrol et
 return RNFS.exists(filePath)
 .then((exists) => {
 if (exists) {
 console.log('File already exists');
 return RNFS.writeFile(filePath, base64Data, 'base64', 'append');
 } else {
 console.log('File does not exist');
 return RNFS.writeFile(filePath, base64Data, 'base64');
 }
 })
 .catch((error) => {
 console.error('Error checking file existence:', error);
 throw error;
 });
 })
 .then(() => {
 Alert.alert('Success', 'MP3 file downloaded successfully.');
 console.log('File downloaded successfully!');
 })
 .catch((error) => {
 Alert.alert('Error', error.message);
 console.error('Error downloading file:', error);
 });
 } catch (error) {
 Alert.alert('Error', error.message);
 console.error(error);
 }
 };