obs-studio/test/test-input/sync-pair-vid.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

133 lines
3.1 KiB
C

#include <stdlib.h>
#include <util/threading.h>
#include <util/platform.h>
#include <graphics/graphics.h>
#include <obs.h>
struct sync_pair_vid {
obs_source_t *source;
gs_texture_t *tex;
gs_texture_t *white;
gs_texture_t *black;
};
uint64_t starting_time = 0;
uint64_t last_frame = 0;
static const char *sync_pair_vid_getname(void *unused)
{
UNUSED_PARAMETER(unused);
return "Sync Test Pair (Video)";
}
static void sync_pair_vid_destroy(void *data)
{
struct sync_pair_vid *spv = data;
obs_enter_graphics();
gs_texture_destroy(spv->tex);
gs_texture_destroy(spv->white);
gs_texture_destroy(spv->black);
obs_leave_graphics();
bfree(spv);
}
static inline void fill_texture(uint32_t *pixels, uint32_t pixel)
{
size_t x, y;
for (y = 0; y < 32; y++) {
for (x = 0; x < 32; x++) {
pixels[y*32 + x] = pixel;
}
}
}
static void *sync_pair_vid_create(obs_data_t *settings, obs_source_t *source)
{
struct sync_pair_vid *spv = bzalloc(sizeof(struct sync_pair_vid));
spv->source = source;
obs_enter_graphics();
spv->tex = gs_texture_create(32, 32, GS_RGBA, 1, NULL, GS_DYNAMIC);
spv->white = gs_texture_create(32, 32, GS_RGBA, 1, NULL, GS_DYNAMIC);
spv->black = gs_texture_create(32, 32, GS_RGBA, 1, NULL, GS_DYNAMIC);
uint8_t *ptr;
uint32_t linesize;
if (gs_texture_map(spv->white, &ptr, &linesize)) {
fill_texture((uint32_t*)ptr, 0xFFFFFFFF);
gs_texture_unmap(spv->white);
}
if (gs_texture_map(spv->black, &ptr, &linesize)) {
fill_texture((uint32_t*)ptr, 0xFF000000);
gs_texture_unmap(spv->black);
}
obs_leave_graphics();
return spv;
}
static inline bool whitelist_time(uint64_t ts, uint64_t interval,
uint64_t fps_num, uint64_t fps_den)
{
if (!starting_time)
return false;
uint64_t count = (ts - starting_time) / interval;
uint64_t sec = count * fps_den / fps_num;
return sec % 2 == 1;
}
static void sync_pair_vid_render(void *data, gs_effect_t *effect)
{
struct sync_pair_vid *spv = data;
uint64_t ts = obs_get_video_frame_time();
if (!starting_time)
starting_time = ts;
uint64_t interval = video_output_get_frame_time(obs_get_video());
const struct video_output_info *voi =
video_output_get_info(obs_get_video());
uint64_t fps_num = voi->fps_num;
uint64_t fps_den = voi->fps_den;
bool whitelist = whitelist_time(ts, interval, fps_num, fps_den);
#if 0
if (last_frame != ts) {
uint8_t *ptr;
uint32_t linesize;
if (gs_texture_map(spv->tex, &ptr, &linesize)) {
fill_texture((uint32_t*)ptr, whitelist ? 0xFFFFFFFF : 0xFF000000);
gs_texture_unmap(spv->tex);
}
last_frame = ts;
}
obs_source_draw(spv->tex, 0, 0, 0, 0, 0);
#else
obs_source_draw(whitelist ? spv->white : spv->black, 0, 0, 0, 0, 0);
#endif
}
static uint32_t sync_pair_vid_size(void *data)
{
return 32;
}
struct obs_source_info sync_video = {
.id = "sync_video",
.type = OBS_SOURCE_TYPE_INPUT,
.output_flags = OBS_SOURCE_VIDEO,
.get_name = sync_pair_vid_getname,
.create = sync_pair_vid_create,
.destroy = sync_pair_vid_destroy,
.video_render = sync_pair_vid_render,
.get_width = sync_pair_vid_size,
.get_height = sync_pair_vid_size,
};