mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-27 12:16:31 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
472673ea90 | ||
|
|
f7ebe31c71 | ||
|
|
3a831817f4 | ||
|
|
913cdac7a6 | ||
|
|
777697dc1e | ||
|
|
5f437b9a35 | ||
|
|
b089f896da |
@@ -1,7 +1,7 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
current_version = 6.37
|
current_version = 6.40
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
||||||
serialize =
|
serialize =
|
||||||
{major}.{minor}
|
{major}.{minor}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer-dump.
|
.\" Manpage for ustreamer-dump.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER-DUMP 1 "version 6.37" "January 2021"
|
.TH USTREAMER-DUMP 1 "version 6.40" "January 2021"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer-dump \- Dump uStreamer's memory sink to file
|
ustreamer-dump \- Dump uStreamer's memory sink to file
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer.
|
.\" Manpage for ustreamer.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER 1 "version 6.37" "November 2020"
|
.TH USTREAMER 1 "version 6.40" "November 2020"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
||||||
@@ -276,6 +276,9 @@ Timeout for lock. Default: 1.
|
|||||||
.BR \-\-exit\-on\-parent\-death
|
.BR \-\-exit\-on\-parent\-death
|
||||||
Exit the program if the parent process is dead. Required \fBWITH_PDEATHSIG\fR feature. Default: disabled.
|
Exit the program if the parent process is dead. Required \fBWITH_PDEATHSIG\fR feature. Default: disabled.
|
||||||
.TP
|
.TP
|
||||||
|
.BR \-\-exit\-on\-device\-error
|
||||||
|
Exit on any device error instead of polling until success. Default: disabled.
|
||||||
|
.TP
|
||||||
.BR \-\-exit\-on\-no\-clients \fIsec
|
.BR \-\-exit\-on\-no\-clients \fIsec
|
||||||
Exit the program if there have been no stream or sink clients or any HTTP requests in the last N seconds. Default: 0 (disabled).
|
Exit the program if there have been no stream or sink clients or any HTTP requests in the last N seconds. Default: 0 (disabled).
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
pkgname=ustreamer
|
pkgname=ustreamer
|
||||||
pkgver=6.37
|
pkgver=6.40
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
||||||
url="https://github.com/pikvm/ustreamer"
|
url="https://github.com/pikvm/ustreamer"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=ustreamer
|
PKG_NAME:=ustreamer
|
||||||
PKG_VERSION:=6.37
|
PKG_VERSION:=6.40
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ def main() -> None:
|
|||||||
flags = _find_flags()
|
flags = _find_flags()
|
||||||
setup(
|
setup(
|
||||||
name="ustreamer",
|
name="ustreamer",
|
||||||
version="6.37",
|
version="6.40",
|
||||||
description="uStreamer tools",
|
description="uStreamer tools",
|
||||||
author="Maxim Devaev",
|
author="Maxim Devaev",
|
||||||
author_email="mdevaev@gmail.com",
|
author_email="mdevaev@gmail.com",
|
||||||
|
|||||||
@@ -569,19 +569,28 @@ bool _capture_is_buffer_valid(const us_capture_s *cap, const struct v4l2_buffer
|
|||||||
if (us_is_jpeg(cap->run->format)) {
|
if (us_is_jpeg(cap->run->format)) {
|
||||||
if (buf->bytesused < 125) {
|
if (buf->bytesused < 125) {
|
||||||
// https://stackoverflow.com/questions/2253404/what-is-the-smallest-valid-jpeg-file-size-in-bytes
|
// https://stackoverflow.com/questions/2253404/what-is-the-smallest-valid-jpeg-file-size-in-bytes
|
||||||
_LOG_DEBUG("Discarding invalid frame, too small to be a valid JPEG: bytesused=%u", buf->bytesused);
|
_LOG_DEBUG("Discarding invalid frame, too small to be a valid JPEG: bytesused=%u",
|
||||||
|
buf->bytesused);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 *const end_ptr = data + buf->bytesused;
|
const u16 begin_marker = (((u16)(data[0]) << 8) | data[1]);
|
||||||
const u8 *const eoi_ptr = end_ptr - 2;
|
if (begin_marker != 0xFFD8) {
|
||||||
const u16 eoi_marker = (((u16)(eoi_ptr[0]) << 8) | eoi_ptr[1]);
|
_LOG_DEBUG("Discarding JPEG frame with invalid header: begin_marker=0x%04x, bytesused=%u",
|
||||||
if (eoi_marker != 0xFFD9 && eoi_marker != 0xD900 && eoi_marker != 0x0000) {
|
begin_marker, buf->bytesused);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8 *const end_ptr = data + buf->bytesused - 2;
|
||||||
|
const u16 end_marker = (((u16)(end_ptr[0]) << 8) | end_ptr[1]);
|
||||||
|
if (end_marker != 0xFFD9 && end_marker != 0xD900 && end_marker != 0x0000) {
|
||||||
if (!cap->allow_truncated_frames) {
|
if (!cap->allow_truncated_frames) {
|
||||||
_LOG_DEBUG("Discarding truncated JPEG frame: eoi_marker=0x%04x, bytesused=%u", eoi_marker, buf->bytesused);
|
_LOG_DEBUG("Discarding truncated JPEG frame: end_marker=0x%04x, bytesused=%u",
|
||||||
|
end_marker, buf->bytesused);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_LOG_DEBUG("Got truncated JPEG frame: eoi_marker=0x%04x, bytesused=%u", eoi_marker, buf->bytesused);
|
_LOG_DEBUG("Got truncated JPEG frame: end_marker=0x%04x, bytesused=%u",
|
||||||
|
end_marker, buf->bytesused);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define US_VERSION_MAJOR 6
|
#define US_VERSION_MAJOR 6
|
||||||
#define US_VERSION_MINOR 37
|
#define US_VERSION_MINOR 40
|
||||||
|
|
||||||
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
||||||
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ enum _US_OPT_VALUES {
|
|||||||
# ifdef WITH_PDEATHSIG
|
# ifdef WITH_PDEATHSIG
|
||||||
_O_EXIT_ON_PARENT_DEATH,
|
_O_EXIT_ON_PARENT_DEATH,
|
||||||
# endif
|
# endif
|
||||||
|
_O_EXIT_ON_DEVICE_ERROR,
|
||||||
_O_EXIT_ON_NO_CLIENTS,
|
_O_EXIT_ON_NO_CLIENTS,
|
||||||
# ifdef WITH_SETPROCTITLE
|
# ifdef WITH_SETPROCTITLE
|
||||||
_O_PROCESS_NAME_PREFIX,
|
_O_PROCESS_NAME_PREFIX,
|
||||||
@@ -227,6 +228,7 @@ static const struct option _LONG_OPTS[] = {
|
|||||||
# ifdef WITH_PDEATHSIG
|
# ifdef WITH_PDEATHSIG
|
||||||
{"exit-on-parent-death", no_argument, NULL, _O_EXIT_ON_PARENT_DEATH},
|
{"exit-on-parent-death", no_argument, NULL, _O_EXIT_ON_PARENT_DEATH},
|
||||||
# endif
|
# endif
|
||||||
|
{"exit-on-device-error", no_argument, NULL, _O_EXIT_ON_DEVICE_ERROR},
|
||||||
{"exit-on-no-clients", required_argument, NULL, _O_EXIT_ON_NO_CLIENTS},
|
{"exit-on-no-clients", required_argument, NULL, _O_EXIT_ON_NO_CLIENTS},
|
||||||
# ifdef WITH_SETPROCTITLE
|
# ifdef WITH_SETPROCTITLE
|
||||||
{"process-name-prefix", required_argument, NULL, _O_PROCESS_NAME_PREFIX},
|
{"process-name-prefix", required_argument, NULL, _O_PROCESS_NAME_PREFIX},
|
||||||
@@ -490,6 +492,7 @@ int options_parse(us_options_s *options, us_capture_s *cap, us_encoder_s *enc, u
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
# endif
|
# endif
|
||||||
|
case _O_EXIT_ON_DEVICE_ERROR: OPT_SET(stream->exit_on_device_error, true);
|
||||||
case _O_EXIT_ON_NO_CLIENTS: OPT_NUMBER("--exit-on-no-clients", stream->exit_on_no_clients, 0, 86400, 0);
|
case _O_EXIT_ON_NO_CLIENTS: OPT_NUMBER("--exit-on-no-clients", stream->exit_on_no_clients, 0, 86400, 0);
|
||||||
# ifdef WITH_SETPROCTITLE
|
# ifdef WITH_SETPROCTITLE
|
||||||
case _O_PROCESS_NAME_PREFIX: OPT_SET(process_name_prefix, optarg);
|
case _O_PROCESS_NAME_PREFIX: OPT_SET(process_name_prefix, optarg);
|
||||||
|
|||||||
@@ -604,7 +604,9 @@ static int _stream_init_loop(us_stream_s *stream) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
silent_error:
|
silent_error:
|
||||||
US_ONCE({ US_LOG_INFO("Waiting for the capture device ..."); });
|
if (!stream->exit_on_device_error) {
|
||||||
|
US_ONCE({ US_LOG_INFO("Waiting for the capture device ..."); });
|
||||||
|
}
|
||||||
goto offline_and_retry;
|
goto offline_and_retry;
|
||||||
|
|
||||||
verbose_error:
|
verbose_error:
|
||||||
@@ -612,6 +614,10 @@ static int _stream_init_loop(us_stream_s *stream) {
|
|||||||
goto offline_and_retry;
|
goto offline_and_retry;
|
||||||
|
|
||||||
offline_and_retry:
|
offline_and_retry:
|
||||||
|
if (stream->exit_on_device_error) {
|
||||||
|
US_LOG_INFO("Device error, exiting ...");
|
||||||
|
us_process_suicide();
|
||||||
|
}
|
||||||
for (uint count = 0; count < stream->error_delay * 10; ++count) {
|
for (uint count = 0; count < stream->error_delay * 10; ++count) {
|
||||||
if (atomic_load(&run->stop)) {
|
if (atomic_load(&run->stop)) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ typedef struct {
|
|||||||
bool notify_parent;
|
bool notify_parent;
|
||||||
bool slowdown;
|
bool slowdown;
|
||||||
uint error_delay;
|
uint error_delay;
|
||||||
|
bool exit_on_device_error;
|
||||||
uint exit_on_no_clients;
|
uint exit_on_no_clients;
|
||||||
|
|
||||||
us_memsink_s *jpeg_sink;
|
us_memsink_s *jpeg_sink;
|
||||||
|
|||||||
Reference in New Issue
Block a user