void vid_free(vid_t vid) { struct vid *v = vid; v4l2_stop_capture(v->cam); fbd_free(v->fbd); if (v->enc) jpg_enc_free(v->enc); if (v->dec) jpg_dec_free(v->dec); v4l2_free(v->cam); free(v); }
int main(int argc, char *argv[]) { app_t a = app_create(0); v4l2_dev_t v = v4l2_create(a, "/dev/video2", 0, 0); v4l2_set_img_proc(v, img_proc, v); v4l2_start_capture(v); app_exec(a); v4l2_stop_capture(v); v4l2_free(v); app_free(a); return 0; }
/** * Stops the streaming * This could take some time, because the thread is stopped asynchronous. */ void video_thread_stop(void) { // Check if not already stopped streaming if (!video_thread.is_running) { return; } // Stop the streaming thread video_thread.is_running = false; // Stop the capturing if (!v4l2_stop_capture(video_thread.dev)) { printf("[video_thread] Could not stop capture of %s.\n", video_thread.dev->name); return; } // TODO: wait for the thread to finish to be able to start the thread again! }
/** * Close the V4L2 device (Thread safe) * This needs to be preformed to clean up all the buffers and close the device. * Note that this also stops the capturing if it is still capturing. * @param[in] *dev The video for linux device to close(cleanup) */ void v4l2_close(struct v4l2_device *dev) { uint8_t i; // Stop capturing (ignore result as it may already be stopped) v4l2_stop_capture(dev); // Unmap all buffers for (i = 0; i < dev->buffers_cnt; ++i) { if (munmap(dev->buffers[i].buf, dev->buffers[i].length) < 0) { printf("[v4l2] Could not unmap buffer %d for %s\n", i, dev->name); } } // Close the file pointer and free all memory close(dev->fd); free(dev->name); free(dev); }
int main(int argc, char *argv[]) { app_t a = app_create(0); jpg_dec_t d = jpg_dec_create(); v4l2_dev_t v = v4l2_create(a, NULL, 0, 0); v4l2_set_img_proc(v, img_proc, d); v4l2_start_capture(v); app_exec(a); v4l2_stop_capture(v); v4l2_free(v); jpg_dec_free(d); app_free(a); return 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; }