From 9d64164b417c1d76e6fe06bbaddfa787ec0e8ee9 Mon Sep 17 00:00:00 2001 From: ddennedy Date: Mon, 22 Dec 2003 17:17:53 +0000 Subject: [PATCH] add sample aspect ratio scaling output to producer_pixbuf, fix a bug in rgb to yuv conversions, add producer_pango git-svn-id: https://mlt.svn.sourceforge.net/svnroot/mlt/trunk/mlt@9 d19143bc-622f-0410-bfdd-b5b2a6649095 --- mlt/src/framework/mlt_frame.c | 19 ++ mlt/src/modules/gtk2/Makefile | 7 +- mlt/src/modules/gtk2/factory.c | 3 + mlt/src/modules/gtk2/producer_pango.c | 322 +++++++++++++++++++++++++ mlt/src/modules/gtk2/producer_pango.h | 41 ++++ mlt/src/modules/gtk2/producer_pixbuf.c | 23 +- mlt/src/modules/gtk2/producer_pixbuf.h | 1 + mlt/src/tests/dan.c | 3 +- src/framework/mlt_frame.c | 19 ++ src/modules/gtk2/Makefile | 7 +- src/modules/gtk2/factory.c | 3 + src/modules/gtk2/producer_pango.c | 322 +++++++++++++++++++++++++ src/modules/gtk2/producer_pango.h | 41 ++++ src/modules/gtk2/producer_pixbuf.c | 23 +- src/modules/gtk2/producer_pixbuf.h | 1 + src/tests/dan.c | 3 +- 16 files changed, 828 insertions(+), 10 deletions(-) create mode 100644 mlt/src/modules/gtk2/producer_pango.c create mode 100644 mlt/src/modules/gtk2/producer_pango.h create mode 100644 src/modules/gtk2/producer_pango.c create mode 100644 src/modules/gtk2/producer_pango.h diff --git a/mlt/src/framework/mlt_frame.c b/mlt/src/framework/mlt_frame.c index 9c9eac14..abe88bac 100644 --- a/mlt/src/framework/mlt_frame.c +++ b/mlt/src/framework/mlt_frame.c @@ -309,6 +309,16 @@ int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stri *d++ = y1; *d++ = (v0+v1) >> 1; } + if ( width % 2 ) + { + r = *s++; + g = *s++; + b = *s++; + *alpha++ = *s++; + RGB2YUV (r, g, b, y0, u0 , v0); + *d++ = y0; + *d++ = u0; + } } return ret; } @@ -339,6 +349,15 @@ int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride *d++ = y1; *d++ = (v0+v1) >> 1; } + if ( width % 2 ) + { + r = *s++; + g = *s++; + b = *s++; + RGB2YUV (r, g, b, y0, u0 , v0); + *d++ = y0; + *d++ = u0; + } } return ret; } diff --git a/mlt/src/modules/gtk2/Makefile b/mlt/src/modules/gtk2/Makefile index 17a75ab1..3130918d 100644 --- a/mlt/src/modules/gtk2/Makefile +++ b/mlt/src/modules/gtk2/Makefile @@ -2,11 +2,12 @@ TARGET = ../libmltgtk2.so OBJS = factory.o \ - producer_pixbuf.o + producer_pixbuf.o \ + producer_pango.o -CFLAGS = `pkg-config gdk-pixbuf-2.0 --cflags` -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = `pkg-config gdk-pixbuf-2.0 --cflags` `pkg-config pangoft2 --cflags` -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -LDFLAGS = `pkg-config gdk-pixbuf-2.0 --libs` +LDFLAGS = `pkg-config gdk-pixbuf-2.0 --libs` `pkg-config pangoft2 --libs` SRCS := $(OBJS:.o=.c) diff --git a/mlt/src/modules/gtk2/factory.c b/mlt/src/modules/gtk2/factory.c index fc3a7fa9..38e1692c 100644 --- a/mlt/src/modules/gtk2/factory.c +++ b/mlt/src/modules/gtk2/factory.c @@ -21,11 +21,14 @@ #include #include "producer_pixbuf.h" +#include "producer_pango.h" void *mlt_create_producer( char *id, void *arg ) { if ( !strcmp( id, "pixbuf" ) ) return producer_pixbuf_init( arg ); + else if ( !strcmp( id, "pango" ) ) + return producer_pango_init( arg ); return NULL; } diff --git a/mlt/src/modules/gtk2/producer_pango.c b/mlt/src/modules/gtk2/producer_pango.c new file mode 100644 index 00000000..85b7b396 --- /dev/null +++ b/mlt/src/modules/gtk2/producer_pango.c @@ -0,0 +1,322 @@ +/* + * producer_pango.c -- a pango-based titler + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Dan Dennedy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "producer_pango.h" +#include +#include +#include +#include +#include +#include + +// special color type used by internal pango routines +typedef struct +{ + uint8_t r, g, b, a; +} rgba_color; + +// Forward declarations +static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); +static void producer_close( mlt_producer parent ); +static void pango_draw_background( GdkPixbuf *pixbuf, rgba_color bg ); +static GdkPixbuf *pango_get_pixbuf( const char *markup, rgba_color fg, rgba_color bg, int pad, int align ); + +mlt_producer producer_pango_init( const char *markup ) +{ + producer_pango this = calloc( sizeof( struct producer_pango_s ), 1 ); + if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) + { + mlt_producer producer = &this->parent; + + producer->get_frame = producer_get_frame; + producer->close = producer_close; + + this->markup = strdup( markup ); + this->is_pal = 1; + g_type_init(); + + return producer; + } + free( this ); + return NULL; +} + +static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +{ + // Obtain properties of frame + mlt_properties properties = mlt_frame_properties( this ); + + // May need to know the size of the image to clone it + int size = 0; + + // Get the image + uint8_t *image = mlt_properties_get_data( properties, "image", &size ); + + // Get width and height + *width = mlt_properties_get_int( properties, "width" ); + *height = mlt_properties_get_int( properties, "height" ); + + // Clone if necessary + if ( writable ) + { + // Clone our image + uint8_t *copy = malloc( size ); + memcpy( copy, image, size ); + + // We're going to pass the copy on + image = copy; + + // Now update properties so we free the copy after + mlt_properties_set_data( properties, "image", copy, size, free, NULL ); + } + + // Pass on the image + *buffer = image; + + return 0; +} + +static uint8_t *producer_get_alpha_mask( mlt_frame this ) +{ + // Obtain properties of frame + mlt_properties properties = mlt_frame_properties( this ); + + // Return the alpha mask + return mlt_properties_get_data( properties, "alpha", NULL ); +} + +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) +{ + producer_pango this = producer->child; + GdkPixbuf *pixbuf = NULL; + + // Generate a frame + *frame = mlt_frame_init( ); + + // Obtain properties of frame + mlt_properties properties = mlt_frame_properties( *frame ); + + // optimization for subsequent iterations on single picture + if ( this->image != NULL ) + { + // Set width/height + mlt_properties_set_int( properties, "width", this->width ); + mlt_properties_set_int( properties, "height", this->height ); + + // if picture sequence pass the image and alpha data without destructor + mlt_properties_set_data( properties, "image", this->image, 0, NULL, NULL ); + mlt_properties_set_data( properties, "alpha", this->alpha, 0, NULL, NULL ); + + // Set alpha mask call back + ( *frame )->get_alpha_mask = producer_get_alpha_mask; + + // Stack the get image callback + mlt_frame_push_get_image( *frame, producer_get_image ); + + } + else + { + // the following four will be replaced by properties + rgba_color fg = { 0xff, 0xff, 0xff, 0xff }; + rgba_color bg = { 0, 0, 0, 0x7f }; + int pad = 8; + int align = 0; /* left */ + + // Render the title + pixbuf = pango_get_pixbuf( this->markup, fg, bg, pad, align ); + } + + // If we have a pixbuf + if ( pixbuf ) + { + // Scale to adjust for sample aspect ratio + if ( this->is_pal ) + { + GdkPixbuf *temp = pixbuf; + GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, + (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 54.0/59.0), + gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER ); + pixbuf = scaled; + g_object_unref( temp ); + } + else + { + GdkPixbuf *temp = pixbuf; + GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, + (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 11.0/10.0 ), + gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER ); + pixbuf = scaled; + g_object_unref( temp ); + } + + // Store width and height + this->width = gdk_pixbuf_get_width( pixbuf ); + this->height = gdk_pixbuf_get_height( pixbuf ); + + // Allocate/define image and alpha + uint8_t *image = malloc( this->width * this->height * 2 ); + uint8_t *alpha = NULL; + + // Extract YUV422 and alpha + if ( gdk_pixbuf_get_has_alpha( pixbuf ) ) + { + // Allocate the alpha mask + alpha = malloc( this->width * this->height ); + + // Convert the image + mlt_convert_rgb24a_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ), + this->width, this->height, + gdk_pixbuf_get_rowstride( pixbuf ), + image, alpha ); + } + else + { + // No alpha to extract + mlt_convert_rgb24_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ), + this->width, this->height, + gdk_pixbuf_get_rowstride( pixbuf ), + image ); + } + + // Finished with pixbuf now + g_object_unref( pixbuf ); + + // Set width/height of frame + mlt_properties_set_int( properties, "width", this->width ); + mlt_properties_set_int( properties, "height", this->height ); + + // if single picture, reference the image and alpha in the producer + this->image = image; + this->alpha = alpha; + + // pass the image and alpha data without destructor + mlt_properties_set_data( properties, "image", image, 0, NULL, NULL ); + mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL ); + + // Set alpha call back + ( *frame )->get_alpha_mask = producer_get_alpha_mask; + + // Push the get_image method + mlt_frame_push_get_image( *frame, producer_get_image ); + } + + // Update timecode on the frame we're creating + mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); + + // Calculate the next timecode + mlt_producer_prepare_next( producer ); + + return 0; +} + +static void producer_close( mlt_producer parent ) +{ + producer_pango this = parent->child; + if ( this->markup ) + free( this->markup ); + if ( this->image ) + free( this->image ); + if ( this->alpha ) + free( this->alpha ); + parent->close = NULL; + mlt_producer_close( parent ); + free( this ); +} + +static void pango_draw_background( GdkPixbuf *pixbuf, rgba_color bg ) +{ + int ww = gdk_pixbuf_get_width( pixbuf ); + int hh = gdk_pixbuf_get_height( pixbuf ); + uint8_t *p = gdk_pixbuf_get_pixels( pixbuf ); + int i, j; + + for ( j = 0; j < hh; j++ ) + { + for ( i = 0; i < ww; i++ ) + { + *p++ = bg.r; + *p++ = bg.g; + *p++ = bg.b; + *p++ = bg.a; + } + } +} + +static GdkPixbuf *pango_get_pixbuf( const char *markup, rgba_color fg, rgba_color bg, int pad, int align ) +{ + PangoFT2FontMap *fontmap = (PangoFT2FontMap*) pango_ft2_font_map_new(); + PangoContext *context = pango_ft2_font_map_create_context( fontmap ); + PangoLayout *layout = pango_layout_new( context ); +// PangoFontDescription *font; + int w, h, x; + int i, j; + GdkPixbuf *pixbuf = NULL; + FT_Bitmap bitmap; + uint8_t *src = NULL; + uint8_t* dest = NULL; + int stride; + + pango_ft2_font_map_set_resolution( fontmap, 72, 72 ); + pango_layout_set_width( layout, -1 ); // set wrapping constraints +// pango_layout_set_font_description( layout, "Sans 48" ); +// pango_layout_set_spacing( layout, space ); + pango_layout_set_alignment( layout, ( PangoAlignment ) align ); + pango_layout_set_markup( layout, markup, (markup == NULL ? 0 : strlen( markup ) ) ); + pango_layout_get_pixel_size( layout, &w, &h ); + + pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, TRUE /* has alpha */, 8, w + 2 * pad, h + 2 * pad ); + pango_draw_background( pixbuf, bg ); + + stride = gdk_pixbuf_get_rowstride( pixbuf ); + + bitmap.width = w; + bitmap.pitch = 32 * ( ( w + 31 ) / 31 ); + bitmap.rows = h; + bitmap.buffer = ( unsigned char * ) calloc( 1, h * bitmap.pitch ); + bitmap.num_grays = 256; + bitmap.pixel_mode = ft_pixel_mode_grays; + + pango_ft2_render_layout( &bitmap, layout, 0, 0 ); + + src = bitmap.buffer; + x = ( gdk_pixbuf_get_width( pixbuf ) - w - 2 * pad ) * align / 2 + pad; + dest = gdk_pixbuf_get_pixels( pixbuf ) + 4 * x + pad * stride; + for ( j = 0; j < h; j++ ) + { + uint8_t *d = dest; + for ( i = 0; i < w; i++ ) + { + float a = ( float ) bitmap.buffer[ j * bitmap.pitch + i ] / 255.0; + *d++ = ( int ) ( a * fg.r + ( 1 - a ) * bg.r ); + *d++ = ( int ) ( a * fg.g + ( 1 - a ) * bg.g ); + *d++ = ( int ) ( a * fg.b + ( 1 - a ) * bg.b ); + *d++ = ( int ) ( a * fg.a + ( 1 - a ) * bg.a ); + } + dest += stride; + } + free( bitmap.buffer ); + + g_object_unref( layout ); + g_object_unref( context ); + g_object_unref( fontmap ); + + return pixbuf; +} + diff --git a/mlt/src/modules/gtk2/producer_pango.h b/mlt/src/modules/gtk2/producer_pango.h new file mode 100644 index 00000000..f067e7cc --- /dev/null +++ b/mlt/src/modules/gtk2/producer_pango.h @@ -0,0 +1,41 @@ +/* + * producer_pango.h -- a pango-based titler + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Dan Dennedy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _PRODUCER_PANGO_H_ +#define _PRODUCER_PANGO_H_ + +#include + +typedef struct producer_pango_s *producer_pango; + +struct producer_pango_s +{ + struct mlt_producer_s parent; + char *markup; + int width; + int height; + uint8_t *image; + uint8_t *alpha; + int is_pal; +}; + +extern mlt_producer producer_pango_init( const char *markup ); + +#endif diff --git a/mlt/src/modules/gtk2/producer_pixbuf.c b/mlt/src/modules/gtk2/producer_pixbuf.c index 8a74a468..1ba370f9 100644 --- a/mlt/src/modules/gtk2/producer_pixbuf.c +++ b/mlt/src/modules/gtk2/producer_pixbuf.c @@ -40,6 +40,7 @@ mlt_producer producer_pixbuf_init( const char *filename ) this->filename = strdup( filename ); this->counter = -1; + this->is_pal = 1; g_type_init(); return producer; @@ -83,7 +84,7 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma return 0; } -uint8_t *producer_get_alpha_mask( mlt_frame this ) +static uint8_t *producer_get_alpha_mask( mlt_frame this ) { // Obtain properties of frame mlt_properties properties = mlt_frame_properties( this ); @@ -145,6 +146,26 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // If we have a pixbuf if ( pixbuf ) { + // Scale to adjust for sample aspect ratio + if ( this->is_pal ) + { + GdkPixbuf *temp = pixbuf; + GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, + (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 54.0/59.0), + gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER ); + pixbuf = scaled; + g_object_unref( temp ); + } + else + { + GdkPixbuf *temp = pixbuf; + GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, + (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 11.0/10.0 ), + gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER ); + pixbuf = scaled; + g_object_unref( temp ); + } + // Store width and height this->width = gdk_pixbuf_get_width( pixbuf ); this->height = gdk_pixbuf_get_height( pixbuf ); diff --git a/mlt/src/modules/gtk2/producer_pixbuf.h b/mlt/src/modules/gtk2/producer_pixbuf.h index c7f76ef3..04fb2f41 100644 --- a/mlt/src/modules/gtk2/producer_pixbuf.h +++ b/mlt/src/modules/gtk2/producer_pixbuf.h @@ -34,6 +34,7 @@ struct producer_pixbuf_s int height; uint8_t *image; uint8_t *alpha; + int is_pal; }; extern mlt_producer producer_pixbuf_init( const char *filename ); diff --git a/mlt/src/tests/dan.c b/mlt/src/tests/dan.c index e8d61263..cdd1b866 100644 --- a/mlt/src/tests/dan.c +++ b/mlt/src/tests/dan.c @@ -23,7 +23,8 @@ int main( int argc, char **argv ) mlt_producer dv1 = mlt_factory_producer( "libdv", file1 ); //mlt_producer dv1 = producer_pixbuf_init( file1 ); //mlt_producer dv2 = producer_libdv_init( file2 ); - mlt_producer dv2 = mlt_factory_producer( "pixbuf", file2 ); + //mlt_producer dv2 = mlt_factory_producer( "pixbuf", file2 ); + mlt_producer dv2 = mlt_factory_producer( "pango", "Mutton Lettuce Tomato" ); // Register producers(s) with a multitrack object mlt_multitrack multitrack = mlt_multitrack_init( ); diff --git a/src/framework/mlt_frame.c b/src/framework/mlt_frame.c index 9c9eac14..abe88bac 100644 --- a/src/framework/mlt_frame.c +++ b/src/framework/mlt_frame.c @@ -309,6 +309,16 @@ int mlt_convert_rgb24a_to_yuv422( uint8_t *rgba, int width, int height, int stri *d++ = y1; *d++ = (v0+v1) >> 1; } + if ( width % 2 ) + { + r = *s++; + g = *s++; + b = *s++; + *alpha++ = *s++; + RGB2YUV (r, g, b, y0, u0 , v0); + *d++ = y0; + *d++ = u0; + } } return ret; } @@ -339,6 +349,15 @@ int mlt_convert_rgb24_to_yuv422( uint8_t *rgb, int width, int height, int stride *d++ = y1; *d++ = (v0+v1) >> 1; } + if ( width % 2 ) + { + r = *s++; + g = *s++; + b = *s++; + RGB2YUV (r, g, b, y0, u0 , v0); + *d++ = y0; + *d++ = u0; + } } return ret; } diff --git a/src/modules/gtk2/Makefile b/src/modules/gtk2/Makefile index 17a75ab1..3130918d 100644 --- a/src/modules/gtk2/Makefile +++ b/src/modules/gtk2/Makefile @@ -2,11 +2,12 @@ TARGET = ../libmltgtk2.so OBJS = factory.o \ - producer_pixbuf.o + producer_pixbuf.o \ + producer_pango.o -CFLAGS = `pkg-config gdk-pixbuf-2.0 --cflags` -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread +CFLAGS = `pkg-config gdk-pixbuf-2.0 --cflags` `pkg-config pangoft2 --cflags` -I../../ -Wall -g -D_FILE_OFFSET_BITS=64 -pthread -LDFLAGS = `pkg-config gdk-pixbuf-2.0 --libs` +LDFLAGS = `pkg-config gdk-pixbuf-2.0 --libs` `pkg-config pangoft2 --libs` SRCS := $(OBJS:.o=.c) diff --git a/src/modules/gtk2/factory.c b/src/modules/gtk2/factory.c index fc3a7fa9..38e1692c 100644 --- a/src/modules/gtk2/factory.c +++ b/src/modules/gtk2/factory.c @@ -21,11 +21,14 @@ #include #include "producer_pixbuf.h" +#include "producer_pango.h" void *mlt_create_producer( char *id, void *arg ) { if ( !strcmp( id, "pixbuf" ) ) return producer_pixbuf_init( arg ); + else if ( !strcmp( id, "pango" ) ) + return producer_pango_init( arg ); return NULL; } diff --git a/src/modules/gtk2/producer_pango.c b/src/modules/gtk2/producer_pango.c new file mode 100644 index 00000000..85b7b396 --- /dev/null +++ b/src/modules/gtk2/producer_pango.c @@ -0,0 +1,322 @@ +/* + * producer_pango.c -- a pango-based titler + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Dan Dennedy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "producer_pango.h" +#include +#include +#include +#include +#include +#include + +// special color type used by internal pango routines +typedef struct +{ + uint8_t r, g, b, a; +} rgba_color; + +// Forward declarations +static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ); +static void producer_close( mlt_producer parent ); +static void pango_draw_background( GdkPixbuf *pixbuf, rgba_color bg ); +static GdkPixbuf *pango_get_pixbuf( const char *markup, rgba_color fg, rgba_color bg, int pad, int align ); + +mlt_producer producer_pango_init( const char *markup ) +{ + producer_pango this = calloc( sizeof( struct producer_pango_s ), 1 ); + if ( this != NULL && mlt_producer_init( &this->parent, this ) == 0 ) + { + mlt_producer producer = &this->parent; + + producer->get_frame = producer_get_frame; + producer->close = producer_close; + + this->markup = strdup( markup ); + this->is_pal = 1; + g_type_init(); + + return producer; + } + free( this ); + return NULL; +} + +static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +{ + // Obtain properties of frame + mlt_properties properties = mlt_frame_properties( this ); + + // May need to know the size of the image to clone it + int size = 0; + + // Get the image + uint8_t *image = mlt_properties_get_data( properties, "image", &size ); + + // Get width and height + *width = mlt_properties_get_int( properties, "width" ); + *height = mlt_properties_get_int( properties, "height" ); + + // Clone if necessary + if ( writable ) + { + // Clone our image + uint8_t *copy = malloc( size ); + memcpy( copy, image, size ); + + // We're going to pass the copy on + image = copy; + + // Now update properties so we free the copy after + mlt_properties_set_data( properties, "image", copy, size, free, NULL ); + } + + // Pass on the image + *buffer = image; + + return 0; +} + +static uint8_t *producer_get_alpha_mask( mlt_frame this ) +{ + // Obtain properties of frame + mlt_properties properties = mlt_frame_properties( this ); + + // Return the alpha mask + return mlt_properties_get_data( properties, "alpha", NULL ); +} + +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) +{ + producer_pango this = producer->child; + GdkPixbuf *pixbuf = NULL; + + // Generate a frame + *frame = mlt_frame_init( ); + + // Obtain properties of frame + mlt_properties properties = mlt_frame_properties( *frame ); + + // optimization for subsequent iterations on single picture + if ( this->image != NULL ) + { + // Set width/height + mlt_properties_set_int( properties, "width", this->width ); + mlt_properties_set_int( properties, "height", this->height ); + + // if picture sequence pass the image and alpha data without destructor + mlt_properties_set_data( properties, "image", this->image, 0, NULL, NULL ); + mlt_properties_set_data( properties, "alpha", this->alpha, 0, NULL, NULL ); + + // Set alpha mask call back + ( *frame )->get_alpha_mask = producer_get_alpha_mask; + + // Stack the get image callback + mlt_frame_push_get_image( *frame, producer_get_image ); + + } + else + { + // the following four will be replaced by properties + rgba_color fg = { 0xff, 0xff, 0xff, 0xff }; + rgba_color bg = { 0, 0, 0, 0x7f }; + int pad = 8; + int align = 0; /* left */ + + // Render the title + pixbuf = pango_get_pixbuf( this->markup, fg, bg, pad, align ); + } + + // If we have a pixbuf + if ( pixbuf ) + { + // Scale to adjust for sample aspect ratio + if ( this->is_pal ) + { + GdkPixbuf *temp = pixbuf; + GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, + (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 54.0/59.0), + gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER ); + pixbuf = scaled; + g_object_unref( temp ); + } + else + { + GdkPixbuf *temp = pixbuf; + GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, + (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 11.0/10.0 ), + gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER ); + pixbuf = scaled; + g_object_unref( temp ); + } + + // Store width and height + this->width = gdk_pixbuf_get_width( pixbuf ); + this->height = gdk_pixbuf_get_height( pixbuf ); + + // Allocate/define image and alpha + uint8_t *image = malloc( this->width * this->height * 2 ); + uint8_t *alpha = NULL; + + // Extract YUV422 and alpha + if ( gdk_pixbuf_get_has_alpha( pixbuf ) ) + { + // Allocate the alpha mask + alpha = malloc( this->width * this->height ); + + // Convert the image + mlt_convert_rgb24a_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ), + this->width, this->height, + gdk_pixbuf_get_rowstride( pixbuf ), + image, alpha ); + } + else + { + // No alpha to extract + mlt_convert_rgb24_to_yuv422( gdk_pixbuf_get_pixels( pixbuf ), + this->width, this->height, + gdk_pixbuf_get_rowstride( pixbuf ), + image ); + } + + // Finished with pixbuf now + g_object_unref( pixbuf ); + + // Set width/height of frame + mlt_properties_set_int( properties, "width", this->width ); + mlt_properties_set_int( properties, "height", this->height ); + + // if single picture, reference the image and alpha in the producer + this->image = image; + this->alpha = alpha; + + // pass the image and alpha data without destructor + mlt_properties_set_data( properties, "image", image, 0, NULL, NULL ); + mlt_properties_set_data( properties, "alpha", alpha, 0, NULL, NULL ); + + // Set alpha call back + ( *frame )->get_alpha_mask = producer_get_alpha_mask; + + // Push the get_image method + mlt_frame_push_get_image( *frame, producer_get_image ); + } + + // Update timecode on the frame we're creating + mlt_frame_set_timecode( *frame, mlt_producer_position( producer ) ); + + // Calculate the next timecode + mlt_producer_prepare_next( producer ); + + return 0; +} + +static void producer_close( mlt_producer parent ) +{ + producer_pango this = parent->child; + if ( this->markup ) + free( this->markup ); + if ( this->image ) + free( this->image ); + if ( this->alpha ) + free( this->alpha ); + parent->close = NULL; + mlt_producer_close( parent ); + free( this ); +} + +static void pango_draw_background( GdkPixbuf *pixbuf, rgba_color bg ) +{ + int ww = gdk_pixbuf_get_width( pixbuf ); + int hh = gdk_pixbuf_get_height( pixbuf ); + uint8_t *p = gdk_pixbuf_get_pixels( pixbuf ); + int i, j; + + for ( j = 0; j < hh; j++ ) + { + for ( i = 0; i < ww; i++ ) + { + *p++ = bg.r; + *p++ = bg.g; + *p++ = bg.b; + *p++ = bg.a; + } + } +} + +static GdkPixbuf *pango_get_pixbuf( const char *markup, rgba_color fg, rgba_color bg, int pad, int align ) +{ + PangoFT2FontMap *fontmap = (PangoFT2FontMap*) pango_ft2_font_map_new(); + PangoContext *context = pango_ft2_font_map_create_context( fontmap ); + PangoLayout *layout = pango_layout_new( context ); +// PangoFontDescription *font; + int w, h, x; + int i, j; + GdkPixbuf *pixbuf = NULL; + FT_Bitmap bitmap; + uint8_t *src = NULL; + uint8_t* dest = NULL; + int stride; + + pango_ft2_font_map_set_resolution( fontmap, 72, 72 ); + pango_layout_set_width( layout, -1 ); // set wrapping constraints +// pango_layout_set_font_description( layout, "Sans 48" ); +// pango_layout_set_spacing( layout, space ); + pango_layout_set_alignment( layout, ( PangoAlignment ) align ); + pango_layout_set_markup( layout, markup, (markup == NULL ? 0 : strlen( markup ) ) ); + pango_layout_get_pixel_size( layout, &w, &h ); + + pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, TRUE /* has alpha */, 8, w + 2 * pad, h + 2 * pad ); + pango_draw_background( pixbuf, bg ); + + stride = gdk_pixbuf_get_rowstride( pixbuf ); + + bitmap.width = w; + bitmap.pitch = 32 * ( ( w + 31 ) / 31 ); + bitmap.rows = h; + bitmap.buffer = ( unsigned char * ) calloc( 1, h * bitmap.pitch ); + bitmap.num_grays = 256; + bitmap.pixel_mode = ft_pixel_mode_grays; + + pango_ft2_render_layout( &bitmap, layout, 0, 0 ); + + src = bitmap.buffer; + x = ( gdk_pixbuf_get_width( pixbuf ) - w - 2 * pad ) * align / 2 + pad; + dest = gdk_pixbuf_get_pixels( pixbuf ) + 4 * x + pad * stride; + for ( j = 0; j < h; j++ ) + { + uint8_t *d = dest; + for ( i = 0; i < w; i++ ) + { + float a = ( float ) bitmap.buffer[ j * bitmap.pitch + i ] / 255.0; + *d++ = ( int ) ( a * fg.r + ( 1 - a ) * bg.r ); + *d++ = ( int ) ( a * fg.g + ( 1 - a ) * bg.g ); + *d++ = ( int ) ( a * fg.b + ( 1 - a ) * bg.b ); + *d++ = ( int ) ( a * fg.a + ( 1 - a ) * bg.a ); + } + dest += stride; + } + free( bitmap.buffer ); + + g_object_unref( layout ); + g_object_unref( context ); + g_object_unref( fontmap ); + + return pixbuf; +} + diff --git a/src/modules/gtk2/producer_pango.h b/src/modules/gtk2/producer_pango.h new file mode 100644 index 00000000..f067e7cc --- /dev/null +++ b/src/modules/gtk2/producer_pango.h @@ -0,0 +1,41 @@ +/* + * producer_pango.h -- a pango-based titler + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Dan Dennedy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _PRODUCER_PANGO_H_ +#define _PRODUCER_PANGO_H_ + +#include + +typedef struct producer_pango_s *producer_pango; + +struct producer_pango_s +{ + struct mlt_producer_s parent; + char *markup; + int width; + int height; + uint8_t *image; + uint8_t *alpha; + int is_pal; +}; + +extern mlt_producer producer_pango_init( const char *markup ); + +#endif diff --git a/src/modules/gtk2/producer_pixbuf.c b/src/modules/gtk2/producer_pixbuf.c index 8a74a468..1ba370f9 100644 --- a/src/modules/gtk2/producer_pixbuf.c +++ b/src/modules/gtk2/producer_pixbuf.c @@ -40,6 +40,7 @@ mlt_producer producer_pixbuf_init( const char *filename ) this->filename = strdup( filename ); this->counter = -1; + this->is_pal = 1; g_type_init(); return producer; @@ -83,7 +84,7 @@ static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_forma return 0; } -uint8_t *producer_get_alpha_mask( mlt_frame this ) +static uint8_t *producer_get_alpha_mask( mlt_frame this ) { // Obtain properties of frame mlt_properties properties = mlt_frame_properties( this ); @@ -145,6 +146,26 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i // If we have a pixbuf if ( pixbuf ) { + // Scale to adjust for sample aspect ratio + if ( this->is_pal ) + { + GdkPixbuf *temp = pixbuf; + GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, + (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 54.0/59.0), + gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER ); + pixbuf = scaled; + g_object_unref( temp ); + } + else + { + GdkPixbuf *temp = pixbuf; + GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, + (gint) ( (float) gdk_pixbuf_get_width( pixbuf ) * 11.0/10.0 ), + gdk_pixbuf_get_height( pixbuf ), GDK_INTERP_HYPER ); + pixbuf = scaled; + g_object_unref( temp ); + } + // Store width and height this->width = gdk_pixbuf_get_width( pixbuf ); this->height = gdk_pixbuf_get_height( pixbuf ); diff --git a/src/modules/gtk2/producer_pixbuf.h b/src/modules/gtk2/producer_pixbuf.h index c7f76ef3..04fb2f41 100644 --- a/src/modules/gtk2/producer_pixbuf.h +++ b/src/modules/gtk2/producer_pixbuf.h @@ -34,6 +34,7 @@ struct producer_pixbuf_s int height; uint8_t *image; uint8_t *alpha; + int is_pal; }; extern mlt_producer producer_pixbuf_init( const char *filename ); diff --git a/src/tests/dan.c b/src/tests/dan.c index e8d61263..cdd1b866 100644 --- a/src/tests/dan.c +++ b/src/tests/dan.c @@ -23,7 +23,8 @@ int main( int argc, char **argv ) mlt_producer dv1 = mlt_factory_producer( "libdv", file1 ); //mlt_producer dv1 = producer_pixbuf_init( file1 ); //mlt_producer dv2 = producer_libdv_init( file2 ); - mlt_producer dv2 = mlt_factory_producer( "pixbuf", file2 ); + //mlt_producer dv2 = mlt_factory_producer( "pixbuf", file2 ); + mlt_producer dv2 = mlt_factory_producer( "pango", "Mutton Lettuce Tomato" ); // Register producers(s) with a multitrack object mlt_multitrack multitrack = mlt_multitrack_init( ); -- 2.39.2