
Recherche avancée
Médias (91)
-
Géodiversité
9 septembre 2011, par ,
Mis à jour : Août 2018
Langue : français
Type : Texte
-
USGS Real-time Earthquakes
8 septembre 2011, par
Mis à jour : Septembre 2011
Langue : français
Type : Texte
-
SWFUpload Process
6 septembre 2011, par
Mis à jour : Septembre 2011
Langue : français
Type : Texte
-
La conservation du net art au musée. Les stratégies à l’œuvre
26 mai 2011
Mis à jour : Juillet 2013
Langue : français
Type : Texte
-
Podcasting Legal guide
16 mai 2011, par
Mis à jour : Mai 2011
Langue : English
Type : Texte
-
Creativecommons informational flyer
16 mai 2011, par
Mis à jour : Juillet 2013
Langue : English
Type : Texte
Autres articles (66)
-
Ecrire une actualité
21 juin 2013, parPrésentez les changements dans votre MédiaSPIP ou les actualités de vos projets sur votre MédiaSPIP grâce à la rubrique actualités.
Dans le thème par défaut spipeo de MédiaSPIP, les actualités sont affichées en bas de la page principale sous les éditoriaux.
Vous pouvez personnaliser le formulaire de création d’une actualité.
Formulaire de création d’une actualité Dans le cas d’un document de type actualité, les champs proposés par défaut sont : Date de publication ( personnaliser la date de publication ) (...) -
Soumettre améliorations et plugins supplémentaires
10 avril 2011Si vous avez développé une nouvelle extension permettant d’ajouter une ou plusieurs fonctionnalités utiles à MediaSPIP, faites le nous savoir et son intégration dans la distribution officielle sera envisagée.
Vous pouvez utiliser la liste de discussion de développement afin de le faire savoir ou demander de l’aide quant à la réalisation de ce plugin. MediaSPIP étant basé sur SPIP, il est également possible d’utiliser le liste de discussion SPIP-zone de SPIP pour (...) -
Initialisation de MediaSPIP (préconfiguration)
20 février 2010, parLors de l’installation de MediaSPIP, celui-ci est préconfiguré pour les usages les plus fréquents.
Cette préconfiguration est réalisée par un plugin activé par défaut et non désactivable appelé MediaSPIP Init.
Ce plugin sert à préconfigurer de manière correcte chaque instance de MediaSPIP. Il doit donc être placé dans le dossier plugins-dist/ du site ou de la ferme pour être installé par défaut avant de pouvoir utiliser le site.
Dans un premier temps il active ou désactive des options de SPIP qui ne le (...)
Sur d’autres sites (6839)
-
Converting a voice recording into an mp3
21 juillet 2023, par Raphael MFor a vue.js messaging project, I'm using the wavesurfer.js library to record voice messages. However Google chrome gives me an audio/webm blob and Safari gives me an audio/mp4 blob.


I'm trying to find a solution to transcode the blob into audio/mp3. I've tried several methods, including ffmpeg. However, ffmpeg gives me an error when compiling "npm run dev" : "Can't resolve '/node_modules/@ffmpeg/core/dist/ffmpeg-core.js'".


"@ffmpeg/core": "^0.11.0",
"@ffmpeg/ffmpeg": "^0.11.6"



I tried to downgrade ffmpeg


"@ffmpeg/core": "^0.9.0",
"@ffmpeg/ffmpeg": "^0.9.8"



I no longer get the error message when compiling, but when I want to convert my audio stream, the console displays a problem with SharedBuffer : "Uncaught (in promise) ReferenceError : SharedArrayBuffer is not defined".


Here's my complete code below.
Is there a reliable way of transcoding the audio stream into mp3 ?


Can you give me an example ?


Thanks


<template>
 <div class="left-panel">
 <header class="radial-blue">
 <div class="container">
 <h1 class="mb-30">Posez votre première question à nos thérapeutes</h1>
 <p><b>Attention</b>, vous disposez seulement de 2 messages. Veillez à les utiliser de manière judicieuse !</p>
 <div class="available-messages">
 <div class="item disabled">
 <span>Message 1</span>
 </div>
 <div class="item">
 <span>Message 2</span>
 </div>
 </div>
 </div>
 </header>
 </div>
 <div class="right-panel">
 <div class="messagerie bg-light">
 <messaging ref="messagingComponent"></messaging>
 <footer>
 <button type="button"><img src="http://stackoverflow.com/assets/backoffice/images/record-start.svg" style='max-width: 300px; max-height: 300px' /></button>
 <div class="loading-animation">
 <img src="http://stackoverflow.com/assets/backoffice/images/record-loading.svg" style='max-width: 300px; max-height: 300px' />
 </div>
 <button type="button"><img src="http://stackoverflow.com/assets/backoffice/images/record-stop.svg" style='max-width: 300px; max-height: 300px' /></button>
 <div class="textarea gradient text-dark">
 <textarea placeholder="Posez votre question"></textarea>
 </div>
 <div class="loading-text">Chargement de votre microphone en cours...</div>
 <div class="loading-text">Envoi de votre message en cours...</div>
 <div ref="visualizer"></div>
 <button type="button"><img src="http://stackoverflow.com/assets/backoffice/images/send.svg" style='max-width: 300px; max-height: 300px' /></button>
 <div>
 {{ formatTimer() }}
 </div>
 </footer>
 </div>
 </div>
</template>

<code class="echappe-js"><script>&#xA;import Messaging from "./Messaging.vue";&#xA;import { createFFmpeg, fetchFile } from &#x27;@ffmpeg/ffmpeg&#x27;;&#xA;&#xA;export default {&#xA; data() {&#xA; return {&#xA; isMicrophoneLoading: false,&#xA; isSubmitLoading: false,&#xA; isMobile: false,&#xA; isMessagerie: false,&#xA; isRecording: false,&#xA; audioUrl: &#x27;&#x27;,&#xA; messageText: &#x27;&#x27;,&#xA; message:null,&#xA; wavesurfer: null,&#xA; access:(this.isMobile?&#x27;denied&#x27;:&#x27;granted&#x27;),&#xA; maxMinutes: 5,&#xA; orangeTimer: 3,&#xA; redTimer: 4,&#xA; timer: 0,&#xA; timerInterval: null,&#xA; ffmpeg: null,&#xA; };&#xA; },&#xA; components: {&#xA; Messaging,&#xA; },&#xA; mounted() {&#xA; this.checkScreenSize();&#xA; window.addEventListener(&#x27;resize&#x27;, this.checkScreenSize);&#xA;&#xA; if(!this.isMobile)&#xA; {&#xA; this.$moment.locale(&#x27;fr&#x27;);&#xA; window.addEventListener(&#x27;beforeunload&#x27;, (event) => {&#xA; if (this.isMessagerie) {&#xA; event.preventDefault();&#xA; event.returnValue = &#x27;&#x27;;&#xA; }&#xA; });&#xA;&#xA; this.initializeWaveSurfer();&#xA; }&#xA; },&#xA; beforeUnmount() {&#xA; window.removeEventListener(&#x27;resize&#x27;, this.checkScreenSize);&#xA; },&#xA; methods: {&#xA; checkScreenSize() {&#xA; this.isMobile = window.innerWidth < 1200;&#xA;&#xA; const windowHeight = window.innerHeight;&#xA; const navbarHeight = this.$navbarHeight;&#xA; let padding = parseInt(navbarHeight &#x2B;181);&#xA;&#xA; const messageListHeight = windowHeight - padding;&#xA; this.$refs.messagingComponent.$refs.messageList.style.height = messageListHeight &#x2B; &#x27;px&#x27;;&#xA; },&#xA; showMessagerie() {&#xA; this.isMessagerie = true;&#xA; this.$refs.messagingComponent.scrollToBottom();&#xA; },&#xA; checkMicrophoneAccess() {&#xA; if (navigator.mediaDevices &amp;&amp; navigator.mediaDevices.getUserMedia) {&#xA;&#xA; return navigator.mediaDevices.getUserMedia({audio: true})&#xA; .then(function (stream) {&#xA; stream.getTracks().forEach(function (track) {&#xA; track.stop();&#xA; });&#xA; return true;&#xA; })&#xA; .catch(function (error) {&#xA; console.error(&#x27;Erreur lors de la demande d\&#x27;acc&#xE8;s au microphone:&#x27;, error);&#xA; return false;&#xA; });&#xA; } else {&#xA; console.error(&#x27;getUserMedia n\&#x27;est pas support&#xE9; par votre navigateur.&#x27;);&#xA; return false;&#xA; }&#xA; },&#xA; initializeWaveSurfer() {&#xA; this.wavesurfer = this.$wavesurfer.create({&#xA; container: &#x27;#visualizer&#x27;,&#xA; barWidth: 3,&#xA; barHeight: 1.5,&#xA; height: 46,&#xA; responsive: true,&#xA; waveColor: &#x27;rgba(108,115,202,0.3)&#x27;,&#xA; progressColor: &#x27;rgba(108,115,202,1)&#x27;,&#xA; cursorColor: &#x27;transparent&#x27;&#xA; });&#xA;&#xA; this.record = this.wavesurfer.registerPlugin(this.$recordPlugin.create());&#xA; },&#xA; startRecording() {&#xA; const _this = this;&#xA; this.isMicrophoneLoading = true;&#xA;&#xA; setTimeout(() =>&#xA; {&#xA; _this.checkMicrophoneAccess().then(function (accessible)&#xA; {&#xA; if (accessible) {&#xA; _this.record.startRecording();&#xA;&#xA; _this.record.once(&#x27;startRecording&#x27;, () => {&#xA; _this.isMicrophoneLoading = false;&#xA; _this.isRecording = true;&#xA; _this.updateChildMessage( &#x27;server&#x27;, &#x27;Allez-y ! Vous pouvez enregistrer votre message audio maintenant. La dur&#xE9;e maximale autoris&#xE9;e pour votre enregistrement est de 5 minutes.&#x27;, &#x27;text&#x27;, &#x27;&#x27;, &#x27;Message automatique&#x27;);&#xA; _this.startTimer();&#xA; });&#xA; } else {&#xA; _this.isRecording = false;&#xA; _this.isMicrophoneLoading = false;&#xA; _this.$swal.fire({&#xA; title: &#x27;Microphone non d&#xE9;tect&#xE9;&#x27;,&#xA; html: &#x27;<p>Le microphone de votre appareil est inaccessible ou l\&#x27;acc&#xE8;s a &#xE9;t&#xE9; refus&#xE9;.</p><p>Merci de v&#xE9;rifier les param&#xE8;tres de votre navigateur afin de v&#xE9;rifier les autorisations de votre microphone.</p>&#x27;,&#xA; footer: &#x27;<a href='http://stackoverflow.com/contact'>Vous avez besoin d\&#x27;aide ?</a>&#x27;,&#xA; });&#xA; }&#xA; });&#xA; }, 100);&#xA; },&#xA; stopRecording() {&#xA; this.stopTimer();&#xA; this.isRecording = false;&#xA; this.isSubmitLoading = true;&#xA; this.record.stopRecording();&#xA;&#xA; this.record.once(&#x27;stopRecording&#x27;, () => {&#xA; const blobUrl = this.record.getRecordedUrl();&#xA; fetch(blobUrl).then(response => response.blob()).then(blob => {&#xA; this.uploadAudio(blob);&#xA; });&#xA; });&#xA; },&#xA; startTimer() {&#xA; this.timerInterval = setInterval(() => {&#xA; this.timer&#x2B;&#x2B;;&#xA; if (this.timer === this.maxMinutes * 60) {&#xA; this.stopRecording();&#xA; }&#xA; }, 1000);&#xA; },&#xA; stopTimer() {&#xA; clearInterval(this.timerInterval);&#xA; this.timer = 0;&#xA; },&#xA; formatTimer() {&#xA; const minutes = Math.floor(this.timer / 60);&#xA; const seconds = this.timer % 60;&#xA; const formattedMinutes = minutes < 10 ? `0${minutes}` : minutes;&#xA; const formattedSeconds = seconds < 10 ? `0${seconds}` : seconds;&#xA; return `${formattedMinutes}:${formattedSeconds}`;&#xA; },&#xA; async uploadAudio(blob)&#xA; {&#xA; const format = blob.type === &#x27;audio/webm&#x27; ? &#x27;webm&#x27; : &#x27;mp4&#x27;;&#xA;&#xA; // Convert the blob to MP3&#xA; const mp3Blob = await this.convertToMp3(blob, format);&#xA;&#xA; const s3 = new this.$AWS.S3({&#xA; accessKeyId: &#x27;xxx&#x27;,&#xA; secretAccessKey: &#x27;xxx&#x27;,&#xA; region: &#x27;eu-west-1&#x27;&#xA; });&#xA;&#xA; var currentDate = new Date();&#xA; var filename = currentDate.getDate().toString() &#x2B; &#x27;-&#x27; &#x2B; currentDate.getMonth().toString() &#x2B; &#x27;-&#x27; &#x2B; currentDate.getFullYear().toString() &#x2B; &#x27;--&#x27; &#x2B; currentDate.getHours().toString() &#x2B; &#x27;-&#x27; &#x2B; currentDate.getMinutes().toString() &#x2B; &#x27;.mp4&#x27;;&#xA;&#xA; const params = {&#xA; Bucket: &#x27;xxx/audio&#x27;,&#xA; Key: filename,&#xA; Body: mp3Blob,&#xA; ACL: &#x27;public-read&#x27;,&#xA; ContentType: &#x27;audio/mp3&#x27;&#xA; }&#xA;&#xA; s3.upload(params, (err, data) => {&#xA; if (err) {&#xA; console.error(&#x27;Error uploading audio:&#x27;, err)&#xA; } else {&#xA; const currentDate = this.$moment();&#xA; const timestamp = currentDate.format(&#x27;dddd DD MMMM YYYY HH:mm&#x27;);&#xA;&#xA; this.updateChildMessage( &#x27;client&#x27;, &#x27;&#x27;, &#x27;audio&#x27;, mp3Blob, timestamp);&#xA; this.isSubmitLoading = false;&#xA; }&#xA; });&#xA; },&#xA; async convertToMp3(blob, format) {&#xA; const ffmpeg = createFFmpeg({ log: true });&#xA; await ffmpeg.load();&#xA;&#xA; const inputPath = &#x27;input.&#x27; &#x2B; format;&#xA; const outputPath = &#x27;output.mp3&#x27;;&#xA;&#xA; ffmpeg.FS(&#x27;writeFile&#x27;, inputPath, await fetchFile(blob));&#xA;&#xA; await ffmpeg.run(&#x27;-i&#x27;, inputPath, &#x27;-acodec&#x27;, &#x27;libmp3lame&#x27;, outputPath);&#xA;&#xA; const mp3Data = ffmpeg.FS(&#x27;readFile&#x27;, outputPath);&#xA; const mp3Blob = new Blob([mp3Data.buffer], { type: &#x27;audio/mp3&#x27; });&#xA;&#xA; ffmpeg.FS(&#x27;unlink&#x27;, inputPath);&#xA; ffmpeg.FS(&#x27;unlink&#x27;, outputPath);&#xA;&#xA; return mp3Blob;&#xA; },&#xA; sendMessage() {&#xA; this.isSubmitLoading = true;&#xA; if (this.messageText.trim() !== &#x27;&#x27;) {&#xA; const emmet = &#x27;client&#x27;;&#xA; const text = this.escapeHTML(this.messageText)&#xA; .replace(/\n/g, &#x27;<br>&#x27;);&#xA;&#xA; const currentDate = this.$moment();&#xA; const timestamp = currentDate.format(&#x27;dddd DD MMMM YYYY HH:mm&#x27;);&#xA;&#xA; this.$nextTick(() => {&#xA; this.messageText = &#x27;&#x27;;&#xA;&#xA; const textarea = document.getElementById(&#x27;messageTextarea&#x27;);&#xA; if (textarea) {&#xA; textarea.scrollTop = 0;&#xA; textarea.scrollLeft = 0;&#xA; }&#xA; });&#xA;&#xA; this.updateChildMessage(emmet, text, &#x27;text&#x27;, &#x27;&#x27;, timestamp);&#xA; this.isSubmitLoading = false;&#xA; }&#xA; },&#xA; escapeHTML(text) {&#xA; const map = {&#xA; &#x27;&amp;&#x27;: &#x27;&amp;amp;&#x27;,&#xA; &#x27;<&#x27;: &#x27;&amp;lt;&#x27;,&#xA; &#x27;>&#x27;: &#x27;&amp;gt;&#x27;,&#xA; &#x27;"&#x27;: &#x27;&amp;quot;&#x27;,&#xA; "&#x27;": &#x27;&amp;#039;&#x27;,&#xA; "`": &#x27;&amp;#x60;&#x27;,&#xA; "/": &#x27;&amp;#x2F;&#x27;&#xA; };&#xA; return text.replace(/[&amp;<>"&#x27;`/]/g, (match) => map[match]);&#xA; },&#xA; updateChildMessage(emmet, text, type, blob, timestamp) {&#xA; const newMessage = {&#xA; id: this.$refs.messagingComponent.lastMessageId &#x2B; 1,&#xA; emmet: emmet,&#xA; text: text,&#xA; type: type,&#xA; blob: blob,&#xA; timestamp: timestamp&#xA; };&#xA;&#xA; this.$refs.messagingComponent.updateMessages(newMessage);&#xA; }&#xA; },&#xA;};&#xA;</script>



-
Screen Recording with FFmpeg-Lib with c++
27 janvier 2020, par BaschdelI’m trying to record the whole desktop stream with FFmpeg on Windows.
I found a working example here. The Problem is that some og the functions depricated. So I tried to replace them with the updated ones.But there are some slight problems. The error "has triggered a breakpoint." occurse and also "not able to read the location."
The bigger problem is that I don’t know if this is the right way to do this..My code looks like this :
using namespace std;
/* initialize the resources*/
Recorder::Recorder()
{
av_register_all();
avcodec_register_all();
avdevice_register_all();
cout<<"\nall required functions are registered successfully";
}
/* uninitialize the resources */
Recorder::~Recorder()
{
avformat_close_input(&pAVFormatContext);
if( !pAVFormatContext )
{
cout<<"\nfile closed sucessfully";
}
else
{
cout<<"\nunable to close the file";
exit(1);
}
avformat_free_context(pAVFormatContext);
if( !pAVFormatContext )
{
cout<<"\navformat free successfully";
}
else
{
cout<<"\nunable to free avformat context";
exit(1);
}
}
/* establishing the connection between camera or screen through its respective folder */
int Recorder::openCamera()
{
value = 0;
options = NULL;
pAVFormatContext = NULL;
pAVFormatContext = avformat_alloc_context();//Allocate an AVFormatContext.
openScreen(pAVFormatContext);
/* set frame per second */
value = av_dict_set( &options,"framerate","30",0 );
if(value < 0)
{
cout<<"\nerror in setting dictionary value";
exit(1);
}
value = av_dict_set( &options, "preset", "medium", 0 );
if(value < 0)
{
cout<<"\nerror in setting preset values";
exit(1);
}
// value = avformat_find_stream_info(pAVFormatContext,NULL);
if(value < 0)
{
cout<<"\nunable to find the stream information";
exit(1);
}
VideoStreamIndx = -1;
/* find the first video stream index . Also there is an API available to do the below operations */
for(int i = 0; i < pAVFormatContext->nb_streams; i++ ) // find video stream posistion/index.
{
if( pAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO )
{
VideoStreamIndx = i;
break;
}
}
if( VideoStreamIndx == -1)
{
cout<<"\nunable to find the video stream index. (-1)";
exit(1);
}
// assign pAVFormatContext to VideoStreamIndx
pAVCodecContext = pAVFormatContext->streams[VideoStreamIndx]->codec;
pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id);
if( pAVCodec == NULL )
{
cout<<"\nunable to find the decoder";
exit(1);
}
value = avcodec_open2(pAVCodecContext , pAVCodec , NULL);//Initialize the AVCodecContext to use the given AVCodec.
if( value < 0 )
{
cout<<"\nunable to open the av codec";
exit(1);
}
}
/* initialize the video output file and its properties */
int Recorder::init_outputfile()
{
outAVFormatContext = NULL;
value = 0;
output_file = "output.mp4";
avformat_alloc_output_context2(&outAVFormatContext, NULL, NULL, output_file);
if (!outAVFormatContext)
{
cout<<"\nerror in allocating av format output context";
exit(1);
}
/* Returns the output format in the list of registered output formats which best matches the provided parameters, or returns NULL if there is no match. */
output_format = av_guess_format(NULL, output_file ,NULL);
if( !output_format )
{
cout<<"\nerror in guessing the video format. try with correct format";
exit(1);
}
video_st = avformat_new_stream(outAVFormatContext ,NULL);
if( !video_st )
{
cout<<"\nerror in creating a av format new stream";
exit(1);
}
if (codec_id == AV_CODEC_ID_H264)
{
av_opt_set(outAVCodecContext->priv_data, "preset", "slow", 0);
}
outAVCodec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
if (!outAVCodec)
{
cout << "\nerror in finding the av codecs. try again with correct codec";
exit(1);
}
outAVCodecContext = avcodec_alloc_context3(outAVCodec);
if( !outAVCodecContext )
{
cout<<"\nerror in allocating the codec contexts";
exit(1);
}
/* set property of the video file */
outAVCodecContext = video_st->codec;
outAVCodecContext->codec_id = AV_CODEC_ID_MPEG4;// AV_CODEC_ID_MPEG4; // AV_CODEC_ID_H264 // AV_CODEC_ID_MPEG1VIDEO
outAVCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
outAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
outAVCodecContext->bit_rate = 400000; // 2500000
outAVCodecContext->width = 1920;
outAVCodecContext->height = 1080;
outAVCodecContext->gop_size = 3;
outAVCodecContext->max_b_frames = 2;
outAVCodecContext->time_base.num = 1;
outAVCodecContext->time_base.den = 30; //15fps
/* Some container formats (like MP4) require global headers to be present
Mark the encoder so that it behaves accordingly. */
if ( outAVFormatContext->oformat->flags & AVFMT_GLOBALHEADER)
{
outAVCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
value = avcodec_open2(outAVCodecContext, outAVCodec, NULL);
if( value < 0)
{
cout<<"\nerror in opening the avcodec";
exit(1);
}
/* create empty video file */
if ( !(outAVFormatContext->flags & AVFMT_NOFILE) )
{
if( avio_open2(&outAVFormatContext->pb , output_file , AVIO_FLAG_WRITE ,NULL, NULL) < 0 )
{
cout<<"\nerror in creating the video file";
exit(1);
}
}
if(!outAVFormatContext->nb_streams)
{
cout<<"\noutput file dose not contain any stream";
exit(1);
}
/* imp: mp4 container or some advanced container file required header information*/
value = avformat_write_header(outAVFormatContext , &options);
if(value < 0)
{
cout<<"\nerror in writing the header context";
exit(1);
}
/*
// uncomment here to view the complete video file informations
cout<<"\n\nOutput file information :\n\n";
av_dump_format(outAVFormatContext , 0 ,output_file ,1);
*/
}
int Recorder::stop() {
threading = false;
demux->join();
rescale->join();
mux->join();
return 0;
}
int Recorder::start() {
initVideoThreads();
return 0;
}
int Recorder::initVideoThreads() {
demux = new thread(&Recorder::demuxVideoStream, this, pAVCodecContext, pAVFormatContext, VideoStreamIndx);
rescale = new thread(&Recorder::rescaleVideoStream, this, pAVCodecContext, outAVCodecContext);
demux = new thread(&Recorder::encodeVideoStream, this, outAVCodecContext);
return 0;
}
void Recorder::demuxVideoStream(AVCodecContext* codecContext, AVFormatContext* formatContext, int streamIndex)
{
// init packet
AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));
av_init_packet(packet);
int ctr = 0;
while (threading)
{
if (av_read_frame(formatContext, packet) < 0) {
exit(1);
}
if (packet->stream_index == streamIndex)
{
int return_value; // = 0;
ctr++;
do
{
return_value = avcodec_send_packet(codecContext, packet);
} while (return_value == AVERROR(EAGAIN) && threading);
//int i = avcodec_send_packet(codecContext, packet);
if (return_value < 0 && threading) { // call Decoder
cout << "unable to decode video";
exit(1);
}
}
}
avcodec_send_packet(codecContext, NULL); // flush decoder
// return 0;
}
void Recorder::rescaleVideoStream(AVCodecContext* inCodecContext, AVCodecContext* outCodecContext)
{
bool closing = false;
AVFrame* inFrame = av_frame_alloc();
if (!inFrame)
{
cout << "\nunable to release the avframe resources";
exit(1);
}
int nbytes = av_image_get_buffer_size(outAVCodecContext->pix_fmt, outAVCodecContext->width, outAVCodecContext->height, 32);
uint8_t* video_outbuf = (uint8_t*)av_malloc(nbytes);
if (video_outbuf == NULL)
{
cout << "\nunable to allocate memory";
exit(1);
}
AVFrame* outFrame = av_frame_alloc();//Allocate an AVFrame and set its fields to default values.
if (!outFrame)
{
cout << "\nunable to release the avframe resources for outframe";
exit(1);
}
// Setup the data pointers and linesizes based on the specified image parameters and the provided array.
int value = av_image_fill_arrays(outFrame->data, outFrame->linesize, video_outbuf, AV_PIX_FMT_YUV420P, outAVCodecContext->width, outAVCodecContext->height, 1); // returns : the size in bytes required for src
if (value < 0)
{
cout << "\nerror in filling image array";
}
int ctr = 0;
while (threading || !closing) {
int value = avcodec_receive_frame(inCodecContext, inFrame);
if (value == 0) {
ctr++;
SwsContext* swsCtx_ = sws_getContext(inCodecContext->width,
inCodecContext->height,
inCodecContext->pix_fmt,
outAVCodecContext->width,
outAVCodecContext->height,
outAVCodecContext->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(swsCtx_, inFrame->data, inFrame->linesize, 0, inCodecContext->height, outFrame->data, outFrame->linesize);
int return_value;
do
{
return_value = avcodec_send_frame(outCodecContext, outFrame);
} while (return_value == AVERROR(EAGAIN) && threading);
}
closing = (value == AVERROR_EOF);
}
avcodec_send_frame(outCodecContext, NULL);
// av_free(video_outbuf);
// return 0;
}
void Recorder::encodeVideoStream(AVCodecContext* codecContext)
{
bool closing = true;
AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));
av_init_packet(packet);
int ctr = 0;
while (threading || !closing) {
packet->data = NULL; // packet data will be allocated by the encoder
packet->size = 0;
ctr++;
int value = avcodec_receive_packet(codecContext, packet);
if (value == 0) {
if (packet->pts != AV_NOPTS_VALUE)
packet->pts = av_rescale_q(packet->pts, video_st->codec->time_base, video_st->time_base);
if (packet->dts != AV_NOPTS_VALUE)
packet->dts = av_rescale_q(packet->dts, video_st->codec->time_base, video_st->time_base);
//printf("Write frame %3d (size= %2d)\n", j++, packet->size / 1000);
if (av_write_frame(outAVFormatContext, packet) != 0)
{
cout << "\nerror in writing video frame";
}
}
closing = (value == AVERROR_EOF);
}
value = av_write_trailer(outAVFormatContext);
if (value < 0)
{
cout << "\nerror in writing av trailer";
exit(1);
}
// av_free(packet);
// return 0;
}
int Recorder::openScreen(AVFormatContext* pFormatCtx) {
/*
X11 video input device.
To enable this input device during configuration you need libxcb installed on your system. It will be automatically detected during configuration.
This device allows one to capture a region of an X11 display.
refer : https://www.ffmpeg.org/ffmpeg-devices.html#x11grab
*/
/* current below is for screen recording. to connect with camera use v4l2 as a input parameter for av_find_input_format */
pAVInputFormat = av_find_input_format("gdigrab");
//value = avformat_open_input(&pAVFormatContext, ":0.0+10,250", pAVInputFormat, NULL);
value = avformat_open_input(&pAVFormatContext, "desktop", pAVInputFormat, NULL);
if (value != 0)
{
cout << "\nerror in opening input device";
exit(1);
}
return 0;
} -
Error : Output format mp4 is not available
12 avril 2024, par alpaca pwaaI'm using fluent-ffmpeg in my nextjs application, I'm trying to process the video and specified a format to stream on my s3 bucket but it keeps on failing. My terminal keeps on throwing "Error : Error : Output format mp4 is not available". I already verify my ffmpeg format "ffmpeg -format" and confirm that it supports encoding and decoding mp4 files. I've already tried solutions from other forums but it's not working for me.


createVideo: privateProcedure
 .input(
 z.object({
 fileId: z.string(),
 })
 )
 .mutation(async ({ ctx, input }) => {
 const { getUser } = getKindeServerSession();
 const user = await getUser();

 if (!user || !user.id || !user.email) {
 throw new TRPCError({ code: "UNAUTHORIZED" });
 }

 const dbUser = await db.user.findFirst({
 where: {
 id: user.id,
 },
 });

 if (!dbUser) {
 throw new TRPCError({
 code: "UNAUTHORIZED",
 message: "User not found in the database.",
 });
 }

 const putObjectCommand = new PutObjectCommand({
 Bucket: process.env.AWS_BUCKET_NAME!,
 Key: generateFileName(),
 });

 const s3 = new S3Client({
 region: process.env.AWS_BUCKET_REGION!,
 credentials: {
 accessKeyId: process.env.AWS_ACCESS_KEY!,
 secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
 },
 });

 const singedURL = await getSignedUrl(s3, putObjectCommand, {
 expiresIn: 60,
 });

 const ffmpeg = require("fluent-ffmpeg");
 const passthroughStream = new PassThrough();

 ffmpeg({ source: "./template1.mp4" })
 .on("end", async () => {
 console.log("Job done");
 await uploadToS3(passthroughStream);
 })
 .on("error", (error: string) => {
 console.error("Error:", error);
 throw new Error("Error processing video");
 })
 .videoFilter({
 filter: "drawtext",
 options: {
 text: "hi",
 fontsize: 24,
 fontcolor: "white",
 x: "(w-text_w)/2",
 y: "(h-text_h)/2",
 box: 1,
 boxcolor: "black@0.5",
 boxborderw: 5,
 fontfile: "/Windows/fonts/calibri.ttf",
 },
 })
 .videoCodec("libx264")
 .outputFormat("mp4")
 .outputOptions(["-movflags frag_keyframe+empty_moov"])
 .pipe(passthroughStream, { end: true });

 const uploadToS3 = async (stream: PassThrough) => {
 const upload = new Upload({
 client: s3,
 params: {
 Bucket: process.env.AWS_BUCKET_NAME!,
 Key: generateFileName(),
 Body: stream,
 },
 });
 await upload.done();
 };

 await new Promise((resolve, reject) => {
 passthroughStream.on("end", resolve);
 passthroughStream.on("error", reject);
 });

 const createdVideo = await db.video.create({
 data: {
 name: "Test Name",
 url: singedURL.split("?")[0],
 key: singedURL,
 fileId: input.fileId,
 },
 });

 return createdVideo;
 }),



Here's the ffmpeg log.


ffmpeg started on 2024-04-11 at 20:58:56
Report written to "ffmpeg-20240411-205856.log"
Log level: 48
Command line:
"C:\\ProgramData\\chocolatey\\lib\\ffmpeg-full\\tools\\ffmpeg\\bin\\ffmpeg.exe" -i ./template1.mp4 -filter:v "drawtext=text=hi:fontsize=24:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:box=1:boxcolor=black@0.5:boxborderw=5:fontfile=/Windows/fonts/calibri.ttf" -report pipe:1
ffmpeg version 7.0-full_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers
 built with gcc 13.2.0 (Rev5, Built by MSYS2 project)
 configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libaribb24 --enable-libaribcaption --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libxevd --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxeve --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-dxva2 --enable-d3d11va --enable-d3d12va --enable-f libavutil 59. 8.100 / 59. 8.100
 libavcodec 61. 3.100 / 61. 3.100
 libavformat 61. 1.100 / 61. 1.100
 libavdevice 61. 1.100 / 61. 1.100
 libavfilter 10. 1.100 / 10. 1.100
 libswscale 8. 1.100 / 8. 1.100
 libswresample 5. 1.100 / 5. 1.100
 libpostproc 58. 1.100 / 58. 1.100
Splitting the commandline.
Reading option '-i' ... matched as input url with argument './template1.mp4'.
Reading option '-filter:v' ... matched as option 'filter' (apply specified filters to audio/video) with argument 'drawtext=text=hi:fontsize=24:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:box=1:boxcolor=black@0.5:boxborderw=5:fontfile=/Windows/fonts/calibri.ttf'.
Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'.
Reading option 'pipe:1' ... matched as output url.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option report (generate a report) with argument 1.
Successfully parsed a group of options.
Parsing a group of options: input url ./template1.mp4.
Successfully parsed a group of options.
Opening an input file: ./template1.mp4.
[AVFormatContext @ 00000262cd0888c0] Opening './template1.mp4' for reading
[file @ 00000262cd0a94c0] Setting default whitelist 'file,crypto,data'
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] ISO: File Type Major Brand: isom
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] Processing st: 0, edit list 0 - media time: 1024, duration: 126981
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] Offset DTS by 1024 to make first pts zero.
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] Setting codecpar->delay to 2 for stream st: 0
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] Before avformat_find_stream_info() pos: 6965 bytes read:32768 seeks:0 nb_streams:1
[h264 @ 00000262cd0bb140] nal_unit_type: 7(SPS), nal_ref_idc: 3
[h264 @ 00000262cd0bb140] Decoding VUI
[h264 @ 00000262cd0bb140] nal_unit_type: 8(PPS), nal_ref_idc: 3
[h264 @ 00000262cd0bb140] nal_unit_type: 7(SPS), nal_ref_idc: 3
[h264 @ 00000262cd0bb140] Decoding VUI
[h264 @ 00000262cd0bb140] nal_unit_type: 8(PPS), nal_ref_idc: 3
[h264 @ 00000262cd0bb140] Decoding VUI
[h264 @ 00000262cd0bb140] nal_unit_type: 6(SEI), nal_ref_idc: 0
[h264 @ 00000262cd0bb140] nal_unit_type: 7(SPS), nal_ref_idc: 3
[h264 @ 00000262cd0bb140] nal_unit_type: 8(PPS), nal_ref_idc: 3
[h264 @ 00000262cd0bb140] nal_unit_type: 5(IDR), nal_ref_idc: 3
[h264 @ 00000262cd0bb140] Decoding VUI
[h264 @ 00000262cd0bb140] Format yuv420p chosen by get_format().
[h264 @ 00000262cd0bb140] Reinit context to 1088x1920, pix_fmt: yuv420p
[h264 @ 00000262cd0bb140] no picture 
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] All info found
[mov,mp4,m4a,3gp,3g2,mj2 @ 00000262cd0888c0] After avformat_find_stream_info() pos: 82242 bytes read:82242 seeks:0 frames:1
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './template1.mp4':
 Metadata:
 major_brand : isom
 minor_version : 512
 compatible_brands: isomiso2avc1mp41
 encoder : Lavf58.76.100
 Duration: 00:00:08.27, start: 0.000000, bitrate: 3720 kb/s
 Stream #0:0[0x1](und), 1, 1/15360: Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920, 3714 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
 Metadata:
 handler_name : VideoHandler
 vendor_id : [0][0][0][0]
Successfully opened the file.
Parsing a group of options: output url pipe:1.
Applying option filter:v (apply specified filters to audio/video) with argument drawtext=text=hi:fontsize=24:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:box=1:boxcolor=black@0.5:boxborderw=5:fontfile=/Windows/fonts/calibri.ttf.
Successfully parsed a group of options.
Opening an output file: pipe:1.
[AVFormatContext @ 00000262cd0b2240] Unable to choose an output format for 'pipe:1'; use a standard extension for the filename or specify the format manually.
[out#0 @ 00000262cd0bb300] Error initializing the muxer for pipe:1: Invalid argument
Error opening output file pipe:1.
Error opening output files: Invalid argument
[AVIOContext @ 00000262cd0a9580] Statistics: 82242 bytes read, 0 seeks



I should be able to stream the processed video to my s3, but it keeps on throwing "Error : Error : Output format mp4 is not available"