mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-15 07:44:10 +00:00
obs-ffmpeg: Add auto reconnect to remote media sources
(Note: This commit also modifies deps/media-playback) Co-authored-by: Eric Lindvall <eric@5stops.com> Co-authored-by: Ryan Foster <RytoEX@gmail.com> Co-authored-by: Jim <obs.jim@gmail.com>
This commit is contained in:
parent
0fff23d8e1
commit
0a4b1d622c
9
deps/media-playback/media-playback/media.c
vendored
9
deps/media-playback/media-playback/media.c
vendored
|
@ -587,6 +587,7 @@ static bool init_avformat(mp_media_t *m)
|
|||
m->fmt->flags |= AVFMT_FLAG_NOBUFFER;
|
||||
}
|
||||
if (!m->is_local_file) {
|
||||
av_dict_set(&opts, "stimeout", "30000000", 0);
|
||||
m->fmt->interrupt_callback.callback = interrupt_callback;
|
||||
m->fmt->interrupt_callback.opaque = m;
|
||||
}
|
||||
|
@ -596,7 +597,9 @@ static bool init_avformat(mp_media_t *m)
|
|||
av_dict_free(&opts);
|
||||
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "MP: Failed to open media: '%s'", m->path);
|
||||
if (!m->reconnecting)
|
||||
blog(LOG_WARNING, "MP: Failed to open media: '%s'",
|
||||
m->path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -606,6 +609,7 @@ static bool init_avformat(mp_media_t *m)
|
|||
return false;
|
||||
}
|
||||
|
||||
m->reconnecting = false;
|
||||
m->has_video = mp_decode_init(m, AVMEDIA_TYPE_VIDEO, m->hw);
|
||||
m->has_audio = mp_decode_init(m, AVMEDIA_TYPE_AUDIO, m->hw);
|
||||
|
||||
|
@ -820,7 +824,7 @@ void mp_media_free(mp_media_t *media)
|
|||
pthread_mutex_init_value(&media->mutex);
|
||||
}
|
||||
|
||||
void mp_media_play(mp_media_t *m, bool loop)
|
||||
void mp_media_play(mp_media_t *m, bool loop, bool reconnecting)
|
||||
{
|
||||
pthread_mutex_lock(&m->mutex);
|
||||
|
||||
|
@ -829,6 +833,7 @@ void mp_media_play(mp_media_t *m, bool loop)
|
|||
|
||||
m->looping = loop;
|
||||
m->active = true;
|
||||
m->reconnecting = reconnecting;
|
||||
|
||||
pthread_mutex_unlock(&m->mutex);
|
||||
|
||||
|
|
4
deps/media-playback/media-playback/media.h
vendored
4
deps/media-playback/media-playback/media.h
vendored
|
@ -64,6 +64,7 @@ struct mp_media {
|
|||
struct mp_decode v;
|
||||
struct mp_decode a;
|
||||
bool is_local_file;
|
||||
bool reconnecting;
|
||||
bool has_video;
|
||||
bool has_audio;
|
||||
bool is_file;
|
||||
|
@ -117,12 +118,13 @@ struct mp_media_info {
|
|||
enum video_range_type force_range;
|
||||
bool hardware_decoding;
|
||||
bool is_local_file;
|
||||
bool reconnecting;
|
||||
};
|
||||
|
||||
extern bool mp_media_init(mp_media_t *media, const struct mp_media_info *info);
|
||||
extern void mp_media_free(mp_media_t *media);
|
||||
|
||||
extern void mp_media_play(mp_media_t *media, bool loop);
|
||||
extern void mp_media_play(mp_media_t *media, bool loop, bool reconnecting);
|
||||
extern void mp_media_stop(mp_media_t *media);
|
||||
extern void mp_media_play_pause(mp_media_t *media, bool pause);
|
||||
extern int64_t mp_get_current_time(mp_media_t *m);
|
||||
|
|
|
@ -66,3 +66,5 @@ NVENC.OutdatedDriver="Your current video card driver does not support this NVENC
|
|||
NVENC.UnsupportedDevice="NVENC Error: Unsupported device. Check your video card supports NVENC and that the drivers are up to date."
|
||||
NVENC.TooManySessions="NVENC Error: Too many concurrent sessions. Try closing other recording software which might be using NVENC such as NVIDIA Shadowplay or Windows 10 Game DVR."
|
||||
NVENC.CheckDrivers="Please check your video drivers are up to date."
|
||||
|
||||
ReconnectDelayTime="Reconnect Delay"
|
||||
|
|
|
@ -58,6 +58,12 @@ struct ffmpeg_source {
|
|||
bool close_when_inactive;
|
||||
bool seekable;
|
||||
|
||||
pthread_t reconnect_thread;
|
||||
bool stop_reconnect;
|
||||
bool reconnect_thread_valid;
|
||||
volatile bool reconnecting;
|
||||
int reconnect_delay_sec;
|
||||
|
||||
enum obs_media_state state;
|
||||
obs_hotkey_pair_id play_pause_hotkey;
|
||||
obs_hotkey_id stop_hotkey;
|
||||
|
@ -85,6 +91,8 @@ static bool is_local_file_modified(obs_properties_t *props,
|
|||
obs_properties_get(props, "close_when_inactive");
|
||||
obs_property_t *seekable = obs_properties_get(props, "seekable");
|
||||
obs_property_t *speed = obs_properties_get(props, "speed_percent");
|
||||
obs_property_t *reconnect_delay_sec =
|
||||
obs_properties_get(props, "reconnect_delay_sec");
|
||||
obs_property_set_visible(input, !enabled);
|
||||
obs_property_set_visible(input_format, !enabled);
|
||||
obs_property_set_visible(buffering, !enabled);
|
||||
|
@ -93,6 +101,7 @@ static bool is_local_file_modified(obs_properties_t *props,
|
|||
obs_property_set_visible(looping, enabled);
|
||||
obs_property_set_visible(speed, enabled);
|
||||
obs_property_set_visible(seekable, !enabled);
|
||||
obs_property_set_visible(reconnect_delay_sec, !enabled);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -103,6 +112,7 @@ static void ffmpeg_source_defaults(obs_data_t *settings)
|
|||
obs_data_set_default_bool(settings, "looping", false);
|
||||
obs_data_set_default_bool(settings, "clear_on_media_end", true);
|
||||
obs_data_set_default_bool(settings, "restart_on_activate", true);
|
||||
obs_data_set_default_int(settings, "reconnect_delay_sec", 10);
|
||||
obs_data_set_default_int(settings, "buffering_mb", 2);
|
||||
obs_data_set_default_int(settings, "speed_percent", 100);
|
||||
}
|
||||
|
@ -174,6 +184,11 @@ static obs_properties_t *ffmpeg_source_getproperties(void *data)
|
|||
obs_module_text("InputFormat"),
|
||||
OBS_TEXT_DEFAULT);
|
||||
|
||||
prop = obs_properties_add_int_slider(
|
||||
props, "reconnect_delay_sec",
|
||||
obs_module_text("ReconnectDelayTime"), 1, 60, 1);
|
||||
obs_property_int_set_suffix(prop, " S");
|
||||
|
||||
#ifndef __APPLE__
|
||||
obs_properties_add_bool(props, "hw_decode",
|
||||
obs_module_text("HardwareDecode"));
|
||||
|
@ -245,12 +260,18 @@ static void preload_frame(void *opaque, struct obs_source_frame *f)
|
|||
|
||||
if (s->is_clear_on_media_end || s->is_looping)
|
||||
obs_source_preload_video(s->source, f);
|
||||
|
||||
if (!s->is_local_file && os_atomic_set_bool(&s->reconnecting, false))
|
||||
FF_BLOG(LOG_INFO, "Reconnected.");
|
||||
}
|
||||
|
||||
static void get_audio(void *opaque, struct obs_source_audio *a)
|
||||
{
|
||||
struct ffmpeg_source *s = opaque;
|
||||
obs_source_output_audio(s->source, a);
|
||||
|
||||
if (!s->is_local_file && os_atomic_set_bool(&s->reconnecting, false))
|
||||
FF_BLOG(LOG_INFO, "Reconnected.");
|
||||
}
|
||||
|
||||
static void media_stopped(void *opaque)
|
||||
|
@ -282,12 +303,50 @@ static void ffmpeg_source_open(struct ffmpeg_source *s)
|
|||
.speed = s->speed_percent,
|
||||
.force_range = s->range,
|
||||
.hardware_decoding = s->is_hw_decoding,
|
||||
.is_local_file = s->is_local_file || s->seekable};
|
||||
.is_local_file = s->is_local_file || s->seekable,
|
||||
.reconnecting = s->reconnecting,
|
||||
};
|
||||
|
||||
s->media_valid = mp_media_init(&s->media, &info);
|
||||
}
|
||||
}
|
||||
|
||||
static void ffmpeg_source_start(struct ffmpeg_source *s)
|
||||
{
|
||||
if (!s->media_valid)
|
||||
ffmpeg_source_open(s);
|
||||
|
||||
if (!s->media_valid)
|
||||
return;
|
||||
|
||||
mp_media_play(&s->media, s->is_looping, s->reconnecting);
|
||||
if (s->is_local_file)
|
||||
obs_source_show_preloaded_video(s->source);
|
||||
|
||||
set_media_state(s, OBS_MEDIA_STATE_PLAYING);
|
||||
obs_source_media_started(s->source);
|
||||
}
|
||||
|
||||
static void *ffmpeg_source_reconnect(void *data)
|
||||
{
|
||||
struct ffmpeg_source *s = data;
|
||||
os_sleep_ms(s->reconnect_delay_sec * 1000);
|
||||
|
||||
if (s->stop_reconnect || s->media_valid)
|
||||
goto finish;
|
||||
|
||||
bool active = obs_source_active(s->source);
|
||||
if (!s->close_when_inactive || active)
|
||||
ffmpeg_source_open(s);
|
||||
|
||||
if (!s->restart_on_activate || active)
|
||||
ffmpeg_source_start(s);
|
||||
|
||||
finish:
|
||||
s->reconnect_thread_valid = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ffmpeg_source_tick(void *data, float seconds)
|
||||
{
|
||||
UNUSED_PARAMETER(seconds);
|
||||
|
@ -298,21 +357,22 @@ static void ffmpeg_source_tick(void *data, float seconds)
|
|||
mp_media_free(&s->media);
|
||||
s->media_valid = false;
|
||||
}
|
||||
|
||||
s->destroy_media = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ffmpeg_source_start(struct ffmpeg_source *s)
|
||||
{
|
||||
if (!s->media_valid)
|
||||
ffmpeg_source_open(s);
|
||||
|
||||
if (s->media_valid) {
|
||||
mp_media_play(&s->media, s->is_looping);
|
||||
if (s->is_local_file)
|
||||
obs_source_show_preloaded_video(s->source);
|
||||
set_media_state(s, OBS_MEDIA_STATE_PLAYING);
|
||||
obs_source_media_started(s->source);
|
||||
if (!s->is_local_file) {
|
||||
if (!os_atomic_set_bool(&s->reconnecting, true)) {
|
||||
FF_BLOG(LOG_WARNING, "Disconnected. "
|
||||
"Reconnecting...");
|
||||
}
|
||||
if (pthread_create(&s->reconnect_thread, NULL,
|
||||
ffmpeg_source_reconnect, s) != 0) {
|
||||
FF_BLOG(LOG_WARNING, "Could not create "
|
||||
"reconnect thread");
|
||||
return;
|
||||
}
|
||||
s->reconnect_thread_valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,8 +398,19 @@ static void ffmpeg_source_update(void *data, obs_data_t *settings)
|
|||
input = (char *)obs_data_get_string(settings, "input");
|
||||
input_format =
|
||||
(char *)obs_data_get_string(settings, "input_format");
|
||||
s->reconnect_delay_sec =
|
||||
(int)obs_data_get_int(settings, "reconnect_delay_sec");
|
||||
s->reconnect_delay_sec = s->reconnect_delay_sec == 0
|
||||
? 10
|
||||
: s->reconnect_delay_sec;
|
||||
s->is_looping = false;
|
||||
s->close_when_inactive = true;
|
||||
|
||||
if (s->reconnect_thread_valid) {
|
||||
s->stop_reconnect = true;
|
||||
pthread_join(s->reconnect_thread, NULL);
|
||||
s->stop_reconnect = false;
|
||||
}
|
||||
}
|
||||
|
||||
s->input = input ? bstrdup(input) : NULL;
|
||||
|
@ -539,6 +610,11 @@ static void ffmpeg_source_destroy(void *data)
|
|||
|
||||
if (s->hotkey)
|
||||
obs_hotkey_unregister(s->hotkey);
|
||||
if (!s->is_local_file) {
|
||||
s->stop_reconnect = true;
|
||||
if (s->reconnect_thread_valid)
|
||||
pthread_join(s->reconnect_thread, NULL);
|
||||
}
|
||||
if (s->media_valid)
|
||||
mp_media_free(&s->media);
|
||||
|
||||
|
|
Loading…
Reference in a new issue