From 5a95afe50f17eedb34e9a600c052c939de67067e Mon Sep 17 00:00:00 2001
From: Seven Du <dujinfang@x-y-t.cn>
Date: Sat, 25 Apr 2020 17:50:31 +0800
Subject: [PATCH] [core] add switch_img_read_png_from_memory

---
 src/include/switch_core_video.h |  1 +
 src/switch_core_video.c         | 73 ++++++++++++++++++++++-----------
 2 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h
index 340d1fa30a..21e6b77414 100644
--- a/src/include/switch_core_video.h
+++ b/src/include/switch_core_video.h
@@ -390,6 +390,7 @@ SWITCH_DECLARE(void) switch_img_patch_hole(switch_image_t *IMG, switch_image_t *
 
 SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, switch_image_t *img, int x, int y);
 SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char *file_name, switch_img_fmt_t img_fmt);
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png_from_memory(void *mem, size_t size, switch_img_fmt_t img_fmt);
 SWITCH_DECLARE(switch_status_t) switch_img_write_png(switch_image_t *img, char *file_name);
 SWITCH_DECLARE(switch_status_t) switch_png_open(switch_png_t **pngP, const char *file_name);
 SWITCH_DECLARE(void) switch_png_free(switch_png_t **pngP);
diff --git a/src/switch_core_video.c b/src/switch_core_video.c
index 1b39ce46a3..e5b1688db7 100644
--- a/src/switch_core_video.c
+++ b/src/switch_core_video.c
@@ -2412,66 +2412,88 @@ SWITCH_DECLARE(switch_status_t) switch_png_patch_img(switch_png_t *use_png, swit
 
 #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* available from libpng 1.6.0 */
 
-SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, switch_img_fmt_t img_fmt)
+static switch_image_t *png2img(png_image *png, switch_img_fmt_t img_fmt)
 {
-	png_image png = { 0 };
 	png_bytep buffer = NULL;
 	switch_image_t *img = NULL;
 
-	png.version = PNG_IMAGE_VERSION;
-
-	if (!png_image_begin_read_from_file(&png, file_name)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error open png: %s\n", file_name);
-		goto err;
-	}
+	png->version = PNG_IMAGE_VERSION;
 
 	if (img_fmt == SWITCH_IMG_FMT_I420) {
-		png.format = PNG_FORMAT_RGB;
+		png->format = PNG_FORMAT_RGB;
 	} else if (img_fmt == SWITCH_IMG_FMT_ARGB) {
 #if SWITCH_BYTE_ORDER == __BIG_ENDIAN
-		png.format = PNG_FORMAT_ARGB;
+		png->format = PNG_FORMAT_ARGB;
 #else
-		png.format = PNG_FORMAT_BGRA;
+		png->format = PNG_FORMAT_BGRA;
 #endif
 	} else {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unsupported image format: %x\n", img_fmt);
 		goto err;
 	}
 
-	buffer = malloc(PNG_IMAGE_SIZE(png));
+	buffer = malloc(PNG_IMAGE_SIZE(*png));
 	switch_assert(buffer);
 
-	if (!png_image_finish_read(&png, NULL/*background*/, buffer, 0, NULL)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read png: %s\n", file_name);
+	if (!png_image_finish_read(png, NULL/*background*/, buffer, 0, NULL)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error read png\n");
 		goto err;
 	}
 
-	if (png.width > SWITCH_IMG_MAX_WIDTH || png.height > SWITCH_IMG_MAX_HEIGHT) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PNG is too large! %dx%d\n", png.width, png.height);
+	if (png->width > SWITCH_IMG_MAX_WIDTH || png->height > SWITCH_IMG_MAX_HEIGHT) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PNG is too large! %dx%d\n", png->width, png->height);
 		goto err;
 	}
 
-	img = switch_img_alloc(NULL, img_fmt, png.width, png.height, 1);
+	img = switch_img_alloc(NULL, img_fmt, png->width, png->height, 1);
 	switch_assert(img);
 
 	if (img_fmt == SWITCH_IMG_FMT_I420) {
-		RAWToI420(buffer, png.width * 3,
+		RAWToI420(buffer, png->width * 3,
 			img->planes[SWITCH_PLANE_Y], img->stride[SWITCH_PLANE_Y],
 			img->planes[SWITCH_PLANE_U], img->stride[SWITCH_PLANE_U],
 			img->planes[SWITCH_PLANE_V], img->stride[SWITCH_PLANE_V],
-			png.width, png.height);
+			png->width, png->height);
 	} else if (img_fmt == SWITCH_IMG_FMT_ARGB){
-		ARGBCopy(buffer, png.width * 4,
-			img->planes[SWITCH_PLANE_PACKED], png.width * 4,
-			png.width, png.height);
+		ARGBCopy(buffer, png->width * 4,
+			img->planes[SWITCH_PLANE_PACKED], png->width * 4,
+			png->width, png->height);
 	}
 
 err:
-	png_image_free(&png);
+	png_image_free(png);
 	switch_safe_free(buffer);
 	return img;
 }
 
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png(const char* file_name, switch_img_fmt_t img_fmt)
+{
+	png_image png = { 0 };
+
+	png.version = PNG_IMAGE_VERSION;
+
+	if (!png_image_begin_read_from_file(&png, file_name)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error open png: %s\n", file_name);
+		return NULL;
+	}
+
+	return png2img(&png, img_fmt);
+}
+
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png_from_memory(void *mem, size_t size, switch_img_fmt_t img_fmt)
+{
+	png_image png = { 0 };
+
+	png.version = PNG_IMAGE_VERSION;
+
+	if (!png_image_begin_read_from_memory(&png, mem, size)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error open png from memory\n");
+		return NULL;
+	}
+
+	return png2img(&png, img_fmt);
+}
+
 #else /* libpng < 1.6.0 */
 
 // ref: most are out-dated, man libpng :)
@@ -2734,6 +2756,11 @@ end:
 	return img;
 }
 
+SWITCH_DECLARE(switch_image_t *) switch_img_read_png_from_memory(void *mem, size_t size, switch_img_fmt_t img_fmt)
+{
+	return NULL;
+}
+
 #endif
 
 static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)