stream fix for webkit

This commit is contained in:
Devaev Maxim
2018-11-05 04:09:13 +03:00
parent ab437d402b
commit ca52f12378
4 changed files with 58 additions and 15 deletions

View File

@@ -62,6 +62,13 @@ const char *HTML_INDEX_PAGE = " \
Enable workaround for Chromium/Blink \ 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> \ </li> \
<br> \
<li> \
<i>dual_final_frames=1</i><br> \
Enable workaround for Safari/WebKit bug when using option --drop-same-frames.<br> \
Without this option, when the frame series is completed, WebKit-based browser<br> \
renders the last one with a delay. \
</li> \
</ul> \ </ul> \
</li> \ </li> \
<br> \ <br> \

View File

@@ -35,6 +35,13 @@
Enable workaround for Chromium/Blink 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> </li>
<br>
<li>
<i>dual_final_frames=1</i><br>
Enable workaround for Safari/WebKit bug when using option --drop-same-frames.<br>
Without this option, when the frame series is completed, WebKit-based browser<br>
renders the last one with a delay.
</li>
</ul> </ul>
</li> </li>
<br> <br>

View File

@@ -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_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_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_new_picture(struct http_server_t *server);
static bool _expose_blank_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) { for (struct stream_client_t * client = server->run->stream_clients; client != NULL; client = client->next) {
assert(evbuffer_add_printf(buf, 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->id,
client->fps, client->fps,
(client->advance_headers ? "true" : "false"), (client->advance_headers ? "true" : "false"),
(client->dual_final_frames ? "true" : "false"),
(client->next ? ", " : "") (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), &params); evhttp_parse_query(evhttp_request_get_uri(request), &params);
client->extra_headers = _http_get_param_true(&params, "extra_headers"); client->extra_headers = _http_get_param_true(&params, "extra_headers");
client->advance_headers = _http_get_param_true(&params, "advance_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); evhttp_clear_headers(&params);
uuid_generate(uuid); uuid_generate(uuid);
@@ -470,7 +472,7 @@ static void _http_callback_stream_error(UNUSED struct bufferevent *buf_event, UN
free(client); 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 evhttp_connection *conn;
struct bufferevent *buf_event; struct bufferevent *buf_event;
long long now; 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) { for (struct stream_client_t *client = server->run->stream_clients; client != NULL; client = client->next) {
conn = evhttp_request_get_connection(client->request); conn = evhttp_request_get_connection(client->request);
if (conn != NULL && (updated || client->need_first_frame)) { if (conn != NULL) {
buf_event = evhttp_connection_get_bufferevent(conn); // Фикс для бага WebKit. При включенной опции дропа одинаковых фреймов,
bufferevent_setcb(buf_event, NULL, _http_callback_stream_write, _http_callback_stream_error, (void *)client); // WebKit отрисовывает последний фрейм в серии с некоторой задержкой,
bufferevent_enable(buf_event, EV_READ|EV_WRITE); // и нужно послать два фрейма, чтобы серия была вовремя завершена.
client->need_first_frame = false; // Это похоже на баг Blink (см. _http_callback_stream_write() и advance_headers),
queued = true; // но фикс для него не лечит проблему вебкита. Такие дела.
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) { 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; 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 \ # define UNLOCK_STREAM \
{ server->run->stream->updated = false; A_PTHREAD_M_UNLOCK(&server->run->stream->mutex); } { 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 ..."); LOG_DEBUG("Refreshing HTTP exposed ...");
A_PTHREAD_M_LOCK(&server->run->stream->mutex); A_PTHREAD_M_LOCK(&server->run->stream->mutex);
if (server->run->stream->picture.size > 0) { // If online if (server->run->stream->picture.size > 0) { // If online
updated = _expose_new_picture(server); picture_updated = _expose_new_picture(server);
UNLOCK_STREAM; UNLOCK_STREAM;
} else { } else {
UNLOCK_STREAM; UNLOCK_STREAM;
updated = _expose_blank_picture(server); picture_updated = _expose_blank_picture(server);
} }
stream_updated = true;
} else if (!server->run->exposed->online) { } else if (!server->run->exposed->online) {
LOG_DEBUG("Refreshing HTTP exposed (BLANK) ..."); LOG_DEBUG("Refreshing HTTP exposed (BLANK) ...");
updated = _expose_blank_picture(server); picture_updated = _expose_blank_picture(server);
stream_updated = true;
} }
# undef UNLOCK_STREAM # 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) { static bool _expose_new_picture(struct http_server_t *server) {

View File

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