mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-20 00:36:30 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c751e4ff08 | ||
|
|
99a00ca57c | ||
|
|
c009a7efe4 | ||
|
|
291d7431b0 | ||
|
|
a1cd490fdf | ||
|
|
7a85774085 | ||
|
|
2ed3c4815b | ||
|
|
724c6e118f | ||
|
|
da3a3adc65 | ||
|
|
32013a6360 | ||
|
|
16a2495766 |
@@ -1,7 +1,7 @@
|
||||
[bumpversion]
|
||||
commit = True
|
||||
tag = True
|
||||
current_version = 0.78
|
||||
current_version = 0.79
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)?
|
||||
serialize =
|
||||
{major}.{minor}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
pkgname=ustreamer
|
||||
pkgver=0.78
|
||||
pkgver=0.79
|
||||
pkgrel=1
|
||||
pkgdesc="Lightweight and fast MJPG-HTTP streamer"
|
||||
url="https://github.com/pi-kvm/ustreamer"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ustreamer
|
||||
PKG_VERSION:=0.78
|
||||
PKG_VERSION:=0.79
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||
|
||||
|
||||
@@ -23,5 +23,5 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef VERSION
|
||||
# define VERSION "0.78"
|
||||
# define VERSION "0.79"
|
||||
#endif
|
||||
|
||||
29
src/device.c
29
src/device.c
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "device.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
@@ -37,7 +39,6 @@
|
||||
#include "tools.h"
|
||||
#include "logging.h"
|
||||
#include "xioctl.h"
|
||||
#include "device.h"
|
||||
|
||||
|
||||
static const struct {
|
||||
@@ -82,7 +83,7 @@ static const char *_format_to_string_supported(unsigned format);
|
||||
static const char *_standard_to_string(v4l2_std_id standard);
|
||||
|
||||
|
||||
struct device_t *device_init() {
|
||||
struct device_t *device_init(void) {
|
||||
struct controls_t *ctl;
|
||||
struct device_runtime_t *run;
|
||||
struct device_t *dev;
|
||||
@@ -279,9 +280,9 @@ int device_grab_buffer(struct device_t *dev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Got a new frame in buffer index=%u; bytesused=%u", 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=%u; nbuffers=%u", 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;
|
||||
}
|
||||
|
||||
@@ -384,24 +385,22 @@ static int _device_open_dv_timings(struct device_t *dev) {
|
||||
}
|
||||
|
||||
static int _device_apply_dv_timings(struct device_t *dev) {
|
||||
struct v4l2_dv_timings dv_timings;
|
||||
struct v4l2_dv_timings dv;
|
||||
|
||||
MEMSET_ZERO(dv_timings);
|
||||
MEMSET_ZERO(dv);
|
||||
|
||||
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=%ux%u; pixclk=%llu",
|
||||
dv_timings.bt.width,
|
||||
dv_timings.bt.height,
|
||||
dv_timings.bt.pixelclock);
|
||||
if (xioctl(dev->run->fd, VIDIOC_QUERY_DV_TIMINGS, &dv) == 0) {
|
||||
LOG_INFO("Got new DV timings: resolution=%ux%u, pixclk=%llu",
|
||||
dv.bt.width, dv.bt.height, dv.bt.pixelclock);
|
||||
|
||||
LOG_DEBUG("Calling ioctl(VIDIOC_S_DV_TIMINGS) ...");
|
||||
if (xioctl(dev->run->fd, VIDIOC_S_DV_TIMINGS, &dv_timings) < 0) {
|
||||
if (xioctl(dev->run->fd, VIDIOC_S_DV_TIMINGS, &dv) < 0) {
|
||||
LOG_PERROR("Failed to set DV timings");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_device_apply_resolution(dev, dv_timings.bt.width, dv_timings.bt.height) < 0) {
|
||||
if (_device_apply_resolution(dev, dv.bt.width, dv.bt.height) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -431,7 +430,7 @@ static int _device_open_format(struct device_t *dev) {
|
||||
// Set format
|
||||
LOG_DEBUG("Calling ioctl(VIDIOC_S_FMT) ...");
|
||||
if (xioctl(dev->run->fd, VIDIOC_S_FMT, &fmt) < 0) {
|
||||
LOG_PERROR("Unable to set pixelformat=%s; resolution=%ux%u",
|
||||
LOG_PERROR("Unable to set pixelformat=%s, resolution=%ux%u",
|
||||
_format_to_string_supported(dev->format),
|
||||
dev->run->width,
|
||||
dev->run->height);
|
||||
@@ -602,7 +601,7 @@ static int _device_apply_resolution(struct device_t *dev, unsigned width, unsign
|
||||
width == 0 || width > VIDEO_MAX_WIDTH
|
||||
|| height == 0 || height > VIDEO_MAX_HEIGHT
|
||||
) {
|
||||
LOG_ERROR("Requested forbidden resolution=%ux%u: min=1x1; max=%ux%u",
|
||||
LOG_ERROR("Requested forbidden resolution=%ux%u: min=1x1, max=%ux%u",
|
||||
width, height, VIDEO_MAX_WIDTH, VIDEO_MAX_HEIGHT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ struct device_t {
|
||||
};
|
||||
|
||||
|
||||
struct device_t *device_init();
|
||||
struct device_t *device_init(void);
|
||||
void device_destroy(struct device_t *dev);
|
||||
|
||||
int device_parse_format(const char *str);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "encoder.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <strings.h>
|
||||
#include <assert.h>
|
||||
@@ -29,7 +31,6 @@
|
||||
#include "tools.h"
|
||||
#include "logging.h"
|
||||
#include "device.h"
|
||||
#include "encoder.h"
|
||||
|
||||
#include "encoders/cpu/encoder.h"
|
||||
#include "encoders/hw/encoder.h"
|
||||
@@ -51,7 +52,7 @@ static const struct {
|
||||
};
|
||||
|
||||
|
||||
struct encoder_t *encoder_init() {
|
||||
struct encoder_t *encoder_init(void) {
|
||||
struct encoder_runtime_t *run;
|
||||
struct encoder_t *encoder;
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ struct encoder_t {
|
||||
};
|
||||
|
||||
|
||||
struct encoder_t *encoder_init();
|
||||
struct encoder_t *encoder_init(void);
|
||||
void encoder_destroy(struct encoder_t *encoder);
|
||||
|
||||
enum encoder_type_t encoder_parse_type(const char *str);
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "encoder.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -36,8 +38,6 @@
|
||||
#include "../../tools.h"
|
||||
#include "../../device.h"
|
||||
|
||||
#include "encoder.h"
|
||||
|
||||
|
||||
struct _jpeg_dest_manager_t {
|
||||
struct jpeg_destination_mgr mgr; // Default manager
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "encoder.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
@@ -37,7 +39,6 @@
|
||||
#include "../../device.h"
|
||||
|
||||
#include "huffman.h"
|
||||
#include "encoder.h"
|
||||
|
||||
|
||||
static bool _is_huffman(const unsigned char *data);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "component.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <IL/OMX_Core.h>
|
||||
@@ -28,7 +30,6 @@
|
||||
#include "../../logging.h"
|
||||
|
||||
#include "formatters.h"
|
||||
#include "component.h"
|
||||
|
||||
|
||||
static int _component_wait_port_changed(OMX_HANDLETYPE *component, OMX_U32 port, OMX_BOOL enabled);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "encoder.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -39,7 +41,6 @@
|
||||
|
||||
#include "formatters.h"
|
||||
#include "component.h"
|
||||
#include "encoder.h"
|
||||
|
||||
|
||||
static const OMX_U32 _INPUT_PORT = 340;
|
||||
@@ -69,7 +70,7 @@ static OMX_ERRORTYPE _omx_output_available_handler(
|
||||
OMX_PTR v_omx, UNUSED OMX_BUFFERHEADERTYPE *buffer);
|
||||
|
||||
|
||||
struct omx_encoder_t *omx_encoder_init() {
|
||||
struct omx_encoder_t *omx_encoder_init(void) {
|
||||
// Some theory:
|
||||
// - http://www.fourcc.org/yuv.php
|
||||
// - https://kwasi-ich.de/blog/2017/11/26/omx/
|
||||
|
||||
@@ -50,7 +50,7 @@ struct omx_encoder_t {
|
||||
};
|
||||
|
||||
|
||||
struct omx_encoder_t *omx_encoder_init();
|
||||
struct omx_encoder_t *omx_encoder_init(void);
|
||||
void omx_encoder_destroy(struct omx_encoder_t *omx);
|
||||
|
||||
int omx_encoder_prepare(struct omx_encoder_t *omx, struct device_t *dev, unsigned quality);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "formatters.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -27,7 +29,6 @@
|
||||
#include <IL/OMX_Core.h>
|
||||
|
||||
#include "../../tools.h"
|
||||
#include "formatters.h"
|
||||
|
||||
|
||||
#define CASE_TO_STRING(_value) \
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../tools.h"
|
||||
#include "base64.h"
|
||||
|
||||
|
||||
static const char ENCODING_TABLE[] = {
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "blank.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
@@ -32,8 +34,6 @@
|
||||
|
||||
#include "data/blank_jpeg.h"
|
||||
|
||||
#include "blank.h"
|
||||
|
||||
|
||||
struct _jpeg_error_manager_t {
|
||||
struct jpeg_error_mgr mgr; // Default manager
|
||||
@@ -41,7 +41,7 @@ struct _jpeg_error_manager_t {
|
||||
};
|
||||
|
||||
|
||||
static struct blank_t *_blank_init_internal();
|
||||
static struct blank_t *_blank_init_internal(void);
|
||||
static struct blank_t *_blank_init_external(const char *path);
|
||||
static int _jpeg_read_geometry(FILE *fp, unsigned *width, unsigned *height);
|
||||
static void _jpeg_error_handler(j_common_ptr jpeg);
|
||||
@@ -68,7 +68,7 @@ void blank_destroy(struct blank_t *blank) {
|
||||
free(blank);
|
||||
}
|
||||
|
||||
static struct blank_t *_blank_init_internal() {
|
||||
static struct blank_t *_blank_init_internal(void) {
|
||||
struct blank_t *blank;
|
||||
|
||||
A_CALLOC(blank, 1);
|
||||
|
||||
@@ -20,14 +20,14 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "mime.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <event2/util.h>
|
||||
|
||||
#include "../tools.h"
|
||||
|
||||
#include "mime.h"
|
||||
|
||||
|
||||
static const struct {
|
||||
const char *ext;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "path.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -27,8 +29,6 @@
|
||||
|
||||
#include "../tools.h"
|
||||
|
||||
#include "path.h"
|
||||
|
||||
|
||||
char *simplify_request_path(const char *str) {
|
||||
// Based on Lighttpd sources:
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "server.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
@@ -56,7 +58,6 @@
|
||||
#include "base64.h"
|
||||
#include "mime.h"
|
||||
#include "static.h"
|
||||
#include "server.h"
|
||||
|
||||
#include "data/index_html.h"
|
||||
|
||||
@@ -208,7 +209,7 @@ int http_server_listen(struct http_server_t *server) {
|
||||
# define MAX_SUN_PATH (sizeof(unix_addr.sun_path) - 1)
|
||||
|
||||
if (strlen(server->unix_path) > MAX_SUN_PATH) {
|
||||
LOG_ERROR("UNIX socket path is too long, max=%zu", MAX_SUN_PATH);
|
||||
LOG_ERROR("UNIX socket path is too long; max=%zu", MAX_SUN_PATH);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -568,7 +569,7 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server
|
||||
}
|
||||
|
||||
evhttp_connection_get_peer(conn, &client_addr, &client_port);
|
||||
LOG_INFO("HTTP: Registered the new stream client: [%s]:%u; id=%s; clients now: %u",
|
||||
LOG_INFO("HTTP: Registered the new stream client: [%s]:%u, id=%s; clients now: %u",
|
||||
client_addr, client_port, client->id, server->run->stream_clients_count);
|
||||
|
||||
buf_event = evhttp_connection_get_bufferevent(conn);
|
||||
@@ -845,13 +846,13 @@ static bool _expose_new_picture_unsafe(struct http_server_t *server) {
|
||||
) {
|
||||
EXPOSED(expose_cmp_time) = get_now_monotonic();
|
||||
EXPOSED(expose_end_time) = EXPOSED(expose_cmp_time);
|
||||
LOG_VERBOSE("HTTP: dropped same frame number %u; comparsion time = %.06Lf",
|
||||
LOG_VERBOSE("HTTP: dropped same frame number %u; cmp_time=%.06Lf",
|
||||
EXPOSED(dropped), EXPOSED(expose_cmp_time) - EXPOSED(expose_begin_time));
|
||||
EXPOSED(dropped) += 1;
|
||||
return false; // Not updated
|
||||
} else {
|
||||
EXPOSED(expose_cmp_time) = get_now_monotonic();
|
||||
LOG_VERBOSE("HTTP: passed same frame check (frames are differ); comparsion time = %.06Lf",
|
||||
LOG_VERBOSE("HTTP: passed same frame check (frames are differ); cmp_time=%.06Lf",
|
||||
EXPOSED(expose_cmp_time) - EXPOSED(expose_begin_time));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "static.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -32,7 +34,6 @@
|
||||
#include "../logging.h"
|
||||
|
||||
#include "path.h"
|
||||
#include "static.h"
|
||||
|
||||
|
||||
char *find_static_file_path(const char *root_path, const char *request_path) {
|
||||
|
||||
@@ -203,7 +203,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
# define OPT_UNSIGNED(_dest, _name, _min, _max) { \
|
||||
errno = 0; char *_end = NULL; int _tmp = strtol(optarg, &_end, 0); \
|
||||
if (errno || *_end || _tmp < _min || _tmp > _max) { \
|
||||
printf("Invalid value for '%s=%s'; min=%u; max=%u\n", _name, optarg, _min, _max); \
|
||||
printf("Invalid value for '%s=%s': min=%u, max=%u\n", _name, optarg, _min, _max); \
|
||||
return -1; \
|
||||
} \
|
||||
_dest = _tmp; \
|
||||
@@ -327,7 +327,7 @@ struct main_context_t {
|
||||
|
||||
static struct main_context_t *_ctx;
|
||||
|
||||
static void _block_thread_signals() {
|
||||
static void _block_thread_signals(void) {
|
||||
sigset_t mask;
|
||||
assert(!sigemptyset(&mask));
|
||||
assert(!sigaddset(&mask, SIGINT));
|
||||
@@ -353,7 +353,7 @@ static void _signal_handler(int signum) {
|
||||
http_server_loop_break(_ctx->server);
|
||||
}
|
||||
|
||||
static void _install_signal_handlers() {
|
||||
static void _install_signal_handlers(void) {
|
||||
struct sigaction sig_act;
|
||||
|
||||
MEMSET_ZERO(sig_act);
|
||||
|
||||
61
src/stream.c
61
src/stream.c
@@ -20,6 +20,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <unistd.h>
|
||||
@@ -36,7 +38,6 @@
|
||||
#include "xioctl.h"
|
||||
#include "device.h"
|
||||
#include "encoder.h"
|
||||
#include "stream.h"
|
||||
|
||||
#ifdef WITH_WORKERS_GPIO_DEBUG
|
||||
# include <wiringPi.h>
|
||||
@@ -52,7 +53,6 @@ struct _worker_t {
|
||||
atomic_bool *proc_stop;
|
||||
atomic_bool *workers_stop;
|
||||
|
||||
pthread_mutex_t last_comp_time_mutex;
|
||||
long double last_comp_time;
|
||||
|
||||
pthread_mutex_t has_job_mutex;
|
||||
@@ -80,6 +80,8 @@ struct _workers_pool_t {
|
||||
struct _worker_t *oldest_worker;
|
||||
struct _worker_t *latest_worker;
|
||||
|
||||
long double approx_comp_time;
|
||||
|
||||
pthread_mutex_t free_workers_mutex;
|
||||
unsigned free_workers;
|
||||
pthread_cond_t free_workers_cond;
|
||||
@@ -101,7 +103,7 @@ static void *__worker_thread(void *v_worker);
|
||||
|
||||
static struct _worker_t *_workers_pool_wait(struct _workers_pool_t *pool);
|
||||
static void _workers_pool_assign(struct _workers_pool_t *pool, struct _worker_t *ready_worker, unsigned buf_index);
|
||||
static long double _workers_pool_get_fluency_delay(struct _workers_pool_t *pool);
|
||||
static long double _workers_pool_get_fluency_delay(struct _workers_pool_t *pool, struct _worker_t *ready_worker);
|
||||
|
||||
|
||||
struct stream_t *stream_init(struct device_t *dev, struct encoder_t *encoder) {
|
||||
@@ -157,9 +159,9 @@ void stream_loop(struct stream_t *stream) {
|
||||
if (!ready_worker->job_failed) {
|
||||
if (ready_worker->job_timely) {
|
||||
_stream_expose_picture(stream, ready_worker->buf_index, captured_fps);
|
||||
LOG_PERF("##### Encoded picture exposed; worker = %u", ready_worker->number);
|
||||
LOG_PERF("##### Encoded picture exposed; worker=%u", ready_worker->number);
|
||||
} else {
|
||||
LOG_PERF("----- Encoded picture dropped; worker = %u", ready_worker->number);
|
||||
LOG_PERF("----- Encoded picture dropped; worker=%u", ready_worker->number);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
@@ -224,7 +226,7 @@ void stream_loop(struct stream_t *stream) {
|
||||
{
|
||||
if (now < grab_after) {
|
||||
fluency_passed += 1;
|
||||
LOG_VERBOSE("Passed %u frames for fluency: now=%.03Lf; grab_after=%.03Lf", fluency_passed, now, grab_after);
|
||||
LOG_VERBOSE("Passed %u frames for fluency: now=%.03Lf, grab_after=%.03Lf", fluency_passed, now, grab_after);
|
||||
goto pass_frame;
|
||||
}
|
||||
fluency_passed = 0;
|
||||
@@ -233,14 +235,14 @@ void stream_loop(struct stream_t *stream) {
|
||||
captured_fps = captured_fps_accum;
|
||||
captured_fps_accum = 0;
|
||||
captured_fps_second = now_second;
|
||||
LOG_PERF("A new second has come, Captured-FPS = %u", captured_fps);
|
||||
LOG_PERF("A new second has come; captured_fps=%u", captured_fps);
|
||||
}
|
||||
captured_fps_accum += 1;
|
||||
|
||||
long double fluency_delay = _workers_pool_get_fluency_delay(pool);
|
||||
long double fluency_delay = _workers_pool_get_fluency_delay(pool, ready_worker);
|
||||
|
||||
grab_after = now + fluency_delay;
|
||||
LOG_VERBOSE("Fluency: delay=%.03Lf; grab_after=%.03Lf", fluency_delay, grab_after);
|
||||
LOG_VERBOSE("Fluency: delay=%.03Lf, grab_after=%.03Lf", fluency_delay, grab_after);
|
||||
}
|
||||
|
||||
_workers_pool_assign(pool, ready_worker, buf_index);
|
||||
@@ -295,7 +297,7 @@ void stream_switch_slowdown(struct stream_t *stream, bool slowdown) {
|
||||
static struct _workers_pool_t *_stream_init_loop(struct stream_t *stream) {
|
||||
struct _workers_pool_t *pool = NULL;
|
||||
|
||||
LOG_DEBUG("%s: stream->proc->stop = %d", __FUNCTION__, atomic_load(&stream->proc->stop));
|
||||
LOG_DEBUG("%s: stream->proc->stop=%d", __FUNCTION__, atomic_load(&stream->proc->stop));
|
||||
|
||||
while (!atomic_load(&stream->proc->stop)) {
|
||||
SEP_INFO('=');
|
||||
@@ -461,14 +463,10 @@ static void *__worker_thread(void *v_worker) {
|
||||
worker->job_start_time = PICTURE(encode_begin_time);
|
||||
atomic_store(&worker->has_job, false);
|
||||
|
||||
long double last_comp_time = PICTURE(encode_end_time) - worker->job_start_time;
|
||||
worker->last_comp_time = PICTURE(encode_end_time) - worker->job_start_time;
|
||||
|
||||
A_MUTEX_LOCK(&worker->last_comp_time_mutex);
|
||||
worker->last_comp_time = last_comp_time;
|
||||
A_MUTEX_UNLOCK(&worker->last_comp_time_mutex);
|
||||
|
||||
LOG_VERBOSE("Compressed JPEG size=%zu; time=%0.3Lf; worker=%u; buffer=%u",
|
||||
PICTURE(used), last_comp_time, worker->number, worker->buf_index);
|
||||
LOG_VERBOSE("Compressed new JPEG: size=%zu, time=%0.3Lf, worker=%u, buffer=%u",
|
||||
PICTURE(used), worker->last_comp_time, worker->number, worker->buf_index);
|
||||
} else {
|
||||
worker->job_failed = true;
|
||||
atomic_store(&worker->has_job, false);
|
||||
@@ -547,33 +545,22 @@ static void _workers_pool_assign(struct _workers_pool_t *pool, struct _worker_t
|
||||
LOG_DEBUG("Assigned new frame in buffer %u to worker %u", buf_index, ready_worker->number);
|
||||
}
|
||||
|
||||
static long double _workers_pool_get_fluency_delay(struct _workers_pool_t *pool) {
|
||||
long double sum_comp_time = 0;
|
||||
long double avg_comp_time;
|
||||
static long double _workers_pool_get_fluency_delay(struct _workers_pool_t *pool, struct _worker_t *ready_worker) {
|
||||
long double approx_comp_time;
|
||||
long double min_delay;
|
||||
long double soft_delay;
|
||||
|
||||
for (unsigned number = 0; number < pool->n_workers; ++number) {
|
||||
# define WORKER(_next) pool->workers[number]._next
|
||||
approx_comp_time = pool->approx_comp_time * 0.9 + ready_worker->last_comp_time * 0.1;
|
||||
|
||||
A_MUTEX_LOCK(&WORKER(last_comp_time_mutex));
|
||||
if (WORKER(last_comp_time) > 0) {
|
||||
sum_comp_time += WORKER(last_comp_time);
|
||||
}
|
||||
A_MUTEX_UNLOCK(&WORKER(last_comp_time_mutex));
|
||||
LOG_VERBOSE("Correcting approx_comp_time: %.3Lf -> %.3Lf (last_comp_time=%.3Lf)",
|
||||
pool->approx_comp_time, approx_comp_time, ready_worker->last_comp_time);
|
||||
|
||||
# undef WORKER
|
||||
}
|
||||
pool->approx_comp_time = approx_comp_time;
|
||||
|
||||
avg_comp_time = sum_comp_time / pool->n_workers; // Среднее время работы воркеров
|
||||
min_delay = pool->approx_comp_time / pool->n_workers; // Среднее время работы размазывается на N воркеров
|
||||
|
||||
min_delay = avg_comp_time / pool->n_workers; // Среднее время работы размазывается на N воркеров
|
||||
|
||||
if (pool->desired_frames_interval > 0 && min_delay > 0) {
|
||||
if (pool->desired_frames_interval > 0 && min_delay > 0 && pool->desired_frames_interval > min_delay) {
|
||||
// Искусственное время задержки на основе желаемого FPS, если включен --desired-fps
|
||||
soft_delay = pool->desired_frames_interval - sum_comp_time;
|
||||
return (min_delay > soft_delay ? min_delay : soft_delay);
|
||||
return pool->desired_frames_interval;
|
||||
}
|
||||
|
||||
return min_delay;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ import textwrap
|
||||
|
||||
|
||||
# =====
|
||||
def get_prepend() -> str:
|
||||
return textwrap.dedent("""
|
||||
C_PREPEND = textwrap.dedent("""
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||
|
||||
@@ -29,7 +29,7 @@ import common
|
||||
|
||||
# =====
|
||||
def main() -> None:
|
||||
assert len(sys.argv) == 4, "%s <file.html> <file.h> <name>" % (sys.argv[0])
|
||||
assert len(sys.argv) == 4, f"{sys.argv[0]} <file.html> <file.h> <name>"
|
||||
html_path = sys.argv[1]
|
||||
header_path = sys.argv[2]
|
||||
name = sys.argv[3]
|
||||
@@ -42,11 +42,11 @@ def main() -> None:
|
||||
text = text.replace("%VERSION%", "\" VERSION \"")
|
||||
text = textwrap.indent(text, "\t", (lambda line: True))
|
||||
text = "\n".join(
|
||||
("%s \\" if line.strip() else "%s\\") % (line)
|
||||
(f"{line} \\" if line.strip() else f"{line}\\")
|
||||
for line in text.split("\n")
|
||||
)
|
||||
text = "const char HTML_%s_PAGE[] = \" \\\n%s\n\";\n" % (name, text)
|
||||
text = common.get_prepend() + "\n#include \"../../config.h\"\n\n\n" + text
|
||||
text = f"const char HTML_{name}_PAGE[] = \" \\\n{text}\n\";\n"
|
||||
text = f"{common.C_PREPEND}\n#include \"../../config.h\"\n\n\n{text}"
|
||||
|
||||
with open(header_path, "w") as header_file:
|
||||
header_file.write(text)
|
||||
|
||||
@@ -60,7 +60,7 @@ def _get_jpeg_size(data: bytes) -> Tuple[int, int]:
|
||||
|
||||
# =====
|
||||
def main() -> None:
|
||||
assert len(sys.argv) == 4, "%s <file.jpeg> <file.h> <name>" % (sys.argv[0])
|
||||
assert len(sys.argv) == 4, f"{sys.argv[0]} <file.jpeg> <file.h> <name>"
|
||||
jpeg_path = sys.argv[1]
|
||||
header_path = sys.argv[2]
|
||||
name = sys.argv[3]
|
||||
@@ -74,13 +74,13 @@ def main() -> None:
|
||||
for ch in jpeg_data:
|
||||
if len(rows[-1]) > 20:
|
||||
rows.append([])
|
||||
rows[-1].append("0x%.2X" % (ch))
|
||||
rows[-1].append(f"0x{ch:02X}")
|
||||
|
||||
text = ",\n\t".join(", ".join(row) for row in rows)
|
||||
text = "const unsigned char %s_JPEG_DATA[] = {\n\t%s\n};\n" % (name, text)
|
||||
text = "const unsigned %s_JPEG_HEIGHT = %d;\n\n" % (name, height) + text
|
||||
text = "const unsigned %s_JPEG_WIDTH = %d;\n" % (name, width) + text
|
||||
text = common.get_prepend() + "\n\n" + text
|
||||
text = f"const unsigned char {name}_JPEG_DATA[] = {{\n\t{text}\n}};\n"
|
||||
text = f"const unsigned {name}_JPEG_HEIGHT = {height};\n\n{text}"
|
||||
text = f"const unsigned {name}_JPEG_WIDTH = {width};\n{text}"
|
||||
text = f"{common.C_PREPEND}\n\n{text}"
|
||||
|
||||
with open(header_path, "w") as header_file:
|
||||
header_file.write(text)
|
||||
|
||||
Reference in New Issue
Block a user