From c9182a987885da948941d486117aa4afefeceee2 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sun, 17 Sep 2017 05:50:30 -0700 Subject: [PATCH] obs-ffmpeg: Fix potential seek issues with media source (This commit also modifies deps/media-playback) Before, the media-playback library would detect whether something was seekable by checking the filename for "://", which is unideal because there are other cases where targets may not be seekable. So instead, an explicit "seekable" property (off by default) is now in place in the media source when not in "local file" mode. Seeking will only be enabled if local file mode is on, or if "seekable" is explicitly checked by the user. Closes jp9000/obs-studio#1022 --- deps/media-playback/media-playback/media.c | 21 ++++++++------------- deps/media-playback/media-playback/media.h | 4 ++-- plugins/obs-ffmpeg/data/locale/en-US.ini | 1 + plugins/obs-ffmpeg/obs-ffmpeg-source.c | 11 ++++++++++- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/deps/media-playback/media-playback/media.c b/deps/media-playback/media-playback/media.c index f6459e6ea..aaa34397a 100644 --- a/deps/media-playback/media-playback/media.c +++ b/deps/media-playback/media-playback/media.c @@ -357,7 +357,7 @@ static void mp_media_next_video(mp_media_t *m, bool preload) frame->height = f->height; frame->flip = flip; - if (m->is_network && !d->got_first_keyframe) { + if (!m->is_local_file && !d->got_first_keyframe) { if (!f->key_frame) return; @@ -407,18 +407,17 @@ static bool mp_media_reset(mp_media_t *m) ? av_rescale_q(seek_pos, AV_TIME_BASE_Q, stream->time_base) : seek_pos; - if (!m->is_network && !m->is_concat) { + if (m->is_local_file) { int ret = av_seek_frame(m->fmt, 0, seek_target, seek_flags); if (ret < 0) { blog(LOG_WARNING, "MP: Failed to seek: %s", av_err2str(ret)); - return false; } } - if (m->has_video && !m->is_network) + if (m->has_video && m->is_local_file) mp_decode_flush(&m->v); - if (m->has_audio && !m->is_network) + if (m->has_audio && m->is_local_file) mp_decode_flush(&m->a); int64_t next_ts = mp_media_get_base_pts(m); @@ -448,7 +447,7 @@ static bool mp_media_reset(mp_media_t *m) m->next_ns = 0; } - if (!active && !m->is_network && m->v_preload_cb) + if (!active && m->is_local_file && m->v_preload_cb) mp_media_next_video(m, true); if (stopping && m->stop_cb) m->stop_cb(m->opaque); @@ -528,7 +527,7 @@ static bool init_avformat(mp_media_t *m) } AVDictionary *opts = NULL; - if (m->buffering && m->is_network) + if (m->buffering && !m->is_local_file) av_dict_set_int(&opts, "buffer_size", m->buffering, 0); m->fmt = avformat_alloc_context(); @@ -674,6 +673,7 @@ bool mp_media_init(mp_media_t *media, mp_stop_cb stop_cb, mp_video_cb v_preload_cb, bool hw_decoding, + bool is_local_file, enum video_range_type force_range) { memset(media, 0, sizeof(*media)); @@ -685,12 +685,7 @@ bool mp_media_init(mp_media_t *media, media->v_preload_cb = v_preload_cb; media->force_range = force_range; media->buffering = buffering; - - if (path && *path) - media->is_network = !!strstr(path, "://"); - - if (format && *format) - media->is_concat = strcmp(format, "concat") == 0; + media->is_local_file = is_local_file; static bool initialized = false; if (!initialized) { diff --git a/deps/media-playback/media-playback/media.h b/deps/media-playback/media-playback/media.h index 9c53d56f7..d72c9820a 100644 --- a/deps/media-playback/media-playback/media.h +++ b/deps/media-playback/media-playback/media.h @@ -62,8 +62,7 @@ struct mp_media { struct mp_decode v; struct mp_decode a; - bool is_network; - bool is_concat; + bool is_local_file; bool has_video; bool has_audio; bool is_file; @@ -107,6 +106,7 @@ extern bool mp_media_init(mp_media_t *media, mp_stop_cb stop_cb, mp_video_cb v_preload_cb, bool hardware_decoding, + bool is_local_file, enum video_range_type force_range); extern void mp_media_free(mp_media_t *media); diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini index 5a5ecf763..d315cfcec 100644 --- a/plugins/obs-ffmpeg/data/locale/en-US.ini +++ b/plugins/obs-ffmpeg/data/locale/en-US.ini @@ -36,6 +36,7 @@ ColorRange.Auto="Auto" ColorRange.Partial="Partial" ColorRange.Full="Full" RestartMedia="Restart Media" +Seekable="Seekable" MediaFileFilter.AllMediaFiles="All Media Files" MediaFileFilter.VideoFiles="Video Files" diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-source.c b/plugins/obs-ffmpeg/obs-ffmpeg-source.c index 753a4e504..7c89ae3a5 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-source.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-source.c @@ -58,6 +58,7 @@ struct ffmpeg_source { bool is_clear_on_media_end; bool restart_on_activate; bool close_when_inactive; + bool seekable; }; static bool is_local_file_modified(obs_properties_t *props, @@ -73,12 +74,14 @@ static bool is_local_file_modified(obs_properties_t *props, obs_property_t *looping = obs_properties_get(props, "looping"); obs_property_t *buffering = obs_properties_get(props, "buffering_mb"); obs_property_t *close = obs_properties_get(props, "close_when_inactive"); + obs_property_t *seekable = obs_properties_get(props, "seekable"); obs_property_set_visible(input, !enabled); obs_property_set_visible(input_format, !enabled); obs_property_set_visible(buffering, !enabled); obs_property_set_visible(close, enabled); obs_property_set_visible(local_file, enabled); obs_property_set_visible(looping, enabled); + obs_property_set_visible(seekable, !enabled); return true; } @@ -181,6 +184,8 @@ static obs_properties_t *ffmpeg_source_getproperties(void *data) obs_property_list_add_int(prop, obs_module_text("ColorRange.Full"), VIDEO_RANGE_FULL); + obs_properties_add_bool(props, "seekable", obs_module_text("Seekable")); + return props; } @@ -244,7 +249,10 @@ static void ffmpeg_source_open(struct ffmpeg_source *s) s->input, s->input_format, s->buffering_mb * 1024 * 1024, s, get_frame, get_audio, media_stopped, - preload_frame, s->is_hw_decoding, s->range); + preload_frame, + s->is_hw_decoding, + s->is_local_file || s->seekable, + s->range); } static void ffmpeg_source_tick(void *data, float seconds) @@ -316,6 +324,7 @@ static void ffmpeg_source_update(void *data, obs_data_t *settings) "color_range"); s->buffering_mb = (int)obs_data_get_int(settings, "buffering_mb"); s->is_local_file = is_local_file; + s->seekable = obs_data_get_bool(settings, "seekable"); if (s->media_valid) { mp_media_free(&s->media);