diff --git a/src/data/html_index.h b/src/data/html_index.h
index 25c18b9..d75f847 100644
--- a/src/data/html_index.h
+++ b/src/data/html_index.h
@@ -62,6 +62,13 @@ const char *HTML_INDEX_PAGE = " \
Enable workaround for Chromium/Blink \
Bug #527446. \
\
+
\
+
\
+ dual_final_frames=1
\
+ Enable workaround for Safari/WebKit bug when using option --drop-same-frames.
\
+ Without this option, when the frame series is completed, WebKit-based browser
\
+ renders the last one with a delay. \
+ \
\
\
\
diff --git a/src/data/index.html b/src/data/index.html
index 16e6c58..6db51b6 100644
--- a/src/data/index.html
+++ b/src/data/index.html
@@ -35,6 +35,13 @@
Enable workaround for Chromium/Blink
Bug #527446.
+
+
+ dual_final_frames=1
+ Enable workaround for Safari/WebKit bug when using option --drop-same-frames.
+ Without this option, when the frame series is completed, WebKit-based browser
+ renders the last one with a delay.
+
diff --git a/src/http.c b/src/http.c
index a5721de..564caac 100644
--- a/src/http.c
+++ b/src/http.c
@@ -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);
@@ -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"),
+ (client->dual_final_frames ? "true" : "false"),
(client->next ? ", " : "")
));
}
@@ -286,6 +287,7 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server
evhttp_parse_query(evhttp_request_get_uri(request), ¶ms);
client->extra_headers = _http_get_param_true(¶ms, "extra_headers");
client->advance_headers = _http_get_param_true(¶ms, "advance_headers");
+ client->dual_final_frames = _http_get_param_true(¶ms, "dual_final_frames");
evhttp_clear_headers(¶ms);
uuid_generate(uuid);
@@ -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) {
diff --git a/src/http.h b/src/http.h
index 5eaf2d5..93d648a 100644
--- a/src/http.h
+++ b/src/http.h
@@ -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;