feat(events): add "TransitionEnd" and "TransitionVideoEnd" events

Adds events for `TransitionEnd` and `TransitionVideoEnd`.

`TransitionVideoEnd` is specific to Stinger transitions. It is fired when their video has actually completed playback. This is important, because `TransitionEnd` is fired at the cut point of the Stinger, which is nice to have but isn't always what the user might want.

This builds on #409, and should be merged after it.
This commit is contained in:
Alex Van Camp 2020-02-06 18:44:28 -06:00
parent c7b49b28c2
commit 1057d765f7
4 changed files with 96 additions and 28 deletions

View File

@ -413,6 +413,30 @@ bool Utils::SetTransitionByName(QString transitionName) {
} }
} }
obs_data_t* Utils::GetTransitionData(obs_source_t* transition) {
int duration = Utils::GetTransitionDuration(transition);
if (duration < 0) {
blog(LOG_WARNING, "GetTransitionData: duration is negative !");
}
obs_data_t* transitionData = obs_data_create();
obs_data_set_string(transitionData, "name", obs_source_get_name(transition));
obs_data_set_string(transitionData, "type", obs_source_get_id(transition));
obs_data_set_int(transitionData, "duration", duration);
OBSSourceAutoRelease sourceScene = obs_transition_get_source(transition, OBS_TRANSITION_SOURCE_A);
if (sourceScene) {
obs_data_set_string(transitionData, "from-scene", obs_source_get_name(sourceScene));
}
OBSSourceAutoRelease destinationScene = obs_transition_get_active_source(transition);
if (destinationScene) {
obs_data_set_string(transitionData, "to-scene", obs_source_get_name(destinationScene));
}
return transitionData;
}
QString Utils::OBSVersionString() { QString Utils::OBSVersionString() {
uint32_t version = obs_get_version(); uint32_t version = obs_get_version();

View File

@ -60,6 +60,7 @@ namespace Utils {
int GetTransitionDuration(obs_source_t* transition); int GetTransitionDuration(obs_source_t* transition);
obs_source_t* GetTransitionFromName(QString transitionName); obs_source_t* GetTransitionFromName(QString transitionName);
bool SetTransitionByName(QString transitionName); bool SetTransitionByName(QString transitionName);
obs_data_t* GetTransitionData(obs_source_t* transition);
QString OBSVersionString(); QString OBSVersionString();

View File

@ -122,7 +122,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
switch (event) { switch (event) {
case OBS_FRONTEND_EVENT_FINISHED_LOADING: case OBS_FRONTEND_EVENT_FINISHED_LOADING:
owner->hookTransitionBeginEvent(); owner->hookTransitionPlaybackEvents();
break; break;
case OBS_FRONTEND_EVENT_SCENE_CHANGED: case OBS_FRONTEND_EVENT_SCENE_CHANGED:
@ -134,7 +134,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
break; break;
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED: case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED:
owner->hookTransitionBeginEvent(); owner->hookTransitionPlaybackEvents();
owner->OnSceneCollectionChange(); owner->OnSceneCollectionChange();
break; break;
@ -147,7 +147,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
break; break;
case OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED: case OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED:
owner->hookTransitionBeginEvent(); owner->hookTransitionPlaybackEvents();
owner->OnTransitionListChange(); owner->OnTransitionListChange();
break; break;
@ -231,7 +231,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
break; break;
case OBS_FRONTEND_EVENT_EXIT: case OBS_FRONTEND_EVENT_EXIT:
owner->unhookTransitionBeginEvent(); owner->unhookTransitionPlaybackEvents();
owner->OnExit(); owner->OnExit();
break; break;
} }
@ -309,6 +309,8 @@ void WSEvents::disconnectSourceSignals(obs_source_t* source) {
signal_handler_disconnect(sh, "item_deselect", OnSceneItemDeselected, this); signal_handler_disconnect(sh, "item_deselect", OnSceneItemDeselected, this);
signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this); signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this);
signal_handler_disconnect(sh, "transition_stop", OnTransitionEnd, this);
signal_handler_disconnect(sh, "transition_video_stop", OnTransitionVideoEnd, this);
} }
void WSEvents::connectFilterSignals(obs_source_t* filter) { void WSEvents::connectFilterSignals(obs_source_t* filter) {
@ -331,7 +333,7 @@ void WSEvents::disconnectFilterSignals(obs_source_t* filter) {
signal_handler_disconnect(sh, "enable", OnSourceFilterVisibilityChanged, this); signal_handler_disconnect(sh, "enable", OnSourceFilterVisibilityChanged, this);
} }
void WSEvents::hookTransitionBeginEvent() { void WSEvents::hookTransitionPlaybackEvents() {
obs_frontend_source_list transitions = {}; obs_frontend_source_list transitions = {};
obs_frontend_get_transitions(&transitions); obs_frontend_get_transitions(&transitions);
@ -340,12 +342,16 @@ void WSEvents::hookTransitionBeginEvent() {
signal_handler_t* sh = obs_source_get_signal_handler(transition); signal_handler_t* sh = obs_source_get_signal_handler(transition);
signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this); signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this);
signal_handler_connect(sh, "transition_start", OnTransitionBegin, this); signal_handler_connect(sh, "transition_start", OnTransitionBegin, this);
signal_handler_disconnect(sh, "transition_stop", OnTransitionEnd, this);
signal_handler_connect(sh, "transition_stop", OnTransitionEnd, this);
signal_handler_disconnect(sh, "transition_video_stop", OnTransitionVideoEnd, this);
signal_handler_connect(sh, "transition_video_stop", OnTransitionVideoEnd, this);
} }
obs_frontend_source_list_free(&transitions); obs_frontend_source_list_free(&transitions);
} }
void WSEvents::unhookTransitionBeginEvent() { void WSEvents::unhookTransitionPlaybackEvents() {
obs_frontend_source_list transitions = {}; obs_frontend_source_list transitions = {};
obs_frontend_get_transitions(&transitions); obs_frontend_get_transitions(&transitions);
@ -353,6 +359,8 @@ void WSEvents::unhookTransitionBeginEvent() {
obs_source_t* transition = transitions.sources.array[i]; obs_source_t* transition = transitions.sources.array[i];
signal_handler_t* sh = obs_source_get_signal_handler(transition); signal_handler_t* sh = obs_source_get_signal_handler(transition);
signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this); signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this);
signal_handler_disconnect(sh, "transition_stop", OnTransitionEnd, this);
signal_handler_disconnect(sh, "transition_video_stop", OnTransitionVideoEnd, this);
} }
obs_frontend_source_list_free(&transitions); obs_frontend_source_list_free(&transitions);
@ -895,29 +903,62 @@ void WSEvents::OnTransitionBegin(void* param, calldata_t* data) {
return; return;
} }
int duration = Utils::GetTransitionDuration(transition); OBSDataAutoRelease fields = Utils::GetTransitionData(transition);
if (duration < 0) {
blog(LOG_WARNING, "OnTransitionBegin: duration is negative !");
}
OBSDataAutoRelease fields = obs_data_create();
obs_data_set_string(fields, "name", obs_source_get_name(transition));
obs_data_set_string(fields, "type", obs_source_get_id(transition));
obs_data_set_int(fields, "duration", duration);
OBSSourceAutoRelease sourceScene = obs_transition_get_source(transition, OBS_TRANSITION_SOURCE_A);
if (sourceScene) {
obs_data_set_string(fields, "from-scene", obs_source_get_name(sourceScene));
}
OBSSourceAutoRelease destinationScene = obs_transition_get_active_source(transition);
if (destinationScene) {
obs_data_set_string(fields, "to-scene", obs_source_get_name(destinationScene));
}
instance->broadcastUpdate("TransitionBegin", fields); instance->broadcastUpdate("TransitionBegin", fields);
} }
/**
* A transition (other than "cut") has ended.
*
* @return {String} `name` Transition name.
* @return {String} `type` Transition type.
* @return {int} `duration` Transition duration (in milliseconds).
* @return {String} `from-scene` Source scene of the transition
* @return {String} `to-scene` Destination scene of the transition
*
* @api events
* @name TransitionEnd
* @category transitions
* @since 4.8.0
*/
void WSEvents::OnTransitionEnd(void* param, calldata_t* data) {
auto instance = reinterpret_cast<WSEvents*>(param);
OBSSource transition = calldata_get_pointer<obs_source_t>(data, "source");
if (!transition) {
return;
}
OBSDataAutoRelease fields = Utils::GetTransitionData(transition);
instance->broadcastUpdate("TransitionEnd", fields);
}
/**
* A stinger transition has finished playing its video.
*
* @return {String} `name` Transition name.
* @return {String} `type` Transition type.
* @return {int} `duration` Transition duration (in milliseconds).
* @return {String} `from-scene` Source scene of the transition
* @return {String} `to-scene` Destination scene of the transition
*
* @api events
* @name TransitionVideoEnd
* @category transitions
* @since 4.8.0
*/
void WSEvents::OnTransitionVideoEnd(void* param, calldata_t* data) {
auto instance = reinterpret_cast<WSEvents*>(param);
OBSSource transition = calldata_get_pointer<obs_source_t>(data, "source");
if (!transition) {
return;
}
OBSDataAutoRelease fields = Utils::GetTransitionData(transition);
instance->broadcastUpdate("TransitionVideoEnd", fields);
}
/** /**
* A source has been created. A source can be an input, a scene or a transition. * A source has been created. A source can be an input, a scene or a transition.
* *

View File

@ -43,8 +43,8 @@ public:
void connectFilterSignals(obs_source_t* filter); void connectFilterSignals(obs_source_t* filter);
void disconnectFilterSignals(obs_source_t* filter); void disconnectFilterSignals(obs_source_t* filter);
void hookTransitionBeginEvent(); void hookTransitionPlaybackEvents();
void unhookTransitionBeginEvent(); void unhookTransitionPlaybackEvents();
uint64_t getStreamingTime(); uint64_t getStreamingTime();
uint64_t getRecordingTime(); uint64_t getRecordingTime();
@ -116,6 +116,8 @@ private:
enum obs_frontend_event event, void* privateData); enum obs_frontend_event event, void* privateData);
static void OnTransitionBegin(void* param, calldata_t* data); static void OnTransitionBegin(void* param, calldata_t* data);
static void OnTransitionEnd(void* param, calldata_t* data);
static void OnTransitionVideoEnd(void* param, calldata_t* data);
static void OnSourceCreate(void* param, calldata_t* data); static void OnSourceCreate(void* param, calldata_t* data);
static void OnSourceDestroy(void* param, calldata_t* data); static void OnSourceDestroy(void* param, calldata_t* data);