mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-20 08:46:31 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59bd4e8dd2 | ||
|
|
ce6184b8cd | ||
|
|
9ca511d29d | ||
|
|
74de28c64a | ||
|
|
24060e8068 | ||
|
|
3a03d48855 | ||
|
|
935a9125d6 | ||
|
|
d4ea97ef2c | ||
|
|
867aa4e52a | ||
|
|
bc2bb444dc | ||
|
|
19796f3b64 | ||
|
|
348a6e4a8f | ||
|
|
ba3300ddde | ||
|
|
09526884f4 |
@@ -1,7 +1,7 @@
|
||||
[bumpversion]
|
||||
commit = True
|
||||
tag = True
|
||||
current_version = 0.43
|
||||
current_version = 0.48
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)?
|
||||
serialize =
|
||||
{major}.{minor}
|
||||
|
||||
2
PKGBUILD
2
PKGBUILD
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
pkgname=ustreamer
|
||||
pkgver=0.43
|
||||
pkgver=0.48
|
||||
pkgrel=1
|
||||
pkgdesc="Lightweight and fast MJPG-HTTP streamer"
|
||||
url="https://github.com/pi-kvm/ustreamer"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
| Option to skip frames when streaming<br>static images by HTTP to save traffic |  Yes <sup>2</sup> |  No |
|
||||
| Streaming via UNIX domain socket |  Yes |  No |
|
||||
| Debug logs without recompiling,<br>performance statistics log,<br>access to HTTP broadcast parameters |  Yes |  No |
|
||||
| Supported input devices |  YUYV, UYVY,<br>RGB565, ~~MJPG~~ <sup>3</sup> |  YUYV, UYVY,<br>RGB565, MJPG |
|
||||
| Supported input formats |  YUYV, UYVY,<br>RGB565, ~~MJPG~~ <sup>3</sup> |  YUYV, UYVY,<br>RGB565, MJPG |
|
||||
| Access to webcam controls (focus, servos)<br>and settings such as brightness via HTTP |  No |  Yes |
|
||||
| Option to serve files<br>with a built-in HTTP server, auth settings |  No <sup>4</sup> |  Yes |
|
||||
|
||||
@@ -60,7 +60,6 @@ $ ./ustreamer \
|
||||
--format=uyvy \ # Device input format
|
||||
--encoder=omx \ # Hardware encoding with OpenMAX
|
||||
--dv-timings \ # Use DV-timings
|
||||
--quality=20 \ # OpenMAX has a non-linear quality scale
|
||||
--drop-same-frames=30 # Save that traffic
|
||||
```
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ $ ./ustreamer \
|
||||
--format=uyvy \ # Настройка входного формата устройства
|
||||
--encoder=omx \ # Использование аппаратного кодирования с помощью OpenMAX
|
||||
--dv-timings \ # Включение DV-таймингов
|
||||
--quality=20 \ # У OpenMAX нелинейная шкала качества
|
||||
--drop-same-frames=30 # Экономим трафик
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
@@ -21,4 +22,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define VERSION "0.43"
|
||||
#define VERSION "0.48"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
66
src/device.c
66
src/device.c
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
@@ -26,6 +27,7 @@
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <linux/videodev2.h>
|
||||
@@ -63,6 +65,7 @@ static int _device_open_format(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_queue_buffers(struct device_t *dev);
|
||||
static int _device_apply_resolution(struct device_t *dev, const unsigned width, const unsigned height);
|
||||
|
||||
static const char *_format_to_string_auto(char *buf, const size_t size, const unsigned format);
|
||||
static const char *_format_to_string_null(const unsigned format);
|
||||
@@ -161,7 +164,7 @@ void device_close(struct device_t *dev) {
|
||||
for (unsigned index = 0; index < dev->run->n_buffers; ++index) {
|
||||
if (dev->run->hw_buffers[index].start != MAP_FAILED) {
|
||||
if (munmap(dev->run->hw_buffers[index].start, dev->run->hw_buffers[index].length) < 0) {
|
||||
LOG_PERROR("Can't unmap device buffer %d", index);
|
||||
LOG_PERROR("Can't unmap device buffer %u", index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,6 +225,7 @@ static int _device_open_check_cap(struct device_t *dev) {
|
||||
}
|
||||
|
||||
static int _device_open_dv_timings(struct device_t *dev) {
|
||||
_device_apply_resolution(dev, dev->width, dev->height);
|
||||
if (dev->dv_timings) {
|
||||
LOG_DEBUG("Using DV-timings");
|
||||
|
||||
@@ -239,10 +243,6 @@ static int _device_open_dv_timings(struct device_t *dev) {
|
||||
LOG_PERROR("Can't subscribe to V4L2_EVENT_SOURCE_CHANGE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
dev->run->width = dev->width;
|
||||
dev->run->height = dev->height;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -255,7 +255,7 @@ static int _device_apply_dv_timings(struct device_t *dev) {
|
||||
LOG_DEBUG("Calling ioctl(VIDIOC_QUERY_DV_TIMINGS) ...");
|
||||
if (xioctl(dev->run->fd, VIDIOC_QUERY_DV_TIMINGS, &dv_timings) == 0) {
|
||||
LOG_INFO(
|
||||
"Got new DV timings: resolution=%dx%d; pixclk=%llu",
|
||||
"Got new DV timings: resolution=%ux%u; pixclk=%llu",
|
||||
dv_timings.bt.width,
|
||||
dv_timings.bt.height,
|
||||
dv_timings.bt.pixelclock
|
||||
@@ -267,8 +267,9 @@ static int _device_apply_dv_timings(struct device_t *dev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->run->width = dv_timings.bt.width;
|
||||
dev->run->height = dv_timings.bt.height;
|
||||
if (_device_apply_resolution(dev, dv_timings.bt.width, dv_timings.bt.height) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_DEBUG("Calling ioctl(VIDIOC_QUERYSTD) ...");
|
||||
@@ -299,7 +300,7 @@ static int _device_open_format(struct device_t *dev) {
|
||||
char format_str[8];
|
||||
|
||||
LOG_PERROR(
|
||||
"Unable to set format=%s; resolution=%dx%d",
|
||||
"Unable to set format=%s; resolution=%ux%u",
|
||||
_format_to_string_auto(format_str, 8, dev->format),
|
||||
dev->run->width,
|
||||
dev->run->height
|
||||
@@ -309,11 +310,12 @@ static int _device_open_format(struct device_t *dev) {
|
||||
|
||||
// Check resolution
|
||||
if (fmt.fmt.pix.width != dev->run->width || fmt.fmt.pix.height != dev->run->height) {
|
||||
LOG_ERROR("Requested resolution=%dx%d is unavailable", dev->run->width, dev->run->height);
|
||||
LOG_ERROR("Requested resolution=%ux%u is unavailable", dev->run->width, dev->run->height);
|
||||
}
|
||||
dev->run->width = fmt.fmt.pix.width;
|
||||
dev->run->height = fmt.fmt.pix.height;
|
||||
LOG_INFO("Using resolution: %dx%d", dev->run->width, dev->run->height);
|
||||
if (_device_apply_resolution(dev, fmt.fmt.pix.width, fmt.fmt.pix.height) < 0) {
|
||||
return -1;
|
||||
}
|
||||
LOG_INFO("Using resolution: %ux%u", dev->run->width, dev->run->height);
|
||||
|
||||
// Check format
|
||||
if (fmt.fmt.pix.pixelformat != dev->format) {
|
||||
@@ -357,10 +359,10 @@ static int _device_open_mmap(struct device_t *dev) {
|
||||
}
|
||||
|
||||
if (req.count < 1) {
|
||||
LOG_ERROR("Insufficient buffer memory: %d", req.count);
|
||||
LOG_ERROR("Insufficient buffer memory: %u", req.count);
|
||||
return -1;
|
||||
} else {
|
||||
LOG_INFO("Requested %d HW buffers, got %d", dev->n_buffers, req.count);
|
||||
LOG_INFO("Requested %u HW buffers, got %u", dev->n_buffers, req.count);
|
||||
}
|
||||
|
||||
LOG_DEBUG("Allocating HW buffers ...");
|
||||
@@ -374,17 +376,17 @@ static int _device_open_mmap(struct device_t *dev) {
|
||||
buf_info.memory = V4L2_MEMORY_MMAP;
|
||||
buf_info.index = dev->run->n_buffers;
|
||||
|
||||
LOG_DEBUG("Calling ioctl(VIDIOC_QUERYBUF) for device buffer %d ...", dev->run->n_buffers);
|
||||
LOG_DEBUG("Calling ioctl(VIDIOC_QUERYBUF) for device buffer %u ...", dev->run->n_buffers);
|
||||
if (xioctl(dev->run->fd, VIDIOC_QUERYBUF, &buf_info) < 0) {
|
||||
LOG_PERROR("Can't VIDIOC_QUERYBUF");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Mapping device buffer %d ...", dev->run->n_buffers);
|
||||
LOG_DEBUG("Mapping device buffer %u ...", dev->run->n_buffers);
|
||||
dev->run->hw_buffers[dev->run->n_buffers].length = buf_info.length;
|
||||
dev->run->hw_buffers[dev->run->n_buffers].start = mmap(NULL, buf_info.length, PROT_READ|PROT_WRITE, MAP_SHARED, dev->run->fd, buf_info.m.offset);
|
||||
if (dev->run->hw_buffers[dev->run->n_buffers].start == MAP_FAILED) {
|
||||
LOG_PERROR("Can't map device buffer %d", dev->run->n_buffers);
|
||||
LOG_PERROR("Can't map device buffer %u", dev->run->n_buffers);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -400,7 +402,7 @@ static int _device_open_queue_buffers(struct device_t *dev) {
|
||||
buf_info.memory = V4L2_MEMORY_MMAP;
|
||||
buf_info.index = index;
|
||||
|
||||
LOG_DEBUG("Calling ioctl(VIDIOC_QBUF) for buffer %d ...", index);
|
||||
LOG_DEBUG("Calling ioctl(VIDIOC_QBUF) for buffer %u ...", index);
|
||||
if (xioctl(dev->run->fd, VIDIOC_QBUF, &buf_info) < 0) {
|
||||
LOG_PERROR("Can't VIDIOC_QBUF");
|
||||
return -1;
|
||||
@@ -415,18 +417,34 @@ static void _device_open_alloc_picbufs(struct device_t *dev) {
|
||||
|
||||
dev->run->max_picture_size = ((dev->run->width * dev->run->height) << 1) * 2;
|
||||
for (unsigned index = 0; index < dev->run->n_buffers; ++index) {
|
||||
LOG_DEBUG("Allocating picture buffer %d sized %lu bytes... ", index, dev->run->max_picture_size);
|
||||
LOG_DEBUG("Allocating picture buffer %u sized %lu bytes... ", index, dev->run->max_picture_size);
|
||||
A_CALLOC(dev->run->pictures[index].data, dev->run->max_picture_size);
|
||||
dev->run->pictures[index].allocated = dev->run->max_picture_size;
|
||||
}
|
||||
}
|
||||
|
||||
static int _device_apply_resolution(struct device_t *dev, const unsigned width, const unsigned height) {
|
||||
// Тут VIDEO_MIN_* не используются из-за странностей минимального разрешения при отсутствии сигнала
|
||||
// у некоторых устройств, например Auvidea B101
|
||||
if (
|
||||
width == 0 || width > VIDEO_MAX_WIDTH
|
||||
|| height == 0 || height > VIDEO_MAX_HEIGHT
|
||||
) {
|
||||
LOG_ERROR("Requested forbidden resolution=%ux%u: min=1x1; max=%ux%u",
|
||||
width, height, VIDEO_MAX_WIDTH, VIDEO_MAX_HEIGHT);
|
||||
return -1;
|
||||
}
|
||||
dev->run->width = width;
|
||||
dev->run->height = height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *_format_to_string_auto(char *buf, const size_t size, const unsigned format) {
|
||||
assert(size >= 8);
|
||||
buf[0] = format & 0x7f;
|
||||
buf[1] = (format >> 8) & 0x7f;
|
||||
buf[2] = (format >> 16) & 0x7f;
|
||||
buf[3] = (format >> 24) & 0x7f;
|
||||
buf[0] = format & 0x7F;
|
||||
buf[1] = (format >> 8) & 0x7F;
|
||||
buf[2] = (format >> 16) & 0x7F;
|
||||
buf[3] = (format >> 24) & 0x7F;
|
||||
if (format & (1 << 31)) {
|
||||
buf[4] = '-';
|
||||
buf[5] = 'B';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
@@ -28,6 +29,12 @@
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
|
||||
#define VIDEO_MIN_WIDTH 320
|
||||
#define VIDEO_MAX_WIDTH 1920
|
||||
|
||||
#define VIDEO_MIN_HEIGHT 180
|
||||
#define VIDEO_MAX_HEIGHT 1200
|
||||
|
||||
#define STANDARD_UNKNOWN V4L2_STD_UNKNOWN
|
||||
#define STANDARDS_STR "UNKNOWN, PAL, NTSC, SECAM"
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
@@ -65,7 +66,7 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) {
|
||||
LOG_DEBUG("Initializing encoder ...");
|
||||
}
|
||||
|
||||
LOG_INFO("Using JPEG quality: %d%%", encoder->quality);
|
||||
LOG_INFO("Using JPEG quality: %u%%", encoder->quality);
|
||||
|
||||
# ifdef OMX_ENCODER
|
||||
if (encoder->type == ENCODER_TYPE_OMX) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
14
src/http.c
14
src/http.c
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
@@ -180,12 +181,12 @@ int http_server_listen(struct http_server_t *server) {
|
||||
LOG_INFO("Listening HTTP on UNIX socket '%s'", server->unix_path);
|
||||
|
||||
} else {
|
||||
LOG_DEBUG("Binding HTTP to [%s]:%d ...", server->host, server->port);
|
||||
LOG_DEBUG("Binding HTTP to [%s]:%u ...", server->host, server->port);
|
||||
if (evhttp_bind_socket(server->run->http, server->host, server->port) < 0) {
|
||||
LOG_PERROR("Can't bind HTTP on [%s]:%d", server->host, server->port)
|
||||
LOG_PERROR("Can't bind HTTP on [%s]:%u", server->host, server->port)
|
||||
return -1;
|
||||
}
|
||||
LOG_INFO("Listening HTTP on [%s]:%d", server->host, server->port);
|
||||
LOG_INFO("Listening HTTP on [%s]:%u", server->host, server->port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -296,7 +297,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)));
|
||||
|
||||
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("Expires", "Mon, 3 Jan 2000 12:34:56 GMT");
|
||||
|
||||
@@ -309,6 +310,7 @@ static void _http_callback_snapshot(struct evhttp_request *request, void *v_serv
|
||||
ADD_TIME_HEADER("X-Timestamp", get_now_real());
|
||||
|
||||
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_TIME_HEADER("X-UStreamer-Grab-Time", EXPOSED(picture.grab_time));
|
||||
@@ -446,7 +448,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
|
||||
assert(evbuffer_add_printf(buf,
|
||||
"HTTP/1.0 200 OK" 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
|
||||
"Expires: Mon, 3 Jan 2000 12:34:56 GMT" RN
|
||||
"Set-Cookie: stream_client=%s/%s; path=/; max-age=30" RN
|
||||
@@ -479,6 +481,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
|
||||
if (client->extra_headers) {
|
||||
assert(evbuffer_add_printf(buf,
|
||||
"X-UStreamer-Online: %s" RN
|
||||
"X-UStreamer-Dropped: %u" RN
|
||||
"X-UStreamer-Width: %u" RN
|
||||
"X-UStreamer-Height: %u" RN
|
||||
"X-UStreamer-Client-FPS: %u" RN
|
||||
@@ -491,6 +494,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
|
||||
"X-UStreamer-Send-Time: %.06Lf" RN
|
||||
RN,
|
||||
bool_to_string(EXPOSED(online)),
|
||||
EXPOSED(dropped),
|
||||
EXPOSED(width),
|
||||
EXPOSED(height),
|
||||
client->fps,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# This source file based on code of MJPG-Streamer. #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
31
src/main.c
31
src/main.c
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
@@ -99,32 +100,32 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
|
||||
printf("------------------\n");
|
||||
printf(" -d|--device </dev/path> -- Path to V4L2 device. Default: %s.\n\n", dev->path);
|
||||
printf(" -i|--input <N> -- Input channel. Default: %u.\n\n", dev->input);
|
||||
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(" -x|--width <N> -- Initial image width. Default: %u.\n\n", dev->width);
|
||||
printf(" -y|--height <N> -- Initial image height. Default: %u.\n\n", dev->height);
|
||||
printf(" -m|--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(" -f|--desired-fps <N> -- Desired FPS; default: maximum as possible.\n\n");
|
||||
printf(" -f|--desired-fps <N> -- Desired FPS. Default: maximum as possible.\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|--quality <N> -- Set quality of JPEG encoding from 1 to 100 (best). Default: %d.\n\n", encoder->quality);
|
||||
printf(" Default: %u (number of CPU cores + 1)\n\n", dev->n_buffers);
|
||||
printf(" -w|--workers <N> -- The number of compressing threads. Default: %u (== --buffers).\n\n", dev->n_workers);
|
||||
printf(" -q|--quality <N> -- Set quality of JPEG encoding from 1 to 100 (best). Default: %u.\n\n", encoder->quality);
|
||||
printf(" -c|--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-timeout <seconds> -- Timeout for device querying. Default: %u\n\n", dev->timeout);
|
||||
printf(" --device-persistent -- Don't re-initialize device on timeout. Default: disabled.\n\n");
|
||||
printf(" --device-error-delay <seconds> -- Delay before trying to connect to the device again\n");
|
||||
printf(" after a timeout. Default: %d\n\n", dev->error_delay);
|
||||
printf(" after a timeout. Default: %u\n\n", dev->error_delay);
|
||||
printf("HTTP server options:\n");
|
||||
printf("--------------------\n");
|
||||
printf(" -s|--host <address> -- Listen on Hostname or IP. Default: %s\n\n", server->host);
|
||||
printf(" -p|--port <N> -- Bind to this TCP port. Default: %d\n\n", server->port);
|
||||
printf(" -p|--port <N> -- Bind to this TCP port. Default: %u\n\n", server->port);
|
||||
printf(" -u|--unix <path> -- Bind to UNIX domain socket. Default: disabled\n\n");
|
||||
printf(" -r|--unix-rm -- Try to remove old UNIX socket file before binding. Default: disabled\n\n");
|
||||
printf(" -o|--unix-mode <mode> -- Set UNIX socket file permissions (like 777). Default: disabled\n\n");
|
||||
@@ -134,15 +135,15 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
|
||||
printf(" or webcams, it's useless. Default: disabled.\n\n");
|
||||
printf(" --fake-width <N> -- Override image width for /state. Default: disabled\n\n");
|
||||
printf(" --fake-height <N> -- Override image height for /state. Default: disabled.\n\n");
|
||||
printf(" --server-timeout <seconds> -- Timeout for client connections. Default: %d\n\n", server->timeout);
|
||||
printf(" --server-timeout <seconds> -- Timeout for client connections. Default: %u\n\n", server->timeout);
|
||||
printf("Misc options:\n");
|
||||
printf("-------------\n");
|
||||
printf(" --log-level <N> -- Verbosity level of messages from 0 (info) to 3 (debug).\n");
|
||||
printf(" Enabling debugging messages can slow down the program.\n");
|
||||
printf(" Available levels: 0=info, 1=performance, 2=verbose, 3=debug.\n");
|
||||
printf(" Default: %d.\n\n", log_level);
|
||||
printf(" --perf -- Enable performance messages (same as log-level=1). Default: disabled.\n\n");
|
||||
printf(" --verbose -- Enable verbose messages and lower (same as log-level=2). Default: disabled.\n\n");
|
||||
printf(" Default: %u.\n\n", log_level);
|
||||
printf(" --perf -- Enable performance messages (same as --log-level=1). Default: disabled.\n\n");
|
||||
printf(" --verbose -- Enable verbose messages and lower (same as --log-level=2). Default: disabled.\n\n");
|
||||
printf(" --debug -- Enable debug messages and lower (same as --log-level=3). Default: disabled.\n\n");
|
||||
printf(" -h|--help -- Print this messages and exit.\n\n");
|
||||
}
|
||||
@@ -176,8 +177,8 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
switch (ch) {
|
||||
case 'd': OPT_SET(dev->path, optarg);
|
||||
case 'i': OPT_UNSIGNED(dev->input, "--input", 0, 128);
|
||||
case 'x': OPT_UNSIGNED(dev->width, "--width", 320, 1920);
|
||||
case 'y': OPT_UNSIGNED(dev->height, "--height", 180, 1200);
|
||||
case 'x': OPT_UNSIGNED(dev->width, "--width", VIDEO_MIN_WIDTH, VIDEO_MAX_WIDTH);
|
||||
case 'y': OPT_UNSIGNED(dev->height, "--height", VIDEO_MIN_HEIGHT, VIDEO_MAX_HEIGHT);
|
||||
# pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
# pragma GCC diagnostic push
|
||||
case 'm': OPT_PARSE(dev->format, device_parse_format, FORMAT_UNKNOWN, "pixel format");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
19
src/stream.c
19
src/stream.c
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
@@ -189,7 +190,7 @@ void stream_loop(struct stream_t *stream) {
|
||||
// For example a VGA (640x480) webcam picture is normally >= 8kByte large,
|
||||
// corrupted frames are smaller.
|
||||
if (buf_info.bytesused < stream->dev->min_frame_size) {
|
||||
LOG_DEBUG("Dropping too small frame sized %d bytes, assuming it as broken", buf_info.bytesused);
|
||||
LOG_DEBUG("Dropping too small frame sized %u bytes, assuming it as broken", buf_info.bytesused);
|
||||
goto pass_frame;
|
||||
}
|
||||
|
||||
@@ -215,7 +216,7 @@ void stream_loop(struct stream_t *stream) {
|
||||
LOG_VERBOSE("Fluency: delay=%.03Lf; grab_after=%.03Lf", fluency_delay, grab_after);
|
||||
}
|
||||
|
||||
LOG_DEBUG("Grabbed a new frame to buffer %d", buf_info.index);
|
||||
LOG_DEBUG("Grabbed a new frame to buffer %u", buf_info.index);
|
||||
pool.workers[free_worker_number].ctx.buf_info = buf_info;
|
||||
|
||||
if (!oldest_worker) {
|
||||
@@ -343,7 +344,7 @@ static int _stream_init_loop(struct device_t *dev, struct workers_pool_t *pool)
|
||||
LOG_DEBUG("%s: *dev->stop = %d", __FUNCTION__, dev->stop);
|
||||
while (!dev->stop) {
|
||||
if ((retval = _stream_init(dev, pool)) < 0) {
|
||||
LOG_INFO("Sleeping %d seconds before new stream init ...", dev->error_delay);
|
||||
LOG_INFO("Sleeping %u seconds before new stream init ...", dev->error_delay);
|
||||
sleep(dev->error_delay);
|
||||
} else {
|
||||
break;
|
||||
@@ -378,7 +379,7 @@ static int _stream_init(struct device_t *dev, struct workers_pool_t *pool) {
|
||||
}
|
||||
|
||||
static void _stream_init_workers(struct device_t *dev, struct workers_pool_t *pool) {
|
||||
LOG_INFO("Spawning %d workers ...", dev->n_workers);
|
||||
LOG_INFO("Spawning %u workers ...", dev->n_workers);
|
||||
|
||||
*pool->workers_stop = false;
|
||||
A_CALLOC(pool->workers, dev->n_workers);
|
||||
@@ -434,7 +435,7 @@ static void *_stream_worker_thread(void *v_ctx) {
|
||||
# define PICTURE(_next) ctx->dev->run->pictures[ctx->buf_index]._next
|
||||
|
||||
if (!*ctx->workers_stop) {
|
||||
LOG_DEBUG("Worker %u compressing JPEG from buffer %d ...", ctx->number, ctx->buf_index);
|
||||
LOG_DEBUG("Worker %u compressing JPEG from buffer %u ...", ctx->number, ctx->buf_index);
|
||||
|
||||
PICTURE(encode_begin_time) = get_now_monotonic();
|
||||
if (encoder_compress_buffer(ctx->encoder, ctx->dev, ctx->number, ctx->buf_index) < 0) {
|
||||
@@ -453,7 +454,7 @@ static void *_stream_worker_thread(void *v_ctx) {
|
||||
A_PTHREAD_M_UNLOCK(ctx->last_comp_time_mutex);
|
||||
|
||||
LOG_VERBOSE(
|
||||
"Compressed JPEG size=%ld; time=%0.3Lf; worker=%u; buffer=%d",
|
||||
"Compressed JPEG size=%ld; time=%0.3Lf; worker=%u; buffer=%u",
|
||||
PICTURE(size), last_comp_time, ctx->number, ctx->buf_index
|
||||
);
|
||||
} else {
|
||||
@@ -470,7 +471,7 @@ static void *_stream_worker_thread(void *v_ctx) {
|
||||
A_PTHREAD_C_SIGNAL(ctx->free_workers_cond);
|
||||
}
|
||||
|
||||
LOG_DEBUG("Bye-bye (worker %d)", ctx->number);
|
||||
LOG_DEBUG("Bye-bye (worker %u)", ctx->number);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -528,9 +529,9 @@ static int _stream_grab_buffer(struct device_t *dev, struct v4l2_buffer *buf_inf
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Got a new frame in buffer index=%d; bytesused=%d", buf_info->index, buf_info->bytesused);
|
||||
LOG_DEBUG("Got a new frame in buffer index=%u; bytesused=%u", buf_info->index, buf_info->bytesused);
|
||||
if (buf_info->index >= dev->run->n_buffers) {
|
||||
LOG_ERROR("Got invalid buffer index=%d; nbuffers=%d", buf_info->index, dev->run->n_buffers);
|
||||
LOG_ERROR("Got invalid buffer index=%u; nbuffers=%u", buf_info->index, dev->run->n_buffers);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -44,6 +44,7 @@ def main():
|
||||
text = "const char *%s = \" \\\n%s\n\";\n" % (name, text)
|
||||
text = textwrap.dedent("""
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
@@ -42,7 +42,7 @@ def main():
|
||||
for ch in jpg_data:
|
||||
if len(rows[-1]) > 20:
|
||||
rows.append([])
|
||||
rows[-1].append(hex(ch))
|
||||
rows[-1].append("0x%.2X" % (ch))
|
||||
|
||||
text = ",\n\t".join(", ".join(row) for row in rows)
|
||||
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 = textwrap.dedent("""
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||
|
||||
Reference in New Issue
Block a user