FreeSWITCH API Documentation  1.7.0
switch_core_video.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Seven Du <dujinfang@gmail.com>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  * Anthony Minessale II <anthm@freeswitch.org>
26  *
27  *
28  * switch_core_video.c -- Core Video
29  *
30  */
31 
32 #ifdef SWITCH_HAVE_VPX
33 #include "vpx/vpx_image.h"
34 #if VPX_IMAGE_ABI_VERSION != (4)
35 #error VPX_IMAGE_ABI_VERSION is not (4)
36 #endif
37 #endif
38 
39 #include <switch.h>
40 #include <switch_utf8.h>
41 
42 #ifdef SWITCH_HAVE_YUV
43 #include <libyuv.h>
44 #endif
45 
46 // #define HAVE_LIBGD
47 #ifdef HAVE_LIBGD
48 #include <gd.h>
49 #endif
50 
51 #ifdef SWITCH_HAVE_YUV
52 static inline void switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_color_t *yuv, int x, int y);
53 #endif
54 
55 static inline void switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_color_t *rgb, int x, int y);
56 
57 
58 /*!\brief Convert RGB color to YUV
59 *
60 * \param[in] rgb RGB color pointer
61 * \param[out] yuv YUV color pointer
62 */
63 #ifdef SWITCH_HAVE_YUV
64 static inline void switch_color_rgb2yuv(switch_rgb_color_t *rgb, switch_yuv_color_t *yuv);
65 #endif
66 
67 /*!\brief Convert YUV color to RGB
68 *
69 * \param[in] yuv YUV color pointer
70 * \param[out] rgb RGB color pointer
71 */
72 #ifdef SWITCH_HAVE_YUV
73 static inline void switch_color_yuv2rgb(switch_yuv_color_t *yuv, switch_rgb_color_t *rgb);
74 #endif
75 
76 /*!\brief Draw a pixel on an image
77 *
78 * \param[in] img Image descriptor
79 * \param[in] x leftmost pos
80 * \param[in] y topmost pos
81 * \param[in] color RGB color
82 */
83 static inline void switch_img_draw_pixel(switch_image_t *img, int x, int y, switch_rgb_color_t *color);
84 
85 
86 struct pos_el {
88  const char *name;
89 };
90 
91 
92 static struct pos_el POS_TABLE[] = {
93  {POS_LEFT_TOP, "left-top"},
94  {POS_LEFT_MID, "left-mid"},
95  {POS_LEFT_BOT, "left-bot"},
96  {POS_CENTER_TOP, "center-top"},
97  {POS_CENTER_MID, "center-mid"},
98  {POS_CENTER_BOT, "center-bot"},
99  {POS_RIGHT_TOP, "right-top"},
100  {POS_RIGHT_MID, "right-mid"},
101  {POS_RIGHT_BOT, "right-bot"},
102  {POS_NONE, "none"},
103  {POS_NONE, NULL}
104 };
105 
106 
108 {
110  int i;
111 
112  switch_assert(name);
113 
114  for(i = 0; POS_TABLE[i].name; i++) {
115  if (!strcasecmp(POS_TABLE[i].name, name)) {
116  r = POS_TABLE[i].pos;
117  break;
118  }
119  }
120 
121  return r;
122 }
123 
124 
125 struct fit_el {
127  const char *name;
128 };
129 
130 
131 static struct fit_el IMG_FIT_TABLE[] = {
132  {SWITCH_FIT_SIZE, "fit-size"},
133  {SWITCH_FIT_SCALE, "fit-scale"},
134  {SWITCH_FIT_SIZE_AND_SCALE, "fit-size-and-scale"},
135  {SWITCH_FIT_NONE, NULL}
136 };
137 
138 
140 {
142  int i;
143 
144  switch_assert(name);
145 
146  for(i = 0; IMG_FIT_TABLE[i].name; i++) {
147  if (!strcasecmp(IMG_FIT_TABLE[i].name, name)) {
148  r = IMG_FIT_TABLE[i].fit;
149  break;
150  }
151  }
152 
153  return r;
154 }
155 
157 {
158 #ifdef SWITCH_HAVE_VPX
159 #ifdef SWITCH_HAVE_YUV
160  return SWITCH_TRUE;
161 #else
162  return SWITCH_FALSE;
163 #endif
164 #else
165  return SWITCH_FALSE;
166 #endif
167 }
168 
170  switch_img_fmt_t fmt,
171  unsigned int d_w,
172  unsigned int d_h,
173  unsigned int align)
174 {
175 #ifdef SWITCH_HAVE_VPX
176 #ifdef HAVE_LIBGD
177  if (fmt == SWITCH_IMG_FMT_GD) {
178  gdImagePtr gd = gdImageCreateTrueColor(d_w, d_h);
179 
180  if (!gd) return NULL;
181 
182  switch_img_free(&img);
183  img = (switch_image_t *)vpx_img_alloc(NULL, SWITCH_IMG_FMT_ARGB, 1, 1, 1);
184 
185  if (!img) {
186  gdImageDestroy(gd);
187  return NULL;
188  }
189 
190  img->user_priv = gd;
191  img->d_w = d_w;
192  img->d_h = d_h;
193  img->fmt = SWITCH_IMG_FMT_GD;
194  return img;
195  }
196 #endif
197 
198  return (switch_image_t *)vpx_img_alloc((vpx_image_t *)img, (vpx_img_fmt_t)fmt, d_w, d_h, align);
199 #else
200  return NULL;
201 #endif
202 }
203 
205  switch_img_fmt_t fmt,
206  unsigned int d_w,
207  unsigned int d_h,
208  unsigned int align,
209  unsigned char *img_data)
210 {
211 #ifdef SWITCH_HAVE_VPX
212  return (switch_image_t *)vpx_img_wrap((vpx_image_t *)img, (vpx_img_fmt_t)fmt, d_w, d_h, align, img_data);
213 #else
214  return NULL;
215 #endif
216 }
217 
219  unsigned int x,
220  unsigned int y,
221  unsigned int w,
222  unsigned int h)
223 {
224 #ifdef SWITCH_HAVE_VPX
225  return vpx_img_set_rect((vpx_image_t *)img, x, y, w, h);
226 #else
227  return 0;
228 #endif
229 }
230 
232 {
233 #ifdef SWITCH_HAVE_YUV
234  switch_image_t *tmp_img;
235 
236  switch_assert(img);
237 
238 
239  if ((*img)->fmt != SWITCH_IMG_FMT_I420) return;
240 
241  if (mode == SRM_90 || mode == SRM_270) {
242  tmp_img = switch_img_alloc(NULL, (*img)->fmt, (*img)->d_h, (*img)->d_w, 1);
243  } else {
244  tmp_img = switch_img_alloc(NULL, (*img)->fmt, (*img)->d_w, (*img)->d_h, 1);
245  }
246 
247  switch_assert(tmp_img);
248 
249  I420Rotate((*img)->planes[SWITCH_PLANE_Y], (*img)->stride[SWITCH_PLANE_Y],
250  (*img)->planes[SWITCH_PLANE_U], (*img)->stride[SWITCH_PLANE_U],
251  (*img)->planes[SWITCH_PLANE_V], (*img)->stride[SWITCH_PLANE_V],
252  tmp_img->planes[SWITCH_PLANE_Y], tmp_img->stride[SWITCH_PLANE_Y],
253  tmp_img->planes[SWITCH_PLANE_U], tmp_img->stride[SWITCH_PLANE_U],
254  tmp_img->planes[SWITCH_PLANE_V], tmp_img->stride[SWITCH_PLANE_V],
255  (*img)->d_w, (*img)->d_h, (int)mode);
256 
257 
258  switch_img_free(img);
259  *img = tmp_img;
260 
261 #endif
262 }
263 
265 {
266 #ifdef SWITCH_HAVE_VPX
267  if (img && *img) {
268  if ((*img)->fmt == SWITCH_IMG_FMT_GD) {
269 #ifdef HAVE_LIBGD
270  gdImageDestroy((gdImagePtr)(*img)->user_priv);
271 #endif
272  } else {
273  switch_safe_free((*img)->user_priv);
274  }
275  vpx_img_free((vpx_image_t *)*img);
276  *img = NULL;
277  }
278 #endif
279 }
280 
281 #ifndef MIN
282 #define MIN(a,b) ((a) < (b) ? (a) : (b))
283 #endif
284 
285 #ifndef MAX
286 #define MAX(a,b) ((a) > (b) ? (a) : (b))
287 #endif
288 
290 {
291  int i, len, max_h;
292  int xoff = 0, yoff = 0;
293 
294  switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420);
295 
296  if (img->fmt == SWITCH_IMG_FMT_ARGB) {
297  int max_w = MIN(img->d_w, IMG->d_w - abs(x));
298  int max_h = MIN(img->d_h, IMG->d_h - abs(y));
299  int j;
300  uint8_t alpha;
301  switch_rgb_color_t *rgb;
302 
303  for (i = 0; i < max_h; i++) {
304  for (j = 0; j < max_w; j++) {
305  alpha = img->planes[SWITCH_PLANE_PACKED][i * img->stride[SWITCH_PLANE_PACKED] + j * 4];
306 
307  if (alpha > 0) {
308  switch_rgb_color_t RGB = { 0 };
309 
310  switch_img_get_rgb_pixel(IMG, &RGB, x + j, y + i);
311  rgb = (switch_rgb_color_t *)(img->planes[SWITCH_PLANE_PACKED] + i * img->stride[SWITCH_PLANE_PACKED] + j * 4);
312 
313  if (alpha < 255) {
314  RGB.a = 255;
315  RGB.r = ((RGB.r * (255 - alpha)) >> 8) + ((rgb->r * alpha) >> 8);
316  RGB.g = ((RGB.g * (255 - alpha)) >> 8) + ((rgb->g * alpha) >> 8);
317  RGB.b = ((RGB.b * (255 - alpha)) >> 8) + ((rgb->b * alpha) >> 8);
318 
319  switch_img_draw_pixel(IMG, x + j, y + i, &RGB);
320  } else {
321  switch_img_draw_pixel(IMG, x + j, y + i, rgb);
322  }
323  }
324  }
325  }
326 
327  return;
328 
329 #ifdef HAVE_LIBGD
330  } else if (img->fmt == SWITCH_IMG_FMT_GD) {
331  gdImagePtr gd = (gdImagePtr)img->user_priv;
332  switch_rgb_color_t rgb_color;
333  int pixel;
334  int i, j;
335 
336  switch_assert(gd);
337 
338  if (!gd->trueColor) {
339  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "GD is experimental, only true color image is supported\n");
340  return;
341  }
342  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "truecolor: %d alpha: %d, transparent? %d\n", gd->trueColor, gd->saveAlphaFlag, gd->transparent);
343 
344  for(i = 0; i < img->d_h; i++) {
345  for(j = 0; j < img->d_w; j++) {
346  pixel = gd->tpixels[i][j];
347  rgb_color.a = 255; // TODO: handle transparent
348  rgb_color.r = gdTrueColorGetRed(pixel);
349  rgb_color.g = gdTrueColorGetGreen(pixel);
350  rgb_color.b = gdTrueColorGetBlue(pixel);
351  switch_img_draw_pixel(IMG, x + j, y + i, &rgb_color);
352  }
353  }
354 
355  return;
356 #endif
357 
358  }
359 
360  if (x < 0) {
361  xoff = -x;
362  x = 0;
363  }
364 
365  if (y < 0) {
366  yoff = -y;
367  y = 0;
368  }
369 
370  max_h = MIN(y + img->d_h - yoff, IMG->d_h);
371  len = MIN(img->d_w - xoff, IMG->d_w - x);
372 
373 
374  if (x & 0x1) { x++; len--; }
375  if (y & 0x1) y++;
376  if (len <= 0) return;
377 
378  for (i = y; i < max_h; i++) {
379  memcpy(IMG->planes[SWITCH_PLANE_Y] + IMG->stride[SWITCH_PLANE_Y] * i + x, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * (i - y + yoff) + xoff, len);
380  }
381 
382  if ((len & 1) && (x + len) < img->d_w - 1) len++;
383 
384  len /= 2;
385 
386  for (i = y; i < max_h; i += 2) {
387  memcpy(IMG->planes[SWITCH_PLANE_U] + IMG->stride[SWITCH_PLANE_U] * (i / 2) + x / 2, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * ((i - y + yoff) / 2) + xoff / 2, len);
388  memcpy(IMG->planes[SWITCH_PLANE_V] + IMG->stride[SWITCH_PLANE_V] * (i / 2) + x / 2, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * ((i - y + yoff) / 2) + xoff / 2, len);
389  }
390 }
391 
392 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)
393 {
394 #ifdef SWITCH_HAVE_VPX
395  switch_image_t *tmp;
396  uint8_t *data;
397 
398  if (x >= img->d_w || y >= img->d_h) return;
399 
400  if (!(img->fmt & SWITCH_IMG_FMT_PLANAR)) {
401  data = img->planes[SWITCH_PLANE_PACKED];
402  } else {
403  data = img->planes[SWITCH_PLANE_Y];
404  }
405 
406  tmp = (switch_image_t *)vpx_img_wrap(NULL, img->fmt, img->d_w, img->d_h, 1, data);
407  if (!tmp) return;
408 
409  w = MIN(img->d_w - x, w);
410  h = MIN(img->d_h - y, h);
411 
412  if (!switch_img_set_rect(tmp, x, y, w, h)) {
413  switch_img_patch(IMG, tmp, X, Y);
414  }
415 
416  switch_img_free(&tmp);
417 #endif
418 }
419 
421 {
422  switch_assert(img);
423  switch_assert(new_img);
424 
425 #ifdef SWITCH_HAVE_YUV
426  if (img->fmt != SWITCH_IMG_FMT_I420 && img->fmt != SWITCH_IMG_FMT_ARGB) return;
427 
428  if (*new_img != NULL) {
429  if (img->fmt != (*new_img)->fmt || img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_w) {
430  switch_img_free(new_img);
431  }
432  }
433 
434  if (*new_img == NULL) {
435  *new_img = switch_img_alloc(NULL, img->fmt, img->d_w, img->d_h, 1);
436  }
437 
438  switch_assert(*new_img);
439 
440  if (img->fmt == SWITCH_IMG_FMT_I420) {
441  I420Copy(img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
442  img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
443  img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
444  (*new_img)->planes[SWITCH_PLANE_Y], (*new_img)->stride[SWITCH_PLANE_Y],
445  (*new_img)->planes[SWITCH_PLANE_U], (*new_img)->stride[SWITCH_PLANE_U],
446  (*new_img)->planes[SWITCH_PLANE_V], (*new_img)->stride[SWITCH_PLANE_V],
447  img->d_w, img->d_h);
448  } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
449  ARGBCopy(img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED],
450  (*new_img)->planes[SWITCH_PLANE_PACKED], (*new_img)->stride[SWITCH_PLANE_PACKED],
451  img->d_w, img->d_h);
452  }
453 #else
454  return;
455 #endif
456 }
457 
458 
460 {
461  switch_assert(img);
462  switch_assert(new_img);
463 
464 #ifdef SWITCH_HAVE_YUV
465  if (img->fmt != SWITCH_IMG_FMT_I420) abort();
466 
467  if (*new_img != NULL) {
468  if (img->fmt != (*new_img)->fmt || img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_w) {
469  switch_img_free(new_img);
470  }
471  }
472 
473  if (*new_img == NULL) {
474  if (mode == SRM_90 || mode == SRM_270) {
475  *new_img = switch_img_alloc(NULL, img->fmt, img->d_h, img->d_w, 1);
476  } else {
477  *new_img = switch_img_alloc(NULL, img->fmt, img->d_w, img->d_h, 1);
478  }
479  }
480 
481  switch_assert(*new_img);
482 
483 
484  I420Rotate(img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
485  img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
486  img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
487  (*new_img)->planes[SWITCH_PLANE_Y], (*new_img)->stride[SWITCH_PLANE_Y],
488  (*new_img)->planes[SWITCH_PLANE_U], (*new_img)->stride[SWITCH_PLANE_U],
489  (*new_img)->planes[SWITCH_PLANE_V], (*new_img)->stride[SWITCH_PLANE_V],
490  img->d_w, img->d_h, (int)mode);
491 #else
492  return;
493 #endif
494 }
495 
496 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)
497 {
498 #ifdef SWITCH_HAVE_VPX
499  switch_image_t *new_img = NULL, *tmp;
500  uint8_t *data;
501 
502  switch_assert(img);
503 
504  if (x >= img->d_w || y >= img->d_h) return NULL;
505 
506  if (!(img->fmt & SWITCH_IMG_FMT_PLANAR)) {
507  data = img->planes[SWITCH_PLANE_PACKED];
508  } else {
509  data = img->planes[SWITCH_PLANE_Y];
510  }
511 
512  tmp = (switch_image_t *)vpx_img_wrap(NULL, img->fmt, img->d_w, img->d_h, 1, data);
513  if (!tmp) return NULL;
514 
515  w = MIN(img->d_w - x, w);
516  h = MIN(img->d_h - y, h);
517 
518  if (!switch_img_set_rect(tmp, x, y, w, h)) {
519  switch_img_copy(tmp, &new_img);
520  }
521 
522  switch_img_free(&tmp);
523 
524  return new_img;
525 #else
526  return NULL;
527 #endif
528 }
529 
530 static inline void switch_img_draw_pixel(switch_image_t *img, int x, int y, switch_rgb_color_t *color)
531 {
532 #ifdef SWITCH_HAVE_YUV
533  switch_yuv_color_t yuv;
534 
535  if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
536 
537  if (img->fmt == SWITCH_IMG_FMT_I420) {
538  switch_color_rgb2yuv(color, &yuv);
539 
540  img->planes[SWITCH_PLANE_Y][y * img->stride[SWITCH_PLANE_Y] + x] = yuv.y;
541 
542  if (((x & 0x1) == 0) && ((y & 0x1) == 0)) {// only draw on even position
543  img->planes[SWITCH_PLANE_U][y / 2 * img->stride[SWITCH_PLANE_U] + x / 2] = yuv.u;
544  img->planes[SWITCH_PLANE_V][y / 2 * img->stride[SWITCH_PLANE_V] + x / 2] = yuv.v;
545  }
546  } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
547  uint8_t *alpha = img->planes[SWITCH_PLANE_PACKED] + img->d_w * 4 * y + x * 4;
548  *(alpha ) = color->a;
549  *(alpha + 1) = color->r;
550  *(alpha + 2) = color->g;
551  *(alpha + 3) = color->b;
552  }
553 #endif
554 }
555 
556 SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color)
557 {
558 #ifdef SWITCH_HAVE_YUV
559  int len, i, max_h;
560  switch_yuv_color_t yuv_color;
561 
562  if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
563 
564  if (img->fmt == SWITCH_IMG_FMT_I420) {
565  switch_color_rgb2yuv(color, &yuv_color);
566 
567  max_h = MIN(y + h, img->d_h);
568  len = MIN(w, img->d_w - x);
569 
570  if (x & 1) { x++; len--; }
571  if (y & 1) y++;
572  if (len <= 0) return;
573 
574  for (i = y; i < max_h; i++) {
575  memset(img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * i + x, yuv_color.y, len);
576  }
577 
578  if ((len & 1) && (x + len) < img->d_w - 1) len++;
579 
580  len /= 2;
581 
582  for (i = y; i < max_h; i += 2) {
583  memset(img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * (i / 2) + x / 2, yuv_color.u, len);
584  memset(img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * (i / 2) + x / 2, yuv_color.v, len);
585  }
586  } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
587  for (i = 0; i < img->d_w; i++) {
588  *(img->planes[SWITCH_PLANE_PACKED] + i * 4 ) = color->a;
589  *(img->planes[SWITCH_PLANE_PACKED] + i * 4 + 1) = color->r;
590  *(img->planes[SWITCH_PLANE_PACKED] + i * 4 + 2) = color->g;
591  *(img->planes[SWITCH_PLANE_PACKED] + i * 4 + 3) = color->b;
592  }
593 
594  for (i = 1; i < img->d_h; i++) {
595  memcpy( img->planes[SWITCH_PLANE_PACKED] + i * img->d_w * 4,
596  img->planes[SWITCH_PLANE_PACKED], img->d_w * 4);
597  }
598  }
599 #endif
600 }
601 
602 #ifdef SWITCH_HAVE_YUV
603 static inline void switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_color_t *yuv, int x, int y)
604 {
605  // switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
606  if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
607 
608  yuv->y = *(img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * y + x);
609  yuv->u = *(img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * (y / 2) + x / 2);
610  yuv->v = *(img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * (y / 2) + x / 2);
611 }
612 #endif
613 
614 static inline void switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_color_t *rgb, int x, int y)
615 {
616 #ifdef SWITCH_HAVE_YUV
617  if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
618 
619  if (img->fmt == SWITCH_IMG_FMT_I420) {
620  switch_yuv_color_t yuv;
621 
622  switch_img_get_yuv_pixel(img, &yuv, x, y);
623  switch_color_yuv2rgb(&yuv, rgb);
624  } else if (img->fmt == SWITCH_IMG_FMT_ARGB) {
625  uint8_t *a = img->planes[SWITCH_PLANE_PACKED] + img->d_w * 4 * y + 4 * x;
626  rgb->a = *a;
627  rgb->r = *(++a);
628  rgb->g = *(++a);
629  rgb->b = *(++a);
630  }
631 #endif
632 }
633 
634 SWITCH_DECLARE(void) switch_img_overlay(switch_image_t *IMG, switch_image_t *img, int x, int y, uint8_t percent)
635 {
636  int i, j, len, max_h;
637  switch_rgb_color_t RGB = {0}, rgb = {0}, c = {0};
638  int xoff = 0, yoff = 0;
639  uint8_t alpha = (int8_t)((255 * percent) / 100);
640 
641 
642  switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420);
643 
644  if (x < 0) {
645  xoff = -x;
646  x = 0;
647  }
648 
649  if (y < 0) {
650  yoff = -y;
651  y = 0;
652  }
653 
654  max_h = MIN(y + img->d_h - yoff, IMG->d_h);
655  len = MIN(img->d_w - xoff, IMG->d_w - x);
656 
657  if (x & 1) { x++; len--; }
658  if (y & 1) y++;
659  if (len <= 0) return;
660 
661  for (i = y; i < max_h; i++) {
662  for (j = 0; j < len; j++) {
663  switch_img_get_rgb_pixel(IMG, &RGB, x + j, i);
664  switch_img_get_rgb_pixel(img, &rgb, j + xoff, i - y + yoff);
665 
666  if (rgb.a > 0) {
667  c.r = ((RGB.r * (255 - alpha)) >> 8) + ((rgb.r * alpha) >> 8);
668  c.g = ((RGB.g * (255 - alpha)) >> 8) + ((rgb.g * alpha) >> 8);
669  c.b = ((RGB.b * (255 - alpha)) >> 8) + ((rgb.b * alpha) >> 8);
670  } else {
671  c.r = RGB.r;
672  c.g = RGB.g;
673  c.b = RGB.b;
674  }
675 
676  switch_img_draw_pixel(IMG, x + j, i, &c);
677  }
678  }
679 }
680 
681 static uint8_t scv_art[14][16] = {
682  {0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00},
683  {0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00},
684  {0x00, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00},
685  {0x00, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x00},
686  {0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00},
687  {0x00, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x00},
688  {0x00, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00},
689  {0x00, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00},
690  {0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00},
691  {0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7E, 0x00},
692  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}, /*.*/
693  {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*:*/
694  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*-*/
695  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* */
696 };
697 
698 static void scv_tag(void *buffer, int w, int x, int y, uint8_t n)
699 {
700  int i = 0, j=0;
701  uint8_t *p = buffer;
702 
703  if (n > 13) return;
704 
705  for(i=0; i<8; i++) {
706  for (j=0; j<16; j++) {
707  *( p + (y + j) * w + (x + i)) = (scv_art[n][j] & 0x80 >> i) ? 0xFF : 0x00;
708  }
709  }
710 }
711 
712 SWITCH_DECLARE(void) switch_img_add_text(void *buffer, int w, int x, int y, char *s)
713 {
714  while (*s) {
715  int index;
716 
717  if (x > w - 8) break;
718 
719  switch (*s) {
720  case '.': index = 10; break;
721  case ':': index = 11; break;
722  case '-': index = 12; break;
723  case ' ': index = 13; break;
724  default:
725  index = *s - 0x30;
726  }
727 
728  scv_tag(buffer, w, x, y, index);
729  x += 8;
730  s++;
731  }
732 }
733 
735 {
736  if (zstr(str)) return;
737 
738  if ((*str) == '#' && strlen(str) == 7) {
739  unsigned int r, g, b;
740  sscanf(str, "#%02x%02x%02x", &r, &g, &b);
741  color->r = r;
742  color->g = g;
743  color->b = b;
744  } else {
745  if (!strcmp(str, "red")) {
746  color->r = 255;
747  color->g = 0;
748  color->b = 0;
749  } else if (!strcmp(str, "green")) {
750  color->r = 0;
751  color->g = 255;
752  color->b = 0;
753  } else if (!strcmp(str, "blue")) {
754  color->r = 0;
755  color->g = 0;
756  color->b = 255;
757  }
758  }
759 }
760 
761 #ifdef SWITCH_HAVE_YUV
762 static inline void switch_color_rgb2yuv(switch_rgb_color_t *rgb, switch_yuv_color_t *yuv)
763 {
764  yuv->y = (uint8_t)(((rgb->r * 4897) >> 14) + ((rgb->g * 9611) >> 14) + ((rgb->b * 1876) >> 14));
765  yuv->u = (uint8_t)(- ((rgb->r * 2766) >> 14) - ((5426 * rgb->g) >> 14) + rgb->b / 2 + 128);
766  yuv->v = (uint8_t)(rgb->r / 2 -((6855 * rgb->g) >> 14) - ((rgb->b * 1337) >> 14) + 128);
767 }
768 #endif
769 
770 #define CLAMP(val) MAX(0, MIN(val, 255))
771 
772 #ifdef SWITCH_HAVE_YUV
773 static inline void switch_color_yuv2rgb(switch_yuv_color_t *yuv, switch_rgb_color_t *rgb)
774 {
775 #if 0
776  int C = yuv->y - 16;
777  int D = yuv->u - 128;
778  int E = yuv->v - 128;
779 
780  rgb->r = CLAMP((298 * C + 409 * E + 128) >> 8);
781  rgb->g = CLAMP((298 * C - 100 * D - 208 * E + 128) >> 8);
782  rgb->b = CLAMP((298 * C + 516 * D + 128) >> 8);
783 #endif
784 
785  rgb->a = 255;
786  rgb->r = CLAMP( yuv->y + ((22457 * (yuv->v-128)) >> 14));
787  rgb->g = CLAMP((yuv->y - ((715 * (yuv->v-128)) >> 10) - ((5532 * (yuv->u-128)) >> 14)));
788  rgb->b = CLAMP((yuv->y + ((28384 * (yuv->u-128)) >> 14)));
789  }
790 #endif
791 
793 {
794 #ifdef SWITCH_HAVE_YUV
795  switch_rgb_color_t rgb = { 0 };
796 
797  switch_color_set_rgb(&rgb, str);
798  switch_color_rgb2yuv(&rgb, color);
799 #endif
800 }
801 
802 #if SWITCH_HAVE_FREETYPE
803 #include <ft2build.h>
804 #include FT_FREETYPE_H
805 #include FT_GLYPH_H
806 #endif
807 
808 #define MAX_GRADIENT 8
809 
811 #if SWITCH_HAVE_FREETYPE
812  FT_Library library;
813  FT_Face face;
814 #endif
815  char *font_family;
816  double angle;
817  uint16_t font_size;
825 };
826 
828 {
829  int i;
830  switch_rgb_color_t *color;
831 
832  switch_rgb_color_t *c1 = &handle->bgcolor;
833  switch_rgb_color_t *c2 = &handle->color;
834 
835  for (i = 0; i < MAX_GRADIENT; i++) {
836  color = &handle->gradient_table[i];
837  color->r = c1->r + (c2->r - c1->r) * i / MAX_GRADIENT;
838  color->g = c1->g + (c2->g - c1->g) * i / MAX_GRADIENT;
839  color->b = c1->b + (c2->b - c1->b) * i / MAX_GRADIENT;
840  }
841 }
842 
844  const char *font_color, const char *bgcolor, uint16_t font_size, double angle, switch_memory_pool_t *pool)
845 {
846  int free_pool = 0;
847  switch_img_txt_handle_t *new_handle;
848 
849  if (!pool) {
850  free_pool = 1;
852  }
853 
854  new_handle = switch_core_alloc(pool, sizeof(*new_handle));
855 
856 #if SWITCH_HAVE_FREETYPE
857  if (FT_Init_FreeType(&new_handle->library)) {
858  return SWITCH_STATUS_FALSE;
859  }
860 /*#else
861  return SWITCH_STATUS_FALSE; */
862 #endif
863 
864  new_handle->pool = pool;
865  new_handle->free_pool = free_pool;
866 
867  if (zstr(font_family)) {
868  font_family = switch_core_sprintf(new_handle->pool, "%s%s%s",SWITCH_GLOBAL_dirs.fonts_dir, SWITCH_PATH_SEPARATOR, "FreeMono.ttf");
869  }
870 
871  if (!switch_is_file_path(font_family)) {
872  new_handle->font_family = switch_core_sprintf(new_handle->pool, "%s%s%s",SWITCH_GLOBAL_dirs.fonts_dir, SWITCH_PATH_SEPARATOR, font_family);
873  } else {
874  new_handle->font_family = switch_core_strdup(new_handle->pool, font_family);
875  }
876 
877  if (switch_file_exists(new_handle->font_family, new_handle->pool) != SWITCH_STATUS_SUCCESS) {
878  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Font %s does not exist\n", new_handle->font_family);
879  if (free_pool) {
881  }
882  *handleP = NULL;
883  return SWITCH_STATUS_FALSE;
884  }
885 
886  new_handle->font_size = font_size;
887  new_handle->angle = angle;
888 
889  switch_color_set_rgb(&new_handle->color, font_color);
890  switch_color_set_rgb(&new_handle->bgcolor, bgcolor);
891 
892  init_gradient_table(new_handle);
893 
894  *handleP = new_handle;
895 
896  return SWITCH_STATUS_SUCCESS;
897 }
898 
899 
901 {
902  switch_img_txt_handle_t *old_handle;
904 
905  switch_assert(handleP);
906 
907  old_handle = *handleP;
908  *handleP = NULL;
909  if (!old_handle) return;
910 
911 
912 #if SWITCH_HAVE_FREETYPE
913  if (old_handle->library) {
914  FT_Done_FreeType(old_handle->library);
915  old_handle->library = NULL;
916  }
917 #endif
918  pool = old_handle->pool;
919 
920  if (old_handle->free_pool) {
922  pool = NULL;
923  old_handle = NULL;
924  }
925 
926 }
927 
928 #if SWITCH_HAVE_FREETYPE
929 static void draw_bitmap(switch_img_txt_handle_t *handle, switch_image_t *img, FT_Bitmap* bitmap, FT_Int x, FT_Int y)
930 {
931  FT_Int i, j, p, q;
932  FT_Int x_max = x + bitmap->width;
933  FT_Int y_max = y + bitmap->rows;
934 
935  if (bitmap->width == 0) return;
936 
937  switch (bitmap->pixel_mode) {
938  case FT_PIXEL_MODE_GRAY: // it should always be GRAY since we use FT_LOAD_RENDER?
939  break;
940  case FT_PIXEL_MODE_NONE:
941  case FT_PIXEL_MODE_MONO:
942  {
943  for ( j = y, q = 0; j < y_max; j++, q++ ) {
944  for ( i = x, p = 0; i < x_max; i++, p++ ) {
945  uint8_t byte;
946  int linesize = ((bitmap->width - 1) / 8 + 1) * 8;
947 
948  if ( i < 0 || j < 0 || i >= img->d_w || j >= img->d_h) continue;
949 
950  byte = bitmap->buffer[(q * linesize + p) / 8];
951  if ((byte >> (7 - (p % 8))) & 0x1) {
952  switch_img_draw_pixel(img, i, j, &handle->color);
953  }
954  }
955  }
956  return;
957  }
958  case FT_PIXEL_MODE_GRAY2:
959  case FT_PIXEL_MODE_GRAY4:
960  case FT_PIXEL_MODE_LCD:
961  case FT_PIXEL_MODE_LCD_V:
962  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unsupported pixel mode %d\n", bitmap->pixel_mode);
963  return;
964  }
965 
966  for ( i = x, p = 0; i < x_max; i++, p++ ) {
967  for ( j = y, q = 0; j < y_max; j++, q++ ) {
968  int gradient = bitmap->buffer[q * bitmap->width + p];
969  if ( i < 0 || j < 0 || i >= img->d_w || j >= img->d_h) continue;
970 
971  if (handle->use_bgcolor) {
972  switch_img_draw_pixel(img, i, j, &handle->gradient_table[gradient * MAX_GRADIENT / 256]);
973  } else {
974  switch_rgb_color_t rgb_color = {0};
976  switch_img_get_rgb_pixel(img, &rgb_color, i, j);
977 
978  if (rgb_color.a > 0) {
979  c.a = rgb_color.a * gradient / 255;
980  c.r = ((rgb_color.r * (255 - gradient)) >> 8) + ((handle->color.r * gradient) >> 8);
981  c.g = ((rgb_color.g * (255 - gradient)) >> 8) + ((handle->color.g * gradient) >> 8);
982  c.b = ((rgb_color.b * (255 - gradient)) >> 8) + ((handle->color.b * gradient) >> 8);
983  } else {
984  c.a = gradient;
985  c.r = handle->color.r;
986  c.g = handle->color.g;
987  c.b = handle->color.b;
988  }
989 
990  switch_img_draw_pixel(img, i, j, &c);
991  }
992  }
993  }
994 }
995 #endif
996 
997 
999  int x, int y, const char *text,
1000  const char *font_family, const char *font_color,
1001  const char *bgcolor, uint16_t font_size, double angle)
1002 {
1003 #if SWITCH_HAVE_FREETYPE
1004  FT_GlyphSlot slot;
1005  FT_Matrix matrix; /* transformation matrix */
1006  FT_Vector pen; /* untransformed origin */
1007  FT_Error error;
1008  //int target_height;
1009  int index = 0;
1010  FT_ULong ch;
1011  FT_Face face;
1012  uint32_t width = 0;
1013  int this_x = 0, last_x = 0, space = 0;
1014  uint32_t ret;
1015 
1016  if (zstr(text)) return 0;
1017 
1018  if (!handle) return 0;
1019 
1020  switch_assert(!img || img->fmt == SWITCH_IMG_FMT_I420 || img->fmt == SWITCH_IMG_FMT_ARGB);
1021 
1022  if (font_family) {
1023  handle->font_family = switch_core_strdup(handle->pool, font_family);
1024  } else {
1025  font_family = handle->font_family;
1026  }
1027 
1028  if (font_size) {
1029  handle->font_size = font_size;
1030  } else {
1031  font_size = handle->font_size;
1032  }
1033 
1034  if (font_color) {
1035  switch_color_set_rgb(&handle->color, font_color);
1036  }
1037 
1038  if (bgcolor) {
1039  switch_color_set_rgb(&handle->bgcolor, bgcolor);
1040  handle->use_bgcolor = SWITCH_TRUE;
1041  } else {
1042  handle->use_bgcolor = SWITCH_FALSE;
1043  }
1044 
1045  handle->angle = angle;
1046 
1047  //angle = 0; (45.0 / 360 ) * 3.14159 * 2;
1048 
1049  //target_height = img->d_h;
1050 
1051  error = FT_New_Face(handle->library, font_family, 0, &face); /* create face object */
1052  if (error) {
1053  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to open font %s\n", font_family);
1054  return 0;
1055  }
1056 
1057  /* use 50pt at 100dpi */
1058  error = FT_Set_Char_Size(face, 64 * font_size, 0, 96, 96); /* set character size */
1059  if (error) return 0;
1060 
1061  slot = face->glyph;
1062 
1063  if (handle->use_bgcolor && slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO) {
1064  init_gradient_table(handle);
1065  }
1066 
1067  /* set up matrix */
1068  matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
1069  matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
1070  matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
1071  matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
1072 
1073  pen.x = x;
1074  pen.y = y;
1075 
1076  while(*(text + index)) {
1077  ch = switch_u8_get_char((char *)text, &index);
1078 
1079  if (ch == '\n') {
1080  pen.x = x;
1081  pen.y += (font_size + font_size / 4);
1082  continue;
1083  }
1084 
1085  /* set transformation */
1086  FT_Set_Transform(face, &matrix, &pen);
1087 
1088  /* load glyph image into the slot (erase previous one) */
1089  error = FT_Load_Char(face, ch, FT_LOAD_RENDER);
1090 
1091  if (error) continue;
1092 
1093  this_x = pen.x + slot->bitmap_left;
1094 
1095  if (img) {
1096  /* now, draw to our target surface (convert position) */
1097  draw_bitmap(handle, img, &slot->bitmap, this_x, pen.y - slot->bitmap_top + font_size);
1098  }
1099 
1100  if (last_x) {
1101  space = this_x - last_x;
1102  } else {
1103  space = 0;
1104  }
1105 
1106  last_x = this_x;
1107 
1108  width += space;
1109 
1110  /* increment pen position */
1111  pen.x += slot->advance.x >> 6;
1112  pen.y += slot->advance.y >> 6;
1113  }
1114 
1115  ret = width + slot->bitmap.width * 5;
1116 
1117  FT_Done_Face(face);
1118 
1119  return ret;
1120 #else
1121  return 0;
1122 #endif
1123 }
1124 
1126 {
1127  const char *fg ="#cccccc";
1128  const char *bg = "#142e55";
1129  // const char *bg = NULL; // use a NULL bg for transparent
1130  const char *font_face = NULL;
1131  const char *fontsz = "4%";
1132  char *txt = "Value Optimized Out!";
1133  int argc = 0;
1134  char *argv[6] = { 0 };
1135  switch_rgb_color_t bgcolor = { 0 };
1136  int pre_width = 0, width = 0, font_size = 0, height = 0;
1137  int len = 0;
1138  char *duptxt = strdup(text);
1139  switch_img_txt_handle_t *txthandle = NULL;
1140  switch_image_t *txtimg = NULL;
1141  int x = 0, y = 0;
1142 
1143  if (strchr(text, ':')) {
1144  argc = switch_split(duptxt, ':', argv);
1145 
1146  if (argc > 0 && !zstr(argv[0])) {
1147  fg = argv[0];
1148  }
1149 
1150  if (argc > 1 && !zstr(argv[1])) {
1151  bg = argv[1];
1152  }
1153 
1154  if (argc > 2 && !zstr(argv[2])) {
1155  font_face = argv[2];
1156  }
1157 
1158  if (argc > 3 && !zstr(argv[3])) {
1159  fontsz = argv[3];
1160  }
1161 
1162  if (argc > 4) {
1163  txt = argv[4];
1164  }
1165  } else txt = duptxt;
1166 
1167  if (!txt) txt = duptxt;
1168 
1169  if (strrchr(fontsz, '%')) {
1170  font_size = 1 + ((int) (float)h * (atof(fontsz) / 100.0f));
1171  } else {
1172  font_size = atoi(fontsz);
1173  }
1174 
1175  while (*txt == ' ') txt++;
1176  while (end_of(txt) == ' ') end_of(txt) = '\0';
1177 
1178  len = strlen(txt);
1179 
1180  if (len < 5) len = 5;
1181 
1182 
1183  switch_img_txt_handle_create(&txthandle, font_face, fg, bg, font_size, 0, NULL);
1184  switch_color_set_rgb(&bgcolor, bg);
1185 
1186  pre_width = switch_img_txt_handle_render(txthandle,
1187  NULL,
1188  font_size / 2, font_size / 2,
1189  txt, NULL, fg, bg, 0, 0);
1190 
1191  height = font_size * 2;
1192 
1193  if (full && w > width) {
1194  width = w;
1195  } else {
1196  width = pre_width;
1197  }
1198 
1199  if (bg) {
1200  txtimg = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, width, height, 1);
1201  switch_assert(txtimg);
1202  switch_img_fill(txtimg, 0, 0, txtimg->d_w, txtimg->d_h, &bgcolor);
1203  } else {
1204  txtimg = switch_img_alloc(NULL, SWITCH_IMG_FMT_ARGB, width, height, 1);
1205  switch_assert(txtimg);
1206  memset(txtimg->planes[SWITCH_PLANE_PACKED], 0, width * height * 4);
1207  }
1208 
1209  x = font_size / 2;
1210  y = font_size / 2;
1211 
1212  if (full) {
1213  x = (txtimg->d_w / 2) - (pre_width / 2);
1214  }
1215 
1216  switch_img_txt_handle_render(txthandle,
1217  txtimg,
1218  x, y,
1219  txt, NULL, fg, bg, 0, 0);
1220  switch_img_txt_handle_destroy(&txthandle);
1221 
1222  switch_safe_free(duptxt);
1223 
1224  return txtimg;
1225 }
1226 
1227 /* WARNING:
1228  patch a big IMG with a rect hole, note this function is WIP ......
1229  It ONLY works when the hole is INSIDE the big IMG and the place the small img will patch to,
1230  more sanity checks need to be decided
1231 */
1233 {
1234  int i, len;
1235 
1236  switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
1237  switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420);
1238 
1239  len = MIN(img->d_w, IMG->d_w - x);
1240  if (len <= 0) return;
1241 
1242  for (i = y; i < (y + img->d_h) && i < IMG->d_h; i++) {
1243  if (rect && i >= rect->y && i < (rect->y + rect->h)) {
1244  int size = rect->x > x ? rect->x - x : 0;
1245  memcpy(IMG->planes[SWITCH_PLANE_Y] + IMG->stride[SWITCH_PLANE_Y] * i + x, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * (i - y), size);
1246  size = MIN(img->d_w - rect->w - size, IMG->d_w - (rect->x + rect->w));
1247  memcpy(IMG->planes[SWITCH_PLANE_Y] + IMG->stride[SWITCH_PLANE_Y] * i + rect->x + rect->w, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * (i - y) + rect->w + (rect->x - x), size);
1248  } else {
1249  memcpy(IMG->planes[SWITCH_PLANE_Y] + IMG->stride[SWITCH_PLANE_Y] * i + x, img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * (i - y), len);
1250  }
1251  }
1252 
1253  len /= 2;
1254 
1255  for (i = y; i < (y + img->d_h) && i < IMG->d_h; i += 2) {
1256  if (rect && i > rect->y && i < (rect->y + rect->h)) {
1257  int size = rect->x > x ? rect->x - x : 0;
1258 
1259  size /= 2;
1260  memcpy(IMG->planes[SWITCH_PLANE_U] + IMG->stride[SWITCH_PLANE_U] * (i / 2) + x / 2, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * ((i - y) / 2), size);
1261  memcpy(IMG->planes[SWITCH_PLANE_V] + IMG->stride[SWITCH_PLANE_V] * (i / 2) + x / 2, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * ((i - y) / 2), size);
1262  size = MIN(img->d_w - rect->w - size, IMG->d_w - (rect->x + rect->w)) / 2;
1263  memcpy(IMG->planes[SWITCH_PLANE_U] + IMG->stride[SWITCH_PLANE_U] * (i / 2) + (rect->x + rect->w) / 2, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * ((i - y) / 2) + (rect->w + (rect->x - x)) / 2, size);
1264  memcpy(IMG->planes[SWITCH_PLANE_V] + IMG->stride[SWITCH_PLANE_V] * (i / 2) + (rect->x + rect->w) / 2, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * ((i - y) / 2) + (rect->w + (rect->x - x)) / 2, size);
1265  } else {
1266  memcpy(IMG->planes[SWITCH_PLANE_U] + IMG->stride[SWITCH_PLANE_U] * (i / 2) + x / 2, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * ((i - y) / 2), len);
1267  memcpy(IMG->planes[SWITCH_PLANE_V] + IMG->stride[SWITCH_PLANE_V] * (i / 2) + x / 2, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * ((i - y) / 2), len);
1268  }
1269  }
1270 }
1271 
1272 #define SWITCH_IMG_MAX_WIDTH 1920 * 2
1273 #define SWITCH_IMG_MAX_HEIGHT 1080 * 2
1274 
1275 #if !defined(SWITCH_HAVE_YUV)
1276 #undef SWITCH_HAVE_PNG
1277 #endif
1278 
1279 #ifdef SWITCH_HAVE_PNG
1280 // WIP png functions, need furthur tweak/check to make sure it works on all png files and errors are properly detected and reported
1281 // #define PNG_DEBUG 3
1282 #define PNG_SKIP_SETJMP_CHECK
1283 #include <png.h>
1284 
1285 
1286 #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* available from libpng 1.6.0 */
1287 
1288 struct switch_png_opaque_s {
1289  png_image png;
1290  png_bytep buffer;
1291 };
1292 
1293 
1294 
1295 SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char *file_name)
1296 {
1297  switch_png_t *use_png;
1299 
1300  switch_zmalloc(use_png, sizeof(*use_png));
1301  switch_zmalloc(use_png->pvt, sizeof(struct switch_png_opaque_s));
1302  use_png->pvt->png.version = PNG_IMAGE_VERSION;
1303 
1304  if (!png_image_begin_read_from_file(&use_png->pvt->png, file_name)) {
1305  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read PNG %s\n", file_name);
1307  }
1308 
1309  use_png->pvt->png.format = PNG_FORMAT_ARGB;
1310 
1311  use_png->pvt->buffer = malloc(PNG_IMAGE_SIZE(use_png->pvt->png));
1312  switch_assert(use_png->pvt->buffer);
1313 
1314  if (!png_image_finish_read(&use_png->pvt->png, NULL/*background*/, use_png->pvt->buffer, 0, NULL)) {
1315  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read PNG %s\n", file_name);
1317  }
1318 
1319 
1320  use_png->w = use_png->pvt->png.width;
1321  use_png->h = use_png->pvt->png.height;
1322 
1323 end:
1324 
1325  if (status == SWITCH_STATUS_SUCCESS) {
1326  *pngP = use_png;
1327  } else {
1328  switch_png_free(&use_png);
1329  *pngP = NULL;
1330  }
1331 
1332  return status;
1333 }
1334 
1336 {
1337  switch_png_t *use_png;
1338 
1339  if (pngP) {
1340  use_png = *pngP;
1341  *pngP = NULL;
1342  png_image_free(&use_png->pvt->png);
1343  switch_safe_free(use_png->pvt->buffer);
1344  switch_safe_free(use_png->pvt);
1345  switch_safe_free(use_png);
1346  }
1347 }
1348 
1349 
1351 {
1353  switch_rgb_color_t *rgb_color;
1354  uint8_t alpha;
1355  int i, j;
1356 
1357  switch_assert(use_png);
1358 
1359  for (i = 0; i < use_png->pvt->png.height; i++) {
1360  for (j = 0; j < use_png->pvt->png.width; j++) {
1361  //alpha = use_png->pvt->buffer[i * use_png->pvt->png.width * 4 + j * 4 + 3];
1362  alpha = use_png->pvt->buffer[i * use_png->pvt->png.width * 4 + j * 4];
1363  // printf("%d, %d alpha: %d\n", j, i, alpha);
1364 
1365  if (alpha) { // todo, mux alpha with the underlying pixel
1366  rgb_color = (switch_rgb_color_t *)(use_png->pvt->buffer + i * use_png->pvt->png.width * 4 + j * 4);
1367  switch_img_draw_pixel(img, x + j, y + i, rgb_color);
1368  }
1369  }
1370  }
1371 
1372  return status;
1373 }
1374 
1375 #else /* libpng < 1.6.0 */
1376 
1377 SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char *file_name)
1378 {
1379  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT IMPLEMENTED\n");
1380  return SWITCH_STATUS_FALSE;
1381 }
1382 
1384 {
1385  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT IMPLEMENTED\n");
1386 }
1387 
1389 {
1390  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT IMPLEMENTED\n");
1391  return SWITCH_STATUS_FALSE;
1392 }
1393 
1394 #endif
1395 
1396 
1397 #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* available from libpng 1.6.0 */
1398 
1399 SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, switch_img_fmt_t img_fmt)
1400 {
1401  png_image png = { 0 };
1402  png_bytep buffer = NULL;
1403  switch_image_t *img = NULL;
1404 
1405  png.version = PNG_IMAGE_VERSION;
1406 
1407  if (!png_image_begin_read_from_file(&png, file_name)) {
1408  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error open png: %s\n", file_name);
1409  goto err;
1410  }
1411 
1412  if (img_fmt == SWITCH_IMG_FMT_I420) {
1413  png.format = PNG_FORMAT_RGB;
1414  } else if (img_fmt == SWITCH_IMG_FMT_ARGB) {
1415  png.format = PNG_FORMAT_ARGB;
1416  } else {
1417  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unsupported image format: %x\n", img_fmt);
1418  goto err;
1419  }
1420 
1421  buffer = malloc(PNG_IMAGE_SIZE(png));
1422  switch_assert(buffer);
1423 
1424  if (!png_image_finish_read(&png, NULL/*background*/, buffer, 0, NULL)) {
1425  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read png: %s\n", file_name);
1426  goto err;
1427  }
1428 
1429  if (png.width > SWITCH_IMG_MAX_WIDTH || png.height > SWITCH_IMG_MAX_HEIGHT) {
1430  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PNG is too large! %dx%d\n", png.width, png.height);
1431  goto err;
1432  }
1433 
1434  img = switch_img_alloc(NULL, img_fmt, png.width, png.height, 1);
1435  switch_assert(img);
1436 
1437  if (img_fmt == SWITCH_IMG_FMT_I420) {
1438  RAWToI420(buffer, png.width * 3,
1442  png.width, png.height);
1443  } else if (img_fmt == SWITCH_IMG_FMT_ARGB){
1444  ARGBToARGB(buffer, png.width * 4,
1445  img->planes[SWITCH_PLANE_PACKED], png.width * 4,
1446  png.width, png.height);
1447  }
1448 
1449 err:
1450  png_image_free(&png);
1451  switch_safe_free(buffer);
1452  return img;
1453 }
1454 
1455 #else /* libpng < 1.6.0 */
1456 
1457 // ref: most are out-dated, man libpng :)
1458 // http://zarb.org/~gc/html/libpng.html
1459 // http://www.libpng.org/pub/png/book/toc.html
1460 // http://www.vias.org/pngguide/chapter01_03_02.html
1461 // http://www.libpng.org/pub/png/libpng-1.2.5-manual.html
1462 // ftp://ftp.oreilly.com/examples/9781565920583/CDROM/SOFTWARE/SOURCE/LIBPNG/EXAMPLE.C
1463 
1464 SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, switch_img_fmt_t img_fmt)
1465 {
1466  png_byte header[8]; // 8 is the maximum size that can be checked
1467  png_bytep *row_pointers = NULL;
1468  int y;
1469 
1470  int width, height;
1471  png_byte color_type;
1472  png_byte bit_depth;
1473 
1474  png_structp png_ptr = NULL;
1475  png_infop info_ptr = NULL;
1476  //int number_of_passes;
1477  int row_bytes;
1478  png_color_8p sig_bit;
1479 
1480  png_byte *buffer = NULL;
1481  switch_image_t *img = NULL;
1482 
1483  FILE *fp;
1484 
1485  if (img_fmt != SWITCH_IMG_FMT_I420 && img_fmt != SWITCH_IMG_FMT_ARGB) {
1486  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Only ARGB and I420 are supported, you want 0x%x\n", img_fmt);
1487  return NULL;
1488  }
1489 
1490  /* open file and test for it being a png */
1491  fp = fopen(file_name, "rb");
1492  if (!fp) {
1493  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File %s could not be opened for reading\n", file_name);
1494  goto end;
1495  }
1496 
1497  fread(header, 1, 8, fp);
1498  if (png_sig_cmp(header, 0, 8)) {
1499  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File %s is not recognized as a PNG file\n", file_name);
1500  goto end;
1501  }
1502 
1503  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1504  if (!png_ptr) {
1505  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "png_create_read_struct failed\n");
1506  goto end;
1507  }
1508 
1509  info_ptr = png_create_info_struct(png_ptr);
1510  if (!info_ptr) {
1511  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "png_create_info_struct failed\n");
1512  goto end;
1513  }
1514 
1515  if (setjmp(png_jmpbuf(png_ptr))) {
1516  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error during init_io\n");
1517  goto end;
1518  }
1519 
1520  png_init_io(png_ptr, fp);
1521  png_set_sig_bytes(png_ptr, 8);
1522  png_read_info(png_ptr, info_ptr);
1523 
1524  width = png_get_image_width(png_ptr, info_ptr);
1525  height = png_get_image_height(png_ptr, info_ptr);
1526  color_type = png_get_color_type(png_ptr, info_ptr);
1527  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
1528  //number_of_passes = png_set_interlace_handling(png_ptr);
1529 
1530  /* set up the transformations you want. Note that these are
1531  all optional. Only call them if you want them */
1532 
1533  /* expand paletted colors into true rgb */
1534  if (color_type == PNG_COLOR_TYPE_PALETTE) {
1535  png_set_expand(png_ptr);
1536  }
1537 
1538  /* expand grayscale images to the full 8 bits */
1539  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
1540  png_set_expand(png_ptr);
1541  }
1542 
1543  /* expand images with transparency to full alpha channels */
1544  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
1545  png_set_expand(png_ptr);
1546  }
1547 
1548  /* Set the background color to draw transparent and alpha images over */
1549  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
1550  // png_get_bKGD(png_ptr, info_ptr, &my_background);
1551  // png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
1552  } else {
1553  // png_color_16 my_background = { 0 }; //{index,r, g, b, grey}
1554  // png_color_16 my_background = {0, 99, 99, 99, 0};
1555  // png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
1556  }
1557 
1558  /* tell libpng to handle the gamma conversion for you */
1559  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
1560  // png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
1561  } else {
1562  // png_set_gamma(png_ptr, screen_gamma, 0.45);
1563  }
1564 
1565  /* tell libpng to strip 16 bit depth files down to 8 bits */
1566  if (bit_depth == 16) {
1567  png_set_strip_16(png_ptr);
1568  }
1569 
1570 #if 0
1571  /* dither rgb files down to 8 bit palettes & reduce palettes
1572  to the number of colors available on your screen */
1573  if (0 && color_type & PNG_COLOR_MASK_COLOR) {
1574  if (png_get_valid(png_ptr, info_ptr, & PNG_INFO_PLTE)) {
1575  png_set_dither(png_ptr, info_ptr->palette,
1576  info_ptr->num_palette, max_screen_colors,
1577  info_ptr->histogram);
1578  } else {
1579  png_color std_color_cube[MAX_SCREEN_COLORS] =
1580  {/* ... colors ... */};
1581 
1582  png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
1583  MAX_SCREEN_COLORS, NULL);
1584  }
1585  }
1586 #endif
1587 
1588  /* invert monocrome files */
1589  if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
1590  // png_set_invert(png_ptr);
1591  }
1592 
1593  png_get_sBIT(png_ptr, info_ptr, &sig_bit);
1594 
1595  /* shift the pixels down to their true bit depth */
1596  // if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT) && (bit_depth > (*sig_bit).red)) {
1597  // png_set_shift(png_ptr, sig_bit);
1598  // }
1599 
1600  /* pack pixels into bytes */
1601  if (bit_depth < 8) {
1602  png_set_packing(png_ptr);
1603  }
1604 
1605  /* flip the rgb pixels to bgr */
1606  if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
1607  // png_set_bgr(png_ptr);
1608  }
1609 
1610  /* swap bytes of 16 bit files to least significant bit first */
1611  if (bit_depth == 16) {
1612  png_set_swap(png_ptr);
1613  }
1614 
1615  if (0 && color_type & PNG_COLOR_MASK_ALPHA) {
1616  if (setjmp(png_jmpbuf(png_ptr))) {
1618  goto end;
1619  }
1620 
1621  png_set_strip_alpha(png_ptr);
1622  }
1623 
1624  if (setjmp(png_jmpbuf(png_ptr))) {
1625  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Error during read_updated_info\n");
1626  goto end;
1627  }
1628 
1629  if (color_type == PNG_COLOR_TYPE_PALETTE) {
1630  png_set_palette_to_rgb(png_ptr);
1631  }
1632 
1633  png_read_update_info(png_ptr, info_ptr);
1634 
1635  color_type = png_get_color_type(png_ptr, info_ptr);
1636  // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "color_type: 0x%x\n", color_type);
1637 
1638  if (width > SWITCH_IMG_MAX_WIDTH || height > SWITCH_IMG_MAX_HEIGHT) {
1639  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PNG is too large! %dx%d\n", width, height);
1640  }
1641 
1642  row_bytes = png_get_rowbytes(png_ptr, info_ptr);
1643  //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size: %dx%d row_bytes:%d color_type:%d bit_dept:%d\n", width, height, row_bytes, color_type, bit_depth);
1644 
1645  row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
1646  switch_assert(row_pointers);
1647 
1648  buffer = (png_byte *)malloc(row_bytes * height);
1649  switch_assert(buffer);
1650 
1651  for (y = 0; y < height; y++) {
1652  row_pointers[y] = buffer + row_bytes * y;
1653  }
1654 
1655  /* read file */
1656  if (setjmp(png_jmpbuf(png_ptr))) {
1657  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error during read_image");
1658  goto end;
1659  }
1660 
1661  png_read_image(png_ptr, row_pointers);
1662 
1663  if (color_type == PNG_COLOR_TYPE_RGBA) {
1664  if (row_bytes > width * 4) {
1665  for(y = 1; y < height; y++) {
1666  memcpy(buffer + y * width * 4, row_pointers[y], width * 4);
1667  }
1668  }
1669 
1670  img = switch_img_alloc(NULL, img_fmt, width, height, 1);
1671  switch_assert(img);
1672 
1673  if (img_fmt == SWITCH_IMG_FMT_I420) {
1674  ABGRToI420(buffer, width * 4,
1678  width, height);
1679  } else if (img_fmt == SWITCH_IMG_FMT_ARGB) {
1680  ARGBToRGBA(buffer, width * 4,
1681  img->planes[SWITCH_PLANE_PACKED], width * 4,
1682  width, height);
1683  }
1684  } else if (color_type == PNG_COLOR_TYPE_RGB) {
1685  if (row_bytes > width * 3) {
1686  for(y = 1; y < height; y++) {
1687  memcpy(buffer + y * width * 3, row_pointers[y], width * 3);
1688  }
1689  }
1690 
1691  if (img_fmt == SWITCH_IMG_FMT_ARGB) {
1692  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No alpha channel in image [%s], fallback to I420\n", file_name);
1693  img_fmt = SWITCH_IMG_FMT_I420;
1694  }
1695 
1696  img = switch_img_alloc(NULL, img_fmt, width, height, 1);
1697  switch_assert(img);
1698 
1699  RAWToI420(buffer, width * 3,
1703  width, height);
1704  } else {
1705  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unsupported color type: %d\n", png_get_color_type(png_ptr, info_ptr));
1706  }
1707 
1708 end:
1709  switch_safe_free(buffer);
1710  switch_safe_free(row_pointers);
1711  if (fp) fclose(fp);
1712  if (info_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
1713 
1714  return img;
1715 }
1716 
1717 #endif
1718 
1719 
1720 #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED /* available from libpng 1.6.0 */
1721 
1723 {
1724  png_image png = { 0 };
1725  png_bytep buffer = NULL;
1727 
1728  buffer = malloc(img->d_w * img->d_h * 3);
1729  switch_assert(buffer);
1730 
1731  I420ToRAW( img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
1732  img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
1733  img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
1734  buffer, img->d_w * 3,
1735  img->d_w, img->d_h);
1736 
1737  png.version = PNG_IMAGE_VERSION;
1738  png.format = PNG_FORMAT_RGB;
1739  png.width = img->d_w;
1740  png.height = img->d_h;
1741 
1742  if (!png_image_write_to_file(&png, file_name, 0, buffer, 0, NULL)) {
1743  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error write PNG %s\n", file_name);
1744  status = SWITCH_STATUS_FALSE;
1745  }
1746 
1747  switch_safe_free(buffer);
1748  return status;
1749 }
1750 
1751 #else
1752 
1754 {
1755  int width, height;
1756  png_byte color_type;
1757  png_byte bit_depth;
1758  png_structp png_ptr;
1759  png_infop info_ptr;
1760  png_bytep *row_pointers = NULL;
1761  int row_bytes;
1762  int y;
1763  png_byte *buffer = NULL;
1764  FILE *fp = NULL;
1766 
1767  width = img->d_w;
1768  height = img->d_h;
1769  bit_depth = 8;
1770  color_type = PNG_COLOR_TYPE_RGB;
1771 
1772  fp = fopen(file_name, "wb");
1773  if (!fp) {
1774  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File %s could not be opened for writing", file_name);
1775  goto end;
1776  }
1777 
1778  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1779  if (!png_ptr) {
1780  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "png_create_write_struct failed");
1781  goto end;
1782  }
1783 
1784  info_ptr = png_create_info_struct(png_ptr);
1785  if (!info_ptr) {
1786  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "png_create_info_struct failed");
1787  goto end;
1788  }
1789 
1790  if (setjmp(png_jmpbuf(png_ptr))) {
1791  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error during init_io");
1792  goto end;
1793  }
1794 
1795  png_init_io(png_ptr, fp);
1796 
1797  if (setjmp(png_jmpbuf(png_ptr))) {
1798  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error during writing header");
1799  goto end;
1800  }
1801 
1802  png_set_IHDR(png_ptr, info_ptr, width, height,
1803  bit_depth, color_type, PNG_INTERLACE_NONE,
1804  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
1805 
1806  png_write_info(png_ptr, info_ptr);
1807 
1808  row_bytes = png_get_rowbytes(png_ptr, info_ptr);
1809  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size: %dx%d row_bytes:%d color_type:%d bit_dept:%d\n", width, height, row_bytes, color_type, bit_depth);
1810 
1811  row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
1812  switch_assert(row_pointers);
1813 
1814  buffer = (png_byte *)malloc(row_bytes * height);
1815  switch_assert(buffer);
1816 
1817  for (y = 0; y < height; y++) {
1818  row_pointers[y] = buffer + row_bytes * y;
1819  }
1820 
1821  I420ToRAW( img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
1822  img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
1823  img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
1824  buffer, width * 3,
1825  width, height);
1826 
1827  for(y = height - 1; y > 0; y--) {
1828  // todo, check overlaps
1829  memcpy(row_pointers[y], buffer + row_bytes * y, width * 3);
1830  }
1831 
1832  if (setjmp(png_jmpbuf(png_ptr))) {
1833  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error during writing bytes");
1834  goto end;
1835  }
1836 
1837  png_write_image(png_ptr, row_pointers);
1838 
1839  if (setjmp(png_jmpbuf(png_ptr))) {
1840  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error during end of write");
1841  goto end;
1842  }
1843 
1844  png_write_end(png_ptr, NULL);
1845 
1846  status = SWITCH_STATUS_SUCCESS;
1847 
1848 end:
1849 
1850  switch_safe_free(buffer);
1851  switch_safe_free(row_pointers);
1852  fclose(fp);
1853  png_destroy_write_struct(&png_ptr, &info_ptr);
1854 
1855  return status;
1856 }
1857 
1858 #endif
1859 
1860 #else
1861 
1862 SWITCH_DECLARE(switch_status_t) switch_img_patch_png(switch_image_t *img, int x, int y, const char *file_name)
1863 {
1864  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This function is not available, libpng not installed\n");
1865  return SWITCH_STATUS_FALSE;
1866 }
1867 
1869 {
1870  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This function is not available, libpng not installed\n");
1871  return NULL;
1872 }
1873 
1875 {
1876  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This function is not available, libpng not installed\n");
1877  return SWITCH_STATUS_FALSE;
1878 }
1879 
1880 #endif
1881 
1882 SWITCH_DECLARE(switch_status_t) switch_img_letterbox(switch_image_t *img, switch_image_t **imgP, int width, int height, const char *color)
1883 {
1884  int img_w = 0, img_h = 0;
1885  double screen_aspect = 0, img_aspect = 0;
1886  int x_pos = 0;
1887  int y_pos = 0;
1888  switch_image_t *IMG = NULL, *scale_img = NULL;
1889  switch_rgb_color_t bgcolor = { 0 };
1890 
1891  switch_assert(imgP);
1892  *imgP = NULL;
1893 
1894  if (img->d_w == width && img->d_h == height) {
1895  switch_img_copy(img, imgP);
1896  return SWITCH_STATUS_SUCCESS;
1897  }
1898 
1899  IMG = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, width, height, 1);
1900  switch_color_set_rgb(&bgcolor, color);
1901  switch_img_fill(IMG, 0, 0, IMG->d_w, IMG->d_h, &bgcolor);
1902 
1903  img_w = IMG->d_w;
1904  img_h = IMG->d_h;
1905 
1906  screen_aspect = (double) IMG->d_w / IMG->d_h;
1907  img_aspect = (double) img->d_w / img->d_h;
1908 
1909 
1910  if (screen_aspect > img_aspect) {
1911  img_w = img_aspect * IMG->d_h;
1912  x_pos = (IMG->d_w - img_w) / 2;
1913  } else if (screen_aspect < img_aspect) {
1914  img_h = IMG->d_w / img_aspect;
1915  y_pos = (IMG->d_h - img_h) / 2;
1916  }
1917 
1918  switch_img_scale(img, &scale_img, img_w, img_h);
1919  switch_img_patch(IMG, scale_img, x_pos, y_pos);
1920  switch_img_free(&scale_img);
1921 
1922  *imgP = IMG;
1923 
1924  return SWITCH_STATUS_SUCCESS;
1925 }
1926 
1928 {
1929  switch_image_t *src, *tmp = NULL;
1930  int new_w = 0, new_h = 0;
1931 
1932  switch_assert(srcP);
1933  switch_assert(width && height);
1934 
1935  src = *srcP;
1936 
1937  if (!src || (src->d_w == width && src->d_h == height)) {
1938  return SWITCH_STATUS_SUCCESS;
1939  }
1940 
1941  if (fit == SWITCH_FIT_SCALE) {
1942  switch_img_scale(src, &tmp, width, height);
1943  switch_img_free(&src);
1944  *srcP = tmp;
1945  return SWITCH_STATUS_SUCCESS;
1946  }
1947 
1948  new_w = src->d_w;
1949  new_h = src->d_h;
1950 
1951  if (src->d_w < width && src->d_h < height) {
1952  float rw = (float)new_w / width;
1953  float rh = (float)new_h / height;
1954 
1955  if (rw > rh) {
1956  new_h = (int)((float)new_h / rw);
1957  new_w = width;
1958  } else {
1959  new_w = (int)((float)new_w / rh);
1960  new_h = height;
1961  }
1962  } else {
1963  while(new_w > width || new_h > height) {
1964  if (new_w > width) {
1965  double m = (double) width / new_w;
1966  new_w = width;
1967  new_h = (int) (new_h * m);
1968  } else {
1969  double m = (double) height / new_h;
1970  new_h = height;
1971  new_w = (int) (new_w * m);
1972  }
1973  }
1974  }
1975 
1976  if (new_w && new_h) {
1977  if (switch_img_scale(src, &tmp, new_w, new_h) == SWITCH_STATUS_SUCCESS) {
1978  switch_img_free(&src);
1979  *srcP = tmp;
1980 
1981  if (fit == SWITCH_FIT_SIZE_AND_SCALE) {
1982  src = *srcP;
1983  switch_img_scale(src, &tmp, width, height);
1984  switch_img_free(&src);
1985  *srcP = tmp;
1986  }
1987 
1988  return SWITCH_STATUS_SUCCESS;
1989  }
1990  }
1991 
1992  return SWITCH_STATUS_FALSE;
1993 }
1994 
1995 #ifdef SWITCH_HAVE_YUV
1996 static inline uint32_t switch_img_fmt2fourcc(switch_img_fmt_t fmt)
1997 {
1998  uint32_t fourcc;
1999 
2000  switch(fmt) {
2001  case SWITCH_IMG_FMT_NONE: fourcc = FOURCC_ANY ; break;
2002  case SWITCH_IMG_FMT_RGB24: fourcc = FOURCC_24BG; break;
2003  case SWITCH_IMG_FMT_RGB32: fourcc = FOURCC_ANY ; break;
2004  case SWITCH_IMG_FMT_RGB565: fourcc = FOURCC_ANY ; break;
2005  case SWITCH_IMG_FMT_RGB555: fourcc = FOURCC_ANY ; break;
2006  case SWITCH_IMG_FMT_UYVY: fourcc = FOURCC_ANY ; break;
2007  case SWITCH_IMG_FMT_YUY2: fourcc = FOURCC_YUY2; break;
2008  case SWITCH_IMG_FMT_YVYU: fourcc = FOURCC_ANY ; break;
2009  case SWITCH_IMG_FMT_BGR24: fourcc = FOURCC_RAW ; break;
2010  case SWITCH_IMG_FMT_RGB32_LE: fourcc = FOURCC_ANY ; break;
2011  case SWITCH_IMG_FMT_ARGB: fourcc = FOURCC_ANY ; break;
2012  case SWITCH_IMG_FMT_ARGB_LE: fourcc = FOURCC_ANY ; break;
2013  case SWITCH_IMG_FMT_RGB565_LE: fourcc = FOURCC_ANY ; break;
2014  case SWITCH_IMG_FMT_RGB555_LE: fourcc = FOURCC_ANY ; break;
2015  case SWITCH_IMG_FMT_YV12: fourcc = FOURCC_ANY ; break;
2016  case SWITCH_IMG_FMT_I420: fourcc = FOURCC_I420; break;
2017  case SWITCH_IMG_FMT_VPXYV12: fourcc = FOURCC_ANY ; break;
2018  case SWITCH_IMG_FMT_VPXI420: fourcc = FOURCC_ANY ; break;
2019  case SWITCH_IMG_FMT_I422: fourcc = FOURCC_ANY ; break;
2020  case SWITCH_IMG_FMT_I444: fourcc = FOURCC_ANY ; break;
2021  case SWITCH_IMG_FMT_I440: fourcc = FOURCC_ANY ; break;
2022  case SWITCH_IMG_FMT_444A: fourcc = FOURCC_ANY ; break;
2023  case SWITCH_IMG_FMT_I42016: fourcc = FOURCC_ANY ; break;
2024  case SWITCH_IMG_FMT_I42216: fourcc = FOURCC_ANY ; break;
2025  case SWITCH_IMG_FMT_I44416: fourcc = FOURCC_ANY ; break;
2026  case SWITCH_IMG_FMT_I44016: fourcc = FOURCC_ANY ; break;
2027  default: fourcc = FOURCC_ANY;
2028  }
2029 
2030  return fourcc;
2031 }
2032 #endif
2033 
2035 {
2036 #ifdef SWITCH_HAVE_YUV
2037  uint32_t fourcc;
2038  int ret;
2039 
2040  switch_assert(src->fmt == SWITCH_IMG_FMT_I420); // todo: support other formats
2041  switch_assert(dest);
2042 
2043  fourcc = switch_img_fmt2fourcc(fmt);
2044 
2045  if (fourcc == FOURCC_ANY) {
2046  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unsupported format: %d\n", fmt);
2047  return SWITCH_STATUS_FALSE;
2048  }
2049 
2050  ret = ConvertFromI420(src->planes[0], src->stride[0],
2051  src->planes[1], src->stride[1],
2052  src->planes[2], src->stride[2],
2053  dest, size,
2054  src->d_w, src->d_h,
2055  fourcc);
2056 
2057  return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
2058 #else
2059  return SWITCH_STATUS_FALSE;
2060 #endif
2061 }
2062 
2064 {
2065 #ifdef SWITCH_HAVE_YUV
2066  uint32_t fourcc;
2067  int ret;
2068 
2069  fourcc = switch_img_fmt2fourcc(fmt);
2070 
2071  if (fourcc == FOURCC_ANY) {
2072  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unsupported format: %d\n", fmt);
2073  return SWITCH_STATUS_FALSE;
2074  }
2075 
2076  if (!dest && width > 0 && height > 0) dest = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, width, height, 1);
2077  if (!dest) return SWITCH_STATUS_FALSE;
2078 
2079  if (width == 0 || height == 0) {
2080  width = dest->d_w;
2081  height = dest->d_h;
2082  }
2083 
2084 /*
2085  int ConvertToI420(const uint8* src_frame, size_t src_size,
2086  uint8* dst_y, int dst_stride_y,
2087  uint8* dst_u, int dst_stride_u,
2088  uint8* dst_v, int dst_stride_v,
2089  int crop_x, int crop_y,
2090  int src_width, int src_height,
2091  int crop_width, int crop_height,
2092  enum RotationMode rotation,
2093  uint32 format);
2094 
2095  src_size is only used when FOURCC_MJPG which we don't support so always 0
2096 */
2097 
2098  ret = ConvertToI420(src, 0,
2099  dest->planes[0], dest->stride[0],
2100  dest->planes[1], dest->stride[1],
2101  dest->planes[2], dest->stride[2],
2102  0, 0,
2103  width, height,
2104  width, height,
2105  0, fourcc);
2106 
2107  return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
2108 #else
2109  return SWITCH_STATUS_FALSE;
2110 #endif
2111 }
2112 
2114 {
2115 #ifdef SWITCH_HAVE_YUV
2116  switch_image_t *dest = NULL;
2117  int ret = 0;
2118 
2119  if (destP) {
2120  dest = *destP;
2121  }
2122 
2123  if (!dest) dest = switch_img_alloc(NULL, src->fmt, width, height, 1);
2124 
2125  switch_assert(src->fmt == dest->fmt);
2126 
2127  if (src->fmt == SWITCH_IMG_FMT_I420) {
2128  ret = I420Scale(src->planes[0], src->stride[0],
2129  src->planes[1], src->stride[1],
2130  src->planes[2], src->stride[2],
2131  src->d_w, src->d_h,
2132  dest->planes[0], dest->stride[0],
2133  dest->planes[1], dest->stride[1],
2134  dest->planes[2], dest->stride[2],
2135  width, height,
2136  kFilterBox);
2137  } else if (src->fmt == SWITCH_IMG_FMT_ARGB) {
2138  ret = ARGBScale(src->planes[SWITCH_PLANE_PACKED], src->d_w * 4,
2139  src->d_w, src->d_h,
2140  dest->planes[SWITCH_PLANE_PACKED], width * 4,
2141  width, height,
2142  kFilterBox);
2143  }
2144 
2145  if (ret != 0) {
2146  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scaling Error: ret: %d\n", ret);
2147  return SWITCH_STATUS_FALSE;
2148  }
2149 
2150  if (destP) {
2151  *destP = dest;
2152  }
2153 
2154  return SWITCH_STATUS_SUCCESS;
2155 #else
2156  return SWITCH_STATUS_FALSE;
2157 #endif
2158 }
2159 
2160 SWITCH_DECLARE(void) switch_img_find_position(switch_img_position_t pos, int sw, int sh, int iw, int ih, int *xP, int *yP)
2161 {
2162  switch(pos) {
2163  case POS_NONE:
2164  case POS_LEFT_TOP:
2165  *xP = 0;
2166  *yP = 0;
2167  break;
2168  case POS_LEFT_MID:
2169  *xP = 0;
2170  *yP = (sh - ih) / 2;
2171  break;
2172  case POS_LEFT_BOT:
2173  *xP = 0;
2174  *yP = (sh - ih);
2175  break;
2176  case POS_CENTER_TOP:
2177  *xP = (sw - iw) / 2;
2178  *yP = 0;
2179  break;
2180  case POS_CENTER_MID:
2181  *xP = (sw - iw) / 2;
2182  *yP = (sh - ih) / 2;
2183  break;
2184  case POS_CENTER_BOT:
2185  *xP = (sw - iw) / 2;
2186  *yP = (sh - ih);
2187  break;
2188  case POS_RIGHT_TOP:
2189  *xP = (sw - iw);
2190  *yP = 0;
2191  break;
2192  case POS_RIGHT_MID:
2193  *xP = (sw - iw);
2194  *yP = (sh - ih) / 2;
2195  break;
2196  case POS_RIGHT_BOT:
2197  *xP = (sw - iw);
2198  *yP = (sh - ih);
2199  break;
2200  };
2201 
2202 }
2203 
2204 #ifdef HAVE_LIBGD
2205 SWITCH_DECLARE(switch_image_t *) switch_img_read_file(const char* file_name)
2206 {
2207  switch_image_t *img = switch_img_alloc(NULL, SWITCH_IMG_FMT_ARGB, 1, 1, 1);
2208  gdImagePtr gd = NULL;
2209  char *ext;
2210  FILE *fp;
2211 
2212  if (!img) return NULL;
2213 
2214  // gd = gdImageCreateFromFile(file_name); // only available in 2.1.1
2215 
2216  ext = strrchr(file_name, '.');
2217  if (!ext) goto err;
2218 
2219  fp = fopen(file_name, "rb");
2220  if (!fp) goto err;
2221 
2222  if (!strcmp(ext, ".png")) {
2223  gd = gdImageCreateFromPng(fp);
2224  } else if (!strcmp(ext, ".gif")) {
2225  gd = gdImageCreateFromGif(fp);
2226  } else if (!strcmp(ext, ".jpg") || !strcmp(ext, ".jpeg")) {
2227  gd = gdImageCreateFromJpeg(fp);
2228  } else {
2229  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Not supported file type: %s\n", ext);
2230  }
2231 
2232  fclose(fp);
2233  if (!gd) goto err;
2234 
2235  img->fmt = SWITCH_IMG_FMT_GD;
2236  img->d_w = gd->sx;
2237  img->d_h = gd->sy;
2238  img->user_priv = gd;
2239  return img;
2240 
2241 err:
2242  switch_img_free(&img);
2243  return NULL;
2244 }
2245 #else
2247 {
2248  return NULL;
2249 }
2250 #endif
2251 
2252 SWITCH_DECLARE(switch_status_t) switch_I420_copy(const uint8_t *src_y, int src_stride_y,
2253  const uint8_t *src_u, int src_stride_u,
2254  const uint8_t *src_v, int src_stride_v,
2255  uint8_t *dst_y, int dst_stride_y,
2256  uint8_t *dst_u, int dst_stride_u,
2257  uint8_t *dst_v, int dst_stride_v,
2258  int width, int height)
2259 {
2260 #ifdef SWITCH_HAVE_YUV
2261  int ret = I420Copy(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
2262  dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
2263  width, height);
2264  return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
2265 #else
2266  return SWITCH_STATUS_FALSE;
2267 #endif
2268 }
2269 
2270 SWITCH_DECLARE(switch_status_t) switch_I420_copy2(uint8_t *src_planes[], int src_stride[],
2271  uint8_t *dst_planes[], int dst_stride[],
2272  int width, int height)
2273 {
2274 #ifdef SWITCH_HAVE_YUV
2275  int ret = I420Copy(src_planes[SWITCH_PLANE_Y], src_stride[SWITCH_PLANE_Y],
2276  src_planes[SWITCH_PLANE_U], src_stride[SWITCH_PLANE_U],
2277  src_planes[SWITCH_PLANE_V], src_stride[SWITCH_PLANE_V],
2278  dst_planes[SWITCH_PLANE_Y], dst_stride[SWITCH_PLANE_Y],
2279  dst_planes[SWITCH_PLANE_U], dst_stride[SWITCH_PLANE_U],
2280  dst_planes[SWITCH_PLANE_V], dst_stride[SWITCH_PLANE_V],
2281  width, height);
2282  return ret == 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
2283 #else
2284  return SWITCH_STATUS_FALSE;
2285 #endif
2286 }
2287 /* For Emacs:
2288  * Local Variables:
2289  * mode:c
2290  * indent-tabs-mode:t
2291  * tab-width:4
2292  * c-basic-offset:4
2293  * End:
2294  * For VIM:
2295  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
2296  */
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core's master pool.
Definition: switch_core.h:631
void vpx_img_free(vpx_image_t *img)
Close an image descriptor.
Image Descriptor.
Definition: switch_image.h:88
switch_rgb_color_t color
#define SWITCH_CHANNEL_LOG
vpx_image_t * vpx_img_alloc(vpx_image_t *img, vpx_img_fmt_t fmt, unsigned int d_w, unsigned int d_h, unsigned int align)
Open a descriptor, allocating storage for the underlying image.
static struct pos_el POS_TABLE[]
switch_image_t * switch_img_read_file(const char *file_name)
switch_img_position_t pos
#define SWITCH_IMG_FMT_I444
Definition: switch_vpx.h:81
#define SWITCH_IMG_FMT_RGB24
Definition: switch_vpx.h:63
const char * name
switch_image_t * switch_img_write_text_img(int w, int h, switch_bool_t full, const char *text)
int vpx_img_set_rect(vpx_image_t *img, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
Set the rectangle identifying the displayed portion of the image.
#define SWITCH_IMG_MAX_HEIGHT
switch_bool_t
Definition: switch_types.h:405
#define SWITCH_IMG_FMT_VPXYV12
Definition: switch_vpx.h:78
#define switch_core_strdup(_pool, _todup)
Copy a string using memory allocation from a given pool.
Definition: switch_core.h:729
#define switch_split(_data, _delim, _array)
Definition: switch_utils.h:342
#define SWITCH_IMG_FMT_I440
Definition: switch_vpx.h:82
#define SWITCH_IMG_FMT_RGB555
Definition: switch_vpx.h:66
#define switch_core_destroy_memory_pool(p)
Returns a subpool back to the main pool.
Definition: switch_core.h:640
switch_memory_pool_t * pool
void switch_img_rotate_copy(switch_image_t *img, switch_image_t **new_img, switch_image_rotation_mode_t mode)
Representation of a rectangle on a surface.
#define SWITCH_IMG_FMT_YVYU
Definition: switch_vpx.h:69
switch_status_t switch_img_write_png(switch_image_t *img, char *file_name)
#define SWITCH_PLANE_V
Definition: switch_vpx.h:55
#define end_of(_s)
Definition: switch_utils.h:616
#define SWITCH_PLANE_PACKED
Definition: switch_vpx.h:52
void switch_img_copy(switch_image_t *img, switch_image_t **new_img)
Copy image to a new image.
#define SWITCH_IMG_FMT_ARGB
Definition: switch_vpx.h:72
switch_status_t switch_img_fit(switch_image_t **srcP, int width, int height, switch_img_fit_t fit)
#define SWITCH_IMG_FMT_RGB32
Definition: switch_vpx.h:64
switch_image_t * switch_img_read_png(const char *file_name, switch_img_fmt_t img_fmt)
static void scv_tag(void *buffer, int w, int x, int y, uint8_t n)
#define SWITCH_IMG_FMT_I44416
Definition: switch_vpx.h:86
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)
patch part of a small img (x,y,w,h) to a big IMG at position X,Y
switch_img_position_t parse_img_position(const char *name)
void switch_img_free(switch_image_t **img)
Close an image descriptor.
#define SWITCH_IMG_FMT_NONE
Definition: switch_vpx.h:62
void switch_img_txt_handle_destroy(switch_img_txt_handle_t **handleP)
Free a text handle.
void switch_png_free(switch_png_t **pngP)
#define SWITCH_IMG_FMT_YV12
Definition: switch_vpx.h:76
#define zstr(x)
Definition: switch_utils.h:281
vpx_image_t * vpx_img_wrap(vpx_image_t *img, vpx_img_fmt_t fmt, unsigned int d_w, unsigned int d_h, unsigned int align, unsigned char *img_data)
Open a descriptor, using existing storage for the underlying image.
unsigned int d_w
Definition: switch_image.h:99
switch_status_t switch_img_letterbox(switch_image_t *img, switch_image_t **imgP, int width, int height, const char *color)
switch_status_t switch_img_to_raw(switch_image_t *src, void *dest, switch_size_t size, switch_img_fmt_t fmt)
convert img to raw format
#define SWITCH_IMG_FMT_VPXI420
Definition: switch_vpx.h:79
switch_png_opaque_t * pvt
#define SWITCH_IMG_FMT_RGB565_LE
Definition: switch_vpx.h:74
#define SWITCH_IMG_FMT_GD
Definition: switch_vpx.h:89
switch_memory_pool_t * pool
#define SWITCH_PATH_SEPARATOR
Definition: switch_types.h:122
switch_status_t switch_img_patch_png(switch_image_t *img, int x, int y, const char *file_name)
int stride[4]
Definition: switch_image.h:117
switch_img_fit_t
#define switch_core_alloc(_pool, _mem)
Allocate memory directly from a memory pool.
Definition: switch_core.h:682
switch_img_position_t
vpx_img_fmt_t fmt
Definition: switch_image.h:89
#define switch_zmalloc(ptr, len)
unsigned char * planes[4]
Definition: switch_image.h:116
void switch_img_rotate(switch_image_t **img, switch_image_rotation_mode_t mode)
Flip the image vertically (top for bottom)
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:789
switch_byte_t switch_byte_t uint32_t switch_bitpack_mode_t mode
#define SWITCH_IMG_FMT_RGB32_LE
Definition: switch_vpx.h:71
switch_img_fit_t fit
switch_image_t * switch_img_wrap(switch_image_t *img, switch_img_fmt_t fmt, unsigned int d_w, unsigned int d_h, unsigned int align, unsigned char *img_data)
Open a descriptor, using existing storage for the underlying image.
#define SWITCH_IMG_FMT_PLANAR
Definition: switch_vpx.h:47
switch_bool_t switch_core_has_video(void)
#define SWITCH_PLANE_Y
Definition: switch_vpx.h:53
static struct fit_el IMG_FIT_TABLE[]
static void switch_img_draw_pixel(switch_image_t *img, int x, int y, switch_rgb_color_t *color)
Convert RGB color to YUV.
switch_status_t switch_png_patch_img(switch_png_t *use_png, switch_image_t *img, int x, int y)
uintptr_t switch_size_t
uint32_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)
Render text to an img.
int switch_img_set_rect(switch_image_t *img, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
Set the rectangle identifying the displayed portion of the image.
#define CLAMP(val)
vpx_img_fmt_t switch_img_fmt_t
Definition: switch_vpx.h:91
#define SWITCH_IMG_FMT_I42216
Definition: switch_vpx.h:85
static void switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_color_t *rgb, int x, int y)
#define SWITCH_PLANE_U
Definition: switch_vpx.h:54
switch_directories SWITCH_GLOBAL_dirs
Definition: switch_core.c:60
void switch_img_overlay(switch_image_t *IMG, switch_image_t *img, int x, int y, uint8_t percent)
put a small img over a big IMG at position x,y, with alpha transparency
switch_status_t switch_I420_copy2(uint8_t *src_planes[], int src_stride[], uint8_t *dst_planes[], int dst_stride[], int width, int height)
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)
Created a text handle.
switch_status_t switch_file_exists(const char *filename, switch_memory_pool_t *pool)
Definition: switch_apr.c:496
void switch_img_add_text(void *buffer, int w, int x, int y, char *s)
switch_status_t
Common return values.
#define switch_goto_status(_status, _label)
Definition: switch_utils.h:256
static void init_gradient_table(switch_img_txt_handle_t *handle)
#define SWITCH_IMG_FMT_ARGB_LE
Definition: switch_vpx.h:73
static uint8_t scv_art[14][16]
switch_status_t switch_png_open(switch_png_t **pngP, const char *file_name)
switch_status_t switch_img_from_raw(switch_image_t *dest, void *src, switch_img_fmt_t fmt, int width, int height)
convert raw memory to switch_img_t
switch_image_t * switch_img_alloc(switch_image_t *img, switch_img_fmt_t fmt, unsigned int d_w, unsigned int d_h, unsigned int align)
Open a descriptor, allocating storage for the underlying image.
Main Library Header.
static switch_bool_t switch_is_file_path(const char *file)
#define SWITCH_DECLARE(type)
#define SWITCH_IMG_FMT_UYVY
Definition: switch_vpx.h:67
#define SWITCH_IMG_FMT_I420
Definition: switch_vpx.h:77
#define SWITCH_IMG_FMT_I44016
Definition: switch_vpx.h:87
switch_img_fit_t parse_img_fit(const char *name)
#define SWITCH_IMG_FMT_BGR24
Definition: switch_vpx.h:70
switch_status_t switch_img_scale(switch_image_t *src, switch_image_t **destP, int width, int height)
void switch_img_patch_hole(switch_image_t *IMG, switch_image_t *img, int x, int y, switch_image_rect_t *rect)
#define SWITCH_IMG_FMT_RGB555_LE
Definition: switch_vpx.h:75
void switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y)
patch a small img to a big IMG at position x,y
uint32_t switch_u8_get_char(char *s, int *i)
Definition: switch_utf8.c:469
struct apr_pool_t switch_memory_pool_t
#define SWITCH_IMG_FMT_444A
Definition: switch_vpx.h:83
switch_status_t switch_I420_copy(const uint8_t *src_y, int src_stride_y, const uint8_t *src_u, int src_stride_u, const uint8_t *src_v, int src_stride_v, uint8_t *dst_y, int dst_stride_y, uint8_t *dst_u, int dst_stride_u, uint8_t *dst_v, int dst_stride_v, int width, int height)
I420 to I420 Copy.
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
#define SWITCH_IMG_FMT_I42016
Definition: switch_vpx.h:84
void switch_color_set_yuv(switch_yuv_color_t *color, const char *str)
Set YUV color with a string.
switch_image_rotation_mode_t
void * user_priv
Definition: switch_image.h:124
unsigned int d_h
Definition: switch_image.h:100
char * switch_core_sprintf(_In_ switch_memory_pool_t *pool, _In_z_ _Printf_format_string_ const char *fmt,...)
printf-style style printing routine. The data is output to a string allocated from the pool ...
#define switch_assert(expr)
const char * name
#define SWITCH_IMG_FMT_RGB565
Definition: switch_vpx.h:65
void switch_img_find_position(switch_img_position_t pos, int sw, int sh, int iw, int ih, int *xP, int *yP)
#define MAX_GRADIENT
void switch_color_set_rgb(switch_rgb_color_t *color, const char *str)
Set RGB color with a string.
enum vpx_img_fmt vpx_img_fmt_t
List of supported image formats.
memset(buf, 0, buflen)
#define SWITCH_IMG_FMT_I422
Definition: switch_vpx.h:80
#define MIN(a, b)
void switch_img_fill(switch_image_t *img, int x, int y, int w, int h, switch_rgb_color_t *color)
Fill image with color.
#define SWITCH_IMG_MAX_WIDTH
switch_rgb_color_t bgcolor
switch_image_t * switch_img_copy_rect(switch_image_t *img, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
Copy part of an image to a new image.
#define SWITCH_IMG_FMT_YUY2
Definition: switch_vpx.h:68
switch_rgb_color_t gradient_table[MAX_GRADIENT]