Exemple #1
0
/**
 * Device removed callback
 *
 * We stop recording here so we don't block the device node
 */
static void device_removed(const char *dev, void *vptr)
{
	V4L2_DATA(vptr);

	obs_source_update_properties(data->source);

	if (strcmp(data->device_id, dev))
		return;

	blog(LOG_INFO, "Device %s disconnected", dev);

	v4l2_terminate(data);
}
Exemple #2
0
static obs_properties_t *v4l2_properties(void *vptr)
{
	V4L2_DATA(vptr);

	obs_properties_t *props = obs_properties_create();

	obs_property_t *device_list = obs_properties_add_list(props,
			"device_id", obs_module_text("Device"),
			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);

	obs_property_t *input_list = obs_properties_add_list(props,
			"input", obs_module_text("Input"),
			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);

	obs_property_t *format_list = obs_properties_add_list(props,
			"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 *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);

	obs_properties_add_list(props,
			"framerate", obs_module_text("FrameRate"),
			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);

	obs_properties_add_bool(props,
			"buffering", obs_module_text("UseBuffering"));

	obs_data_t *settings = obs_source_get_settings(data->source);
	v4l2_device_list(device_list, settings);
	obs_data_release(settings);

	obs_property_set_modified_callback(device_list, device_selected);
	obs_property_set_modified_callback(input_list, input_selected);
	obs_property_set_modified_callback(format_list, format_selected);
	obs_property_set_modified_callback(resolution_list,
			resolution_selected);

	return props;
}
Exemple #3
0
/**
 * Device removed callback
 *
 * We stop recording here so we don't block the device node
 */
static void device_removed(void *vptr, calldata_t *calldata)
{
	V4L2_DATA(vptr);

	obs_source_update_properties(data->source);

	const char *dev;
	calldata_get_string(calldata, "device", &dev);

	if (strcmp(data->device_id, dev))
		return;

	blog(LOG_INFO, "Device %s disconnected", dev);

	v4l2_terminate(data);
}
Exemple #4
0
static void v4l2_destroy(void *vptr)
{
	V4L2_DATA(vptr);

	if (!data)
		return;

	v4l2_terminate(data);

	if (data->device_id)
		bfree(data->device_id);

#if HAVE_UDEV
	v4l2_unref_udev(data->udev);
#endif

	bfree(data);
}
Exemple #5
0
/**
 * 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.
 */
static void v4l2_update(void *vptr, obs_data_t *settings)
{
	V4L2_DATA(vptr);

	v4l2_terminate(data);

	if (data->device_id)
		bfree(data->device_id);

	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->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");

	v4l2_init(data);
}
Exemple #6
0
static void v4l2_destroy(void *vptr)
{
	V4L2_DATA(vptr);

	if (!data)
		return;

	v4l2_terminate(data);

	if (data->device_id)
		bfree(data->device_id);

#if HAVE_UDEV
	signal_handler_t *sh = v4l2_get_udev_signalhandler();

	signal_handler_disconnect(sh, "device_added", device_added, data);
	signal_handler_disconnect(sh, "device_removed", device_removed, data);

	v4l2_unref_udev();
#endif

	bfree(data);
}
Exemple #7
0
/*
 * Worker thread to get video data
 */
static void *v4l2_thread(void *vptr)
{
	V4L2_DATA(vptr);
	int r;
	fd_set fds;
	uint8_t *start;
	uint64_t frames;
	uint64_t first_ts;
	struct timeval tv;
	struct v4l2_buffer buf;
	struct obs_source_frame out;
	size_t plane_offsets[MAX_AV_PLANES];

	if (v4l2_start_capture(data->dev, &data->buffers) < 0)
		goto exit;

	frames   = 0;
	first_ts = 0;
	v4l2_prep_obs_frame(data, &out, plane_offsets);

	while (os_event_try(data->event) == EAGAIN) {
		FD_ZERO(&fds);
		FD_SET(data->dev, &fds);
		tv.tv_sec = 1;
		tv.tv_usec = 0;

		r = select(data->dev + 1, &fds, NULL, NULL, &tv);
		if (r < 0) {
			if (errno == EINTR)
				continue;
			blog(LOG_DEBUG, "select failed");
			break;
		} else if (r == 0) {
			blog(LOG_DEBUG, "select timeout");
			continue;
		}

		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;

		if (v4l2_ioctl(data->dev, VIDIOC_DQBUF, &buf) < 0) {
			if (errno == EAGAIN)
				continue;
			blog(LOG_DEBUG, "failed to dequeue buffer");
			break;
		}

		out.timestamp = timeval2ns(buf.timestamp);
		if (!frames)
			first_ts = out.timestamp;
		out.timestamp -= first_ts;

		start = (uint8_t *) data->buffers.info[buf.index].start;
		for (uint_fast32_t i = 0; i < MAX_AV_PLANES; ++i)
			out.data[i] = start + plane_offsets[i];
		obs_source_output_video(data->source, &out);

		if (v4l2_ioctl(data->dev, VIDIOC_QBUF, &buf) < 0) {
			blog(LOG_DEBUG, "failed to enqueue buffer");
			break;
		}

		frames++;
	}

	blog(LOG_INFO, "Stopped capture after %"PRIu64" frames", frames);

exit:
	v4l2_stop_capture(data->dev);
	return NULL;
}