From 1e244d7d49a8113261d0d5b5cce7e4e14202e3ba Mon Sep 17 00:00:00 2001 From: Clayton Groeneveld Date: Wed, 10 Jul 2019 00:47:07 -0500 Subject: [PATCH 1/3] vlc-video: Add media control support --- plugins/vlc-video/vlc-video-plugin.c | 6 ++ plugins/vlc-video/vlc-video-plugin.h | 9 +++ plugins/vlc-video/vlc-video-source.c | 104 +++++++++++++++++++++++---- 3 files changed, 107 insertions(+), 12 deletions(-) diff --git a/plugins/vlc-video/vlc-video-plugin.c b/plugins/vlc-video/vlc-video-plugin.c index 45e00480c..3c110c45c 100644 --- a/plugins/vlc-video/vlc-video-plugin.c +++ b/plugins/vlc-video/vlc-video-plugin.c @@ -36,8 +36,11 @@ LIBVLC_AUDIO_SET_FORMAT_CALLBACKS libvlc_audio_set_format_callbacks_; LIBVLC_MEDIA_PLAYER_PLAY libvlc_media_player_play_; LIBVLC_MEDIA_PLAYER_STOP libvlc_media_player_stop_; LIBVLC_MEDIA_PLAYER_GET_TIME libvlc_media_player_get_time_; +LIBVLC_MEDIA_PLAYER_SET_TIME libvlc_media_player_set_time_; LIBVLC_VIDEO_GET_SIZE libvlc_video_get_size_; LIBVLC_MEDIA_PLAYER_EVENT_MANAGER libvlc_media_player_event_manager_; +LIBVLC_MEDIA_PLAYER_GET_STATE libvlc_media_player_get_state_; +LIBVLC_MEDIA_PLAYER_GET_LENGTH libvlc_media_player_get_length_; /* libvlc media list */ LIBVLC_MEDIA_LIST_NEW libvlc_media_list_new_; @@ -108,8 +111,11 @@ static bool load_vlc_funcs(void) LOAD_VLC_FUNC(libvlc_media_player_play); LOAD_VLC_FUNC(libvlc_media_player_stop); LOAD_VLC_FUNC(libvlc_media_player_get_time); + LOAD_VLC_FUNC(libvlc_media_player_set_time); LOAD_VLC_FUNC(libvlc_video_get_size); LOAD_VLC_FUNC(libvlc_media_player_event_manager); + LOAD_VLC_FUNC(libvlc_media_player_get_state); + LOAD_VLC_FUNC(libvlc_media_player_get_length); /* libvlc media list */ LOAD_VLC_FUNC(libvlc_media_list_new); diff --git a/plugins/vlc-video/vlc-video-plugin.h b/plugins/vlc-video/vlc-video-plugin.h index 085bc128c..e2af06e18 100644 --- a/plugins/vlc-video/vlc-video-plugin.h +++ b/plugins/vlc-video/vlc-video-plugin.h @@ -61,10 +61,16 @@ typedef int (*LIBVLC_MEDIA_PLAYER_PLAY)(libvlc_media_player_t *p_mi); typedef void (*LIBVLC_MEDIA_PLAYER_STOP)(libvlc_media_player_t *p_mi); typedef libvlc_time_t (*LIBVLC_MEDIA_PLAYER_GET_TIME)( libvlc_media_player_t *p_mi); +typedef void (*LIBVLC_MEDIA_PLAYER_SET_TIME)(libvlc_media_player_t *p_mi, + libvlc_time_t i_time); typedef int (*LIBVLC_VIDEO_GET_SIZE)(libvlc_media_player_t *p_mi, unsigned num, unsigned *px, unsigned *py); typedef libvlc_event_manager_t *(*LIBVLC_MEDIA_PLAYER_EVENT_MANAGER)( libvlc_media_player_t *p_mp); +typedef libvlc_state_t (*LIBVLC_MEDIA_PLAYER_GET_STATE)( + libvlc_media_player_t *p_mi); +typedef libvlc_time_t (*LIBVLC_MEDIA_PLAYER_GET_LENGTH)( + libvlc_media_player_t *p_mi); /* libvlc media list */ typedef libvlc_media_list_t *(*LIBVLC_MEDIA_LIST_NEW)( @@ -124,8 +130,11 @@ extern LIBVLC_AUDIO_SET_FORMAT_CALLBACKS libvlc_audio_set_format_callbacks_; extern LIBVLC_MEDIA_PLAYER_PLAY libvlc_media_player_play_; extern LIBVLC_MEDIA_PLAYER_STOP libvlc_media_player_stop_; extern LIBVLC_MEDIA_PLAYER_GET_TIME libvlc_media_player_get_time_; +extern LIBVLC_MEDIA_PLAYER_SET_TIME libvlc_media_player_set_time_; extern LIBVLC_VIDEO_GET_SIZE libvlc_video_get_size_; extern LIBVLC_MEDIA_PLAYER_EVENT_MANAGER libvlc_media_player_event_manager_; +extern LIBVLC_MEDIA_PLAYER_GET_STATE libvlc_media_player_get_state_; +extern LIBVLC_MEDIA_PLAYER_GET_LENGTH libvlc_media_player_get_length_; /* libvlc media list */ extern LIBVLC_MEDIA_LIST_NEW libvlc_media_list_new_; diff --git a/plugins/vlc-video/vlc-video-source.c b/plugins/vlc-video/vlc-video-source.c index 1c4cff0f7..45c61bcf1 100644 --- a/plugins/vlc-video/vlc-video-source.c +++ b/plugins/vlc-video/vlc-video-source.c @@ -661,20 +661,61 @@ static void vlcs_update(void *data, obs_data_t *settings) obs_data_array_release(array); } -static void vlcs_stopped(const struct libvlc_event_t *event, void *data) +static void vlcs_started(const struct libvlc_event_t *event, void *data) { struct vlc_source *c = data; - if (!c->loop) - obs_source_output_video(c->source, NULL); + obs_source_media_started(c->source); UNUSED_PARAMETER(event); } -static void vlcs_play_pause(void *data) +static void vlcs_stopped(const struct libvlc_event_t *event, void *data) +{ + struct vlc_source *c = data; + if (!c->loop) { + obs_source_output_video(c->source, NULL); + obs_source_media_ended(c->source); + } + + UNUSED_PARAMETER(event); +} + +static enum obs_media_state vlcs_get_state(void *data) { struct vlc_source *c = data; - libvlc_media_list_player_pause_(c->media_list_player); + libvlc_state_t state = libvlc_media_player_get_state_(c->media_player); + + switch (state) { + case libvlc_NothingSpecial: + return OBS_MEDIA_STATE_NONE; + case libvlc_Opening: + return OBS_MEDIA_STATE_OPENING; + case libvlc_Buffering: + return OBS_MEDIA_STATE_BUFFERING; + case libvlc_Playing: + return OBS_MEDIA_STATE_PLAYING; + case libvlc_Paused: + return OBS_MEDIA_STATE_PAUSED; + case libvlc_Stopped: + return OBS_MEDIA_STATE_STOPPED; + case libvlc_Ended: + return OBS_MEDIA_STATE_ENDED; + case libvlc_Error: + return OBS_MEDIA_STATE_ERROR; + } + + return 0; +} + +static void vlcs_play_pause(void *data, bool pause) +{ + struct vlc_source *c = data; + + if (pause) + libvlc_media_list_player_pause_(c->media_list_player); + else + libvlc_media_list_player_play_(c->media_list_player); } static void vlcs_restart(void *data) @@ -707,6 +748,27 @@ static void vlcs_playlist_prev(void *data) libvlc_media_list_player_previous_(c->media_list_player); } +static int64_t vlcs_get_duration(void *data) +{ + struct vlc_source *c = data; + + return (int64_t)libvlc_media_player_get_length_(c->media_player); +} + +static int64_t vlcs_get_time(void *data) +{ + struct vlc_source *c = data; + + return (int64_t)libvlc_media_player_get_time_(c->media_player); +} + +static void vlcs_set_time(void *data, int64_t ms) +{ + struct vlc_source *c = data; + + libvlc_media_player_set_time_(c->media_player, (libvlc_time_t)ms); +} + static void vlcs_play_pause_hotkey(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey, bool pressed) { @@ -715,8 +777,14 @@ static void vlcs_play_pause_hotkey(void *data, obs_hotkey_id id, struct vlc_source *c = data; - if (pressed && obs_source_active(c->source)) - vlcs_play_pause(c); + enum obs_media_state state = obs_source_media_get_state(c->source); + + if (pressed && obs_source_active(c->source)) { + if (state == OBS_MEDIA_STATE_PLAYING) + obs_source_media_play_pause(c->source, true); + else if (state == OBS_MEDIA_STATE_PAUSED) + obs_source_media_play_pause(c->source, false); + } } static void vlcs_restart_hotkey(void *data, obs_hotkey_id id, @@ -728,7 +796,7 @@ static void vlcs_restart_hotkey(void *data, obs_hotkey_id id, struct vlc_source *c = data; if (pressed && obs_source_active(c->source)) - vlcs_restart(c); + obs_source_media_restart(c->source); } static void vlcs_stop_hotkey(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey, @@ -740,7 +808,7 @@ static void vlcs_stop_hotkey(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey, struct vlc_source *c = data; if (pressed && obs_source_active(c->source)) - vlcs_stop(c); + obs_source_media_stop(c->source); } static void vlcs_playlist_next_hotkey(void *data, obs_hotkey_id id, @@ -752,7 +820,7 @@ static void vlcs_playlist_next_hotkey(void *data, obs_hotkey_id id, struct vlc_source *c = data; if (pressed && obs_source_active(c->source)) - vlcs_playlist_next(c); + obs_source_media_next(c->source); } static void vlcs_playlist_prev_hotkey(void *data, obs_hotkey_id id, @@ -764,7 +832,7 @@ static void vlcs_playlist_prev_hotkey(void *data, obs_hotkey_id id, struct vlc_source *c = data; if (pressed && obs_source_active(c->source)) - vlcs_playlist_prev(c); + obs_source_media_previous(c->source); } static void *vlcs_create(obs_data_t *settings, obs_source_t *source) @@ -824,6 +892,8 @@ static void *vlcs_create(obs_data_t *settings, obs_source_t *source) event_manager = libvlc_media_player_event_manager_(c->media_player); libvlc_event_attach_(event_manager, libvlc_MediaPlayerEndReached, vlcs_stopped, c); + libvlc_event_attach_(event_manager, libvlc_MediaPlayerOpening, + vlcs_started, c); obs_source_update(source, NULL); @@ -952,7 +1022,8 @@ struct obs_source_info vlc_source_info = { .id = "vlc_source", .type = OBS_SOURCE_TYPE_INPUT, .output_flags = OBS_SOURCE_ASYNC_VIDEO | OBS_SOURCE_AUDIO | - OBS_SOURCE_DO_NOT_DUPLICATE, + OBS_SOURCE_DO_NOT_DUPLICATE | + OBS_SOURCE_CONTROLLABLE_MEDIA, .get_name = vlcs_get_name, .create = vlcs_create, .destroy = vlcs_destroy, @@ -962,4 +1033,13 @@ struct obs_source_info vlc_source_info = { .activate = vlcs_activate, .deactivate = vlcs_deactivate, .icon_type = OBS_ICON_TYPE_MEDIA, + .media_play_pause = vlcs_play_pause, + .media_restart = vlcs_restart, + .media_stop = vlcs_stop, + .media_next = vlcs_playlist_next, + .media_previous = vlcs_playlist_prev, + .media_get_duration = vlcs_get_duration, + .media_get_time = vlcs_get_time, + .media_set_time = vlcs_set_time, + .media_get_state = vlcs_get_state, }; From 68f8206877087c0118a19f1f7d6de1850a233b81 Mon Sep 17 00:00:00 2001 From: Clayton Groeneveld Date: Fri, 31 Jan 2020 13:03:01 -0600 Subject: [PATCH 2/3] obs-ffmpeg: Add media control support --- plugins/obs-ffmpeg/obs-ffmpeg-source.c | 77 +++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-source.c b/plugins/obs-ffmpeg/obs-ffmpeg-source.c index 0719df46f..c5a48c574 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-source.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-source.c @@ -57,6 +57,8 @@ struct ffmpeg_source { bool restart_on_activate; bool close_when_inactive; bool seekable; + + enum obs_media_state state; }; static bool is_local_file_modified(obs_properties_t *props, @@ -491,11 +493,77 @@ static void ffmpeg_source_deactivate(void *data) } } +static void ffmpeg_source_play_pause(void *data, bool pause) +{ + struct ffmpeg_source *s = data; + + mp_media_play_pause(&s->media, pause); + + if (pause) + set_media_state(s, OBS_MEDIA_STATE_PAUSED); + else + set_media_state(s, OBS_MEDIA_STATE_PLAYING); +} + +static void ffmpeg_source_stop(void *data) +{ + struct ffmpeg_source *s = data; + + if (s->media_valid) { + mp_media_stop(&s->media); + obs_source_output_video(s->source, NULL); + set_media_state(s, OBS_MEDIA_STATE_STOPPED); + } +} + +static void ffmpeg_source_restart(void *data) +{ + struct ffmpeg_source *s = data; + + if (obs_source_active(s->source)) + ffmpeg_source_start(s); + + set_media_state(s, OBS_MEDIA_STATE_PLAYING); +} + +static int64_t ffmpeg_source_get_duration(void *data) +{ + struct ffmpeg_source *s = data; + int64_t dur = 0; + + if (s->media.fmt) + dur = (float)s->media.fmt->duration / 1000.0f; + + return dur; +} + +static int64_t ffmpeg_source_get_time(void *data) +{ + struct ffmpeg_source *s = data; + + return mp_get_current_time(&s->media); +} + +static void ffmpeg_source_set_time(void *data, int64_t ms) +{ + struct ffmpeg_source *s = data; + + mp_media_seek_to(&s->media, ms); +} + +static enum obs_media_state ffmpeg_source_get_state(void *data) +{ + struct ffmpeg_source *s = data; + + return s->state; +} + struct obs_source_info ffmpeg_source = { .id = "ffmpeg_source", .type = OBS_SOURCE_TYPE_INPUT, .output_flags = OBS_SOURCE_ASYNC_VIDEO | OBS_SOURCE_AUDIO | - OBS_SOURCE_DO_NOT_DUPLICATE, + OBS_SOURCE_DO_NOT_DUPLICATE | + OBS_SOURCE_CONTROLLABLE_MEDIA, .get_name = ffmpeg_source_getname, .create = ffmpeg_source_create, .destroy = ffmpeg_source_destroy, @@ -506,4 +574,11 @@ struct obs_source_info ffmpeg_source = { .video_tick = ffmpeg_source_tick, .update = ffmpeg_source_update, .icon_type = OBS_ICON_TYPE_MEDIA, + .media_play_pause = ffmpeg_source_play_pause, + .media_restart = ffmpeg_source_restart, + .media_stop = ffmpeg_source_stop, + .media_get_duration = ffmpeg_source_get_duration, + .media_get_time = ffmpeg_source_get_time, + .media_set_time = ffmpeg_source_set_time, + .media_get_state = ffmpeg_source_get_state, }; From abcff0073c43d0305751477c5bf3470326729c37 Mon Sep 17 00:00:00 2001 From: Clayton Groeneveld Date: Fri, 31 Jan 2020 13:12:09 -0600 Subject: [PATCH 3/3] obs-ffmpeg: Add media hotkeys --- plugins/obs-ffmpeg/data/locale/en-US.ini | 5 +- plugins/obs-ffmpeg/obs-ffmpeg-source.c | 67 +++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini index e42f40d6c..ffd5034cc 100644 --- a/plugins/obs-ffmpeg/data/locale/en-US.ini +++ b/plugins/obs-ffmpeg/data/locale/en-US.ini @@ -40,9 +40,12 @@ ColorRange="YUV Color Range" ColorRange.Auto="Auto" ColorRange.Partial="Partial" ColorRange.Full="Full" -RestartMedia="Restart Media" +RestartMedia="Restart" SpeedPercentage="Speed" Seekable="Seekable" +Play="Play" +Pause="Pause" +Stop="Stop" 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 c5a48c574..d042d3d23 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-source.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-source.c @@ -59,8 +59,16 @@ struct ffmpeg_source { bool seekable; enum obs_media_state state; + obs_hotkey_pair_id play_pause_hotkey; + obs_hotkey_id stop_hotkey; }; +static void set_media_state(void *data, enum obs_media_state state) +{ + struct ffmpeg_source *s = data; + s->state = state; +} + static bool is_local_file_modified(obs_properties_t *props, obs_property_t *prop, obs_data_t *settings) { @@ -299,6 +307,7 @@ static void ffmpeg_source_start(struct ffmpeg_source *s) 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); } } @@ -376,7 +385,7 @@ static void restart_hotkey(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey, struct ffmpeg_source *s = data; if (obs_source_active(s->source)) - ffmpeg_source_start(s); + obs_source_media_restart(s->source); } static void restart_proc(void *data, calldata_t *cd) @@ -432,6 +441,50 @@ static void get_nb_frames(void *data, calldata_t *cd) calldata_set_int(cd, "num_frames", frames); } +static bool ffmpeg_source_play_hotkey(void *data, obs_hotkey_pair_id id, + obs_hotkey_t *hotkey, bool pressed) +{ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(hotkey); + + struct ffmpeg_source *s = data; + + if (s->state == OBS_MEDIA_STATE_PLAYING || !pressed || + !obs_source_active(s->source)) + return false; + + obs_source_media_play_pause(s->source, false); + return true; +} + +static bool ffmpeg_source_pause_hotkey(void *data, obs_hotkey_pair_id id, + obs_hotkey_t *hotkey, bool pressed) +{ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(hotkey); + + struct ffmpeg_source *s = data; + + if (s->state != OBS_MEDIA_STATE_PLAYING || !pressed || + !obs_source_active(s->source)) + return false; + + obs_source_media_play_pause(s->source, true); + return true; +} + +static void ffmpeg_source_stop_hotkey(void *data, obs_hotkey_id id, + obs_hotkey_t *hotkey, bool pressed) +{ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(hotkey); + + struct ffmpeg_source *s = data; + + if (pressed && obs_source_active(s->source)) + obs_source_media_stop(s->source); +} + static void *ffmpeg_source_create(obs_data_t *settings, obs_source_t *source) { UNUSED_PARAMETER(settings); @@ -443,6 +496,16 @@ static void *ffmpeg_source_create(obs_data_t *settings, obs_source_t *source) obs_module_text("RestartMedia"), restart_hotkey, s); + s->play_pause_hotkey = obs_hotkey_pair_register_source( + s->source, "MediaSource.Play", obs_module_text("Play"), + "MediaSource.Pause", obs_module_text("Pause"), + ffmpeg_source_play_hotkey, ffmpeg_source_pause_hotkey, s, s); + + s->stop_hotkey = obs_hotkey_register_source(source, "MediaSource.Stop", + obs_module_text("Stop"), + ffmpeg_source_stop_hotkey, + s); + proc_handler_t *ph = obs_source_get_proc_handler(source); proc_handler_add(ph, "void restart()", restart_proc, s); proc_handler_add(ph, "void get_duration(out int duration)", @@ -476,7 +539,7 @@ static void ffmpeg_source_activate(void *data) struct ffmpeg_source *s = data; if (s->restart_on_activate) - ffmpeg_source_start(s); + obs_source_media_restart(s->source); } static void ffmpeg_source_deactivate(void *data)