diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index 880af749e5..aba9b5c7a3 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -61,6 +61,13 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_IMG_FMT_HIGH VPX_IMG_FMT_HIGH #define SWITCH_IMG_FMT_I420 VPX_IMG_FMT_I420 +typedef struct switch_yuv_color_s { + uint8_t y; + uint8_t u; + uint8_t v; +} switch_yuv_color_t; + + typedef vpx_img_fmt_t switch_img_fmt_t; typedef vpx_image_t switch_image_t; @@ -176,8 +183,16 @@ SWITCH_DECLARE(void) switch_img_flip(switch_image_t *img); */ SWITCH_DECLARE(void) switch_img_free(switch_image_t **img); +SWITCH_DECLARE(void) switch_img_draw_text(switch_image_t *IMG, int x, int y, char *text); + SWITCH_DECLARE(void) switch_img_add_text(void *buffer, int w, int x, int y, char *s); +SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, int x, int y, int w, int h); + +SWITCH_DECLARE(void) switch_image_draw_pixel(switch_image_t *img, int x, int y, switch_yuv_color_t color); + +SWITCH_DECLARE(void) switch_color_set(switch_yuv_color_t *color, char *color_str); + /** @} */ SWITCH_END_EXTERN_C diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 484683cb9a..222b2268bf 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -362,13 +362,6 @@ typedef struct mcu_layer_s { switch_image_t *cur_img; } mcu_layer_t; -typedef struct bgcolor_yuv_s -{ - uint8_t y; - uint8_t u; - uint8_t v; -} bgcolor_yuv_t; - typedef struct mcu_canvas_s { int width; int height; @@ -377,7 +370,7 @@ typedef struct mcu_canvas_s { int total_layers; int layers_used; int layout_floor_id; - bgcolor_yuv_t bgcolor; + switch_yuv_color_t bgcolor; switch_mutex_t *mutex; switch_mutex_t *cond_mutex; switch_mutex_t *cond2_mutex; @@ -708,6 +701,93 @@ typedef struct layout_group_s { video_layout_node_t *layouts; } layout_group_t; +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +static void draw_bitmap(switch_image_t *img, FT_Bitmap* bitmap, FT_Int x, FT_Int y, switch_yuv_color_t color) +{ + FT_Int i, j, p, q; + FT_Int x_max = x + bitmap->width; + FT_Int y_max = y + bitmap->rows; + + for ( i = x, p = 0; i < x_max; i++, p++ ) { + for ( j = y, q = 0; j < y_max; j++, q++ ) { + if ( i < 0 || j < 0 || i >= img->d_w || j >= img->d_h) continue; + + if (bitmap->buffer[q * bitmap->width + p]) { + // TODO the value ranges from 1 - 255, maybe we should reset the color based on that + switch_image_draw_pixel(img, i, j, color); + } + } + } +} + +SWITCH_DECLARE(void) switch_img_draw_text(switch_image_t *img, int x, int y, char *text) +{ + FT_Library library; + FT_Face face; + FT_GlyphSlot slot; + FT_Matrix matrix; /* transformation matrix */ + FT_Vector pen; /* untransformed origin */ + FT_Error error; + char* font_family = "/usr/local/freeswitch/SimHei.ttf"; + int font_size = 64; + double angle; + int target_height; + int n, num_chars; + switch_yuv_color_t color; + + if (zstr(text)) return; + switch_color_set(&color, "#FFFFFF"); + + num_chars = strlen(text); + angle = 0; // (45.0 / 360 ) * 3.14159 * 2; + target_height = img->d_h; + + error = FT_Init_FreeType( &library ); /* initialize library */ + if (error) return; + + error = FT_New_Face(library, font_family, 0, &face); /* create face object */ + if (error) return; + + /* use 50pt at 100dpi */ + error = FT_Set_Char_Size(face, 50 * font_size, 0, 100, 0); /* set character size */ + if (error) return; + + slot = face->glyph; + + /* set up matrix */ + matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); + matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); + matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L ); + matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); + + /* the pen position in 26.6 cartesian space coordinates; */ + /* start at (300,200) relative to the upper left corner */ + pen.x = x * 64; + pen.y = (target_height - y) * 64; + + for(n = 0; n < num_chars; n++) { + /* set transformation */ + FT_Set_Transform(face, &matrix, &pen); + + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Char(face, text[n], FT_LOAD_RENDER); + if (error) continue; + + /* now, draw to our target surface (convert position) */ + draw_bitmap(img, &slot->bitmap, slot->bitmap_left, target_height - slot->bitmap_top + font_size, color); + + /* increment pen position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + } + + FT_Done_Face(face); + FT_Done_FreeType(library); +} + static void conference_parse_layouts(conference_obj_t *conference) { switch_event_t *params; @@ -890,7 +970,7 @@ static int mcu_canvas_wake(mcu_canvas_t *mcu_canvas) return 0; } -static void reset_image(switch_image_t *img, bgcolor_yuv_t *color) +static void reset_image(switch_image_t *img, switch_yuv_color_t *color) { int i; @@ -904,32 +984,6 @@ static void reset_image(switch_image_t *img, bgcolor_yuv_t *color) } } -static void set_bgcolor(bgcolor_yuv_t *bgcolor, char *bgcolor_str) -{ - uint8_t y = 134; - uint8_t u = 128; - uint8_t v = 124; - - if (bgcolor_str != NULL && strlen(bgcolor_str) == 7) { - uint8_t red, green, blue; - char str[7]; - bgcolor_str ++; - strncpy(str, bgcolor_str, 6); - red = (str[0] >= 'A' ? (str[0] - 'A' + 10) * 16 : (str[0] - '0') * 16) + (str[1] >= 'A' ? (str[1] - 'A' + 10) : (str[0] - '0')); - green = (str[2] >= 'A' ? (str[2] - 'A' + 10) * 16 : (str[2] - '0') * 16) + (str[3] >= 'A' ? (str[3] - 'A' + 10) : (str[0] - '0')); - blue = (str[4] >= 'A' ? (str[4] - 'A' + 10) * 16 : (str[4] - '0') * 16) + (str[5] >= 'A' ? (str[5] - 'A' + 10) : (str[0] - '0')); - - y = (uint8_t)(((red * 4897) >> 14) + ((green * 9611) >> 14) + ((blue * 1876) >> 14)); - u = (uint8_t)(- ((red * 2766) >> 14) - ((5426 * green) >> 14) + blue / 2 + 128); - v = (uint8_t)(red / 2 -((6855 * green) >> 14) - ((blue * 1337) >> 14) + 128); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "analy_bgcolor, red = %u, green = %u, blue = %u, y = %u, u = %u, v = %u\n", red, green, blue, y, u, v); - } - - bgcolor->y = y; - bgcolor->u = u; - bgcolor->v = v; -} - #define SCALE_FACTOR 360.0f static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer) @@ -1041,7 +1095,7 @@ static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer) static void set_canvas_bgcolor(mcu_canvas_t *canvas, char *color) { - set_bgcolor(&canvas->bgcolor, color); + switch_color_set(&canvas->bgcolor, color); reset_image(canvas->img, &canvas->bgcolor); } @@ -1480,6 +1534,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread } } + // switch_img_draw_text(conference->canvas->img, 10, 10, "AVA 123 你好 FreeSWITCH"); if (used) { switch_time_t now = switch_micro_time_now(); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index bbdc40dddc..9e0eadbf21 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -131,6 +131,47 @@ SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_i } +SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, int x, int y, int w, int h) +{ + switch_image_t *new_img = NULL; + int i = 0; + int len; + + switch_assert(img); + switch_assert(x >= 0 && y >= 0 && w >= 0 && h >= 0); + + if (!img->fmt == SWITCH_IMG_FMT_I420) return NULL; + + new_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, w, h, 1); + if (new_img == NULL) return NULL; + + len = MIN(img->d_w - x, w); + if (len <= 0) return NULL; + + for (i = 0; i < (img->d_h - y) && i < h; i++) { + memcpy(new_img->planes[SWITCH_PLANE_Y] + new_img->stride[SWITCH_PLANE_Y] * i, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * (y + i) + x, len); + } + + len /= 2; + + for (i = 0; i < (img->d_h - y) && i < h; i += 2) { + memcpy(new_img->planes[SWITCH_PLANE_U] + new_img->stride[SWITCH_PLANE_U] * i / 2, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * (y + i) / 2 + x / 2, len); + memcpy(new_img->planes[SWITCH_PLANE_V] + new_img->stride[SWITCH_PLANE_V] * i / 2, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * (y + i) / 2 + x / 2, len); + } + return new_img; +} + +SWITCH_DECLARE(void) switch_image_draw_pixel(switch_image_t *img, int x, int y, switch_yuv_color_t color) +{ + if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return; + + img->planes[SWITCH_PLANE_Y][y * img->stride[SWITCH_PLANE_Y] + x] = color.y; + + if (((x & 0x1) == 0) && ((y & 0x1) == 0)) {// only draw on even position + img->planes[SWITCH_PLANE_U][y / 2 * img->stride[SWITCH_PLANE_U] + x / 2] = color.u; + img->planes[SWITCH_PLANE_V][y / 2 * img->stride[SWITCH_PLANE_V] + x / 2] = color.v; + } +} static uint8_t scv_art[14][16] = { {0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00}, @@ -185,6 +226,31 @@ SWITCH_DECLARE(void) switch_img_add_text(void *buffer, int w, int x, int y, char } } +SWITCH_DECLARE(void) switch_color_set(switch_yuv_color_t *color, char *color_str) +{ + uint8_t y = 134; + uint8_t u = 128; + uint8_t v = 124; + + if (color_str != NULL && strlen(color_str) == 7) { + uint8_t red, green, blue; + char str[7]; + color_str++; + strncpy(str, color_str, 6); + red = (str[0] >= 'A' ? (str[0] - 'A' + 10) * 16 : (str[0] - '0') * 16) + (str[1] >= 'A' ? (str[1] - 'A' + 10) : (str[0] - '0')); + green = (str[2] >= 'A' ? (str[2] - 'A' + 10) * 16 : (str[2] - '0') * 16) + (str[3] >= 'A' ? (str[3] - 'A' + 10) : (str[0] - '0')); + blue = (str[4] >= 'A' ? (str[4] - 'A' + 10) * 16 : (str[4] - '0') * 16) + (str[5] >= 'A' ? (str[5] - 'A' + 10) : (str[0] - '0')); + + y = (uint8_t)(((red * 4897) >> 14) + ((green * 9611) >> 14) + ((blue * 1876) >> 14)); + u = (uint8_t)(- ((red * 2766) >> 14) - ((5426 * green) >> 14) + blue / 2 + 128); + v = (uint8_t)(red / 2 -((6855 * green) >> 14) - ((blue * 1337) >> 14) + 128); + // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "set color, red = %u, green = %u, blue = %u, y = %u, u = %u, v = %u\n", red, green, blue, y, u, v); + } + + color->y = y; + color->u = u; + color->v = v; +} /* For Emacs: * Local Variables: