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