Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linux-v4l2: Add support for dv timings #385

Merged
merged 6 commits into from Feb 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/linux-v4l2/data/locale/en-US.ini
Expand Up @@ -3,6 +3,7 @@ Device="Device"
Input="Input"
ImageFormat="Video Format"
VideoStandard="Video Standard"
DVTiming="DV Timing"
Resolution="Resolution"
FrameRate="Frame Rate"
LeaveUnchanged="Leave Unchanged"
Expand Down
37 changes: 37 additions & 0 deletions plugins/linux-v4l2/v4l2-helpers.c
Expand Up @@ -236,3 +236,40 @@ int_fast32_t v4l2_set_standard(int_fast32_t dev, int *standard)

return 0;
}

int_fast32_t v4l2_enum_dv_timing(int_fast32_t dev, struct v4l2_dv_timings *dvt,
int index)
{
if (!dev || !dvt)
return -1;

struct v4l2_enum_dv_timings iter;
memset(&iter, 0, sizeof(iter));
iter.index = index;

if (v4l2_ioctl(dev, VIDIOC_ENUM_DV_TIMINGS, &iter) < 0)
return -1;

memcpy(dvt, &iter.timings, sizeof(struct v4l2_dv_timings));

return 0;
}

int_fast32_t v4l2_set_dv_timing(int_fast32_t dev, int *timing)
{
if (!dev || !timing)
return -1;

if (*timing == -1)
return 0;

struct v4l2_dv_timings dvt;

if (v4l2_enum_dv_timing(dev, &dvt, *timing) < 0)
return -1;

if (v4l2_ioctl(dev, VIDIOC_S_DV_TIMINGS, &dvt) < 0)
return -1;

return 0;
}
23 changes: 23 additions & 0 deletions plugins/linux-v4l2/v4l2-helpers.h
Expand Up @@ -270,6 +270,29 @@ int_fast32_t v4l2_set_framerate(int_fast32_t dev, int *framerate);
*/
int_fast32_t v4l2_set_standard(int_fast32_t dev, int *standard);

/**
* Get the dv timing for an input with a specified index
*
* @param dev handle to the v4l2 device
* @param timing pointer to the timing structure to fill
* @param index index of the dv timing to fetch
*
* @return negative on failure
*/
int_fast32_t v4l2_enum_dv_timing(int_fast32_t dev, struct v4l2_dv_timings *dvt,
int index);
/**
* Set a dv timing on the device
*
* Currently standard will not be changed on success or error.
*
* @param dev handle to the v4l2 device
* @param timing index of the timing to use or -1 to leave as is
*
* @return negative on failure
*/
int_fast32_t v4l2_set_dv_timing(int_fast32_t dev, int *timing);

#ifdef __cplusplus
}
#endif
63 changes: 62 additions & 1 deletion plugins/linux-v4l2/v4l2-input.c
Expand Up @@ -57,6 +57,7 @@ struct v4l2_data {
int input;
int pixfmt;
int standard;
int dv_timing;
int resolution;
int framerate;
bool sys_timing;
Expand Down Expand Up @@ -216,6 +217,7 @@ static void v4l2_defaults(obs_data_t *settings)
obs_data_set_default_int(settings, "input", -1);
obs_data_set_default_int(settings, "pixelformat", -1);
obs_data_set_default_int(settings, "standard", -1);
obs_data_set_default_int(settings, "dv_timing", -1);
obs_data_set_default_int(settings, "resolution", -1);
obs_data_set_default_int(settings, "framerate", -1);
obs_data_set_default_bool(settings, "system_timing", false);
Expand Down Expand Up @@ -399,6 +401,43 @@ static void v4l2_standard_list(int dev, obs_property_t *prop)
}
}

/*
* List dv timings for the device
*/
static void v4l2_dv_timing_list(int dev, obs_property_t *prop)
{
struct v4l2_dv_timings dvt;
struct dstr buf;
int index = 0;
dstr_init(&buf);

obs_property_list_clear(prop);

obs_property_list_add_int(prop, obs_module_text("LeaveUnchanged"), -1);

while (v4l2_enum_dv_timing(dev, &dvt, index) == 0) {
/* i do not pretend to understand, this is from qv4l2 ... */
double h = (double) dvt.bt.height + dvt.bt.vfrontporch +
dvt.bt.vsync + dvt.bt.vbackporch +
dvt.bt.il_vfrontporch + dvt.bt.il_vsync +
dvt.bt.il_vbackporch;
double w = (double) dvt.bt.width + dvt.bt.hfrontporch +
dvt.bt.hsync + dvt.bt.hbackporch;
double i = (dvt.bt.interlaced) ? 2.0f : 1.0f;
double rate = (double) dvt.bt.pixelclock / (w * (h / i));

dstr_printf(&buf, "%ux%u%c %.2f",
dvt.bt.width, dvt.bt.height,
(dvt.bt.interlaced) ? 'i' : 'p', rate);

obs_property_list_add_int(prop, buf.array, index);

index++;
}

dstr_free(&buf);
}

/*
* List resolutions for device and format
*/
Expand Down Expand Up @@ -556,30 +595,37 @@ static bool format_selected(obs_properties_t *props, obs_property_t *p,
uint32_t caps = 0;
if (v4l2_get_input_caps(dev, input, &caps) < 0)
return false;
caps &= V4L2_IN_CAP_STD;
caps &= V4L2_IN_CAP_STD | V4L2_IN_CAP_DV_TIMINGS;

obs_property_t *resolution = obs_properties_get(props, "resolution");
obs_property_t *framerate = obs_properties_get(props, "framerate");
obs_property_t *standard = obs_properties_get(props, "standard");
obs_property_t *dv_timing = obs_properties_get(props, "dv_timing");

obs_property_set_visible(resolution, (!caps) ? true : false);
obs_property_set_visible(framerate, (!caps) ? true : false);
obs_property_set_visible(standard,
(caps & V4L2_IN_CAP_STD) ? true : false);
obs_property_set_visible(dv_timing,
(caps & V4L2_IN_CAP_DV_TIMINGS) ? true : false);

if (!caps) {
v4l2_resolution_list(dev, obs_data_get_int(
settings, "pixelformat"), resolution);
}
if (caps & V4L2_IN_CAP_STD)
v4l2_standard_list(dev, standard);
if (caps & V4L2_IN_CAP_DV_TIMINGS)
v4l2_dv_timing_list(dev, dv_timing);

v4l2_close(dev);

if (!caps)
obs_property_modified(resolution, settings);
if (caps & V4L2_IN_CAP_STD)
obs_property_modified(standard, settings);
if (caps & V4L2_IN_CAP_DV_TIMINGS)
obs_property_modified(dv_timing, settings);

return true;
}
Expand Down Expand Up @@ -673,6 +719,11 @@ static obs_properties_t *v4l2_properties(void *vptr)
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_visible(standard_list, false);

obs_property_t *dv_timing_list = obs_properties_add_list(props,
"dv_timing", obs_module_text("DVTiming"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_visible(dv_timing_list, false);

obs_property_t *resolution_list = obs_properties_add_list(props,
"resolution", obs_module_text("Resolution"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
Expand Down Expand Up @@ -775,6 +826,15 @@ static void v4l2_init(struct v4l2_data *data)
data->resolution = -1;
data->framerate = -1;
}
/* set dv timing if supported */
if (input_caps & V4L2_IN_CAP_DV_TIMINGS) {
if (v4l2_set_dv_timing(data->dev, &data->dv_timing) < 0) {
blog(LOG_ERROR, "Unable to set dv timing");
goto fail;
}
data->resolution = -1;
data->framerate = -1;
}

/* set pixel format and resolution */
if (v4l2_set_format(data->dev, &data->resolution, &data->pixfmt,
Expand Down Expand Up @@ -837,6 +897,7 @@ static void v4l2_update(void *vptr, obs_data_t *settings)
data->input = obs_data_get_int(settings, "input");
data->pixfmt = obs_data_get_int(settings, "pixelformat");
data->standard = obs_data_get_int(settings, "standard");
data->dv_timing = obs_data_get_int(settings, "dv_timing");
data->resolution = obs_data_get_int(settings, "resolution");
data->framerate = obs_data_get_int(settings, "framerate");
data->sys_timing = obs_data_get_bool(settings, "system_timing");
Expand Down