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. 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
    ```

  21. 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
    ```

  22. 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
    ```

  23. 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.

  24. 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.