Compare commits

...

21 Commits
v0.44 ... v0.51

Author SHA1 Message Date
Devaev Maxim
cc25abcc00 Bump version: 0.50 → 0.51 2019-03-03 05:23:51 +03:00
Devaev Maxim
e80ee2f574 refactoring 2019-03-03 04:25:32 +03:00
Devaev Maxim
56a95c7f17 ARRAY_LEN() 2019-03-02 11:30:10 +03:00
Devaev Maxim
667e3610b2 encoder runtime 2019-03-02 11:29:57 +03:00
Devaev Maxim
142c8c84ac Bump version: 0.49 → 0.50 2019-03-01 11:36:15 +03:00
Devaev Maxim
383075d323 refactoring 2019-03-01 10:44:50 +03:00
Devaev Maxim
e2922aa820 fixed short options 2019-03-01 07:48:03 +03:00
Devaev Maxim
dc9667cf0c report about using pixelformat 2019-03-01 07:07:16 +03:00
Devaev Maxim
bbbfda0b5c Bump version: 0.48 → 0.49 2019-02-22 02:55:13 +03:00
Devaev Maxim
aa3f079ee9 fixed memory leak in http_server_destroy() 2019-02-22 02:54:03 +03:00
Devaev Maxim
59bd4e8dd2 Bump version: 0.47 → 0.48 2019-02-21 08:02:31 +03:00
Devaev Maxim
ce6184b8cd refactoring 2019-02-21 08:02:21 +03:00
Devaev Maxim
9ca511d29d Bump version: 0.46 → 0.47 2019-02-19 04:38:14 +03:00
Devaev Maxim
74de28c64a refactoring 2019-02-19 04:33:35 +03:00
Maxim Devaev
24060e8068 Update README.md 2019-01-28 17:33:57 +03:00
Maxim Devaev
3a03d48855 Update README.ru.md 2019-01-22 03:32:52 +03:00
Maxim Devaev
935a9125d6 Update README.md 2019-01-22 03:32:17 +03:00
Devaev Maxim
d4ea97ef2c Bump version: 0.45 → 0.46 2018-12-18 03:17:44 +03:00
Devaev Maxim
867aa4e52a proxy-revalidate 2018-12-18 03:17:34 +03:00
Devaev Maxim
bc2bb444dc Bump version: 0.44 → 0.45 2018-12-18 01:37:50 +03:00
Devaev Maxim
19796f3b64 X-UStreamer-Dropped 2018-12-18 01:37:39 +03:00
29 changed files with 758 additions and 692 deletions

View File

@@ -1,7 +1,7 @@
[bumpversion] [bumpversion]
commit = True commit = True
tag = True tag = True
current_version = 0.44 current_version = 0.51
parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)? parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)?
serialize = serialize =
{major}.{minor} {major}.{minor}

View File

@@ -3,7 +3,7 @@
pkgname=ustreamer pkgname=ustreamer
pkgver=0.44 pkgver=0.51
pkgrel=1 pkgrel=1
pkgdesc="Lightweight and fast MJPG-HTTP streamer" pkgdesc="Lightweight and fast MJPG-HTTP streamer"
url="https://github.com/pi-kvm/ustreamer" url="https://github.com/pi-kvm/ustreamer"

View File

@@ -15,7 +15,7 @@
| Option to skip frames when streaming<br>static images by HTTP to save traffic | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes <sup>2</sup> | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | | Option to skip frames when streaming<br>static images by HTTP to save traffic | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes <sup>2</sup> | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No |
| Streaming via UNIX domain socket | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | | Streaming via UNIX domain socket | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No |
| Debug logs without recompiling,<br>performance statistics log,<br>access to HTTP broadcast parameters | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | | Debug logs without recompiling,<br>performance statistics log,<br>access to HTTP broadcast parameters | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No |
| Supported input devices | ![#ffaa00](https://placehold.it/15/ffaa00/000000?text=+) YUYV, UYVY,<br>RGB565, ~~MJPG~~ <sup>3</sup> | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) YUYV, UYVY,<br>RGB565, MJPG | | Supported input formats | ![#ffaa00](https://placehold.it/15/ffaa00/000000?text=+) YUYV, UYVY,<br>RGB565, ~~MJPG~~ <sup>3</sup> | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) YUYV, UYVY,<br>RGB565, MJPG |
| Access to webcam controls (focus, servos)<br>and settings such as brightness via HTTP | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | | Access to webcam controls (focus, servos)<br>and settings such as brightness via HTTP | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes |
| Option to serve files<br>with a built-in HTTP server, auth settings | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No <sup>4</sup> | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | | Option to serve files<br>with a built-in HTTP server, auth settings | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No <sup>4</sup> | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes |
@@ -60,7 +60,6 @@ $ ./ustreamer \
--format=uyvy \ # Device input format --format=uyvy \ # Device input format
--encoder=omx \ # Hardware encoding with OpenMAX --encoder=omx \ # Hardware encoding with OpenMAX
--dv-timings \ # Use DV-timings --dv-timings \ # Use DV-timings
--quality=20 \ # OpenMAX has a non-linear quality scale
--drop-same-frames=30 # Save that traffic --drop-same-frames=30 # Save that traffic
``` ```

View File

@@ -60,7 +60,6 @@ $ ./ustreamer \
--format=uyvy \ # Настройка входного формата устройства --format=uyvy \ # Настройка входного формата устройства
--encoder=omx \ # Использование аппаратного кодирования с помощью OpenMAX --encoder=omx \ # Использование аппаратного кодирования с помощью OpenMAX
--dv-timings \ # Включение DV-таймингов --dv-timings \ # Включение DV-таймингов
--quality=20 \ # У OpenMAX нелинейная шкала качества
--drop-same-frames=30 # Экономим трафик --drop-same-frames=30 # Экономим трафик
``` ```

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -21,4 +22,4 @@
#pragma once #pragma once
#define VERSION "0.44" #define VERSION "0.51"

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -64,11 +65,11 @@ static int _device_open_format(struct device_t *dev);
static void _device_open_alloc_picbufs(struct device_t *dev); static void _device_open_alloc_picbufs(struct device_t *dev);
static int _device_open_mmap(struct device_t *dev); static int _device_open_mmap(struct device_t *dev);
static int _device_open_queue_buffers(struct device_t *dev); static int _device_open_queue_buffers(struct device_t *dev);
static int _device_apply_resolution(struct device_t *dev, const unsigned width, const unsigned height); static int _device_apply_resolution(struct device_t *dev, unsigned width, unsigned height);
static const char *_format_to_string_auto(char *buf, const size_t size, const unsigned format); static const char *_format_to_string_auto(char *buf, size_t size, unsigned format);
static const char *_format_to_string_null(const unsigned format); static const char *_format_to_string_null(unsigned format);
static const char *_standard_to_string(const v4l2_std_id standard); static const char *_standard_to_string(v4l2_std_id standard);
struct device_t *device_init() { struct device_t *device_init() {
@@ -97,8 +98,8 @@ void device_destroy(struct device_t *dev) {
free(dev); free(dev);
} }
int device_parse_format(const char *const str) { int device_parse_format(const char *str) {
for (unsigned index = 0; index < sizeof(_FORMATS) / sizeof(_FORMATS[0]); ++index) { for (unsigned index = 0; index < ARRAY_LEN(_FORMATS); ++index) {
if (!strcasecmp(str, _FORMATS[index].name)) { if (!strcasecmp(str, _FORMATS[index].name)) {
return _FORMATS[index].format; return _FORMATS[index].format;
} }
@@ -106,8 +107,8 @@ int device_parse_format(const char *const str) {
return FORMAT_UNKNOWN; return FORMAT_UNKNOWN;
} }
v4l2_std_id device_parse_standard(const char *const str) { v4l2_std_id device_parse_standard(const char *str) {
for (unsigned index = 1; index < sizeof(_STANDARDS) / sizeof(_STANDARDS[0]); ++index) { for (unsigned index = 1; index < ARRAY_LEN(_STANDARDS); ++index) {
if (!strcasecmp(str, _STANDARDS[index].name)) { if (!strcasecmp(str, _STANDARDS[index].name)) {
return _STANDARDS[index].standard; return _STANDARDS[index].standard;
} }
@@ -285,6 +286,7 @@ static int _device_apply_dv_timings(struct device_t *dev) {
static int _device_open_format(struct device_t *dev) { static int _device_open_format(struct device_t *dev) {
struct v4l2_format fmt; struct v4l2_format fmt;
char format_str[8];
MEMSET_ZERO(fmt); MEMSET_ZERO(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -296,8 +298,6 @@ static int _device_open_format(struct device_t *dev) {
// Set format // Set format
LOG_DEBUG("Calling ioctl(VIDIOC_S_FMT) ..."); LOG_DEBUG("Calling ioctl(VIDIOC_S_FMT) ...");
if (xioctl(dev->run->fd, VIDIOC_S_FMT, &fmt) < 0) { if (xioctl(dev->run->fd, VIDIOC_S_FMT, &fmt) < 0) {
char format_str[8];
LOG_PERROR( LOG_PERROR(
"Unable to set format=%s; resolution=%ux%u", "Unable to set format=%s; resolution=%ux%u",
_format_to_string_auto(format_str, 8, dev->format), _format_to_string_auto(format_str, 8, dev->format),
@@ -318,13 +318,12 @@ static int _device_open_format(struct device_t *dev) {
// Check format // Check format
if (fmt.fmt.pix.pixelformat != dev->format) { if (fmt.fmt.pix.pixelformat != dev->format) {
char format_requested_str[8];
char format_obtained_str[8]; char format_obtained_str[8];
char *format_str_nullable; char *format_str_nullable;
LOG_ERROR( LOG_ERROR(
"Could not obtain the requested pixelformat=%s; driver gave us %s", "Could not obtain the requested pixelformat=%s; driver gave us %s",
_format_to_string_auto(format_requested_str, 8, dev->format), _format_to_string_auto(format_str, 8, dev->format),
_format_to_string_auto(format_obtained_str, 8, fmt.fmt.pix.pixelformat) _format_to_string_auto(format_obtained_str, 8, fmt.fmt.pix.pixelformat)
); );
@@ -339,7 +338,9 @@ static int _device_open_format(struct device_t *dev) {
return -1; return -1;
} }
} }
dev->run->format = fmt.fmt.pix.pixelformat; dev->run->format = fmt.fmt.pix.pixelformat;
LOG_INFO("Using pixelformat: %s", _format_to_string_auto(format_str, 8, dev->run->format));
return 0; return 0;
} }
@@ -422,7 +423,7 @@ static void _device_open_alloc_picbufs(struct device_t *dev) {
} }
} }
static int _device_apply_resolution(struct device_t *dev, const unsigned width, const unsigned height) { static int _device_apply_resolution(struct device_t *dev, unsigned width, unsigned height) {
// Тут VIDEO_MIN_* не используются из-за странностей минимального разрешения при отсутствии сигнала // Тут VIDEO_MIN_* не используются из-за странностей минимального разрешения при отсутствии сигнала
// у некоторых устройств, например Auvidea B101 // у некоторых устройств, например Auvidea B101
if ( if (
@@ -438,12 +439,12 @@ static int _device_apply_resolution(struct device_t *dev, const unsigned width,
return 0; return 0;
} }
static const char *_format_to_string_auto(char *buf, const size_t size, const unsigned format) { static const char *_format_to_string_auto(char *buf, size_t size, unsigned format) {
assert(size >= 8); assert(size >= 8);
buf[0] = format & 0x7f; buf[0] = format & 0x7F;
buf[1] = (format >> 8) & 0x7f; buf[1] = (format >> 8) & 0x7F;
buf[2] = (format >> 16) & 0x7f; buf[2] = (format >> 16) & 0x7F;
buf[3] = (format >> 24) & 0x7f; buf[3] = (format >> 24) & 0x7F;
if (format & (1 << 31)) { if (format & (1 << 31)) {
buf[4] = '-'; buf[4] = '-';
buf[5] = 'B'; buf[5] = 'B';
@@ -455,8 +456,8 @@ static const char *_format_to_string_auto(char *buf, const size_t size, const un
return buf; return buf;
} }
static const char *_format_to_string_null(const unsigned format) { static const char *_format_to_string_null(unsigned format) {
for (unsigned index = 0; index < sizeof(_FORMATS) / sizeof(_FORMATS[0]); ++index) { for (unsigned index = 0; index < ARRAY_LEN(_FORMATS); ++index) {
if (format == _FORMATS[index].format) { if (format == _FORMATS[index].format) {
return _FORMATS[index].name; return _FORMATS[index].name;
} }
@@ -465,7 +466,7 @@ static const char *_format_to_string_null(const unsigned format) {
} }
static const char *_standard_to_string(v4l2_std_id standard) { static const char *_standard_to_string(v4l2_std_id standard) {
for (unsigned index = 0; index < sizeof(_STANDARDS) / sizeof(_STANDARDS[0]); ++index) { for (unsigned index = 0; index < ARRAY_LEN(_STANDARDS); ++index) {
if (standard == _STANDARDS[index].standard) { if (standard == _STANDARDS[index].standard) {
return _STANDARDS[index].name; return _STANDARDS[index].name;
} }

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -92,8 +93,8 @@ struct device_t {
struct device_t *device_init(); struct device_t *device_init();
void device_destroy(struct device_t *dev); void device_destroy(struct device_t *dev);
int device_parse_format(const char *const str); int device_parse_format(const char *str);
v4l2_std_id device_parse_standard(const char *const str); v4l2_std_id device_parse_standard(const char *str);
int device_open(struct device_t *dev); int device_open(struct device_t *dev);
void device_close(struct device_t *dev); void device_close(struct device_t *dev);

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -46,11 +47,16 @@ static const struct {
struct encoder_t *encoder_init() { struct encoder_t *encoder_init() {
struct encoder_runtime_t *run;
struct encoder_t *encoder; struct encoder_t *encoder;
A_CALLOC(run, 1);
run->type = ENCODER_TYPE_CPU;
A_CALLOC(encoder, 1); A_CALLOC(encoder, 1);
encoder->type = ENCODER_TYPE_CPU; encoder->type = run->type;
encoder->quality = 80; encoder->quality = 80;
encoder->run = run;
return encoder; return encoder;
} }
@@ -60,15 +66,16 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) {
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
assert(encoder->type != ENCODER_TYPE_UNKNOWN); assert(encoder->type != ENCODER_TYPE_UNKNOWN);
encoder->run->type = encoder->type;
if (encoder->type != ENCODER_TYPE_CPU) { if (encoder->run->type != ENCODER_TYPE_CPU) {
LOG_DEBUG("Initializing encoder ..."); LOG_DEBUG("Initializing encoder ...");
} }
LOG_INFO("Using JPEG quality: %u%%", encoder->quality); LOG_INFO("Using JPEG quality: %u%%", encoder->quality);
# ifdef OMX_ENCODER # ifdef OMX_ENCODER
if (encoder->type == ENCODER_TYPE_OMX) { if (encoder->run->type == ENCODER_TYPE_OMX) {
if (dev->n_workers > OMX_MAX_ENCODERS) { if (dev->n_workers > OMX_MAX_ENCODERS) {
LOG_INFO( LOG_INFO(
"OMX-based encoder can only work with %u worker threads; forced --workers=%u", "OMX-based encoder can only work with %u worker threads; forced --workers=%u",
@@ -76,11 +83,11 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) {
); );
dev->n_workers = OMX_MAX_ENCODERS; dev->n_workers = OMX_MAX_ENCODERS;
} }
encoder->n_omxs = dev->n_workers; encoder->run->n_omxs = dev->n_workers;
A_CALLOC(encoder->omxs, encoder->n_omxs); A_CALLOC(encoder->run->omxs, encoder->run->n_omxs);
for (unsigned index = 0; index < encoder->n_omxs; ++index) { for (unsigned index = 0; index < encoder->run->n_omxs; ++index) {
if ((encoder->omxs[index] = omx_encoder_init()) == NULL) { if ((encoder->run->omxs[index] = omx_encoder_init()) == NULL) {
goto use_fallback; goto use_fallback;
} }
} }
@@ -93,26 +100,27 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) {
# pragma GCC diagnostic push # pragma GCC diagnostic push
use_fallback: use_fallback:
LOG_ERROR("Can't initialize selected encoder, using CPU instead it"); LOG_ERROR("Can't initialize selected encoder, using CPU instead it");
encoder->type = ENCODER_TYPE_CPU; encoder->run->type = ENCODER_TYPE_CPU;
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
} }
void encoder_destroy(struct encoder_t *encoder) { void encoder_destroy(struct encoder_t *encoder) {
# ifdef OMX_ENCODER # ifdef OMX_ENCODER
if (encoder->omxs) { if (encoder->run->omxs) {
for (unsigned index = 0; index < encoder->n_omxs; ++index) { for (unsigned index = 0; index < encoder->run->n_omxs; ++index) {
if (encoder->omxs[index]) { if (encoder->run->omxs[index]) {
omx_encoder_destroy(encoder->omxs[index]); omx_encoder_destroy(encoder->run->omxs[index]);
} }
} }
free(encoder->omxs); free(encoder->run->omxs);
} }
# endif # endif
free(encoder->run);
free(encoder); free(encoder);
} }
enum encoder_type_t encoder_parse_type(const char *const str) { enum encoder_type_t encoder_parse_type(const char *str) {
for (unsigned index = 0; index < sizeof(_ENCODER_TYPES) / sizeof(_ENCODER_TYPES[0]); ++index) { for (unsigned index = 0; index < ARRAY_LEN(_ENCODER_TYPES); ++index) {
if (!strcasecmp(str, _ENCODER_TYPES[index].name)) { if (!strcasecmp(str, _ENCODER_TYPES[index].name)) {
return _ENCODER_TYPES[index].type; return _ENCODER_TYPES[index].type;
} }
@@ -123,13 +131,13 @@ enum encoder_type_t encoder_parse_type(const char *const str) {
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic push #pragma GCC diagnostic push
void encoder_prepare_live(struct encoder_t *encoder, struct device_t *dev) { void encoder_prepare_live(struct encoder_t *encoder, struct device_t *dev) {
assert(encoder->type != ENCODER_TYPE_UNKNOWN); assert(encoder->run->type != ENCODER_TYPE_UNKNOWN);
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
# ifdef OMX_ENCODER # ifdef OMX_ENCODER
if (encoder->type == ENCODER_TYPE_OMX) { if (encoder->run->type == ENCODER_TYPE_OMX) {
for (unsigned index = 0; index < encoder->n_omxs; ++index) { for (unsigned index = 0; index < encoder->run->n_omxs; ++index) {
if (omx_encoder_prepare_live(encoder->omxs[index], dev, encoder->quality) < 0) { if (omx_encoder_prepare_live(encoder->run->omxs[index], dev, encoder->quality) < 0) {
goto use_fallback; goto use_fallback;
} }
} }
@@ -142,24 +150,23 @@ void encoder_prepare_live(struct encoder_t *encoder, struct device_t *dev) {
# pragma GCC diagnostic push # pragma GCC diagnostic push
use_fallback: use_fallback:
LOG_ERROR("Can't prepare selected encoder, falling back to CPU"); LOG_ERROR("Can't prepare selected encoder, falling back to CPU");
encoder->type = ENCODER_TYPE_CPU; encoder->run->type = ENCODER_TYPE_CPU;
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
} }
#pragma GCC diagnostic ignored "-Wunused-label" #pragma GCC diagnostic ignored "-Wunused-label"
#pragma GCC diagnostic push #pragma GCC diagnostic push
int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, unsigned worker_number, unsigned buf_index) {
const unsigned worker_number, const unsigned buf_index) {
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
assert(encoder->type != ENCODER_TYPE_UNKNOWN); assert(encoder->run->type != ENCODER_TYPE_UNKNOWN);
if (encoder->type == ENCODER_TYPE_CPU) { if (encoder->run->type == ENCODER_TYPE_CPU) {
jpeg_encoder_compress_buffer(dev, buf_index, encoder->quality); jpeg_encoder_compress_buffer(dev, buf_index, encoder->quality);
} }
# ifdef OMX_ENCODER # ifdef OMX_ENCODER
else if (encoder->type == ENCODER_TYPE_OMX) { else if (encoder->run->type == ENCODER_TYPE_OMX) {
if (omx_encoder_compress_buffer(encoder->omxs[worker_number], dev, buf_index) < 0) { if (omx_encoder_compress_buffer(encoder->run->omxs[worker_number], dev, buf_index) < 0) {
goto error; goto error;
} }
} }
@@ -171,7 +178,7 @@ int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev,
# pragma GCC diagnostic push # pragma GCC diagnostic push
error: error:
LOG_INFO("HW compressing error, falling back to CPU"); LOG_INFO("HW compressing error, falling back to CPU");
encoder->type = ENCODER_TYPE_CPU; encoder->run->type = ENCODER_TYPE_CPU;
return -1; return -1;
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
} }

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -44,9 +45,8 @@ enum encoder_type_t {
#endif #endif
}; };
struct encoder_t { struct encoder_runtime_t {
enum encoder_type_t type; enum encoder_type_t type;
unsigned quality;
#ifdef OMX_ENCODER #ifdef OMX_ENCODER
unsigned n_omxs; unsigned n_omxs;
struct omx_encoder_t **omxs; struct omx_encoder_t **omxs;
@@ -54,13 +54,20 @@ struct encoder_t {
}; };
struct encoder_t {
enum encoder_type_t type;
unsigned quality;
struct encoder_runtime_t *run;
};
struct encoder_t *encoder_init(); struct encoder_t *encoder_init();
void encoder_destroy(struct encoder_t *encoder); void encoder_destroy(struct encoder_t *encoder);
enum encoder_type_t encoder_parse_type(const char *const str); enum encoder_type_t encoder_parse_type(const char *str);
void encoder_prepare(struct encoder_t *encoder, struct device_t *dev); void encoder_prepare(struct encoder_t *encoder, struct device_t *dev);
void encoder_prepare_live(struct encoder_t *encoder, struct device_t *dev); void encoder_prepare_live(struct encoder_t *encoder, struct device_t *dev);
int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, unsigned worker_number, unsigned buf_index);
const unsigned worker_number, const unsigned buf_index);

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -65,7 +66,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
static void _http_callback_stream_error(struct bufferevent *buf_event, short what, void *v_ctx); static void _http_callback_stream_error(struct bufferevent *buf_event, short what, void *v_ctx);
static void _http_exposed_refresh(int fd, short event, void *v_server); static void _http_exposed_refresh(int fd, short event, void *v_server);
static void _http_queue_send_stream(struct http_server_t *server, const bool stream_updated, const bool picture_updated); static void _http_queue_send_stream(struct http_server_t *server, bool stream_updated, bool picture_updated);
static bool _expose_new_picture(struct http_server_t *server); static bool _expose_new_picture(struct http_server_t *server);
static bool _expose_blank_picture(struct http_server_t *server); static bool _expose_blank_picture(struct http_server_t *server);
@@ -117,6 +118,14 @@ void http_server_destroy(struct http_server_t *server) {
event_base_free(server->run->base); event_base_free(server->run->base);
libevent_global_shutdown(); libevent_global_shutdown();
for (struct stream_client_t *client = server->run->stream_clients; client != NULL;) {
struct stream_client_t *next = client->next;
free(client->key);
free(client);
client = next;
}
free(server->run->exposed->picture.data); free(server->run->exposed->picture.data);
free(server->run->exposed); free(server->run->exposed);
free(server->run); free(server->run);
@@ -252,14 +261,16 @@ static void _http_callback_state(struct evhttp_request *request, void *v_server)
assert((buf = evbuffer_new())); assert((buf = evbuffer_new()));
assert(evbuffer_add_printf(buf, assert(evbuffer_add_printf(buf,
"{\"ok\": true, \"result\":" "{\"ok\": true, \"result\": {"
" {\"source\": {\"resolution\": {\"width\": %u, \"height\": %u}," " \"encoder\": {\"fallback\": %s, \"quality\": %u},"
" \"online\": %s, \"quality\": %u, \"desired_fps\": %u, \"captured_fps\": %u}," " \"source\": {\"resolution\": {\"width\": %u, \"height\": %u},"
" \"online\": %s, \"desired_fps\": %u, \"captured_fps\": %u},"
" \"stream\": {\"queued_fps\": %u, \"clients\": %u, \"clients_stat\": {", " \"stream\": {\"queued_fps\": %u, \"clients\": %u, \"clients_stat\": {",
bool_to_string(server->run->stream->encoder->type != server->run->stream->encoder->run->type),
server->run->stream->encoder->quality,
(server->fake_width ? server->fake_width : server->run->exposed->width), (server->fake_width ? server->fake_width : server->run->exposed->width),
(server->fake_height ? server->fake_height : server->run->exposed->height), (server->fake_height ? server->fake_height : server->run->exposed->height),
bool_to_string(server->run->exposed->online), bool_to_string(server->run->exposed->online),
server->run->stream->encoder->quality,
server->run->stream->dev->desired_fps, server->run->stream->dev->desired_fps,
server->run->exposed->captured_fps, server->run->exposed->captured_fps,
server->run->exposed->queued_fps, server->run->exposed->queued_fps,
@@ -296,7 +307,7 @@ static void _http_callback_snapshot(struct evhttp_request *request, void *v_serv
assert(!evbuffer_add(buf, (const void *)EXPOSED(picture.data), EXPOSED(picture.size))); assert(!evbuffer_add(buf, (const void *)EXPOSED(picture.data), EXPOSED(picture.size)));
ADD_HEADER("Access-Control-Allow-Origin:", "*"); ADD_HEADER("Access-Control-Allow-Origin:", "*");
ADD_HEADER("Cache-Control", "no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0"); ADD_HEADER("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate, pre-check=0, post-check=0, max-age=0");
ADD_HEADER("Pragma", "no-cache"); ADD_HEADER("Pragma", "no-cache");
ADD_HEADER("Expires", "Mon, 3 Jan 2000 12:34:56 GMT"); ADD_HEADER("Expires", "Mon, 3 Jan 2000 12:34:56 GMT");
@@ -309,6 +320,7 @@ static void _http_callback_snapshot(struct evhttp_request *request, void *v_serv
ADD_TIME_HEADER("X-Timestamp", get_now_real()); ADD_TIME_HEADER("X-Timestamp", get_now_real());
ADD_HEADER("X-UStreamer-Online", bool_to_string(EXPOSED(online))); 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-Width", EXPOSED(width));
ADD_UNSIGNED_HEADER("X-UStreamer-Height", EXPOSED(height)); ADD_UNSIGNED_HEADER("X-UStreamer-Height", EXPOSED(height));
ADD_TIME_HEADER("X-UStreamer-Grab-Time", EXPOSED(picture.grab_time)); ADD_TIME_HEADER("X-UStreamer-Grab-Time", EXPOSED(picture.grab_time));
@@ -446,7 +458,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
assert(evbuffer_add_printf(buf, assert(evbuffer_add_printf(buf,
"HTTP/1.0 200 OK" RN "HTTP/1.0 200 OK" RN
"Access-Control-Allow-Origin: *" RN "Access-Control-Allow-Origin: *" RN
"Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0" RN "Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate, pre-check=0, post-check=0, max-age=0" RN
"Pragma: no-cache" RN "Pragma: no-cache" RN
"Expires: Mon, 3 Jan 2000 12:34:56 GMT" RN "Expires: Mon, 3 Jan 2000 12:34:56 GMT" RN
"Set-Cookie: stream_client=%s/%s; path=/; max-age=30" RN "Set-Cookie: stream_client=%s/%s; path=/; max-age=30" RN
@@ -479,6 +491,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
if (client->extra_headers) { if (client->extra_headers) {
assert(evbuffer_add_printf(buf, assert(evbuffer_add_printf(buf,
"X-UStreamer-Online: %s" RN "X-UStreamer-Online: %s" RN
"X-UStreamer-Dropped: %u" RN
"X-UStreamer-Width: %u" RN "X-UStreamer-Width: %u" RN
"X-UStreamer-Height: %u" RN "X-UStreamer-Height: %u" RN
"X-UStreamer-Client-FPS: %u" RN "X-UStreamer-Client-FPS: %u" RN
@@ -491,6 +504,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
"X-UStreamer-Send-Time: %.06Lf" RN "X-UStreamer-Send-Time: %.06Lf" RN
RN, RN,
bool_to_string(EXPOSED(online)), bool_to_string(EXPOSED(online)),
EXPOSED(dropped),
EXPOSED(width), EXPOSED(width),
EXPOSED(height), EXPOSED(height),
client->fps, client->fps,
@@ -559,7 +573,7 @@ static void _http_callback_stream_error(UNUSED struct bufferevent *buf_event, UN
free(client); free(client);
} }
static void _http_queue_send_stream(struct http_server_t *server, const bool stream_updated, const bool picture_updated) { static void _http_queue_send_stream(struct http_server_t *server, bool stream_updated, bool picture_updated) {
struct evhttp_connection *conn; struct evhttp_connection *conn;
struct bufferevent *buf_event; struct bufferevent *buf_event;
long long now; long long now;

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# This source file based on code of MJPG-Streamer. # # This source file based on code of MJPG-Streamer. #
@@ -48,24 +49,27 @@ struct _mjpg_destination_mgr {
static void _jpeg_set_dest_picture(j_compress_ptr jpeg, unsigned char *picture, unsigned long *written); static void _jpeg_set_dest_picture(j_compress_ptr jpeg, unsigned char *picture, unsigned long *written);
static void _jpeg_write_scanlines_yuyv(struct jpeg_compress_struct *jpeg, static void _jpeg_write_scanlines_yuyv(
unsigned char *line_buffer, const unsigned char *data, struct jpeg_compress_struct *jpeg,
const unsigned width, const unsigned height);
static void _jpeg_write_scanlines_uyvy(struct jpeg_compress_struct *jpeg,
unsigned char *line_buffer, const unsigned char *data, unsigned char *line_buffer, const unsigned char *data,
const unsigned width, const unsigned height); unsigned width, unsigned height);
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, static void _jpeg_write_scanlines_uyvy(
struct jpeg_compress_struct *jpeg,
unsigned char *line_buffer, const unsigned char *data, unsigned char *line_buffer, const unsigned char *data,
const unsigned width, const unsigned height); unsigned width, unsigned height);
static void _jpeg_write_scanlines_rgb565(
struct jpeg_compress_struct *jpeg,
unsigned char *line_buffer, const unsigned char *data,
unsigned width, unsigned height);
static void _jpeg_init_destination(j_compress_ptr jpeg); static void _jpeg_init_destination(j_compress_ptr jpeg);
static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg); static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg);
static void _jpeg_term_destination(j_compress_ptr jpeg); static void _jpeg_term_destination(j_compress_ptr jpeg);
void jpeg_encoder_compress_buffer(struct device_t *dev, const unsigned index, const unsigned quality) { void jpeg_encoder_compress_buffer(struct device_t *dev, unsigned index, unsigned quality) {
// This function based on compress_image_to_jpeg() from mjpg-streamer // This function based on compress_image_to_jpeg() from mjpg-streamer
struct jpeg_compress_struct jpeg; struct jpeg_compress_struct jpeg;
@@ -92,6 +96,7 @@ void jpeg_encoder_compress_buffer(struct device_t *dev, const unsigned index, co
# define WRITE_SCANLINES(_func) \ # define WRITE_SCANLINES(_func) \
_func(&jpeg, line_buffer, dev->run->hw_buffers[index].start, dev->run->width, dev->run->height) _func(&jpeg, line_buffer, dev->run->hw_buffers[index].start, dev->run->width, dev->run->height)
switch (dev->run->format) { switch (dev->run->format) {
// https://www.fourcc.org/yuv.php // https://www.fourcc.org/yuv.php
case V4L2_PIX_FMT_YUYV: WRITE_SCANLINES(_jpeg_write_scanlines_yuyv); break; case V4L2_PIX_FMT_YUYV: WRITE_SCANLINES(_jpeg_write_scanlines_yuyv); break;
@@ -99,6 +104,7 @@ void jpeg_encoder_compress_buffer(struct device_t *dev, const unsigned index, co
case V4L2_PIX_FMT_RGB565: WRITE_SCANLINES(_jpeg_write_scanlines_rgb565); break; case V4L2_PIX_FMT_RGB565: WRITE_SCANLINES(_jpeg_write_scanlines_rgb565); break;
default: assert(0 && "Unsupported input format for JPEG compressor"); default: assert(0 && "Unsupported input format for JPEG compressor");
} }
# undef WRITE_SCANLINES # undef WRITE_SCANLINES
// TODO: process jpeg errors: // TODO: process jpeg errors:
@@ -127,9 +133,12 @@ static void _jpeg_set_dest_picture(j_compress_ptr jpeg, unsigned char *picture,
dest->written = written; dest->written = written;
} }
static void _jpeg_write_scanlines_yuyv(struct jpeg_compress_struct *jpeg, #define NORM_COMPONENT(_x) (((_x) > 255) ? 255 : (((_x) < 0) ? 0 : (_x)))
static void _jpeg_write_scanlines_yuyv(
struct jpeg_compress_struct *jpeg,
unsigned char *line_buffer, const unsigned char *data, unsigned char *line_buffer, const unsigned char *data,
const unsigned width, const unsigned height) { unsigned width, unsigned height) {
JSAMPROW scanlines[1]; JSAMPROW scanlines[1];
unsigned z = 0; unsigned z = 0;
@@ -146,9 +155,9 @@ static void _jpeg_write_scanlines_yuyv(struct jpeg_compress_struct *jpeg,
int g = (y - (88 * u) - (183 * v)) >> 8; int g = (y - (88 * u) - (183 * v)) >> 8;
int b = (y + (454 * u)) >> 8; int b = (y + (454 * u)) >> 8;
*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); *(ptr++) = NORM_COMPONENT(r);
*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = NORM_COMPONENT(g);
*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); *(ptr++) = NORM_COMPONENT(b);
if (z++) { if (z++) {
z = 0; z = 0;
@@ -161,9 +170,10 @@ static void _jpeg_write_scanlines_yuyv(struct jpeg_compress_struct *jpeg,
} }
} }
static void _jpeg_write_scanlines_uyvy(struct jpeg_compress_struct *jpeg, static void _jpeg_write_scanlines_uyvy(
struct jpeg_compress_struct *jpeg,
unsigned char *line_buffer, const unsigned char *data, unsigned char *line_buffer, const unsigned char *data,
const unsigned width, const unsigned height) { unsigned width, unsigned height) {
JSAMPROW scanlines[1]; JSAMPROW scanlines[1];
unsigned z = 0; unsigned z = 0;
@@ -180,9 +190,9 @@ static void _jpeg_write_scanlines_uyvy(struct jpeg_compress_struct *jpeg,
int g = (y - (88 * u) - (183 * v)) >> 8; int g = (y - (88 * u) - (183 * v)) >> 8;
int b = (y + (454 * u)) >> 8; int b = (y + (454 * u)) >> 8;
*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); *(ptr++) = NORM_COMPONENT(r);
*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = NORM_COMPONENT(g);
*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); *(ptr++) = NORM_COMPONENT(b);
if (z++) { if (z++) {
z = 0; z = 0;
@@ -195,9 +205,12 @@ static void _jpeg_write_scanlines_uyvy(struct jpeg_compress_struct *jpeg,
} }
} }
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, #undef NORM_COMPONENT
static void _jpeg_write_scanlines_rgb565(
struct jpeg_compress_struct *jpeg,
unsigned char *line_buffer, const unsigned char *data, unsigned char *line_buffer, const unsigned char *data,
const unsigned width, const unsigned height) { unsigned width, unsigned height) {
JSAMPROW scanlines[1]; JSAMPROW scanlines[1];

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -24,4 +25,4 @@
#include "../device.h" #include "../device.h"
void jpeg_encoder_compress_buffer(struct device_t *dev, const unsigned index, const unsigned quality); void jpeg_encoder_compress_buffer(struct device_t *dev, unsigned index, unsigned quality);

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -40,7 +41,7 @@
#include "http.h" #include "http.h"
static const char _short_opts[] = "d:i:x:y:f:a:z:tn:w:q:c:s:p:u:ro:e:h"; static const char _short_opts[] = "d:i:x:y:m:a:f:z:tb:w:q:c:s:p:u:ro:e:h";
static const struct option _long_opts[] = { static const struct option _long_opts[] = {
{"device", required_argument, NULL, 'd'}, {"device", required_argument, NULL, 'd'},
{"input", required_argument, NULL, 'i'}, {"input", required_argument, NULL, 'i'},

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -30,11 +31,11 @@
#include "component.h" #include "component.h"
static int _component_wait_port_changed(OMX_HANDLETYPE *component, const OMX_U32 port, const OMX_BOOL enabled); static int _component_wait_port_changed(OMX_HANDLETYPE *component, OMX_U32 port, OMX_BOOL enabled);
static int _component_wait_state_changed(OMX_HANDLETYPE *component, const OMX_STATETYPE wanted); static int _component_wait_state_changed(OMX_HANDLETYPE *component, OMX_STATETYPE wanted);
int component_enable_port(OMX_HANDLETYPE *component, const OMX_U32 port) { int component_enable_port(OMX_HANDLETYPE *component, OMX_U32 port) {
OMX_ERRORTYPE error; OMX_ERRORTYPE error;
LOG_DEBUG("Enabling OMX port %u ...", port); LOG_DEBUG("Enabling OMX port %u ...", port);
@@ -45,7 +46,7 @@ int component_enable_port(OMX_HANDLETYPE *component, const OMX_U32 port) {
return _component_wait_port_changed(component, port, OMX_TRUE); return _component_wait_port_changed(component, port, OMX_TRUE);
} }
int component_disable_port(OMX_HANDLETYPE *component, const OMX_U32 port) { int component_disable_port(OMX_HANDLETYPE *component, OMX_U32 port) {
OMX_ERRORTYPE error; OMX_ERRORTYPE error;
LOG_DEBUG("Disabling OMX port %u ...", port); LOG_DEBUG("Disabling OMX port %u ...", port);
@@ -56,7 +57,7 @@ int component_disable_port(OMX_HANDLETYPE *component, const OMX_U32 port) {
return _component_wait_port_changed(component, port, OMX_FALSE); return _component_wait_port_changed(component, port, OMX_FALSE);
} }
int component_get_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYPE *portdef, const OMX_U32 port) { int component_get_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYPE *portdef, OMX_U32 port) {
OMX_ERRORTYPE error; OMX_ERRORTYPE error;
OMX_INIT_STRUCTURE(*portdef); OMX_INIT_STRUCTURE(*portdef);
@@ -81,8 +82,8 @@ int component_set_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYP
return 0; return 0;
} }
int component_set_state(OMX_HANDLETYPE *component, const OMX_STATETYPE state) { int component_set_state(OMX_HANDLETYPE *component, OMX_STATETYPE state) {
const char *const state_str = omx_state_to_string(state); const char *state_str = omx_state_to_string(state);
OMX_ERRORTYPE error; OMX_ERRORTYPE error;
int retries = 50; int retries = 50;
@@ -107,7 +108,7 @@ int component_set_state(OMX_HANDLETYPE *component, const OMX_STATETYPE state) {
} }
static int _component_wait_port_changed(OMX_HANDLETYPE *component, const OMX_U32 port, const OMX_BOOL enabled) { static int _component_wait_port_changed(OMX_HANDLETYPE *component, OMX_U32 port, OMX_BOOL enabled) {
OMX_ERRORTYPE error; OMX_ERRORTYPE error;
OMX_PARAM_PORTDEFINITIONTYPE portdef; OMX_PARAM_PORTDEFINITIONTYPE portdef;
int retries = 50; int retries = 50;
@@ -132,7 +133,7 @@ static int _component_wait_port_changed(OMX_HANDLETYPE *component, const OMX_U32
return (portdef.bEnabled == enabled ? 0 : -1); return (portdef.bEnabled == enabled ? 0 : -1);
} }
static int _component_wait_state_changed(OMX_HANDLETYPE *component, const OMX_STATETYPE wanted) { static int _component_wait_state_changed(OMX_HANDLETYPE *component, OMX_STATETYPE wanted) {
OMX_ERRORTYPE error; OMX_ERRORTYPE error;
OMX_STATETYPE state; OMX_STATETYPE state;
int retries = 50; int retries = 50;

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -38,10 +39,10 @@
} }
int component_enable_port(OMX_HANDLETYPE *component, const OMX_U32 port); int component_enable_port(OMX_HANDLETYPE *component, OMX_U32 port);
int component_disable_port(OMX_HANDLETYPE *component, const OMX_U32 port); int component_disable_port(OMX_HANDLETYPE *component, OMX_U32 port);
int component_get_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYPE *portdef, const OMX_U32 port); int component_get_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYPE *portdef, OMX_U32 port);
int component_set_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYPE *portdef); int component_set_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYPE *portdef);
int component_set_state(OMX_HANDLETYPE *component, const OMX_STATETYPE state); int component_set_state(OMX_HANDLETYPE *component, OMX_STATETYPE state);

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -51,17 +52,20 @@ static int _i_omx = 0;
static int _omx_init_component(struct omx_encoder_t *omx); static int _omx_init_component(struct omx_encoder_t *omx);
static int _omx_init_disable_ports(struct omx_encoder_t *omx); static int _omx_init_disable_ports(struct omx_encoder_t *omx);
static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev); static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev);
static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality); static int _omx_setup_output(struct omx_encoder_t *omx, unsigned quality);
static int _omx_encoder_clear_ports(struct omx_encoder_t *omx); static int _omx_encoder_clear_ports(struct omx_encoder_t *omx);
static OMX_ERRORTYPE _omx_event_handler(UNUSED OMX_HANDLETYPE encoder, static OMX_ERRORTYPE _omx_event_handler(
UNUSED OMX_HANDLETYPE encoder,
OMX_PTR v_omx, OMX_EVENTTYPE event, OMX_U32 data1, OMX_PTR v_omx, OMX_EVENTTYPE event, OMX_U32 data1,
UNUSED OMX_U32 data2, UNUSED OMX_PTR event_data); UNUSED OMX_U32 data2, UNUSED OMX_PTR event_data);
static OMX_ERRORTYPE _omx_input_required_handler(UNUSED OMX_HANDLETYPE encoder, static OMX_ERRORTYPE _omx_input_required_handler(
UNUSED OMX_HANDLETYPE encoder,
OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer); OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer);
static OMX_ERRORTYPE _omx_output_available_handler(UNUSED OMX_HANDLETYPE encoder, static OMX_ERRORTYPE _omx_output_available_handler(
UNUSED OMX_HANDLETYPE encoder,
OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer); OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer);
@@ -148,7 +152,7 @@ void omx_encoder_destroy(struct omx_encoder_t *omx) {
free(omx); free(omx);
} }
int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, const unsigned quality) { int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, unsigned quality) {
if (component_set_state(&omx->encoder, OMX_StateIdle) < 0) { if (component_set_state(&omx->encoder, OMX_StateIdle) < 0) {
return -1; return -1;
} }
@@ -167,7 +171,7 @@ int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, co
return 0; return 0;
} }
int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, const unsigned index) { int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, unsigned index) {
OMX_ERRORTYPE error; OMX_ERRORTYPE error;
bool loaded = false; bool loaded = false;
@@ -329,7 +333,7 @@ static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev) {
return 0; return 0;
} }
static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality) { static int _omx_setup_output(struct omx_encoder_t *omx, unsigned quality) {
OMX_ERRORTYPE error; OMX_ERRORTYPE error;
OMX_PARAM_PORTDEFINITIONTYPE portdef; OMX_PARAM_PORTDEFINITIONTYPE portdef;
@@ -433,7 +437,8 @@ static int _omx_encoder_clear_ports(struct omx_encoder_t *omx) {
return retcode; return retcode;
} }
static OMX_ERRORTYPE _omx_event_handler(UNUSED OMX_HANDLETYPE encoder, static OMX_ERRORTYPE _omx_event_handler(
UNUSED OMX_HANDLETYPE encoder,
OMX_PTR v_omx, OMX_EVENTTYPE event, OMX_U32 data1, OMX_PTR v_omx, OMX_EVENTTYPE event, OMX_U32 data1,
UNUSED OMX_U32 data2, UNUSED OMX_PTR event_data) { UNUSED OMX_U32 data2, UNUSED OMX_PTR event_data) {
@@ -449,7 +454,8 @@ static OMX_ERRORTYPE _omx_event_handler(UNUSED OMX_HANDLETYPE encoder,
return OMX_ErrorNone; return OMX_ErrorNone;
} }
static OMX_ERRORTYPE _omx_input_required_handler(UNUSED OMX_HANDLETYPE encoder, static OMX_ERRORTYPE _omx_input_required_handler(
UNUSED OMX_HANDLETYPE encoder,
OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer) { OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer) {
// Called by OMX when the encoder component requires // Called by OMX when the encoder component requires
@@ -462,7 +468,8 @@ static OMX_ERRORTYPE _omx_input_required_handler(UNUSED OMX_HANDLETYPE encoder,
return OMX_ErrorNone; return OMX_ErrorNone;
} }
static OMX_ERRORTYPE _omx_output_available_handler(UNUSED OMX_HANDLETYPE encoder, static OMX_ERRORTYPE _omx_output_available_handler(
UNUSED OMX_HANDLETYPE encoder,
OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer) { OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer) {
// Called by OMX when the encoder component has filled // Called by OMX when the encoder component has filled

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -51,5 +52,5 @@ struct omx_encoder_t {
struct omx_encoder_t *omx_encoder_init(); struct omx_encoder_t *omx_encoder_init();
void omx_encoder_destroy(struct omx_encoder_t *omx); void omx_encoder_destroy(struct omx_encoder_t *omx);
int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, const unsigned quality); int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, unsigned quality);
int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, const unsigned index); int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, unsigned index);

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -38,7 +39,7 @@
assert(0 && _buf); \ assert(0 && _buf); \
} }
const char *omx_error_to_string(const OMX_ERRORTYPE error) { const char *omx_error_to_string(OMX_ERRORTYPE error) {
switch (error) { switch (error) {
CASE_TO_STRING(OMX_ErrorNone); CASE_TO_STRING(OMX_ErrorNone);
CASE_TO_STRING(OMX_ErrorInsufficientResources); CASE_TO_STRING(OMX_ErrorInsufficientResources);
@@ -69,7 +70,7 @@ const char *omx_error_to_string(const OMX_ERRORTYPE error) {
} }
} }
const char *omx_state_to_string(const OMX_STATETYPE state) { const char *omx_state_to_string(OMX_STATETYPE state) {
switch (state) { switch (state) {
CASE_TO_STRING(OMX_StateLoaded); CASE_TO_STRING(OMX_StateLoaded);
CASE_TO_STRING(OMX_StateIdle); CASE_TO_STRING(OMX_StateIdle);

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -41,5 +42,5 @@
} }
const char *omx_error_to_string(const OMX_ERRORTYPE error); const char *omx_error_to_string(OMX_ERRORTYPE error);
const char *omx_state_to_string(const OMX_STATETYPE state); const char *omx_state_to_string(OMX_STATETYPE state);

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -48,7 +49,7 @@ static void _stream_init_workers(struct device_t *dev, struct workers_pool_t *po
static void *_stream_worker_thread(void *v_ctx); static void *_stream_worker_thread(void *v_ctx);
static void _stream_destroy_workers(struct device_t *dev, struct workers_pool_t *pool); static void _stream_destroy_workers(struct device_t *dev, struct workers_pool_t *pool);
static int _stream_control(struct device_t *dev, const bool enable); static int _stream_control(struct device_t *dev, bool enable);
static int _stream_grab_buffer(struct device_t *dev, struct v4l2_buffer *buf_info); static int _stream_grab_buffer(struct device_t *dev, struct v4l2_buffer *buf_info);
static int _stream_release_buffer(struct device_t *dev, struct v4l2_buffer *buf_info); static int _stream_release_buffer(struct device_t *dev, struct v4l2_buffer *buf_info);
static int _stream_handle_event(struct device_t *dev); static int _stream_handle_event(struct device_t *dev);
@@ -499,7 +500,7 @@ static void _stream_destroy_workers(struct device_t *dev, struct workers_pool_t
pool->workers = NULL; pool->workers = NULL;
} }
static int _stream_control(struct device_t *dev, const bool enable) { static int _stream_control(struct device_t *dev, bool enable) {
if (enable != dev->run->capturing) { if (enable != dev->run->capturing) {
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -47,18 +48,18 @@
#define A_PTHREAD_C_SIGNAL(...) assert(!pthread_cond_signal(__VA_ARGS__)) #define A_PTHREAD_C_SIGNAL(...) assert(!pthread_cond_signal(__VA_ARGS__))
#define A_PTHREAD_C_WAIT_TRUE(_var, _cond, _mutex) { while(!_var) assert(!pthread_cond_wait(_cond, _mutex)); } #define A_PTHREAD_C_WAIT_TRUE(_var, _cond, _mutex) { while(!_var) assert(!pthread_cond_wait(_cond, _mutex)); }
#define A_CALLOC(_dest, _nmemb) assert((_dest = calloc(_nmemb, sizeof(*(_dest))))) #define A_CALLOC(_dest, _nmemb) assert((_dest = calloc(_nmemb, sizeof(*(_dest)))))
#define A_REALLOC(_dest, _nmemb) assert((_dest = realloc(_dest, _nmemb * sizeof(*(_dest))))) #define A_REALLOC(_dest, _nmemb) assert((_dest = realloc(_dest, _nmemb * sizeof(*(_dest)))))
#define MEMSET_ZERO(_obj) memset(&(_obj), 0, sizeof(_obj)) #define MEMSET_ZERO(_obj) memset(&(_obj), 0, sizeof(_obj))
#define MEMSET_ZERO_PTR(_ptr) memset(_ptr, 0, sizeof(*(_ptr))) #define MEMSET_ZERO_PTR(_ptr) memset(_ptr, 0, sizeof(*(_ptr)))
#define ARRAY_LEN(_array) (sizeof(_array) / sizeof(_array[0]))
#define INLINE inline __attribute__((always_inline)) #define INLINE inline __attribute__((always_inline))
#define UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused))
INLINE char *bool_to_string(const bool flag) { INLINE char *bool_to_string(bool flag) {
return (flag ? "true" : "false"); return (flag ? "true" : "false");
} }

View File

@@ -1,4 +1,5 @@
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
@@ -32,7 +33,7 @@
#define XIOCTL_RETRIES 4 #define XIOCTL_RETRIES 4
INLINE int xioctl(const int fd, const int request, void *arg) { INLINE int xioctl(int fd, int request, void *arg) {
int retries = XIOCTL_RETRIES; int retries = XIOCTL_RETRIES;
int retval = -1; int retval = -1;

View File

@@ -44,6 +44,7 @@ def main():
text = "const char *%s = \" \\\n%s\n\";\n" % (name, text) text = "const char *%s = \" \\\n%s\n\";\n" % (name, text)
text = textwrap.dedent(""" text = textwrap.dedent("""
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #

View File

@@ -42,7 +42,7 @@ def main():
for ch in jpg_data: for ch in jpg_data:
if len(rows[-1]) > 20: if len(rows[-1]) > 20:
rows.append([]) rows.append([])
rows[-1].append(hex(ch)) rows[-1].append("0x%.2X" % (ch))
text = ",\n\t".join(", ".join(row) for row in rows) text = ",\n\t".join(", ".join(row) for row in rows)
text = "const unsigned char %s_JPG_DATA[] = {\n\t%s\n};\n" % (prefix, text) text = "const unsigned char %s_JPG_DATA[] = {\n\t%s\n};\n" % (prefix, text)
@@ -51,6 +51,7 @@ def main():
text = "const unsigned %s_JPG_WIDTH = %d;\n" % (prefix, width) + text text = "const unsigned %s_JPG_WIDTH = %d;\n" % (prefix, width) + text
text = textwrap.dedent(""" text = textwrap.dedent("""
/***************************************************************************** /*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. # # uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# # # #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> # # Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #