
Recherche avancée
Médias (1)
-
Collections - Formulaire de création rapide
19 février 2013, par
Mis à jour : Février 2013
Langue : français
Type : Image
Autres articles (49)
-
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 (...) -
MediaSPIP version 0.1 Beta
16 avril 2011, parMediaSPIP 0.1 beta est la première version de MediaSPIP décrétée comme "utilisable".
Le fichier zip ici présent contient uniquement les sources de MediaSPIP en version standalone.
Pour avoir une installation fonctionnelle, il est nécessaire d’installer manuellement l’ensemble des dépendances logicielles sur le serveur.
Si vous souhaitez utiliser cette archive pour une installation en mode ferme, il vous faudra également procéder à d’autres modifications (...) -
Publier sur MédiaSpip
13 juin 2013Puis-je poster des contenus à partir d’une tablette Ipad ?
Oui, si votre Médiaspip installé est à la version 0.2 ou supérieure. Contacter au besoin l’administrateur de votre MédiaSpip pour le savoir
Sur d’autres sites (11899)
-
audio convert to mp3,pcm and vox using ffmpeg
8 juillet 2014, par user3789242Please can someone help me with the code for ffmpeg.
I have to useffmpeg
to convert a recorder voice (using HTML5) intomp3
,pcm
orvox
depending on the user’s selection.
I don’t know how to write the code forffmpeg
if some one can help me with the code or libraries.
Thank you in advance.Here is my code for recording the voice with a visualizer :
// variables
var leftchannel = [];
var rightchannel = [];
var recorder = null;
var recording = false;
var recordingLength = 0;
var volume = null;
var audioInput = null;
var sampleRate = 44100;
var audioContext = null;
var context = null;
var outputString;
if (!navigator.getUserMedia)
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
if (navigator.getUserMedia){
navigator.getUserMedia({audio:true}, success, function(e) {
alert('Error capturing audio.');
});
} else alert('getUserMedia not supported in this browser.');
function getVal(value)
{
// if R is pressed, we start recording
if ( value == "record"){
recording = true;
// reset the buffers for the new recording
leftchannel.length = rightchannel.length = 0;
recordingLength = 0;
document.getElementById('output').innerHTML="Recording now...";
// if S is pressed, we stop the recording and package the WAV file
} else if ( value == "stop" ){
// we stop recording
recording = false;
document.getElementById('output').innerHTML="Building wav file...";
// we flat the left and right channels down
var leftBuffer = mergeBuffers ( leftchannel, recordingLength );
var rightBuffer = mergeBuffers ( rightchannel, recordingLength );
// we interleave both channels together
var interleaved = interleave ( leftBuffer, rightBuffer );
var buffer = new ArrayBuffer(44 + interleaved.length * 2);
var view = new DataView(buffer);
// RIFF chunk descriptor
writeUTFBytes(view, 0, 'RIFF');
view.setUint32(4, 44 + interleaved.length * 2, true);
writeUTFBytes(view, 8, 'WAVE');
// FMT sub-chunk
writeUTFBytes(view, 12, 'fmt ');
view.setUint32(16, 16, true);
view.setUint16(20, 1, true);
// stereo (2 channels)
view.setUint16(22, 2, true);
view.setUint32(24, sampleRate, true);
view.setUint32(28, sampleRate * 4, true);
view.setUint16(32, 4, true);
view.setUint16(34, 16, true);
// data sub-chunk
writeUTFBytes(view, 36, 'data');
view.setUint32(40, interleaved.length * 2, true);
var lng = interleaved.length;
var index = 44;
var volume = 1;
for (var i = 0; i < lng; i++){
view.setInt16(index, interleaved[i] * (0x7FFF * volume), true);
index += 2;
}
var blob = new Blob ( [ view ], { type : 'audio/wav' } );
// let's save it locally
document.getElementById('output').innerHTML='Handing off the file now...';
var url = (window.URL || window.webkitURL).createObjectURL(blob);
var li = document.createElement('li');
var au = document.createElement('audio');
var hf = document.createElement('a');
au.controls = true;
au.src = url;
hf.href = url;
hf.download = 'audio_recording_' + new Date().getTime() + '.wav';
hf.innerHTML = hf.download;
li.appendChild(au);
li.appendChild(hf);
recordingList.appendChild(li);
}
}
function success(e){
audioContext = window.AudioContext || window.webkitAudioContext;
context = new audioContext();
volume = context.createGain();
// creates an audio node from the microphone incoming stream(source)
source = context.createMediaStreamSource(e);
// connect the stream(source) to the gain node
source.connect(volume);
var bufferSize = 2048;
recorder = context.createScriptProcessor(bufferSize, 2, 2);
//node for the visualizer
analyser = context.createAnalyser();
analyser.smoothingTimeConstant = 0.3;
analyser.fftSize = 512;
splitter = context.createChannelSplitter();
//when recording happens
recorder.onaudioprocess = function(e){
if (!recording) return;
var left = e.inputBuffer.getChannelData (0);
var right = e.inputBuffer.getChannelData (1);
leftchannel.push (new Float32Array (left));
rightchannel.push (new Float32Array (right));
recordingLength += bufferSize;
// get the average for the first channel
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
var c=document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// clear the current state
ctx.clearRect(0, 0, 1000, 325);
var gradient = ctx.createLinearGradient(0,0,0,300);
gradient.addColorStop(1,'#000000');
gradient.addColorStop(0.75,'#ff0000');
gradient.addColorStop(0.25,'#ffff00');
gradient.addColorStop(0,'#ffffff');
// set the fill style
ctx.fillStyle=gradient;
drawSpectrum(array);
function drawSpectrum(array) {
for ( var i = 0; i < (array.length); i++ ){
var value = array[i];
ctx.fillRect(i*5,325-value,3,325);
}
}
}
function getAverageVolume(array) {
var values = 0;
var average;
var length = array.length;
// get all the frequency amplitudes
for (var i = 0; i < length; i++) {
values += array[i];
}
average = values / length;
return average;
}
// we connect the recorder(node to destination(speakers))
volume.connect(splitter);
splitter.connect(analyser, 0, 0);
analyser.connect(recorder);
recorder.connect(context.destination);
}
function mergeBuffers(channelBuffer, recordingLength){
var result = new Float32Array(recordingLength);
var offset = 0;
var lng = channelBuffer.length;
for (var i = 0; i < lng; i++){
var buffer = channelBuffer[i];
result.set(buffer, offset);
offset += buffer.length;
}
return result;
}
function interleave(leftChannel, rightChannel){
var length = leftChannel.length + rightChannel.length;
var result = new Float32Array(length);
var inputIndex = 0;
for (var index = 0; index < length; ){
result[index++] = leftChannel[inputIndex];
result[index++] = rightChannel[inputIndex];
inputIndex++;
}
return result;
}
function writeUTFBytes(view, offset, string){
var lng = string.length;
for (var i = 0; i < lng; i++){
view.setUint8(offset + i, string.charCodeAt(i));
}
} -
ffmpeg Command in Docker with Rust Tokio Closes Warp Server Connection (curl 52 Error)
3 juin 2024, par user762345I’m encountering an issue where executing an ffmpeg concatenation command through Rust’s Tokio process in a Docker container causes subsequent HTTP requests to fail. The error occurs exclusively after running the ffmpeg command and making immediate requests, resulting in a “curl 52 empty response from server” error with the connection being closed. Notably, this issue does not occur when running the same setup outside of Docker. Additionally, if no HTTP requests are made after the ffmpeg command, the curl 52 error does not occur.


Here is the verbose curl output of my minimum reproducible example (see below).


curl -v "http://localhost:3030"
* Trying 127.0.0.1:3030...
* Connected to localhost (127.0.0.1) port 3030 (#0)
> GET / HTTP/1.1
> Host: localhost:3030
> User-Agent: curl/8.1.2
> Accept: */*
> 
* Empty reply from server
* Closing connection 0
curl: (52) Empty reply from server



Here are Docker logs from my minimum reproducible example (see below). The wav files are concatenated successfully, then the container appears to rebuild.


[2024-06-03T05:26:58Z INFO minimal_docker_webserver_post_error] Starting server on 0.0.0.0:3030
[2024-06-03T05:26:58Z INFO warp::server] Server::run; addr=0.0.0.0:3030
[2024-06-03T05:26:58Z INFO warp::server] listening on http://0.0.0.0:3030
[2024-06-03T05:27:07Z INFO minimal_docker_webserver_post_error] WAV files concatenated successfully
[Running 'cargo run']
 Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s
 Running `target/debug/minimal_docker_webserver_post_error`
[2024-06-03T05:27:08Z INFO minimal_docker_webserver_post_error] Starting server on 0.0.0.0:3030
[2024-06-03T05:27:08Z INFO warp::server] Server::run; addr=0.0.0.0:3030
[2024-06-03T05:27:08Z INFO warp::server] listening on http://0.0.0.0:3030



What I have tried :
I tried using different web frameworks (Warp, Actix-web) and request crates (reqwest, ureq). I also tried running the setup outside of Docker, which worked as expected without any issues. Additionally, I tried running the setup in Docker without making any HTTP requests after the ffmpeg command, and the connection closed successfully without errors. I also tried posting to httpbin with a minimal request, but the issue persisted.


Minimum reproducible example :


main.rs


use warp::Filter;
use reqwest::Client;
use std::convert::Infallible;
use log::{info, error};
use env_logger;
use tokio::process::Command;

#[tokio::main]
async fn main() {
 std::env::set_var("RUST_LOG", "debug");
 env_logger::init();

 let route = warp::path::end()
 .and_then(handle_request);

 info!("Starting server on 0.0.0.0:3030");
 warp::serve(route)
 .run(([0, 0, 0, 0], 3030))
 .await;
}

async fn handle_request() -> Result<impl infallible="infallible"> {
 let client = Client::new();

 let output = Command::new("ffmpeg")
 .args(&[
 "y",
 "-i", "concat:/usr/src/minimal_docker_webserver_post_error/file1.wav|/usr/src/minimal_docker_webserver_post_error/file2.wav",
 "-c", "copy",
 "/usr/src/minimal_docker_webserver_post_error/combined.wav"
 ])
 .output()
 .await;

 match output {
 Ok(output) => {
 if output.status.success() {
 info!("WAV files concatenated successfully");
 } else {
 error!("Failed to concatenate WAV files: {:?}", output);
 return Ok(warp::reply::with_status("Failed to concatenate WAV files", warp::http::StatusCode::INTERNAL_SERVER_ERROR));
 }
 },
 Err(e) => {
 error!("Failed to execute ffmpeg: {:?}", e);
 return Ok(warp::reply::with_status("Failed to execute ffmpeg", warp::http::StatusCode::INTERNAL_SERVER_ERROR));
 }
 }

 // ISSUE: Connection closes with curl: (52) Empty reply from server
 match client.get("https://httpbin.org/get").send().await {
 Ok(response) => info!("GET request successful: {:?}", response),
 Err(e) => error!("GET request failed: {:?}", e),
 }

 match client.post("https://httpbin.org/post")
 .body("field1=value1&field2=value2")
 .send().await {
 Ok(response) => info!("POST request successful: {:?}", response),
 Err(e) => error!("POST request failed: {:?}", e),
 }

 Ok(warp::reply::with_status("Request handled", warp::http::StatusCode::OK))
}
</impl>


FFMPEG command to generate the two wav files for concatenation


ffmpeg -f lavfi -i "sine=frequency=1000:duration=5" file1.wav && ffmpeg -f lavfi -i "sine=frequency=500:duration=5" file2.wav



Dockerfile


# Use the official Rust image as the base image
FROM rust:latest

# Install cargo-watch
RUN cargo install cargo-watch

# Install ffmpeg
RUN apt-get update && apt-get install -y ffmpeg

# Set the working directory inside the container
WORKDIR /usr/src/minimal_docker_webserver_post_error

# Copy the Cargo.toml and Cargo.lock files
COPY Cargo.toml Cargo.lock ./

# Copy the source code
COPY src ./src

# Copy wav files
COPY file1.wav /usr/src/minimal_docker_webserver_post_error/file1.wav
COPY file2.wav /usr/src/minimal_docker_webserver_post_error/file2.wav

# Install dependencies
RUN cargo build --release

# Expose the port that the application will run on
EXPOSE 3030

# Set the entry point to use cargo-watch
CMD ["cargo", "watch", "-x", "run"]



Cargo.toml


[package]
name = "minimal_docker_webserver_post_error"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
warp = "0.3"
reqwest = { version = "0.12.4", features = ["json"] }
tokio = { version = "1", features = ["full"] }
log = "0.4"
env_logger = "0.11.3"



Making the request to the warp server


curl -v "http://localhost:3030"



-
webrtc to rtmp send video from camera to rtmp link
14 avril 2024, par Leo-Mahendrai cant send the video from webrtc which is converted to bufferd data for every 10seconds and send to server.js where it takes it via websockets and convert it to flv format using ffmpeg.


i am trying to send it to rtmp server named restreamer for start, here i tried to convert the buffer data and send it to rtmp link using ffmpeg commands, where i initially started to suceesfully save the file from webrtc to mp4 format for a duration of 2-3 minute.


after i tried to use webrtc to send video data for every 10 seconds and in server i tried to send it to rtmp but i cant send it, but i can see the connection of rtmp url and server is been taken place but i cant see the video i can see the logs in rtmp server as


2024-04-14 12:35:45 ts=2024-04-14T07:05:45Z level=INFO component="RTMP" msg="no streams available" action="INVALID" address=":1935" client="172.17.0.1:37700" path="/3d30c5a9-2059-4843-8957-da963c7bc19b.stream" who="PUBLISH"
2024-04-14 12:35:45 ts=2024-04-14T07:05:45Z level=INFO component="RTMP" msg="no streams available" action="INVALID" address=":1935" client="172.17.0.1:37716" path="/3d30c5a9-2059-4843-8957-da963c7bc19b.stream" who="PUBLISH"
2024-04-14 12:35:45 ts=2024-04-14T07:05:45Z level=INFO component="RTMP" msg="no streams available" action="INVALID" address=":1935" client="172.17.0.1:37728" path="/3d30c5a9-2059-4843-8957-da963c7bc19b.stream" who="PUBLISH" 



my frontend code


const handleSendVideo = async () => {
 console.log("start");
 
 if (!ws) {
 console.error('WebSocket connection not established.');
 return;
 }
 
 try {
 const videoStream = await navigator.mediaDevices.getUserMedia({ video: true });
 const mediaRecorder = new MediaRecorder(videoStream);
 
 const requiredFrameSize = 460800;
 const frameDuration = 10 * 1000; // 10 seconds in milliseconds
 
 mediaRecorder.ondataavailable = async (event) => {
 if (ws.readyState !== WebSocket.OPEN) {
 console.error('WebSocket connection is not open.');
 return;
 }
 
 if (event.data.size > 0) {
 const arrayBuffer = await event.data.arrayBuffer();
 const uint8Array = new Uint8Array(arrayBuffer);
 
 const width = videoStream.getVideoTracks()[0].getSettings().width;
 const height = videoStream.getVideoTracks()[0].getSettings().height;
 
 const numFrames = Math.ceil(uint8Array.length / requiredFrameSize);
 
 for (let i = 0; i < numFrames; i++) {
 const start = i * requiredFrameSize;
 const end = Math.min((i + 1) * requiredFrameSize, uint8Array.length);
 let frameData = uint8Array.subarray(start, end);
 
 // Pad or trim the frameData to match the required size
 if (frameData.length < requiredFrameSize) {
 // Pad with zeros to reach the required size
 const paddedData = new Uint8Array(requiredFrameSize);
 paddedData.set(frameData, 0);
 frameData = paddedData;
 } else if (frameData.length > requiredFrameSize) {
 // Trim to match the required size
 frameData = frameData.subarray(0, requiredFrameSize);
 }
 
 const dataToSend = {
 buffer: Array.from(frameData), // Convert Uint8Array to array of numbers
 width: width,
 height: height,
 pixelFormat: 'yuv420p',
 mode: 'SendRtmp'
 };
 
 console.log("Sending frame:", i);
 ws.send(JSON.stringify(dataToSend));
 }
 }
 };
 
 // Start recording and send data every 10 seconds
 mediaRecorder.start(frameDuration);
 
 console.log("MediaRecorder started.");
 } catch (error) {
 console.error('Error accessing media devices or starting recorder:', error);
 }
 };



and my backend


wss.on('connection', (ws) => {
 console.log('WebSocket connection established.');

 ws.on('message', async (data) => {
 try {
 const parsedData = JSON.parse(data);

 if (parsedData.mode === 'SendRtmp' && Array.isArray(parsedData.buffer)) {
 const { buffer, pixelFormat, width, height } = parsedData;
 const bufferArray = Buffer.from(buffer);

 await sendRtmpVideo(bufferArray, pixelFormat, width, height);
 } else {
 console.log('Received unknown or invalid mode or buffer data');
 }
 } catch (error) {
 console.error('Error parsing WebSocket message:', error);
 }
 });

 ws.on('close', () => {
 console.log('WebSocket connection closed.');
 });
 });
 const sendRtmpVideo = async (frameBuffer, pixelFormat, width, height) => {
 console.log("ffmpeg data",frameBuffer)
 try {
 const ratio = `${width}x${height}`;
 const ffmpegCommand = [
 '-re',
 '-f', 'rawvideo',
 '-pix_fmt', pixelFormat,
 '-s', ratio,
 '-i', 'pipe:0',
 '-c:v', 'libx264',
 '-preset', 'fast', // Specify the preset for libx264
 '-b:v', '3000k', // Specify the video bitrate
 '-loglevel', 'debug',
 '-f', 'flv',
 // '-flvflags', 'no_duration_filesize', 
 RTMPLINK
 ];


 const ffmpeg = spawn('ffmpeg', ffmpegCommand);

 ffmpeg.on('exit', (code, signal) => {
 if (code === 0) {
 console.log('FFmpeg process exited successfully.');
 } else {
 console.error(`FFmpeg process exited with code ${code} and signal ${signal}`);
 }
 });

 ffmpeg.on('error', (error) => {
 console.error('FFmpeg spawn error:', error);
 });

 ffmpeg.stderr.on('data', (data) => {
 console.error(`FFmpeg stderr: ${data}`);
 });

 ffmpeg.stdin.write(frameBuffer, (err) => {
 if (err) {
 console.error('Error writing to FFmpeg stdin:', err);
 } else {
 console.log('Data written to FFmpeg stdin successfully.');
 }
 ffmpeg.stdin.end(); // Close stdin after writing the buffer
 });
 } catch (error) {
 console.error('Error in sendRtmpVideo:', error);
 }
 };