(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:
jp9000
2016-06-11 11:42:29 -07:00
parent 29e849e355
commit d7db0b8b01
8 changed files with 270 additions and 85 deletions

View File

@@ -63,6 +63,7 @@ struct rtmp_stream {
os_sem_t *send_sem;
os_event_t *stop_event;
uint64_t stop_ts;
struct dstr path, key;
struct dstr username, password;
@@ -146,6 +147,7 @@ static void rtmp_stream_destroy(void *data)
if (stream->connecting)
pthread_join(stream->connect_thread, NULL);
stream->stop_ts = 0;
os_event_signal(stream->stop_event);
if (active(stream)) {
@@ -193,7 +195,7 @@ fail:
return NULL;
}
static void rtmp_stream_stop(void *data)
static void rtmp_stream_stop(void *data, uint64_t ts)
{
struct rtmp_stream *stream = data;
@@ -203,11 +205,12 @@ static void rtmp_stream_stop(void *data)
if (connecting(stream))
pthread_join(stream->connect_thread, NULL);
stream->stop_ts = ts / 1000ULL;
os_event_signal(stream->stop_event);
if (active(stream)) {
os_sem_post(stream->send_sem);
obs_output_end_data_capture(stream->output);
if (stream->stop_ts == 0)
os_sem_post(stream->send_sem);
}
}
@@ -322,11 +325,20 @@ static void *send_thread(void *data)
while (os_sem_wait(stream->send_sem) == 0) {
struct encoder_packet packet;
if (stopping(stream))
if (stopping(stream) && stream->stop_ts == 0) {
break;
}
if (!get_next_packet(stream, &packet))
continue;
if (stopping(stream)) {
if (packet.sys_dts_usec >= (int64_t)stream->stop_ts) {
obs_free_encoder_packet(&packet);
break;
}
}
if (!stream->sent_headers) {
if (!send_headers(stream)) {
os_atomic_set_bool(&stream->disconnected, true);
@@ -351,6 +363,8 @@ static void *send_thread(void *data)
if (!stopping(stream)) {
pthread_detach(stream->send_thread);
obs_output_signal_stop(stream->output, OBS_OUTPUT_DISCONNECTED);
} else {
obs_output_end_data_capture(stream->output);
}
free_packets(stream);
@@ -795,7 +809,7 @@ static void rtmp_stream_data(void *data, struct encoder_packet *packet)
struct encoder_packet new_packet;
bool added_packet = false;
if (disconnected(stream))
if (disconnected(stream) || !active(stream))
return;
if (packet->type == OBS_ENCODER_VIDEO)