Recherche avancée

Médias (9)

Mot : - Tags -/soundtrack

Autres articles (38)

  • Initialisation de MediaSPIP (préconfiguration)

    20 février 2010, par

    Lors 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 (...)

  • Submit bugs and patches

    13 avril 2011

    Unfortunately a software is never perfect.
    If you think you have found a bug, report it using our ticket system. Please to help us to fix it by providing the following information : the browser you are using, including the exact version as precise an explanation as possible of the problem if possible, the steps taken resulting in the problem a link to the site / page in question
    If you think you have solved the bug, fill in a ticket and attach to it a corrective patch.
    You may also (...)

  • Keeping control of your media in your hands

    13 avril 2011, par

    The vocabulary used on this site and around MediaSPIP in general, aims to avoid reference to Web 2.0 and the companies that profit from media-sharing.
    While using MediaSPIP, you are invited to avoid using words like "Brand", "Cloud" and "Market".
    MediaSPIP is designed to facilitate the sharing of creative media online, while allowing authors to retain complete control of their work.
    MediaSPIP aims to be accessible to as many people as possible and development is based on expanding the (...)

Sur d’autres sites (8098)

  • Converting a voice recording into an mp3

    21 juillet 2023, par Raphael M

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

    &#xA;

  • Using node-media-server and FFMPEG, Transmuxing ends when rtmp is publishing with no errors

    8 juillet 2023, par Sina KH

    I've configured and used node-media-server library on 2 of my test servers and it works great, but when I'm trying to make it work on production, it creates directories for different qualities, but does not generate .ts and .m3u8 for them. It only creates original hls outputs.&#xA;My logs show that instantly after [rtmp publish] Handle video. and [rtmp publish] Handle audio. files, it receives [rtmp publish] Close stream. id=Y8KK9U3D streamPath=/live/15_1280 streamId=1 and [rtmp play] Close stream. id=7MC9Q65N streamPath=/live/15_1280 streamId=1&#xA;Please note that everything is the same on my test and prod servers, and with no known cause, it fails on some of my servers and works on some other ones. I've tried both deploying dockerized and not dockerized versions, with different node versions.&#xA;FFMPEG version is also the same on all systems.

    &#xA;

    My configs :

    &#xA;

    const config = {&#xA;    rtmp: {&#xA;        port: parseInt(process.env.STREAM_RTMP_PORT || &#x27;8082&#x27;),&#xA;        chunk_size: parseInt(process.env.STREAM_CHUNK_SIZE || &#x27;60000&#x27;),&#xA;        gop_cache: true,&#xA;        ping: 60,&#xA;        ping_timeout: 30&#xA;    },&#xA;    http: {&#xA;        mediaroot: process.env.FILE_PATH &#x2B; &#x27;/media&#x27;,&#xA;        port: parseInt(process.env.STREAM_HTTP_PORT || &#x27;8081&#x27;),&#xA;        allow_origin: &#x27;*&#x27;&#xA;    },&#xA;    auth: process.env.STREAM_SECRET?.length ? {&#xA;        api: true,&#xA;        play: false,&#xA;        publish: true,&#xA;        secret: process.env.STREAM_SECRET,&#xA;        api_user: process.env.STREAM_API_AUTH_USER,&#xA;        api_pass: process.env.STREAM_API_AUTH_PASS,&#xA;    } : undefined,&#xA;    trans: {&#xA;        ffmpeg: process.env.FFMPEG_PATH || &#x27;&#x27;,&#xA;        tasks: [&#xA;            {&#xA;                app: &#x27;live&#x27;,&#xA;&#xA;                hls: true,&#xA;                hlsFlags: &#x27;[hls_time=2:hls_list_size=3:hls_flags=delete_segments]&#x27;,&#xA;                hlsKeep: true, // to prevent hls file delete after end the stream&#xA;&#xA;                // dash: true,&#xA;                // dashFlags: &#x27;[f=dash:window_size=3:extra_window_size=5]&#x27;,&#xA;                // dashKeep: true, // to prevent dash file delete after end the stream&#xA;&#xA;                mp4: true,&#xA;                mp4Flags: &#x27;[movflags=frag_keyframe&#x2B;empty_moov]&#x27;,&#xA;            }&#xA;        ]&#xA;    },&#xA;    fission: {&#xA;        ffmpeg: process.env.FFMPEG_PATH || &#x27;&#x27;,&#xA;        tasks: [&#xA;            {&#xA;                rule: "live/*",&#xA;                model: [&#xA;                    {&#xA;                        ab: "128k",&#xA;                        vb: "1500k",&#xA;                        vs: "720x1280",&#xA;                        vf: "30",&#xA;                    },&#xA;                    {&#xA;                        ab: "64k",&#xA;                        vb: "1000k",&#xA;                        vs: "480x854",&#xA;                        vf: "24",&#xA;                    },&#xA;                    {&#xA;                        ab: "32k",&#xA;                        vb: "600k",&#xA;                        vs: "360x640",&#xA;                        vf: "20",&#xA;                    },&#xA;                ]&#xA;            },&#xA;        ]&#xA;    }&#xA;}&#xA;

    &#xA;

    and logs :

    &#xA;

    [NodeEvent on preConnect] id=OKRRCRT1 args={"app":"live","type":"nonprivate","supportsGoAway":true,"flashVer":"FMLE/3.0 (compatible; FMSc/1.0)","swfUrl":"rtmp://IP_PORT_HERE/live","tcUrl":"rtmp://IP_PORT_HERE/live"}&#xA;7/5/2023 16:13:28 963 [INFO] [rtmp connect] id=OKRRCRT1 ip=MY_IP_HERE app=live args={"app":"live","type":"nonprivate","supportsGoAway":true,"flashVer":"FMLE/3.0 (compatible; FMSc/1.0)","swfUrl":"rtmp://IP_PORT_HERE/live","tcUrl":"rtmp://IP_PORT_HERE/live"}&#xA;[NodeEvent on postConnect] id=OKRRCRT1 args={"app":"live","type":"nonprivate","supportsGoAway":true,"flashVer":"FMLE/3.0 (compatible; FMSc/1.0)","swfUrl":"rtmp://IP_PORT_HERE/live","tcUrl":"rtmp://IP_PORT_HERE/live"}&#xA;[NodeEvent on prePublish] id=OKRRCRT1 StreamPath=/live/15 args={"sign":"CORRECT_SIGN_HERE__REMOVED_TO_SHARE_IT_WITH_YOU"}&#xA;7/5/2023 16:13:28 963 [INFO] [rtmp publish] New stream. id=OKRRCRT1 streamPath=/live/15 streamId=1&#xA;[NodeEvent on postPublish] id=OKRRCRT1 StreamPath=/live/15 args={"sign":"CORRECT_SIGN_HERE__REMOVED_TO_SHARE_IT_WITH_YOU"}&#xA;7/5/2023 16:13:28 963 [INFO] [Transmuxing MP4] /live/15 to /home/data/stream_files/media/live/15/2023-07-05-16-13-28.mp4&#xA;7/5/2023 16:13:28 963 [INFO] [Transmuxing HLS] /live/15 to /home/data/stream_files/media/live/15/index.m3u8&#xA;[NodeEvent on preConnect] id=CPRQV6U6 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:28 963 [INFO] [rtmp connect] id=CPRQV6U6 ip=::ffff:127.0.0.1 app=live args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on postConnect] id=CPRQV6U6 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on preConnect] id=FTAZ3SW8 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:28 963 [INFO] [rtmp connect] id=FTAZ3SW8 ip=::ffff:127.0.0.1 app=live args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on postConnect] id=FTAZ3SW8 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on prePlay] id=CPRQV6U6 StreamPath=/live/15 args={}&#xA;[NodeEvent on postPlay] id=CPRQV6U6 StreamPath=/live/15 args={}&#xA;7/5/2023 16:13:28 963 [INFO] [rtmp play] Join stream. id=CPRQV6U6 streamPath=/live/15  streamId=1 &#xA;[NodeEvent on prePlay] id=FTAZ3SW8 StreamPath=/live/15 args={}&#xA;[NodeEvent on postPlay] id=FTAZ3SW8 StreamPath=/live/15 args={}&#xA;7/5/2023 16:13:28 963 [INFO] [rtmp play] Join stream. id=FTAZ3SW8 streamPath=/live/15  streamId=1 &#xA;7/5/2023 16:13:29 963 [INFO] [rtmp publish] Handle audio. id=OKRRCRT1 streamPath=/live/15 sound_format=10 sound_type=2 sound_size=1 sound_rate=3 codec_name=AAC 48000 2ch&#xA;7/5/2023 16:13:29 963 [INFO] [rtmp publish] Handle video. id=OKRRCRT1 streamPath=/live/15 frame_type=1 codec_id=7 codec_name=H264 1920x1080&#xA;[NodeEvent on preConnect] id=ISVLTK71 args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;7/5/2023 16:13:30 963 [INFO] [rtmp connect] id=ISVLTK71 ip=::ffff:127.0.0.1 app=live args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;[NodeEvent on postConnect] id=ISVLTK71 args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;[NodeEvent on prePublish] id=ISVLTK71 StreamPath=/live/15_1280 args={}&#xA;7/5/2023 16:13:30 963 [INFO] [rtmp publish] New stream. id=ISVLTK71 streamPath=/live/15_1280 streamId=1&#xA;[NodeEvent on postPublish] id=ISVLTK71 StreamPath=/live/15_1280 args={}&#xA;7/5/2023 16:13:30 963 [INFO] [Transmuxing MP4] /live/15_1280 to /home/data/stream_files/media/live/15_1280/2023-07-05-16-13-30.mp4&#xA;7/5/2023 16:13:30 963 [INFO] [Transmuxing HLS] /live/15_1280 to /home/data/stream_files/media/live/15_1280/index.m3u8&#xA;[NodeEvent on preConnect] id=YNOFQB7P args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp connect] id=YNOFQB7P ip=::ffff:127.0.0.1 app=live args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;[NodeEvent on postConnect] id=YNOFQB7P args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;[NodeEvent on preConnect] id=OT8T2OPP args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp connect] id=OT8T2OPP ip=::ffff:127.0.0.1 app=live args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on postConnect] id=OT8T2OPP args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on prePublish] id=YNOFQB7P StreamPath=/live/15_854 args={}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp publish] New stream. id=YNOFQB7P streamPath=/live/15_854 streamId=1&#xA;[NodeEvent on postPublish] id=YNOFQB7P StreamPath=/live/15_854 args={}&#xA;7/5/2023 16:13:31 963 [INFO] [Transmuxing MP4] /live/15_854 to /home/data/stream_files/media/live/15_854/2023-07-05-16-13-31.mp4&#xA;7/5/2023 16:13:31 963 [INFO] [Transmuxing HLS] /live/15_854 to /home/data/stream_files/media/live/15_854/index.m3u8&#xA;[NodeEvent on prePlay] id=OT8T2OPP StreamPath=/live/15_1280 args={}&#xA;[NodeEvent on postPlay] id=OT8T2OPP StreamPath=/live/15_1280 args={}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp play] Join stream. id=OT8T2OPP streamPath=/live/15_1280  streamId=1 &#xA;[NodeEvent on preConnect] id=62KCI105 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp connect] id=62KCI105 ip=::ffff:127.0.0.1 app=live args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on postConnect] id=62KCI105 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on preConnect] id=9QAHATOC args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp connect] id=9QAHATOC ip=::ffff:127.0.0.1 app=live args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;[NodeEvent on postConnect] id=9QAHATOC args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;[NodeEvent on prePlay] id=62KCI105 StreamPath=/live/15_854 args={}&#xA;[NodeEvent on postPlay] id=62KCI105 StreamPath=/live/15_854 args={}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp play] Join stream. id=62KCI105 streamPath=/live/15_854  streamId=1 &#xA;[NodeEvent on prePublish] id=9QAHATOC StreamPath=/live/15_640 args={}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp publish] New stream. id=9QAHATOC streamPath=/live/15_640 streamId=1&#xA;[NodeEvent on postPublish] id=9QAHATOC StreamPath=/live/15_640 args={}&#xA;7/5/2023 16:13:31 963 [INFO] [Transmuxing MP4] /live/15_640 to /home/data/stream_files/media/live/15_640/2023-07-05-16-13-31.mp4&#xA;7/5/2023 16:13:31 963 [INFO] [Transmuxing HLS] /live/15_640 to /home/data/stream_files/media/live/15_640/index.m3u8&#xA;[NodeEvent on preConnect] id=V308RJRW args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp connect] id=V308RJRW ip=::ffff:127.0.0.1 app=live args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on postConnect] id=V308RJRW args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on prePlay] id=V308RJRW StreamPath=/live/15_640 args={}&#xA;[NodeEvent on postPlay] id=V308RJRW StreamPath=/live/15_640 args={}&#xA;7/5/2023 16:13:31 963 [INFO] [rtmp play] Join stream. id=V308RJRW streamPath=/live/15_640  streamId=1 &#xA;7/5/2023 16:13:32 963 [INFO] [rtmp publish] Handle video. id=ISVLTK71 streamPath=/live/15_1280 frame_type=1 codec_id=7 codec_name=H264 720x1280&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp publish] Handle audio. id=ISVLTK71 streamPath=/live/15_1280 sound_format=10 sound_type=2 sound_size=1 sound_rate=3 codec_name=AAC 48000 2ch&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp publish] Close stream. id=ISVLTK71 streamPath=/live/15_1280 streamId=1&#xA;[NodeEvent on donePublish] id=ISVLTK71 StreamPath=/live/15_1280 args={}&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp play] Close stream. id=OT8T2OPP streamPath=/live/15_1280 streamId=1&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp disconnect] id=OT8T2OPP&#xA;[NodeEvent on doneConnect] id=OT8T2OPP args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp publish] Handle video. id=YNOFQB7P streamPath=/live/15_854 frame_type=1 codec_id=7 codec_name=H264 480x854&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp publish] Handle audio. id=YNOFQB7P streamPath=/live/15_854 sound_format=10 sound_type=2 sound_size=1 sound_rate=3 codec_name=AAC 48000 2ch&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp publish] Close stream. id=YNOFQB7P streamPath=/live/15_854 streamId=1&#xA;[NodeEvent on donePublish] id=YNOFQB7P StreamPath=/live/15_854 args={}&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp play] Close stream. id=62KCI105 streamPath=/live/15_854 streamId=1&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp disconnect] id=62KCI105&#xA;[NodeEvent on doneConnect] id=62KCI105 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp publish] Close stream. id=9QAHATOC streamPath=/live/15_640 streamId=1&#xA;[NodeEvent on donePublish] id=9QAHATOC StreamPath=/live/15_640 args={}&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp play] Close stream. id=V308RJRW streamPath=/live/15_640 streamId=1&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp disconnect] id=V308RJRW&#xA;[NodeEvent on doneConnect] id=V308RJRW args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;[NodeEvent on donePlay] id=CPRQV6U6 StreamPath=/live/15 args={}&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp play] Close stream. id=CPRQV6U6 streamPath=/live/15 streamId=1&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp disconnect] id=CPRQV6U6&#xA;[NodeEvent on doneConnect] id=CPRQV6U6 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:32 963 [INFO] [Transmuxing end] /live/15_1280&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp disconnect] id=ISVLTK71&#xA;[NodeEvent on doneConnect] id=ISVLTK71 args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;7/5/2023 16:13:32 963 [INFO] [Transmuxing end] /live/15_640&#xA;7/5/2023 16:13:32 963 [INFO] [Transmuxing end] /live/15_854&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp disconnect] id=9QAHATOC&#xA;[NodeEvent on doneConnect] id=9QAHATOC args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;7/5/2023 16:13:32 963 [INFO] [rtmp disconnect] id=YNOFQB7P&#xA;[NodeEvent on doneConnect] id=YNOFQB7P args={"app":"live","type":"nonprivate","flashVer":"FMLE/3.0 (compatible; Lavf59.27.100)","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live"}&#xA;7/5/2023 16:13:32 963 [INFO] [Fission end] /live/15&#xA;7/5/2023 16:13:46 963 [INFO] [rtmp publish] Close stream. id=OKRRCRT1 streamPath=/live/15 streamId=1&#xA;[NodeEvent on donePublish] id=OKRRCRT1 StreamPath=/live/15 args={"sign":"CORRECT_SIGN_HERE__REMOVED_TO_SHARE_IT_WITH_YOU"}&#xA;7/5/2023 16:13:46 963 [INFO] [rtmp disconnect] id=OKRRCRT1&#xA;[NodeEvent on doneConnect] id=OKRRCRT1 args={"app":"live","type":"nonprivate","supportsGoAway":true,"flashVer":"FMLE/3.0 (compatible; FMSc/1.0)","swfUrl":"rtmp://IP_PORT_HERE/live","tcUrl":"rtmp://IP_PORT_HERE/live"}&#xA;7/5/2023 16:13:46 963 [INFO] [rtmp play] Close stream. id=FTAZ3SW8 streamPath=/live/15 streamId=1&#xA;7/5/2023 16:13:46 963 [INFO] [rtmp disconnect] id=FTAZ3SW8&#xA;[NodeEvent on doneConnect] id=FTAZ3SW8 args={"app":"live","flashVer":"LNX 9,0,124,2","tcUrl":"rtmp://127.0.0.1:PORT_HERE/live","fpad":false,"capabilities":15,"audioCodecs":4071,"videoCodecs":252,"videoFunction":1}&#xA;7/5/2023 16:13:46 963 [INFO] [Transmuxing end] /live/15&#xA;

    &#xA;

  • Video encoding task not working with Django Celery Redis FFMPEG and GraphQL

    18 juin 2023, par phanio

    I'm having a hard time trying to understand how is this FFMPEG encoding works while using Django, Celery, Redis, GraphQL and Docker too.

    &#xA;

    I have this video / courses platform project and want I'm trying to do using FFMPEG, Celery and Redis is to create different video resolutions so I can display them the way Youtube does inside the videoplayer ( the videoplayer is handled in frontend by Nextjs and Apollo Client ), now on the backend I've just learned that in order to use properly the FFMPEG to resize the oridinal video size, I need to use Celery and Redis to perform asyncronus tasks. I've found a few older posts here on stackoverflow and google, but is not quite enough info for someone who is using the ffmpeg and clery and redis for the first time ( I've started already step by step and created that example that adds two numbers together with celery, that works well ). Now I'm not sure what is wrong with my code, because first of all I'm not really sure where should I trigger the task from, I mean from which file, because at the end of the task I want to send the data through api using GrapQL Strawberry.

    &#xA;

    This is what I've tried by now :

    &#xA;

    So first things first my project structure looks like this

    &#xA;

    - backend #root directory&#xA; --- backend&#xA;    -- __init__.py&#xA;    -- celery.py&#xA;    -- settings.py&#xA;    -- urls.py&#xA;      etc..&#xA;&#xA; --- static&#xA;   -- videos&#xA;&#xA; --- video&#xA;   -- models.py&#xA;   -- schema.py&#xA;   -- tasks.py&#xA;   -- types.py&#xA;   etc..&#xA;&#xA; --- .env&#xA;&#xA; --- db.sqlite3&#xA;&#xA; --- docker-compose.yml&#xA;&#xA; --- Dockerfile&#xA;&#xA; --- manage.py&#xA;&#xA; --- requirements.txt&#xA;

    &#xA;

    here is my settings.py file :

    &#xA;

    from pathlib import Path&#xA;import os&#xA;&#xA;# Build paths inside the project like this: BASE_DIR / &#x27;subdir&#x27;.&#xA;BASE_DIR = Path(__file__).resolve().parent.parent&#xA;&#xA;DEBUG = True&#xA;&#xA;ALLOWED_HOSTS=["localhost", "0.0.0.0", "127.0.0.1"]&#xA;&#xA;DEFAULT_AUTO_FIELD = &#x27;django.db.models.BigAutoField&#x27;&#xA;&#xA;&#xA;# Application definition&#xA;&#xA;INSTALLED_APPS = [&#xA;    "corsheaders",&#xA;    &#x27;django.contrib.admin&#x27;,&#xA;    &#x27;django.contrib.auth&#x27;,&#xA;    &#x27;django.contrib.contenttypes&#x27;,&#xA;    &#x27;django.contrib.sessions&#x27;,&#xA;    &#x27;django.contrib.messages&#x27;,&#xA;    &#x27;django.contrib.staticfiles&#x27;,&#xA;&#xA;    "strawberry.django",&#xA;    "video"&#xA;]&#xA;&#xA;etc...&#xA;&#xA;STATIC_URL = &#x27;/static/&#x27;&#xA;MEDIA_URL = &#x27;/videos/&#x27;&#xA;&#xA;STATICFILES_DIRS = [&#xA;    BASE_DIR / &#x27;static&#x27;,&#xA;    # BASE_DIR / &#x27;frontend/build/static&#x27;,&#xA;]&#xA;&#xA;MEDIA_ROOT = BASE_DIR / &#x27;static/videos&#x27;&#xA;&#xA;STATIC_ROOT = BASE_DIR / &#x27;staticfiles&#x27;&#xA;&#xA;STATICFILES_STORAGE = &#x27;whitenoise.storage.CompressedManifestStaticFilesStorage&#x27;&#xA;&#xA;CORS_ALLOW_ALL_ORIGINS = True&#xA;&#xA;&#xA;CELERY_BEAT_SCHEDULER = &#x27;django_celery_beat.schedulers:DatabaseScheduler&#x27;&#xA;&#xA;# REDIS CACHE&#xA;CACHES = {&#xA;    "default": {&#xA;        "BACKEND": "django_redis.cache.RedisCache",&#xA;        "LOCATION": f"redis://127.0.0.1:6379/1",&#xA;        "OPTIONS": {&#xA;            "CLIENT_CLASS": "django_redis.client.DefaultClient",&#xA;        },&#xA;    }&#xA;}&#xA;&#xA;# Docker&#xA;CELERY_BROKER_URL = os.environ.get("CELERY_BROKER", "redis://redis:6379/0")&#xA;CELERY_RESULT_BACKEND = os.environ.get("CELERY_BROKER", "redis://redis:6379/0")&#xA;

    &#xA;

    This is my main urls.py file :

    &#xA;

    from django.contrib import admin&#xA;from django.conf import settings&#xA;from django.conf.urls.static import static&#xA;from django.urls import path&#xA;from django.urls.conf import include&#xA;from strawberry.django.views import GraphQLView&#xA;&#xA;from video.schema import schema&#xA;&#xA;urlpatterns = [&#xA;    path(&#x27;admin/&#x27;, admin.site.urls),&#xA;    path("graphql", GraphQLView.as_view(schema=schema)),&#xA;]&#xA;&#xA;if settings.DEBUG:&#xA;    urlpatterns &#x2B;= static(settings.MEDIA_URL,&#xA;                          document_root=settings.MEDIA_ROOT)&#xA;    urlpatterns &#x2B;= static(settings.STATIC_URL,&#xA;                          document_root=settings.STATIC_ROOT)&#xA;

    &#xA;

    This is my celery.py file :

    &#xA;

    from __future__ import absolute_import, unicode_literals&#xA;import os&#xA;from celery import Celery&#xA;from django.conf import settings&#xA;&#xA;os.environ.setdefault(&#x27;DJANGO_SETTINGS_MODULE&#x27;, &#x27;backend.settings&#x27;)&#xA;&#xA;backend = Celery(&#x27;backend&#x27;)&#xA;&#xA;backend.config_from_object(&#x27;django.conf:settings&#x27;, namespace="CELERY")&#xA;&#xA;backend.autodiscover_tasks()&#xA;&#xA;@backend.task(bind=True)&#xA;def debug_task(self):&#xA;    print(&#x27;Request: {0!r}&#x27;.format(self.request))&#xA;

    &#xA;

    This is my init.py file :

    &#xA;

    from .celery import backend as celery_backend&#xA;&#xA;__all__ = (&#x27;celery_backend&#x27;,)&#xA;

    &#xA;

    This is my Dockerfile :

    &#xA;

    FROM python:3&#xA;ENV PYTHONUNBUFFERED=1&#xA;&#xA;WORKDIR /usr/src/backend&#xA;&#xA;RUN apt-get -y update&#xA;RUN apt-get -y upgrade&#xA;RUN apt-get install -y ffmpeg&#xA;&#xA;COPY requirements.txt ./&#xA;RUN pip install -r requirements.txt&#xA;

    &#xA;

    This is my docker-compose.yml file :

    &#xA;

    version: "3.8"&#xA;&#xA;services:&#xA;  django:&#xA;    build: .&#xA;    container_name: django&#xA;    command: python manage.py runserver 0.0.0.0:8000&#xA;    volumes:&#xA;      - .:/usr/src/backend/&#xA;    ports:&#xA;      - "8000:8000"&#xA;    environment:&#xA;      - DEBUG=1&#xA;      - DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]&#xA;      - CELERY_BROKER=redis://redis:6379/0&#xA;      - CELERY_BACKEND=redis://redis:6379/0&#xA;    depends_on:&#xA;      - pgdb&#xA;      - redis&#xA;&#xA;  celery:&#xA;    build: .&#xA;    command: celery -A backend worker -l INFO&#xA;    volumes:&#xA;      - .:/usr/src/backend&#xA;    depends_on:&#xA;      - django&#xA;      - redis&#xA;&#xA;  pgdb:&#xA;    image: postgres&#xA;    container_name: pgdb&#xA;    environment:&#xA;      - POSTGRES_DB=postgres&#xA;      - POSTGRES_USER=postgres&#xA;      - POSTGRES_PASSWORD=postgres&#xA;    volumes:&#xA;      - pgdata:/var/lib/postgresql/data/&#xA;&#xA;  redis:&#xA;    image: "redis:alpine"&#xA;&#xA;volumes:&#xA;  pgdata:&#xA;

    &#xA;

    And now inside my video app folder :

    &#xA;

    My models.py file :

    &#xA;

      &#xA;
    • here I've created separated fields for all resolution sizes, from video_file_2k to video_file_144, I was thinking that maybe after the process of the encoding this will populate those fields..
    • &#xA;

    &#xA;

    from django.db import models&#xA;from django.urls import reverse&#xA;&#xA;&#xA;class Video(models.Model):&#xA;    video_id = models.AutoField(primary_key=True, editable=False)&#xA;    slug = models.SlugField(max_length=255)&#xA;    title = models.CharField(max_length=150, blank=True, null=True)&#xA;    description = models.TextField(blank=True, null=True)&#xA;    video_file = models.FileField(null=False, blank=False)&#xA;    video_file_2k = models.FileField(null=True, blank=True)&#xA;    video_file_fullhd = models.FileField(null=True, blank=True)&#xA;    video_file_hd = models.FileField(null=True, blank=True)&#xA;    video_file_480 = models.FileField(null=True, blank=True)&#xA;    video_file_360 = models.FileField(null=True, blank=True)&#xA;    video_file_240 = models.FileField(null=True, blank=True)&#xA;    video_file_144 = models.FileField(null=True, blank=True)&#xA;    category = models.CharField(max_length=64, blank=False, null=False)&#xA;    created_at = models.DateTimeField(&#xA;        ("Created at"), auto_now_add=True, editable=False)&#xA;    updated_at = models.DateTimeField(("Updated at"), auto_now=True)&#xA;&#xA;    class Meta:&#xA;        ordering = ("-created_at",)&#xA;        verbose_name = ("Video")&#xA;        verbose_name_plural = ("Videos")&#xA;&#xA;    def get_absolute_url(self):&#xA;        return reverse("store:video_detail", args=[self.slug])&#xA;&#xA;    def __str__(self):&#xA;        return self.title&#xA;

    &#xA;

    This is my schema.py file :

    &#xA;

    import strawberry&#xA;from strawberry.file_uploads import Upload&#xA;from typing import List&#xA;from .types import VideoType&#xA;from .models import Video&#xA;from .tasks import task_video_encoding_1080p, task_video_encoding_720p&#xA;&#xA;&#xA;@strawberry.type&#xA;class Query:&#xA;    @strawberry.field&#xA;    def videos(self, category: str = None) -> List[VideoType]:&#xA;        if category:&#xA;            videos = Video.objects.filter(category=category)&#xA;            return videos&#xA;        return Video.objects.all()&#xA;&#xA;    @strawberry.field&#xA;    def video(self, slug: str) -> VideoType:&#xA;        if slug == slug:&#xA;            video = Video.objects.get(slug=slug)&#xA;            return video&#xA;&#xA;    @strawberry.field&#xA;    def video_by_id(self, video_id: int) -> VideoType:&#xA;        if video_id == video_id:&#xA;            video = Video.objects.get(pk=video_id)&#xA;&#xA;          # Here I&#x27;ve tried to trigger my tasks, when I visited 0.0.0.0:8000/graphql url&#xA;          # and I was querying for a video by it&#x27;s id , then I&#x27;ve got the error from celery &#xA;            task_video_encoding_1080p.delay(video_id)&#xA;            task_video_encoding_720p.delay(video_id)&#xA;&#xA;            return video&#xA;&#xA;&#xA;@strawberry.type&#xA;class Mutation:&#xA;    @strawberry.field&#xA;    def create_video(self, slug: str, title: str, description: str, video_file: Upload, video_file_2k: str, video_file_fullhd: str, video_file_hd: str, video_file_480: str, video_file_360: str, video_file_240: str, video_file_144: str, category: str) -> VideoType:&#xA;&#xA;        video = Video(slug=slug, title=title, description=description,&#xA;                      video_file=video_file, video_file_2k=video_file_2k, video_file_fullhd=video_file_fullhd, video_file_hd=video_file_hd, video_file_480=video_file_480, video_file_360=video_file_360, video_file_240=video_file_240, video_file_144=video_file_144,category=category)&#xA;        &#xA;        video.save()&#xA;        return video&#xA;&#xA;    @strawberry.field&#xA;    def update_video(self, video_id: int, slug: str, title: str, description: str, video_file: str, category: str) -> VideoType:&#xA;        video = Video.objects.get(video_id=video_id)&#xA;        video.slug = slug&#xA;        video.title = title&#xA;        video.description = description&#xA;        video.video_file = video_file&#xA;        video.category = category&#xA;        video.save()&#xA;        return video&#xA;&#xA;    @strawberry.field&#xA;    def delete_video(self, video_id: int) -> bool:&#xA;        video = Video.objects.get(video_id=video_id)&#xA;        video.delete&#xA;        return True&#xA;&#xA;&#xA;schema = strawberry.Schema(query=Query, mutation=Mutation)&#xA;

    &#xA;

    This is my types.py file ( strawberry graphql related ) :

    &#xA;

    import strawberry&#xA;&#xA;from .models import Video&#xA;&#xA;&#xA;@strawberry.django.type(Video)&#xA;class VideoType:&#xA;    video_id: int&#xA;    slug: str&#xA;    title: str&#xA;    description: str&#xA;    video_file: str&#xA;    video_file_2k: str&#xA;    video_file_fullhd: str&#xA;    video_file_hd: str&#xA;    video_file_480: str&#xA;    video_file_360: str&#xA;    video_file_240: str&#xA;    video_file_144: str&#xA;    category: str&#xA;

    &#xA;

    And this is my tasks.py file :

    &#xA;

    from __future__ import absolute_import, unicode_literals&#xA;import os, subprocess&#xA;from django.conf import settings&#xA;from django.core.exceptions import ValidationError&#xA;from celery import shared_task&#xA;from celery.utils.log import get_task_logger&#xA;from .models import Video&#xA;FFMPEG_PATH = os.environ["IMAGEIO_FFMPEG_EXE"] = "/opt/homebrew/Cellar/ffmpeg/6.0/bin/ffmpeg"&#xA;&#xA;logger = get_task_logger(__name__)&#xA;&#xA;&#xA;# CELERY TASKS&#xA;@shared_task&#xA;def add(x,y):&#xA;    return x &#x2B; y&#xA;&#xA;&#xA;@shared_task&#xA;def task_video_encoding_720p(video_id):&#xA;    logger.info(&#x27;Video Processing started&#x27;)&#xA;    try:&#xA;        video = Video.objects.get(video_id=video_id)&#xA;        input_file_path = video.video_file.path&#xA;        input_file_url = video.video_file.url&#xA;        input_file_name = video.video_file.name&#xA;&#xA;        # get the filename (without extension)&#xA;        filename = os.path.basename(input_file_url)&#xA;&#xA;        # path to the new file, change it according to where you want to put it&#xA;        output_file_name = os.path.join(&#x27;videos&#x27;, &#x27;mp4&#x27;, &#x27;{}.mp4&#x27;.format(filename))&#xA;        output_file_path = os.path.join(settings.MEDIA_ROOT, output_file_name)&#xA;&#xA;        # 2-pass encoding&#xA;        for i in range(1):&#xA;           new_video_720p = subprocess.call([FFMPEG_PATH, &#x27;-i&#x27;, input_file_path, &#x27;-s&#x27;, &#x27;1280x720&#x27;, &#x27;-vcodec&#x27;, &#x27;mpeg4&#x27;, &#x27;-acodec&#x27;, &#x27;libvo_aacenc&#x27;, &#x27;-b&#x27;, &#x27;10000k&#x27;, &#x27;-pass&#x27;, i, &#x27;-r&#x27;, &#x27;30&#x27;, output_file_path])&#xA;        #    new_video_720p = subprocess.call([FFMPEG_PATH, &#x27;-i&#x27;, input_file_path, &#x27;-s&#x27;, &#x27;{}x{}&#x27;.format(height * 16/9, height), &#x27;-vcodec&#x27;, &#x27;mpeg4&#x27;, &#x27;-acodec&#x27;, &#x27;libvo_aacenc&#x27;, &#x27;-b&#x27;, &#x27;10000k&#x27;, &#x27;-pass&#x27;, i, &#x27;-r&#x27;, &#x27;30&#x27;, output_file_path])&#xA;&#xA;        if new_video_720p == 0:&#xA;            # save the new file in the database&#xA;            # video.video_file_hd.name = output_file_name&#xA;            video.save(update_fields=[&#x27;video_file_hd&#x27;])&#xA;            logger.info(&#x27;Video Processing Finished&#x27;)&#xA;            return video&#xA;&#xA;        else:&#xA;            logger.info(&#x27;Proceesing Failed.&#x27;) # Just for now&#xA;&#xA;    except:&#xA;        raise ValidationError(&#x27;Something went wrong&#x27;)&#xA;&#xA;&#xA;@shared_task&#xA;# def task_video_encoding_1080p(video_id, height):&#xA;def task_video_encoding_1080p(video_id):&#xA;    logger.info(&#x27;Video Processing started&#x27;)&#xA;    try:&#xA;        video = Video.objects.get(video_id=video_id)&#xA;        input_file_path = video.video_file.url&#xA;        input_file_name = video.video_file.name&#xA;&#xA;        # get the filename (without extension)&#xA;        filename = os.path.basename(input_file_path)&#xA;&#xA;        # path to the new file, change it according to where you want to put it&#xA;        output_file_name = os.path.join(&#x27;videos&#x27;, &#x27;mp4&#x27;, &#x27;{}.mp4&#x27;.format(filename))&#xA;        output_file_path = os.path.join(settings.MEDIA_ROOT, output_file_name)&#xA;&#xA;        for i in range(1):&#xA;            new_video_1080p = subprocess.call([FFMPEG_PATH, &#x27;-i&#x27;, input_file_path, &#x27;-s&#x27;, &#x27;1920x1080&#x27;, &#x27;-vcodec&#x27;, &#x27;mpeg4&#x27;, &#x27;-acodec&#x27;, &#x27;libvo_aacenc&#x27;, &#x27;-b&#x27;, &#x27;10000k&#x27;, &#x27;-pass&#x27;, i, &#x27;-r&#x27;, &#x27;30&#x27;, output_file_path])&#xA;&#xA;        if new_video_1080p == 0:&#xA;            # save the new file in the database&#xA;            # video.video_file_hd.name = output_file_name&#xA;            video.save(update_fields=[&#x27;video_file_fullhd&#x27;])&#xA;            logger.info(&#x27;Video Processing Finished&#x27;)&#xA;            return video&#xA;        else:&#xA;            logger.info(&#x27;Proceesing Failed.&#x27;) # Just for now&#xA;&#xA;    except:&#xA;        raise ValidationError(&#x27;Something went wrong&#x27;)&#xA;

    &#xA;

    In my first attempt I wasn't triggering the tasks no where, then I've tried to trigger the task from the schema.py file from graphql inside the video_by_id, but there I've got this error :

    &#xA;

    backend-celery-1  | django.core.exceptions.ValidationError: [&#x27;Something went wrong&#x27;]&#xA;backend-celery-1  | [2023-06-18 16:38:52,859: ERROR/ForkPoolWorker-4] Task video.tasks.task_video_encoding_1080p[d33b1a42-5914-467c-ad5c-00565bc8be6f] raised unexpected: ValidationError([&#x27;Something went wrong&#x27;])&#xA;backend-celery-1  | Traceback (most recent call last):&#xA;backend-celery-1  |   File "/usr/src/backend/video/tasks.py", line 81, in task_video_encoding_1080p&#xA;backend-celery-1  |     new_video_1080p = subprocess.call([FFMPEG_PATH, &#x27;-i&#x27;, input_file_path, &#x27;-s&#x27;, &#x27;1920x1080&#x27;, &#x27;-vcodec&#x27;, &#x27;mpeg4&#x27;, &#x27;-acodec&#x27;, &#x27;libvo_aacenc&#x27;, &#x27;-b&#x27;, &#x27;10000k&#x27;, &#x27;-pass&#x27;, i, &#x27;-r&#x27;, &#x27;30&#x27;, output_file_path])&#xA;backend-celery-1  |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&#xA;backend-celery-1  |   File "/usr/local/lib/python3.11/subprocess.py", line 389, in call&#xA;backend-celery-1  |     with Popen(*popenargs, **kwargs) as p:&#xA;backend-celery-1  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^&#xA;backend-celery-1  |   File "/usr/local/lib/python3.11/subprocess.py", line 1026, in __init__&#xA;backend-celery-1  |     self._execute_child(args, executable, preexec_fn, close_fds,&#xA;backend-celery-1  |   File "/usr/local/lib/python3.11/subprocess.py", line 1883, in _execute_child&#xA;backend-celery-1  |     self.pid = _fork_exec(&#xA;backend-celery-1  |                ^^^^^^^^^^^&#xA;backend-celery-1  | TypeError: expected str, bytes or os.PathLike object, not int&#xA;backend-celery-1  | &#xA;backend-celery-1  | During handling of the above exception, another exception occurred:&#xA;backend-celery-1  | &#xA;backend-celery-1  | Traceback (most recent call last):&#xA;backend-celery-1  |   File "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", line 477, in trace_task&#xA;backend-celery-1  |     R = retval = fun(*args, **kwargs)&#xA;backend-celery-1  |                  ^^^^^^^^^^^^^^^^^^^^&#xA;backend-celery-1  |   File "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", line 760, in __protected_call__&#xA;backend-celery-1  |     return self.run(*args, **kwargs)&#xA;backend-celery-1  |            ^^^^^^^^^^^^^^^^^^^^^^^^^&#xA;backend-celery-1  |   File "/usr/src/backend/video/tasks.py", line 93, in task_video_encoding_1080p&#xA;backend-celery-1  |     raise ValidationError(&#x27;Something went wrong&#x27;)&#xA;backend-celery-1  | django.core.exceptions.ValidationError: [&#x27;Something went wrong&#x27;]&#xA;

    &#xA;

    If anyone has done this kind of project or something like this please any suggestion or help is much appreciated.

    &#xA;

    Thank you in advance !

    &#xA;