Recherche avancée

Médias (91)

Autres articles (110)

  • MediaSPIP 0.1 Beta version

    25 avril 2011, par

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

  • Multilang : améliorer l’interface pour les blocs multilingues

    18 février 2011, par

    Multilang est un plugin supplémentaire qui n’est pas activé par défaut lors de l’initialisation de MediaSPIP.
    Après son activation, une préconfiguration est mise en place automatiquement par MediaSPIP init permettant à la nouvelle fonctionnalité d’être automatiquement opérationnelle. Il n’est donc pas obligatoire de passer par une étape de configuration pour cela.

  • HTML5 audio and video support

    13 avril 2011, par

    MediaSPIP uses HTML5 video and audio tags to play multimedia files, taking advantage of the latest W3C innovations supported by modern browsers.
    The MediaSPIP player used has been created specifically for MediaSPIP and can be easily adapted to fit in with a specific theme.
    For older browsers the Flowplayer flash fallback is used.
    MediaSPIP allows for media playback on major mobile platforms with the above (...)

Sur d’autres sites (13979)

  • FFMpeg for IOS - Disabling Log Levels

    12 novembre 2013, par Veeru

    I have compiled ffmpeg for ios. The configuration for compiling, i have borrowed from kxmovie's Rake file.

    Everything works fine, but i would like to disable all the debug messages showed in console by the decoder.

    How can i achieve this. I believe it should be the ffmpeg is compiled, but am not sure how to go about it. Any suggestions would be highly appreciated.

    configure command :

    ./configure —disable-ffmpeg —disable-ffplay —disable-ffserver
    —disable-ffprobe —disable-doc —disable-bzlib —target-os=darwin —enable-cross-compile —enable-gpl —enable-version3 —assert-level=2 —disable-mmx —arch=i386 —cpu=i386 —extra-ldflags='-arch i386' —extra-cflags='-arch i386' —disable-asm —cc=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc
    —as='gas-preprocessor.pl /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc'
    —sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk
    —extra-ldflags=-L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/usr/lib/system

  • Encoding/Decoding H264 using libav in C++ [closed]

    20 mai, par gbock93

    I want to build an application to

    


      

    • capture frames in YUYV 4:2:2 format
    • 


    • encode them to H264
    • 


    • send over network
    • 


    • decode the received data
    • 


    • display the video stream
    • 


    


    To do so I wrote 2 classes, H264Encoder and H264Decoder.

    


    I post only the .cpp contents, the .h are trivial :

    


    H264Encoder.cpp

    


    #include &#xA;&#xA;#include <stdexcept>&#xA;#include <iostream>&#xA;&#xA;H264Encoder::H264Encoder(unsigned int width_, unsigned int height_, unsigned int fps_):&#xA;    m_width(width_),&#xA;    m_height(height_),&#xA;    m_fps(fps_),&#xA;    m_frame_index(0),&#xA;    m_context(nullptr),&#xA;    m_frame(nullptr),&#xA;    m_packet(nullptr),&#xA;    m_sws_ctx(nullptr)&#xA;{&#xA;    // Find the video codec&#xA;    AVCodec* codec;&#xA;    codec = avcodec_find_encoder(AV_CODEC_ID_H264);&#xA;    if (!codec)&#xA;        throw std::runtime_error("[Encoder]: Error: Codec not found");&#xA;&#xA;    // Allocate codec&#xA;    m_context = avcodec_alloc_context3(codec);&#xA;    if (!m_context)&#xA;        throw std::runtime_error("[Encoder]: Error: Could not allocate codec context");&#xA;&#xA;    // Configure codec&#xA;    av_opt_set(m_context->priv_data, "preset", "ultrafast", 0);&#xA;    av_opt_set(m_context->priv_data, "tune", "zerolatency", 0);&#xA;    av_opt_set(m_context->priv_data, "crf",           "35", 0); // Range: [0; 51], sane range: [18; 26], lower -> higher compression&#xA;&#xA;    m_context->width        = (int)width_;&#xA;    m_context->height       = (int)height_;&#xA;    m_context->time_base    = {1, (int)fps_};&#xA;    m_context->framerate    = {(int)fps_, 1};&#xA;    m_context->codec_id     = AV_CODEC_ID_H264;&#xA;    m_context->pix_fmt      = AV_PIX_FMT_YUV420P; // H265|4 codec take as input only AV_PIX_FMT_YUV420P&#xA;    m_context->bit_rate     = 400000;&#xA;    m_context->gop_size     = 10;&#xA;    m_context->max_b_frames = 1;&#xA;&#xA;    // Open codec&#xA;    if (avcodec_open2(m_context, codec, nullptr) &lt; 0)&#xA;        throw std::runtime_error("[Encoder]: Error: Could not open codec");&#xA;&#xA;    // Allocate frame and its buffer&#xA;    m_frame = av_frame_alloc();&#xA;    if (!m_frame) &#xA;        throw std::runtime_error("[Encoder]: Error: Could not allocate frame");&#xA;&#xA;    m_frame->format = m_context->pix_fmt;&#xA;    m_frame->width  = m_context->width;&#xA;    m_frame->height = m_context->height;&#xA;&#xA;    if (av_frame_get_buffer(m_frame, 0) &lt; 0)&#xA;        throw std::runtime_error("[Encoder]: Error: Cannot allocate frame buffer");&#xA;    &#xA;    // Allocate packet&#xA;    m_packet = av_packet_alloc();&#xA;    if (!m_packet) &#xA;        throw std::runtime_error("[Encoder]: Error: Could not allocate packet");&#xA;&#xA;    // Convert from YUYV422 to YUV420P&#xA;    m_sws_ctx = sws_getContext(&#xA;        width_, height_, AV_PIX_FMT_YUYV422,&#xA;        width_, height_, AV_PIX_FMT_YUV420P,&#xA;        SWS_BILINEAR, nullptr, nullptr, nullptr&#xA;    );&#xA;    if (!m_sws_ctx) &#xA;        throw std::runtime_error("[Encoder]: Error: Could not allocate sws context");&#xA;&#xA;    //&#xA;    printf("[Encoder]: H264Encoder ready.\n");&#xA;}&#xA;&#xA;H264Encoder::~H264Encoder()&#xA;{&#xA;    sws_freeContext(m_sws_ctx);&#xA;    av_packet_free(&amp;m_packet);&#xA;    av_frame_free(&amp;m_frame);&#xA;    avcodec_free_context(&amp;m_context);&#xA;&#xA;    printf("[Encoder]: H264Encoder destroyed.\n");&#xA;}&#xA;&#xA;std::vector H264Encoder::encode(const cv::Mat&amp; img_)&#xA;{&#xA;    /*&#xA;    - YUYV422 is a packed format. It has 3 components (av_pix_fmt_desc_get((AVPixelFormat)AV_PIX_FMT_YUYV422)->nb_components == 3) but&#xA;        data is stored in a single plane (av_pix_fmt_count_planes((AVPixelFormat)AV_PIX_FMT_YUYV422) == 1).&#xA;    - YUV420P is a planar format. It has 3 components (av_pix_fmt_desc_get((AVPixelFormat)AV_PIX_FMT_YUV420P)->nb_components == 3) and&#xA;        each component is stored in a separate plane (av_pix_fmt_count_planes((AVPixelFormat)AV_PIX_FMT_YUV420P) == 3) with its&#xA;        own stride.&#xA;    */&#xA;    std::cout &lt;&lt; "[Encoder]" &lt;&lt; std::endl;&#xA;    std::cout &lt;&lt; "[Encoder]: Encoding img " &lt;&lt; img_.cols &lt;&lt; "x" &lt;&lt; img_.rows &lt;&lt; " | element size " &lt;&lt; img_.elemSize() &lt;&lt; std::endl;&#xA;    assert(img_.elemSize() == 2);&#xA;&#xA;    uint8_t* input_data[1] = {(uint8_t*)img_.data};&#xA;    int input_linesize[1] = {2 * (int)m_width};&#xA;    &#xA;    if (av_frame_make_writable(m_frame) &lt; 0)&#xA;        throw std::runtime_error("[Encoder]: Error: Cannot make frame data writable");&#xA;&#xA;    // Convert from YUV422 image to YUV420 frame. Apply scaling if necessary&#xA;    sws_scale(&#xA;        m_sws_ctx,&#xA;        input_data, input_linesize, 0, m_height,&#xA;        m_frame->data, m_frame->linesize&#xA;    );&#xA;    m_frame->pts = m_frame_index;&#xA;&#xA;    int n_planes = av_pix_fmt_count_planes((AVPixelFormat)m_frame->format);&#xA;    std::cout &lt;&lt; "[Encoder]: Sending Frame " &lt;&lt; m_frame_index &lt;&lt; " with dimensions " &lt;&lt; m_frame->width &lt;&lt; "x" &lt;&lt; m_frame->height &lt;&lt; "x" &lt;&lt; n_planes &lt;&lt; std::endl;&#xA;    for (int i=0; iframerate.num) &#x2B; 1;&#xA;            break;&#xA;        case AVERROR(EAGAIN):&#xA;            throw std::runtime_error("[Encoder]: avcodec_send_frame: EAGAIN");&#xA;        case AVERROR_EOF:&#xA;            throw std::runtime_error("[Encoder]: avcodec_send_frame: EOF");&#xA;        case AVERROR(EINVAL):&#xA;            throw std::runtime_error("[Encoder]: avcodec_send_frame: EINVAL");&#xA;        case AVERROR(ENOMEM):&#xA;            throw std::runtime_error("[Encoder]: avcodec_send_frame: ENOMEM");&#xA;        default:&#xA;            throw std::runtime_error("[Encoder]: avcodec_send_frame: UNKNOWN");&#xA;    }&#xA;&#xA;    // Receive packet from codec&#xA;    std::vector result;&#xA;    while(ret >= 0)&#xA;    {&#xA;        ret = avcodec_receive_packet(m_context, m_packet);&#xA;&#xA;        switch (ret)&#xA;        {&#xA;        case 0:&#xA;            std::cout &lt;&lt; "[Encoder]: Received packet from codec of size " &lt;&lt; m_packet->size &lt;&lt; " bytes " &lt;&lt; std::endl;&#xA;            result.insert(result.end(), m_packet->data, m_packet->data &#x2B; m_packet->size);&#xA;            av_packet_unref(m_packet);&#xA;            break;&#xA;&#xA;        case AVERROR(EAGAIN):&#xA;            std::cout &lt;&lt; "[Encoder]: avcodec_receive_packet: EAGAIN" &lt;&lt; std::endl;&#xA;            break;&#xA;        case AVERROR_EOF:&#xA;            std::cout &lt;&lt; "[Encoder]: avcodec_receive_packet: EOF" &lt;&lt; std::endl;&#xA;            break;&#xA;        case AVERROR(EINVAL):&#xA;            throw std::runtime_error("[Encoder]: avcodec_receive_packet: EINVAL");&#xA;        default:&#xA;            throw std::runtime_error("[Encoder]: avcodec_receive_packet: UNKNOWN");&#xA;        }&#xA;    }&#xA;&#xA;    std::cout &lt;&lt; "[Encoder]: Encoding complete" &lt;&lt; std::endl;&#xA;    return result;&#xA;}&#xA;</iostream></stdexcept>

    &#xA;

    H264Decoder.cpp

    &#xA;

    #include &#xA;&#xA;#include <iostream>&#xA;#include <stdexcept>&#xA;&#xA;H264Decoder::H264Decoder():&#xA;    m_context(nullptr),&#xA;    m_frame(nullptr),&#xA;    m_packet(nullptr)&#xA;{&#xA;    // Find the video codec&#xA;    AVCodec* codec;&#xA;    codec = avcodec_find_decoder(AV_CODEC_ID_H264);&#xA;    if (!codec)&#xA;        throw std::runtime_error("[Decoder]: Error: Codec not found");&#xA;&#xA;    // Allocate codec&#xA;    m_context = avcodec_alloc_context3(codec);&#xA;    if (!m_context)&#xA;        throw std::runtime_error("[Decoder]: Error: Could not allocate codec context");&#xA;&#xA;    // Open codec&#xA;    if (avcodec_open2(m_context, codec, nullptr) &lt; 0)&#xA;        throw std::runtime_error("[Decoder]: Error: Could not open codec");&#xA;&#xA;    // Allocate frame&#xA;    m_frame = av_frame_alloc();&#xA;    if (!m_frame)&#xA;        throw std::runtime_error("[Decoder]: Error: Could not allocate frame");&#xA;&#xA;    // Allocate packet&#xA;    m_packet = av_packet_alloc();&#xA;    if (!m_packet) &#xA;        throw std::runtime_error("[Decoder]: Error: Could not allocate packet");&#xA;&#xA;    //&#xA;    printf("[Decoder]: H264Decoder ready.\n");&#xA;}&#xA;&#xA;H264Decoder::~H264Decoder()&#xA;{&#xA;    av_packet_free(&amp;m_packet);&#xA;    av_frame_free(&amp;m_frame);&#xA;    avcodec_free_context(&amp;m_context);&#xA;&#xA;    printf("[Decoder]: H264Decoder destroyed.\n");&#xA;}&#xA;&#xA;bool H264Decoder::decode(uint8_t* data_, size_t size_, cv::Mat&amp; img_)&#xA;{&#xA;    std::cout &lt;&lt; "[Decoder]" &lt;&lt; std::endl;&#xA;    std::cout &lt;&lt; "[Decoder]: decoding " &lt;&lt; size_ &lt;&lt; " bytes of data" &lt;&lt; std::endl;&#xA;&#xA;    // Fill packet&#xA;    m_packet->data = data_;&#xA;    m_packet->size = size_;&#xA;&#xA;    if (size_ == 0)&#xA;        return false;&#xA;&#xA;    // Send packet to codec&#xA;    int send_result = avcodec_send_packet(m_context, m_packet);&#xA;&#xA;    switch (send_result)&#xA;    {&#xA;        case 0:&#xA;            std::cout &lt;&lt; "[Decoder]: Sent packet to codec" &lt;&lt; std::endl;&#xA;            break;&#xA;        case AVERROR(EAGAIN):&#xA;            throw std::runtime_error("[Decoder]: avcodec_send_packet: EAGAIN");&#xA;        case AVERROR_EOF:&#xA;            throw std::runtime_error("[Decoder]: avcodec_send_packet: EOF");&#xA;        case AVERROR(EINVAL):&#xA;            throw std::runtime_error("[Decoder]: avcodec_send_packet: EINVAL");&#xA;        case AVERROR(ENOMEM):&#xA;            throw std::runtime_error("[Decoder]: avcodec_send_packet: ENOMEM");&#xA;        default:&#xA;            throw std::runtime_error("[Decoder]: avcodec_send_packet: UNKNOWN");&#xA;    }&#xA;&#xA;    // Receive frame from codec&#xA;    int n_planes;&#xA;    uint8_t* output_data[1];&#xA;    int output_line_size[1];&#xA;&#xA;    int receive_result = avcodec_receive_frame(m_context, m_frame);&#xA;&#xA;    switch (receive_result)&#xA;    {&#xA;        case 0:&#xA;            n_planes = av_pix_fmt_count_planes((AVPixelFormat)m_frame->format);&#xA;            std::cout &lt;&lt; "[Decoder]: Received Frame with dimensions " &lt;&lt; m_frame->width &lt;&lt; "x" &lt;&lt; m_frame->height &lt;&lt; "x" &lt;&lt; n_planes &lt;&lt; std::endl;&#xA;            for (int i=0; i/&#xA;    std::cout &lt;&lt; "[Decoder]: Decoding complete" &lt;&lt; std::endl;&#xA;    return true;&#xA;}&#xA;</stdexcept></iostream>

    &#xA;

    To test the two classes I put together a main.cpp to grab a frame, encode/decode and display the decoded frame (no network transmission in place) :

    &#xA;

    main.cpp

    &#xA;

    while(...)&#xA;{&#xA;    // get frame from custom camera class. Format is YUYV 4:2:2&#xA;    camera.getFrame(camera_frame);&#xA;    // Construct a cv::Mat to represent the grabbed frame&#xA;    cv::Mat camera_frame_yuyv = cv::Mat(camera_frame.height, camera_frame.width, CV_8UC2, camera_frame.data.data());&#xA;    // Encode image&#xA;    std::vector encoded_data = encoder.encode(camera_frame_yuyv);&#xA;    if (!encoded_data.empty())&#xA;    {&#xA;        // Decode image&#xA;        cv::Mat decoded_frame;&#xA;        if (decoder.decode(encoded_data.data(), encoded_data.size(), decoded_frame))&#xA;        {&#xA;            // Display image&#xA;            cv::imshow("Camera", decoded_frame);&#xA;            cv::waitKey(1);&#xA;        }&#xA;    }&#xA;}&#xA;

    &#xA;

    Compiling and executing the code I get random results between subsequent executions :

    &#xA;

      &#xA;
    • Sometimes the whole loop runs without problems and I see the decoded image.
    • &#xA;

    • Sometimes the program crashes at the sws_scale(...) call in the decoder with "Assertion desc failed at src/libswscale/swscale_internal.h:757".
    • &#xA;

    • Sometimes the loop runs but I see a black image and the message Slice parameters 0, 720 are invalid is displayed when executing the sws_scale(...) call in the decoder.
    • &#xA;

    &#xA;

    Why is the behaviour so random ? What am I doing wrong with the libav API ?

    &#xA;

    Some resources I found useful :

    &#xA;

    &#xA;

  • FFmpeg overlay positioning issue : Converting frontend center coordinates to FFmpeg top-left coordinates

    25 janvier, par tarun

    I'm building a web-based video editor where users can :

    &#xA;

    Add multiple videos&#xA;Add images&#xA;Add text overlays with background color

    &#xA;

    Frontend sends coordinates where each element's (x,y) represents its center position.&#xA;on click of the export button i want all data to be exported as one final video&#xA;on click i send the data to the backend like -

    &#xA;

     const exportAllVideos = async () => {&#xA;    try {&#xA;      const formData = new FormData();&#xA;        &#xA;      &#xA;      const normalizedVideos = videos.map(video => ({&#xA;          ...video,&#xA;          startTime: parseFloat(video.startTime),&#xA;          endTime: parseFloat(video.endTime),&#xA;          duration: parseFloat(video.duration)&#xA;      })).sort((a, b) => a.startTime - b.startTime);&#xA;&#xA;      &#xA;      for (const video of normalizedVideos) {&#xA;          const response = await fetch(video.src);&#xA;          const blobData = await response.blob();&#xA;          const file = new File([blobData], `${video.id}.mp4`, { type: "video/mp4" });&#xA;          formData.append("videos", file);&#xA;      }&#xA;&#xA;      &#xA;      const normalizedImages = images.map(image => ({&#xA;          ...image,&#xA;          startTime: parseFloat(image.startTime),&#xA;          endTime: parseFloat(image.endTime),&#xA;          x: parseInt(image.x),&#xA;          y: parseInt(image.y),&#xA;          width: parseInt(image.width),&#xA;          height: parseInt(image.height),&#xA;          opacity: parseInt(image.opacity)&#xA;      }));&#xA;&#xA;      &#xA;      for (const image of normalizedImages) {&#xA;          const response = await fetch(image.src);&#xA;          const blobData = await response.blob();&#xA;          const file = new File([blobData], `${image.id}.png`, { type: "image/png" });&#xA;          formData.append("images", file);&#xA;      }&#xA;&#xA;      &#xA;      const normalizedTexts = texts.map(text => ({&#xA;          ...text,&#xA;          startTime: parseFloat(text.startTime),&#xA;          endTime: parseFloat(text.endTime),&#xA;          x: parseInt(text.x),&#xA;          y: parseInt(text.y),&#xA;          fontSize: parseInt(text.fontSize),&#xA;          opacity: parseInt(text.opacity)&#xA;      }));&#xA;&#xA;      &#xA;      formData.append("metadata", JSON.stringify({&#xA;          videos: normalizedVideos,&#xA;          images: normalizedImages,&#xA;          texts: normalizedTexts&#xA;      }));&#xA;&#xA;      const response = await fetch("my_flask_endpoint", {&#xA;          method: "POST",&#xA;          body: formData&#xA;      });&#xA;&#xA;      if (!response.ok) {&#xA;        &#xA;          console.log(&#x27;wtf&#x27;, response);&#xA;          &#xA;      }&#xA;&#xA;      const finalVideo = await response.blob();&#xA;      const url = URL.createObjectURL(finalVideo);&#xA;      const a = document.createElement("a");&#xA;      a.href = url;&#xA;      a.download = "final_video.mp4";&#xA;      a.click();&#xA;      URL.revokeObjectURL(url);&#xA;&#xA;    } catch (e) {&#xA;      console.log(e, "err");&#xA;    }&#xA;  };&#xA;

    &#xA;

    the frontend data for each object that is text image and video we are storing it as an array of objects below is the Data strcutre for each object -

    &#xA;

    // the frontend data for each&#xA;  const newVideo = {&#xA;      id: uuidv4(),&#xA;      src: URL.createObjectURL(videoData.videoBlob),&#xA;      originalDuration: videoData.duration,&#xA;      duration: videoData.duration,&#xA;      startTime: 0,&#xA;      playbackOffset: 0,&#xA;      endTime: videoData.endTime || videoData.duration,&#xA;      isPlaying: false,&#xA;      isDragging: false,&#xA;      speed: 1,&#xA;      volume: 100,&#xA;      x: window.innerHeight / 2,&#xA;      y: window.innerHeight / 2,&#xA;      width: videoData.width,&#xA;      height: videoData.height,&#xA;    };&#xA;    const newTextObject = {&#xA;      id: uuidv4(),&#xA;      description: text,&#xA;      opacity: 100,&#xA;      x: containerWidth.width / 2,&#xA;      y: containerWidth.height / 2,&#xA;      fontSize: 18,&#xA;      duration: 20,&#xA;      endTime: 20,&#xA;      startTime: 0,&#xA;      color: "#ffffff",&#xA;      backgroundColor: hasBG,&#xA;      padding: 8,&#xA;      fontWeight: "normal",&#xA;      width: 200,&#xA;      height: 40,&#xA;    };&#xA;&#xA;    const newImage = {&#xA;      id: uuidv4(),&#xA;      src: URL.createObjectURL(imageData),&#xA;      x: containerWidth.width / 2,&#xA;      y: containerWidth.height / 2,&#xA;      width: 200,&#xA;      height: 200,&#xA;      borderRadius: 0,&#xA;      startTime: 0,&#xA;      endTime: 20,&#xA;      duration: 20,&#xA;      opacity: 100,&#xA;    };&#xA;&#xA;

    &#xA;

    BACKEND CODE -

    &#xA;

    import os&#xA;import shutil&#xA;import subprocess&#xA;from flask import Flask, request, send_file&#xA;import ffmpeg&#xA;import json&#xA;from werkzeug.utils import secure_filename&#xA;import uuid&#xA;from flask_cors import CORS&#xA;&#xA;&#xA;app = Flask(__name__)&#xA;CORS(app, resources={r"/*": {"origins": "*"}})&#xA;&#xA;&#xA;&#xA;UPLOAD_FOLDER = &#x27;temp_uploads&#x27;&#xA;if not os.path.exists(UPLOAD_FOLDER):&#xA;    os.makedirs(UPLOAD_FOLDER)&#xA;&#xA;&#xA;@app.route(&#x27;/&#x27;)&#xA;def home():&#xA;    return &#x27;Hello World&#x27;&#xA;&#xA;&#xA;OUTPUT_WIDTH = 1920&#xA;OUTPUT_HEIGHT = 1080&#xA;&#xA;&#xA;&#xA;@app.route(&#x27;/process&#x27;, methods=[&#x27;POST&#x27;])&#xA;def process_video():&#xA;    work_dir = None&#xA;    try:&#xA;        work_dir = os.path.abspath(os.path.join(UPLOAD_FOLDER, str(uuid.uuid4())))&#xA;        os.makedirs(work_dir)&#xA;        print(f"Created working directory: {work_dir}")&#xA;&#xA;        metadata = json.loads(request.form[&#x27;metadata&#x27;])&#xA;        print("Received metadata:", json.dumps(metadata, indent=2))&#xA;        &#xA;        video_paths = []&#xA;        videos = request.files.getlist(&#x27;videos&#x27;)&#xA;        for idx, video in enumerate(videos):&#xA;            filename = f"video_{idx}.mp4"&#xA;            filepath = os.path.join(work_dir, filename)&#xA;            video.save(filepath)&#xA;            if os.path.exists(filepath) and os.path.getsize(filepath) > 0:&#xA;                video_paths.append(filepath)&#xA;                print(f"Saved video to: {filepath} Size: {os.path.getsize(filepath)}")&#xA;            else:&#xA;                raise Exception(f"Failed to save video {idx}")&#xA;&#xA;        image_paths = []&#xA;        images = request.files.getlist(&#x27;images&#x27;)&#xA;        for idx, image in enumerate(images):&#xA;            filename = f"image_{idx}.png"&#xA;            filepath = os.path.join(work_dir, filename)&#xA;            image.save(filepath)&#xA;            if os.path.exists(filepath):&#xA;                image_paths.append(filepath)&#xA;                print(f"Saved image to: {filepath}")&#xA;&#xA;        output_path = os.path.join(work_dir, &#x27;output.mp4&#x27;)&#xA;&#xA;        filter_parts = []&#xA;&#xA;        base_duration = metadata["videos"][0]["duration"] if metadata["videos"] else 10&#xA;        filter_parts.append(f&#x27;color=c=black:s={OUTPUT_WIDTH}x{OUTPUT_HEIGHT}:d={base_duration}[canvas];&#x27;)&#xA;&#xA;        for idx, (path, meta) in enumerate(zip(video_paths, metadata[&#x27;videos&#x27;])):&#xA;            x_pos = int(meta.get("x", 0) - (meta.get("width", 0) / 2))&#xA;            y_pos = int(meta.get("y", 0) - (meta.get("height", 0) / 2))&#xA;            &#xA;            filter_parts.extend([&#xA;                f&#x27;[{idx}:v]setpts=PTS-STARTPTS,scale={meta.get("width", -1)}:{meta.get("height", -1)}[v{idx}];&#x27;,&#xA;                f&#x27;[{idx}:a]asetpts=PTS-STARTPTS[a{idx}];&#x27;&#xA;            ])&#xA;&#xA;            if idx == 0:&#xA;                filter_parts.append(&#xA;                    f&#x27;[canvas][v{idx}]overlay=x={x_pos}:y={y_pos}:eval=init[temp{idx}];&#x27;&#xA;                )&#xA;            else:&#xA;                filter_parts.append(&#xA;                    f&#x27;[temp{idx-1}][v{idx}]overlay=x={x_pos}:y={y_pos}:&#x27;&#xA;                    f&#x27;enable=\&#x27;between(t,{meta["startTime"]},{meta["endTime"]})\&#x27;:eval=init&#x27;&#xA;                    f&#x27;[temp{idx}];&#x27;&#xA;                )&#xA;&#xA;        last_video_temp = f&#x27;temp{len(video_paths)-1}&#x27;&#xA;&#xA;        if video_paths:&#xA;            audio_mix_parts = []&#xA;            for idx in range(len(video_paths)):&#xA;                audio_mix_parts.append(f&#x27;[a{idx}]&#x27;)&#xA;            filter_parts.append(f&#x27;{"".join(audio_mix_parts)}amix=inputs={len(video_paths)}[aout];&#x27;)&#xA;&#xA;        &#xA;        if image_paths:&#xA;            for idx, (img_path, img_meta) in enumerate(zip(image_paths, metadata[&#x27;images&#x27;])):&#xA;                input_idx = len(video_paths) &#x2B; idx&#xA;                &#xA;                &#xA;                x_pos = int(img_meta["x"] - (img_meta["width"] / 2))&#xA;                y_pos = int(img_meta["y"] - (img_meta["height"] / 2))&#xA;                &#xA;                filter_parts.extend([&#xA;                    f&#x27;[{input_idx}:v]scale={img_meta["width"]}:{img_meta["height"]}[img{idx}];&#x27;,&#xA;                    f&#x27;[{last_video_temp}][img{idx}]overlay=x={x_pos}:y={y_pos}:&#x27;&#xA;                    f&#x27;enable=\&#x27;between(t,{img_meta["startTime"]},{img_meta["endTime"]})\&#x27;:&#x27;&#xA;                    f&#x27;alpha={img_meta["opacity"]/100}[imgout{idx}];&#x27;&#xA;                ])&#xA;                last_video_temp = f&#x27;imgout{idx}&#x27;&#xA;&#xA;        if metadata.get(&#x27;texts&#x27;):&#xA;            for idx, text in enumerate(metadata[&#x27;texts&#x27;]):&#xA;                next_output = f&#x27;text{idx}&#x27; if idx &lt; len(metadata[&#x27;texts&#x27;]) - 1 else &#x27;vout&#x27;&#xA;                &#xA;                escaped_text = text["description"].replace("&#x27;", "\\&#x27;")&#xA;                &#xA;                x_pos = int(text["x"] - (text["width"] / 2))&#xA;                y_pos = int(text["y"] - (text["height"] / 2))&#xA;                &#xA;                text_filter = (&#xA;                    f&#x27;[{last_video_temp}]drawtext=text=\&#x27;{escaped_text}\&#x27;:&#x27;&#xA;                    f&#x27;x={x_pos}:y={y_pos}:&#x27;&#xA;                    f&#x27;fontsize={text["fontSize"]}:&#x27;&#xA;                    f&#x27;fontcolor={text["color"]}&#x27;&#xA;                )&#xA;                &#xA;                if text.get(&#x27;backgroundColor&#x27;):&#xA;                    text_filter &#x2B;= f&#x27;:box=1:boxcolor={text["backgroundColor"]}:boxborderw=5&#x27;&#xA;                &#xA;                if text.get(&#x27;fontWeight&#x27;) == &#x27;bold&#x27;:&#xA;                    text_filter &#x2B;= &#x27;:font=Arial-Bold&#x27;&#xA;                &#xA;                text_filter &#x2B;= (&#xA;                    f&#x27;:enable=\&#x27;between(t,{text["startTime"]},{text["endTime"]})\&#x27;&#x27;&#xA;                    f&#x27;[{next_output}];&#x27;&#xA;                )&#xA;                &#xA;                filter_parts.append(text_filter)&#xA;                last_video_temp = next_output&#xA;        else:&#xA;            filter_parts.append(f&#x27;[{last_video_temp}]null[vout];&#x27;)&#xA;&#xA;        &#xA;        filter_complex = &#x27;&#x27;.join(filter_parts)&#xA;&#xA;        &#xA;        cmd = [&#xA;            &#x27;ffmpeg&#x27;,&#xA;            *sum([[&#x27;-i&#x27;, path] for path in video_paths], []),&#xA;            *sum([[&#x27;-i&#x27;, path] for path in image_paths], []),&#xA;            &#x27;-filter_complex&#x27;, filter_complex,&#xA;            &#x27;-map&#x27;, &#x27;[vout]&#x27;&#xA;        ]&#xA;        &#xA;        &#xA;        if video_paths:&#xA;            cmd.extend([&#x27;-map&#x27;, &#x27;[aout]&#x27;])&#xA;        &#xA;        cmd.extend([&#x27;-y&#x27;, output_path])&#xA;&#xA;        print(f"Running ffmpeg command: {&#x27; &#x27;.join(cmd)}")&#xA;        result = subprocess.run(cmd, capture_output=True, text=True)&#xA;        &#xA;        if result.returncode != 0:&#xA;            print(f"FFmpeg error output: {result.stderr}")&#xA;            raise Exception(f"FFmpeg processing failed: {result.stderr}")&#xA;&#xA;        return send_file(&#xA;            output_path,&#xA;            mimetype=&#x27;video/mp4&#x27;,&#xA;            as_attachment=True,&#xA;            download_name=&#x27;final_video.mp4&#x27;&#xA;        )&#xA;&#xA;    except Exception as e:&#xA;        print(f"Error in video processing: {str(e)}")&#xA;        return {&#x27;error&#x27;: str(e)}, 500&#xA;    &#xA;    finally:&#xA;        if work_dir and os.path.exists(work_dir):&#xA;            try:&#xA;                print(f"Directory contents before cleanup: {os.listdir(work_dir)}")&#xA;                if not os.environ.get(&#x27;FLASK_DEBUG&#x27;):&#xA;                    shutil.rmtree(work_dir)&#xA;                else:&#xA;                    print(f"Keeping directory for debugging: {work_dir}")&#xA;            except Exception as e:&#xA;                print(f"Cleanup error: {str(e)}")&#xA;&#xA;                &#xA;if __name__ == &#x27;__main__&#x27;:&#xA;    app.run(debug=True, port=8000)&#xA;&#xA;

    &#xA;

    I'm also attaching what the final thing looks like on the frontend web vs in the downloaded video&#xA;and as u can see the downloaded video has all coords and positions messed up be it of the texts, images as well as videosdownloaded videos view&#xA;frontend web view

    &#xA;

    can somebody please help me figure this out :)

    &#xA;