瀏覽代碼

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.
jp9000 8 年之前
父節點
當前提交
0941a9c13d
共有 3 個文件被更改,包括 67 次插入0 次删除
  1. 1 0
      libobs/obs-internal.h
  2. 59 0
      libobs/obs-source.c
  3. 7 0
      libobs/obs.h

+ 1 - 0
libobs/obs-internal.h

@@ -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;

+ 59 - 0
libobs/obs-source.c

@@ -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)
 {

+ 7 - 0
libobs/obs.h

@@ -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);