Recherche avancée

Médias (0)

Mot : - Tags -/navigation

Aucun média correspondant à vos critères n’est disponible sur le site.

Autres articles (52)

  • Les autorisations surchargées par les plugins

    27 avril 2010, par

    Mediaspip core
    autoriser_auteur_modifier() afin que les visiteurs soient capables de modifier leurs informations sur la page d’auteurs

  • Publier sur MédiaSpip

    13 juin 2013

    Puis-je poster des contenus à partir d’une tablette Ipad ?
    Oui, si votre Médiaspip installé est à la version 0.2 ou supérieure. Contacter au besoin l’administrateur de votre MédiaSpip pour le savoir

  • Des sites réalisés avec MediaSPIP

    2 mai 2011, par

    Cette page présente quelques-uns des sites fonctionnant sous MediaSPIP.
    Vous pouvez bien entendu ajouter le votre grâce au formulaire en bas de page.

Sur d’autres sites (10155)

  • C++ ffmpeg lib version 7.0 - noice in exported audio

    2 septembre 2024, par Chris P

    I want to make a C++ lib named cppdub which will mimic the python module pydub.

    


    One main function is to export the AudioSegment to a file with a specific format (example : mp3).

    


    The code is :

    


    AudioSegment AudioSegment::from_file(const std::string&amp; file_path, const std::string&amp; format, const std::string&amp; codec,&#xA;    const std::map&amp; parameters, int start_second, int duration) {&#xA;&#xA;    avformat_network_init();&#xA;    av_log_set_level(AV_LOG_ERROR); // Adjust logging level as needed&#xA;&#xA;    AVFormatContext* format_ctx = nullptr;&#xA;    if (avformat_open_input(&amp;format_ctx, file_path.c_str(), nullptr, nullptr) != 0) {&#xA;        std::cerr &lt;&lt; "Error: Could not open audio file." &lt;&lt; std::endl;&#xA;        return AudioSegment();  // Return an empty AudioSegment on failure&#xA;    }&#xA;&#xA;    if (avformat_find_stream_info(format_ctx, nullptr) &lt; 0) {&#xA;        std::cerr &lt;&lt; "Error: Could not find stream information." &lt;&lt; std::endl;&#xA;        avformat_close_input(&amp;format_ctx);&#xA;        return AudioSegment();&#xA;    }&#xA;&#xA;    int audio_stream_index = -1;&#xA;    for (unsigned int i = 0; i &lt; format_ctx->nb_streams; i&#x2B;&#x2B;) {&#xA;        if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {&#xA;            audio_stream_index = i;&#xA;            break;&#xA;        }&#xA;    }&#xA;&#xA;    if (audio_stream_index == -1) {&#xA;        std::cerr &lt;&lt; "Error: Could not find audio stream." &lt;&lt; std::endl;&#xA;        avformat_close_input(&amp;format_ctx);&#xA;        return AudioSegment();&#xA;    }&#xA;&#xA;    AVCodecParameters* codec_par = format_ctx->streams[audio_stream_index]->codecpar;&#xA;    const AVCodec* my_codec = avcodec_find_decoder(codec_par->codec_id);&#xA;    AVCodecContext* codec_ctx = avcodec_alloc_context3(my_codec);&#xA;&#xA;    if (avcodec_parameters_to_context(codec_ctx, codec_par) &lt; 0) {&#xA;        std::cerr &lt;&lt; "Error: Could not initialize codec context." &lt;&lt; std::endl;&#xA;        avformat_close_input(&amp;format_ctx);&#xA;        return AudioSegment();&#xA;    }&#xA;&#xA;    if (avcodec_open2(codec_ctx, my_codec, nullptr) &lt; 0) {&#xA;        std::cerr &lt;&lt; "Error: Could not open codec." &lt;&lt; std::endl;&#xA;        avcodec_free_context(&amp;codec_ctx);&#xA;        avformat_close_input(&amp;format_ctx);&#xA;        return AudioSegment();&#xA;    }&#xA;&#xA;    SwrContext* swr_ctx = swr_alloc();&#xA;    if (!swr_ctx) {&#xA;        std::cerr &lt;&lt; "Error: Could not allocate SwrContext." &lt;&lt; std::endl;&#xA;        avcodec_free_context(&amp;codec_ctx);&#xA;        avformat_close_input(&amp;format_ctx);&#xA;        return AudioSegment();&#xA;    }&#xA;&#xA;    av_opt_set_chlayout(swr_ctx, "in_chlayout", &amp;codec_ctx->ch_layout, 0);&#xA;    av_opt_set_int(swr_ctx, "in_sample_rate", codec_ctx->sample_rate, 0);&#xA;    av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", codec_ctx->sample_fmt, 0);&#xA;&#xA;    AVChannelLayout dst_ch_layout;&#xA;    av_channel_layout_copy(&amp;dst_ch_layout, &amp;codec_ctx->ch_layout);&#xA;    av_channel_layout_uninit(&amp;dst_ch_layout);&#xA;    av_channel_layout_default(&amp;dst_ch_layout, 2);&#xA;&#xA;    av_opt_set_chlayout(swr_ctx, "out_chlayout", &amp;dst_ch_layout, 0);&#xA;    av_opt_set_int(swr_ctx, "out_sample_rate", 48000, 0);&#xA;    av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);&#xA;&#xA;    if (swr_init(swr_ctx) &lt; 0) {&#xA;        std::cerr &lt;&lt; "Error: Failed to initialize the resampling context" &lt;&lt; std::endl;&#xA;        swr_free(&amp;swr_ctx);&#xA;        avcodec_free_context(&amp;codec_ctx);&#xA;        avformat_close_input(&amp;format_ctx);&#xA;        return AudioSegment();&#xA;    }&#xA;&#xA;    AVPacket packet;&#xA;    AVFrame* frame = av_frame_alloc();&#xA;    if (!frame) {&#xA;        std::cerr &lt;&lt; "Error: Could not allocate frame." &lt;&lt; std::endl;&#xA;        swr_free(&amp;swr_ctx);&#xA;        avcodec_free_context(&amp;codec_ctx);&#xA;        avformat_close_input(&amp;format_ctx);&#xA;        return AudioSegment();&#xA;    }&#xA;&#xA;    std::vector<char> output;&#xA;    while (av_read_frame(format_ctx, &amp;packet) >= 0) {&#xA;        if (packet.stream_index == audio_stream_index) {&#xA;            if (avcodec_send_packet(codec_ctx, &amp;packet) == 0) {&#xA;                while (avcodec_receive_frame(codec_ctx, frame) == 0) {&#xA;                    if (frame->pts != AV_NOPTS_VALUE) {&#xA;                        frame->pts = av_rescale_q(frame->pts, codec_ctx->time_base, format_ctx->streams[audio_stream_index]->time_base);&#xA;                    }&#xA;&#xA;                    uint8_t* output_buffer;&#xA;                    int output_samples = av_rescale_rnd(&#xA;                        swr_get_delay(swr_ctx, codec_ctx->sample_rate) &#x2B; frame->nb_samples,&#xA;                        48000, codec_ctx->sample_rate, AV_ROUND_UP);&#xA;&#xA;                    int output_buffer_size = av_samples_get_buffer_size(&#xA;                        nullptr, 2, output_samples, AV_SAMPLE_FMT_S16, 1);&#xA;&#xA;                    output_buffer = (uint8_t*)av_malloc(output_buffer_size);&#xA;&#xA;                    if (output_buffer) {&#xA;                        memset(output_buffer, 0, output_buffer_size); // Zero padding to avoid random noise&#xA;                        int converted_samples = swr_convert(swr_ctx, &amp;output_buffer, output_samples,&#xA;                            (const uint8_t**)frame->extended_data, frame->nb_samples);&#xA;&#xA;                        if (converted_samples >= 0) {&#xA;                            output.insert(output.end(), output_buffer, output_buffer &#x2B; output_buffer_size);&#xA;                        }&#xA;                        else {&#xA;                            std::cerr &lt;&lt; "Error: Failed to convert audio samples." &lt;&lt; std::endl;&#xA;                        }&#xA;&#xA;                        av_free(output_buffer);&#xA;                    }&#xA;                    else {&#xA;                        std::cerr &lt;&lt; "Error: Could not allocate output buffer." &lt;&lt; std::endl;&#xA;                    }&#xA;                }&#xA;            }&#xA;            else {&#xA;                std::cerr &lt;&lt; "Error: Failed to send packet to codec context." &lt;&lt; std::endl;&#xA;            }&#xA;        }&#xA;        av_packet_unref(&amp;packet);&#xA;    }&#xA;&#xA;    av_frame_free(&amp;frame);&#xA;    swr_free(&amp;swr_ctx);&#xA;    avcodec_free_context(&amp;codec_ctx);&#xA;    avformat_close_input(&amp;format_ctx);&#xA;&#xA;    std::map metadata = {&#xA;        {"sample_width", 2},&#xA;        {"frame_rate", 48000},&#xA;        {"channels", 2},&#xA;        {"frame_width", 4}&#xA;    };&#xA;&#xA;    return AudioSegment(static_cast<const>(output.data()), output.size(), metadata);&#xA;}&#xA;&#xA;&#xA;std::ofstream AudioSegment::export_segment(std::string&amp; out_f,&#xA;    const std::string&amp; format,&#xA;    const std::string&amp; codec,&#xA;    const std::string&amp; bitrate,&#xA;    const std::vector&amp; parameters,&#xA;    const std::map&amp; tags,&#xA;    const std::string&amp; id3v2_version,&#xA;    const std::string&amp; cover) {&#xA;    av_log_set_level(AV_LOG_DEBUG);&#xA;    AVCodecContext* codec_ctx = nullptr;&#xA;    AVFormatContext* format_ctx = nullptr;&#xA;    AVStream* stream = nullptr;&#xA;    AVFrame* frame = nullptr;&#xA;    AVPacket* pkt = nullptr;&#xA;    int ret;&#xA;&#xA;    // Open output file&#xA;    std::ofstream out_file(out_f, std::ios::binary);&#xA;    if (!out_file) {&#xA;        throw std::runtime_error("Failed to open output file.");&#xA;    }&#xA;&#xA;    // Initialize format context&#xA;    avformat_alloc_output_context2(&amp;format_ctx, nullptr, format.c_str(), out_f.c_str());&#xA;    if (!format_ctx) {&#xA;        throw std::runtime_error("Could not allocate format context.");&#xA;    }&#xA;&#xA;    // Find encoder&#xA;    const AVCodec* codec_ptr = avcodec_find_encoder_by_name(codec.c_str());&#xA;    if (!codec_ptr) {&#xA;        throw std::runtime_error("Codec not found.");&#xA;    }&#xA;&#xA;    // Add stream&#xA;    stream = avformat_new_stream(format_ctx, codec_ptr);&#xA;    if (!stream) {&#xA;        throw std::runtime_error("Failed to create new stream.");&#xA;    }&#xA;&#xA;    // Allocate codec context&#xA;    codec_ctx = avcodec_alloc_context3(codec_ptr);&#xA;    if (!codec_ctx) {&#xA;        throw std::runtime_error("Could not allocate audio codec context.");&#xA;    }&#xA;&#xA;    // Set codec parameters&#xA;    codec_ctx->bit_rate = std::stoi(bitrate);&#xA;    codec_ctx->sample_fmt = codec_ptr->sample_fmts ? codec_ptr->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;&#xA;    codec_ctx->sample_rate = frame_rate_;&#xA;    codec_ctx->ch_layout.nb_channels = this->get_channels();&#xA;    AVChannelLayout ch_layout_1;&#xA;    av_channel_layout_uninit(&amp;ch_layout_1);&#xA;    av_channel_layout_default(&amp;ch_layout_1, this->get_channels());&#xA;    codec_ctx->ch_layout = ch_layout_1;&#xA;&#xA;    // Open codec&#xA;    ret = avcodec_open2(codec_ctx, codec_ptr, nullptr);&#xA;    if (ret &lt; 0) {&#xA;        throw std::runtime_error("Could not open codec.");&#xA;    }&#xA;&#xA;    // Initialize packet&#xA;    pkt = av_packet_alloc();&#xA;    if (!pkt) {&#xA;        throw std::runtime_error("Could not allocate AVPacket.");&#xA;    }&#xA;&#xA;    // Initialize frame&#xA;    frame = av_frame_alloc();&#xA;    if (!frame) {&#xA;        throw std::runtime_error("Could not allocate AVFrame.");&#xA;    }&#xA;&#xA;    frame->nb_samples = codec_ctx->frame_size;&#xA;    frame->format = codec_ctx->sample_fmt;&#xA;    frame->ch_layout = codec_ctx->ch_layout;&#xA;    frame->sample_rate = codec_ctx->sample_rate;&#xA;&#xA;    // Allocate data buffer&#xA;    ret = av_frame_get_buffer(frame, 0);&#xA;    if (ret &lt; 0) {&#xA;        throw std::runtime_error("Could not allocate audio data buffers.");&#xA;    }&#xA;&#xA;    // Encode frames&#xA;    int samples_read = 0;&#xA;    while (samples_read &lt; data_.size()) {&#xA;        ret = av_frame_make_writable(frame);&#xA;        if (ret &lt; 0) {&#xA;            throw std::runtime_error("Frame not writable.");&#xA;        }&#xA;&#xA;        // Determine the number of samples to copy into the frame&#xA;        int frame_size = std::min<int>(codec_ctx->frame_size, (data_.size() - samples_read) / frame_width_);&#xA;        int buffer_size = frame_size * frame_width_;&#xA;&#xA;        // Clear the frame data to avoid artifacts from previous data&#xA;        std::memset(frame->data[0], 0, codec_ctx->frame_size * frame_width_);&#xA;&#xA;        // Copy the actual audio data into the frame&#xA;        std::memcpy(frame->data[0], data_.data() &#x2B; samples_read, buffer_size);&#xA;        samples_read &#x2B;= buffer_size;&#xA;&#xA;        // If the frame is partially filled, pad the remaining part with zeros&#xA;        if (frame_size &lt; codec_ctx->frame_size) {&#xA;            std::memset(frame->data[0] &#x2B; buffer_size, 0, (codec_ctx->frame_size - frame_size) * frame_width_);&#xA;        }&#xA;&#xA;        // Send the frame for encoding&#xA;        ret = avcodec_send_frame(codec_ctx, frame);&#xA;        if (ret &lt; 0) {&#xA;            throw std::runtime_error("Error sending frame for encoding.");&#xA;        }&#xA;&#xA;        // Receive and write packets&#xA;        while (ret >= 0) {&#xA;            ret = avcodec_receive_packet(codec_ctx, pkt);&#xA;            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {&#xA;                break;&#xA;            }&#xA;            else if (ret &lt; 0) {&#xA;                throw std::runtime_error("Error encoding frame.");&#xA;            }&#xA;&#xA;            out_file.write(reinterpret_cast(pkt->data), pkt->size);&#xA;            av_packet_unref(pkt);&#xA;        }&#xA;    }&#xA;&#xA;    // **Explicitly flush the encoder**&#xA;    ret = avcodec_send_frame(codec_ctx, nullptr);&#xA;    if (ret &lt; 0) {&#xA;        throw std::runtime_error("Error flushing the encoder.");&#xA;    }&#xA;&#xA;    // Receive and write remaining packets after flushing&#xA;    while (ret >= 0) {&#xA;        ret = avcodec_receive_packet(codec_ctx, pkt);&#xA;        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {&#xA;            break;&#xA;        }&#xA;        else if (ret &lt; 0) {&#xA;            throw std::runtime_error("Error encoding frame during flush.");&#xA;        }&#xA;&#xA;        out_file.write(reinterpret_cast(pkt->data), pkt->size);&#xA;        av_packet_unref(pkt);&#xA;    }&#xA;&#xA;    // Cleanup&#xA;    av_frame_free(&amp;frame);&#xA;    av_packet_free(&amp;pkt);&#xA;    avcodec_free_context(&amp;codec_ctx);&#xA;    avformat_free_context(format_ctx);&#xA;&#xA;    return out_file;&#xA;}&#xA;</int></const></char>

    &#xA;

    I have no run time error but i see this message in console :

    &#xA;

    [libmp3lame @ 000002d26b239ac0] Trying to remove 47 more samples than there are in the queue&#xA;

    &#xA;

    I can play the exported mp3 file but there is background noise.

    &#xA;

  • How to optimize this code that gets video frame as image

    14 août 2024, par TSR

    I am quite new to mp4 file. But here is my working attempt to extract image frame given video url and a timestamp.

    &#xA;

    In reality the input url is an 8K 10hours 200GB video, so I can't download it all, I can't load it to memory, and this is an API call so it has to be fast.

    &#xA;

    Is there anything else I can optimize ?

    &#xA;

    My doubts :

    &#xA;

      &#xA;
    • This line ffprobe -v error -select_streams v:0 -show_entries packet=pos,size,dts_time -read_intervals ${timestamp}%&#x2B;5 -of csv=p=0 "${url}" I chose this clingy 5s, in which case would this fail ?

      &#xA;

    • &#xA;

    • Same line, I don't know what's going on under the hood of this ffprobe command, but I tested it with the big 8K video and it seems to complete fast. So is it safe to assume that the entire 200GB was not downloaded ? An explanation of how this ffprobe command work would be appreciated

      &#xA;

    • &#xA;

    • Based on trial and error, I concluded that the intervals returned is parsable by ffmpeg only if the first frame until the timestamp is included. If I include only that the single frame interval, ffmpeg says it is an invalid file. (Makes sense cuz I don't think I'll get an image from a 4byte data.) However, how can I be sure that I am selecting the least number of intervals.

      &#xA;

    • &#xA;

    • Worse bottleneck : The function extractFrame takes 6seconds on the big video. It seems to read the entire video segment fetched (by the preceding subrange step). I couldn't find a way to jump to the last frame without computing. Is this how MP4 work ? I read somewhere that MP4 computes the current frame based on the previous. If that is true, does it mean there is no way to compute a specific frame without reading everything since the last keyframe ?

      &#xA;

    • &#xA;

    • Finally, this ffmpeg line is fishy (I got it from SO Extract final frame from a video using ffmpeg) it says that it ovewrites the output at everyframe . Does it mean it is writing to the disk every time ? I experience severe degradation in performance when I used .png instead of .jpg. This tells me that the image is computed every&#xA;frame. Can we compute only the final image at the very end ?

      &#xA;

    • &#xA;

    &#xA;

    Here is the working code to optimize.

    &#xA;

    import path from "path";&#xA;import axios from "axios";&#xA;import ffmpeg from "fluent-ffmpeg";&#xA;import fs from "fs";&#xA;import {promisify} from &#x27;util&#x27;;&#xA;import {exec} from &#x27;child_process&#x27;;&#xA;&#xA;const execPromise = promisify(exec);&#xA;&#xA;&#xA;// URL of the video and desired timestamp (in seconds)&#xA;&#xA;const videoUrl = &#x27;https://raw.githubusercontent.com/tolotrasamuel/assets/main/videoplayback.mp4&#x27;;&#xA;&#xA;console.log(videoUrl);&#xA;const timestamp = 30; // Example: 30 seconds into the video&#xA;&#xA;&#xA;// Function to get the byte range using ffprobe&#xA;const getByteRangeForTimestamp = async (url, timestamp) => {&#xA;    // Use ffprobe to get the offset and size of the frame at the given timestamp&#xA;    const command = `ffprobe -v error -select_streams v:0 -show_entries packet=pos,size,dts_time -read_intervals ${timestamp}%&#x2B;5 -of csv=p=0 "${url}"`;&#xA;    console.log(&#x27;Running command:&#x27;, command);&#xA;    const {stdout} = await execPromise(command);&#xA;&#xA;&#xA;    // Parse the output&#xA;    const timeStamps = stdout.trim().split("\n");&#xA;    const frames = timeStamps.map(ts => {&#xA;        const [dts_time, size, offset] = ts.split(&#x27;,&#x27;);&#xA;        const timeInt = parseFloat(dts_time);&#xA;        const offsetInt = parseInt(offset);&#xA;        const sizeInt = parseInt(size);&#xA;        return {dts_time: timeInt, size: sizeInt, offset: offsetInt};&#xA;    })&#xA;&#xA;    if (frames.length === 0) {&#xA;        throw new Error(&#x27;No frames found in the specified interval&#x27;);&#xA;    }&#xA;&#xA;    let closest;&#xA;&#xA;&#xA;    let i = 0&#xA;    while (i &lt; frames.length) {&#xA;        if (i === frames.length) {&#xA;            throw new Error(&#x27;No frames found in the specified 5s interval&#x27;);&#xA;        }&#xA;        if (frames[i].dts_time >= timestamp) {&#xA;            const oldDiff = Math.abs(closest.dts_time - timestamp);&#xA;            const newDiff = Math.abs(frames[i].dts_time - timestamp);&#xA;            if (newDiff &lt; oldDiff) {&#xA;                closest = frames[i];&#xA;            }&#xA;            break;&#xA;        }&#xA;        closest = frames[i];&#xA;        i&#x2B;&#x2B;;&#xA;    }&#xA;&#xA;    // I experimented with this, but it seems that the first frame is always at the beginning of a valid atom&#xA;    // anything after that will make the video unplayable&#xA;    const startByte = frames[0].offset;&#xA;    const endByte = closest.offset &#x2B; closest.size - 1;&#xA;&#xA;    const diff = Math.abs(closest.dts_time - timestamp);&#xA;    const size = endByte - startByte &#x2B; 1;&#xA;    console.log("Start: ", startByte, "End: ", endByte, "Diff: ", diff, "Timestamp: ", timestamp, "Closest: ", closest.dts_time, "Size to fetch: ", size)&#xA;&#xA;&#xA;    const startTime = closest.dts_time - frames[0].dts_time;&#xA;    return {startByte, endByte, startTime};&#xA;};&#xA;&#xA;// Download the specific segment&#xA;const downloadSegment = async (url, startByte, endByte, outputPath) => {&#xA;    console.log(`Downloading bytes ${startByte}-${endByte}...`);&#xA;    const response = await axios.get(url, {&#xA;        responseType: &#x27;arraybuffer&#x27;,&#xA;        headers: {&#xA;            Range: `bytes=${startByte}-${endByte}`,&#xA;        },&#xA;    });&#xA;&#xA;    console.log(&#x27;Segment downloaded!&#x27;, response.data.length, "Written to: ", outputPath);&#xA;    fs.writeFileSync(outputPath, response.data);&#xA;};&#xA;&#xA;// Extract frame from the segment&#xA;const extractFrameRaw = async (videoPath, timestamp, outputFramePath) => {&#xA;&#xA;&#xA;    const command = `ffmpeg -sseof -3 -i ${videoPath} -update 1 -q:v 1 ${outputFramePath} -y`;&#xA;    console.log(&#x27;Running command:&#x27;, command);&#xA;    const startTime = new Date().getTime();&#xA;    await execPromise(command);&#xA;    const endTime = new Date().getTime();&#xA;    console.log(&#x27;Processing time:&#x27;, endTime - startTime, &#x27;ms&#x27;);&#xA;    console.log(&#x27;Frame extracted to:&#x27;, outputFramePath);&#xA;};&#xA;const extractFrame = (videoPath, timestamp, outputFramePath) => {&#xA;    ffmpeg(videoPath)&#xA;        .inputOptions([&#x27;-sseof -5&#x27;])  // Seeks to 3 seconds before the end of the video&#xA;        .outputOptions([&#xA;            &#x27;-update 1&#x27;, // Continuously update the output file with new frames&#xA;            &#x27;-q:v 1&#x27;     // Set the highest JPEG quality&#xA;        ])&#xA;        .output(outputFramePath)  // Set the output file path&#xA;&#xA;        // log&#xA;        .on(&#x27;start&#x27;, function (commandLine) {&#xA;            console.log(&#x27;Spawned Ffmpeg with command: &#x27; &#x2B; commandLine);&#xA;        })&#xA;        .on(&#x27;progress&#x27;, function (progress) {&#xA;            console.log(&#x27;Processing: &#x27; &#x2B; progress.timemark &#x2B; &#x27;% done&#x27;, progress, &#x27;frame: &#x27;, progress.frames);&#xA;        })&#xA;        .on(&#x27;end&#x27;, function () {&#xA;            console.log(&#x27;Processing finished !&#x27;);&#xA;        })&#xA;        .on(&#x27;error&#x27;, function (err, stdout, stderr) {&#xA;            console.error(&#x27;Error:&#x27;, err);&#xA;            console.error(&#x27;ffmpeg stderr:&#x27;, stderr);&#xA;        })&#xA;        .run();&#xA;};&#xA;&#xA;&#xA;const __dirname = path.resolve();&#xA;&#xA;// Main function to orchestrate the process&#xA;(async () => {&#xA;    try {&#xA;        // ffmpeg.setFfmpegPath(&#x27;/usr/local/bin/ffmpeg&#x27;);&#xA;        const {startByte, endByte, startTime} = await getByteRangeForTimestamp(videoUrl, timestamp);&#xA;        const tmpVideoPath = path.resolve(__dirname, &#x27;temp_video.mp4&#x27;);&#xA;        const outputFramePath = path.resolve(__dirname, `frame_${timestamp}.jpg`);&#xA;&#xA;        await downloadSegment(videoUrl, startByte, endByte, tmpVideoPath);&#xA;        await extractFrame(tmpVideoPath, startTime, outputFramePath);&#xA;    } catch (err) {&#xA;        console.error(&#x27;Error:&#x27;, err);&#xA;    }&#xA;})();&#xA;

    &#xA;

  • How to extract the first frame from a video ?

    10 août 2024, par Andrew

    I am trying to extract the first frame from a video to save it as a preview.

    &#xA;

    Here's an almost working solution using ffmpeg :

    &#xA;

    func extractFirstFrame(videoBytes []byte) ([]byte, error) {&#xA;    input := bytes.NewReader(videoBytes)&#xA;&#xA;    var output bytes.Buffer&#xA;&#xA;    err := ffmpeg.Input("pipe:0").&#xA;        Filter("select", ffmpeg.Args{"gte(n,1)"}).&#xA;        Output(&#xA;            "pipe:1",&#xA;            ffmpeg.KwArgs{&#xA;                "vframes": 1,&#xA;                "format":  "image2",&#xA;                "vcodec":  "mjpeg",&#xA;            }).&#xA;        WithInput(input).&#xA;        WithOutput(&amp;output).&#xA;        Run()&#xA;&#xA;    if err != nil {&#xA;        return nil, fmt.Errorf("error extracting frame: %v", err)&#xA;    }&#xA;&#xA;    return output.Bytes(), nil&#xA;}&#xA;

    &#xA;

    The problem with this is that it can only process horizontal videos. For some reason it will throw a 0xbebbb1b7 error for a vertical videos. I don't understand why is that, probably because this is my very first time with ffmpeg.

    &#xA;

    Also, I am concerned if this solution is optimal. My assumption is that the whole video will be loaded into the memory first, which is kinda bad and I would like to avoid that

    &#xA;

    I use https://github.com/u2takey/ffmpeg-go, but errors are the same even if I run it using exec :

    &#xA;

        cmd := exec.Command(&#xA;        "ffmpeg",&#xA;        "-i", "pipe:0",&#xA;        "-vf", "select=eq(n\\,0)",&#xA;        "-q:v", "3",&#xA;        "-f", "image2",&#xA;        "pipe:1",&#xA;    )&#xA;

    &#xA;

    Interestingly enough, I noticed that running command in the terminal will work as expected with any type of video ffmpeg -i .\video_2024-08-10_00-03-00.mp4 -vf "select=eq(n\,0)"  -q:v 3 output_image.jpg, so the problem may be on how I send those videos to my server. I useFiber and send videos as multipart/form-data and then read it like this :

    &#xA;

        form_data, err := c.FormFile("image")&#xA;    file, err := form_data.Open()&#xA;    bytes, err := io.ReadAll(file)&#xA;    ....&#xA;    preview, err := extractFirstFrame(bytes)&#xA;&#xA;

    &#xA;

    I also managed to find logs for the failed attempt :

    &#xA;

    &#xA;ffmpeg version 7.0.2-full_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers&#xA;  built with gcc 13.2.0 (Rev5, Built by MSYS2 project)&#xA;  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-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libcodec2 --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint&#xA;  libavutil      59.  8.100 / 59.  8.100&#xA;  libavcodec     61.  3.100 / 61.  3.100&#xA;  libavformat    61.  1.100 / 61.  1.100&#xA;  libavdevice    61.  1.100 / 61.  1.100&#xA;  libavfilter    10.  1.100 / 10.  1.100&#xA;  libswscale      8.  1.100 /  8.  1.100&#xA;  libswresample   5.  1.100 /  5.  1.100&#xA;  libpostproc    58.  1.100 / 58.  1.100&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002a562ff0e80] stream 0, offset 0x30: partial file&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002a562ff0e80] Could not find codec parameters for stream 1 (Video: h264 (avc1 / 0x31637661), none, 720x1280, 3093 kb/s): unspecified pixel format&#xA;Consider increasing the value for the &#x27;analyzeduration&#x27; (0) and &#x27;probesize&#x27; (5000000) options&#xA;Input #0, mov,mp4,m4a,3gp,3g2,mj2, from &#x27;pipe:0&#x27;:&#xA;  Metadata:&#xA;    major_brand     : isom&#xA;    minor_version   : 512&#xA;    compatible_brands: isomiso2avc1mp41&#xA;    creation_time   : 2024-08-09T20:00:29.000000Z&#xA;  Duration: 00:00:06.80, start: 0.000000, bitrate: N/A&#xA;  Stream #0:0[0x1](eng): Audio: aac (mp4a / 0x6134706D), 22050 Hz, stereo, fltp, 74 kb/s (default)&#xA;      Metadata:&#xA;        creation_time   : 2024-08-09T20:00:23.000000Z&#xA;        handler_name    : SoundHandle&#xA;        vendor_id       : [0][0][0][0]&#xA;  Stream #0:1[0x2](eng): Video: h264 (avc1 / 0x31637661), none, 720x1280, 3093 kb/s, 30 fps, 30 tbr, 90k tbn (default)&#xA;      Metadata:&#xA;        creation_time   : 2024-08-09T20:00:23.000000Z&#xA;        handler_name    : VideoHandle&#xA;        vendor_id       : [0][0][0][0]&#xA;Stream mapping:&#xA;  Stream #0:1 -> #0:0 (h264 (native) -> mjpeg (native))&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002a562ff0e80] stream 1, offset 0x5d: partial file&#xA;[in#0/mov,mp4,m4a,3gp,3g2,mj2 @ 000002a562fda2c0] Error during demuxing: Invalid data found when processing input&#xA;Cannot determine format of input 0:1 after EOF&#xA;[vf#0:0 @ 000002a5636c0ec0] Task finished with error code: -1094995529 (Invalid data found when processing input)&#xA;[vf#0:0 @ 000002a5636c0ec0] Terminating thread with return code -1094995529 (Invalid data found when processing input)&#xA;[vost#0:0/mjpeg @ 000002a5636c0400] Could not open encoder before EOF&#xA;[vost#0:0/mjpeg @ 000002a5636c0400] Task finished with error code: -22 (Invalid argument)&#xA;[vost#0:0/mjpeg @ 000002a5636c0400] Terminating thread with return code -22 (Invalid argument)&#xA;[out#0/image2 @ 000002a562ff5640] Nothing was written into output file, because at least one of its streams received no packets.&#xA;frame=    0 fps=0.0 q=0.0 Lsize=       0KiB time=N/A bitrate=N/A speed=N/A&#xA;Conversion failed!&#xA;

    &#xA;

    Logs for the same video, but ran via terminal :

    &#xA;

    ffmpeg version 7.0.2-full_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers&#xA;  built with gcc 13.2.0 (Rev5, Built by MSYS2 project)&#xA;  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-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libcodec2 --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint&#xA;  libavutil      59.  8.100 / 59.  8.100&#xA;  libavcodec     61.  3.100 / 61.  3.100&#xA;  libavformat    61.  1.100 / 61.  1.100&#xA;  libavdevice    61.  1.100 / 61.  1.100&#xA;  libavfilter    10.  1.100 / 10.  1.100&#xA;  libswscale      8.  1.100 /  8.  1.100&#xA;  libswresample   5.  1.100 /  5.  1.100&#xA;  libpostproc    58.  1.100 / 58.  1.100&#xA;Input #0, mov,mp4,m4a,3gp,3g2,mj2, from &#x27;.\video_2024-08-10_00-03-00.mp4&#x27;:&#xA;  Metadata:&#xA;    major_brand     : isom&#xA;    minor_version   : 512&#xA;    compatible_brands: isomiso2avc1mp41&#xA;    creation_time   : 2024-08-09T20:00:29.000000Z&#xA;  Duration: 00:00:06.80, start: 0.000000, bitrate: 3175 kb/s&#xA;  Stream #0:0[0x1](eng): Audio: aac (HE-AAC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 74 kb/s (default)&#xA;      Metadata:&#xA;        creation_time   : 2024-08-09T20:00:23.000000Z&#xA;        handler_name    : SoundHandle&#xA;        vendor_id       : [0][0][0][0]&#xA;  Stream #0:1[0x2](eng): Video: h264 (Baseline) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 720x1280, 3093 kb/s, 30 fps, 30 tbr, 90k tbn (default)&#xA;      Metadata:&#xA;        creation_time   : 2024-08-09T20:00:23.000000Z&#xA;        handler_name    : VideoHandle&#xA;        vendor_id       : [0][0][0][0]&#xA;Stream mapping:&#xA;  Stream #0:1 -> #0:0 (h264 (native) -> mjpeg (native))&#xA;Press [q] to stop, [?] for help&#xA;[swscaler @ 00000219eb4d0c00] deprecated pixel format used, make sure you did set range correctly&#xA;Output #0, image2, to &#x27;output_image.jpg&#x27;:&#xA;  Metadata:&#xA;    major_brand     : isom&#xA;    minor_version   : 512&#xA;    compatible_brands: isomiso2avc1mp41&#xA;    encoder         : Lavf61.1.100&#xA;  Stream #0:0(eng): Video: mjpeg, yuvj420p(pc, unknown/bt709/bt709, progressive), 720x1280, q=2-31, 200 kb/s, 30 fps, 30 tbn (default)&#xA;      Metadata:&#xA;        creation_time   : 2024-08-09T20:00:23.000000Z&#xA;        handler_name    : VideoHandle&#xA;        vendor_id       : [0][0][0][0]&#xA;        encoder         : Lavc61.3.100 mjpeg&#xA;      Side data:&#xA;        cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: N/A&#xA;[image2 @ 00000219e7aa51c0] The specified filename &#x27;output_image.jpg&#x27; does not contain an image sequence pattern or a pattern is invalid.&#xA;[image2 @ 00000219e7aa51c0] Use a pattern such as %03d for an image sequence or use the -update option (with -frames:v 1 if needed) to write a single image.&#xA;[out#0/image2 @ 00000219e7b5e400] video:49KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown&#xA;frame=    1 fps=0.0 q=3.0 Lsize=N/A time=00:00:00.03 bitrate=N/A speed=0.322x&#xA;

    &#xA;

    I also realized that the problem was not related to the video orientation, but to to the video from a specific source uploaded specifically on my server 🤡 Such a weird coincidence that I decided to test my video upload with those files, but anyway. And those are.... Downloaded instagram reels lol. But again, ffmpeg works just fine when ran in terminal

    &#xA;