Selaa lähdekoodia

Add flag to obs_source_frame for unbuffered video

Add 'flags' member variable to obs_source_frame structure.

The OBS_VIDEO_UNBUFFERED flags causes the video to play back as soon as
it's received (in the next frame playback), causing it to disregard the
timestamp value for the sake of video playback (however, note that the
video timestamp is still used for audio synchronization if audio is
present on the source as well).

This is partly a convenience feature, and partly a necessity for certain
plugins (such as the linux v4l plugin) where timestamp information for
the video frames can sometimes be unreliable.
jp9000 11 vuotta sitten
vanhempi
sitoutus
c3f4b0f018

+ 11 - 0
libobs/obs-source.c

@@ -1604,6 +1604,17 @@ static bool ready_async_frame(obs_source_t *source, uint64_t sys_time)
 	uint64_t frame_time = next_frame->timestamp;
 	uint64_t frame_offset = 0;
 
+	while ((next_frame->flags & OBS_VIDEO_UNBUFFERED) != 0 &&
+		source->video_frames.num > 1) {
+
+		da_erase(source->video_frames, 0);
+		obs_source_frame_destroy(next_frame);
+		next_frame = source->video_frames.array[0];
+	}
+
+	if ((next_frame->flags & OBS_VIDEO_UNBUFFERED) != 0)
+		return true;
+
 #if DEBUG_ASYNC_FRAMES
 	blog(LOG_DEBUG, "source->last_frame_ts: %llu, frame_time: %llu, "
 			"sys_offset: %llu, frame_offset: %llu, "

+ 4 - 0
libobs/obs.h

@@ -174,6 +174,9 @@ struct obs_source_audio {
 	uint64_t            timestamp;
 };
 
+/** Specifies that the video frame should be played as soon as possible */
+#define OBS_VIDEO_UNBUFFERED (1<<0)
+
 /**
  * Source asynchronous video output structure.  Used with
  * obs_source_output_video to output asynchronous video.  Video is buffered as
@@ -189,6 +192,7 @@ struct obs_source_frame {
 	uint32_t            width;
 	uint32_t            height;
 	uint64_t            timestamp;
+	uint32_t            flags;
 
 	enum video_format   format;
 	float               color_matrix[16];

+ 1 - 0
plugins/linux-v4l2/v4l2-input.c

@@ -178,6 +178,7 @@ static void *v4l2_thread(void *vptr)
 		}
 
 		out.timestamp = timeval2ns(buf.timestamp);
+		out.flags = 0;
 		start = (uint8_t *) data->buffers.info[buf.index].start;
 		for (uint_fast32_t i = 0; i < MAX_AV_PLANES; ++i)
 			out.data[i] = start + plane_offsets[i];

+ 1 - 0
plugins/mac-avcapture/av-capture.m

@@ -232,6 +232,7 @@ static inline bool update_frame(struct av_capture *capture,
 	CMTime target_pts_nano = CMTimeConvertScale(target_pts, NANO_TIMESCALE,
 			kCMTimeRoundingMethod_Default);
 	frame->timestamp = target_pts_nano.value;
+	frame->flags = 0;
 
 	if (!update_frame(capture, frame, sampleBuffer))
 		return;

+ 1 - 1
plugins/mac-capture/mac-window-capture.m

@@ -75,7 +75,7 @@ static inline void capture_frame(struct window_capture *wc)
 		.height      = height,
 		.data[0]     = data,
 		.linesize[0] = width * 4,
-		.timestamp   = ts,
+		.timestamp   = ts
 	};
 
 	obs_source_output_video(wc->source, &frame);

+ 2 - 0
plugins/win-dshow/win-dshow.cpp

@@ -377,6 +377,7 @@ void DShowInput::OnEncodedVideoData(enum AVCodecID id,
 
 	if (got_output) {
 		frame.timestamp = (uint64_t)ts * 100;
+		frame.flags = 0;
 #if LOG_ENCODED_VIDEO_TS
 		blog(LOG_DEBUG, "video ts: %llu", frame.timestamp);
 #endif
@@ -397,6 +398,7 @@ void DShowInput::OnVideoData(const VideoConfig &config,
 	const int cy = config.cy;
 
 	frame.timestamp  = (uint64_t)startTime * 100;
+	frame.flags      = 0;
 	frame.width      = config.cx;
 	frame.height     = config.cy;
 	frame.format     = ConvertVideoFormat(config.format);