various fixes

This commit is contained in:
Devaev Maxim 2018-09-24 22:20:43 +03:00
parent c2b82312ec
commit 0717d2ee6a
11 changed files with 190 additions and 46 deletions

View File

@ -28,8 +28,11 @@
#include <linux/videodev2.h>
#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 {

View File

@ -19,6 +19,9 @@
*****************************************************************************/
#include <strings.h>
#include <assert.h>
#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
}

View File

@ -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);

View File

@ -21,9 +21,6 @@
#pragma once
#include <stdlib.h>
#include <stddef.h>
#include "../device.h"

View File

@ -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 <mdevaev@gmail.com>\n\n");
printf("Capturing options:\n");
printf("------------------\n");
printf(" -d|--device </dev/path> -- Path to V4L2 device. Default: %s\n\n", dev->path);
printf(" -x|--width <N> -- Initial image width. Default: %d\n\n", dev->width);
printf(" -y|--height <N> -- Initial image height. Default: %d\n\n", dev->height);
printf(" -f|--format <YUYV|UYVY|RGB565> -- Image format. Default: YUYV.\n\n");
printf(" -a|--tv-standard <PAL|NTSC|SECAM> -- Force TV standard. Default: disabled.\n\n");
printf(" -e|--every-frame <N> -- Drop all input frames except specified. Default: disabled.\n\n");
printf(" -z|--min-frame-size <N> -- 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 <N> -- 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 <N> -- The number of compressing threads. Default: %d (== --buffers).\n\n", dev->n_workers);
printf(" -q|--jpeg-quality <N> -- Set quality of JPEG encoding from 1 to 100 (best). Default: %d\n\n", dev->jpeg_quality);
printf(" --device-timeout <seconds> -- Timeout for device querying. Default: %d\n\n", dev->timeout);
printf(" --device-error-timeout <seconds> -- Delay before trying to connect to the device again\n");
printf(" after a timeout. Default: %d\n\n", dev->error_timeout);
printf(" -d|--device </dev/path> -- Path to V4L2 device. Default: %s\n\n", dev->path);
printf(" -x|--width <N> -- Initial image width. Default: %d\n\n", dev->width);
printf(" -y|--height <N> -- Initial image height. Default: %d\n\n", dev->height);
printf(" -f|--format <fmt> -- Image format.\n");
printf(" Available: %s; default: YUYV.\n\n", FORMATS_STR);
printf(" -a|--tv-standard <std> -- Force TV standard.\n");
printf(" Available: %s; default: disabled.\n\n", STANDARDS_STR);
printf(" -e|--every-frame <N> -- Drop all input frames except specified. Default: disabled.\n\n");
printf(" -z|--min-frame-size <N> -- 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 <N> -- 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 <N> -- The number of compressing threads. Default: %d (== --buffers).\n\n", dev->n_workers);
printf(" -q|--jpeg-quality <N> -- Set quality of JPEG encoding from 1 to 100 (best). Default: %d\n\n", dev->jpeg_quality);
printf(" --encoder <type> -- Use specified encoder. It may affects to workers number.\n");
printf(" -- Available: %s; default: CPU.\n\n", ENCODER_TYPES_STR);
printf(" --device-timeout <seconds> -- Timeout for device querying. Default: %d\n\n", dev->timeout);
printf(" --device-error-timeout <seconds> -- 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 <address> -- 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;

View File

@ -1,3 +1,24 @@
/*****************************************************************************
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# 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 <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#include <unistd.h>
#include <IL/OMX_Core.h>

View File

@ -1,3 +1,24 @@
/*****************************************************************************
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# 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 <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#pragma once
#include <string.h>

View File

@ -1,3 +1,24 @@
/*****************************************************************************
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# 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 <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#include <string.h>
#include <unistd.h>
#include <assert.h>

View File

@ -1,3 +1,24 @@
/*****************************************************************************
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# 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 <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#pragma once
#include <stdbool.h>

View File

@ -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

View File

@ -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;