home.social

#else — Public Fediverse posts

Live and recent posts from across the Fediverse tagged #else, aggregated by home.social.

  1. CW: C++
    #include "util/ffmpeg_movie_writer.h"

    #include <godot_cpp/classes/image.hpp>

    #ifdef FFMPEG_AVAILABLE
    extern "C" {
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswresample/swresample.h>
    #include <libswscale/swscale.h>
    }
    #endif

    void FFmpegMovieWriter::_bind_methods() {
    }

    uint32_t FFmpegMovieWriter::_get_audio_mix_rate() const {
    return 48000;
    }

    AudioServer::SpeakerMode FFmpegMovieWriter::_get_audio_speaker_mode() const {
    return AudioServer::SPEAKER_MODE_STEREO;
    }

    bool FFmpegMovieWriter::_handles_file(const String &p_path) const {
    return p_path.get_extension().to_lower() == "mkv";
    }

    PackedStringArray FFmpegMovieWriter::_get_supported_extensions() const {
    return { "mkv" };
    }

    Error FFmpegMovieWriter::_write_begin(const Vector2i &p_movie_size, uint32_t p_fps, const String &p_base_path) {
    #ifdef FFMPEG_AVAILABLE
    int error = avformat_alloc_output_context2(&_context, nullptr, "matroska", p_base_path.utf8().get_data());
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    const AVCodec *video_codec = avcodec_find_encoder(AV_CODEC_ID_AV1);
    ERR_FAIL_NULL_V_MSG(video_codec, FAILED, "ffmpeg was not compiled with AV1 support");

    _video_context = avcodec_alloc_context3(video_codec);
    ERR_FAIL_NULL_V_MSG(_video_context, FAILED, "failed to allocate video context");

    _video_context->time_base = av_make_q(1, p_fps);
    _video_context->framerate = av_make_q(p_fps, 1);
    _video_context->width = p_movie_size.x;
    _video_context->height = p_movie_size.y;
    _video_context->sample_aspect_ratio = av_make_q(1, 1);
    _video_context->pix_fmt = AV_PIX_FMT_YUV420P;

    AVDictionary *video_options = nullptr;
    av_dict_set_int(&video_options, "crf", 30, 0);

    error = avcodec_open2(_video_context, video_codec, &video_options);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    av_dict_free(&video_options);

    _video_stream = avformat_new_stream(_context, video_codec);
    ERR_FAIL_NULL_V_MSG(_video_stream, FAILED, "failed to create video stream");
    error = avcodec_parameters_from_context(_video_stream->codecpar, _video_context);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    const AVCodec *audio_codec = avcodec_find_encoder(AV_CODEC_ID_OPUS);
    ERR_FAIL_NULL_V_MSG(audio_codec, FAILED, "ffmpeg was not compiled with Opus support");

    _audio_context = avcodec_alloc_context3(audio_codec);
    ERR_FAIL_NULL_V_MSG(_audio_context, FAILED, "failed to allocate audio context");

    _audio_context->bit_rate = 96000;
    _audio_context->time_base = av_make_q(1, 48000);
    _audio_context->sample_rate = 48000;
    _audio_context->sample_fmt = AV_SAMPLE_FMT_S16;
    _audio_context->ch_layout = AV_CHANNEL_LAYOUT_STEREO;

    error = avcodec_open2(_audio_context, audio_codec, nullptr);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _audio_stream = avformat_new_stream(_context, audio_codec);
    ERR_FAIL_NULL_V_MSG(_audio_stream, FAILED, "failed to create audio stream");
    error = avcodec_parameters_from_context(_audio_stream->codecpar, _audio_context);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _image_frame = av_frame_alloc();
    ERR_FAIL_NULL_V_MSG(_image_frame, FAILED, "failed to create image frame");
    _image_frame->width = p_movie_size.x;
    _image_frame->height = p_movie_size.y;
    _image_frame->format = AV_PIX_FMT_RGBA;
    _image_frame->sample_aspect_ratio = av_make_q(1, 1);
    error = av_frame_get_buffer(_image_frame, 0);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _video_frame = av_frame_alloc();
    ERR_FAIL_NULL_V_MSG(_video_frame, FAILED, "failed to create video frame");
    _video_frame->width = _video_context->width;
    _video_frame->height = _video_context->height;
    _video_frame->format = _video_context->pix_fmt;
    _video_frame->sample_aspect_ratio = _video_context->sample_aspect_ratio;
    error = av_frame_get_buffer(_video_frame, 0);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _sws_context = sws_alloc_context();
    ERR_FAIL_NULL_V_MSG(_sws_context, FAILED, "failed to allocate libswscale context");

    error = sws_frame_setup(_sws_context, _video_frame, _image_frame);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    DEV_ASSERT(_audio_context->sample_rate % p_fps == 0);
    _raw_audio_frame = av_frame_alloc();
    ERR_FAIL_NULL_V_MSG(_raw_audio_frame, FAILED, "failed to create raw audio frame");
    _raw_audio_frame->nb_samples = _audio_context->sample_rate / p_fps;
    _raw_audio_frame->format = AV_SAMPLE_FMT_S32;
    _raw_audio_frame->sample_rate = _audio_context->sample_rate;
    error = av_channel_layout_copy(&_raw_audio_frame->ch_layout, &_audio_context->ch_layout);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));
    error = av_frame_get_buffer(_raw_audio_frame, 0);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _audio_frame = av_frame_alloc();
    ERR_FAIL_NULL_V_MSG(_audio_frame, FAILED, "failed to create audio frame");
    _audio_frame->nb_samples = _audio_context->frame_size;
    _audio_frame->format = _audio_context->sample_fmt;
    _audio_frame->sample_rate = _audio_context->sample_rate;
    error = av_channel_layout_copy(&_audio_frame->ch_layout, &_audio_context->ch_layout);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));
    error = av_frame_get_buffer(_audio_frame, 0);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _swr_context = swr_alloc();
    ERR_FAIL_NULL_V_MSG(_swr_context, FAILED, "failed to allocate libswresample context");

    error = swr_config_frame(_swr_context, _audio_frame, _raw_audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    error = swr_init(_swr_context);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _packet = av_packet_alloc();

    error = avio_open(&_context->pb, p_base_path.utf8().get_data(), AVIO_FLAG_WRITE);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    error = avformat_write_header(_context, nullptr);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    return OK;
    #else
    return ERR_UNAVAILABLE;
    #endif
    }

    Error FFmpegMovieWriter::_write_frame(const Ref<Image> &p_frame_image, const void *p_audio_frame_block) {
    #ifdef FFMPEG_AVAILABLE
    ERR_FAIL_COND_V(!_write_image(p_frame_image), FAILED);
    ERR_FAIL_COND_V(!_write_audio(p_audio_frame_block), FAILED);

    return OK;
    #else
    return ERR_UNAVAILABLE;
    #endif
    }

    void FFmpegMovieWriter::_write_end() {
    #ifdef FFMPEG_AVAILABLE
    int error = avcodec_send_frame(_video_context, nullptr);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));

    ERR_FAIL_COND(!_write_packets(_video_context, _video_stream));

    // check for any remaining samples at the end of the stream
    if (swr_get_delay(_swr_context, _audio_frame->sample_rate) > 0) {
    error = av_frame_make_writable(_audio_frame);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));

    error = swr_convert_frame(_swr_context, _audio_frame, nullptr);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));

    _audio_frame->pts = _audio_pts;

    error = avcodec_send_frame(_audio_context, _audio_frame);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));
    }

    error = avcodec_send_frame(_audio_context, nullptr);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));

    ERR_FAIL_COND(!_write_packets(_audio_context, _audio_stream));

    av_write_trailer(_context);

    avio_closep(&_context->pb);

    av_packet_free(&_packet);
    av_frame_free(&_raw_audio_frame);
    av_frame_free(&_audio_frame);
    av_frame_free(&_video_frame);
    av_frame_free(&_image_frame);
    swr_free(&_swr_context);
    sws_free_context(&_sws_context);
    avcodec_free_context(&_audio_context);
    avcodec_free_context(&_video_context);
    avformat_free_context(_context);
    #endif
    }

    #ifdef FFMPEG_AVAILABLE
    bool FFmpegMovieWriter::_write_packets(AVCodecContext *p_context, AVStream *p_stream) {
    while (avcodec_receive_packet(p_context, _packet) == 0) {
    av_packet_rescale_ts(_packet, p_context->time_base, p_stream->time_base);
    _packet->stream_index = p_stream->index;

    if (p_context->pix_fmt != AV_PIX_FMT_NONE) {
    __builtin_debugtrap();
    }

    int error = av_interleaved_write_frame(_context, _packet);
    CRASH_COND(error < 0);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));
    }

    return true;
    }

    bool FFmpegMovieWriter::_write_image(const Ref<Image> &p_frame_image) {
    DEV_ASSERT(p_frame_image->get_format() == Image::FORMAT_RGBA8);
    DEV_ASSERT(p_frame_image->get_width() == _image_frame->width);
    DEV_ASSERT(p_frame_image->get_height() == _image_frame->height);

    int error = av_frame_make_writable(_image_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));
    memcpy(_image_frame->data[0], p_frame_image->get_data().ptr(), p_frame_image->get_data_size());

    error = av_frame_make_writable(_video_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    error = sws_scale_frame(_sws_context, _video_frame, _image_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    _video_frame->pts = _video_pts;
    _video_pts++;

    error = avcodec_send_frame(_video_context, _video_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    return _write_packets(_video_context, _video_stream);
    }

    bool FFmpegMovieWriter::_write_audio(const void *p_audio_frame_block) {
    int error = av_frame_make_writable(_raw_audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));
    memcpy(_raw_audio_frame->data[0], p_audio_frame_block, _raw_audio_frame->nb_samples * sizeof(int32_t));

    error = swr_convert_frame(_swr_context, nullptr, _raw_audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    while (swr_get_delay(_swr_context, _audio_frame->sample_rate) >= _audio_frame->nb_samples) {
    error = av_frame_make_writable(_audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    error = swr_convert_frame(_swr_context, _audio_frame, nullptr);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    _audio_frame->pts = _audio_pts;
    _audio_pts += _audio_frame->nb_samples;

    error = avcodec_send_frame(_audio_context, _audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));
    }

    return _write_packets(_audio_context, _audio_stream);
    }
    #endif
  2. CW: C++
    #include "util/ffmpeg_movie_writer.h"

    #include <godot_cpp/classes/image.hpp>

    #ifdef FFMPEG_AVAILABLE
    extern "C" {
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswresample/swresample.h>
    #include <libswscale/swscale.h>
    }
    #endif

    void FFmpegMovieWriter::_bind_methods() {
    }

    uint32_t FFmpegMovieWriter::_get_audio_mix_rate() const {
    return 48000;
    }

    AudioServer::SpeakerMode FFmpegMovieWriter::_get_audio_speaker_mode() const {
    return AudioServer::SPEAKER_MODE_STEREO;
    }

    bool FFmpegMovieWriter::_handles_file(const String &p_path) const {
    return p_path.get_extension().to_lower() == "mkv";
    }

    PackedStringArray FFmpegMovieWriter::_get_supported_extensions() const {
    return { "mkv" };
    }

    Error FFmpegMovieWriter::_write_begin(const Vector2i &p_movie_size, uint32_t p_fps, const String &p_base_path) {
    #ifdef FFMPEG_AVAILABLE
    int error = avformat_alloc_output_context2(&_context, nullptr, "matroska", p_base_path.utf8().get_data());
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    const AVCodec *video_codec = avcodec_find_encoder(AV_CODEC_ID_AV1);
    ERR_FAIL_NULL_V_MSG(video_codec, FAILED, "ffmpeg was not compiled with AV1 support");

    _video_context = avcodec_alloc_context3(video_codec);
    ERR_FAIL_NULL_V_MSG(_video_context, FAILED, "failed to allocate video context");

    _video_context->time_base = av_make_q(1, p_fps);
    _video_context->framerate = av_make_q(p_fps, 1);
    _video_context->width = p_movie_size.x;
    _video_context->height = p_movie_size.y;
    _video_context->sample_aspect_ratio = av_make_q(1, 1);
    _video_context->pix_fmt = AV_PIX_FMT_YUV420P;

    AVDictionary *video_options = nullptr;
    av_dict_set_int(&video_options, "crf", 30, 0);

    error = avcodec_open2(_video_context, video_codec, &video_options);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    av_dict_free(&video_options);

    _video_stream = avformat_new_stream(_context, video_codec);
    ERR_FAIL_NULL_V_MSG(_video_stream, FAILED, "failed to create video stream");
    error = avcodec_parameters_from_context(_video_stream->codecpar, _video_context);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    const AVCodec *audio_codec = avcodec_find_encoder(AV_CODEC_ID_OPUS);
    ERR_FAIL_NULL_V_MSG(audio_codec, FAILED, "ffmpeg was not compiled with Opus support");

    _audio_context = avcodec_alloc_context3(audio_codec);
    ERR_FAIL_NULL_V_MSG(_audio_context, FAILED, "failed to allocate audio context");

    _audio_context->bit_rate = 96000;
    _audio_context->time_base = av_make_q(1, 48000);
    _audio_context->sample_rate = 48000;
    _audio_context->sample_fmt = AV_SAMPLE_FMT_S16;
    _audio_context->ch_layout = AV_CHANNEL_LAYOUT_STEREO;

    error = avcodec_open2(_audio_context, audio_codec, nullptr);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _audio_stream = avformat_new_stream(_context, audio_codec);
    ERR_FAIL_NULL_V_MSG(_audio_stream, FAILED, "failed to create audio stream");
    error = avcodec_parameters_from_context(_audio_stream->codecpar, _audio_context);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _image_frame = av_frame_alloc();
    ERR_FAIL_NULL_V_MSG(_image_frame, FAILED, "failed to create image frame");
    _image_frame->width = p_movie_size.x;
    _image_frame->height = p_movie_size.y;
    _image_frame->format = AV_PIX_FMT_RGBA;
    _image_frame->sample_aspect_ratio = av_make_q(1, 1);
    error = av_frame_get_buffer(_image_frame, 0);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _video_frame = av_frame_alloc();
    ERR_FAIL_NULL_V_MSG(_video_frame, FAILED, "failed to create video frame");
    _video_frame->width = _video_context->width;
    _video_frame->height = _video_context->height;
    _video_frame->format = _video_context->pix_fmt;
    _video_frame->sample_aspect_ratio = _video_context->sample_aspect_ratio;
    error = av_frame_get_buffer(_video_frame, 0);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _sws_context = sws_alloc_context();
    ERR_FAIL_NULL_V_MSG(_sws_context, FAILED, "failed to allocate libswscale context");

    error = sws_frame_setup(_sws_context, _video_frame, _image_frame);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    DEV_ASSERT(_audio_context->sample_rate % p_fps == 0);
    _raw_audio_frame = av_frame_alloc();
    ERR_FAIL_NULL_V_MSG(_raw_audio_frame, FAILED, "failed to create raw audio frame");
    _raw_audio_frame->nb_samples = _audio_context->sample_rate / p_fps;
    _raw_audio_frame->format = AV_SAMPLE_FMT_S32;
    _raw_audio_frame->sample_rate = _audio_context->sample_rate;
    error = av_channel_layout_copy(&_raw_audio_frame->ch_layout, &_audio_context->ch_layout);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));
    error = av_frame_get_buffer(_raw_audio_frame, 0);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _audio_frame = av_frame_alloc();
    ERR_FAIL_NULL_V_MSG(_audio_frame, FAILED, "failed to create audio frame");
    _audio_frame->nb_samples = _audio_context->frame_size;
    _audio_frame->format = _audio_context->sample_fmt;
    _audio_frame->sample_rate = _audio_context->sample_rate;
    error = av_channel_layout_copy(&_audio_frame->ch_layout, &_audio_context->ch_layout);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));
    error = av_frame_get_buffer(_audio_frame, 0);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _swr_context = swr_alloc();
    ERR_FAIL_NULL_V_MSG(_swr_context, FAILED, "failed to allocate libswresample context");

    error = swr_config_frame(_swr_context, _audio_frame, _raw_audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    error = swr_init(_swr_context);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    _packet = av_packet_alloc();

    error = avio_open(&_context->pb, p_base_path.utf8().get_data(), AVIO_FLAG_WRITE);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    error = avformat_write_header(_context, nullptr);
    ERR_FAIL_COND_V_MSG(error < 0, FAILED, av_err2str(error));

    return OK;
    #else
    return ERR_UNAVAILABLE;
    #endif
    }

    Error FFmpegMovieWriter::_write_frame(const Ref<Image> &p_frame_image, const void *p_audio_frame_block) {
    #ifdef FFMPEG_AVAILABLE
    ERR_FAIL_COND_V(!_write_image(p_frame_image), FAILED);
    ERR_FAIL_COND_V(!_write_audio(p_audio_frame_block), FAILED);

    return OK;
    #else
    return ERR_UNAVAILABLE;
    #endif
    }

    void FFmpegMovieWriter::_write_end() {
    #ifdef FFMPEG_AVAILABLE
    int error = avcodec_send_frame(_video_context, nullptr);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));

    ERR_FAIL_COND(!_write_packets(_video_context, _video_stream));

    // check for any remaining samples at the end of the stream
    if (swr_get_delay(_swr_context, _audio_frame->sample_rate) > 0) {
    error = av_frame_make_writable(_audio_frame);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));

    error = swr_convert_frame(_swr_context, _audio_frame, nullptr);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));

    _audio_frame->pts = _audio_pts;

    error = avcodec_send_frame(_audio_context, _audio_frame);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));
    }

    error = avcodec_send_frame(_audio_context, nullptr);
    ERR_FAIL_COND_MSG(error < 0, av_err2str(error));

    ERR_FAIL_COND(!_write_packets(_audio_context, _audio_stream));

    av_write_trailer(_context);

    avio_closep(&_context->pb);

    av_packet_free(&_packet);
    av_frame_free(&_raw_audio_frame);
    av_frame_free(&_audio_frame);
    av_frame_free(&_video_frame);
    av_frame_free(&_image_frame);
    swr_free(&_swr_context);
    sws_free_context(&_sws_context);
    avcodec_free_context(&_audio_context);
    avcodec_free_context(&_video_context);
    avformat_free_context(_context);
    #endif
    }

    #ifdef FFMPEG_AVAILABLE
    bool FFmpegMovieWriter::_write_packets(AVCodecContext *p_context, AVStream *p_stream) {
    while (avcodec_receive_packet(p_context, _packet) == 0) {
    av_packet_rescale_ts(_packet, p_context->time_base, p_stream->time_base);
    _packet->stream_index = p_stream->index;

    if (p_context->pix_fmt != AV_PIX_FMT_NONE) {
    __builtin_debugtrap();
    }

    int error = av_interleaved_write_frame(_context, _packet);
    CRASH_COND(error < 0);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));
    }

    return true;
    }

    bool FFmpegMovieWriter::_write_image(const Ref<Image> &p_frame_image) {
    DEV_ASSERT(p_frame_image->get_format() == Image::FORMAT_RGBA8);
    DEV_ASSERT(p_frame_image->get_width() == _image_frame->width);
    DEV_ASSERT(p_frame_image->get_height() == _image_frame->height);

    int error = av_frame_make_writable(_image_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));
    memcpy(_image_frame->data[0], p_frame_image->get_data().ptr(), p_frame_image->get_data_size());

    error = av_frame_make_writable(_video_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    error = sws_scale_frame(_sws_context, _video_frame, _image_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    _video_frame->pts = _video_pts;
    _video_pts++;

    error = avcodec_send_frame(_video_context, _video_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    return _write_packets(_video_context, _video_stream);
    }

    bool FFmpegMovieWriter::_write_audio(const void *p_audio_frame_block) {
    int error = av_frame_make_writable(_raw_audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));
    memcpy(_raw_audio_frame->data[0], p_audio_frame_block, _raw_audio_frame->nb_samples * sizeof(int32_t));

    error = swr_convert_frame(_swr_context, nullptr, _raw_audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    while (swr_get_delay(_swr_context, _audio_frame->sample_rate) >= _audio_frame->nb_samples) {
    error = av_frame_make_writable(_audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    error = swr_convert_frame(_swr_context, _audio_frame, nullptr);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));

    _audio_frame->pts = _audio_pts;
    _audio_pts += _audio_frame->nb_samples;

    error = avcodec_send_frame(_audio_context, _audio_frame);
    ERR_FAIL_COND_V_MSG(error < 0, false, av_err2str(error));
    }

    return _write_packets(_audio_context, _audio_stream);
    }
    #endif
  3. I'm aware the export dialog had a field where excluded files can be specified, but it's a bit basic. Ideally I'd love to have something like this:

    #ifdef DEMO_MODE
    [file list to exclude from demo mode]
    #else
    [file list to exclude from full version]
    #endif

  4. I'm aware the export dialog had a field where excluded files can be specified, but it's a bit basic. Ideally I'd love to have something like this:

    #ifdef DEMO_MODE
    [file list to exclude from demo mode]
    #else
    [file list to exclude from full version]
    #endif

  5. I'm aware the export dialog had a field where excluded files can be specified, but it's a bit basic. Ideally I'd love to have something like this:

    #ifdef DEMO_MODE
    [file list to exclude from demo mode]
    #else
    [file list to exclude from full version]
    #endif

  6. I'm aware the export dialog had a field where excluded files can be specified, but it's a bit basic. Ideally I'd love to have something like this:

    #ifdef DEMO_MODE
    [file list to exclude from demo mode]
    #else
    [file list to exclude from full version]
    #endif

  7. I'm aware the export dialog had a field where excluded files can be specified, but it's a bit basic. Ideally I'd love to have something like this:

    #ifdef DEMO_MODE
    [file list to exclude from demo mode]
    #else
    [file list to exclude from full version]
    #endif

  8. int
    openat2p(int dirfd, const char *path,
    int flags, mode_t mode)
    {
    #ifdef __linux__
    struct open_how how = {
    .flags = flags,
    .mode = mode,
    .resolve =
    RESOLVE_BENEATH |
    RESOLVE_NO_SYMLINKS |
    RESOLVE_NO_MAGICLINKS
    };
    #endif

    if (dirfd < 0) {
    errno = EBADF;
    return -1;
    }

    if (path == NULL) {
    errno = EFAULT;
    return -1;
    }

    #ifdef __linux__
    return syscall(SYS_openat2, dirfd, path, &how, sizeof(how));
    #else
    return openat(dirfd, path, flags, mode);
    #endif
    }

  9. int
    openat2p(int dirfd, const char *path,
    int flags, mode_t mode)
    {
    #ifdef __linux__
    struct open_how how = {
    .flags = flags,
    .mode = mode,
    .resolve =
    RESOLVE_BENEATH |
    RESOLVE_NO_SYMLINKS |
    RESOLVE_NO_MAGICLINKS
    };
    #endif

    if (dirfd < 0) {
    errno = EBADF;
    return -1;
    }

    if (path == NULL) {
    errno = EFAULT;
    return -1;
    }

    #ifdef __linux__
    return syscall(SYS_openat2, dirfd, path, &how, sizeof(how));
    #else
    return openat(dirfd, path, flags, mode);
    #endif
    }

  10. int
    openat2p(int dirfd, const char *path,
    int flags, mode_t mode)
    {
    #ifdef __linux__
    struct open_how how = {
    .flags = flags,
    .mode = mode,
    .resolve =
    RESOLVE_BENEATH |
    RESOLVE_NO_SYMLINKS |
    RESOLVE_NO_MAGICLINKS
    };
    #endif

    if (dirfd < 0) {
    errno = EBADF;
    return -1;
    }

    if (path == NULL) {
    errno = EFAULT;
    return -1;
    }

    #ifdef __linux__
    return syscall(SYS_openat2, dirfd, path, &how, sizeof(how));
    #else
    return openat(dirfd, path, flags, mode);
    #endif
    }

  11. int
    openat2p(int dirfd, const char *path,
    int flags, mode_t mode)
    {
    __linux__
    struct open_how how = {
    .flags = flags,
    .mode = mode,
    .resolve =
    RESOLVE_BENEATH |
    RESOLVE_NO_SYMLINKS |
    RESOLVE_NO_MAGICLINKS
    };

    if (dirfd < 0) {
    errno = EBADF;
    return -1;
    }

    if (path == NULL) {
    errno = EFAULT;
    return -1;
    }

    __linux__
    return syscall(SYS_openat2, dirfd, path, &how, sizeof(how));

    return openat(dirfd, path, flags, mode);

    }

  12. int
    openat2p(int dirfd, const char *path,
    int flags, mode_t mode)
    {
    #ifdef __linux__
    struct open_how how = {
    .flags = flags,
    .mode = mode,
    .resolve =
    RESOLVE_BENEATH |
    RESOLVE_NO_SYMLINKS |
    RESOLVE_NO_MAGICLINKS
    };
    #endif

    if (dirfd < 0) {
    errno = EBADF;
    return -1;
    }

    if (path == NULL) {
    errno = EFAULT;
    return -1;
    }

    #ifdef __linux__
    return syscall(SYS_openat2, dirfd, path, &how, sizeof(how));
    #else
    return openat(dirfd, path, flags, mode);
    #endif
    }

  13. @funkylab it’s really to do with it not being standardised more than anything else. Like what is the expectation of preprocessing the following file lol.h

    #ifndef foo
    #define foo
    #else
    #pragma once
    #endif
    #include "lol.h"
    Yo

    Is it a single “Yo” or two lines of “Yo”?

    If it was defined that it needed to be the first thing in a file following whitespace, I think i’f be fine with it.

  14. @funkylab it’s really to do with it not being standardised more than anything else. Like what is the expectation of preprocessing the following file lol.h

    #ifndef foo
    #define foo
    #else
    #pragma once
    #endif
    #include "lol.h"
    Yo

    Is it a single “Yo” or two lines of “Yo”?

    If it was defined that it needed to be the first thing in a file following whitespace, I think i’f be fine with it.

  15. @funkylab it’s really to do with it not being standardised more than anything else. Like what is the expectation of preprocessing the following file lol.h

    #ifndef foo
    #define foo
    #else
    #pragma once
    #endif
    #include "lol.h"
    Yo

    Is it a single “Yo” or two lines of “Yo”?

    If it was defined that it needed to be the first thing in a file following whitespace, I think i’f be fine with it.

  16. @funkylab it’s really to do with it not being standardised more than anything else. Like what is the expectation of preprocessing the following file lol.h

    #ifndef foo
    #define foo
    #else
    #pragma once
    #endif
    #include "lol.h"
    Yo

    Is it a single “Yo” or two lines of “Yo”?

    If it was defined that it needed to be the first thing in a file following whitespace, I think i’f be fine with it.

  17. @funkylab it’s really to do with it not being standardised more than anything else. Like what is the expectation of preprocessing the following file lol.h

    #ifndef foo
    #define foo
    #else
    #pragma once
    #endif
    #include "lol.h"
    Yo

    Is it a single “Yo” or two lines of “Yo”?

    If it was defined that it needed to be the first thing in a file following whitespace, I think i’f be fine with it.

  18. Geez, Apple. Get your house in order.

    ```swift
    #if targetEnvironment(simulator)
    import Foundation
    #else
    #if os(macOS)
    @preconcurrency import NetworkExtension
    #else
    import NetworkExtension
    #endif
    #endif
    ```

  19. Geez, Apple. Get your house in order.

    ```swift
    #if targetEnvironment(simulator)
    import Foundation
    #else
    #if os(macOS)
    @preconcurrency import NetworkExtension
    #else
    import NetworkExtension
    #endif
    #endif
    ```

  20. update: I did, that works great.

    but also, I really had to bite the bullet and parse #ifdef #else etc. so now I have a little stack machine set up.

  21. @draeand I don't even think it used the docs lol. For the record, if you're curious: // Prism state
    #ifdef USE_PRISM
    static PrismContext* g_prismCtx = nullptr;
    static PrismBackend* g_prismBackend = nullptr;
    #endif

    Then, // Screen reader output - uses async message to avoid blocking UI
    #ifdef USE_PRISM
    static std::string g_pendingSpeech;
    static bool g_speechInterrupt = true;

    void DoSpeak() {
    if (g_prismBackend && !g_pendingSpeech.empty()) {
    prism_backend_output(g_prismBackend, g_pendingSpeech.c_str(), g_speechInterrupt);
    g_pendingSpeech.clear();
    }
    }

    void Speak(const char* text, bool interrupt = true) {
    if (g_prismBackend && g_hwnd) {
    g_pendingSpeech = text;
    g_speechInterrupt = interrupt;
    PostMessage(g_hwnd, WM_SPEAK, 0, 0);
    }
    }

    void Speak(const std::string& text, bool interrupt = true) {
    Speak(text.c_str(), interrupt);
    }
    #else
    void DoSpeak() {}
    void Speak(const char*, bool = true) {}
    void Speak(const std::string&, bool = true) {}
    #endif

    and in the init funcs: // Initialize Prism for screen reader support
    #ifdef USE_PRISM
    bool InitPrism(HWND hwnd) {
    PrismConfig cfg = prism_config_init();
    cfg.hwnd = hwnd;

    g_prismCtx = prism_init(&cfg);
    if (!g_prismCtx) {
    return false;
    }

    g_prismBackend = prism_registry_acquire_best(g_prismCtx);
    if (!g_prismBackend) {
    return false;
    }

    PrismError err = prism_backend_initialize(g_prismBackend);
    if (err != PRISM_OK) {
    return false;
    }

    return true;
    }

    // Shutdown Prism
    void FreePrism() {
    if (g_prismBackend) {
    prism_backend_free(g_prismBackend);
    g_prismBackend = nullptr;
    }
    if (g_prismCtx) {
    prism_shutdown(g_prismCtx);
    g_prismCtx = nullptr;
    }
    }
    #else
    bool InitPrism(HWND) { return false; }
    void FreePrism() {}
    #endif

  22. @kabel42 error messages for macros are tame until people start abusing macros and specially N layer macros that each is conditional and holy i hate that

    but imo a simple `#ifdef PLATFORM_A /* some code for pa */ #else /* some fallback code */` is usually just fine
  23. bcm2835_vcaudio.c で

    sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE;

    のまま

    vcaudio_swvol_codec()

    *dst++ = htole16((aint_t)v);
    とBEのときだけひっくり返すのか、

    #if BYTE_ORDER == BIG_ENDIAN
    sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_BE;
    #else
    sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE;
    #endif

    とすべきなのか

  24. DECLARE_CONSTEXPR
    template<typename T>
    constexpr int f1(); // works

    template<typename T>
    inline int f1(); // also works

    template<>
    constexpr int f1<int>(){ return 1;}

    static int global = 2;
    template<>
    inline int f1<double>(){ return global;}

    constexpr int f2(); // here declaration must match definition
    constexpr int f2() { return 3; }

    int main() {
    constexpr auto v1 = f1<int>();
    auto const v2 = f1<double>();
    auto const v3 = f2();
    return v1 + v2 + v3;
    }

  25. @nixCraft

    thank you! You see it too, right?

    The desktop-revolution is ON. Hooray! 🥳
    What's gained by still using "the european mainstream non-open america-OS"?
    What powers "mobile-anything" devices?
    What powers all the "free-or-premium" online services?

    And modern gamers know if it runs on: #nix #kodi #arkos #foss #else? 💾 💠

    I mean:
    > I don't understand the question.
    > Who is Agi, and is FSD a new radical party?

    All the best! 🍀

  26. Täältä haarasta löytyi ne kaikki joiden korvaushakemukset vakuutusyhtiö hylkäsi!

    (Yllättävää oli kuitenkin se, että lohdutuspalkinto oli mattokauppa)

    #else #ohjelmointi #vakuutukset #huumori

  27. @christianselig man, i have an app with a single target, but with separate configs (Alpha, Debug, Release) and I’m adding ALPHA to the compiler flags and the highlighting has never worked: the `#if ALPHA` code DOES get executed, but the #else block is highlighted 🫠

  28. src/corelib/global/qsimd.h

    ```
    #if defined(Q_PROCESSOR_ARM) && defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(_M_ARM64)
    # include <arm_neon.h>
    # define QT_COMPILER_USES_neon 1
    #else
    # define QT_COMPILER_USES_neon -1
    #endif
    ```
    ってのがあるのに、なんでそこら中のソースで
    #if defined(__ARM_NEON__)
    しとるんや

  29. #Swift folks (especially @mattiem ):

    With Swift 6.2’s new concurrency checking/rejecting on Actor’s `static var …`, is it safe-enough to do something like this for dependency injection?

    ```swift
    struct Config {
    nonisolated(unsafe) private static var _shared: Self = .init()
    #if TESTING
    static var shared: Self {
    get { Self._shared }
    set { Self._shared = newValue }
    }
    #else
    static var shared: Self { Self._shared }
    #endif


    }
    ```

  30. As it happens, we still use CVS in our operating system project (there are reasons for doing this, but migration to git would indeed make sense).

    While working on our project, we occasionally have to do a full checkout of the whole codebase, which is several gigabytes. Over time, this operation has gotten very, very, very slow - I mean "2+ hours to perform a checkout" slow.

    This was getting quite ridiculous. Even though it's CVS, it shouldn't crawl like this. A quick build of CVS with debug symbols and sampling the "cvs server" process with Linux perf showed something peculiar: The code was spending the majority of the time inside one function.

    So what is this get_memnode() function? Turns out this is a support function from Gnulib that enables page-aligned memory allocations. (NOTE: I have no clue why CVS thinks doing page-aligned allocations is beneficial here - but here we are.)

    The code in question has support for three different backend allocators:
    1. mmap
    2. posix_memalign
    3. malloc

    Sounds nice, except that both 1 and 3 use a linked list to track the allocations. The get_memnode() function is called when deallocating memory to find out the original pointer to pass to the backend deallocation function: The node search code appears as:

    for (c = *p_next; c != NULL; p_next = &c->next, c = c->next)
    if (c->aligned_ptr == aligned_ptr)
    break;

    The get_memnode() function is called from pagealign_free():

    #if HAVE_MMAP
    if (munmap (aligned_ptr, get_memnode (aligned_ptr)) < 0)
    error (EXIT_FAILURE, errno, "Failed to unmap memory");
    #elif HAVE_POSIX_MEMALIGN
    free (aligned_ptr);
    #else
    free (get_memnode (aligned_ptr));
    #endif

    This is an O(n) operation. CVS must be allocating a huge number of small allocations, which will result in it spending most of the CPU time in get_memnode() trying to find the node to remove from the list.

    Why should we care? This is "just CVS" after all. Well, Gnulib is used in a lot of projects, not just CVS. While pagealign_alloc() is likely not the most used functionality, it can still end up hurting performance in many places.

    The obvious easy fix is to prefer the posix_memalign method over the other options (I quickly made this happen for my personal CVS build by adding tactical #undef HAVE_MMAP). Even better, the list code should be replaced with something more sensible. In fact, there is no need to store the original pointer in a list; a better solution is to allocate enough memory and store the pointer before the calculated aligned pointer. This way, the original pointer can be fetched from the negative offset of the pointer passed to pagealign_free(). This way, it will be O(1).

    I tried to report this to the Gnulib project, but I have trouble reaching gnu.org services currently. I'll be sure to do that once things recover.

    #opensource #development #bugstories

  31. CW: c is a serious programming language used by serious people

    if (4294967295u + 1 == 0) {
    puts("a");
    } else {
    puts("b");
    }

    #if 4294967295u + 1 == 0
    puts("a");
    #else
    puts("b");
    #endif

    /* output:
    a
    b
    */