obs-studio/libobs/obs-source-transition.c

1037 lines
27 KiB
C
Raw Normal View History

libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
/******************************************************************************
Copyright (C) 2013-2014 by Hugh Bailey <obs.jim@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "obs-internal.h"
#define lock_transition(transition) \
pthread_mutex_lock(&transition->transition_mutex);
#define unlock_transition(transition) \
pthread_mutex_unlock(&transition->transition_mutex);
#define trylock_textures(transition) \
pthread_mutex_trylock(&transition->transition_tex_mutex)
#define lock_textures(transition) \
pthread_mutex_lock(&transition->transition_tex_mutex)
#define unlock_textures(transition) \
pthread_mutex_unlock(&transition->transition_tex_mutex)
static inline bool transition_valid(const obs_source_t *transition,
const char *func)
{
if (!obs_ptr_valid(transition, func))
return false;
else if (transition->info.type != OBS_SOURCE_TYPE_TRANSITION)
return false;
return true;
}
bool obs_transition_init(obs_source_t *transition)
{
pthread_mutex_init_value(&transition->transition_mutex);
pthread_mutex_init_value(&transition->transition_tex_mutex);
if (pthread_mutex_init(&transition->transition_mutex, NULL) != 0)
return false;
if (pthread_mutex_init(&transition->transition_tex_mutex, NULL) != 0)
return false;
transition->transition_alignment = OBS_ALIGN_LEFT | OBS_ALIGN_TOP;
transition->transition_texrender[0] =
gs_texrender_create(GS_RGBA, GS_ZS_NONE);
transition->transition_texrender[1] =
gs_texrender_create(GS_RGBA, GS_ZS_NONE);
transition->transition_source_active[0] = true;
return transition->transition_texrender[0] != NULL &&
transition->transition_texrender[1] != NULL;
}
void obs_transition_free(obs_source_t *transition)
{
pthread_mutex_destroy(&transition->transition_mutex);
pthread_mutex_destroy(&transition->transition_tex_mutex);
gs_enter_context(obs->video.graphics);
gs_texrender_destroy(transition->transition_texrender[0]);
gs_texrender_destroy(transition->transition_texrender[1]);
gs_leave_context();
}
void obs_transition_clear(obs_source_t *transition)
{
obs_source_t *s[2];
bool active[2];
if (!transition_valid(transition, "obs_transition_clear"))
return;
lock_transition(transition);
for (size_t i = 0; i < 2; i++) {
s[i] = transition->transition_sources[i];
active[i] = transition->transition_source_active[i];
transition->transition_sources[i] = NULL;
transition->transition_source_active[i] = false;
}
transition->transitioning_video = false;
transition->transitioning_audio = false;
unlock_transition(transition);
for (size_t i = 0; i < 2; i++) {
if (s[i] && active[i])
obs_source_remove_active_child(transition, s[i]);
obs_source_release(s[i]);
}
}
void add_alignment(struct vec2 *v, uint32_t align, int cx, int cy);
static inline uint32_t get_cx(obs_source_t *tr)
{
return tr->transition_cx ?
tr->transition_cx : tr->transition_actual_cx;
}
static inline uint32_t get_cy(obs_source_t *tr)
{
return tr->transition_cy ?
tr->transition_cy : tr->transition_actual_cy;
}
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
static void recalculate_transition_matrix(obs_source_t *tr, size_t idx)
{
obs_source_t *child;
struct matrix4 mat;
struct vec2 pos;
struct vec2 scale;
float tr_cx = (float)get_cx(tr);
float tr_cy = (float)get_cy(tr);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
float source_cx;
float source_cy;
float tr_aspect = tr_cx / tr_cy;
float source_aspect;
enum obs_transition_scale_type scale_type = tr->transition_scale_type;
lock_transition(tr);
child = tr->transition_sources[idx];
if (!child) {
unlock_transition(tr);
return;
}
source_cx = (float)obs_source_get_width(child);
source_cy = (float)obs_source_get_height(child);
unlock_transition(tr);
if (source_cx == 0.0f || source_cy == 0.0f)
return;
source_aspect = source_cx / source_cy;
if (scale_type == OBS_TRANSITION_SCALE_MAX_ONLY) {
if (source_cx > tr_cx || source_cy > tr_cy) {
scale_type = OBS_TRANSITION_SCALE_ASPECT;
} else {
scale.x = 1.0f;
scale.y = 1.0f;
}
}
if (scale_type == OBS_TRANSITION_SCALE_ASPECT) {
bool use_width = tr_aspect < source_aspect;
scale.x = scale.y = use_width ?
tr_cx / source_cx :
tr_cy / source_cy;
} else if (scale_type == OBS_TRANSITION_SCALE_STRETCH) {
scale.x = tr_cx / source_cx;
scale.y = tr_cy / source_cy;
}
source_cx *= scale.x;
source_cy *= scale.y;
vec2_zero(&pos);
add_alignment(&pos, tr->transition_alignment,
(int)(tr_cx - source_cx),
(int)(tr_cy - source_cy));
matrix4_identity(&mat);
matrix4_scale3f(&mat, &mat, scale.x, scale.y, 1.0f);
matrix4_translate3f(&mat, &mat, pos.x, pos.y, 0.0f);
matrix4_copy(&tr->transition_matrices[idx], &mat);
}
static inline void recalculate_transition_matrices(obs_source_t *transition)
{
recalculate_transition_matrix(transition, 0);
recalculate_transition_matrix(transition, 1);
}
static void recalculate_transition_size(obs_source_t *transition)
{
uint32_t cx = 0, cy = 0;
obs_source_t *child;
lock_transition(transition);
for (size_t i = 0; i < 2; i++) {
child = transition->transition_sources[i];
if (child) {
uint32_t new_cx = obs_source_get_width(child);
uint32_t new_cy = obs_source_get_height(child);
if (new_cx > cx) cx = new_cx;
if (new_cy > cy) cy = new_cy;
}
}
unlock_transition(transition);
transition->transition_actual_cx = cx;
transition->transition_actual_cy = cy;
}
void obs_transition_tick(obs_source_t *transition)
{
recalculate_transition_size(transition);
recalculate_transition_matrices(transition);
if (trylock_textures(transition) == 0) {
gs_texrender_reset(transition->transition_texrender[0]);
gs_texrender_reset(transition->transition_texrender[1]);
unlock_textures(transition);
}
}
static void set_source(obs_source_t *transition,
enum obs_transition_target target, obs_source_t *new_child,
bool (*callback)(obs_source_t *t, size_t idx, obs_source_t *c))
{
size_t idx = (size_t)target;
obs_source_t *old_child;
bool add_success = true;
bool already_active;
if (new_child)
obs_source_addref(new_child);
lock_transition(transition);
old_child = transition->transition_sources[idx];
if (new_child == old_child) {
unlock_transition(transition);
obs_source_release(new_child);
return;
}
already_active = transition->transition_source_active[idx];
if (already_active) {
if (new_child)
add_success = obs_source_add_active_child(transition,
new_child);
if (old_child && add_success)
obs_source_remove_active_child(transition, old_child);
}
if (callback && add_success)
add_success = callback(transition, idx, new_child);
transition->transition_sources[idx] = add_success ? new_child : NULL;
unlock_transition(transition);
if (add_success) {
if (transition->transition_cx == 0 ||
transition->transition_cy == 0) {
recalculate_transition_size(transition);
recalculate_transition_matrices(transition);
}
} else {
obs_source_release(new_child);
}
obs_source_release(old_child);
}
obs_source_t *obs_transition_get_source(obs_source_t *transition,
enum obs_transition_target target)
{
size_t idx = (size_t)target;
obs_source_t *ret;
if (!transition_valid(transition, "obs_transition_get_source"))
return NULL;
lock_transition(transition);
ret = transition->transition_sources[idx];
obs_source_addref(ret);
unlock_transition(transition);
return ret;
}
obs_source_t *obs_transition_get_active_source(obs_source_t *transition)
{
obs_source_t *ret;
if (!transition_valid(transition, "obs_transition_get_source"))
return NULL;
lock_transition(transition);
if (transition->transitioning_audio || transition->transitioning_video)
ret = transition->transition_sources[1];
else
ret = transition->transition_sources[0];
obs_source_addref(ret);
unlock_transition(transition);
return ret;
}
static inline bool activate_child(obs_source_t *transition, size_t idx)
{
bool success = true;
lock_transition(transition);
if (transition->transition_sources[idx] &&
!transition->transition_source_active[idx]) {
success = obs_source_add_active_child(transition,
transition->transition_sources[idx]);
if (success)
transition->transition_source_active[idx] = true;
}
unlock_transition(transition);
return success;
}
static bool activate_transition(obs_source_t *transition, size_t idx,
obs_source_t *child)
{
if (!transition->transition_source_active[idx]) {
if (!obs_source_add_active_child(transition, child))
return false;
transition->transition_source_active[idx] = true;
}
transition->transitioning_video = true;
transition->transitioning_audio = true;
return true;
}
static inline bool transition_active(obs_source_t *transition)
{
return transition->transitioning_audio ||
transition->transitioning_video;
}
bool obs_transition_start(obs_source_t *transition,
enum obs_transition_mode mode, uint32_t duration_ms,
obs_source_t *dest)
{
bool active;
bool same_as_source;
bool same_as_dest;
if (!transition_valid(transition, "obs_transition_start"))
return false;
lock_transition(transition);
same_as_source = dest == transition->transition_sources[0];
same_as_dest = dest == transition->transition_sources[1];
active = transition_active(transition);
unlock_transition(transition);
if (same_as_source && !active)
return false;
if (transition->info.transition_start)
transition->info.transition_start(transition->context.data);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
if (transition->transition_use_fixed_duration)
duration_ms = transition->transition_fixed_duration;
if (!active || (!same_as_dest && !same_as_source)) {
transition->transition_start_time = os_gettime_ns();
transition->transition_duration =
(uint64_t)duration_ms * 1000000ULL;
}
set_source(transition, OBS_TRANSITION_SOURCE_B, dest,
activate_transition);
if (dest == NULL && same_as_dest && !same_as_source) {
transition->transitioning_video = true;
transition->transitioning_audio = true;
}
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
obs_source_dosignal(transition, "source_transition_start",
"transition_start");
recalculate_transition_size(transition);
recalculate_transition_matrices(transition);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
/* TODO: Add mode */
UNUSED_PARAMETER(mode);
return true;
}
void obs_transition_set(obs_source_t *transition, obs_source_t *source)
{
obs_source_t *s[2];
bool active[2];
if (!transition_valid(transition, "obs_transition_clear"))
return;
obs_source_addref(source);
lock_transition(transition);
for (size_t i = 0; i < 2; i++) {
s[i] = transition->transition_sources[i];
active[i] = transition->transition_source_active[i];
transition->transition_sources[i] = NULL;
transition->transition_source_active[i] = false;
}
transition->transition_source_active[0] = true;
transition->transition_sources[0] = source;
transition->transitioning_video = false;
transition->transitioning_audio = false;
unlock_transition(transition);
for (size_t i = 0; i < 2; i++) {
if (s[i] && active[i])
obs_source_remove_active_child(transition, s[i]);
obs_source_release(s[i]);
}
if (source)
obs_source_add_active_child(transition, source);
}
static float calc_time(obs_source_t *transition, uint64_t ts)
{
uint64_t end;
if (ts <= transition->transition_start_time)
return 0.0f;
end = transition->transition_duration;
ts -= transition->transition_start_time;
if (ts >= end || end == 0)
return 1.0f;
return (float)((long double)ts / (long double)end);
}
static inline float get_video_time(obs_source_t *transition)
{
uint64_t ts = obs->video.video_time;
return calc_time(transition, ts);
}
float obs_transition_get_time(obs_source_t *transition)
{
return get_video_time(transition);
}
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
static inline gs_texture_t *get_texture(obs_source_t *transition,
enum obs_transition_target target)
{
size_t idx = (size_t)target;
return gs_texrender_get_texture(transition->transition_texrender[idx]);
}
void obs_transition_set_scale_type(obs_source_t *transition,
enum obs_transition_scale_type type)
{
if (!transition_valid(transition, "obs_transition_set_scale_type"))
return;
transition->transition_scale_type = type;
}
enum obs_transition_scale_type obs_transition_get_scale_type(
const obs_source_t *transition)
{
return transition_valid(transition, "obs_transition_get_scale_type") ?
transition->transition_scale_type :
OBS_TRANSITION_SCALE_MAX_ONLY;
}
void obs_transition_set_alignment(obs_source_t *transition, uint32_t alignment)
{
if (!transition_valid(transition, "obs_transition_set_alignment"))
return;
transition->transition_alignment = alignment;
}
uint32_t obs_transition_get_alignment(const obs_source_t *transition)
{
return transition_valid(transition, "obs_transition_get_alignment") ?
transition->transition_alignment : 0;
}
void obs_transition_set_size(obs_source_t *transition,
uint32_t cx, uint32_t cy)
{
if (!transition_valid(transition, "obs_transition_set_size"))
return;
transition->transition_cx = cx;
transition->transition_cy = cy;
}
void obs_transition_get_size(const obs_source_t *transition,
uint32_t *cx, uint32_t *cy)
{
if (!transition_valid(transition, "obs_transition_set_size")) {
*cx = 0;
*cy = 0;
return;
}
*cx = transition->transition_cx;
*cy = transition->transition_cy;
}
void obs_transition_save(obs_source_t *tr, obs_data_t *data)
{
obs_source_t *child;
lock_transition(tr);
child = transition_active(tr) ?
tr->transition_sources[1] : tr->transition_sources[0];
obs_data_set_string(data, "transition_source_a",
child ? child->context.name : "");
obs_data_set_int(data, "transition_alignment",
tr->transition_alignment);
obs_data_set_int(data, "transition_mode",
(int64_t)tr->transition_mode);
obs_data_set_int(data, "transition_scale_type",
(int64_t)tr->transition_scale_type);
obs_data_set_int(data, "transition_cx", tr->transition_cx);
obs_data_set_int(data, "transition_cy", tr->transition_cy);
unlock_transition(tr);
}
void obs_transition_load(obs_source_t *tr, obs_data_t *data)
{
const char *name = obs_data_get_string(data, "transition_source_a");
int64_t alignment = obs_data_get_int(data, "transition_alignment");
int64_t mode = obs_data_get_int(data, "transition_mode");
int64_t scale_type = obs_data_get_int(data, "transition_scale_type");
int64_t cx = obs_data_get_int(data, "transition_cx");
int64_t cy = obs_data_get_int(data, "transition_cy");
obs_source_t *source = NULL;
if (name) {
source = obs_get_source_by_name(name);
if (source) {
if (!obs_source_add_active_child(tr, source)) {
blog(LOG_WARNING, "Cannot set transition '%s' "
"to source '%s' due to "
"infinite recursion",
tr->context.name, name);
obs_source_release(source);
source = NULL;
}
} else {
blog(LOG_WARNING, "Failed to find source '%s' for "
"transition '%s'",
name, tr->context.name);
}
}
lock_transition(tr);
tr->transition_sources[0] = source;
tr->transition_source_active[0] = true;
tr->transition_alignment = (uint32_t)alignment;
tr->transition_mode = (enum obs_transition_mode)mode;
tr->transition_scale_type = (enum obs_transition_scale_type)scale_type;
tr->transition_cx = (uint32_t)cx;
tr->transition_cy = (uint32_t)cy;
unlock_transition(tr);
recalculate_transition_size(tr);
recalculate_transition_matrices(tr);
}
struct transition_state {
obs_source_t *s[2];
bool transitioning_video;
bool transitioning_audio;
};
static inline void copy_transition_state(obs_source_t *transition,
struct transition_state *state)
{
state->s[0] = transition->transition_sources[0];
state->s[1] = transition->transition_sources[1];
obs_source_addref(state->s[0]);
obs_source_addref(state->s[1]);
state->transitioning_video = transition->transitioning_video;
state->transitioning_audio = transition->transitioning_audio;
}
static inline void enum_child(obs_source_t *tr, obs_source_t *child,
obs_source_enum_proc_t enum_callback, void *param)
{
if (!child)
return;
if (child->context.data && child->info.enum_active_sources)
child->info.enum_active_sources(child->context.data,
enum_callback, param);
enum_callback(tr, child, param);
}
void obs_transition_enum_sources(obs_source_t *transition,
obs_source_enum_proc_t cb, void *param)
{
lock_transition(transition);
for (size_t i = 0; i < 2; i++) {
if (transition->transition_sources[i])
cb(transition, transition->transition_sources[i], param);
}
unlock_transition(transition);
}
static inline void render_child(obs_source_t *transition,
obs_source_t *child, size_t idx)
{
uint32_t cx = get_cx(transition);
uint32_t cy = get_cy(transition);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
struct vec4 blank;
if (!child)
return;
if (gs_texrender_begin(transition->transition_texrender[idx], cx, cy)) {
vec4_zero(&blank);
gs_clear(GS_CLEAR_COLOR, &blank, 0.0f, 0);
gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
gs_matrix_push();
gs_matrix_mul(&transition->transition_matrices[idx]);
obs_source_video_render(child);
gs_matrix_pop();
gs_texrender_end(transition->transition_texrender[idx]);
}
}
static void obs_transition_stop(obs_source_t *transition)
{
obs_source_t *old_child = transition->transition_sources[0];
if (old_child && transition->transition_source_active[0])
obs_source_remove_active_child(transition, old_child);
obs_source_release(old_child);
transition->transition_source_active[0] = true;
transition->transition_source_active[1] = false;
transition->transition_sources[0] = transition->transition_sources[1];
transition->transition_sources[1] = NULL;
}
static inline void handle_stop(obs_source_t *transition)
{
if (transition->info.transition_stop)
transition->info.transition_stop(transition->context.data);
obs_source_dosignal(transition, "source_transition_stop",
"transition_stop");
}
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
void obs_transition_video_render(obs_source_t *transition,
obs_transition_video_render_callback_t callback)
{
struct transition_state state;
struct matrix4 matrices[2];
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
bool locked = false;
bool stopped = false;
bool video_stopped = false;
float t;
if (!transition_valid(transition, "obs_transition_video_render"))
return;
t = get_video_time(transition);
lock_transition(transition);
if (t >= 1.0f && transition->transitioning_video) {
transition->transitioning_video = false;
video_stopped = true;
if (!transition->transitioning_audio) {
obs_transition_stop(transition);
stopped = true;
}
}
copy_transition_state(transition, &state);
matrices[0] = transition->transition_matrices[0];
matrices[1] = transition->transition_matrices[1];
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
unlock_transition(transition);
if (state.transitioning_video)
locked = trylock_textures(transition) == 0;
if (state.transitioning_video && locked && callback) {
gs_texture_t *tex[2];
uint32_t cx;
uint32_t cy;
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
for (size_t i = 0; i < 2; i++) {
if (state.s[i]) {
render_child(transition, state.s[i], i);
tex[i] = get_texture(transition, i);
if (!tex[i])
tex[i] = obs->video.transparent_texture;
} else {
tex[i] = obs->video.transparent_texture;
}
}
cx = get_cx(transition);
cy = get_cy(transition);
if (cx && cy)
callback(transition->context.data, tex[0], tex[1], t,
cx, cy);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
} else if (state.transitioning_audio) {
if (state.s[1]) {
gs_matrix_push();
gs_matrix_mul(&matrices[1]);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
obs_source_video_render(state.s[1]);
gs_matrix_pop();
}
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
} else {
if (state.s[0]) {
gs_matrix_push();
gs_matrix_mul(&matrices[0]);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
obs_source_video_render(state.s[0]);
gs_matrix_pop();
}
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
}
if (locked)
unlock_textures(transition);
obs_source_release(state.s[0]);
obs_source_release(state.s[1]);
if (video_stopped)
obs_source_dosignal(transition, "source_transition_video_stop",
"transition_video_stop");
if (stopped)
handle_stop(transition);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
}
bool obs_transition_video_render_direct(obs_source_t *transition,
enum obs_transition_target target)
{
struct transition_state state;
struct matrix4 matrices[2];
bool stopped = false;
bool video_stopped = false;
bool render_b = target == OBS_TRANSITION_SOURCE_B;
bool transitioning;
float t;
if (!transition_valid(transition, "obs_transition_video_render"))
return false;
t = get_video_time(transition);
lock_transition(transition);
if (t >= 1.0f && transition->transitioning_video) {
transition->transitioning_video = false;
video_stopped = true;
if (!transition->transitioning_audio) {
obs_transition_stop(transition);
stopped = true;
}
}
copy_transition_state(transition, &state);
transitioning = state.transitioning_audio || state.transitioning_video;
matrices[0] = transition->transition_matrices[0];
matrices[1] = transition->transition_matrices[1];
unlock_transition(transition);
int idx = (transitioning && render_b) ? 1 : 0;
if (state.s[idx]) {
gs_matrix_push();
gs_matrix_mul(&matrices[idx]);
obs_source_video_render(state.s[idx]);
gs_matrix_pop();
}
obs_source_release(state.s[0]);
obs_source_release(state.s[1]);
if (video_stopped)
obs_source_dosignal(transition, "source_transition_video_stop",
"transition_video_stop");
if (stopped)
handle_stop(transition);
return transitioning;
}
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
static inline float get_sample_time(obs_source_t *transition,
size_t sample_rate, size_t sample, uint64_t ts)
{
uint64_t sample_ts_offset = (uint64_t)sample * 1000000000ULL /
(uint64_t)sample_rate;
uint64_t i_ts = ts + sample_ts_offset;
return calc_time(transition, i_ts);
}
static inline void mix_child(obs_source_t *transition, float *out, float *in,
size_t count, size_t sample_rate, uint64_t ts,
obs_transition_audio_mix_callback_t mix)
{
void *context_data = transition->context.data;
for (size_t i = 0; i < count; i++) {
float t = get_sample_time(transition, sample_rate, i, ts);
out[i] += in[i] * mix(context_data, t);
}
}
static void process_audio(obs_source_t *transition, obs_source_t *child,
struct obs_source_audio_mix *audio, uint64_t min_ts,
uint32_t mixers, size_t channels, size_t sample_rate,
obs_transition_audio_mix_callback_t mix)
{
bool valid = child && !child->audio_pending;
struct obs_source_audio_mix child_audio;
uint64_t ts;
size_t pos;
if (!valid)
return;
ts = child->audio_ts;
obs_source_get_audio_mix(child, &child_audio);
pos = (size_t)ns_to_audio_frames(sample_rate, ts - min_ts);
if (pos > AUDIO_OUTPUT_FRAMES)
return;
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
struct audio_output_data *output = &audio->output[mix_idx];
struct audio_output_data *input = &child_audio.output[mix_idx];
if ((mixers & (1 << mix_idx)) == 0)
continue;
for (size_t ch = 0; ch < channels; ch++) {
float *out = output->data[ch];
float *in = input->data[ch];
mix_child(transition, out + pos, in,
AUDIO_OUTPUT_FRAMES - pos,
sample_rate, ts, mix);
}
}
}
static inline uint64_t calc_min_ts(obs_source_t *sources[2])
{
uint64_t min_ts = 0;
for (size_t i = 0; i < 2; i++) {
if (sources[i] && !sources[i]->audio_pending) {
if (!min_ts || sources[i]->audio_ts < min_ts)
min_ts = sources[i]->audio_ts;
}
}
return min_ts;
}
static inline bool stop_audio(obs_source_t *transition)
{
transition->transitioning_audio = false;
if (!transition->transitioning_video) {
obs_transition_stop(transition);
return true;
}
return false;
}
bool obs_transition_audio_render(obs_source_t *transition,
uint64_t *ts_out, struct obs_source_audio_mix *audio,
uint32_t mixers, size_t channels, size_t sample_rate,
obs_transition_audio_mix_callback_t mix_a,
obs_transition_audio_mix_callback_t mix_b)
{
obs_source_t *sources[2];
struct transition_state state = {0};
bool stopped = false;
uint64_t min_ts;
float t;
if (!transition_valid(transition, "obs_transition_audio_render"))
return false;
lock_transition(transition);
sources[0] = transition->transition_sources[0];
sources[1] = transition->transition_sources[1];
min_ts = calc_min_ts(sources);
if (min_ts) {
t = calc_time(transition, min_ts);
if (t >= 1.0f && transition->transitioning_audio)
stopped = stop_audio(transition);
sources[0] = transition->transition_sources[0];
sources[1] = transition->transition_sources[1];
min_ts = calc_min_ts(sources);
if (min_ts)
copy_transition_state(transition, &state);
} else if (!transition->transitioning_video &&
transition->transitioning_audio) {
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
stopped = stop_audio(transition);
}
unlock_transition(transition);
if (min_ts) {
if (state.transitioning_audio) {
if (state.s[0])
process_audio(transition, state.s[0], audio,
min_ts, mixers, channels,
sample_rate, mix_a);
if (state.s[1])
process_audio(transition, state.s[1], audio,
min_ts, mixers, channels,
sample_rate, mix_b);
} else if (state.s[0]) {
memcpy(audio->output[0].data[0],
state.s[0]->audio_output_buf[0][0],
TOTAL_AUDIO_SIZE);
}
obs_source_release(state.s[0]);
obs_source_release(state.s[1]);
}
if (stopped)
handle_stop(transition);
libobs: Implement transition sources Transition sources are implemented by registering a source type as OBS_SOURCE_TYPE_TRANSITION. They're automatically marked as video composite sources, and video_render/audio_render callbacks must be set when registering the source. get_width and get_height callbacks are unused for these types of sources, as transitions automatically handle width/height behind the scenes with the transition settings. In the video_render callback, the helper function obs_transition_video_render is used to assist in automatically processing and rendering the audio. A render callback is passed to the function, which in turn passes to/from textures that are automatically rendered in the back-end. Similarly, in the audio_render callback, the helper function obs_transition_audio_render is used to assist in automatically processing and rendering the audio. Two mix callbacks are used to handle how the source/destination sources are mixed together. To ensure the best possible quality, audio processing is per-sample. Transitions can be set to automatically resize, or they can be set to have a fixed size. Sources within transitions can be made to scale to the transition size (with or without aspect ratio), or to not scale unless they're bigger than the transition. They can have a specific alignment within the transition, or they just default to top-left. These features are implemented for the purpose of extending transitions to also act as "switch" sources later, where you can switch to/from two different sources using the transition animation. Planned (but not yet implemented and lower priority) features: - "Switch" transitions which allow the ability to switch back and forth between two sources with a transitioning animation without discarding the references - Easing options to allow the option to transition with a bezier or custom curve - Manual transitioning to allow the front-end/user to manually control the transition offset
2016-01-03 16:41:14 -08:00
*ts_out = min_ts;
return !!min_ts;
}
void obs_transition_enable_fixed(obs_source_t *transition,
bool enable, uint32_t duration)
{
if (!transition_valid(transition, "obs_transition_enable_fixed"))
return;
transition->transition_use_fixed_duration = enable;
transition->transition_fixed_duration = duration;
}
bool obs_transition_fixed(obs_source_t *transition)
{
return transition_valid(transition, "obs_transition_fixed") ?
transition->transition_use_fixed_duration : false;
}
static inline obs_source_t *copy_source_state(obs_source_t *tr_dest,
obs_source_t *tr_source, size_t idx)
{
obs_source_t *old_child = tr_dest->transition_sources[idx];
obs_source_t *new_child = tr_source->transition_sources[idx];
bool active = tr_source->transition_source_active[idx];
if (old_child && tr_dest->transition_source_active[idx])
obs_source_remove_active_child(tr_dest, old_child);
tr_dest->transition_sources[idx] = new_child;
tr_dest->transition_source_active[idx] = active;
if (active && new_child)
obs_source_add_active_child(tr_dest, new_child);
obs_source_addref(new_child);
return old_child;
}
void obs_transition_swap_begin(obs_source_t *tr_dest, obs_source_t *tr_source)
{
obs_source_t *old_children[2];
if (tr_dest == tr_source)
return;
lock_textures(tr_source);
lock_textures(tr_dest);
lock_transition(tr_source);
lock_transition(tr_dest);
for (size_t i = 0; i < 2; i++)
old_children[i] = copy_source_state(tr_dest, tr_source, i);
unlock_transition(tr_dest);
unlock_transition(tr_source);
for (size_t i = 0; i < 2; i++)
obs_source_release(old_children[i]);
}
void obs_transition_swap_end(obs_source_t *tr_dest, obs_source_t *tr_source)
{
if (tr_dest == tr_source)
return;
obs_transition_clear(tr_source);
for (size_t i = 0; i < 2; i++) {
gs_texrender_t *dest = tr_dest->transition_texrender[i];
gs_texrender_t *source = tr_source->transition_texrender[i];
tr_dest->transition_texrender[i] = source;
tr_source->transition_texrender[i] = dest;
}
unlock_textures(tr_dest);
unlock_textures(tr_source);
}