mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-20 16:56:30 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6029408564 | ||
|
|
8734834341 | ||
|
|
809f86955d | ||
|
|
2f557617d8 | ||
|
|
35c8196103 | ||
|
|
c71df1bb25 | ||
|
|
bc107d2870 | ||
|
|
294ed36b8f |
@@ -1,7 +1,7 @@
|
||||
[bumpversion]
|
||||
commit = True
|
||||
tag = True
|
||||
current_version = 0.16
|
||||
current_version = 0.17
|
||||
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.16
|
||||
pkgver=0.17
|
||||
pkgrel=1
|
||||
pkgdesc="Lightweight and fast MJPG-HTTP streamer"
|
||||
url="https://github.com/pi-kvm/ustreamer"
|
||||
|
||||
@@ -21,4 +21,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define VERSION "0.16"
|
||||
#define VERSION "0.17"
|
||||
|
||||
@@ -131,7 +131,7 @@ void encoder_prepare_for_device(struct encoder_t *encoder, struct device_t *dev)
|
||||
int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, const unsigned index) {
|
||||
assert(encoder->type != ENCODER_TYPE_UNKNOWN);
|
||||
|
||||
dev->run->pictures[index].encode_begin_time = now_monotonic_ms();
|
||||
dev->run->pictures[index].encode_begin_time = get_now_monotonic();
|
||||
|
||||
if (encoder->type == ENCODER_TYPE_CPU) {
|
||||
jpeg_encoder_compress_buffer(dev, index, encoder->quality);
|
||||
@@ -144,7 +144,7 @@ int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, con
|
||||
}
|
||||
# endif
|
||||
|
||||
dev->run->pictures[index].encode_end_time = now_monotonic_ms();
|
||||
dev->run->pictures[index].encode_end_time = get_now_monotonic();
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
72
src/http.c
72
src/http.c
@@ -174,10 +174,14 @@ static void _http_callback_ping(struct evhttp_request *request, void *v_server)
|
||||
assert(evbuffer_add_printf(buf,
|
||||
"{\"stream\": {\"resolution\":"
|
||||
" {\"width\": %u, \"height\": %u},"
|
||||
" \"fps\": %u, \"online\": %s}}",
|
||||
" \"fps\": %u, \"eps\": %u,"
|
||||
" \"online\": %s, \"clients\": %u}}",
|
||||
(server->fake_width ? server->fake_width : server->run->exposed->width),
|
||||
(server->fake_height ? server->fake_height : server->run->exposed->height),
|
||||
server->run->exposed->fps, (server->run->exposed->online ? "true" : "false")
|
||||
server->run->exposed->fps, // frame per second (capturing)
|
||||
server->run->exposed->eps, // expose per second (server)
|
||||
(server->run->exposed->online ? "true" : "false"),
|
||||
server->run->stream_clients_count
|
||||
));
|
||||
ADD_HEADER("Content-Type", "application/json");
|
||||
evhttp_send_reply(request, HTTP_OK, "OK", buf);
|
||||
@@ -204,16 +208,16 @@ static void _http_callback_snapshot(struct evhttp_request *request, void *v_serv
|
||||
# define ADD_TIME_HEADER(_key, _value) \
|
||||
{ sprintf(time_buf, "%.06Lf", _value); ADD_HEADER(_key, time_buf); }
|
||||
|
||||
ADD_TIME_HEADER("X-Timestamp", now_real_ms());
|
||||
ADD_TIME_HEADER("X-Timestamp", get_now_real());
|
||||
|
||||
if (server->add_x_timings) {
|
||||
ADD_TIME_HEADER("X-UStreamer-Grab-Time", EXPOSED(picture.grab_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Encode-Begin-Time", EXPOSED(picture.encode_begin_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Encode-End-Time", EXPOSED(picture.encode_end_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Expose-Begin-Time", EXPOSED(expose_begin_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Expose-End-Time", EXPOSED(expose_end_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Send-Time", now_monotonic_ms());
|
||||
}
|
||||
ADD_HEADER("X-UStreamer-Online", (EXPOSED(online) ? "true" : "false"));
|
||||
ADD_TIME_HEADER("X-UStreamer-Grab-Time", EXPOSED(picture.grab_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Encode-Begin-Time", EXPOSED(picture.encode_begin_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Encode-End-Time", EXPOSED(picture.encode_end_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Expose-Begin-Time", EXPOSED(expose_begin_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Expose-Cmp-Time", EXPOSED(expose_cmp_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Expose-End-Time", EXPOSED(expose_end_time));
|
||||
ADD_TIME_HEADER("X-UStreamer-Send-Time", get_now_monotonic());
|
||||
|
||||
# undef ADD_TIME_HEADER
|
||||
|
||||
@@ -310,23 +314,27 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
|
||||
"X-Timestamp: %.06Lf" RN
|
||||
"%s",
|
||||
EXPOSED(picture.size) * sizeof(*EXPOSED(picture.data)),
|
||||
now_real_ms(), (client->server->add_x_timings ? "" : RN)
|
||||
get_now_real(), (client->server->extra_stream_headers ? "" : RN)
|
||||
));
|
||||
if (client->server->add_x_timings) {
|
||||
if (client->server->extra_stream_headers) {
|
||||
assert(evbuffer_add_printf(buf,
|
||||
"X-UStreamer-Online: %s" RN
|
||||
"X-UStreamer-Grab-Time: %.06Lf" RN
|
||||
"X-UStreamer-Encode-Begin-Time: %.06Lf" RN
|
||||
"X-UStreamer-Encode-End-Time: %.06Lf" RN
|
||||
"X-UStreamer-Expose-Begin-Time: %.06Lf" RN
|
||||
"X-UStreamer-Expose-Cmp-Time: %.06Lf" RN
|
||||
"X-UStreamer-Expose-End-Time: %.06Lf" RN
|
||||
"X-UStreamer-Send-Time: %.06Lf" RN
|
||||
RN,
|
||||
(EXPOSED(online) ? "true" : "false"),
|
||||
EXPOSED(picture.grab_time),
|
||||
EXPOSED(picture.encode_begin_time),
|
||||
EXPOSED(picture.encode_end_time),
|
||||
EXPOSED(expose_begin_time),
|
||||
EXPOSED(expose_cmp_time),
|
||||
EXPOSED(expose_end_time),
|
||||
now_monotonic_ms()
|
||||
get_now_monotonic()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -398,6 +406,9 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
|
||||
struct http_server_t *server = (struct http_server_t *)v_server;
|
||||
bool updated = false;
|
||||
bool queue_send = false;
|
||||
long long now;
|
||||
static unsigned eps = 0;
|
||||
static long long eps_second = 0;
|
||||
|
||||
#define LOCK_STREAM \
|
||||
A_PTHREAD_M_LOCK(&server->run->stream->mutex);
|
||||
@@ -423,6 +434,13 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
|
||||
}
|
||||
|
||||
if (queue_send) {
|
||||
if ((now = floor_ms(get_now_monotonic())) != eps_second) {
|
||||
server->run->exposed->eps = eps;
|
||||
eps = 0;
|
||||
eps_second = now;
|
||||
}
|
||||
eps += 1;
|
||||
|
||||
_http_queue_send_stream(server, updated);
|
||||
}
|
||||
|
||||
@@ -436,7 +454,7 @@ static bool _expose_new_picture(struct http_server_t *server) {
|
||||
|
||||
assert(STREAM(picture.size) > 0);
|
||||
EXPOSED(fps) = STREAM(fps);
|
||||
EXPOSED(expose_begin_time) = now_monotonic_ms();
|
||||
EXPOSED(expose_begin_time) = get_now_monotonic();
|
||||
|
||||
# define MEM_STREAM_TO_EXPOSED \
|
||||
EXPOSED(picture.data), STREAM(picture.data), \
|
||||
@@ -449,10 +467,20 @@ static bool _expose_new_picture(struct http_server_t *server) {
|
||||
&& EXPOSED(picture.size) == STREAM(picture.size)
|
||||
&& !memcmp(MEM_STREAM_TO_EXPOSED)
|
||||
) {
|
||||
LOG_PERF("HTTP: dropped same frame number %u", EXPOSED(dropped));
|
||||
EXPOSED(expose_cmp_time) = get_now_monotonic();
|
||||
EXPOSED(expose_end_time) = EXPOSED(expose_cmp_time);
|
||||
LOG_PERF(
|
||||
"HTTP: dropped same frame number %u; comparsion time = %.06Lf",
|
||||
EXPOSED(dropped), EXPOSED(expose_cmp_time) - EXPOSED(expose_begin_time)
|
||||
);
|
||||
EXPOSED(dropped) += 1;
|
||||
EXPOSED(expose_end_time) = now_monotonic_ms();
|
||||
return false; // Not updated
|
||||
} else {
|
||||
EXPOSED(expose_cmp_time) = get_now_monotonic();
|
||||
LOG_PERF(
|
||||
"HTTP: passed same frame check (frames are differ); comparsion time = %.06Lf",
|
||||
EXPOSED(expose_cmp_time) - EXPOSED(expose_begin_time)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,7 +503,8 @@ static bool _expose_new_picture(struct http_server_t *server) {
|
||||
EXPOSED(height) = STREAM(height);
|
||||
EXPOSED(online) = true;
|
||||
EXPOSED(dropped) = 0;
|
||||
EXPOSED(expose_end_time) = now_monotonic_ms();
|
||||
EXPOSED(expose_cmp_time) = EXPOSED(expose_begin_time);
|
||||
EXPOSED(expose_end_time) = get_now_monotonic();
|
||||
|
||||
# undef STREAM
|
||||
# undef EXPOSED
|
||||
@@ -485,7 +514,8 @@ static bool _expose_new_picture(struct http_server_t *server) {
|
||||
static bool _expose_blank_picture(struct http_server_t *server) {
|
||||
# define EXPOSED(_next) server->run->exposed->_next
|
||||
|
||||
EXPOSED(expose_begin_time) = now_monotonic_ms();
|
||||
EXPOSED(expose_begin_time) = get_now_monotonic();
|
||||
EXPOSED(expose_cmp_time) = EXPOSED(expose_begin_time);
|
||||
|
||||
if (EXPOSED(online) || EXPOSED(picture.size) == 0) {
|
||||
if (EXPOSED(picture.allocated) < BLANK_JPG_SIZE) {
|
||||
@@ -514,13 +544,13 @@ static bool _expose_blank_picture(struct http_server_t *server) {
|
||||
if (EXPOSED(dropped) < server->run->drop_same_frames_blank) {
|
||||
LOG_PERF("HTTP: dropped same frame (BLANK) number %u", EXPOSED(dropped));
|
||||
EXPOSED(dropped) += 1;
|
||||
EXPOSED(expose_end_time) = now_monotonic_ms();
|
||||
EXPOSED(expose_end_time) = get_now_monotonic();
|
||||
return false; // Not updated
|
||||
}
|
||||
|
||||
updated:
|
||||
EXPOSED(dropped) = 0;
|
||||
EXPOSED(expose_end_time) = now_monotonic_ms();
|
||||
EXPOSED(expose_end_time) = get_now_monotonic();
|
||||
return true; // Updated
|
||||
|
||||
# undef EXPOSED
|
||||
|
||||
@@ -45,7 +45,9 @@ struct exposed_t {
|
||||
unsigned fps;
|
||||
bool online;
|
||||
unsigned dropped;
|
||||
unsigned eps;
|
||||
long double expose_begin_time;
|
||||
long double expose_cmp_time;
|
||||
long double expose_end_time;
|
||||
};
|
||||
|
||||
@@ -64,7 +66,7 @@ struct http_server_t {
|
||||
char *host;
|
||||
unsigned port;
|
||||
unsigned drop_same_frames;
|
||||
bool add_x_timings;
|
||||
bool extra_stream_headers;
|
||||
unsigned fake_width;
|
||||
unsigned fake_height;
|
||||
unsigned timeout;
|
||||
|
||||
@@ -71,7 +71,7 @@ pthread_mutex_t log_mutex;
|
||||
}
|
||||
|
||||
#define LOG_PRINTF_NOLOCK(_label, _msg, ...) { \
|
||||
printf("-- " _label " [%.03Lf tid=%ld] -- " _msg "\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__); \
|
||||
printf("-- " _label " [%.03Lf tid=%ld] -- " _msg "\n", get_now_monotonic(), syscall(SYS_gettid), ##__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ pthread_mutex_t log_mutex;
|
||||
char _buf[1024] = ""; \
|
||||
strerror_r(errno, _buf, 1024); \
|
||||
LOGGING_LOCK; \
|
||||
printf("-- ERROR [%.03Lf tid=%ld] -- " _msg ": %s\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__, _buf); \
|
||||
printf("-- ERROR [%.03Lf tid=%ld] -- " _msg ": %s\n", get_now_monotonic(), syscall(SYS_gettid), ##__VA_ARGS__, _buf); \
|
||||
fflush(stdout); \
|
||||
LOGGING_UNLOCK; \
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ static const struct option _long_opts[] = {
|
||||
{"host", required_argument, NULL, 's'},
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
{"drop-same-frames", required_argument, NULL, 'r'},
|
||||
{"add-x-timings", no_argument, NULL, 2000},
|
||||
{"extra-stream-headers", no_argument, NULL, 2000},
|
||||
{"fake-width", required_argument, NULL, 2001},
|
||||
{"fake-height", required_argument, NULL, 2002},
|
||||
{"server-timeout", required_argument, NULL, 2003},
|
||||
@@ -119,7 +119,7 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
|
||||
printf(" It can significantly reduce the outgoing traffic, but will increase\n");
|
||||
printf(" the CPU loading. Don't use this option with analog signal sources\n");
|
||||
printf(" or webcams, it's useless. Default: disabled.\n\n");
|
||||
printf(" --add-x-timings -- Add X-UStreamer-*-Time headers to the /stream and /snapshot handles.\n");
|
||||
printf(" --extra-stream-headers -- Add X-UStreamer-* headers to /stream handle (like /snapshot).\n");
|
||||
printf(" Default: disabled.\n\n");
|
||||
printf(" --fake-width <N> -- Override image width for /ping. Default: disabled\n\n");
|
||||
printf(" --fake-height <N> -- Override image height for /ping. Default: disabled.\n\n");
|
||||
@@ -182,7 +182,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
case 's': OPT_SET(server->host, optarg);
|
||||
case 'p': OPT_UNSIGNED(server->port, "--port", 1, 65535);
|
||||
case 'r': OPT_UNSIGNED(server->drop_same_frames, "--drop-same-frames", 0, 30);
|
||||
case 2000: OPT_SET(server->add_x_timings, true);
|
||||
case 2000: OPT_SET(server->extra_stream_headers, true);
|
||||
case 2001: OPT_UNSIGNED(server->fake_width, "--fake-width", 0, 1920);
|
||||
case 2002: OPT_UNSIGNED(server->fake_height, "--fake-height", 0, 1200);
|
||||
case 2003: OPT_UNSIGNED(server->timeout, "--server-timeout", 1, 60);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#define LOG_OMX_ERROR(_error, _msg, ...) { \
|
||||
LOGGING_LOCK; \
|
||||
printf("-- ERROR [%.03Lf tid=%ld] -- " _msg ": %s\n", now_monotonic_ms(), \
|
||||
printf("-- ERROR [%.03Lf tid=%ld] -- " _msg ": %s\n", get_now_monotonic(), \
|
||||
syscall(SYS_gettid), ##__VA_ARGS__, omx_error_to_string(_error)); \
|
||||
LOGGING_UNLOCK; \
|
||||
}
|
||||
|
||||
@@ -162,7 +162,8 @@ void stream_loop(struct stream_t *stream) {
|
||||
LOG_DEBUG("Frame is ready");
|
||||
|
||||
struct v4l2_buffer buf_info;
|
||||
long double now = now_monotonic_ms();
|
||||
long double now = get_now_monotonic();
|
||||
long long now_second = floor_ms(now);
|
||||
|
||||
if (_stream_grab_buffer(stream->dev, &buf_info) < 0) {
|
||||
break;
|
||||
@@ -196,11 +197,11 @@ void stream_loop(struct stream_t *stream) {
|
||||
}
|
||||
fluency_passed = 0;
|
||||
|
||||
if ((long long)now != fps_second) {
|
||||
if (now_second != fps_second) {
|
||||
LOG_PERF("Oldest worker complete, encoding FPS = %u", fps);
|
||||
stream->fps = fps;
|
||||
fps = 0;
|
||||
fps_second = (long long)now;
|
||||
fps_second = now_second;
|
||||
}
|
||||
fps += 1;
|
||||
|
||||
|
||||
14
src/tools.h
14
src/tools.h
@@ -61,7 +61,11 @@ INLINE unsigned max_u(unsigned a, unsigned b) {
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
INLINE void now_ms(clockid_t clk_id, time_t *sec, long *msec) {
|
||||
INLINE long long floor_ms(long double now) {
|
||||
return (long long) now - (now < (long long) now); // floor()
|
||||
}
|
||||
|
||||
INLINE void get_now(clockid_t clk_id, time_t *sec, long *msec) {
|
||||
struct timespec spec;
|
||||
|
||||
assert(!clock_gettime(clk_id, &spec));
|
||||
@@ -74,18 +78,18 @@ INLINE void now_ms(clockid_t clk_id, time_t *sec, long *msec) {
|
||||
}
|
||||
}
|
||||
|
||||
INLINE long double now_monotonic_ms(void) {
|
||||
INLINE long double get_now_monotonic(void) {
|
||||
time_t sec;
|
||||
long msec;
|
||||
|
||||
now_ms(CLOCK_MONOTONIC_RAW, &sec, &msec);
|
||||
get_now(CLOCK_MONOTONIC_RAW, &sec, &msec);
|
||||
return (long double)sec + ((long double)msec) / 1000;
|
||||
}
|
||||
|
||||
INLINE long double now_real_ms(void) {
|
||||
INLINE long double get_now_real(void) {
|
||||
time_t sec;
|
||||
long msec;
|
||||
|
||||
now_ms(CLOCK_REALTIME, &sec, &msec);
|
||||
get_now(CLOCK_REALTIME, &sec, &msec);
|
||||
return (long double)sec + ((long double)msec) / 1000;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user