31.01.15 23:50, Dan Dennedy написав(ла):
On Thu, Jan 29, 2015 at 8:24 AM, Maksym Veremeyenko <ve...@m1stereo.tv
<mailto:ve...@m1stereo.tv>> wrote:

    Hi,

    attached patch implement caching converted image produced by pango
    producer.


1.) It does not use mlt_cache, which means that if someone uses many
pango producers (perhaps they wrote something to read a subtitle) it
will consumer a lot of memory.

2.)

+// convert
+mlt_frame_get_image( frame, &image, format, &this->cached.width,
&this->cached.height, 0 );

You cannot call mlt_frame_get_image() here to do a conversion like that
because it affects mlt_frame.stack_image. I recall we have done that in
the past, but it caused problems, I think with tractor and/or
transitions (21a3f68). It would take more analysis to determine if it
only affects filters and not producers, but I just prefer to be safe and
use frame->convert_image() instead of this function that potentially
affects the image stack.

3.) +//*format = mlt_image_rgb24a;

Remove commented-out code.

i rewritten a code, please review.

--
________________________________________
Maksym Veremeyenko
>From 8485668ff10f1595a13c3d1f57998f51d3d0b135 Mon Sep 17 00:00:00 2001
From: Maksym Veremeyenko <ve...@m1stereo.tv>
Date: Mon, 2 Feb 2015 20:28:31 +0200
Subject: [PATCH] implement caching images

---
 src/modules/gtk2/factory.c          |    5 ++
 src/modules/gtk2/producer_pango.c   |  130 +++++++++++++++++++++++++++++++++--
 src/modules/gtk2/producer_pango.yml |    3 +
 3 files changed, 131 insertions(+), 7 deletions(-)

diff --git a/src/modules/gtk2/factory.c b/src/modules/gtk2/factory.c
index 90a886d..02ade91 100644
--- a/src/modules/gtk2/factory.c
+++ b/src/modules/gtk2/factory.c
@@ -49,6 +49,11 @@ static void initialise( )
 			mlt_service_cache_set_size( NULL, "pixbuf.alpha", n );
 			mlt_service_cache_set_size( NULL, "pixbuf.pixbuf", n );
 		}
+		if ( getenv("MLT_PANGO_PRODUCER_CACHE") )
+		{
+			int n = atoi( getenv("MLT_PANGO_PRODUCER_CACHE" )  );
+			mlt_service_cache_set_size( NULL, "pango.image", n );
+		}
 	}
 }
 
diff --git a/src/modules/gtk2/producer_pango.c b/src/modules/gtk2/producer_pango.c
index 669d9be..9163a49 100644
--- a/src/modules/gtk2/producer_pango.c
+++ b/src/modules/gtk2/producer_pango.c
@@ -20,6 +20,7 @@
 #include <framework/mlt_producer.h>
 #include <framework/mlt_frame.h>
 #include <framework/mlt_geometry.h>
+#include <framework/mlt_cache.h>
 #include <stdlib.h>
 #include <string.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
@@ -40,6 +41,26 @@ typedef enum
 
 static pthread_mutex_t pango_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+struct pango_cached_image_s
+{
+	uint8_t *image, *alpha;
+	mlt_image_format format;
+	int width, height;
+};
+
+static void pango_cached_image_destroy( void* p )
+{
+	struct pango_cached_image_s* i = p;
+
+	if ( !i )
+		return;
+	if ( i->image )
+		mlt_pool_release( i->image );
+	if ( i->alpha )
+		mlt_pool_release( i->alpha );
+	mlt_pool_release( i );
+};
+
 struct producer_pango_s
 {
 	struct mlt_producer_s parent;
@@ -61,6 +82,11 @@ struct producer_pango_s
 	int   weight;
 };
 
+static void clean_cached( producer_pango self )
+{
+	mlt_service_cache_put( MLT_PRODUCER_SERVICE( &self->parent ), "pango.image", NULL, 0, NULL );
+}
+
 // special color type used by internal pango routines
 typedef struct
 {
@@ -425,6 +451,7 @@ static void refresh_image( mlt_frame frame, int width, int height )
 		if ( this->pixbuf )
 			g_object_unref( this->pixbuf );
 		this->pixbuf = NULL;
+		clean_cached( this );
 
 		// Convert from specified encoding to UTF-8
 		if ( encoding != NULL && !strncaseeq( encoding, "utf-8", 5 ) && !strncaseeq( encoding, "utf8", 4 ) )
@@ -464,6 +491,7 @@ static void refresh_image( mlt_frame frame, int width, int height )
 		if ( this->pixbuf )
 			g_object_unref( this->pixbuf );
 		this->pixbuf = NULL;
+		clean_cached( this );
 		pixbuf = mlt_properties_get_data( producer_props, "pixbuf", NULL );
 	}
 
@@ -484,6 +512,7 @@ static void refresh_image( mlt_frame frame, int width, int height )
 
 		// Note - the original pixbuf is already safe and ready for destruction
 		this->pixbuf = gdk_pixbuf_scale_simple( pixbuf, width, height, interp );
+		clean_cached( this );
 
 		// Store width and height
 		this->width = width;
@@ -515,18 +544,104 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
 	// Get width and height
 	*width = this->width;
 	*height = this->height;
-	*format = mlt_image_rgb24a;
 
 	// Always clone here to allow 'animated' text
 	if ( this->pixbuf )
 	{
-		// Clone the image
-		int image_size = this->width * this->height * 4;
-		*buffer = mlt_pool_alloc( image_size );
-		memcpy( *buffer, gdk_pixbuf_get_pixels( this->pixbuf ), image_size );
+		int size, bpp;
+		uint8_t *buf;
+		mlt_cache_item cached_item = mlt_service_cache_get( MLT_PRODUCER_SERVICE( &this->parent ), "pango.image" );
+		struct pango_cached_image_s* cached = mlt_cache_item_data( cached_item, NULL );
 
-		// Now update properties so we free the copy after
-		mlt_frame_set_image( frame, *buffer, image_size, mlt_pool_release );
+		// destroy cached data if request is differ
+		if ( !cached || ( cached && (cached->format != *format || cached->width != *width || cached->height != *height )))
+		{
+			mlt_cache_item_close( cached_item );
+			cached_item = NULL;
+			cached = NULL;
+			clean_cached( this );
+		};
+
+		// create cached image
+		if ( !cached )
+		{
+			int dst_stride, src_stride;
+
+			cached = mlt_pool_alloc( sizeof( struct pango_cached_image_s ));
+			cached->width = this->width;
+			cached->height = this->height;
+			cached->format = gdk_pixbuf_get_has_alpha( this->pixbuf ) ? mlt_image_rgb24a : mlt_image_rgb24;
+			cached->alpha = NULL;
+			cached->image = NULL;
+
+			src_stride = gdk_pixbuf_get_rowstride( this->pixbuf );
+			dst_stride = this->width * ( mlt_image_rgb24a == cached->format ? 4 : 3 );
+
+			size = dst_stride * ( this->height + 1 );
+			buf = mlt_pool_alloc( size );
+
+			if ( src_stride != dst_stride )
+			{
+				int y = this->height;
+				uint8_t *src = gdk_pixbuf_get_pixels( this->pixbuf );
+				uint8_t *dst = buf;
+				while ( y-- )
+				{
+					memcpy( dst, src, dst_stride );
+					dst += dst_stride;
+					src += src_stride;
+				};
+			}
+			else
+			{
+				memcpy( buf, gdk_pixbuf_get_pixels( this->pixbuf ), src_stride * this->height );
+			};
+
+			// convert image
+			if(frame->convert_image && cached->format != *format)
+			{
+				frame->convert_image( frame, &buf, &cached->format, *format );
+				*format = cached->format;
+			};
+
+			size = mlt_image_format_size(cached->format, cached->width, cached->height, &bpp );
+			cached->image = mlt_pool_alloc( size );
+			memcpy( cached->image, buf, size );
+
+			if ( ( buf = mlt_frame_get_alpha_mask( frame ) ) )
+			{
+				size = cached->width * cached->height;
+				cached->alpha = mlt_pool_alloc( size );
+				memcpy( cached->alpha, buf, size );
+			};
+		};
+
+		if ( cached )
+		{
+			// clone image surface
+			size = mlt_image_format_size(cached->format, cached->width, cached->height, &bpp );
+			buf = mlt_pool_alloc( size );
+			memcpy( buf, cached->image, size );
+
+			// set image surface
+			mlt_frame_set_image( frame, buf, size, mlt_pool_release );
+			*buffer = buf;
+
+			// set alpha
+			if ( cached->alpha )
+			{
+				size = cached->width * cached->height;
+				buf = mlt_pool_alloc( size );
+				memcpy( buf, cached->alpha, size );
+				mlt_frame_set_alpha( frame, buf, size, mlt_pool_release );
+			}
+		};
+
+		if ( cached_item )
+			mlt_cache_item_close( cached_item );
+		else
+			mlt_service_cache_put( MLT_PRODUCER_SERVICE( &this->parent ), "pango.image",
+				cached, sizeof( struct pango_cached_image_s ), pango_cached_image_destroy );
 	}
 	else
 	{
@@ -586,6 +701,7 @@ static void producer_close( mlt_producer parent )
 	producer_pango this = parent->child;
 	if ( this->pixbuf )
 		g_object_unref( this->pixbuf );
+	mlt_service_cache_purge( MLT_PRODUCER_SERVICE(parent) );
 	free( this->fgcolor );
 	free( this->bgcolor );
 	free( this->olcolor );
diff --git a/src/modules/gtk2/producer_pango.yml b/src/modules/gtk2/producer_pango.yml
index fda674f..0096322 100644
--- a/src/modules/gtk2/producer_pango.yml
+++ b/src/modules/gtk2/producer_pango.yml
@@ -23,6 +23,9 @@ notes: >
   whatever the consumer requests. Therefore, it will lose its aspect ratio if 
   so requested, and it is up to the consumer to request a proper width and 
   height that maintains the image aspect.
+  
+  Environment variable MLT_PANGO_PRODUCER_CACHE could be used to override and
+  increase the size of cached converted images of simultaneous use.
 
 parameters:
   - identifier: argument
-- 
1.7.7.6

------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Mlt-devel mailing list
Mlt-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlt-devel

Reply via email to