From 9e978e923649afeff91bbb98cda95cd52f7c3b21 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Tue, 31 May 2022 13:45:34 -0700 Subject: add yami_inf decoder option --- client/X11/CMakeLists.txt | 19 +++++ client/X11/xf_gdi.c | 211 +++++++++++++++++++++++++++++++++++++++++++--- client/X11/xfreerdp.c | 106 ++++++++++++++++++++++- client/X11/xfreerdp.h | 9 ++ cmake/ConfigOptions.cmake | 1 + 5 files changed, 332 insertions(+), 14 deletions(-) diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 25eb418..f977165 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -92,6 +92,25 @@ if(WITH_XRANDR) target_link_libraries(xfreerdp ${XRANDR_LIBRARIES}) endif() +# example cmake . -DWITH_YAMIINF=ON +# example YAMIINF_DRM_FILE=/dev/dri/renderD128 YAMIINF_PATH=/opt/yami cmake . -DWITH_YAMIINF=ON +if(WITH_YAMIINF) + add_definitions(-DWITH_YAMIINF) +if(DEFINED ENV{YAMIINF_PATH}) + add_definitions(-DYAMIINF_INC_FILE="$ENV{YAMIINF_PATH}/include/yami_inf.h") + add_definitions(-DYAMIINF_LIB_FILE="$ENV{YAMIINF_PATH}/lib/libyami_inf.so") +else() + add_definitions(-DYAMIINF_INC_FILE="yami_inf.h") + add_definitions(-DYAMIINF_LIB_FILE="libyami_inf.so") +endif() +if(DEFINED ENV{YAMIINF_DRM_FILE}) + add_definitions(-DYAMIINF_DRI_FILE="$ENV{YAMIINF_DRM_FILE}") +else() + add_definitions(-DYAMIINF_DRI_FILE="/dev/dri/renderD128") +endif() + target_link_libraries(xfreerdp -lxcb -lX11-xcb -lxcb-dri3) +endif() + include_directories(${CMAKE_SOURCE_DIR}/resources) target_link_libraries(xfreerdp freerdp-core) diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index 90f2c61..3ec4f3a 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -30,12 +30,20 @@ #include #include #include +#include #include #include #include #include "xf_gdi.h" +#ifdef WITH_YAMIINF +#include /* close */ +#include +#include YAMIINF_INC_FILE +extern struct yami_funcs g_yami_funcs; /* in xfreerdp.c */ +#endif + #define LLOG_LEVEL 1 #define LLOGLN(_level, _args) \ do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0) @@ -654,6 +662,195 @@ void xf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surf } } +#ifdef WITH_YAMIINF +static int xf_gdi_surface_h264(xfInfo* xfi, SURFACE_BITS_COMMAND* surface_bits_command) +{ + STREAM* s; + int error; + int flags; + int session_id; + int src_width; + int src_height; + int dst_width; + int dst_height; + int num_rects; + int h264_bytes; + uint8* rects_p; + void* decoder; + xcb_pixmap_t pixmap = None; + xcb_void_cookie_t cookie; + xcb_generic_error_t* xcb_error; + + if ((surface_bits_command->bitmapDataLength < 1) || (surface_bits_command->bitmapData == NULL)) + { + return 1; + } + s = stream_new(0); + stream_attach(s, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); + LHEXDUMP(10, (surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength)); + if (stream_get_left(s) < 18) + { + LLOGLN(0, ("xf_gdi_surface_h264: error bytes")); + stream_detach(s); + stream_free(s); + return 1; + } + stream_read_uint32(s, flags); + stream_read_uint32(s, session_id); + LLOGLN(10, ("xf_gdi_surface_h264: flags 0x%8.8x session_id %d", flags, session_id)); + stream_read_uint16(s, src_width); + stream_read_uint16(s, src_height); + stream_read_uint16(s, dst_width); + stream_read_uint16(s, dst_height); + stream_read_uint16(s, num_rects); + if ((num_rects < 0) || (stream_get_left(s) < num_rects * 8 + 4)) + { + LLOGLN(0, ("xf_gdi_surface_h264: error bytes")); + stream_detach(s); + stream_free(s); + return 1; + } + stream_get_mark(s, rects_p); /* save for later */ + stream_seek(s, num_rects * 8); + stream_read_uint32(s, h264_bytes); + /* h264_bytes can be zero */ + if ((h264_bytes < 0) || (stream_get_left(s) < h264_bytes)) + { + LLOGLN(0, ("xf_gdi_surface_h264: error bytes")); + stream_detach(s); + stream_free(s); + return 1; + } + session_id &= 0xF; + if (flags & 2) /* delete */ + { + if (xfi->decoders[session_id] != NULL) + { + g_yami_funcs.yami_decoder_delete(xfi->decoders[session_id]); + xfi->decoders[session_id] = 0; + } + } + if ((h264_bytes > 0) && (num_rects > 0)) + { + decoder = xfi->decoders[session_id]; + if (decoder == NULL) + { + error = g_yami_funcs.yami_decoder_create(&decoder, src_width, src_height, + YI_TYPE_H264, YI_H264_DEC_FLAG_LOWLATENCY); + LLOGLN(0, ("xf_gdi_surface_h264: decoder_create rv %d width %d height %d", error, + src_width, src_height)); + if (error == YI_SUCCESS) + { + xfi->decoders[session_id] = decoder; + } + else + { + decoder = NULL; + } + } + if (decoder != NULL) + { + error = g_yami_funcs.yami_decoder_decode(decoder, s->p, h264_bytes); + LLOGLN(10, ("xf_gdi_surface_h264: yami_decoder_decode rv %d", error)); + if (error == YI_SUCCESS) + { + int fd; + int fd_width; + int fd_height; + int fd_stride; + int fd_size; + int fd_bpp; + YI_INT64 fd_time; + error = g_yami_funcs.yami_decoder_get_fd_dst(decoder, &fd, &fd_width, &fd_height, + &fd_stride, &fd_size, &fd_bpp, &fd_time); + LLOGLN(10, ("xf_gdi_surface_h264: yami_decoder_get_fd_dst rv %d", error)); + if (error == YI_SUCCESS) + { + LLOGLN(10, ("xf_gdi_surface_h264: yami_decoder_get_fd_dst fd %d " + "fd_width %d fd_height %d fd_stride %d fd_size %d fd_bpp %d " + "fd_time %lld", fd, fd_width, fd_height, fd_stride, fd_size, + fd_bpp, fd_time)); + LLOGLN(10, ("xf_gdi_surface_h264: fd_bpp %d xfi->depth %d xfi->bpp %d", + fd_bpp, xfi->depth, xfi->bpp)); + pixmap = xcb_generate_id(xfi->xcb); + cookie = xcb_dri3_pixmap_from_buffer(xfi->xcb, pixmap, xfi->drawable, + fd_size, fd_width, fd_height, fd_stride, xfi->depth, xfi->bpp, fd); + xcb_error = xcb_request_check(xfi->xcb, cookie); + free(xcb_error); + close(fd); + } + else + { + LLOGLN(0, ("xf_gdi_surface_h264: yami_decoder_get_fd_dst failed %d", error)); + } + } + else + { + LLOGLN(0, ("xf_gdi_surface_h264: yami_decoder_decode failed %d", error)); + } + } + else + { + LLOGLN(0, ("xf_gdi_surface_h264: error getting decoder")); + } + } + if (pixmap != None) + { + if ((src_width == dst_width) && (src_height == dst_height)) + { + int x; + int y; + int cx; + int cy; + int lx; + int ly; + int index; + Drawable dst = xfi->skip_bs ? xfi->drawable : xfi->primary; + /* size of rects_p checked earlier */ + stream_attach(s, rects_p, num_rects * 8); + for (index = 0; index < num_rects; index++) + { + stream_read_uint16(s, x); + stream_read_uint16(s, y); + stream_read_uint16(s, cx); + stream_read_uint16(s, cy); + lx = x + surface_bits_command->destLeft; + ly = y + surface_bits_command->destTop; + if (lx + cx > surface_bits_command->destRight) + { + cx = surface_bits_command->destRight - lx; + } + if (ly + cy > surface_bits_command->destBottom) + { + cy = surface_bits_command->destBottom - ly; + } + if ((cx > 0) && (cy > 0)) + { + xcb_copy_area(xfi->xcb, pixmap, dst, xfi->xcb_gc, x, y, lx, ly, cx, cy); + if (!xfi->remote_app && !xfi->skip_bs) + { + xcb_copy_area(xfi->xcb, xfi->primary, xfi->drawable, xfi->xcb_gc, lx, ly, lx, ly, cx, cy); + } + } + } + } + else + { + LLOGLN(0, ("xf_gdi_surface_h264: xf_gdi_surface_bits: unsupported stretch")); + } + xcb_free_pixmap(xfi->xcb, pixmap); + } + stream_detach(s); + stream_free(s); + return 0; +} +#else +static int xf_gdi_surface_h264(xfInfo* xfi, SURFACE_BITS_COMMAND* surface_bits_command) +{ + return 0; +} +#endif + void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command) { int i, tx, ty; @@ -665,19 +862,7 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits if (surface_bits_command->codecID == CODEC_ID_H264) { - STREAM* s; - int num_rects; - int h264_bytes; - - s = stream_new(0); - stream_attach(s, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); - stream_read_uint16(s, num_rects); - stream_seek(s, num_rects * 8); - stream_read_uint32(s, h264_bytes); - stream_attach(s, 0, 0); - stream_free(s); - printf("h264 bytes %d num_rects %d h264_bytes %d\n", - surface_bits_command->bitmapDataLength, num_rects, h264_bytes); + xf_gdi_surface_h264(xfi, surface_bits_command); } else if (surface_bits_command->codecID == CODEC_ID_JPEG) { diff --git a/client/X11/xfreerdp.c b/client/X11/xfreerdp.c index 8cb3805..ef03c4e 100644 --- a/client/X11/xfreerdp.c +++ b/client/X11/xfreerdp.c @@ -66,6 +66,20 @@ #include "xfreerdp.h" +#ifdef WITH_YAMIINF +#include /* dlopen dlsym */ +#include /* open */ +#include YAMIINF_INC_FILE +static void* g_yami_lib = NULL; +static yami_get_funcs_proc g_get_funcs_func = NULL; +static int g_drm_fd = -1; +struct yami_funcs g_yami_funcs; +#endif + +#define LLOG_LEVEL 1 +#define LLOGLN(_level, _args) \ + do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0) + static freerdp_sem g_sem; static int g_thread_count = 0; static uint8 g_disconnect_reason = 0; @@ -693,6 +707,12 @@ tbool xf_post_connect(freerdp* instance) xf_create_window(xfi); +#ifdef WITH_YAMIINF + xfi->xcb = XGetXCBConnection(xfi->display); + xfi->xcb_gc = xcb_generate_id(xfi->xcb); + xcb_create_gc(xfi->xcb, xfi->xcb_gc, xfi->drawable, 0, NULL); +#endif + memset(&gcv, 0, sizeof(gcv)); xfi->modifier_map = XGetModifierMapping(xfi->display); @@ -1142,13 +1162,97 @@ int main(int argc, char* argv[]) data = (struct thread_data*) xzalloc(sizeof(struct thread_data)); data->instance = instance; +#ifdef WITH_YAMIINF + memset(&g_yami_funcs, 0, sizeof(g_yami_funcs)); + g_drm_fd = open(YAMIINF_DRI_FILE, O_RDWR); + LLOGLN(0, ("main: open %s O_RDWR g_drm_fd is %d", YAMIINF_DRI_FILE, g_drm_fd)); + if ((g_yami_lib == NULL) && (g_drm_fd != -1)) + { + int failed = 1; + LLOGLN(0, ("main: loading %s", YAMIINF_LIB_FILE)); + g_yami_lib = dlopen(YAMIINF_LIB_FILE, RTLD_LAZY); + if (g_yami_lib != NULL) + { + g_get_funcs_func = (yami_get_funcs_proc)dlsym(g_yami_lib, "yami_get_funcs"); + if (g_get_funcs_func != NULL) + { + int error = g_get_funcs_func(&g_yami_funcs, YI_VERSION_INT(YI_MAJOR, YI_MINOR)); + LLOGLN(0, ("main: g_get_funcs_func rv %d", error)); + if (error == YI_SUCCESS) + { + int version; + error = g_yami_funcs.yami_get_version(&version); + LLOGLN(0, ("main: yami_get_version rv %d", error)); + if (error == YI_SUCCESS) + { + LLOGLN(0, ("main: yami_inf version 0x%8.8x", version)); + error = g_yami_funcs.yami_init(YI_TYPE_DRM, (void*)(size_t)g_drm_fd); + LLOGLN(0, ("main: yami_init rv %d", error)); + if (error == YI_SUCCESS) + { + failed = 0; + } + else + { + LLOGLN(0, ("main: yami_init failed")); + } + } + else + { + LLOGLN(0, ("main: g_get_funcs_func failed")); + } + } + else + { + LLOGLN(0, ("main: yami_get_version failed")); + } + } + else + { + LLOGLN(0, ("main: dlsym lyami_get_funcs failed")); + } + } + else + { + LLOGLN(0, ("main: load libyami_inf.so failed")); + } + if (failed) + { + if (g_yami_lib != NULL) + { + dlclose(g_yami_lib); + g_yami_lib = NULL; + } + g_get_funcs_func = NULL; + memset(&g_yami_funcs, 0, sizeof(g_yami_funcs)); + close(g_drm_fd); + g_drm_fd = -1; + } + } +#endif + g_thread_count++; pthread_create(&thread, 0, thread_func, data); while (g_thread_count > 0) { - freerdp_sem_wait(g_sem); + freerdp_sem_wait(g_sem); + } + +#ifdef WITH_YAMIINF + if (g_yami_lib != NULL) + { + dlclose(g_yami_lib); + g_yami_lib = NULL; } + g_get_funcs_func = NULL; + memset(&g_yami_funcs, 0, sizeof(g_yami_funcs)); + if (g_drm_fd != -1) + { + close(g_drm_fd); + g_drm_fd = -1; + } +#endif freerdp_channels_global_uninit(); diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 9b897b9..fd16b88 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -33,6 +33,10 @@ typedef struct xf_info xfInfo; #include "xf_window.h" #include "xf_monitor.h" +#ifdef WITH_YAMIINF +#include +#endif + /* 1 is grab keyboard, 2 is grab key */ #define XF_GRAB_MODE 2 @@ -186,6 +190,11 @@ struct xf_info int suppress_output; int primary_adjust_x; int primary_adjust_y; +#ifdef WITH_YAMIINF + void* decoders[16]; + xcb_connection_t* xcb; + int xcb_gc; +#endif }; void xf_toggle_fullscreen(xfInfo* xfi); diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 16e7ed9..3eeb729 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -33,3 +33,4 @@ option(WITH_TCUTILS "Use Thinclient utilities." ON) option(WITH_XINERAMA "Use xinerama extension" OFF) option(WITH_XRANDR "Use xrandr extension" ON) option(WITH_FFMPEG "Use ffmpeg library" OFF) +option(WITH_YAMIINF "Use yami_inf for h264" OFF) -- cgit v1.2.3