Skip to content

Commit

Permalink
Add text framework
Browse files Browse the repository at this point in the history
Signed-off-by: Yu-Chen Lin <[email protected]>
  • Loading branch information
npes87184 committed Jun 13, 2020
1 parent 1e4ee54 commit 4b413d6
Show file tree
Hide file tree
Showing 12 changed files with 8,338 additions and 5 deletions.
2 changes: 1 addition & 1 deletion BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ sudo apt install ffmpeg libsdl2-2.0-0 adb
# client build dependencies
sudo apt install gcc git pkg-config meson ninja-build \
libavcodec-dev libavformat-dev libavutil-dev \
libsdl2-dev
libsdl2-dev libsdl2-ttf-dev

# server build dependencies
sudo apt install openjdk-8-jdk
Expand Down
2 changes: 2 additions & 0 deletions Makefile.CrossWindows
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ dist-win32: build-server build-win32 build-win32-noconsole
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/SDL2-2.0.12/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/SDL2_ttf-2.0.15/i686-w64-mingw32/bin/SDL2_ttf.dll "$(DIST)/$(WIN32_TARGET_DIR)/"

dist-win64: build-server build-win64 build-win64-noconsole
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
Expand All @@ -124,6 +125,7 @@ dist-win64: build-server build-win64 build-win64-noconsole
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/SDL2-2.0.12/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/SDL2_ttf-2.0.15/x86_64-w64-mingw32/bin/SDL2_ttf.dll "$(DIST)/$(WIN64_TARGET_DIR)/"

zip-win32: dist-win32
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \
Expand Down
17 changes: 16 additions & 1 deletion app/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ src = [
'src/fps_counter.c',
'src/input_manager.c',
'src/opengl.c',
'src/open_sans_font.c',
'src/receiver.c',
'src/recorder.c',
'src/scrcpy.c',
Expand All @@ -32,6 +33,7 @@ if not get_option('crossbuild_windows')
dependency('libavcodec'),
dependency('libavutil'),
dependency('sdl2'),
dependency('SDL2_ttf'),
]

else
Expand All @@ -43,7 +45,6 @@ else
sdl2_bin_dir = meson.current_source_dir() + '/../prebuilt-deps/' + prebuilt_sdl2 + '/bin'
sdl2_lib_dir = meson.current_source_dir() + '/../prebuilt-deps/' + prebuilt_sdl2 + '/lib'
sdl2_include_dir = '../prebuilt-deps/' + prebuilt_sdl2 + '/include'

sdl2 = declare_dependency(
dependencies: [
cc.find_library('SDL2', dirs: sdl2_bin_dir),
Expand All @@ -52,6 +53,19 @@ else
include_directories: include_directories(sdl2_include_dir)
)

prebuilt_sdl2_ttf = meson.get_cross_property('prebuilt_sdl2_ttf')
sdl2_include_sdl2_dir = '../prebuilt-deps/' + prebuilt_sdl2 + '/include/SDL2'
sdl2_ttf_bin_dir = meson.current_source_dir() + '/../prebuilt-deps/' + prebuilt_sdl2_ttf + '/bin'
sdl2_ttf_lib_dir = meson.current_source_dir() + '/../prebuilt-deps/' + prebuilt_sdl2_ttf + '/lib'
sdl2_ttf_include_dir = '../prebuilt-deps/' + prebuilt_sdl2_ttf + '/include'
sdl2_ttf = declare_dependency(
dependencies: [
cc.find_library('SDL2_ttf', dirs: sdl2_ttf_lib_dir),
cc.find_library('SDL2_ttf', dirs: sdl2_ttf_bin_dir),
],
include_directories: include_directories(sdl2_include_sdl2_dir, sdl2_ttf_include_dir)
)

prebuilt_ffmpeg_shared = meson.get_cross_property('prebuilt_ffmpeg_shared')
prebuilt_ffmpeg_dev = meson.get_cross_property('prebuilt_ffmpeg_dev')
ffmpeg_bin_dir = meson.current_source_dir() + '/../prebuilt-deps/' + prebuilt_ffmpeg_shared + '/bin'
Expand All @@ -67,6 +81,7 @@ else

dependencies = [
ffmpeg,
sdl2_ttf,
sdl2,
cc.find_library('mingw32')
]
Expand Down
2 changes: 2 additions & 0 deletions app/src/events.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#define EVENT_NEW_SESSION SDL_USEREVENT
#define EVENT_NEW_FRAME (SDL_USEREVENT + 1)
#define EVENT_STREAM_STOPPED (SDL_USEREVENT + 2)
#define EVENT_SCREEN_RENDER (SDL_USEREVENT + 3)
#define EVENT_RENDER_TEXT (SDL_USEREVENT + 4)
8,091 changes: 8,091 additions & 0 deletions app/src/open_sans_font.c

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions app/src/open_sans_font.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef OPEN_SANS_FONT_H
#define OPEN_SANS_FONT_H

#include <SDL2/SDL.h>

SDL_RWops *
open_sans_font_raw();

#endif
21 changes: 20 additions & 1 deletion app/src/scrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <libavformat/avformat.h>
#include <sys/time.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#ifdef _WIN32
# include <windows.h>
Expand Down Expand Up @@ -61,15 +62,26 @@ BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) {
}
#endif // _WIN32

static void
ttf_destroy() {
TTF_Quit();
}

// init SDL and set appropriate hints
static bool
sdl_init_and_configure(bool display, const char *render_driver) {
uint32_t flags = display ? SDL_INIT_VIDEO : SDL_INIT_EVENTS;
if (SDL_Init(flags)) {
if (SDL_Init(flags | SDL_INIT_TIMER)) {
LOGC("Could not initialize SDL: %s", SDL_GetError());
return false;
}

if (0 > TTF_Init()) {
LOGC("Could not initialize TTF: %s", TTF_GetError());
return false;
}

atexit(ttf_destroy);
atexit(SDL_Quit);

#ifdef _WIN32
Expand Down Expand Up @@ -163,6 +175,13 @@ handle_event(SDL_Event *event, bool control) {
case SDL_QUIT:
LOGD("User requested to quit");
return EVENT_RESULT_STOPPED_BY_USER;
case EVENT_SCREEN_RENDER:
screen_render(&screen, false);
break;
case EVENT_RENDER_TEXT:
screen_add_text_to_render_queue(&screen, event->user.data1);
screen_render(&screen, false);
break;
case EVENT_NEW_FRAME:
if (!screen.has_frame) {
screen.has_frame = true;
Expand Down
150 changes: 150 additions & 0 deletions app/src/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
#include <assert.h>
#include <string.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#include "config.h"
#include "common.h"
#include "compat.h"
#include "events.h"
#include "icon.xpm"
#include "open_sans_font.h"
#include "tiny_xpm.h"
#include "video_buffer.h"
#include "util/lock.h"
#include "util/log.h"

#define DISPLAY_MARGINS 96
#define OSD_TEXT_TIME 5

static inline struct size
get_rotated_size(struct size size, int rotation) {
Expand Down Expand Up @@ -330,6 +334,21 @@ screen_init_rendering(struct screen *screen, const char *window_title,
// different HiDPI scaling are connected
SDL_SetWindowSize(screen->window, window_size.width, window_size.height);

if (!(screen->mutex = SDL_CreateMutex())) {
LOGC("Could not create mutex: %s", SDL_GetError());
screen_destroy(screen);
return false;
}

SDL_RWops *raw_font = open_sans_font_raw();

screen->font = TTF_OpenFontRW(raw_font, 1, 25);
if (!screen->font) {
LOGW("Init font failed: %s", SDL_GetError());
screen_destroy(screen);
return false;
}

screen_update_content_rect(screen);

return true;
Expand All @@ -342,6 +361,18 @@ screen_show_window(struct screen *screen) {

void
screen_destroy(struct screen *screen) {
if (screen->text_texture) {
SDL_DestroyTexture(screen->text_texture);
}
if (screen->surface) {
SDL_FreeSurface(screen->surface);
}
if (screen->font) {
TTF_CloseFont(screen->font);
}
if (screen->mutex) {
SDL_DestroyMutex(screen->mutex);
}
if (screen->texture) {
SDL_DestroyTexture(screen->texture);
}
Expand Down Expand Up @@ -454,6 +485,87 @@ update_texture(struct screen *screen, const AVFrame *frame) {
}
}

static uint32_t
screen_text_timer_callback(uint32_t interval __attribute__((unused)), void *param __attribute__((unused))) {
static SDL_Event render_event;

render_event.type = EVENT_SCREEN_RENDER;

SDL_PushEvent(&render_event);

return 0;
}

bool
screen_render_text(struct screen *screen) {
struct render_text_request req;

if (time(NULL) >= screen->expired_time) {
if (screen->text_texture) {
SDL_DestroyTexture(screen->text_texture);
screen->text_texture = NULL;
}
if (screen->surface) {
SDL_FreeSurface(screen->surface);
screen->surface = NULL;
}
}

if (screen->surface == NULL || screen->text_texture == NULL) {
mutex_lock(screen->mutex);
if (cbuf_is_empty(&screen->queue)) {
mutex_unlock(screen->mutex);
return true;
}
cbuf_take(&screen->queue, &req);
mutex_unlock(screen->mutex);

SDL_Color text_color = {0, 0, 0, 255};
SDL_Color bg_color = {255, 255, 255, 50};
int width = 0;
int height = 0;

screen->expired_time = req.expired_time;
screen->surface = TTF_RenderText_Shaded(screen->font, req.text, text_color, bg_color);
if (!screen->surface) {
LOGW("Init surface failed: %s", SDL_GetError());
SDL_free(req.text);
return false;
}

screen->text_texture = SDL_CreateTextureFromSurface(screen->renderer, screen->surface);
if (!screen->text_texture) {
LOGW("Init text texture failed: %s", SDL_GetError());
SDL_free(req.text);
SDL_FreeSurface(screen->surface);
return false;
}

if (TTF_SizeText(screen->font, req.text, &width, &height)) {
LOGW("Could not get the size of TTF: %s", TTF_GetError());
SDL_free(req.text);
SDL_DestroyTexture(screen->text_texture);
SDL_FreeSurface(screen->surface);
return false;
}

screen->text_rect.x = screen->rect.w / 2 - width / 2;
screen->text_rect.y = screen->rect.h / 3 * 2;
screen->text_rect.w = width;
screen->text_rect.h = height;

SDL_free(req.text);

if (!SDL_AddTimer((OSD_TEXT_TIME + 1) * 1000, screen_text_timer_callback, NULL)) {
LOGW("Failed to add render timer callback, err: %s", SDL_GetError());
}
}

SDL_RenderCopy(screen->renderer, screen->text_texture, NULL, &(screen->text_rect));

return true;
}

bool
screen_update_frame(struct screen *screen, struct video_buffer *vb) {
mutex_lock(vb->mutex);
Expand All @@ -467,6 +579,7 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
mutex_unlock(vb->mutex);

screen_render(screen, false);

return true;
}

Expand Down Expand Up @@ -501,6 +614,7 @@ screen_render(struct screen *screen, bool update_content_rect) {
SDL_RenderCopyEx(screen->renderer, screen->texture, NULL, dstrect,
angle, NULL, 0);
}
screen_render_text(screen);
SDL_RenderPresent(screen->renderer);
}

Expand Down Expand Up @@ -578,6 +692,42 @@ screen_handle_window_event(struct screen *screen,
}
}

bool
screen_add_text_event(const char *text)
{
char *t = SDL_malloc(strlen(text) + 1);

if (!t) {
LOGW("Failed to allocate memory");
return false;
}

memset(t, 0, strlen(text) + 1);
strncpy(t, text, strlen(text));
static SDL_Event text_event;

text_event.type = EVENT_RENDER_TEXT;
text_event.user.data1 = t;

SDL_PushEvent(&text_event);

return true;
}

void
screen_add_text_to_render_queue(struct screen *screen, char *text) {
struct render_text_request req = {
.text = text,
.expired_time = time(NULL) + OSD_TEXT_TIME,
};

mutex_lock(screen->mutex);
if (!cbuf_push(&screen->queue, req)) {
LOGW("Failed to push request to queue");
}
mutex_unlock(screen->mutex);
}

struct point
screen_convert_to_frame_coords(struct screen *screen, int32_t x, int32_t y) {
unsigned rotation = screen->rotation;
Expand Down
Loading

0 comments on commit 4b413d6

Please sign in to comment.