diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index ce2476761e..bbe1b6e1f3 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -140,7 +140,7 @@ SWITCH_DECLARE(switch_image_t *)switch_img_wrap(switch_image_t *img, unsigned int d_w, unsigned int d_h, unsigned int align, - unsigned char *img_data); + unsigned char *img_data); /*!\brief Set the rectangle identifying the displayed portion of the image @@ -162,9 +162,34 @@ SWITCH_DECLARE(int) switch_img_set_rect(switch_image_t *img, unsigned int w, unsigned int h); - +/*!\brief patch a small img to a big IMG at position x,y +* +* Both IMG and img must be non-NULL +* +* \param[in] IMG The BIG Image descriptor +* \param[in] img The small Image descriptor +* \param[in] x Leftmost pos to patch to +* \param[in] y Topmost pos to patch to +*/ SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y); + +/*!\brief patch part of a small img (x,y,w,h) to a big IMG at position X,Y +* +* Both IMG and img must be non-NULL +* +* \param[in] IMG The BIG Image descriptor +* \param[in] X Leftmost pos to patch to IMG +* \param[in] Y Topmost pos to patch to IMG +* \param[in] img The small Image descriptor +* \param[in] x Leftmost pos to be read from img +* \param[in] y Topmost pos to be read from +* \param[in] w Max width to be read from img +* \param[in] h Max height to be read from img +*/ + +SWITCH_DECLARE(void) switch_img_patch_rect(switch_image_t *IMG, int X, int Y, switch_image_t *img, uint32_t x, uint32_t y, uint32_t w, uint32_t h); + /*!\brief Copy image to a new image * * if new_img is NULL, a new image is allocated @@ -173,6 +198,7 @@ SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, * else, copy the img data to the new_img * * \param[in] img Image descriptor +* \param[out] new_img New Image descriptor, NULL if out of memory */ SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_img); @@ -184,6 +210,8 @@ SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_i * be referenced upside-down. * * \param[in] img Image descriptor +* +* \return 0 if the requested rectangle is valid, nonzero otherwise. */ SWITCH_DECLARE(void) switch_img_flip(switch_image_t *img); @@ -199,22 +227,104 @@ SWITCH_DECLARE(void) switch_img_draw_text(switch_image_t *IMG, int x, int y, swi 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); +/*!\brief Copy part of an image to a new image +* +* +* \param[in] img Image descriptor +* \param[in] x Leftmost pos to be read from +* \param[in] y Topmost pos to be read from +* \param[in] w Max width to be read from +* \param[in] h Max height to be read from +* +* \return NULL if failed to copy, otherwise a valid image descriptor. +*/ +SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, uint32_t x, uint32_t y, uint32_t w, uint32_t h); +/*!\brief Fill image with color +* +* \param[in] img Image descriptor +* \param[in] x Leftmost pos to be read from +* \param[in] y Topmost pos to be read from +* \param[in] w Max width to be read from +* \param[in] h Max height to be read from +* \param[in] color RGB color +*/ SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color); +/*!\brief Draw a pixel on an image +* +* \param[in] img Image descriptor +* \param[in] x leftmost pos +* \param[in] y topmost pos +* \param[in] color YUV color +*/ SWITCH_DECLARE(void) switch_img_draw_pixel(switch_image_t *img, int x, int y, switch_yuv_color_t *color); +/*!\brief Set RGB color with a string +* +* Color string should be in #RRGGBB format +* +* \param[out] color RGB color pointer +* \param[in] color_str Color string in #RRGGBB format +*/ SWITCH_DECLARE(void) switch_color_set_rgb(switch_rgb_color_t *color, const char *color_str); + +/*!\brief Set YUV color with a string +* +* Color string should be in #RRGGBB format +* +* \param[out] color YUV color pointer +* \param[in] color_str Color string in #RRGGBB format +*/ SWITCH_DECLARE(void) switch_color_set_yuv(switch_yuv_color_t *color, const char *color_str); + +/*!\brief Convert RGB color to YUV +* +* \param[in] rgb RGB color pointer +* \param[out] yuv YUV color pointer +*/ SWITCH_DECLARE(void) switch_color_rgb2yuv(switch_rgb_color_t *rgb, switch_yuv_color_t *yuv); + +/*!\brief Convert YUV color to RGB +* +* \param[in] yuv YUV color pointer +* \param[out] rgb RGB color pointer +*/ SWITCH_DECLARE(void) switch_color_yuv2rgb(switch_yuv_color_t *yuv, switch_rgb_color_t *rgb); +/*!\brief Created a text handle +* +* \param[out] handleP Pointer to the text handle pointer +* \param[in] font_family Font family +* \param[in] font_color Font color in #RRGGBB format +* \param[in] bgcolor Background color in #RRGGBB format +* \param[in] font_size Font size in point +* \param[in] angle Angle to rotate +* \param[in] pool APR memory pool +*/ SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_create(switch_img_txt_handle_t **handleP, const char *font_family, const char *font_color, const char *bgcolor, uint16_t font_size, double angle, switch_memory_pool_t *pool); +/*!\brief Free a text handle +* +* \param[in] handleP Pointer to the text handle pointer +*/ SWITCH_DECLARE(void) switch_img_txt_handle_destroy(switch_img_txt_handle_t **handleP); +/*!\brief Render text to an img +* +* \param[in] handle Pointer to the text handle pointer +* \param[in] img The image to be render text on +* \param[in] x Leftmost position +* \param[in] y Topmost position +* \param[in] text Text to render +* \param[in] font_family Font to use, NULL to use the handle font +* \param[in] font_color Font color, NULL to use the handle color +* \param[in] bgcolor Background color, NULL for transparency +* \param[in] font_size Font size in point +* \param[in] angle Angle to rotate +*/ + SWITCH_DECLARE(switch_status_t) switch_img_txt_handle_render(switch_img_txt_handle_t *handle, switch_image_t *img, int x, int y, const char *text, const char *font_family, const char *font_color, const char *bgcolor, uint16_t font_size, double angle); @@ -232,6 +342,16 @@ SWITCH_DECLARE(void) switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_co SWITCH_DECLARE(void) switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_color_t *rgb, int x, int y); +/*!\brief put a small img over a big IMG at position x,y, with alpha transparency +* +* Both IMG and img must be non-NULL +* +* \param[in] IMG The BIG Image descriptor +* \param[in] img The small Image descriptor +* \param[in] x Leftmost pos +* \param[in] y Topmost pos +* \param[in] alpha Alaha value from 0(completely transparent) to 255(opaque) +*/ SWITCH_DECLARE(void) switch_img_overlay(switch_image_t *IMG, switch_image_t *img, int x, int y, uint8_t alpha); SWITCH_DECLARE(switch_status_t) switch_img_scale(switch_image_t *src, switch_image_t **destP, int width, int height); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index 7f63b675ee..fa305bc3eb 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -121,7 +121,6 @@ SWITCH_DECLARE(void) switch_img_free(switch_image_t **img) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif -// simple implementation to patch a small img to a big IMG at position x,y SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y) { int i, len, max_h; @@ -139,11 +138,11 @@ SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, for (i = 0; i < max_h; i++) { for (j = 0; j < max_w; j++) { - alpha = img->planes[SWITCH_PLANE_PACKED][i * img->d_w * 4 + j * 4]; + alpha = img->planes[SWITCH_PLANE_PACKED][i * img->stride[SWITCH_PLANE_PACKED] + j * 4]; // printf("%d, %d alpha: %d\n", j, i, alpha); if (alpha > 127) { // todo: mux alpha with the underlying pixel ? - rgb_color = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->d_w * 4 + j * 4 + 1); + rgb_color = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->stride[SWITCH_PLANE_PACKED] + j * 4 + 1); switch_color_rgb2yuv(rgb_color, &yuv_color); switch_img_draw_pixel(IMG, x + j, y + i, &yuv_color); } @@ -185,6 +184,32 @@ SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, } } +SWITCH_DECLARE(void) switch_img_patch_rect(switch_image_t *IMG, int X, int Y, switch_image_t *img, uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + switch_image_t *tmp; + uint8_t *data; + + if (x >= img->d_w || y >= img->d_h) return; + + if (!(img->fmt & SWITCH_IMG_FMT_PLANAR)) { + data = img->planes[SWITCH_PLANE_PACKED]; + } else { + data = img->planes[SWITCH_PLANE_Y]; + } + + tmp = (switch_image_t *)vpx_img_wrap(NULL, img->fmt, img->d_w, img->d_h, 1, data); + if (!tmp) return; + + w = MIN(img->d_w - x, w); + h = MIN(img->d_h - y, h); + + if (!switch_img_set_rect(tmp, x, y, w, h)) { + switch_img_patch(IMG, tmp, X, Y); + } + + switch_img_free(&tmp); +} + SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_img) { int i = 0; @@ -216,38 +241,53 @@ SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_i memcpy((*new_img)->planes[SWITCH_PLANE_V] + (*new_img)->stride[SWITCH_PLANE_V] * i, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * i, img->d_w / 2); } } else if (img->fmt == SWITCH_IMG_FMT_ARGB) { - memcpy((*new_img)->planes[SWITCH_PLANE_PACKED], img->planes[SWITCH_PLANE_PACKED], img->d_w * img->d_h * 4); + if (img->stride[SWITCH_PLANE_PACKED] == img->d_w * 4 && + (*new_img)->stride[SWITCH_PLANE_PACKED] == (*new_img)->d_w * 4) { // fast copy + memcpy((*new_img)->planes[SWITCH_PLANE_PACKED], img->planes[SWITCH_PLANE_PACKED], img->d_w * img->d_h * 4); + } else if (img->stride[SWITCH_PLANE_PACKED] > img->d_w * 4) { + uint8_t *dst = (*new_img)->planes[SWITCH_PLANE_PACKED]; + uint8_t *src = img->planes[SWITCH_PLANE_PACKED]; + int i; + + for (i = 0; i < img->d_h; i++) { + memcpy(dst, src, img->d_w * 4); + dst += (*new_img)->stride[SWITCH_PLANE_PACKED]; + src += img->stride[SWITCH_PLANE_PACKED]; + } + } else { //should not happen + abort(); + } } } -SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, int x, int y, int w, int h) +SWITCH_DECLARE(switch_image_t *) switch_img_copy_rect(switch_image_t *img, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { - switch_image_t *new_img = NULL; - int i = 0; - int len; + switch_image_t *new_img = NULL, *tmp; + uint8_t *data; switch_assert(img); - switch_assert(x >= 0 && y >= 0 && w >= 0 && h >= 0); - if (!(img->fmt == SWITCH_IMG_FMT_I420)) return NULL; + if (x >= img->d_w || y >= img->d_h) 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); + if (!(img->fmt & SWITCH_IMG_FMT_PLANAR)) { + data = img->planes[SWITCH_PLANE_PACKED]; + } else { + data = img->planes[SWITCH_PLANE_Y]; } - len /= 2; + tmp = (switch_image_t *)vpx_img_wrap(NULL, img->fmt, img->d_w, img->d_h, 1, data); + if (!tmp) return NULL; - 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); + w = MIN(img->d_w - x, w); + h = MIN(img->d_h - y, h); + + if (!switch_img_set_rect(tmp, x, y, w, h)) { + switch_img_copy(tmp, &new_img); } + + switch_img_free(&tmp); + return new_img; }