libobs: Add ability to preload async frames

Prevents any delay when starting up certain async video sources.
Additionally prevents old frames from being presented as well.
This commit is contained in:
jp9000 2017-03-26 05:51:45 -07:00
parent d85224bb9b
commit 0941a9c13d
3 changed files with 67 additions and 0 deletions

View file

@ -603,6 +603,7 @@ struct obs_source {
bool async_flip;
bool async_active;
bool async_update_texture;
struct obs_source_frame *async_preload_frame;
DARRAY(struct async_frame) async_cache;
DARRAY(struct obs_source_frame*)async_frames;
pthread_mutex_t async_mutex;

View file

@ -567,6 +567,8 @@ void obs_source_destroy(struct obs_source *source)
audio_resampler_destroy(source->resampler);
bfree(source->audio_output_buf[0][0]);
obs_source_frame_destroy(source->async_preload_frame);
if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
obs_transition_free(source);
@ -1072,6 +1074,7 @@ static void reset_audio_data(obs_source_t *source, uint64_t os_time)
source->last_audio_input_buf_size = 0;
source->audio_ts = os_time;
source->next_audio_sys_ts_min = os_time;
}
static void handle_ts_jump(obs_source_t *source, uint64_t expected,
@ -2348,6 +2351,62 @@ void obs_source_output_video(obs_source_t *source,
}
}
static inline bool preload_frame_changed(obs_source_t *source,
const struct obs_source_frame *in)
{
if (!source->async_preload_frame)
return true;
return in->width != source->async_preload_frame->width ||
in->height != source->async_preload_frame->height ||
in->format != source->async_preload_frame->format;
}
void obs_source_preload_video(obs_source_t *source,
const struct obs_source_frame *frame)
{
if (!obs_source_valid(source, "obs_source_preload_video"))
return;
if (!frame)
return;
obs_enter_graphics();
if (preload_frame_changed(source, frame)) {
obs_source_frame_destroy(source->async_preload_frame);
source->async_preload_frame = obs_source_frame_create(
frame->format,
frame->width,
frame->height);
}
copy_frame_data(source->async_preload_frame, frame);
set_async_texture_size(source, source->async_preload_frame);
update_async_texture(source, source->async_preload_frame,
source->async_texture,
source->async_texrender);
source->last_frame_ts = frame->timestamp;
obs_leave_graphics();
}
void obs_source_show_preloaded_video(obs_source_t *source)
{
uint64_t sys_ts;
if (!obs_source_valid(source, "obs_source_show_preloaded_video"))
return;
source->async_active = true;
pthread_mutex_lock(&source->audio_buf_mutex);
sys_ts = os_gettime_ns();
reset_audio_timing(source, source->last_frame_ts, sys_ts);
reset_audio_data(source, sys_ts);
pthread_mutex_unlock(&source->audio_buf_mutex);
}
static inline struct obs_audio_data *filter_async_audio(obs_source_t *source,
struct obs_audio_data *in)
{

View file

@ -976,6 +976,13 @@ EXPORT void obs_source_draw(gs_texture_t *image, int x, int y,
EXPORT void obs_source_output_video(obs_source_t *source,
const struct obs_source_frame *frame);
/** Preloads asynchronous video data to allow instantaneous playback */
EXPORT void obs_source_preload_video(obs_source_t *source,
const struct obs_source_frame *frame);
/** Shows any preloaded video data */
EXPORT void obs_source_show_preloaded_video(obs_source_t *source);
/** Outputs audio data (always asynchronous) */
EXPORT void obs_source_output_audio(obs_source_t *source,
const struct obs_source_audio *audio);