
Recherche avancée
Médias (91)
-
Head down (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Echoplex (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Discipline (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Letting you (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
1 000 000 (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
999 999 (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
Autres articles (107)
-
MediaSPIP 0.1 Beta version
25 avril 2011, parMediaSPIP 0.1 beta is the first version of MediaSPIP proclaimed as "usable".
The zip file provided here only contains the sources of MediaSPIP in its standalone version.
To get a working installation, you must manually install all-software dependencies on the server.
If you want to use this archive for an installation in "farm mode", you will also need to proceed to other manual (...) -
Problèmes fréquents
10 mars 2010, parPHP et safe_mode activé
Une des principales sources de problèmes relève de la configuration de PHP et notamment de l’activation du safe_mode
La solution consiterait à soit désactiver le safe_mode soit placer le script dans un répertoire accessible par apache pour le site -
Support de tous types de médias
10 avril 2011Contrairement à beaucoup de logiciels et autres plate-formes modernes de partage de documents, MediaSPIP a l’ambition de gérer un maximum de formats de documents différents qu’ils soient de type : images (png, gif, jpg, bmp et autres...) ; audio (MP3, Ogg, Wav et autres...) ; vidéo (Avi, MP4, Ogv, mpg, mov, wmv et autres...) ; contenu textuel, code ou autres (open office, microsoft office (tableur, présentation), web (html, css), LaTeX, Google Earth) (...)
Sur d’autres sites (7099)
-
Overthinking My Search Engine Problem
31 décembre 2013, par Multimedia Mike — GeneralI wrote a search engine for my Game Music Appreciation website, because the site would have been significantly less valuable without it (and I would eventually realize that the search feature is probably the most valuable part of this endeavor). I came up with a search solution that was a bit sketchy, but worked… until it didn’t. I thought of a fix but still searched for more robust and modern solutions (where ‘modern’ is defined as something that doesn’t require compiling a C program into a static CGI script and hoping that it works on a server I can’t debug on).
Finally, I realized that I was overthinking the problem– did you know that a bunch of relational database management systems (RDBMSs) support full text search (FTS) ? Okay, maybe you did, but I didn’t know this.
Problem Statement
My goal is to enable users to search the metadata (title, composer, copyright, other tags) attached to various games. To do this, I want to index a series of contrived documents that describe the metadata. 2 examples of these contrived documents, interesting because both of these games have very different titles depending on region, something the search engine needs to account for :system : Nintendo NES game : Snoopy’s Silly Sports Spectacular author : None ; copyright : 1988 Kemco ; dumped by : None additional tags : Donald Duck.nsf Donald Duck
system : Super Nintendo
game : Arcana
author : Jun Ishikawa, Hirokazu Ando ; copyright : 1992 HAL Laboratory ; dumped by : Datschge
additional tags : card.rsn.gamemusic Card Master CardmasterThe index needs to map these documents to various pieces of game music and the search solution needs to efficiently search these documents and find the various game music entries that match a user’s request.
Now that I’ve been looking at it for long enough, I’m able to express the problem surprisingly succinctly. If I had understood that much originally, this probably would have been simpler.
First Solution & Breakage
My original solution was based on SWISH-E. The CGI script was a C program that statically linked the SWISH-E library into a binary that miraculously ran on my web provider. At least, it ran until it decided to stop working a month ago when I added a new feature unrelated to search. It was a very bizarre problem, the details of which would probably bore you to tears. But if you care, the details are all there in the Stack Overflow question I asked on the matter.While no one could think of a direct answer to the problem, I eventually thought of a roundabout fix. The problem seemed to pertain to the static linking. Since I couldn’t count on the relevant SWISH-E library to be on my host’s system, I uploaded the shared library to the same directory as the CGI script and used dlopen()/dlsym() to fetch the functions I needed. It worked again, but I didn’t know for how long.
Searching For A Hosted Solution
I know that anything is possible in this day and age ; while my web host is fairly limited, there are lots of solutions for things like this and you can deploy any technology you want, and for reasonable prices. I figured that there must be a hosted solution out there.I have long wanted a compelling reason to really dive into Amazon Web Services (AWS) and this sounded like a good opportunity. After all, my script works well enough ; if I could just find a simple Linux box out there where I could install the SWISH-E library and compile the CGI script, I should be good to go. AWS has a free tier and I started investigating this approach. But it seems like a rabbit hole with a lot of moving pieces necessary for such a simple task.
I had heard that AWS had something in this area. Sure enough, it’s called CloudSearch. However, I’m somewhat discouraged by the fact that it would cost me around $75 per month to run the smallest type of search instance which is at the core of the service.
Finally, I came to another platform called Heroku. It’s supposed to be super-scalable while having a free tier for hobbyists. I started investigating FTS on Heroku and found this article which recommends using the FTS capabilities of their standard hosted PostgreSQL solution. However, the free tier of Postgres hosting only allows for 10,000 rows of data. Right now, my database has about 5400 rows. I expect it to easily overflow the 10,000 limit as soon as I incorporate the C64 SID music corpus.
However, this Postgres approach planted a seed.
RDBMS Revelation
I have 2 RDBMSs available on my hosting plan– MySQL and SQLite (the former is a separate service while SQLite is built into PHP). I quickly learned that both have FTS capabilities. Since I like using SQLite so much, I elected to leverage its FTS functionality. And it’s just this simple :CREATE VIRTUAL TABLE gamemusic_metadata_fts USING fts3 ( content TEXT, game_id INT, title TEXT ) ;
SELECT id, title FROM gamemusic_metadata_fts WHERE content MATCH "arcana" ;
479|ArcanaThe ‘content’ column gets the metadata pseudo-documents. The SQL gets wrapped up in a little PHP so that it queries this small database and turns the result into JSON. The script is then ready as a drop-in replacement for the previous script.
-
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 !


-
What permission ffmpeg-static need in AWS Lambda ?
17 février 2023, par JánosI have this code. It download a image, made a video from it and upload it to S3. It runs on Lambda. Added packages, intalled, zipped, uploaded.


npm install --production
zip -r my-lambda-function.zip ./



But get an
error code 126


2023-02-17T09:27:55.236Z 5c845bb6-02c1-41b0-8759-4459591b57b0 INFO Error: ffmpeg exited with code 126
 at ChildProcess.<anonymous> (/var/task/node_modules/fluent-ffmpeg/lib/processor.js:182:22)
 at ChildProcess.emit (node:events:513:28)
 at ChildProcess._handle.onexit (node:internal/child_process:291:12)
2023-02-17T09:27:55.236Z 5c845bb6-02c1-41b0-8759-4459591b57b0 INFO Error: ffmpeg exited with code 126 at ChildProcess.<anonymous> (/var/task/node_modules/fluent-ffmpeg/lib/processor.js:182:22) at ChildProcess.emit (node:events:513:28) at ChildProcess._handle.onexit (node:internal/child_process:291:12)
</anonymous></anonymous>


Do I need to set a specific premission for ffmpeg ?


import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
import { fromNodeProviderChain } from '@aws-sdk/credential-providers'
import axios from 'axios'
import pathToFfmpeg from 'ffmpeg-static'
import ffmpeg from 'fluent-ffmpeg'
import fs from 'fs'
ffmpeg.setFfmpegPath(pathToFfmpeg)
const credentials = fromNodeProviderChain({
 clientConfig: {
 region: 'eu-central-1',
 },
})
const client = new S3Client({ credentials })

export const handler = async (event, context) => {
 try {
 let body
 let statusCode = 200
 const query = event?.queryStringParameters
 if (!query?.imgId && !query?.video1Id && !query?.video2Id) {
 return
 }

 const imgId = query?.imgId
 const video1Id = query?.video1Id
 const video2Id = query?.video2Id
 console.log(
 `Parameters received, imgId: ${imgId}, video1Id: ${video1Id}, video2Id: ${video2Id}`
 )
 const imgURL = getFileURL(imgId)
 const video1URL = getFileURL(`${video1Id}.mp4`)
 const video2URL = getFileURL(`${video2Id}.mp4`)
 const imagePath = `/tmp/${imgId}`
 const video1Path = `/tmp/${video1Id}.mp4`
 const video2Path = `/tmp/${video2Id}.mp4`
 const outputPath = `/tmp/${imgId}.mp4`
 await Promise.all([
 downloadFile(imgURL, imagePath),
 downloadFile(video1URL, video1Path),
 downloadFile(video2URL, video2Path),
 ])
 await new Promise((resolve, reject) => {
 console.log('Input files downloaded')
 ffmpeg()
 .input(imagePath)
 .inputFormat('image2')
 .inputFPS(30)
 .loop(1)
 .size('1080x1080')
 .videoCodec('libx264')
 .format('mp4')
 .outputOptions([
 '-tune animation',
 '-pix_fmt yuv420p',
 '-profile:v baseline',
 '-level 3.0',
 '-preset medium',
 '-crf 23',
 '-movflags +faststart',
 '-y',
 ])
 .output(outputPath)
 .on('end', () => {
 console.log('Output file generated')
 resolve()
 })
 .on('error', (e) => {
 console.log(e)
 reject()
 })
 .run()
 
 })
 await uploadFile(outputPath, imgId + '.mp4')
 .then((url) => {
 body = JSON.stringify({
 url,
 })
 })
 .catch((error) => {
 console.error(error)
 statusCode = 400
 body = error?.message ?? error
 })
 console.log(`File uploaded to S3`)
 const headers = {
 'Content-Type': 'application/json',
 'Access-Control-Allow-Headers': 'Content-Type',
 'Access-Control-Allow-Origin': 'https://tikex.com, https://borespiac.hu',
 'Access-Control-Allow-Methods': 'GET',
 }
 return {
 statusCode,
 body,
 headers,
 }
 } catch (error) {
 console.error(error)
 return {
 statusCode: 500,
 body: JSON.stringify('Error fetching data'),
 }
 }
}

const downloadFile = async (url, path) => {
 try {
 console.log(`Download will start: ${url}`)
 const response = await axios(url, {
 responseType: 'stream',
 })
 if (response.status !== 200) {
 throw new Error(
 `Failed to download file, status code: ${response.status}`
 )
 }
 response.data
 .pipe(fs.createWriteStream(path))
 .on('finish', () => console.log(`File downloaded to ${path}`))
 .on('error', (e) => {
 throw new Error(`Failed to save file: ${e}`)
 })
 } catch (e) {
 console.error(`Error downloading file: ${e}`)
 }
}
const uploadFile = async (path, id) => {
 const buffer = fs.readFileSync(path)
 const params = {
 Bucket: 't44-post-cover',
 ACL: 'public-read',
 Key: id,
 ContentType: 'video/mp4',
 Body: buffer,
 }
 await client.send(new PutObjectCommand(params))
 return getFileURL(id)
}
const getFileURL = (id) => {
 const bucket = 't44-post-cover'
 const url = `https://${bucket}.s3.eu-central-1.amazonaws.com/${id}`
 return url
}



Added
AWSLambdaBasicExecutionRole-16e770c8-05fa-4c42-9819-12c468cb5b49
permission, with policy :

{
 "Version": "2012-10-17",
 "Statement": [
 {
 "Effect": "Allow",
 "Action": "logs:CreateLogGroup",
 "Resource": "arn:aws:logs:eu-central-1:634617701827:*"
 },
 {
 "Effect": "Allow",
 "Action": [
 "logs:CreateLogStream",
 "logs:PutLogEvents"
 ],
 "Resource": [
 "arn:aws:logs:eu-central-1:634617701827:log-group:/aws/lambda/promo-video-composer-2:*"
 ]
 },
 {
 "Effect": "Allow",
 "Action": [
 "s3:GetObject",
 "s3:PutObject",
 "s3:ListBucket"
 ],
 "Resource": [
 "arn:aws:s3:::example-bucket",
 "arn:aws:s3:::example-bucket/*"
 ]
 },
 {
 "Effect": "Allow",
 "Action": [
 "logs:CreateLogGroup",
 "logs:CreateLogStream",
 "logs:PutLogEvents"
 ],
 "Resource": [
 "arn:aws:logs:*:*:*"
 ]
 },
 {
 "Effect": "Allow",
 "Action": [
 "ec2:DescribeNetworkInterfaces"
 ],
 "Resource": [
 "*"
 ]
 },
 {
 "Effect": "Allow",
 "Action": [
 "sns:*"
 ],
 "Resource": [
 "*"
 ]
 },
 {
 "Effect": "Allow",
 "Action": [
 "cloudwatch:*"
 ],
 "Resource": [
 "*"
 ]
 },
 {
 "Effect": "Allow",
 "Action": [
 "kms:Decrypt"
 ],
 "Resource": [
 "*"
 ]
 }
 ]
}



What do I miss ?


janoskukoda@Janoss-MacBook-Pro promo-video-composer-2 % ls -l $(which ffmpeg)
lrwxr-xr-x 1 janoskukoda admin 35 Feb 10 12:50 /opt/homebrew/bin/ffmpeg -> ../Cellar/ffmpeg/5.1.2_4/bin/ffmpeg