diff --git a/src/capture.c b/src/capture.c index 76dfaf1..f415c6f 100644 --- a/src/capture.c +++ b/src/capture.c @@ -6,6 +6,14 @@ #include #include +#ifdef DUMP_CAPTURED_JPEGS +# warning Enabled DUMP_CAPTURED_JPEGS +# include +# include +# include +# include +#endif + #include "tools.h" #include "device.h" #include "jpeg.h" @@ -16,7 +24,7 @@ static long double _capture_get_fluency_delay(struct device_t *dev, struct worke static int _capture_init_loop(struct device_t *dev, struct workers_pool_t *pool, sig_atomic_t *volatile global_stop); static int _capture_init(struct device_t *dev, struct workers_pool_t *pool, sig_atomic_t *volatile global_stop); static void _capture_init_workers(struct device_t *dev, struct workers_pool_t *pool, sig_atomic_t *volatile global_stop); -static void *_capture_worker_thread(void *v_ctx_ptr); +static void *_capture_worker_thread(void *v_ctx); static void _capture_destroy_workers(struct device_t *dev, struct workers_pool_t *pool); static int _capture_control(struct device_t *dev, const bool enable); static int _capture_grab_buffer(struct device_t *dev, struct v4l2_buffer *buf_info); @@ -24,7 +32,37 @@ static int _capture_release_buffer(struct device_t *dev, struct v4l2_buffer *buf static int _capture_handle_event(struct device_t *dev); -void capture_loop(struct device_t *dev, sig_atomic_t *volatile global_stop) { +void captured_picture_init(struct captured_picture_t *captured) { + memset(captured, 0, sizeof(struct captured_picture_t)); + A_PTHREAD_M_INIT(&captured->mutex); +} + +void captured_picture_destroy(struct captured_picture_t *captured) { + A_PTHREAD_M_DESTROY(&captured->mutex); +} + +#ifdef DUMP_CAPTURED_JPEGS +static void _capture_dump(struct captured_picture_t *captured) { + static unsigned count = 0; + char path[1024]; + + errno = 0; + mkdir("captured", 0777); + assert(errno == 0 || errno == EEXIST); + + sprintf(path, "captured/img_%06u.jpg", count); + int fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644); + assert(fd); + assert(write(fd, captured->picture.data, captured->picture.size) == (ssize_t)captured->picture.size); + assert(!close(fd)); + + LOG_INFO("-DDUMP_CAPTURED_JPEGS dumped %s", path); + + ++count; +} +#endif + +void capture_loop(struct device_t *dev, struct captured_picture_t *captured, sig_atomic_t *volatile global_stop) { struct workers_pool_t pool; volatile sig_atomic_t workers_stop; @@ -35,12 +73,16 @@ void capture_loop(struct device_t *dev, sig_atomic_t *volatile global_stop) { LOG_INFO("Using JPEG quality: %d%%", dev->jpeg_quality); while (_capture_init_loop(dev, &pool, global_stop) == 0) { + struct worker_t *last_worker = NULL; unsigned frames_count = 0; long double grab_after = 0; unsigned fluency_passed = 0; unsigned fps = 0; long long fps_second = 0; + LOG_DEBUG("Allocation memory for captured (result) picture ..."); + A_CALLOC(captured->picture.data, dev->run->max_picture_size, sizeof(*captured->picture.data)); + while (!*global_stop) { SEP_DEBUG('-'); @@ -49,6 +91,23 @@ void capture_loop(struct device_t *dev, sig_atomic_t *volatile global_stop) { A_PTHREAD_C_WAIT_TRUE(pool.has_free_workers, &pool.has_free_workers_cond, &pool.has_free_workers_mutex); A_PTHREAD_M_UNLOCK(&pool.has_free_workers_mutex); + if (last_worker && !last_worker->has_job && dev->run->pictures[last_worker->ctx.index].data) { + A_PTHREAD_M_LOCK(&captured->mutex); + captured->picture.size = dev->run->pictures[last_worker->ctx.index].size; + memcpy( + captured->picture.data, + dev->run->pictures[last_worker->ctx.index].data, + captured->picture.size * sizeof(*captured->picture.data) + ); + A_PTHREAD_M_UNLOCK(&captured->mutex); + + last_worker = last_worker->order_next; + +# ifdef DUMP_CAPTURED_JPEGS + _capture_dump(captured); +# endif + } + if (*global_stop) { break; } @@ -134,6 +193,12 @@ void capture_loop(struct device_t *dev, sig_atomic_t *volatile global_stop) { LOG_DEBUG("Grabbed a new frame to buffer %d", buf_info.index); pool.workers[buf_info.index].ctx.buf_info = buf_info; + if (!last_worker) { + last_worker = &pool.workers[buf_info.index]; + } else { + last_worker->order_next = &pool.workers[buf_info.index]; + } + A_PTHREAD_M_LOCK(&pool.workers[buf_info.index].has_job_mutex); pool.workers[buf_info.index].has_job = true; A_PTHREAD_M_UNLOCK(&pool.workers[buf_info.index].has_job_mutex); @@ -163,6 +228,11 @@ void capture_loop(struct device_t *dev, sig_atomic_t *volatile global_stop) { } } } + + A_PTHREAD_M_LOCK(&captured->mutex); + captured->picture.size = 0; + free(captured->picture.data); + A_PTHREAD_M_UNLOCK(&captured->mutex); } _capture_destroy_workers(dev, &pool); @@ -254,8 +324,8 @@ static void _capture_init_workers(struct device_t *dev, struct workers_pool_t *p } } -static void *_capture_worker_thread(void *v_ctx_ptr) { - struct worker_context_t *ctx = (struct worker_context_t *)v_ctx_ptr; +static void *_capture_worker_thread(void *v_ctx) { + struct worker_context_t *ctx = (struct worker_context_t *)v_ctx; LOG_DEBUG("Hello! I am a worker #%d ^_^", ctx->index); diff --git a/src/capture.h b/src/capture.h index 4f41884..de33b12 100644 --- a/src/capture.h +++ b/src/capture.h @@ -38,6 +38,8 @@ struct worker_t { pthread_mutex_t has_job_mutex; bool has_job; pthread_cond_t has_job_cond; + + struct worker_t *order_next; }; struct workers_pool_t { @@ -49,5 +51,14 @@ struct workers_pool_t { pthread_cond_t has_free_workers_cond; }; +struct captured_picture_t { + struct picture_t picture; + unsigned width; + unsigned height; + pthread_mutex_t mutex; +}; -void capture_loop(struct device_t *dev, sig_atomic_t *volatile global_stop); + +void captured_picture_init(struct captured_picture_t *captured); +void captured_picture_destroy(struct captured_picture_t *captured); +void capture_loop(struct device_t *dev, struct captured_picture_t *captured, sig_atomic_t *volatile global_stop); diff --git a/src/device.c b/src/device.c index cc34732..bde80e9 100644 --- a/src/device.c +++ b/src/device.c @@ -50,8 +50,6 @@ static const char *_standard_to_string(const v4l2_std_id standard); void device_init(struct device_t *dev, struct device_runtime_t *run) { - LOG_DEBUG("Initializing a new device struct ..."); - memset(dev, 0, sizeof(struct device_t)); memset(run, 0, sizeof(struct device_runtime_t)); @@ -67,7 +65,6 @@ void device_init(struct device_t *dev, struct device_runtime_t *run) { dev->run = run; dev->run->fd = -1; - LOG_DEBUG("We have a clear device!"); } int device_parse_format(const char *const str) { @@ -125,6 +122,7 @@ void device_close(struct device_t *dev) { LOG_DEBUG("Releasing picture buffers ..."); for (unsigned index = 0; index < dev->run->n_buffers && dev->run->pictures[index].data; ++index) { free(dev->run->pictures[index].data); + dev->run->pictures[index].data = NULL; } free(dev->run->pictures); dev->run->pictures = NULL; @@ -377,14 +375,13 @@ static int _device_open_queue_buffers(struct device_t *dev) { } static void _device_open_alloc_picbufs(struct device_t *dev) { - unsigned max_picture_size = dev->run->width * dev->run->height << 1; - LOG_DEBUG("Allocating picture buffers ..."); A_CALLOC(dev->run->pictures, dev->run->n_buffers, sizeof(*dev->run->pictures)); + dev->run->max_picture_size = (dev->run->width * dev->run->height) << 1; for (unsigned index = 0; index < dev->run->n_buffers; ++index) { LOG_DEBUG("Allocating picture buffer %d ...", index); - A_MALLOC(dev->run->pictures[index].data, max_picture_size); + A_CALLOC(dev->run->pictures[index].data, dev->run->max_picture_size, sizeof(*dev->run->pictures[index].data)); } } diff --git a/src/device.h b/src/device.h index 52c6c50..b5fdc1f 100644 --- a/src/device.h +++ b/src/device.h @@ -27,6 +27,7 @@ struct device_runtime_t { unsigned n_buffers; struct hw_buffer_t *hw_buffers; struct picture_t *pictures; + unsigned max_picture_size; bool capturing; }; diff --git a/src/main.c b/src/main.c index 68003fe..d774558 100644 --- a/src/main.c +++ b/src/main.c @@ -96,12 +96,13 @@ static void _parse_options(int argc, char *argv[], struct device_t *dev) { } struct threads_context { - struct device_t *dev; - sig_atomic_t *volatile global_stop; + struct device_t *dev; + struct captured_picture_t *captured; + sig_atomic_t *volatile global_stop; }; -static void *_capture_loop_thread(void *v_ctx_ptr) { - struct threads_context *ctx = (struct threads_context *)v_ctx_ptr; +static void *_capture_loop_thread(void *v_ctx) { + struct threads_context *ctx = (struct threads_context *)v_ctx; sigset_t mask; assert(!sigemptyset(&mask)); @@ -109,31 +110,23 @@ static void *_capture_loop_thread(void *v_ctx_ptr) { assert(!sigaddset(&mask, SIGTERM)); assert(!pthread_sigmask(SIG_BLOCK, &mask, NULL)); - capture_loop(ctx->dev, (sig_atomic_t *volatile)ctx->global_stop); + capture_loop(ctx->dev, ctx->captured, (sig_atomic_t *volatile)ctx->global_stop); return NULL; } static volatile sig_atomic_t _global_stop = 0; -static void _interrupt_handler(int signum) { +static void _signal_handler(int signum) { LOG_INFO("===== Stopping by %s =====", strsignal(signum)); _global_stop = 1; } -int main(int argc, char *argv[]) { - struct device_t dev; - struct device_runtime_t run; - - pthread_t capture_loop_tid; - struct threads_context ctx = {&dev, (sig_atomic_t *volatile)&_global_stop}; +static void _init_signal_handlers() { struct sigaction sig_act; - device_init(&dev, &run); - _parse_options(argc, argv, &dev); - MEMSET_ZERO(sig_act); assert(!sigemptyset(&sig_act.sa_mask)); - sig_act.sa_handler = _interrupt_handler; + sig_act.sa_handler = _signal_handler; assert(!sigaddset(&sig_act.sa_mask, SIGINT)); assert(!sigaddset(&sig_act.sa_mask, SIGTERM)); @@ -142,9 +135,22 @@ int main(int argc, char *argv[]) { LOG_INFO("Installing SIGTERM handler ..."); assert(!sigaction(SIGTERM, &sig_act, NULL)); +} +int main(int argc, char *argv[]) { + struct device_t dev; + struct device_runtime_t run; + struct captured_picture_t captured; + struct threads_context ctx = {&dev, &captured, (sig_atomic_t *volatile)&_global_stop}; + pthread_t capture_loop_tid; + + device_init(&dev, &run); + _parse_options(argc, argv, &dev); + _init_signal_handlers(); + + captured_picture_init(&captured); A_PTHREAD_CREATE(&capture_loop_tid, _capture_loop_thread, (void *)&ctx); A_PTHREAD_JOIN(capture_loop_tid); - + captured_picture_destroy(&captured); return 0; } diff --git a/src/tools.h b/src/tools.h index 48f82fc..8c8b404 100644 --- a/src/tools.h +++ b/src/tools.h @@ -67,7 +67,6 @@ unsigned log_level; #define A_CALLOC(_dest, _nmemb, _size) assert((_dest = calloc(_nmemb, _size))) -#define A_MALLOC(_dest, _size) assert((_dest = malloc(_size))); #define MEMSET_ZERO(_x_obj) memset(&(_x_obj), 0, sizeof(_x_obj))