0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 04:42:18 +02:00
obs-studio/test/test-input/sync-async-source.c
jp9000 292a6e59f4 test: Add sync tests
The async source sync test verifies that async sources are playing back
in sync properly, and the "sync pair (video)" and "sync pair (audio)"
sources test the back-end syncing down to the exact sample via inserting
audio data directly in to the back-end with system timestamps.

For these sources, when the video is white, a C sinewave should be
playing, and when the video is black audio is mute.
2017-10-02 07:36:02 -07:00

144 lines
3.1 KiB
C

#include <stdlib.h>
#include <util/threading.h>
#include <util/platform.h>
#include <obs.h>
struct async_sync_test {
obs_source_t *source;
os_event_t *stop_signal;
pthread_t thread;
bool initialized;
};
/* middle C */
static const double rate = 261.63/48000.0;
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
#define M_PI_X2 M_PI*2
static const char *ast_getname(void *unused)
{
UNUSED_PARAMETER(unused);
return "Sync Test (Async Video/Audio Source)";
}
static void ast_destroy(void *data)
{
struct async_sync_test *ast = data;
if (ast->initialized) {
os_event_signal(ast->stop_signal);
pthread_join(ast->thread, NULL);
}
os_event_destroy(ast->stop_signal);
bfree(ast);
}
static inline void fill_texture(uint32_t *pixels, uint32_t color)
{
size_t x, y;
for (y = 0; y < 20; y++) {
for (x = 0; x < 20; x++) {
pixels[y*20 + x] = color;
}
}
}
static void *video_thread(void *data)
{
struct async_sync_test *ast = data;
uint32_t sample_rate = audio_output_get_sample_rate(obs_get_audio());
uint32_t *pixels = bmalloc(20 * 20 * sizeof(uint32_t));
float *samples = bmalloc(sample_rate * sizeof(float));
uint64_t cur_time = os_gettime_ns();
bool whitelist = false;
double cos_val = 0.0;
uint64_t start_time = cur_time;
struct obs_source_frame frame = {
.data = {[0] = (uint8_t*)pixels},
.linesize = {[0] = 20*4},
.width = 20,
.height = 20,
.format = VIDEO_FORMAT_BGRX
};
struct obs_source_audio audio = {
.speakers = SPEAKERS_MONO,
.data = {[0] = (uint8_t*)samples},
.samples_per_sec = sample_rate,
.frames = sample_rate,
.format = AUDIO_FORMAT_FLOAT
};
while (os_event_try(ast->stop_signal) == EAGAIN) {
fill_texture(pixels, whitelist ? 0xFFFFFFFF : 0xFF000000);
frame.timestamp = cur_time - start_time;
audio.timestamp = cur_time - start_time;
if (whitelist) {
for (size_t i = 0; i < sample_rate; i++) {
cos_val += rate * M_PI_X2;
if (cos_val > M_PI_X2)
cos_val -= M_PI_X2;
samples[i] = (float)(cos(cos_val) * 0.5);
}
} else {
for (size_t i = 0; i < sample_rate; i++)
samples[i] = 0.0f;
}
obs_source_output_video(ast->source, &frame);
obs_source_output_audio(ast->source, &audio);
os_sleepto_ns(cur_time += 1000000000);
whitelist = !whitelist;
}
bfree(pixels);
bfree(samples);
return NULL;
}
static void *ast_create(obs_data_t *settings, obs_source_t *source)
{
struct async_sync_test *ast = bzalloc(sizeof(struct async_sync_test));
ast->source = source;
if (os_event_init(&ast->stop_signal, OS_EVENT_TYPE_MANUAL) != 0) {
ast_destroy(ast);
return NULL;
}
if (pthread_create(&ast->thread, NULL, video_thread, ast) != 0) {
ast_destroy(ast);
return NULL;
}
ast->initialized = true;
UNUSED_PARAMETER(settings);
UNUSED_PARAMETER(source);
return ast;
}
struct obs_source_info async_sync_test = {
.id = "async_sync_test",
.type = OBS_SOURCE_TYPE_INPUT,
.output_flags = OBS_SOURCE_ASYNC_VIDEO |
OBS_SOURCE_AUDIO,
.get_name = ast_getname,
.create = ast_create,
.destroy = ast_destroy,
};