(API Change) libobs: Fix output data cutoff on stop
(Note: This commit also modifies obs-ffmpeg and obs-outputs) API Changed: obs_output_info::void (*stop)(void *data); To: obs_output_info::void (*stop)(void *data, uint64_t ts); This fixes the long-time design flaw where obs_output_stop and the output 'stop' callback would just shut down the output without considering the timing of when obs_output_stop was used, discarding any possible buffering and causing the output to get cut off at an unexpected timing. The 'stop' callback of obs_output_info now takes a timestamp with the expectation that the output will use that timestamp to stop output data in accordance to that timing. obs_output_stop now records the timestamp at the time that the function is called and calls the 'stop' callback with that timestamp. If needed, obs_output_force_stop will still stop the output immediately without buffering.
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include <obs-avc.h>
|
||||
#include <util/dstr.h>
|
||||
#include <util/pipe.h>
|
||||
#include <util/threading.h>
|
||||
#include "ffmpeg-mux/ffmpeg-mux.h"
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
@@ -33,10 +34,12 @@
|
||||
struct ffmpeg_muxer {
|
||||
obs_output_t *output;
|
||||
os_process_pipe_t *pipe;
|
||||
int64_t stop_ts;
|
||||
struct dstr path;
|
||||
bool sent_headers;
|
||||
bool active;
|
||||
bool capturing;
|
||||
volatile bool active;
|
||||
volatile bool stopping;
|
||||
volatile bool capturing;
|
||||
};
|
||||
|
||||
static const char *ffmpeg_mux_getname(void *unused)
|
||||
@@ -72,6 +75,21 @@ static void *ffmpeg_mux_create(obs_data_t *settings, obs_output_t *output)
|
||||
#define FFMPEG_MUX "ffmpeg-mux"
|
||||
#endif
|
||||
|
||||
static inline bool capturing(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->capturing);
|
||||
}
|
||||
|
||||
static inline bool stopping(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->stopping);
|
||||
}
|
||||
|
||||
static inline bool active(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
return os_atomic_load_bool(&stream->active);
|
||||
}
|
||||
|
||||
/* TODO: allow codecs other than h264 whenever we start using them */
|
||||
|
||||
static void add_video_encoder_params(struct ffmpeg_muxer *stream,
|
||||
@@ -223,8 +241,8 @@ static bool ffmpeg_mux_start(void *data)
|
||||
}
|
||||
|
||||
/* write headers and start capture */
|
||||
stream->active = true;
|
||||
stream->capturing = true;
|
||||
os_atomic_set_bool(&stream->active, true);
|
||||
os_atomic_set_bool(&stream->capturing, true);
|
||||
obs_output_begin_data_capture(stream->output, 0);
|
||||
|
||||
info("Writing file '%s'...", stream->path.array);
|
||||
@@ -235,29 +253,32 @@ static int deactivate(struct ffmpeg_muxer *stream)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (stream->active) {
|
||||
if (active(stream)) {
|
||||
ret = os_process_pipe_destroy(stream->pipe);
|
||||
stream->pipe = NULL;
|
||||
|
||||
stream->active = false;
|
||||
stream->sent_headers = false;
|
||||
os_atomic_set_bool(&stream->active, false);
|
||||
os_atomic_set_bool(&stream->sent_headers, false);
|
||||
|
||||
info("Output of file '%s' stopped", stream->path.array);
|
||||
}
|
||||
|
||||
if (stopping(stream))
|
||||
obs_output_end_data_capture(stream->output);
|
||||
|
||||
os_atomic_set_bool(&stream->stopping, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ffmpeg_mux_stop(void *data)
|
||||
static void ffmpeg_mux_stop(void *data, uint64_t ts)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
|
||||
if (stream->capturing) {
|
||||
obs_output_end_data_capture(stream->output);
|
||||
stream->capturing = false;
|
||||
if (capturing(stream)) {
|
||||
stream->stop_ts = (int64_t)ts / 1000LL;
|
||||
os_atomic_set_bool(&stream->stopping, true);
|
||||
os_atomic_set_bool(&stream->capturing, false);
|
||||
}
|
||||
|
||||
deactivate(stream);
|
||||
}
|
||||
|
||||
static void signal_failure(struct ffmpeg_muxer *stream)
|
||||
@@ -271,7 +292,7 @@ static void signal_failure(struct ffmpeg_muxer *stream)
|
||||
}
|
||||
|
||||
obs_output_signal_stop(stream->output, code);
|
||||
stream->capturing = false;
|
||||
os_atomic_set_bool(&stream->capturing, false);
|
||||
}
|
||||
|
||||
static bool write_packet(struct ffmpeg_muxer *stream,
|
||||
@@ -358,7 +379,7 @@ static void ffmpeg_mux_data(void *data, struct encoder_packet *packet)
|
||||
{
|
||||
struct ffmpeg_muxer *stream = data;
|
||||
|
||||
if (!stream->active)
|
||||
if (!active(stream))
|
||||
return;
|
||||
|
||||
if (!stream->sent_headers) {
|
||||
@@ -368,6 +389,13 @@ static void ffmpeg_mux_data(void *data, struct encoder_packet *packet)
|
||||
stream->sent_headers = true;
|
||||
}
|
||||
|
||||
if (stopping(stream)) {
|
||||
if (packet->sys_dts_usec >= stream->stop_ts) {
|
||||
deactivate(stream);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
write_packet(stream, packet);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user