Compare commits

...

3 Commits
v0.28 ... v0.29

Author SHA1 Message Date
Devaev Maxim
97b2183038 Bump version: 0.28 → 0.29 2018-11-05 04:39:31 +03:00
Devaev Maxim
2732482d36 refactoring, html fixes 2018-11-05 04:39:20 +03:00
Devaev Maxim
ca52f12378 stream fix for webkit 2018-11-05 04:09:13 +03:00
11 changed files with 94 additions and 45 deletions

View File

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

View File

@@ -29,8 +29,8 @@ install: $(PROG)
regen:
tools/make-jpeg-h.py src/data/blank.jpeg src/data/blank.h BLANK 640 480
tools/make-html-h.py src/data/index.html src/data/html_index.h HTML_INDEX_PAGE
tools/make-jpeg-h.py src/data/blank.jpeg src/data/blank_jpeg.h BLANK 640 480
tools/make-html-h.py src/data/index.html src/data/index_html.h HTML_INDEX_PAGE
$(PROG): $(OBJECTS)
@@ -57,7 +57,7 @@ push:
git push
git push --tags
clean-all: clean
clean:
rm -f src/*.o src/{jpeg,omx}/*.o vgcore.* $(PROG)
rm -rf pkg src/$(PROG)-* src/v*.tar.gz v*.tar.gz $(PROG)-*.pkg.tar.xz

View File

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

View File

@@ -21,4 +21,4 @@
#pragma once
#define VERSION "0.28"
#define VERSION "0.29"

View File

@@ -2,7 +2,7 @@
<html>
<head>
<meta charset=\"utf-8\">
<meta charset="utf-8" />
<title>uStreamer</title>
</head>
@@ -11,29 +11,36 @@
<hr>
<ul>
<li>
<a href=\"/ping\"><b>/ping</b></a><br>
<a href="/ping"><b><samp>/ping</samp></b></a><br>
Get JSON structure with state of the server.
</li>
<br>
<li>
<a href=\"/snapshot\"><b>/snapshot</b></a><br>
Get a current actual image from server.
<a href="/snapshot"><b><samp>/snapshot</samp></b></a><br>
Get a current actual image from the server.
</li>
<br>
<li>
<a href=\"/stream\"><b>/stream</b></a><br>
<a href="/stream"><b><samp>/stream</samp></b></a><br>
Get a live stream. Query params:<br>
<br>
<ul>
<li>
<i>extra_headers=1</i><br>
Add X-UStreamer-* headers to /stream handle (like on <a href=\"/snapshot\">/snapshot</a>).
<b><samp>extra_headers=1</samp></b><br>
Add <samp>X-UStreamer-*</samp> headers to /stream handle (like on <a href="/snapshot"><samp>/snapshot</samp></a>).
</li>
<br>
<li>
<i>advance_headers=1</i><br>
<b><samp>advance_headers=1</samp></b><br>
Enable workaround for Chromium/Blink
<a href=\"https://bugs.chromium.org/p/chromium/issues/detail?id=527446\">Bug #527446</a>.
<a href="https://bugs.chromium.org/p/chromium/issues/detail?id=527446">Bug #527446</a>.
</li>
<br>
<li>
<b><samp>dual_final_frames=1</samp></b><br>
Enable workaround for Safari/WebKit bug when using option <samp>--drop-same-frames</samp>.<br>
Without this option, when the frame series is completed, WebKit-based browsers<br>
renders the last one with a delay.
</li>
</ul>
</li>
@@ -41,6 +48,6 @@
</ul>
<br>
<hr>
<a href=\"https://github.com/pi-kvm/ustreamer\">Sources &amp; docs</a>
<a href="https://github.com/pi-kvm/ustreamer">Sources &amp; docs</a>
</body>
</html>

View File

@@ -29,7 +29,7 @@ const char *HTML_INDEX_PAGE = " \
\
<html> \
<head> \
<meta charset=\"utf-8\"> \
<meta charset=\"utf-8\" /> \
<title>uStreamer</title> \
</head> \
\
@@ -38,30 +38,37 @@ const char *HTML_INDEX_PAGE = " \
<hr> \
<ul> \
<li> \
<a href=\"/ping\"><b>/ping</b></a><br> \
<a href=\"/ping\"><b><samp>/ping</samp></b></a><br> \
Get JSON structure with state of the server. \
</li> \
<br> \
<li> \
<a href=\"/snapshot\"><b>/snapshot</b></a><br> \
Get a current actual image from server. \
<a href=\"/snapshot\"><b><samp>/snapshot</samp></b></a><br> \
Get a current actual image from the server. \
</li> \
<br> \
<li> \
<a href=\"/stream\"><b>/stream</b></a><br> \
<a href=\"/stream\"><b><samp>/stream</samp></b></a><br> \
Get a live stream. Query params:<br> \
<br> \
<ul> \
<li> \
<i>extra_headers=1</i><br> \
Add X-UStreamer-* headers to /stream handle (like on <a href=\"/snapshot\">/snapshot</a>). \
<b><samp>extra_headers=1</samp></b><br> \
Add <samp>X-UStreamer-*</samp> headers to /stream handle (like on <a href=\"/snapshot\"><samp>/snapshot</samp></a>). \
</li> \
<br> \
<li> \
<i>advance_headers=1</i><br> \
<b><samp>advance_headers=1</samp></b><br> \
Enable workaround for Chromium/Blink \
<a href=\"https://bugs.chromium.org/p/chromium/issues/detail?id=527446\">Bug #527446</a>. \
</li> \
<br> \
<li> \
<b><samp>dual_final_frames=1</samp></b><br> \
Enable workaround for Safari/WebKit bug when using option <samp>--drop-same-frames</samp>.<br> \
Without this option, when the frame series is completed, WebKit-based browsers<br> \
renders the last one with a delay. \
</li> \
</ul> \
</li> \
<br> \

View File

@@ -43,8 +43,8 @@
#include "stream.h"
#include "http.h"
#include "data/html_index.h"
#include "data/blank.h"
#include "data/index_html.h"
#include "data/blank_jpeg.h"
static bool _http_get_param_true(struct evkeyvalq *params, const char *key);
@@ -58,7 +58,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_exposed_refresh(int fd, short event, void *v_server);
static void _http_queue_send_stream(struct http_server_t *server, const bool updated);
static void _http_queue_send_stream(struct http_server_t *server, const bool stream_updated, const bool picture_updated);
static bool _expose_new_picture(struct http_server_t *server);
static bool _expose_blank_picture(struct http_server_t *server);
@@ -192,7 +192,7 @@ static void _http_callback_ping(struct evhttp_request *request, void *v_server)
" \"stream\": {\"queued_fps\": %u, \"clients\": %u, \"clients_stat\": {",
(server->fake_width ? server->fake_width : server->run->exposed->width),
(server->fake_height ? server->fake_height : server->run->exposed->height),
(server->run->exposed->online ? "true" : "false"),
bool_to_string(server->run->exposed->online),
server->run->stream->encoder->quality,
server->run->exposed->captured_fps,
server->run->exposed->queued_fps,
@@ -200,10 +200,11 @@ static void _http_callback_ping(struct evhttp_request *request, void *v_server)
));
for (struct stream_client_t * client = server->run->stream_clients; client != NULL; client = client->next) {
assert(evbuffer_add_printf(buf,
"\"%s\": {\"fps\": %u, \"advance_headers\": %s}%s",
"\"%s\": {\"fps\": %u, \"advance_headers\": %s, \"dual_final_frames\": %s}%s",
client->id,
client->fps,
(client->advance_headers ? "true" : "false"),
bool_to_string(client->advance_headers),
bool_to_string(client->dual_final_frames),
(client->next ? ", " : "")
));
}
@@ -236,7 +237,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", (EXPOSED(online) ? "true" : "false"));
ADD_HEADER("X-UStreamer-Online", bool_to_string(EXPOSED(online)));
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));
@@ -286,6 +287,7 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server
evhttp_parse_query(evhttp_request_get_uri(request), &params);
client->extra_headers = _http_get_param_true(&params, "extra_headers");
client->advance_headers = _http_get_param_true(&params, "advance_headers");
client->dual_final_frames = _http_get_param_true(&params, "dual_final_frames");
evhttp_clear_headers(&params);
uuid_generate(uuid);
@@ -404,7 +406,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
"X-UStreamer-Expose-End-Time: %.06Lf" RN
"X-UStreamer-Send-Time: %.06Lf" RN
RN,
(EXPOSED(online) ? "true" : "false"),
bool_to_string(EXPOSED(online)),
client->fps,
EXPOSED(picture.grab_time),
EXPOSED(picture.encode_begin_time),
@@ -470,7 +472,7 @@ static void _http_callback_stream_error(UNUSED struct bufferevent *buf_event, UN
free(client);
}
static void _http_queue_send_stream(struct http_server_t *server, const bool updated) {
static void _http_queue_send_stream(struct http_server_t *server, const bool stream_updated, const bool picture_updated) {
struct evhttp_connection *conn;
struct bufferevent *buf_event;
long long now;
@@ -480,12 +482,32 @@ static void _http_queue_send_stream(struct http_server_t *server, const bool upd
for (struct stream_client_t *client = server->run->stream_clients; client != NULL; client = client->next) {
conn = evhttp_request_get_connection(client->request);
if (conn != NULL && (updated || client->need_first_frame)) {
buf_event = evhttp_connection_get_bufferevent(conn);
bufferevent_setcb(buf_event, NULL, _http_callback_stream_write, _http_callback_stream_error, (void *)client);
bufferevent_enable(buf_event, EV_READ|EV_WRITE);
client->need_first_frame = false;
queued = true;
if (conn != NULL) {
// Фикс для бага WebKit. При включенной опции дропа одинаковых фреймов,
// WebKit отрисовывает последний фрейм в серии с некоторой задержкой,
// и нужно послать два фрейма, чтобы серия была вовремя завершена.
// Это похоже на баг Blink (см. _http_callback_stream_write() и advance_headers),
// но фикс для него не лечит проблему вебкита. Такие дела.
bool dual_update = (
server->drop_same_frames
&& client->dual_final_frames
&& stream_updated
&& client->updated_prev
&& !picture_updated
);
if (dual_update || picture_updated || client->need_first_frame) {
buf_event = evhttp_connection_get_bufferevent(conn);
bufferevent_setcb(buf_event, NULL, _http_callback_stream_write, _http_callback_stream_error, (void *)client);
bufferevent_enable(buf_event, EV_READ|EV_WRITE);
client->need_first_frame = false;
client->updated_prev = (picture_updated || client->need_first_frame); // Игнорировать dual
queued = true;
} else if (stream_updated) { // Для dual
client->updated_prev = false;
}
}
}
@@ -501,7 +523,8 @@ static void _http_queue_send_stream(struct http_server_t *server, const bool upd
static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_server) {
struct http_server_t *server = (struct http_server_t *)v_server;
bool updated = false;
bool stream_updated = false;
bool picture_updated = false;
# define UNLOCK_STREAM \
{ server->run->stream->updated = false; A_PTHREAD_M_UNLOCK(&server->run->stream->mutex); }
@@ -510,20 +533,22 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
LOG_DEBUG("Refreshing HTTP exposed ...");
A_PTHREAD_M_LOCK(&server->run->stream->mutex);
if (server->run->stream->picture.size > 0) { // If online
updated = _expose_new_picture(server);
picture_updated = _expose_new_picture(server);
UNLOCK_STREAM;
} else {
UNLOCK_STREAM;
updated = _expose_blank_picture(server);
picture_updated = _expose_blank_picture(server);
}
stream_updated = true;
} else if (!server->run->exposed->online) {
LOG_DEBUG("Refreshing HTTP exposed (BLANK) ...");
updated = _expose_blank_picture(server);
picture_updated = _expose_blank_picture(server);
stream_updated = true;
}
# undef UNLOCK_STREAM
_http_queue_send_stream(server, updated);
_http_queue_send_stream(server, stream_updated, picture_updated);
}
static bool _expose_new_picture(struct http_server_t *server) {

View File

@@ -31,11 +31,15 @@
struct stream_client_t {
struct http_server_t *server;
struct evhttp_request *request;
char id[37]; // ex. "1b4e28ba-2fa1-11d2-883f-0016d3cca427" + "\0"
bool extra_headers;
bool advance_headers;
bool dual_final_frames;
char id[37]; // ex. "1b4e28ba-2fa1-11d2-883f-0016d3cca427" + "\0"
bool need_initial;
bool need_first_frame;
bool updated_prev;
unsigned fps;
unsigned fps_accum;
long long fps_accum_second;

View File

@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <math.h>
#include <pthread.h>
@@ -57,6 +58,10 @@
#define UNUSED __attribute__((unused))
INLINE char *bool_to_string(const bool flag) {
return (flag ? "true" : "false");
}
INLINE unsigned max_u(unsigned a, unsigned b) {
return (a > b ? a : b);
}

View File

@@ -37,6 +37,7 @@ def main():
text = html_file.read()
text = text.strip()
text = text.replace("\"", "\\\"")
text = text.replace("%VERSION%", "\" VERSION \"")
text = textwrap.indent(text, "\t", (lambda line: True))
text = "\n".join(("%s \\" if line.strip() else "%s\\") % (line) for line in text.split("\n"))