change: UI and migrate to gtest

This commit is contained in:
2026-07-27 05:27:32 +08:00
parent dd5508e571
commit a84e75ef47
56 changed files with 4484 additions and 4949 deletions
+197 -197
View File
@@ -28,6 +28,7 @@
// render_with_params are touched (no sequence).
#include <assert.h>
#include <gtest/gtest.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@@ -51,13 +52,13 @@ static void make_tmpdir(void)
#if defined(_WIN32)
char base[MAX_PATH];
const DWORD len = GetTempPathA(MAX_PATH, base);
assert(len > 0 && len < MAX_PATH);
EXPECT_TRUE(len > 0 && len < MAX_PATH);
snprintf(g_tmpdir, sizeof(g_tmpdir), "%soakengine_encoding_test_%lu",
base, (unsigned long)GetCurrentProcessId());
assert(_mkdir(g_tmpdir) == 0);
EXPECT_TRUE(_mkdir(g_tmpdir) == 0);
#else
strcpy(g_tmpdir, "/tmp/oakengine_encoding_test_XXXXXX");
assert(mkdtemp(g_tmpdir) != NULL);
EXPECT_TRUE(mkdtemp(g_tmpdir) != NULL);
#endif
}
@@ -65,25 +66,25 @@ static void test_format_metadata(void)
{
char buf[256];
assert(oakengine_encoding_format_count() > 0);
EXPECT_TRUE(oakengine_encoding_format_count() > 0);
// Matroska
assert(oakengine_encoding_format_name(OAKENGINE_ENCODING_FORMAT_MATROSKA,
EXPECT_TRUE(oakengine_encoding_format_name(OAKENGINE_ENCODING_FORMAT_MATROSKA,
buf, sizeof(buf)) > 0);
assert(strstr(buf, "Matroska") != NULL);
assert(oakengine_encoding_format_extension(
EXPECT_TRUE(strstr(buf, "Matroska") != NULL);
EXPECT_TRUE(oakengine_encoding_format_extension(
OAKENGINE_ENCODING_FORMAT_MATROSKA, buf, sizeof(buf)) > 0);
assert(strcmp(buf, "mkv") == 0);
EXPECT_TRUE(strcmp(buf, "mkv") == 0);
// Invalid format
assert(oakengine_encoding_format_name(-1, buf, sizeof(buf)) == -1);
assert(oakengine_encoding_format_extension(9999, buf, sizeof(buf)) == -1);
assert(oakengine_encoding_format_video_codec_count(-1) == -1);
EXPECT_TRUE(oakengine_encoding_format_name(-1, buf, sizeof(buf)) == -1);
EXPECT_TRUE(oakengine_encoding_format_extension(9999, buf, sizeof(buf)) == -1);
EXPECT_TRUE(oakengine_encoding_format_video_codec_count(-1) == -1);
// MP4 carries H.264 video and AAC audio
const int vcount =
oakengine_encoding_format_video_codec_count(OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO);
assert(vcount > 0);
EXPECT_TRUE(vcount > 0);
int found_h264 = 0;
for (int i = 0; i < vcount; i++) {
if (oakengine_encoding_format_video_codec_at(
@@ -92,16 +93,16 @@ static void test_format_metadata(void)
found_h264 = 1;
}
}
assert(found_h264);
assert(oakengine_encoding_format_video_codec_at(
EXPECT_TRUE(found_h264);
EXPECT_TRUE(oakengine_encoding_format_video_codec_at(
OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO, vcount) == -1);
// WAV is audio-only and carries PCM
assert(oakengine_encoding_format_video_codec_count(
EXPECT_TRUE(oakengine_encoding_format_video_codec_count(
OAKENGINE_ENCODING_FORMAT_WAV) == 0);
const int acount = oakengine_encoding_format_audio_codec_count(
OAKENGINE_ENCODING_FORMAT_WAV);
assert(acount > 0);
EXPECT_TRUE(acount > 0);
int found_pcm = 0;
for (int i = 0; i < acount; i++) {
if (oakengine_encoding_format_audio_codec_at(
@@ -109,16 +110,16 @@ static void test_format_metadata(void)
found_pcm = 1;
}
}
assert(found_pcm);
EXPECT_TRUE(found_pcm);
// SRT is subtitles-only
assert(oakengine_encoding_format_subtitle_codec_count(
EXPECT_TRUE(oakengine_encoding_format_subtitle_codec_count(
OAKENGINE_ENCODING_FORMAT_SRT) > 0);
assert(oakengine_encoding_format_subtitle_codec_at(
EXPECT_TRUE(oakengine_encoding_format_subtitle_codec_at(
OAKENGINE_ENCODING_FORMAT_SRT, 0) >= 0);
assert(oakengine_encoding_format_subtitle_codec_at(
EXPECT_TRUE(oakengine_encoding_format_subtitle_codec_at(
OAKENGINE_ENCODING_FORMAT_SRT, -1) < 0);
assert(oakengine_encoding_format_audio_codec_count(
EXPECT_TRUE(oakengine_encoding_format_audio_codec_count(
OAKENGINE_ENCODING_FORMAT_SRT) == 0);
}
@@ -126,47 +127,47 @@ static void test_codec_metadata(void)
{
char buf[256];
assert(oakengine_encoding_codec_name(OAKENGINE_ENCODING_CODEC_H264, buf,
EXPECT_TRUE(oakengine_encoding_codec_name(OAKENGINE_ENCODING_CODEC_H264, buf,
sizeof(buf)) > 0);
assert(buf[0] != '\0');
assert(oakengine_encoding_codec_name(-1, buf, sizeof(buf)) == -1);
EXPECT_TRUE(buf[0] != '\0');
EXPECT_TRUE(oakengine_encoding_codec_name(-1, buf, sizeof(buf)) == -1);
assert(oakengine_encoding_codec_is_still_image(5 /* PNG */) == 1);
assert(oakengine_encoding_codec_is_still_image(
EXPECT_TRUE(oakengine_encoding_codec_is_still_image(5 /* PNG */) == 1);
EXPECT_TRUE(oakengine_encoding_codec_is_still_image(
OAKENGINE_ENCODING_CODEC_H264) == 0);
assert(oakengine_encoding_codec_is_lossless(OAKENGINE_ENCODING_CODEC_PCM) ==
EXPECT_TRUE(oakengine_encoding_codec_is_lossless(OAKENGINE_ENCODING_CODEC_PCM) ==
1);
assert(oakengine_encoding_codec_is_lossless(OAKENGINE_ENCODING_CODEC_AAC) ==
EXPECT_TRUE(oakengine_encoding_codec_is_lossless(OAKENGINE_ENCODING_CODEC_AAC) ==
0);
// Encoded pixel formats of H.264 in MP4: yuv420p is the preferred one
const int pcount = oakengine_encoding_pix_fmt_count(
OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO, OAKENGINE_ENCODING_CODEC_H264);
assert(pcount > 0);
assert(oakengine_encoding_pix_fmt_at(OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO,
EXPECT_TRUE(pcount > 0);
EXPECT_TRUE(oakengine_encoding_pix_fmt_at(OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO,
OAKENGINE_ENCODING_CODEC_H264, 0, buf,
sizeof(buf)) > 0);
assert(strcmp(buf, "yuv420p") == 0);
assert(oakengine_encoding_pix_fmt_at(OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO,
EXPECT_TRUE(strcmp(buf, "yuv420p") == 0);
EXPECT_TRUE(oakengine_encoding_pix_fmt_at(OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO,
OAKENGINE_ENCODING_CODEC_H264, pcount,
buf, sizeof(buf)) == -1);
assert(oakengine_encoding_pix_fmt_index(OAKENGINE_ENCODING_CODEC_H264,
EXPECT_TRUE(oakengine_encoding_pix_fmt_index(OAKENGINE_ENCODING_CODEC_H264,
"yuv420p") == 0);
assert(oakengine_encoding_pix_fmt_index(OAKENGINE_ENCODING_CODEC_H264,
EXPECT_TRUE(oakengine_encoding_pix_fmt_index(OAKENGINE_ENCODING_CODEC_H264,
"no-such-format") == 0);
assert(oakengine_encoding_pix_fmt_index(OAKENGINE_ENCODING_CODEC_H264,
EXPECT_TRUE(oakengine_encoding_pix_fmt_index(OAKENGINE_ENCODING_CODEC_H264,
NULL) == 0);
// Sample formats of PCM in WAV
const int scount = oakengine_encoding_sample_format_count(
OAKENGINE_ENCODING_FORMAT_WAV, OAKENGINE_ENCODING_CODEC_PCM);
assert(scount > 0);
EXPECT_TRUE(scount > 0);
for (int i = 0; i < scount; i++) {
assert(oakengine_encoding_sample_format_at(
EXPECT_TRUE(oakengine_encoding_sample_format_at(
OAKENGINE_ENCODING_FORMAT_WAV, OAKENGINE_ENCODING_CODEC_PCM,
i) >= 0);
}
assert(oakengine_encoding_sample_format_at(
EXPECT_TRUE(oakengine_encoding_sample_format_at(
OAKENGINE_ENCODING_FORMAT_WAV, OAKENGINE_ENCODING_CODEC_PCM,
scount) == -1);
}
@@ -175,20 +176,20 @@ static void test_filename_helpers(void)
{
char buf[4096];
assert(oakengine_encoding_filename_contains_digit_placeholder(
EXPECT_TRUE(oakengine_encoding_filename_contains_digit_placeholder(
"/tmp/out_[#####].png") == 1);
assert(oakengine_encoding_filename_contains_digit_placeholder(
EXPECT_TRUE(oakengine_encoding_filename_contains_digit_placeholder(
"/tmp/out.png") == 0);
assert(oakengine_encoding_filename_contains_digit_placeholder(NULL) == 0);
EXPECT_TRUE(oakengine_encoding_filename_contains_digit_placeholder(NULL) == 0);
assert(oakengine_encoding_image_sequence_digit_count(
EXPECT_TRUE(oakengine_encoding_image_sequence_digit_count(
"/tmp/out_[#####].png") == 5);
assert(oakengine_encoding_image_sequence_digit_count("/tmp/out.png") == 0);
EXPECT_TRUE(oakengine_encoding_image_sequence_digit_count("/tmp/out.png") == 0);
assert(oakengine_encoding_filename_remove_digit_placeholder(
EXPECT_TRUE(oakengine_encoding_filename_remove_digit_placeholder(
"/tmp/out_[#####].png", buf, sizeof(buf)) > 0);
assert(strstr(buf, "[#####]") == NULL);
assert(strstr(buf, ".png") != NULL);
EXPECT_TRUE(strstr(buf, "[#####]") == NULL);
EXPECT_TRUE(strstr(buf, ".png") != NULL);
}
static void test_generate_matrix(void)
@@ -196,37 +197,37 @@ static void test_generate_matrix(void)
float m[16];
// Fit with matching dimensions is the identity
assert(oakengine_encoding_generate_matrix(OAKENGINE_ENCODING_SCALING_FIT,
EXPECT_TRUE(oakengine_encoding_generate_matrix(OAKENGINE_ENCODING_SCALING_FIT,
1920, 1080, 1920, 1080,
m) == OAKENGINE_OK);
const float identity[16] = { 1, 0, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 0, 0, 1 };
for (int i = 0; i < 16; i++) {
assert(fabsf(m[i] - identity[i]) < 1e-6f);
EXPECT_TRUE(fabsf(m[i] - identity[i]) < 1e-6f);
}
// Stretch is the identity transform (the preview is normalized device
// coordinates; stretching needs no matrix)
assert(oakengine_encoding_generate_matrix(OAKENGINE_ENCODING_SCALING_STRETCH,
EXPECT_TRUE(oakengine_encoding_generate_matrix(OAKENGINE_ENCODING_SCALING_STRETCH,
960, 540, 1920, 1080,
m) == OAKENGINE_OK);
for (int i = 0; i < 16; i++) {
assert(fabsf(m[i] - identity[i]) < 1e-6f);
EXPECT_TRUE(fabsf(m[i] - identity[i]) < 1e-6f);
}
// Fit into a wider-than-source frame pillarboxes: x scale shrinks to
// source_ar/export_ar
assert(oakengine_encoding_generate_matrix(OAKENGINE_ENCODING_SCALING_FIT,
EXPECT_TRUE(oakengine_encoding_generate_matrix(OAKENGINE_ENCODING_SCALING_FIT,
1920, 1080, 1920, 540,
m) == OAKENGINE_OK);
const float expected_x = (1920.0f / 1080.0f) / (1920.0f / 540.0f);
assert(fabsf(m[0] - expected_x) < 1e-5f);
assert(fabsf(m[5] - 1.0f) < 1e-6f);
EXPECT_TRUE(fabsf(m[0] - expected_x) < 1e-5f);
EXPECT_TRUE(fabsf(m[5] - 1.0f) < 1e-6f);
// Invalid arguments
assert(oakengine_encoding_generate_matrix(-1, 1, 1, 1, 1,
EXPECT_TRUE(oakengine_encoding_generate_matrix(-1, 1, 1, 1, 1,
m) == OAKENGINE_E_INVALID);
assert(oakengine_encoding_generate_matrix(OAKENGINE_ENCODING_SCALING_FIT, 0,
EXPECT_TRUE(oakengine_encoding_generate_matrix(OAKENGINE_ENCODING_SCALING_FIT, 0,
1, 1, 1,
m) == OAKENGINE_E_INVALID);
}
@@ -236,26 +237,26 @@ static void test_params_handle(void)
char buf[1024];
OakEngineEncodingParams *p = oakengine_encoding_params_create();
assert(p != NULL);
EXPECT_TRUE(p != NULL);
// Fresh handle: nothing enabled, format unset
assert(oakengine_encoding_params_is_valid(p) == 0);
assert(oakengine_encoding_params_format(p) == -1);
assert(oakengine_encoding_params_video_enabled(p) == 0);
assert(oakengine_encoding_params_audio_enabled(p) == 0);
assert(oakengine_encoding_params_subtitles_enabled(p) == 0);
assert(oakengine_encoding_params_has_custom_range(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_is_valid(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_format(p) == -1);
EXPECT_TRUE(oakengine_encoding_params_video_enabled(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_audio_enabled(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_subtitles_enabled(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_has_custom_range(p) == 0);
// Filename / format roundtrip
assert(oakengine_encoding_params_set_filename(p, "/tmp/out.mp4") ==
EXPECT_TRUE(oakengine_encoding_params_set_filename(p, "/tmp/out.mp4") ==
OAKENGINE_OK);
assert(oakengine_encoding_params_filename(p, buf, sizeof(buf)) > 0);
assert(strcmp(buf, "/tmp/out.mp4") == 0);
assert(oakengine_encoding_params_set_format(
EXPECT_TRUE(oakengine_encoding_params_filename(p, buf, sizeof(buf)) > 0);
EXPECT_TRUE(strcmp(buf, "/tmp/out.mp4") == 0);
EXPECT_TRUE(oakengine_encoding_params_set_format(
p, OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO) == OAKENGINE_OK);
assert(oakengine_encoding_params_format(p) ==
EXPECT_TRUE(oakengine_encoding_params_format(p) ==
OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO);
assert(oakengine_encoding_params_set_format(p, 9999) ==
EXPECT_TRUE(oakengine_encoding_params_set_format(p, 9999) ==
OAKENGINE_E_INVALID);
// Video roundtrip
@@ -270,132 +271,132 @@ static void test_params_handle(void)
v.interlacing = OAKENGINE_ENCODING_INTERLACE_BOTTOM_FIRST;
v.color_range = OAKENGINE_ENCODING_COLOR_RANGE_FULL;
v.divider = 1;
assert(oakengine_encoding_params_enable_video(
EXPECT_TRUE(oakengine_encoding_params_enable_video(
p, &v, OAKENGINE_ENCODING_CODEC_H264) == OAKENGINE_OK);
assert(oakengine_encoding_params_is_valid(p) == 1);
assert(oakengine_encoding_params_video_enabled(p) == 1);
assert(oakengine_encoding_params_video_codec(p) ==
EXPECT_TRUE(oakengine_encoding_params_is_valid(p) == 1);
EXPECT_TRUE(oakengine_encoding_params_video_enabled(p) == 1);
EXPECT_TRUE(oakengine_encoding_params_video_codec(p) ==
OAKENGINE_ENCODING_CODEC_H264);
assert(oakengine_encoding_params_enable_video(p, NULL, 1) ==
EXPECT_TRUE(oakengine_encoding_params_enable_video(p, NULL, 1) ==
OAKENGINE_E_INVALID);
assert(oakengine_encoding_params_enable_video(p, &v, 9999) ==
EXPECT_TRUE(oakengine_encoding_params_enable_video(p, &v, 9999) ==
OAKENGINE_E_INVALID);
oak_video_params back = {};
assert(oakengine_encoding_params_get_video_params(p, &back) ==
EXPECT_TRUE(oakengine_encoding_params_get_video_params(p, &back) ==
OAKENGINE_OK);
assert(back.width == 1920 && back.height == 1080);
assert(back.time_base_num == 1001 && back.time_base_den == 30000);
assert(back.pixel_aspect_num == 1 && back.pixel_aspect_den == 1);
assert(back.interlacing == OAKENGINE_ENCODING_INTERLACE_BOTTOM_FIRST);
assert(back.color_range == OAKENGINE_ENCODING_COLOR_RANGE_FULL);
EXPECT_TRUE(back.width == 1920 && back.height == 1080);
EXPECT_TRUE(back.time_base_num == 1001 && back.time_base_den == 30000);
EXPECT_TRUE(back.pixel_aspect_num == 1 && back.pixel_aspect_den == 1);
EXPECT_TRUE(back.interlacing == OAKENGINE_ENCODING_INTERLACE_BOTTOM_FIRST);
EXPECT_TRUE(back.color_range == OAKENGINE_ENCODING_COLOR_RANGE_FULL);
// Audio roundtrip
assert(oakengine_encoding_params_enable_audio(p, 48000, 0x3, 4,
EXPECT_TRUE(oakengine_encoding_params_enable_audio(p, 48000, 0x3, 4,
OAKENGINE_ENCODING_CODEC_AAC) ==
OAKENGINE_OK);
assert(oakengine_encoding_params_audio_enabled(p) == 1);
assert(oakengine_encoding_params_audio_codec(p) ==
EXPECT_TRUE(oakengine_encoding_params_audio_enabled(p) == 1);
EXPECT_TRUE(oakengine_encoding_params_audio_codec(p) ==
OAKENGINE_ENCODING_CODEC_AAC);
int sample_rate = 0, sample_format = 0;
uint64_t layout = 0;
assert(oakengine_encoding_params_get_audio_params(p, &sample_rate, &layout,
EXPECT_TRUE(oakengine_encoding_params_get_audio_params(p, &sample_rate, &layout,
&sample_format) ==
OAKENGINE_OK);
assert(sample_rate == 48000 && layout == 0x3 && sample_format == 4);
assert(oakengine_encoding_params_enable_audio(p, 0, 0x3, 4, 0) ==
EXPECT_TRUE(sample_rate == 48000 && layout == 0x3 && sample_format == 4);
EXPECT_TRUE(oakengine_encoding_params_enable_audio(p, 0, 0x3, 4, 0) ==
OAKENGINE_E_INVALID);
// Subtitles (embedded, then sidecar)
assert(oakengine_encoding_params_enable_subtitles(
EXPECT_TRUE(oakengine_encoding_params_enable_subtitles(
p, OAKENGINE_ENCODING_CODEC_SRT) == OAKENGINE_OK);
assert(oakengine_encoding_params_subtitles_enabled(p) == 1);
assert(oakengine_encoding_params_subtitles_are_sidecar(p) == 0);
assert(oakengine_encoding_params_subtitles_codec(p) ==
EXPECT_TRUE(oakengine_encoding_params_subtitles_enabled(p) == 1);
EXPECT_TRUE(oakengine_encoding_params_subtitles_are_sidecar(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_subtitles_codec(p) ==
OAKENGINE_ENCODING_CODEC_SRT);
assert(oakengine_encoding_params_enable_sidecar_subtitles(
EXPECT_TRUE(oakengine_encoding_params_enable_sidecar_subtitles(
p, OAKENGINE_ENCODING_FORMAT_SRT,
OAKENGINE_ENCODING_CODEC_SRT) == OAKENGINE_OK);
assert(oakengine_encoding_params_subtitles_are_sidecar(p) == 1);
assert(oakengine_encoding_params_subtitles_sidecar_format(p) ==
EXPECT_TRUE(oakengine_encoding_params_subtitles_are_sidecar(p) == 1);
EXPECT_TRUE(oakengine_encoding_params_subtitles_sidecar_format(p) ==
OAKENGINE_ENCODING_FORMAT_SRT);
// Scalar setters/getters
oakengine_encoding_params_set_video_bit_rate(p, 8000000);
assert(oakengine_encoding_params_video_bit_rate(p) == 8000000);
EXPECT_TRUE(oakengine_encoding_params_video_bit_rate(p) == 8000000);
oakengine_encoding_params_set_video_min_bit_rate(p, 1000);
assert(oakengine_encoding_params_video_min_bit_rate(p) == 1000);
EXPECT_TRUE(oakengine_encoding_params_video_min_bit_rate(p) == 1000);
oakengine_encoding_params_set_video_max_bit_rate(p, 16000000);
assert(oakengine_encoding_params_video_max_bit_rate(p) == 16000000);
EXPECT_TRUE(oakengine_encoding_params_video_max_bit_rate(p) == 16000000);
oakengine_encoding_params_set_video_buffer_size(p, 2000000);
assert(oakengine_encoding_params_video_buffer_size(p) == 2000000);
EXPECT_TRUE(oakengine_encoding_params_video_buffer_size(p) == 2000000);
oakengine_encoding_params_set_video_threads(p, 4);
assert(oakengine_encoding_params_video_threads(p) == 4);
EXPECT_TRUE(oakengine_encoding_params_video_threads(p) == 4);
oakengine_encoding_params_set_audio_bit_rate(p, 320000);
assert(oakengine_encoding_params_audio_bit_rate(p) == 320000);
EXPECT_TRUE(oakengine_encoding_params_audio_bit_rate(p) == 320000);
assert(oakengine_encoding_params_set_video_pix_fmt(p, "yuv420p") ==
EXPECT_TRUE(oakengine_encoding_params_set_video_pix_fmt(p, "yuv420p") ==
OAKENGINE_OK);
assert(oakengine_encoding_params_video_pix_fmt(p, buf, sizeof(buf)) > 0);
assert(strcmp(buf, "yuv420p") == 0);
EXPECT_TRUE(oakengine_encoding_params_video_pix_fmt(p, buf, sizeof(buf)) > 0);
EXPECT_TRUE(strcmp(buf, "yuv420p") == 0);
oakengine_encoding_params_set_video_is_image_sequence(p, 1);
assert(oakengine_encoding_params_video_is_image_sequence(p) == 1);
EXPECT_TRUE(oakengine_encoding_params_video_is_image_sequence(p) == 1);
oakengine_encoding_params_set_video_is_image_sequence(p, 0);
assert(oakengine_encoding_params_video_is_image_sequence(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_video_is_image_sequence(p) == 0);
assert(oakengine_encoding_params_set_color_transform(p, "sRGB OETF") ==
EXPECT_TRUE(oakengine_encoding_params_set_color_transform(p, "sRGB OETF") ==
OAKENGINE_OK);
assert(oakengine_encoding_params_color_transform_output(p, buf,
EXPECT_TRUE(oakengine_encoding_params_color_transform_output(p, buf,
sizeof(buf)) > 0);
assert(strcmp(buf, "sRGB OETF") == 0);
EXPECT_TRUE(strcmp(buf, "sRGB OETF") == 0);
oakengine_encoding_params_set_export_length(p, 10, 1);
int num = 0, den = 0;
assert(oakengine_encoding_params_get_export_length(p, &num, &den) ==
EXPECT_TRUE(oakengine_encoding_params_get_export_length(p, &num, &den) ==
OAKENGINE_OK);
assert(num == 10 && den == 1);
EXPECT_TRUE(num == 10 && den == 1);
// Custom range
oakengine_encoding_params_set_custom_range(p, 1, 1, 5, 1);
assert(oakengine_encoding_params_has_custom_range(p) == 1);
EXPECT_TRUE(oakengine_encoding_params_has_custom_range(p) == 1);
int64_t in_num = 0, in_den = 0, out_num = 0, out_den = 0;
assert(oakengine_encoding_params_get_custom_range(p, &in_num, &in_den,
EXPECT_TRUE(oakengine_encoding_params_get_custom_range(p, &in_num, &in_den,
&out_num,
&out_den) == OAKENGINE_OK);
assert(in_num == 1 && in_den == 1 && out_num == 5 && out_den == 1);
EXPECT_TRUE(in_num == 1 && in_den == 1 && out_num == 5 && out_den == 1);
// Scaling method
assert(oakengine_encoding_params_set_video_scaling_method(
EXPECT_TRUE(oakengine_encoding_params_set_video_scaling_method(
p, OAKENGINE_ENCODING_SCALING_CROP) == OAKENGINE_OK);
assert(oakengine_encoding_params_video_scaling_method(p) ==
EXPECT_TRUE(oakengine_encoding_params_video_scaling_method(p) ==
OAKENGINE_ENCODING_SCALING_CROP);
assert(oakengine_encoding_params_set_video_scaling_method(p, 42) ==
EXPECT_TRUE(oakengine_encoding_params_set_video_scaling_method(p, 42) ==
OAKENGINE_E_INVALID);
// Video options
assert(oakengine_encoding_params_video_option(p, "crf", buf,
EXPECT_TRUE(oakengine_encoding_params_video_option(p, "crf", buf,
sizeof(buf)) ==
OAKENGINE_E_NOT_FOUND);
assert(oakengine_encoding_params_set_video_option(p, "crf", "18") ==
EXPECT_TRUE(oakengine_encoding_params_set_video_option(p, "crf", "18") ==
OAKENGINE_OK);
assert(oakengine_encoding_params_video_option(p, "crf", buf,
EXPECT_TRUE(oakengine_encoding_params_video_option(p, "crf", buf,
sizeof(buf)) > 0);
assert(strcmp(buf, "18") == 0);
EXPECT_TRUE(strcmp(buf, "18") == 0);
// Disables
oakengine_encoding_params_disable_subtitles(p);
assert(oakengine_encoding_params_subtitles_enabled(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_subtitles_enabled(p) == 0);
oakengine_encoding_params_disable_video(p);
assert(oakengine_encoding_params_video_enabled(p) == 0);
assert(oakengine_encoding_params_get_video_params(p, &back) ==
EXPECT_TRUE(oakengine_encoding_params_video_enabled(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_get_video_params(p, &back) ==
OAKENGINE_E_STATE);
oakengine_encoding_params_disable_audio(p);
assert(oakengine_encoding_params_audio_enabled(p) == 0);
EXPECT_TRUE(oakengine_encoding_params_audio_enabled(p) == 0);
// NULL safety
oakengine_encoding_params_destroy(NULL);
assert(oakengine_encoding_params_is_valid(NULL) == 0);
EXPECT_TRUE(oakengine_encoding_params_is_valid(NULL) == 0);
oakengine_encoding_params_destroy(p);
}
@@ -405,22 +406,22 @@ static void test_preset_files(void)
char buf[1024];
// Preset directory listing is readable (may be empty in the sandbox)
assert(oakengine_encoding_preset_path(buf, sizeof(buf)) > 0);
EXPECT_TRUE(oakengine_encoding_preset_path(buf, sizeof(buf)) > 0);
const int count = oakengine_encoding_preset_count();
assert(count >= 0);
EXPECT_TRUE(count >= 0);
for (int i = 0; i < count; i++) {
assert(oakengine_encoding_preset_name(i, buf, sizeof(buf)) > 0);
EXPECT_TRUE(oakengine_encoding_preset_name(i, buf, sizeof(buf)) > 0);
}
assert(oakengine_encoding_preset_name(count, buf, sizeof(buf)) == -1);
EXPECT_TRUE(oakengine_encoding_preset_name(count, buf, sizeof(buf)) == -1);
// Save/load roundtrip through a temp file
char path[4096];
snprintf(path, sizeof(path), "%s/preset.xml", g_tmpdir);
OakEngineEncodingParams *p = oakengine_encoding_params_create();
assert(oakengine_encoding_params_set_filename(p, "/tmp/out.mp4") ==
EXPECT_TRUE(oakengine_encoding_params_set_filename(p, "/tmp/out.mp4") ==
OAKENGINE_OK);
assert(oakengine_encoding_params_set_format(
EXPECT_TRUE(oakengine_encoding_params_set_format(
p, OAKENGINE_ENCODING_FORMAT_MPEG4_VIDEO) == OAKENGINE_OK);
oak_video_params v = {};
v.width = 1280;
@@ -433,59 +434,59 @@ static void test_preset_files(void)
v.interlacing = OAKENGINE_ENCODING_INTERLACE_NONE;
v.color_range = OAKENGINE_ENCODING_COLOR_RANGE_LIMITED;
v.divider = 1;
assert(oakengine_encoding_params_enable_video(
EXPECT_TRUE(oakengine_encoding_params_enable_video(
p, &v, OAKENGINE_ENCODING_CODEC_H264) == OAKENGINE_OK);
assert(oakengine_encoding_params_set_video_option(p, "crf", "20") ==
EXPECT_TRUE(oakengine_encoding_params_set_video_option(p, "crf", "20") ==
OAKENGINE_OK);
assert(oakengine_encoding_params_save_file(p, path) == OAKENGINE_OK);
EXPECT_TRUE(oakengine_encoding_params_save_file(p, path) == OAKENGINE_OK);
oakengine_encoding_params_destroy(p);
OakEngineEncodingParams *q = oakengine_encoding_params_create();
assert(oakengine_encoding_params_load_file(q, path) == OAKENGINE_OK);
assert(oakengine_encoding_params_video_enabled(q) == 1);
assert(oakengine_encoding_params_video_codec(q) ==
EXPECT_TRUE(oakengine_encoding_params_load_file(q, path) == OAKENGINE_OK);
EXPECT_TRUE(oakengine_encoding_params_video_enabled(q) == 1);
EXPECT_TRUE(oakengine_encoding_params_video_codec(q) ==
OAKENGINE_ENCODING_CODEC_H264);
oak_video_params back = {};
assert(oakengine_encoding_params_get_video_params(q, &back) ==
EXPECT_TRUE(oakengine_encoding_params_get_video_params(q, &back) ==
OAKENGINE_OK);
assert(back.width == 1280 && back.height == 720);
assert(back.time_base_num == 1 && back.time_base_den == 25);
assert(oakengine_encoding_params_video_option(q, "crf", buf,
EXPECT_TRUE(back.width == 1280 && back.height == 720);
EXPECT_TRUE(back.time_base_num == 1 && back.time_base_den == 25);
EXPECT_TRUE(oakengine_encoding_params_video_option(q, "crf", buf,
sizeof(buf)) > 0);
assert(strcmp(buf, "20") == 0);
EXPECT_TRUE(strcmp(buf, "20") == 0);
oakengine_encoding_params_destroy(q);
// Loading a nonexistent file fails
OakEngineEncodingParams *r = oakengine_encoding_params_create();
assert(oakengine_encoding_params_load_file(r, "/no/such/file.xml") ==
EXPECT_TRUE(oakengine_encoding_params_load_file(r, "/no/such/file.xml") ==
OAKENGINE_E_FAILED);
oakengine_encoding_params_destroy(r);
// Bad arguments
assert(oakengine_encoding_params_save_file(NULL, path) ==
EXPECT_TRUE(oakengine_encoding_params_save_file(NULL, path) ==
OAKENGINE_E_INVALID);
}
static void test_last_used_and_render_errors(void)
{
// NULL sequence: no last-used params, no-op setter
assert(oakengine_encoding_params_get_last_used(NULL) == NULL);
EXPECT_TRUE(oakengine_encoding_params_get_last_used(NULL) == NULL);
oakengine_encoding_params_set_last_used(NULL, NULL);
// render_with_params without a valid sequence/params fails cleanly
assert(oakengine_export_render_with_params(NULL, NULL) ==
EXPECT_TRUE(oakengine_export_render_with_params(NULL, NULL) ==
OAKENGINE_E_INVALID);
OakEngineEncodingParams *p = oakengine_encoding_params_create();
assert(oakengine_export_render_with_params(NULL, p) ==
EXPECT_TRUE(oakengine_export_render_with_params(NULL, p) ==
OAKENGINE_E_INVALID);
// Nothing enabled on the handle
assert(oakengine_export_render_with_params(
EXPECT_TRUE(oakengine_export_render_with_params(
reinterpret_cast<OakEngineSequence *>(p), p) ==
OAKENGINE_E_INVALID);
oakengine_encoding_params_destroy(p);
// Audio recording requires an enabled audio track on the handle
assert(oakengine_encoding_start_audio_recording(NULL, NULL, 0) ==
EXPECT_TRUE(oakengine_encoding_start_audio_recording(NULL, NULL, 0) ==
OAKENGINE_E_INVALID);
}
@@ -496,61 +497,61 @@ static void test_video_params_statics(void)
// Standard frame rates
const int fr_count = oakengine_video_params_supported_frame_rate_count();
assert(fr_count > 0);
EXPECT_TRUE(fr_count > 0);
for (int i = 0; i < fr_count; i++) {
assert(oakengine_video_params_supported_frame_rate_at(i, &num, &den) ==
EXPECT_TRUE(oakengine_video_params_supported_frame_rate_at(i, &num, &den) ==
OAKENGINE_OK);
assert(num > 0 && den > 0);
EXPECT_TRUE(num > 0 && den > 0);
}
assert(oakengine_video_params_supported_frame_rate_at(fr_count, &num,
EXPECT_TRUE(oakengine_video_params_supported_frame_rate_at(fr_count, &num,
&den) ==
OAKENGINE_E_INVALID);
// 24000/1001 prints as 23.976...
assert(oakengine_video_params_frame_rate_to_string(24000, 1001, buf,
EXPECT_TRUE(oakengine_video_params_frame_rate_to_string(24000, 1001, buf,
sizeof(buf)) > 0);
assert(strstr(buf, "23.97") != NULL);
EXPECT_TRUE(strstr(buf, "23.97") != NULL);
// Standard pixel aspects: the first one is square (1:1)
const int pa_count = oakengine_video_params_standard_pixel_aspect_count();
assert(pa_count > 0);
assert(oakengine_video_params_standard_pixel_aspect_at(0, &num, &den) ==
EXPECT_TRUE(pa_count > 0);
EXPECT_TRUE(oakengine_video_params_standard_pixel_aspect_at(0, &num, &den) ==
OAKENGINE_OK);
assert(num == 1 && den == 1);
assert(oakengine_video_params_standard_pixel_aspect_name(0, buf,
EXPECT_TRUE(num == 1 && den == 1);
EXPECT_TRUE(oakengine_video_params_standard_pixel_aspect_name(0, buf,
sizeof(buf)) > 0);
assert(buf[0] != '\0');
assert(oakengine_video_params_standard_pixel_aspect_at(pa_count, &num,
EXPECT_TRUE(buf[0] != '\0');
EXPECT_TRUE(oakengine_video_params_standard_pixel_aspect_at(pa_count, &num,
&den) ==
OAKENGINE_E_INVALID);
// Custom PAR label template
assert(oakengine_video_params_format_pixel_aspect_ratio_string(
EXPECT_TRUE(oakengine_video_params_format_pixel_aspect_ratio_string(
"Custom (%1)", 32, 27, buf, sizeof(buf)) > 0);
assert(strstr(buf, "Custom") != NULL);
EXPECT_TRUE(strstr(buf, "Custom") != NULL);
// Dividers
const int div_count = oakengine_video_params_supported_divider_count();
assert(div_count > 0);
EXPECT_TRUE(div_count > 0);
for (int i = 0; i < div_count; i++) {
const int d = oakengine_video_params_supported_divider_at(i);
assert(d > 0);
assert(oakengine_video_params_divider_name(d, buf, sizeof(buf)) > 0);
EXPECT_TRUE(d > 0);
EXPECT_TRUE(oakengine_video_params_divider_name(d, buf, sizeof(buf)) > 0);
}
assert(oakengine_video_params_supported_divider_at(div_count) == -1);
EXPECT_TRUE(oakengine_video_params_supported_divider_at(div_count) == -1);
// Pixel format names: some entry must be non-empty
assert(oakengine_video_params_pixel_format_name(8, buf, sizeof(buf)) > 0);
EXPECT_TRUE(oakengine_video_params_pixel_format_name(8, buf, sizeof(buf)) > 0);
// Float detection (8-bit integer formats are not float)
assert(oakengine_video_params_format_is_float(0) == 0);
EXPECT_TRUE(oakengine_video_params_format_is_float(0) == 0);
// Effective (divider-scaled) size
int w = 0, h = 0;
assert(oakengine_video_params_effective_size(1920, 1080, 2, &w, &h) ==
EXPECT_TRUE(oakengine_video_params_effective_size(1920, 1080, 2, &w, &h) ==
OAKENGINE_OK);
assert(w == 960 && h == 540);
assert(oakengine_video_params_effective_size(0, 1080, 2, &w, &h) ==
EXPECT_TRUE(w == 960 && h == 540);
EXPECT_TRUE(oakengine_video_params_effective_size(0, 1080, 2, &w, &h) ==
OAKENGINE_E_INVALID);
}
@@ -561,43 +562,43 @@ static void test_video_params_pod(void)
oak_video_params p, q;
// make fills every field
assert(oakengine_video_params_make(&p, 1920, 1080, 1001, 30000, 0, 1, 1,
EXPECT_TRUE(oakengine_video_params_make(&p, 1920, 1080, 1001, 30000, 0, 1, 1,
0, 0, 2) == OAKENGINE_OK);
assert(p.width == 1920 && p.height == 1080);
assert(p.time_base_num == 1001 && p.time_base_den == 30000);
assert(p.pixel_aspect_num == 1 && p.pixel_aspect_den == 1);
assert(p.divider == 2);
assert(oakengine_video_params_make(NULL, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1) ==
EXPECT_TRUE(p.width == 1920 && p.height == 1080);
EXPECT_TRUE(p.time_base_num == 1001 && p.time_base_den == 30000);
EXPECT_TRUE(p.pixel_aspect_num == 1 && p.pixel_aspect_den == 1);
EXPECT_TRUE(p.divider == 2);
EXPECT_TRUE(oakengine_video_params_make(NULL, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1) ==
OAKENGINE_E_INVALID);
// equal: identical PODs match, any single-field difference does not
q = p;
assert(oakengine_video_params_equal(&p, &q) == 1);
assert(oakengine_video_params_equal(&p, NULL) == 0);
assert(oakengine_video_params_equal(NULL, &q) == 0);
EXPECT_TRUE(oakengine_video_params_equal(&p, &q) == 1);
EXPECT_TRUE(oakengine_video_params_equal(&p, NULL) == 0);
EXPECT_TRUE(oakengine_video_params_equal(NULL, &q) == 0);
q.divider = 1;
assert(oakengine_video_params_equal(&p, &q) == 0);
EXPECT_TRUE(oakengine_video_params_equal(&p, &q) == 0);
q = p;
q.interlacing = 1;
assert(oakengine_video_params_equal(&p, &q) == 0);
EXPECT_TRUE(oakengine_video_params_equal(&p, &q) == 0);
// is_valid: positive dimensions + in-range format passes; zero
// dimensions or an out-of-range format fail
assert(oakengine_video_params_is_valid(&p) == 1);
assert(oakengine_video_params_is_valid(NULL) == 0);
EXPECT_TRUE(oakengine_video_params_is_valid(&p) == 1);
EXPECT_TRUE(oakengine_video_params_is_valid(NULL) == 0);
q = p;
q.width = 0;
assert(oakengine_video_params_is_valid(&q) == 0);
EXPECT_TRUE(oakengine_video_params_is_valid(&q) == 0);
q = p;
q.format = -1; // olive::PixelFormat::invalid
assert(oakengine_video_params_is_valid(&q) == 0);
EXPECT_TRUE(oakengine_video_params_is_valid(&q) == 0);
// bytes per pixel: u8 RGBA = 4, f32 RGBA = 16 (format values follow
// olive::PixelFormat::Format: 0 = u8, 4 = f32)
const int channels = oakengine_video_params_internal_channel_count();
assert(channels == 4);
assert(oakengine_video_params_bytes_per_pixel(0, channels) == 4);
assert(oakengine_video_params_bytes_per_pixel(4, channels) == 16);
EXPECT_TRUE(channels == 4);
EXPECT_TRUE(oakengine_video_params_bytes_per_pixel(0, channels) == 4);
EXPECT_TRUE(oakengine_video_params_bytes_per_pixel(4, channels) == 16);
}
// Engine-side VideoParams construction used by the app during R6 to avoid
@@ -605,20 +606,20 @@ static void test_video_params_pod(void)
static void test_video_params_create_free(void)
{
// NULL pod -> NULL handle
assert(oakengine_video_params_create(NULL) == NULL);
EXPECT_TRUE(oakengine_video_params_create(NULL) == NULL);
// Empty POD -> default-constructed VideoParams handle
oak_video_params empty = {};
void *vp_empty = oakengine_video_params_create(&empty);
assert(vp_empty != NULL);
EXPECT_TRUE(vp_empty != NULL);
oakengine_video_params_free(vp_empty);
// Display-path POD with explicit timebase
oak_video_params pod;
assert(oakengine_video_params_make(&pod, 1920, 1080, 1001, 30000, 0, 1, 1,
EXPECT_TRUE(oakengine_video_params_make(&pod, 1920, 1080, 1001, 30000, 0, 1, 1,
0, 0, 1) == OAKENGINE_OK);
void *vp = oakengine_video_params_create(&pod);
assert(vp != NULL);
EXPECT_TRUE(vp != NULL);
oakengine_video_params_free(vp);
// Display-path POD without timebase (uses constructor without timebase)
@@ -627,20 +628,20 @@ static void test_video_params_create_free(void)
pod2.height = 480;
pod2.format = 0; // u8
void *vp2 = oakengine_video_params_create(&pod2);
assert(vp2 != NULL);
EXPECT_TRUE(vp2 != NULL);
oakengine_video_params_free(vp2);
// free(NULL) is a no-op
oakengine_video_params_free(NULL);
}
int main(void)
TEST(OakEngineEncoding, Main)
{
make_tmpdir();
// HEADLESS: no GL, but a QCoreApplication (needed by the FFmpeg encoder
// probes and QStandardPaths behind the metadata queries) comes up.
assert(oakengine_init(OAKENGINE_INIT_HEADLESS) == OAKENGINE_OK);
EXPECT_TRUE(oakengine_init(OAKENGINE_INIT_HEADLESS) == OAKENGINE_OK);
test_format_metadata();
test_codec_metadata();
@@ -655,5 +656,4 @@ int main(void)
oakengine_shutdown();
printf("oakengine_encoding_test: OK\n");
return 0;
}