diff --git a/src/device.c b/src/device.c index 9b91928..bfae0d0 100644 --- a/src/device.c +++ b/src/device.c @@ -133,6 +133,28 @@ v4l2_std_id device_parse_standard(const char *str) { return STANDARD_UNKNOWN; } +void device_copy_picture(const struct picture_t *src, struct picture_t *dest) { +# define COPY(_field) dest->_field = src->_field + + if (dest->allocated < src->allocated) { + A_REALLOC(dest->data, src->allocated); + COPY(allocated); + } + + memcpy(dest->data, src->data, src->used); + + COPY(used); + + COPY(width); + COPY(height); + + COPY(grab_time); + COPY(encode_begin_time); + COPY(encode_end_time); + +# undef COPY +} + int device_open(struct device_t *dev) { if ((dev->run->fd = open(dev->path, O_RDWR|O_NONBLOCK)) < 0) { LOG_PERROR("Can't open device"); diff --git a/src/device.h b/src/device.h index 7151455..17289b8 100644 --- a/src/device.h +++ b/src/device.h @@ -54,6 +54,8 @@ struct picture_t { unsigned char *data; size_t used; size_t allocated; + unsigned width; + unsigned height; long double grab_time; long double encode_begin_time; long double encode_end_time; @@ -118,6 +120,8 @@ void device_destroy(struct device_t *dev); int device_parse_format(const char *str); v4l2_std_id device_parse_standard(const char *str); +void device_copy_picture(const struct picture_t *src, struct picture_t *dest); + int device_open(struct device_t *dev); void device_close(struct device_t *dev); diff --git a/src/encoder.c b/src/encoder.c index 9847fb9..9e3af8a 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -217,6 +217,9 @@ int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, uns dev->run->pictures[buf_index].encode_end_time = get_now_monotonic(); + dev->run->pictures[buf_index].width = dev->run->width; + dev->run->pictures[buf_index].height = dev->run->height; + return 0; # pragma GCC diagnostic ignored "-Wunused-label" diff --git a/src/http/blank.c b/src/http/blank.c index 91c04fc..6db3f75 100644 --- a/src/http/blank.c +++ b/src/http/blank.c @@ -31,6 +31,7 @@ #include "../tools.h" #include "../logging.h" +#include "../device.h" #include "data/blank_jpeg.h" @@ -41,14 +42,14 @@ struct _jpeg_error_manager_t { }; -static struct blank_t *_blank_init_internal(void); -static struct blank_t *_blank_init_external(const char *path); +static struct picture_t *_blank_init_internal(void); +static struct picture_t *_blank_init_external(const char *path); static int _jpeg_read_geometry(FILE *fp, unsigned *width, unsigned *height); static void _jpeg_error_handler(j_common_ptr jpeg); -struct blank_t *blank_init(const char *path) { - struct blank_t *blank = NULL; +struct picture_t *blank_init(const char *path) { + struct picture_t *blank = NULL; if (path) { blank = _blank_init_external(path); @@ -63,21 +64,21 @@ struct blank_t *blank_init(const char *path) { return blank; } -void blank_destroy(struct blank_t *blank) { - free(blank->picture.data); +void blank_destroy(struct picture_t *blank) { + free(blank->data); free(blank); } -static struct blank_t *_blank_init_internal(void) { - struct blank_t *blank; +static struct picture_t *_blank_init_internal(void) { + struct picture_t *blank; A_CALLOC(blank, 1); - A_CALLOC(blank->picture.data, ARRAY_LEN(BLANK_JPEG_DATA)); - memcpy(blank->picture.data, BLANK_JPEG_DATA, ARRAY_LEN(BLANK_JPEG_DATA)); + A_CALLOC(blank->data, ARRAY_LEN(BLANK_JPEG_DATA)); + memcpy(blank->data, BLANK_JPEG_DATA, ARRAY_LEN(BLANK_JPEG_DATA)); - blank->picture.used = ARRAY_LEN(BLANK_JPEG_DATA); - blank->picture.allocated = ARRAY_LEN(BLANK_JPEG_DATA); + blank->used = ARRAY_LEN(BLANK_JPEG_DATA); + blank->allocated = ARRAY_LEN(BLANK_JPEG_DATA); blank->width = BLANK_JPEG_WIDTH; blank->height = BLANK_JPEG_HEIGHT; @@ -85,9 +86,9 @@ static struct blank_t *_blank_init_internal(void) { return blank; } -static struct blank_t *_blank_init_external(const char *path) { +static struct picture_t *_blank_init_external(const char *path) { FILE *fp = NULL; - struct blank_t *blank; + struct picture_t *blank; A_CALLOC(blank, 1); @@ -107,13 +108,13 @@ static struct blank_t *_blank_init_external(const char *path) { # define CHUNK_SIZE (100 * 1024) while (true) { - if (blank->picture.used + CHUNK_SIZE >= blank->picture.allocated) { - blank->picture.allocated = blank->picture.used + CHUNK_SIZE * 2; - A_REALLOC(blank->picture.data, blank->picture.allocated); + if (blank->used + CHUNK_SIZE >= blank->allocated) { + blank->allocated = blank->used + CHUNK_SIZE * 2; + A_REALLOC(blank->data, blank->allocated); } - size_t readed = fread(blank->picture.data + blank->picture.used, 1, CHUNK_SIZE, fp); - blank->picture.used += readed; + size_t readed = fread(blank->data + blank->used, 1, CHUNK_SIZE, fp); + blank->used += readed; if (readed < CHUNK_SIZE) { if (feof(fp)) { @@ -127,7 +128,7 @@ static struct blank_t *_blank_init_external(const char *path) { # undef CHUNK_SIZE error: - free(blank->picture.data); + free(blank->data); free(blank); blank = NULL; diff --git a/src/http/blank.h b/src/http/blank.h index 5fa495c..71fd4c6 100644 --- a/src/http/blank.h +++ b/src/http/blank.h @@ -27,12 +27,5 @@ #include "../device.h" -struct blank_t { - struct picture_t picture; - unsigned width; - unsigned height; -}; - - -struct blank_t *blank_init(const char *path); -void blank_destroy(struct blank_t *blank); +struct picture_t *blank_init(const char *path); +void blank_destroy(struct picture_t *blank); diff --git a/src/http/server.c b/src/http/server.c index 331726f..cd57b24 100644 --- a/src/http/server.c +++ b/src/http/server.c @@ -436,8 +436,8 @@ static void _http_callback_state(struct evhttp_request *request, void *v_server) " \"stream\": {\"queued_fps\": %u, \"clients\": %u, \"clients_stat\": {", encoder_type_to_string(encoder_run_type), encoder_run_quality, - (server->fake_width ? server->fake_width : server->run->exposed->width), - (server->fake_height ? server->fake_height : server->run->exposed->height), + (server->fake_width ? server->fake_width : server->run->exposed->picture.width), + (server->fake_height ? server->fake_height : server->run->exposed->picture.height), bool_to_string(server->run->exposed->online), server->run->stream->dev->desired_fps, server->run->exposed->captured_fps, @@ -497,8 +497,8 @@ static void _http_callback_snapshot(struct evhttp_request *request, void *v_serv ADD_HEADER("X-UStreamer-Online", bool_to_string(EXPOSED(online))); ADD_UNSIGNED_HEADER("X-UStreamer-Dropped", EXPOSED(dropped)); - ADD_UNSIGNED_HEADER("X-UStreamer-Width", EXPOSED(width)); - ADD_UNSIGNED_HEADER("X-UStreamer-Height", EXPOSED(height)); + ADD_UNSIGNED_HEADER("X-UStreamer-Width", EXPOSED(picture.width)); + ADD_UNSIGNED_HEADER("X-UStreamer-Height", EXPOSED(picture.height)); ADD_TIME_HEADER("X-UStreamer-Grab-Time", EXPOSED(picture.grab_time)); ADD_TIME_HEADER("X-UStreamer-Encode-Begin-Time", EXPOSED(picture.encode_begin_time)); ADD_TIME_HEADER("X-UStreamer-Encode-End-Time", EXPOSED(picture.encode_end_time)); @@ -684,8 +684,8 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c RN, bool_to_string(EXPOSED(online)), EXPOSED(dropped), - EXPOSED(width), - EXPOSED(height), + EXPOSED(picture.width), + EXPOSED(picture.height), client->fps, EXPOSED(picture.grab_time), EXPOSED(picture.encode_begin_time), @@ -823,7 +823,7 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv if (atomic_load(&server->run->stream->updated)) { LOG_DEBUG("Refreshing HTTP exposed ..."); A_MUTEX_LOCK(&server->run->stream->mutex); - if (server->run->stream->picture.used > 0) { // If online + if (server->run->stream->online) { picture_updated = _expose_new_picture_unsafe(server); UNLOCK_STREAM; } else { @@ -846,19 +846,15 @@ static bool _expose_new_picture_unsafe(struct http_server_t *server) { # define STREAM(_next) server->run->stream->_next # define EXPOSED(_next) server->run->exposed->_next - assert(STREAM(picture.used) > 0); EXPOSED(captured_fps) = STREAM(captured_fps); EXPOSED(expose_begin_time) = get_now_monotonic(); -# define MEM_STREAM_TO_EXPOSED \ - EXPOSED(picture.data), STREAM(picture.data), STREAM(picture.used) - if (server->drop_same_frames) { if ( EXPOSED(online) && EXPOSED(dropped) < server->drop_same_frames && EXPOSED(picture.used) == STREAM(picture.used) - && !memcmp(MEM_STREAM_TO_EXPOSED) + && !memcmp(EXPOSED(picture.data), STREAM(picture.data), STREAM(picture.used)) ) { EXPOSED(expose_cmp_time) = get_now_monotonic(); EXPOSED(expose_end_time) = EXPOSED(expose_cmp_time); @@ -873,23 +869,8 @@ static bool _expose_new_picture_unsafe(struct http_server_t *server) { } } - if (EXPOSED(picture.allocated) < STREAM(picture.allocated)) { - A_REALLOC(EXPOSED(picture.data), STREAM(picture.allocated)); - EXPOSED(picture.allocated) = STREAM(picture.allocated); - } + device_copy_picture(&STREAM(picture), &EXPOSED(picture)); - memcpy(MEM_STREAM_TO_EXPOSED); - -# undef MEM_STREAM_TO_EXPOSED - - EXPOSED(picture.used) = STREAM(picture.used); - - EXPOSED(picture.grab_time) = STREAM(picture.grab_time); - EXPOSED(picture.encode_begin_time) = STREAM(picture.encode_begin_time); - EXPOSED(picture.encode_end_time) = STREAM(picture.encode_end_time); - - EXPOSED(width) = STREAM(width); - EXPOSED(height) = STREAM(height); EXPOSED(online) = true; EXPOSED(dropped) = 0; EXPOSED(expose_cmp_time) = EXPOSED(expose_begin_time); @@ -904,28 +885,14 @@ static bool _expose_new_picture_unsafe(struct http_server_t *server) { } static bool _expose_blank_picture(struct http_server_t *server) { -# define BLANK(_next) server->run->blank->_next # define EXPOSED(_next) server->run->exposed->_next EXPOSED(expose_begin_time) = get_now_monotonic(); EXPOSED(expose_cmp_time) = EXPOSED(expose_begin_time); if (EXPOSED(online) || EXPOSED(picture.used) == 0) { - if (EXPOSED(picture.allocated) < BLANK(picture.used)) { - A_REALLOC(EXPOSED(picture.data), BLANK(picture.used)); - EXPOSED(picture.allocated) = BLANK(picture.used); - } + device_copy_picture(server->run->blank, &EXPOSED(picture)); - memcpy(EXPOSED(picture.data), BLANK(picture.data), BLANK(picture.used)); - - EXPOSED(picture.used) = BLANK(picture.used); - - EXPOSED(picture.grab_time) = 0; - EXPOSED(picture.encode_begin_time) = 0; - EXPOSED(picture.encode_end_time) = 0; - - EXPOSED(width) = BLANK(width); - EXPOSED(height) = BLANK(height); EXPOSED(captured_fps) = 0; EXPOSED(online) = false; goto updated; @@ -944,5 +911,4 @@ static bool _expose_blank_picture(struct http_server_t *server) { return true; // Updated # undef EXPOSED -# undef BLANK } diff --git a/src/http/server.h b/src/http/server.h index 1f9713c..0147a56 100644 --- a/src/http/server.h +++ b/src/http/server.h @@ -59,8 +59,6 @@ struct stream_client_t { struct exposed_t { struct picture_t picture; - unsigned width; - unsigned height; unsigned captured_fps; unsigned queued_fps; bool online; @@ -80,7 +78,7 @@ struct http_server_runtime_t { struct exposed_t *exposed; struct stream_client_t *stream_clients; unsigned stream_clients_count; - struct blank_t *blank; + struct picture_t *blank; unsigned drop_same_frames_blank; }; diff --git a/src/stream.c b/src/stream.c index 0886ce7..04261cf 100644 --- a/src/stream.c +++ b/src/stream.c @@ -121,6 +121,9 @@ struct stream_t *stream_init(struct device_t *dev, struct encoder_t *encoder) { void stream_destroy(struct stream_t *stream) { A_MUTEX_DESTROY(&stream->mutex); + if (stream->picture.data) { + free(stream->picture.data); + } free(stream->proc); free(stream); } @@ -139,9 +142,6 @@ void stream_loop(struct stream_t *stream) { long long captured_fps_second = 0; bool persistent_timeout_reported = false; - LOG_DEBUG("Allocation memory for stream picture ..."); - A_CALLOC(stream->picture.data, stream->dev->run->max_raw_image_size); - LOG_INFO("Capturing ..."); while (!atomic_load(&stream->proc->stop)) { @@ -278,10 +278,7 @@ void stream_loop(struct stream_t *stream) { } A_MUTEX_LOCK(&stream->mutex); - stream->picture.used = 0; // On stream offline - free(stream->picture.data); - stream->width = 0; - stream->height = 0; + stream->online = false; atomic_store(&stream->updated, true); A_MUTEX_UNLOCK(&stream->mutex); @@ -342,17 +339,9 @@ static void _stream_expose_picture(struct stream_t *stream, unsigned buf_index, A_MUTEX_LOCK(&stream->mutex); - stream->picture.used = PICTURE(used); - stream->picture.allocated = PICTURE(allocated); + device_copy_picture(&stream->dev->run->pictures[buf_index], &stream->picture); - memcpy(stream->picture.data, PICTURE(data), stream->picture.used); - - stream->picture.grab_time = PICTURE(grab_time); - stream->picture.encode_begin_time = PICTURE(encode_begin_time); - stream->picture.encode_end_time = PICTURE(encode_end_time); - - stream->width = stream->dev->run->width; - stream->height = stream->dev->run->height; + stream->online = true; stream->captured_fps = captured_fps; atomic_store(&stream->updated, true); diff --git a/src/stream.h b/src/stream.h index 097798d..405db1f 100644 --- a/src/stream.h +++ b/src/stream.h @@ -35,8 +35,7 @@ struct process_t { struct stream_t { struct picture_t picture; - unsigned width; - unsigned height; + bool online; unsigned captured_fps; atomic_bool updated; pthread_mutex_t mutex;