Browse Source

Merge pull request #382 from fryshorts/v4l2-tuner-devices

linux-v4l2: Add support for video standards
Jim 10 years ago
parent
commit
aa681119c7

+ 1 - 0
plugins/linux-v4l2/data/locale/en-US.ini

@@ -2,6 +2,7 @@ V4L2Input="Video Capture Device (V4L2)"
 Device="Device"
 Input="Input"
 ImageFormat="Video Format"
+VideoStandard="Video Standard"
 Resolution="Resolution"
 FrameRate="Frame Rate"
 LeaveUnchanged="Leave Unchanged"

+ 37 - 0
plugins/linux-v4l2/v4l2-helpers.c

@@ -133,6 +133,27 @@ int_fast32_t v4l2_set_input(int_fast32_t dev, int *input)
 		: v4l2_ioctl(dev, VIDIOC_S_INPUT, input);
 }
 
+int_fast32_t v4l2_get_input_caps(int_fast32_t dev, int input, uint32_t *caps)
+{
+	if (!dev || !caps)
+		return -1;
+
+	if (input == -1) {
+		if (v4l2_ioctl(dev, VIDIOC_G_INPUT, &input) < 0)
+			return -1;
+	}
+
+	struct v4l2_input in;
+	memset(&in, 0, sizeof(in));
+	in.index = input;
+
+	if (v4l2_ioctl(dev, VIDIOC_ENUMINPUT, &in) < 0)
+		return -1;
+
+	*caps = in.capabilities;
+	return 0;
+}
+
 int_fast32_t v4l2_set_format(int_fast32_t dev, int *resolution,
 		int *pixelformat, int *bytesperline)
 {
@@ -199,3 +220,19 @@ int_fast32_t v4l2_set_framerate(int_fast32_t dev, int *framerate)
 			par.parm.capture.timeperframe.denominator);
 	return 0;
 }
+
+int_fast32_t v4l2_set_standard(int_fast32_t dev, int *standard)
+{
+	if (!dev || !standard)
+		return -1;
+
+	if (*standard == -1) {
+		if (v4l2_ioctl(dev, VIDIOC_G_STD, standard) < 0)
+			return -1;
+	} else {
+		if (v4l2_ioctl(dev, VIDIOC_S_STD, standard) < 0)
+			return -1;
+	}
+
+	return 0;
+}

+ 23 - 0
plugins/linux-v4l2/v4l2-helpers.h

@@ -219,6 +219,17 @@ int_fast32_t v4l2_destroy_mmap(struct v4l2_buffer_data *buf);
  */
 int_fast32_t v4l2_set_input(int_fast32_t dev, int *input);
 
+/**
+ * Get capabilities for an input.
+ *
+ * @param dev handle for the v4l2 device
+ * @param input index of the input or -1 to use the currently selected
+ * @param caps capabilities for the input
+ *
+ * @return negative on failure
+ */
+int_fast32_t v4l2_get_input_caps(int_fast32_t dev, int input, uint32_t *caps);
+
 /**
  * Set the video format on the device.
  *
@@ -247,6 +258,18 @@ int_fast32_t v4l2_set_format(int_fast32_t dev, int *resolution,
  */
 int_fast32_t v4l2_set_framerate(int_fast32_t dev, int *framerate);
 
+/**
+ * Set a video standard on the device.
+ *
+ * If the action succeeds standard is set to the used video standard id.
+ *
+ * @param dev handle to the v4l2 device
+ * @param standard id of the standard to use or -1 to leave as is
+ *
+ * @return negative on failure
+ */
+int_fast32_t v4l2_set_standard(int_fast32_t dev, int *standard);
+
 #ifdef __cplusplus
 }
 #endif

+ 70 - 10
plugins/linux-v4l2/v4l2-input.c

@@ -56,6 +56,7 @@ struct v4l2_data {
 	char *device_id;
 	int input;
 	int pixfmt;
+	int standard;
 	int resolution;
 	int framerate;
 	bool sys_timing;
@@ -214,6 +215,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, "resolution", -1);
 	obs_data_set_default_int(settings, "framerate", -1);
 	obs_data_set_default_bool(settings, "system_timing", false);
@@ -336,12 +338,9 @@ static void v4l2_input_list(int_fast32_t dev, obs_property_t *prop)
 	obs_property_list_add_int(prop, obs_module_text("LeaveUnchanged"), -1);
 
 	while (v4l2_ioctl(dev, VIDIOC_ENUMINPUT, &in) == 0) {
-		if (in.type & V4L2_INPUT_TYPE_CAMERA) {
-			obs_property_list_add_int(prop, (char *) in.name,
-					in.index);
-			blog(LOG_INFO, "Found input '%s' (Index %d)", in.name,
-					in.index);
-		}
+		obs_property_list_add_int(prop, (char *) in.name, in.index);
+		blog(LOG_INFO, "Found input '%s' (Index %d)", in.name,
+				in.index);
 		in.index++;
 	}
 }
@@ -382,6 +381,24 @@ static void v4l2_format_list(int dev, obs_property_t *prop)
 	dstr_free(&buffer);
 }
 
+/*
+ * List video standards for the device
+ */
+static void v4l2_standard_list(int dev, obs_property_t *prop)
+{
+	struct v4l2_standard std;
+	std.index = 0;
+
+	obs_property_list_clear(prop);
+
+	obs_property_list_add_int(prop, obs_module_text("LeaveUnchanged"), -1);
+
+	while (v4l2_ioctl(dev, VIDIOC_ENUMSTD, &std) == 0) {
+		obs_property_list_add_int(prop, (char *) std.name, std.id);
+		std.index++;
+	}
+}
+
 /*
  * List resolutions for device and format
  */
@@ -535,12 +552,34 @@ static bool format_selected(obs_properties_t *props, obs_property_t *p,
 	if (dev == -1)
 		return false;
 
-	obs_property_t *prop = obs_properties_get(props, "resolution");
-	v4l2_resolution_list(dev, obs_data_get_int(settings, "pixelformat"),
-			prop);
+	int input     = (int) obs_data_get_int(settings, "input");
+	uint32_t caps = 0;
+	if (v4l2_get_input_caps(dev, input, &caps) < 0)
+		return false;
+	caps &= V4L2_IN_CAP_STD;
+
+	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_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);
+
+	if (!caps) {
+		v4l2_resolution_list(dev, obs_data_get_int(
+				settings, "pixelformat"), resolution);
+	}
+	if (caps & V4L2_IN_CAP_STD)
+		v4l2_standard_list(dev, standard);
+
 	v4l2_close(dev);
 
-	obs_property_modified(prop, settings);
+	if (!caps)
+		obs_property_modified(resolution, settings);
+	if (caps & V4L2_IN_CAP_STD)
+		obs_property_modified(standard, settings);
 
 	return true;
 }
@@ -629,6 +668,11 @@ static obs_properties_t *v4l2_properties(void *vptr)
 			"pixelformat", obs_module_text("VideoFormat"),
 			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
 
+	obs_property_t *standard_list = obs_properties_add_list(props,
+			"standard", obs_module_text("VideoStandard"),
+			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
+	obs_property_set_visible(standard_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);
@@ -701,6 +745,7 @@ static void v4l2_destroy(void *vptr)
  */
 static void v4l2_init(struct v4l2_data *data)
 {
+	uint32_t input_caps;
 	int fps_num, fps_denom;
 
 	blog(LOG_INFO, "Start capture from %s", data->device_id);
@@ -716,6 +761,20 @@ static void v4l2_init(struct v4l2_data *data)
 		goto fail;
 	}
 	blog(LOG_INFO, "Input: %d", data->input);
+	if (v4l2_get_input_caps(data->dev, -1, &input_caps) < 0) {
+		blog(LOG_ERROR, "Unable to get input capabilities");
+		goto fail;
+	}
+
+	/* set video standard if supported */
+	if (input_caps & V4L2_IN_CAP_STD) {
+		if (v4l2_set_standard(data->dev, &data->standard) < 0) {
+			blog(LOG_ERROR, "Unable to set video standard");
+			goto fail;
+		}
+		data->resolution = -1;
+		data->framerate  = -1;
+	}
 
 	/* set pixel format and resolution */
 	if (v4l2_set_format(data->dev, &data->resolution, &data->pixfmt,
@@ -777,6 +836,7 @@ static void v4l2_update(void *vptr, obs_data_t *settings)
 	data->device_id  = bstrdup(obs_data_get_string(settings, "device_id"));
 	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->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");