From 0717d2ee6afe45b93a475ada032ad89616257d3d Mon Sep 17 00:00:00 2001 From: Devaev Maxim Date: Mon, 24 Sep 2018 22:20:43 +0300 Subject: [PATCH] various fixes --- src/device.h | 5 +++- src/encoder.c | 66 ++++++++++++++++++++++++++++++++++---------- src/encoder.h | 17 +++++++++++- src/jpeg/encoder.h | 3 -- src/main.c | 54 ++++++++++++++++++++---------------- src/omx/component.c | 21 ++++++++++++++ src/omx/component.h | 21 ++++++++++++++ src/omx/encoder.c | 21 ++++++++++++++ src/omx/encoder.h | 21 ++++++++++++++ src/omx/formatters.c | 3 +- src/stream.c | 4 ++- 11 files changed, 190 insertions(+), 46 deletions(-) diff --git a/src/device.h b/src/device.h index a43767a..5f4f037 100644 --- a/src/device.h +++ b/src/device.h @@ -28,8 +28,11 @@ #include -#define FORMAT_UNKNOWN -1 #define STANDARD_UNKNOWN V4L2_STD_UNKNOWN +#define STANDARDS_STR "UNKNOWN, PAL, NTSC, SECAM" + +#define FORMAT_UNKNOWN -1 +#define FORMATS_STR "YUYV, UYVY, RGB565" struct hw_buffer_t { diff --git a/src/encoder.c b/src/encoder.c index df8a765..ae49e5b 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -19,6 +19,9 @@ *****************************************************************************/ +#include +#include + #include "tools.h" #include "device.h" #include "encoder.h" @@ -29,12 +32,29 @@ # include "omx/encoder.h" #endif + +static const struct { + const char *name; + const enum encoder_type_t type; +} ENCODER_TYPES[] = { + {"CPU", ENCODER_TYPE_CPU}, +# ifdef OMX_ENCODER + {"OMX", ENCODER_TYPE_OMX}, +# endif +}; + + struct encoder_t *encoder_init(enum encoder_type_t type) { struct encoder_t *encoder; + assert(type != ENCODER_TYPE_UNKNOWN); A_CALLOC(encoder, 1); encoder->type = type; + if (encoder->type != ENCODER_TYPE_CPU) { + LOG_DEBUG("Initializing encoder ..."); + } + # ifdef OMX_ENCODER if (type == ENCODER_TYPE_OMX) { if ((encoder->omx = omx_encoder_init()) == NULL) { @@ -63,6 +83,15 @@ void encoder_destroy(struct encoder_t *encoder) { free(encoder); } +enum encoder_type_t encoder_parse_type(const char *const str) { + for (unsigned index = 0; index < sizeof(ENCODER_TYPES) / sizeof(ENCODER_TYPES[0]); ++index) { + if (!strcasecmp(str, ENCODER_TYPES[index].name)) { + return ENCODER_TYPES[index].type; + } + } + return ENCODER_TYPE_UNKNOWN; +} + #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic push void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) { @@ -72,10 +101,10 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) { if (omx_encoder_prepare(encoder->omx, dev) < 0) { goto use_fallback; } - } - if (dev->run->n_workers > 1) { - LOG_INFO("OMX encoder can only work with one worker thread; forcing n_workers to 1"); - dev->run->n_workers = 1; + if (dev->run->n_workers > 1) { + LOG_INFO("OMX encoder can only work with one worker thread; forcing n_workers to 1"); + dev->run->n_workers = 1; + } } # endif @@ -86,20 +115,29 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) { use_fallback: LOG_ERROR("Can't prepare selected encoder, falling back to CPU"); encoder->type = ENCODER_TYPE_CPU; + dev->run->n_workers = dev->n_workers; # pragma GCC diagnostic pop } -void encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int index) { -# ifdef OMX_ENCODER - if (encoder->type == ENCODER_TYPE_OMX) { - if (omx_encoder_compress_buffer(encoder->omx, dev, index) < 0) { - LOG_INFO("OMX compressor error, falling back to CPU method"); - encoder->type = ENCODER_TYPE_CPU; - } - } -# endif - +int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int index) { if (encoder->type == ENCODER_TYPE_CPU) { jpeg_encoder_compress_buffer(dev, index); } +# ifdef OMX_ENCODER + else if (encoder->type == ENCODER_TYPE_OMX) { + if (omx_encoder_compress_buffer(encoder->omx, dev, index) < 0) { + goto error; + } + } +# endif + return 0; + +# pragma GCC diagnostic ignored "-Wunused-label" +# pragma GCC diagnostic push + error: + LOG_INFO("HW compressing error, falling back to CPU"); + encoder->type = ENCODER_TYPE_CPU; + dev->run->n_workers = dev->n_workers; + return -1; +# pragma GCC diagnostic pop } diff --git a/src/encoder.h b/src/encoder.h index c8f2ec9..f45f0af 100644 --- a/src/encoder.h +++ b/src/encoder.h @@ -29,7 +29,20 @@ #endif +#define ENCODER_TYPES_STR "CPU" +#define PUSH _Pragma("push_macro(\"ENCODER_TYPES_STR\")") +#define POP _Pragma("pop_macro(\"ENCODER_TYPES_STR\")") +#ifdef OMX_ENCODER + PUSH +# undef ENCODER_TYPES_STR +# define ENCODER_TYPES_STR POP ENCODER_TYPES_STR ", OMX" +#endif +#undef PUSH +#undef POP + + enum encoder_type_t { + ENCODER_TYPE_UNKNOWN, // Only for encoder_parse_type() and main() ENCODER_TYPE_CPU, #ifdef OMX_ENCODER @@ -49,5 +62,7 @@ struct encoder_t { struct encoder_t *encoder_init(enum encoder_type_t type); void encoder_destroy(struct encoder_t *encoder); +enum encoder_type_t encoder_parse_type(const char *const str); + void encoder_prepare(struct encoder_t *encoder, struct device_t *dev); -void encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int index); +int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int index); diff --git a/src/jpeg/encoder.h b/src/jpeg/encoder.h index c56ab84..25701d6 100644 --- a/src/jpeg/encoder.h +++ b/src/jpeg/encoder.h @@ -21,9 +21,6 @@ #pragma once -#include -#include - #include "../device.h" diff --git a/src/main.c b/src/main.c index dbfb840..6e6fdcb 100644 --- a/src/main.c +++ b/src/main.c @@ -40,7 +40,7 @@ #include "http.h" -static const char _short_opts[] = "d:x:y:f:a:e:z:tn:w:q:s:p:h"; +static const char _short_opts[] = "d:x:y:f:a:e:z:tn:w:q:c:s:p:h"; static const struct option _long_opts[] = { {"device", required_argument, NULL, 'd'}, {"width", required_argument, NULL, 'x'}, @@ -50,9 +50,10 @@ static const struct option _long_opts[] = { {"every-frame", required_argument, NULL, 'e'}, {"min-frame-size", required_argument, NULL, 'z'}, {"dv-timings", no_argument, NULL, 't'}, - {"buffers", required_argument, NULL, 'n'}, + {"buffers", required_argument, NULL, 'b'}, {"workers", required_argument, NULL, 'w'}, {"jpeg-quality", required_argument, NULL, 'q'}, + {"encoder", required_argument, NULL, 'c'}, {"device-timeout", required_argument, NULL, 1000}, {"device-error-timeout", required_argument, NULL, 1001}, @@ -73,24 +74,28 @@ static void _help(struct device_t *dev, struct http_server_t *server) { printf("Copyright (C) 2018 Maxim Devaev \n\n"); printf("Capturing options:\n"); printf("------------------\n"); - printf(" -d|--device -- Path to V4L2 device. Default: %s\n\n", dev->path); - printf(" -x|--width -- Initial image width. Default: %d\n\n", dev->width); - printf(" -y|--height -- Initial image height. Default: %d\n\n", dev->height); - printf(" -f|--format -- Image format. Default: YUYV.\n\n"); - printf(" -a|--tv-standard -- Force TV standard. Default: disabled.\n\n"); - printf(" -e|--every-frame -- Drop all input frames except specified. Default: disabled.\n\n"); - printf(" -z|--min-frame-size -- Drop frames smaller then this limit.\n"); - printf(" Useful if the device produces small-sized garbage frames.\n\n"); - printf(" -t|--dv-timings -- Enable DV timings queriyng and events processing.\n"); - printf(" Supports automatic resolution changing. Default: disabled.\n\n"); - printf(" -n|--buffers -- The number of buffers to receive data from the device.\n"); - printf(" Each buffer may processed using an intermediate thread.\n"); - printf(" Default: %d (number of CPU cores + 1)\n\n", dev->n_buffers); - printf(" -w|--workers -- The number of compressing threads. Default: %d (== --buffers).\n\n", dev->n_workers); - printf(" -q|--jpeg-quality -- Set quality of JPEG encoding from 1 to 100 (best). Default: %d\n\n", dev->jpeg_quality); - printf(" --device-timeout -- Timeout for device querying. Default: %d\n\n", dev->timeout); - printf(" --device-error-timeout -- Delay before trying to connect to the device again\n"); - printf(" after a timeout. Default: %d\n\n", dev->error_timeout); + printf(" -d|--device -- Path to V4L2 device. Default: %s\n\n", dev->path); + printf(" -x|--width -- Initial image width. Default: %d\n\n", dev->width); + printf(" -y|--height -- Initial image height. Default: %d\n\n", dev->height); + printf(" -f|--format -- Image format.\n"); + printf(" Available: %s; default: YUYV.\n\n", FORMATS_STR); + printf(" -a|--tv-standard -- Force TV standard.\n"); + printf(" Available: %s; default: disabled.\n\n", STANDARDS_STR); + printf(" -e|--every-frame -- Drop all input frames except specified. Default: disabled.\n\n"); + printf(" -z|--min-frame-size -- Drop frames smaller then this limit.\n"); + printf(" Useful if the device produces small-sized garbage frames.\n\n"); + printf(" -t|--dv-timings -- Enable DV timings queriyng and events processing.\n"); + printf(" Supports automatic resolution changing. Default: disabled.\n\n"); + printf(" -b|--buffers -- The number of buffers to receive data from the device.\n"); + printf(" Each buffer may processed using an intermediate thread.\n"); + printf(" Default: %d (number of CPU cores + 1)\n\n", dev->n_buffers); + printf(" -w|--workers -- The number of compressing threads. Default: %d (== --buffers).\n\n", dev->n_workers); + printf(" -q|--jpeg-quality -- Set quality of JPEG encoding from 1 to 100 (best). Default: %d\n\n", dev->jpeg_quality); + printf(" --encoder -- Use specified encoder. It may affects to workers number.\n"); + printf(" -- Available: %s; default: CPU.\n\n", ENCODER_TYPES_STR); + printf(" --device-timeout -- Timeout for device querying. Default: %d\n\n", dev->timeout); + printf(" --device-error-timeout -- Delay before trying to connect to the device again\n"); + printf(" after a timeout. Default: %d\n\n", dev->error_timeout); printf("HTTP server options:\n"); printf("--------------------\n"); printf(" --host
-- Listen on Hostname or IP. Default: %s\n\n", server->host); @@ -106,7 +111,7 @@ static void _help(struct device_t *dev, struct http_server_t *server) { printf(" -h|--help -- Print this messages and exit\n\n"); } -static int _parse_options(int argc, char *argv[], struct device_t *dev, struct http_server_t *server) { +static int _parse_options(int argc, char *argv[], struct device_t *dev, struct encoder_t *encoder, struct http_server_t *server) { # define OPT_ARG(_dest) \ { _dest = optarg; break; } @@ -114,7 +119,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct h { _dest = true; break; } # define OPT_UNSIGNED(_dest, _name, _min, _max) \ - { int _tmp = strtol(optarg, NULL, 0); \ + { errno = 0; int _tmp = strtol(optarg, NULL, 0); \ if (errno || _tmp < _min || _tmp > _max) \ { printf("Invalid value for '%s=%u'; minimal=%u; maximum=%u\n", _name, _tmp, _min, _max); return -1; } \ _dest = _tmp; break; } @@ -141,9 +146,10 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct h case 'e': OPT_UNSIGNED(dev->every_frame, "--every-frame", 1, 30); case 'z': OPT_UNSIGNED(dev->min_frame_size, "--min-frame-size", 0, 8192); case 't': OPT_TRUE(dev->dv_timings); - case 'n': OPT_UNSIGNED(dev->n_buffers, "--buffers", 1, 32); + case 'b': OPT_UNSIGNED(dev->n_buffers, "--buffers", 1, 32); case 'w': OPT_UNSIGNED(dev->n_workers, "--workers", 1, 32); case 'q': OPT_UNSIGNED(dev->jpeg_quality, "--jpeg-quality", 1, 100); + case 'c': OPT_PARSE(encoder->type, encoder_parse_type, ENCODER_TYPE_UNKNOWN, "encoder type") case 1000: OPT_UNSIGNED(dev->timeout, "--timeout", 1, 60); case 1001: OPT_UNSIGNED(dev->error_timeout, "--error-timeout", 1, 60); @@ -231,7 +237,7 @@ int main(int argc, char *argv[]) { stream = stream_init(dev, encoder); server = http_server_init(stream); - if ((exit_code = _parse_options(argc, argv, dev, server)) == 0) { + if ((exit_code = _parse_options(argc, argv, dev, encoder, server)) == 0) { _install_signal_handlers(); pthread_t stream_loop_tid; diff --git a/src/omx/component.c b/src/omx/component.c index 4ad8f84..ea7db98 100644 --- a/src/omx/component.c +++ b/src/omx/component.c @@ -1,3 +1,24 @@ +/***************************************************************************** +# uStreamer - Lightweight and fast MJPG-HTTP streamer. # +# # +# Copyright (C) 2018 Maxim Devaev # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +*****************************************************************************/ + + #include #include diff --git a/src/omx/component.h b/src/omx/component.h index d628878..b8b5ec3 100644 --- a/src/omx/component.h +++ b/src/omx/component.h @@ -1,3 +1,24 @@ +/***************************************************************************** +# uStreamer - Lightweight and fast MJPG-HTTP streamer. # +# # +# Copyright (C) 2018 Maxim Devaev # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +*****************************************************************************/ + + #pragma once #include diff --git a/src/omx/encoder.c b/src/omx/encoder.c index a7fe1ad..939fa8d 100644 --- a/src/omx/encoder.c +++ b/src/omx/encoder.c @@ -1,3 +1,24 @@ +/***************************************************************************** +# uStreamer - Lightweight and fast MJPG-HTTP streamer. # +# # +# Copyright (C) 2018 Maxim Devaev # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +*****************************************************************************/ + + #include #include #include diff --git a/src/omx/encoder.h b/src/omx/encoder.h index 66742c3..f38bb01 100644 --- a/src/omx/encoder.h +++ b/src/omx/encoder.h @@ -1,3 +1,24 @@ +/***************************************************************************** +# uStreamer - Lightweight and fast MJPG-HTTP streamer. # +# # +# Copyright (C) 2018 Maxim Devaev # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +*****************************************************************************/ + + #pragma once #include diff --git a/src/omx/formatters.c b/src/omx/formatters.c index ff0de8e..d5412b5 100644 --- a/src/omx/formatters.c +++ b/src/omx/formatters.c @@ -38,7 +38,6 @@ assert(0 && _buf); \ } - const char *omx_error_to_string(const OMX_ERRORTYPE error) { switch (error) { CASE_TO_STRING(OMX_ErrorNone); @@ -79,5 +78,5 @@ const char *omx_state_to_string(const OMX_STATETYPE state) { } } -#undef CASE_ASSERT #undef CASE_TO_STRING +#undef CASE_ASSERT diff --git a/src/stream.c b/src/stream.c index 2fb451a..f4a11a7 100644 --- a/src/stream.c +++ b/src/stream.c @@ -413,7 +413,9 @@ static void *_stream_worker_thread(void *v_ctx) { LOG_DEBUG("Worker %u compressing JPEG from buffer %d ...", ctx->number, ctx->buf_index); - encoder_compress_buffer(ctx->encoder, ctx->dev, ctx->buf_index); + if (encoder_compress_buffer(ctx->encoder, ctx->dev, ctx->buf_index) < 0) { + *ctx->job_failed = true; + } if (_stream_release_buffer(ctx->dev, &ctx->buf_info) == 0) { *ctx->job_start_time = start_time;