diff --git a/src/libs/device.c b/src/libs/device.c index e965126..6e1d57c 100644 --- a/src/libs/device.c +++ b/src/libs/device.c @@ -93,6 +93,7 @@ static int _device_open_io_method(us_device_s *dev); static int _device_open_io_method_mmap(us_device_s *dev); static int _device_open_io_method_userptr(us_device_s *dev); static int _device_open_queue_buffers(us_device_s *dev); +static int _device_open_export_to_dma(us_device_s *dev); static int _device_apply_resolution(us_device_s *dev, uint width, uint height, float hz); static void _device_apply_controls(us_device_s *dev); @@ -176,8 +177,6 @@ int us_device_open(us_device_s *dev) { _D_LOG_PERROR("Can't open device"); goto error; } - _D_LOG_INFO("Device fd=%d opened", run->fd); - if (_device_open_check_cap(dev) < 0) { goto error; } @@ -195,9 +194,21 @@ int us_device_open(us_device_s *dev) { if (_device_open_queue_buffers(dev) < 0) { goto error; } + if (dev->dma_export) { + run->dma = !_device_open_export_to_dma(dev); + if (!run->dma && dev->dma_required) { + goto error; + } + } _device_apply_controls(dev); - _D_LOG_DEBUG("Device fd=%d initialized", run->fd); + enum v4l2_buf_type type = run->capture_type; + if (us_xioctl(run->fd, VIDIOC_STREAMON, &type) < 0) { + _D_LOG_PERROR("Can't start capturing"); + goto error; + } + run->streamon = true; + _D_LOG_INFO("Capturing started"); return 0; error: @@ -208,7 +219,14 @@ error: void us_device_close(us_device_s *dev) { us_device_runtime_s *const run = dev->run; - run->persistent_timeout_reported = false; + if (run->streamon) { + enum v4l2_buf_type type = run->capture_type; + if (us_xioctl(run->fd, VIDIOC_STREAMOFF, &type) < 0) { + _D_LOG_PERROR("Can't stop capturing"); + } + run->streamon = false; + _D_LOG_INFO("Capturing stopped"); + } if (run->hw_bufs != NULL) { _D_LOG_DEBUG("Releasing device buffers ..."); @@ -235,58 +253,8 @@ void us_device_close(us_device_s *dev) { run->n_bufs = 0; } - if (run->fd >= 0) { - _D_LOG_DEBUG("Closing device ..."); - if (close(run->fd) < 0) { - _D_LOG_PERROR("Can't close device fd=%d", run->fd); - } else { - _D_LOG_INFO("Device fd=%d closed", run->fd); - } - run->fd = -1; - } -} - -int us_device_export_to_dma(us_device_s *dev) { - us_device_runtime_s *const run = dev->run; - - for (uint index = 0; index < run->n_bufs; ++index) { - struct v4l2_exportbuffer exp = { - .type = run->capture_type, - .index = index, - }; - _D_LOG_DEBUG("Exporting device buffer=%u to DMA ...", index); - if (us_xioctl(run->fd, VIDIOC_EXPBUF, &exp) < 0) { - _D_LOG_PERROR("Can't export device buffer=%u to DMA", index); - goto error; - } - run->hw_bufs[index].dma_fd = exp.fd; - } - return 0; - -error: - for (uint index = 0; index < run->n_bufs; ++index) { - US_CLOSE_FD(run->hw_bufs[index].dma_fd, close); - } - return -1; -} - -int us_device_switch_capturing(us_device_s *dev, bool enable) { - us_device_runtime_s *const run = dev->run; - - if (enable != run->capturing) { - enum v4l2_buf_type type = run->capture_type; - - _D_LOG_DEBUG("%s device capturing ...", (enable ? "Starting" : "Stopping")); - if (us_xioctl(run->fd, (enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF), &type) < 0) { - _D_LOG_PERROR("Can't %s capturing", (enable ? "start" : "stop")); - if (enable) { - return -1; - } - } - run->capturing = enable; - _D_LOG_INFO("Capturing %s", (enable ? "started" : "stopped")); - } - return 0; + US_CLOSE_FD(run->fd, close); + run->persistent_timeout_reported = false; } int us_device_select(us_device_s *dev, bool *has_read, bool *has_error) { @@ -316,7 +284,7 @@ int us_device_select(us_device_s *dev, bool *has_read, bool *has_error) { *has_read = false; *has_error = false; } - _D_LOG_DEBUG("Device select() --> %d", retval); + _D_LOG_DEBUG("Device select() --> %d; has_read=%d, has_error=%d", retval, *has_read, *has_error); if (retval > 0) { run->persistent_timeout_reported = false; @@ -452,7 +420,7 @@ int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw) { int us_device_consume_event(us_device_s *dev) { struct v4l2_event event; - _D_LOG_DEBUG("Consuming V4L2 event ..."); + _D_LOG_INFO("Consuming V4L2 event ..."); if (us_xioctl(dev->run->fd, VIDIOC_DQEVENT, &event) == 0) { switch (event.type) { case V4L2_EVENT_SOURCE_CHANGE: @@ -932,6 +900,30 @@ static int _device_open_queue_buffers(us_device_s *dev) { return 0; } +static int _device_open_export_to_dma(us_device_s *dev) { + us_device_runtime_s *const run = dev->run; + + for (uint index = 0; index < run->n_bufs; ++index) { + struct v4l2_exportbuffer exp = { + .type = run->capture_type, + .index = index, + }; + _D_LOG_DEBUG("Exporting device buffer=%u to DMA ...", index); + if (us_xioctl(run->fd, VIDIOC_EXPBUF, &exp) < 0) { + _D_LOG_PERROR("Can't export device buffer=%u to DMA", index); + goto error; + } + run->hw_bufs[index].dma_fd = exp.fd; + } + return 0; + +error: + for (uint index = 0; index < run->n_bufs; ++index) { + US_CLOSE_FD(run->hw_bufs[index].dma_fd, close); + } + return -1; +} + static int _device_apply_resolution(us_device_s *dev, uint width, uint height, float hz) { // Тут VIDEO_MIN_* не используются из-за странностей минимального разрешения при отсутствии сигнала // у некоторых устройств, например TC358743 diff --git a/src/libs/device.h b/src/libs/device.h index bf3fab5..05ec177 100644 --- a/src/libs/device.h +++ b/src/libs/device.h @@ -65,9 +65,10 @@ typedef struct { uz raw_size; uint n_bufs; us_hw_buffer_s *hw_bufs; + bool dma; enum v4l2_buf_type capture_type; bool capture_mplane; - bool capturing; + bool streamon; bool persistent_timeout_reported; } us_device_runtime_s; @@ -110,6 +111,8 @@ typedef struct { enum v4l2_memory io_method; bool dv_timings; uint n_bufs; + bool dma_export; + bool dma_required; uint desired_fps; uz min_frame_size; bool persistent; @@ -129,8 +132,6 @@ int us_device_parse_io_method(const char *str); int us_device_open(us_device_s *dev); void us_device_close(us_device_s *dev); -int us_device_export_to_dma(us_device_s *dev); -int us_device_switch_capturing(us_device_s *dev, bool enable); int us_device_select(us_device_s *dev, bool *has_read, bool *has_error); int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw); int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw); diff --git a/src/ustreamer/stream.c b/src/ustreamer/stream.c index 4394a71..087e4ed 100644 --- a/src/ustreamer/stream.c +++ b/src/ustreamer/stream.c @@ -150,8 +150,6 @@ void us_stream_loop(us_stream_s *stream) { # endif } else { if (has_read) { - US_LOG_DEBUG("Frame is ready"); - # ifdef WITH_GPIO us_gpio_set_stream_online(true); # endif @@ -197,17 +195,13 @@ void us_stream_loop(us_stream_s *stream) { } } - if (has_error) { - US_LOG_INFO("Got V4L2 event"); - if (us_device_consume_event(stream->dev) < 0) { - break; - } + if (has_error && us_device_consume_event(stream->dev) < 0) { + break; } } } us_workers_pool_destroy(pool); - us_device_switch_capturing(stream->dev, false); us_device_close(stream->dev); # ifdef WITH_GPIO @@ -266,17 +260,12 @@ static us_workers_pool_s *_stream_init_loop(us_stream_s *stream) { } static us_workers_pool_s *_stream_init_one(us_stream_s *stream) { - if (us_device_open(stream->dev) < 0) { - goto error; - } - if ( + stream->dev->dma_export = ( stream->enc->type == US_ENCODER_TYPE_M2M_VIDEO || stream->enc->type == US_ENCODER_TYPE_M2M_IMAGE || (_RUN(h264) && !us_is_jpeg(stream->dev->run->format)) - ) { - us_device_export_to_dma(stream->dev); - } - if (us_device_switch_capturing(stream->dev, true) < 0) { + ); + if (us_device_open(stream->dev) < 0) { goto error; } return us_encoder_workers_pool_init(stream->enc, stream->dev); diff --git a/src/v4p/main.c b/src/v4p/main.c index 01d579d..e3ff868 100644 --- a/src/v4p/main.c +++ b/src/v4p/main.c @@ -194,7 +194,7 @@ static void _main_loop(void) { if (us_drm_wait_for_vsync(drm) == 0) { us_drm_expose(drm, US_DRM_EXPOSE_BUSY, NULL, 0); } - if (dev->run->capturing) { + if (dev->run->fd >= 0) { goto close; } else { _slowdown(); @@ -205,9 +205,6 @@ static void _main_loop(void) { if (us_device_open(dev) < 0) { goto close; } - if (us_device_switch_capturing(dev, true) < 0) { - goto close; - } while (!atomic_load(&_g_stop)) { if (atomic_load(&_g_ustreamer_online)) { @@ -235,32 +232,28 @@ static void _main_loop(void) { } } else { if (has_read) { - US_LOG_DEBUG("Frame is ready"); us_hw_buffer_s *hw; const int buf_index = us_device_grab_buffer(dev, &hw); if (buf_index >= 0) { - if (us_drm_expose(drm, US_DRM_EXPOSE_FRAME, &hw->raw, dev->run->hz) < 0) { - _slowdown(); - continue; - } + const int exposed = us_drm_expose(drm, US_DRM_EXPOSE_FRAME, &hw->raw, dev->run->hz); if (us_device_release_buffer(dev, hw) < 0) { goto close; } + if (exposed < 0) { + _slowdown(); + continue; + } } else if (buf_index == -2) { goto close; } } - if (has_error) { - US_LOG_INFO("Got V4L2 event"); - if (us_device_consume_event(dev) < 0) { - goto close; - } + if (has_error && us_device_consume_event(dev) < 0) { + goto close; } } } close: - us_device_switch_capturing(dev, false); us_device_close(dev); _slowdown(); }