vdi-cloud/tools/generate-h264-sample.c

55 lines
2.4 KiB
C

// Generate a deterministic 1440p H.264 clip without any display/capture dependency.
// Link against the isolated FFmpeg libavcodec/libavutil built for the terminal.
#include <stdio.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
static int write_packets(AVCodecContext *encoder, AVPacket *packet, FILE *output) {
int result;
while ((result = avcodec_receive_packet(encoder, packet)) == 0) {
if (fwrite(packet->data, 1, packet->size, output) != (size_t)packet->size) return -1;
av_packet_unref(packet);
}
return result == AVERROR(EAGAIN) || result == AVERROR_EOF ? 0 : result;
}
int main(int argc, char **argv) {
if (argc != 2) return 2;
const AVCodec *codec = avcodec_find_encoder_by_name("libx264");
AVCodecContext *encoder = avcodec_alloc_context3(codec);
AVFrame *frame = av_frame_alloc();
AVPacket *packet = av_packet_alloc();
FILE *output = fopen(argv[1], "wb");
if (!codec || !encoder || !frame || !packet || !output) return 1;
encoder->width = frame->width = 2560;
encoder->height = frame->height = 1440;
encoder->pix_fmt = frame->format = AV_PIX_FMT_YUV420P;
encoder->time_base = (AVRational){1, 30};
encoder->framerate = (AVRational){30, 1};
encoder->max_b_frames = 0;
encoder->thread_count = 2;
av_opt_set(encoder->priv_data, "preset", "ultrafast", 0);
av_opt_set(encoder->priv_data, "tune", "zerolatency", 0);
if (avcodec_open2(encoder, codec, NULL) < 0 || av_frame_get_buffer(frame, 32) < 0) return 1;
for (int i = 0; i < 60; i++) {
if (av_frame_make_writable(frame) < 0) return 1;
for (int y = 0; y < frame->height; y++) {
memset(frame->data[0] + y * frame->linesize[0], 32 + (y + i * 4) % 190, frame->width);
}
for (int plane = 1; plane < 3; plane++) {
for (int y = 0; y < frame->height / 2; y++) {
memset(frame->data[plane] + y * frame->linesize[plane], 128, frame->width / 2);
}
}
frame->pts = i;
if (avcodec_send_frame(encoder, frame) < 0 || write_packets(encoder, packet, output) < 0) return 1;
}
if (avcodec_send_frame(encoder, NULL) < 0 || write_packets(encoder, packet, output) < 0) return 1;
if (fclose(output) != 0) return 1;
av_packet_free(&packet);
av_frame_free(&frame);
avcodec_free_context(&encoder);
return 0;
}