Plug open h264
parent
0a70f7fa6a
commit
90f61f03c6
10
meson.build
10
meson.build
|
@ -50,6 +50,10 @@ gnutls = dependency('gnutls', required: get_option('tls'))
|
||||||
zlib = dependency('zlib')
|
zlib = dependency('zlib')
|
||||||
gbm = dependency('gbm', required: get_option('gbm'))
|
gbm = dependency('gbm', required: get_option('gbm'))
|
||||||
|
|
||||||
|
libavcodec = dependency('libavcodec', required: get_option('h264'))
|
||||||
|
libavfilter = dependency('libavfilter', required: get_option('h264'))
|
||||||
|
libavutil = dependency('libavutil', required: get_option('h264'))
|
||||||
|
|
||||||
aml_project = subproject('aml', required: false)
|
aml_project = subproject('aml', required: false)
|
||||||
if aml_project.found()
|
if aml_project.found()
|
||||||
aml = aml_project.get_variable('aml_dep')
|
aml = aml_project.get_variable('aml_dep')
|
||||||
|
@ -108,6 +112,12 @@ if gbm.found()
|
||||||
config.set('HAVE_GBM', true)
|
config.set('HAVE_GBM', true)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if gbm.found() and libavcodec.found() and libavfilter.found() and libavutil.found()
|
||||||
|
sources += [ 'src/h264-encoder.c', 'src/open-h264.c' ]
|
||||||
|
dependencies += [libavcodec, libavfilter, libavutil]
|
||||||
|
config.set('ENABLE_OPEN_H264', true)
|
||||||
|
endif
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
output: 'config.h',
|
output: 'config.h',
|
||||||
configuration: config,
|
configuration: config,
|
||||||
|
|
|
@ -4,3 +4,4 @@ option('jpeg', type: 'feature', value: 'auto', description: 'Enable JPEG compres
|
||||||
option('tls', type: 'feature', value: 'auto', description: 'Enable encryption & authentication')
|
option('tls', type: 'feature', value: 'auto', description: 'Enable encryption & authentication')
|
||||||
option('systemtap', type: 'boolean', value: false, description: 'Enable tracing using sdt')
|
option('systemtap', type: 'boolean', value: false, description: 'Enable tracing using sdt')
|
||||||
option('gbm', type: 'feature', value: 'auto', description: 'Enable GBM integration')
|
option('gbm', type: 'feature', value: 'auto', description: 'Enable GBM integration')
|
||||||
|
option('h264', type: 'feature', value: 'disabled', description: 'Enable open h264 encoding (experimental)')
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "fb.h"
|
#include "fb.h"
|
||||||
#include "resampler.h"
|
#include "resampler.h"
|
||||||
#include "transform-util.h"
|
#include "transform-util.h"
|
||||||
|
#include "encoder.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -40,8 +41,14 @@ static void nvnc_display__on_resampler_done(struct nvnc_fb* fb,
|
||||||
nvnc_fb_ref(fb);
|
nvnc_fb_ref(fb);
|
||||||
nvnc_fb_hold(fb);
|
nvnc_fb_hold(fb);
|
||||||
|
|
||||||
// TODO: Shift according to display position
|
|
||||||
assert(self->server);
|
assert(self->server);
|
||||||
|
|
||||||
|
struct nvnc_client* client;
|
||||||
|
LIST_FOREACH(client, &self->server->clients, link)
|
||||||
|
if (client->encoder)
|
||||||
|
encoder_push(client->encoder, fb, damage);
|
||||||
|
|
||||||
|
// TODO: Shift according to display position
|
||||||
nvnc__damage_region(self->server, damage);
|
nvnc__damage_region(self->server, damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
88
src/server.c
88
src/server.c
|
@ -68,11 +68,13 @@ enum addrtype {
|
||||||
|
|
||||||
static int send_desktop_resize(struct nvnc_client* client, struct nvnc_fb* fb);
|
static int send_desktop_resize(struct nvnc_client* client, struct nvnc_fb* fb);
|
||||||
static int send_qemu_key_ext_frame(struct nvnc_client* client);
|
static int send_qemu_key_ext_frame(struct nvnc_client* client);
|
||||||
static enum rfb_encodings choose_frame_encoding(struct nvnc_client* client);
|
static enum rfb_encodings choose_frame_encoding(struct nvnc_client* client,
|
||||||
|
struct nvnc_fb*);
|
||||||
static enum tight_quality client_get_tight_quality(struct nvnc_client* client);
|
static enum tight_quality client_get_tight_quality(struct nvnc_client* client);
|
||||||
static void on_encode_frame_done(struct encoder*, struct rcbuf*);
|
static void on_encode_frame_done(struct encoder*, struct rcbuf*);
|
||||||
static bool client_has_encoding(const struct nvnc_client* client,
|
static bool client_has_encoding(const struct nvnc_client* client,
|
||||||
enum rfb_encodings encoding);
|
enum rfb_encodings encoding);
|
||||||
|
static void process_fb_update_requests(struct nvnc_client* client);
|
||||||
|
|
||||||
#if defined(GIT_VERSION)
|
#if defined(GIT_VERSION)
|
||||||
EXPORT const char nvnc_version[] = GIT_VERSION;
|
EXPORT const char nvnc_version[] = GIT_VERSION;
|
||||||
|
@ -488,6 +490,7 @@ static int on_client_set_encodings(struct nvnc_client* client)
|
||||||
case RFB_ENCODING_TIGHT:
|
case RFB_ENCODING_TIGHT:
|
||||||
case RFB_ENCODING_TRLE:
|
case RFB_ENCODING_TRLE:
|
||||||
case RFB_ENCODING_ZRLE:
|
case RFB_ENCODING_ZRLE:
|
||||||
|
case RFB_ENCODING_OPEN_H264:
|
||||||
case RFB_ENCODING_CURSOR:
|
case RFB_ENCODING_CURSOR:
|
||||||
case RFB_ENCODING_DESKTOPSIZE:
|
case RFB_ENCODING_DESKTOPSIZE:
|
||||||
case RFB_ENCODING_JPEG_HIGHQ:
|
case RFB_ENCODING_JPEG_HIGHQ:
|
||||||
|
@ -502,6 +505,14 @@ static int on_client_set_encodings(struct nvnc_client* client)
|
||||||
return sizeof(*msg) + 4 * n_encodings;
|
return sizeof(*msg) + 4 * n_encodings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void on_encoder_push_done(struct encoder* encoder, struct rcbuf* payload)
|
||||||
|
{
|
||||||
|
(void)payload;
|
||||||
|
|
||||||
|
struct nvnc_client* client = encoder->userdata;
|
||||||
|
process_fb_update_requests(client);
|
||||||
|
}
|
||||||
|
|
||||||
static void process_fb_update_requests(struct nvnc_client* client)
|
static void process_fb_update_requests(struct nvnc_client* client)
|
||||||
{
|
{
|
||||||
struct nvnc* server = client->server;
|
struct nvnc* server = client->server;
|
||||||
|
@ -545,6 +556,41 @@ static void process_fb_update_requests(struct nvnc_client* client)
|
||||||
|
|
||||||
DTRACE_PROBE1(neatvnc, update_fb_start, client);
|
DTRACE_PROBE1(neatvnc, update_fb_start, client);
|
||||||
|
|
||||||
|
enum rfb_encodings encoding = choose_frame_encoding(client, fb);
|
||||||
|
if (!client->encoder || encoding != encoder_get_type(client->encoder)) {
|
||||||
|
int width = server->display->buffer->width;
|
||||||
|
int height = server->display->buffer->height;
|
||||||
|
encoder_destroy(client->encoder);
|
||||||
|
client->encoder = encoder_new(encoding, width, height);
|
||||||
|
if (!client->encoder) {
|
||||||
|
log_error("Failed to allocate new encoder");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoder_get_kind(client->encoder) == ENCODER_KIND_PUSH_PULL)
|
||||||
|
{
|
||||||
|
client->encoder->on_done = on_encoder_push_done;
|
||||||
|
client->encoder->userdata = client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum encoder_kind kind = encoder_get_kind(client->encoder);
|
||||||
|
if (kind == ENCODER_KIND_PUSH_PULL) {
|
||||||
|
struct rcbuf* buf = encoder_pull(client->encoder);
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct rfb_server_fb_update_msg update_msg = {
|
||||||
|
.type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
|
||||||
|
.n_rects = htons(client->encoder->n_rects),
|
||||||
|
};
|
||||||
|
stream_write(client->net_stream, &update_msg,
|
||||||
|
sizeof(update_msg), NULL, NULL);
|
||||||
|
|
||||||
|
stream_send(client->net_stream, buf, NULL, NULL);
|
||||||
|
pixman_region_clear(&client->damage);
|
||||||
|
--client->n_pending_requests;
|
||||||
|
} else if (kind == ENCODER_KIND_REGULAR) {
|
||||||
/* The client's damage is exchanged for an empty one */
|
/* The client's damage is exchanged for an empty one */
|
||||||
struct pixman_region16 damage = client->damage;
|
struct pixman_region16 damage = client->damage;
|
||||||
pixman_region_init(&client->damage);
|
pixman_region_init(&client->damage);
|
||||||
|
@ -554,18 +600,6 @@ static void process_fb_update_requests(struct nvnc_client* client)
|
||||||
nvnc_fb_hold(fb);
|
nvnc_fb_hold(fb);
|
||||||
nvnc_fb_ref(fb);
|
nvnc_fb_ref(fb);
|
||||||
|
|
||||||
enum rfb_encodings encoding = choose_frame_encoding(client);
|
|
||||||
if (!client->encoder || encoding != encoder_get_type(client->encoder)) {
|
|
||||||
int width = server->display->buffer->width;
|
|
||||||
int height = server->display->buffer->height;
|
|
||||||
encoder_destroy(client->encoder);
|
|
||||||
client->encoder = encoder_new(encoding, width, height);
|
|
||||||
if (!client->encoder) {
|
|
||||||
log_error("Failed to allocate new encoder");
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client_ref(client);
|
client_ref(client);
|
||||||
|
|
||||||
int q = client_get_tight_quality(client);
|
int q = client_get_tight_quality(client);
|
||||||
|
@ -578,18 +612,17 @@ static void process_fb_update_requests(struct nvnc_client* client)
|
||||||
if (encoder_encode(client->encoder, fb, &damage) < 0) {
|
if (encoder_encode(client->encoder, fb, &damage) < 0) {
|
||||||
log_error("Failed to encode current frame");
|
log_error("Failed to encode current frame");
|
||||||
client_unref(client);
|
client_unref(client);
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixman_region_fini(&damage);
|
|
||||||
|
|
||||||
return;
|
|
||||||
failure:
|
|
||||||
client->is_updating = false;
|
client->is_updating = false;
|
||||||
assert(client->current_fb);
|
assert(client->current_fb);
|
||||||
nvnc_fb_release(client->current_fb);
|
nvnc_fb_release(client->current_fb);
|
||||||
nvnc_fb_unref(client->current_fb);
|
nvnc_fb_unref(client->current_fb);
|
||||||
client->current_fb = NULL;
|
client->current_fb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region_fini(&damage);
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_fb_update_request(struct nvnc_client* client)
|
static int on_client_fb_update_request(struct nvnc_client* client)
|
||||||
|
@ -614,10 +647,14 @@ static int on_client_fb_update_request(struct nvnc_client* client)
|
||||||
/* Note: The region sent from the client is ignored for incremental
|
/* Note: The region sent from the client is ignored for incremental
|
||||||
* updates. This avoids superfluous complexity.
|
* updates. This avoids superfluous complexity.
|
||||||
*/
|
*/
|
||||||
if (!incremental)
|
if (!incremental) {
|
||||||
pixman_region_union_rect(&client->damage, &client->damage, x, y,
|
pixman_region_union_rect(&client->damage, &client->damage, x, y,
|
||||||
width, height);
|
width, height);
|
||||||
|
|
||||||
|
if (client->encoder)
|
||||||
|
encoder_request_key_frame(client->encoder);
|
||||||
|
}
|
||||||
|
|
||||||
DTRACE_PROBE1(neatvnc, update_fb_request, client);
|
DTRACE_PROBE1(neatvnc, update_fb_request, client);
|
||||||
|
|
||||||
nvnc_fb_req_fn fn = server->fb_req_fn;
|
nvnc_fb_req_fn fn = server->fb_req_fn;
|
||||||
|
@ -1183,13 +1220,20 @@ static void on_write_frame_done(void* userdata, enum stream_req_status status)
|
||||||
client_unref(client);
|
client_unref(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum rfb_encodings choose_frame_encoding(struct nvnc_client* client)
|
static enum rfb_encodings choose_frame_encoding(struct nvnc_client* client,
|
||||||
|
struct nvnc_fb* fb)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < client->n_encodings; ++i)
|
for (size_t i = 0; i < client->n_encodings; ++i)
|
||||||
switch (client->encodings[i]) {
|
switch (client->encodings[i]) {
|
||||||
case RFB_ENCODING_RAW:
|
case RFB_ENCODING_RAW:
|
||||||
case RFB_ENCODING_TIGHT:
|
case RFB_ENCODING_TIGHT:
|
||||||
case RFB_ENCODING_ZRLE:
|
case RFB_ENCODING_ZRLE:
|
||||||
|
#ifdef ENABLE_OPEN_H264
|
||||||
|
case RFB_ENCODING_OPEN_H264:
|
||||||
|
// h264 is useless for sw frames
|
||||||
|
if (fb->type != NVNC_FB_GBM_BO)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
return client->encodings[i];
|
return client->encodings[i];
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue