Ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server and media proxy that allows to read, publish, proxy, record and playback video and audio streams.
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

#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;
}
}
}