Generating MPEG4 videos with libav* and olive.c

#include <assert.h>
#include <stdio.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#define OLIVEC_IMPLEMENTATION
#include "olive.c"

int main(void) {
    int rc;

    const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    assert(codec);

    AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
    assert(codec_ctx);

#define FRAMERATE 25 

    codec_ctx->width = 352;
    codec_ctx->height = 288;
    codec_ctx->bit_rate = 40000;
    codec_ctx->framerate = (AVRational){FRAMERATE, 1};
    codec_ctx->time_base = (AVRational){1, 60000};
    codec_ctx->gop_size = 12;
    codec_ctx->max_b_frames = 1;
    codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;

    av_opt_set(codec_ctx->priv_data, "preset", "fast", 0);
    av_opt_set(codec_ctx->priv_data, "crf", "20", 0);

    rc = avcodec_open2(codec_ctx, codec, NULL);
    assert(rc == 0);

    AVFormatContext* fmt_ctx;
    rc = avformat_alloc_output_context2(&fmt_ctx, NULL, NULL, "out.mp4");
    assert(rc == 0);

    AVStream* stream = avformat_new_stream(fmt_ctx, NULL);
    assert(stream);

    rc = avcodec_parameters_from_context(stream->codecpar, codec_ctx);
    assert(rc == 0);

    if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
        fmt_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    }

    rc = avio_open(&fmt_ctx->pb, "out.mp4", AVIO_FLAG_WRITE);
    assert(rc == 0);
    rc = avformat_write_header(fmt_ctx, NULL);
    assert(rc == 0);

    AVPacket* packet = av_packet_alloc();

    AVFrame* frame = av_frame_alloc();
    assert(frame);
    frame->width = codec_ctx->width;
    frame->height = codec_ctx->height;
    frame->format = codec_ctx->pix_fmt;

    rc = av_frame_get_buffer(frame, 0);
    assert(rc == 0);

    uint8_t* src_data[4];
    uint8_t* dst_data[4];
    int src_linesize[4];
    int dst_linesize[4];
    av_image_alloc(src_data, src_linesize, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB32, 16);
    av_image_alloc(dst_data, dst_linesize, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P, 16);

    Olivec_Canvas oc = olivec_canvas((uint32_t*)src_data[0], codec_ctx->width, codec_ctx->height, codec_ctx->width);

    struct SwsContext* sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB32, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);

    int64_t duration = stream->time_base.den / stream->time_base.num / codec_ctx->framerate.num / codec_ctx->framerate.den;
    for (int findex = 0; findex < FRAMERATE*10; ++findex) {
        if (findex % 1000 == 0) fprintf(stderr, "%d\n", findex);
        rc = av_frame_make_writable(frame);
        assert(rc == 0);

        olivec_fill(oc, 0xFFFFFFFF);

        uint8_t a = 0xFF;
        uint8_t r = findex & 0xFF;
        uint8_t g = 0x00;
        uint8_t b = 0x00;
        uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;

        olivec_rect(oc, findex%codec_ctx->width, 10, 100, 100, color);
        sws_scale(sws_ctx, (const uint8_t* const*)src_data, src_linesize, 0, codec_ctx->height, dst_data, dst_linesize);

        for (int y = 0; y < codec_ctx->height; ++y) {
            memcpy(&frame->data[0][y * frame->linesize[0]], &dst_data[0][y * dst_linesize[0]], frame->linesize[0]);
        }
        for (int y = 0; y < codec_ctx->height/2; ++y) {
            memcpy(&frame->data[1][y * frame->linesize[1]], &dst_data[1][y * dst_linesize[1]], frame->linesize[1]);
            memcpy(&frame->data[2][y * frame->linesize[2]], &dst_data[2][y * dst_linesize[2]], frame->linesize[2]);
        }

        frame->pts = (int64_t)findex * duration;

        rc = avcodec_send_frame(codec_ctx, frame);
        assert(rc == 0);

        do {
            rc = avcodec_receive_packet(codec_ctx, packet);
            assert(rc == 0 || rc == AVERROR_EOF || rc == AVERROR(EAGAIN));
            if (rc < 0) {
                break;
            }

            rc = av_interleaved_write_frame(fmt_ctx, packet);
            assert(rc == 0);
            av_packet_unref(packet);
        } while (1);
    }

    // flushing the encoder
    rc = avcodec_send_frame(codec_ctx, NULL);
    assert(rc == 0);
    do {
        rc = avcodec_receive_packet(codec_ctx, packet);
        assert(rc == 0 || rc == AVERROR_EOF || rc == AVERROR(EAGAIN));
        if (rc < 0) {
            av_packet_unref(packet);
            break;
        }
        rc = av_interleaved_write_frame(fmt_ctx, packet);
        assert(rc == 0);
        av_packet_unref(packet);
    } while (1);


    av_packet_free(&packet);
    av_frame_free(&frame);

    av_write_trailer(fmt_ctx);
    avformat_close_input(&fmt_ctx);
    avformat_free_context(fmt_ctx);

    return 0;
}
        

Signing certificates with OpenSSL

Generating a self-sign certificate as the Certificate Authority (CA).
openssl req -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout ca.key.pem -days 365 -out ca.cert.pem
        
Generate a private key and a Certificate Signing Request (CSR) for someone.
openssl req -new -sha256 -newkey rsa:2048 -nodes -keyout rivten.key.pem -days 365 -out rivten.csr.pem
        
Checking the data with OpenSSL
openssl x509 -in ca.cert.pem -text -noout
openssl req -in rivten.csr.pem -text -noout
        
Signing the CSR as the CA. (Note: you should create a demoCA folder and a demoCA/index.txt file).
openssl ca -in rivten.csr.pem -out rivten.cert.pem -cert ca.cert.pem -keyfile ca.key.pem -outdir . -create_serial -policy policy_anything
        
Checking the signed certificate
openssl x509 -in rivten.cert.pem -text -noout
        
Verifying the chain (you can use another CAfile and see that it does not work).
openssl verify -show_chain -CAfile ca.cert.pem rivten.cert.pem
        

Building with CMake

cmake -B build -S . -DCMAKE_INSTALL_PREFIX=C:\Users\hugov\local\ -DCMAKE_PREFIX_PATH=C:\Users\hugov\local\ -DCMAKE_BUILD_TYPE=Release
cmake --build build --target install --config Release
        

Appending to a TeX macro

% The logic is the following:
% TeX encounters the first \expandafter, the next control sequence is \def, it puts it on the side for now.
% Then, the next token is \expandafter, the next control sequence is \x, it puts it on the side for now. The list of tokens on the side is <\def;\x>
% Then, the next token is \expandafter, the next control sequence is an opening curly brace. This cause the curly brace to be temporarily hidden. So TeX expands the next token and therefore evaluates \x (important: this just performs one expansion level). This and #1 is the content we want to put in \x now. Let's call it \new_x for this demonstration.
% No other tokens, so TeX takes the list of token and can now evaluate \def\x\new_x, which means define \x to be the new value of \x.
% To delve in more into \expandafter, see this tutorial: https://www.tug.org/TUGboat/Articles/tb09-1/tb20bechtolsheim.pdf

% A cool exercice might be to have another parameter to the addx macro which is the macro to which we should append to.
% This is a cool use-case for csname and endcsname. It might require more expandafter though.
\def\addx#1{\expandafter\def\expandafter\x\expandafter{\x #1}}

\def\x{\y}

\def\y{xx}

hello \x

\addx{\y}

\def\y{yy}

hello \x

\addx{c}

hello \x
\bye