golanggohlsrtmpwebrtcmedia-serverobs-studiortcprtmp-proxyrtmp-serverrtprtsprtsp-proxyrtsp-relayrtsp-serversrtstreamingwebrtc-proxy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
4.7 KiB
171 lines
4.7 KiB
#include <time.h> |
|
|
|
#include <ft2build.h> |
|
#include FT_FREETYPE_H |
|
|
|
#include "text_font.h" |
|
#include "text.h" |
|
|
|
static char errbuf[256]; |
|
|
|
static void set_error(const char *format, ...) { |
|
va_list args; |
|
va_start(args, format); |
|
vsnprintf(errbuf, 256, format, args); |
|
} |
|
|
|
const char *text_get_error() { |
|
return errbuf; |
|
} |
|
|
|
typedef struct { |
|
bool enabled; |
|
char *text_overlay; |
|
FT_Library library; |
|
FT_Face face; |
|
} text_priv_t; |
|
|
|
bool text_create(const parameters_t *params, text_t **text) { |
|
*text = malloc(sizeof(text_priv_t)); |
|
text_priv_t *textp = (text_priv_t *)(*text); |
|
memset(textp, 0, sizeof(text_priv_t)); |
|
|
|
textp->enabled = params->text_overlay_enable; |
|
textp->text_overlay = strdup(params->text_overlay); |
|
|
|
if (textp->enabled) { |
|
int error = FT_Init_FreeType(&textp->library); |
|
if (error) { |
|
set_error("FT_Init_FreeType() failed"); |
|
goto failed; |
|
} |
|
|
|
error = FT_New_Memory_Face( |
|
textp->library, |
|
text_font_ttf, |
|
sizeof(text_font_ttf), |
|
0, |
|
&textp->face); |
|
if (error) { |
|
set_error("FT_New_Memory_Face() failed"); |
|
goto failed; |
|
} |
|
|
|
error = FT_Set_Pixel_Sizes( |
|
textp->face, |
|
25, |
|
25); |
|
if (error) { |
|
set_error("FT_Set_Pixel_Sizes() failed"); |
|
goto failed; |
|
} |
|
} |
|
|
|
return true; |
|
|
|
failed: |
|
free(textp); |
|
|
|
return false; |
|
} |
|
|
|
static void draw_rect(uint8_t *buf, int stride, int height, int x, int y, unsigned int rect_width, unsigned int rect_height) { |
|
uint8_t *Y = buf; |
|
uint8_t *U = Y + stride * height; |
|
uint8_t *V = U + (stride / 2) * (height / 2); |
|
const uint8_t color[3] = {0, 128, 128}; |
|
uint32_t opacity = 45; |
|
|
|
for (unsigned int src_y = 0; src_y < rect_height; src_y++) { |
|
for (unsigned int src_x = 0; src_x < rect_width; src_x++) { |
|
unsigned int dest_x = x + src_x; |
|
unsigned int dest_y = y + src_y; |
|
int i1 = dest_y*stride + dest_x; |
|
int i2 = dest_y/2*stride/2 + dest_x/2; |
|
|
|
Y[i1] = ((color[0] * opacity) + (uint32_t)Y[i1] * (255 - opacity)) / 255; |
|
U[i2] = ((color[1] * opacity) + (uint32_t)U[i2] * (255 - opacity)) / 255; |
|
V[i2] = ((color[2] * opacity) + (uint32_t)V[i2] * (255 - opacity)) / 255; |
|
} |
|
} |
|
} |
|
|
|
static void draw_bitmap(uint8_t *buf, int stride, int height, const FT_Bitmap *bitmap, int x, int y) { |
|
uint8_t *Y = buf; |
|
uint8_t *U = Y + stride * height; |
|
uint8_t *V = U + (stride / 2) * (height / 2); |
|
|
|
for (unsigned int src_y = 0; src_y < bitmap->rows; src_y++) { |
|
for (unsigned int src_x = 0; src_x < bitmap->width; src_x++) { |
|
uint8_t v = bitmap->buffer[src_y*bitmap->pitch + src_x]; |
|
|
|
if (v != 0) { |
|
unsigned int dest_x = x + src_x; |
|
unsigned int dest_y = y + src_y; |
|
int i1 = dest_y*stride + dest_x; |
|
int i2 = dest_y/2*stride/2 + dest_x/2; |
|
uint32_t opacity = (uint32_t)v; |
|
|
|
Y[i1] = (uint8_t)(((uint32_t)v * opacity + (uint32_t)Y[i1] * (255 - opacity)) / 255); |
|
U[i2] = (uint8_t)((128 * opacity + (uint32_t)U[i2] * (255 - opacity)) / 255); |
|
V[i2] = (uint8_t)((128 * opacity + (uint32_t)V[i2] * (255 - opacity)) / 255); |
|
} |
|
} |
|
} |
|
} |
|
|
|
static int get_text_width(FT_Face face, const char *text) { |
|
int ret = 0; |
|
|
|
for (const char *ptr = text; *ptr != 0x00; ptr++) { |
|
int error = FT_Load_Char(face, *ptr, FT_LOAD_RENDER); |
|
if (error) { |
|
continue; |
|
} |
|
|
|
ret += face->glyph->advance.x >> 6; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
void text_draw(text_t *text, uint8_t *buf, int stride, int height) { |
|
text_priv_t *textp = (text_priv_t *)text; |
|
|
|
if (textp->enabled) { |
|
time_t timer = time(NULL); |
|
struct tm *tm_info = localtime(&timer); |
|
char buffer[255]; |
|
memset(buffer, 0, sizeof(buffer)); |
|
strftime(buffer, 255, textp->text_overlay, tm_info); |
|
|
|
draw_rect( |
|
buf, |
|
stride, |
|
height, |
|
7, |
|
7, |
|
get_text_width(textp->face, buffer) + 10, |
|
34); |
|
|
|
int x = 12; |
|
int y = 33; |
|
|
|
for (const char *ptr = buffer; *ptr != 0x00; ptr++) { |
|
int error = FT_Load_Char(textp->face, *ptr, FT_LOAD_RENDER); |
|
if (error) { |
|
continue; |
|
} |
|
|
|
draw_bitmap( |
|
buf, |
|
stride, |
|
height, |
|
&textp->face->glyph->bitmap, |
|
x + textp->face->glyph->bitmap_left, |
|
y - textp->face->glyph->bitmap_top); |
|
|
|
x += textp->face->glyph->advance.x >> 6; |
|
} |
|
} |
|
}
|
|
|