linux-v4l2: Selective stream restart

This commit adds a basic check to see if the v4l2 stream requires a
restart. This is primarly implemented on the basis of the fact that
the options requiring a restart have values stored in the v4l2_data
structure. A restart is only needed if any of the values have changed
since the last update.
master
Ioan Loosley 2020-05-22 18:17:00 +01:00
parent 0cb0fd7522
commit 8814e2bf4c
No known key found for this signature in database
GPG Key ID: 7E64A9CB70DC358A
3 changed files with 90 additions and 7 deletions

3
.gitignore vendored
View File

@ -27,6 +27,7 @@
#clion
.idea/
cmake-build-debug/
#other stuff (windows stuff, qt moc stuff, etc)
Release_MD/
@ -39,6 +40,8 @@ GeneratedFiles/
/UI/obs.rc
.vscode/
/other/
#make stuff

View File

@ -12,3 +12,4 @@ ColorRange="Color Range"
ColorRange.Default="Default"
ColorRange.Partial="Partial"
ColorRange.Full="Full"
CameraCtrls="Camera Controls"

View File

@ -81,6 +81,8 @@ struct v4l2_data {
pthread_t thread;
os_event_t *event;
bool framerateUnchanged;
bool resolutionUnchanged;
int_fast32_t dev;
int width;
int height;
@ -91,6 +93,7 @@ struct v4l2_data {
/* forward declarations */
static void v4l2_init(struct v4l2_data *data);
static void v4l2_terminate(struct v4l2_data *data);
static void v4l2_update(void *vptr, obs_data_t *settings);
/**
* Prepare the output frame structure for obs and compute plane offsets
@ -579,10 +582,18 @@ static bool device_selected(obs_properties_t *props, obs_property_t *p,
return false;
obs_property_t *prop = obs_properties_get(props, "input");
obs_properties_t *ctrl_props_new = obs_properties_create();
obs_properties_remove_by_name(props, "controls");
v4l2_input_list(dev, prop);
v4l2_update_controls(dev, props, settings);
v4l2_update_controls(dev, ctrl_props_new, settings);
v4l2_close(dev);
obs_properties_add_group(props, "controls",
obs_module_text("CameraCtrls"),
OBS_GROUP_NORMAL, ctrl_props_new);
obs_property_modified(prop, settings);
return true;
@ -785,6 +796,12 @@ static obs_properties_t *v4l2_properties(void *vptr)
obs_properties_add_bool(props, "buffering",
obs_module_text("UseBuffering"));
// a group to contain the camera control
obs_properties_t *ctrl_props = obs_properties_create();
obs_properties_add_group(props, "controls",
obs_module_text("CameraCtrls"),
OBS_GROUP_NORMAL, ctrl_props);
obs_data_t *settings = obs_source_get_settings(data->source);
v4l2_device_list(device_list, settings);
obs_data_release(settings);
@ -939,19 +956,78 @@ static void v4l2_update_source_flags(struct v4l2_data *data,
data->source, !obs_data_get_bool(settings, "buffering"));
}
/**
* Checking if any of the settings have changed so that we can restart the
* stream
*/
static bool v4l2_settings_changed(struct v4l2_data *data, obs_data_t *settings)
{
bool res = false;
if (obs_data_get_string(settings, "device_id") != NULL &&
data->device_id != NULL) {
res |= strcmp(data->device_id,
obs_data_get_string(settings, "device_id")) != 0;
res |= data->input != obs_data_get_int(settings, "input");
res |= data->pixfmt !=
obs_data_get_int(settings, "pixelformat");
res |= data->standard != obs_data_get_int(settings, "standard");
res |= data->dv_timing !=
obs_data_get_int(settings, "dv_timing");
if (obs_data_get_int(settings, "resolution") == -1 &&
!data->resolutionUnchanged) {
data->resolutionUnchanged = true;
res |= true;
} else if (obs_data_get_int(settings, "resolution") == -1 &&
data->resolutionUnchanged) {
res |= false;
} else {
data->resolutionUnchanged = false;
res |= (data->resolution !=
obs_data_get_int(settings, "resolution")) &&
(obs_data_get_int(settings, "resolution") != -1);
}
if (obs_data_get_int(settings, "framerate") == -1 &&
!data->framerateUnchanged) {
data->framerateUnchanged = true;
res |= true;
} else if (obs_data_get_int(settings, "framerate") == -1 &&
data->framerateUnchanged) {
res |= false;
} else {
data->framerateUnchanged = false;
res |= (data->framerate !=
obs_data_get_int(settings, "framerate")) &&
(obs_data_get_int(settings, "framerate") != -1);
}
res |= data->color_range !=
obs_data_get_int(settings, "color_range");
} else {
res = true;
}
return res;
}
/**
* Update the settings for the v4l2 source
*
* Since there are very few settings that can be changed without restarting the
* stream we don't bother to even try. Whenever this is called the currently
* active stream (if exists) is stopped, the settings are updated and finally
* the new stream is started.
* There are a few settings that can be changed without restarting the stream
* Whenever this is called the currently active stream (if exists) is stopped,
* the settings are updated and finally the new stream is started.
*/
static void v4l2_update(void *vptr, obs_data_t *settings)
{
V4L2_DATA(vptr);
v4l2_terminate(data);
bool needs_restart = v4l2_settings_changed(data, settings);
if (needs_restart)
v4l2_terminate(data);
if (data->device_id)
bfree(data->device_id);
@ -967,7 +1043,8 @@ static void v4l2_update(void *vptr, obs_data_t *settings)
v4l2_update_source_flags(data, settings);
v4l2_init(data);
if (needs_restart)
v4l2_init(data);
}
static void *v4l2_create(obs_data_t *settings, obs_source_t *source)
@ -975,6 +1052,8 @@ static void *v4l2_create(obs_data_t *settings, obs_source_t *source)
struct v4l2_data *data = bzalloc(sizeof(struct v4l2_data));
data->dev = -1;
data->source = source;
data->resolutionUnchanged = false;
data->framerateUnchanged = false;
/* Bitch about build problems ... */
#ifndef V4L2_CAP_DEVICE_CAPS