/** * 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); }
/** * 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); }
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); }
/** * 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); }
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); }
/** * Initialize the v4l2 device * * This function: * - tries to open the device * - sets pixelformat and requested resolution * - sets the requested framerate * - maps the buffers * - starts the capture thread */ 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); data->dev = v4l2_open(data->device_id, O_RDWR | O_NONBLOCK); if (data->dev == -1) { blog(LOG_ERROR, "Unable to open device"); goto fail; } /* set input */ if (v4l2_set_input(data->dev, &data->input) < 0) { blog(LOG_ERROR, "Unable to set input %d", data->input); 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 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, &data->linesize) < 0) { blog(LOG_ERROR, "Unable to set format"); goto fail; } if (v4l2_to_obs_video_format(data->pixfmt) == VIDEO_FORMAT_NONE) { blog(LOG_ERROR, "Selected video format not supported"); goto fail; } v4l2_unpack_tuple(&data->width, &data->height, data->resolution); blog(LOG_INFO, "Resolution: %dx%d", data->width, data->height); blog(LOG_INFO, "Pixelformat: %s", V4L2_FOURCC_STR(data->pixfmt)); blog(LOG_INFO, "Linesize: %d Bytes", data->linesize); /* set framerate */ if (v4l2_set_framerate(data->dev, &data->framerate) < 0) { blog(LOG_ERROR, "Unable to set framerate"); goto fail; } v4l2_unpack_tuple(&fps_num, &fps_denom, data->framerate); blog(LOG_INFO, "Framerate: %.2f fps", (float) fps_denom / fps_num); /* map buffers */ if (v4l2_create_mmap(data->dev, &data->buffers) < 0) { blog(LOG_ERROR, "Failed to map buffers"); goto fail; } /* start the capture thread */ if (os_event_init(&data->event, OS_EVENT_TYPE_MANUAL) != 0) goto fail; if (pthread_create(&data->thread, NULL, v4l2_thread, data) != 0) goto fail; return; fail: blog(LOG_ERROR, "Initialization failed"); v4l2_terminate(data); }