From 6f0002c023860e4184e641e982efea0f830a2c1b Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 13 Oct 2019 20:59:02 +0100 Subject: [PATCH] add plumbing for stream minimise and ::finish becomes a vfunc --- libvips/include/vips/basic.h | 5 ++ libvips/include/vips/image.h | 3 -- libvips/include/vips/stream.h | 22 ++++++-- libvips/iofuncs/stream.c | 99 ++++++++++++++++++++++++----------- 4 files changed, 90 insertions(+), 39 deletions(-) diff --git a/libvips/include/vips/basic.h b/libvips/include/vips/basic.h index a0adf4b4..b17cfa7a 100644 --- a/libvips/include/vips/basic.h +++ b/libvips/include/vips/basic.h @@ -71,6 +71,11 @@ typedef enum { char *vips_path_filename7( const char *path ); char *vips_path_mode7( const char *path ); +struct _VipsImage; +typedef struct _VipsImage VipsImage; +struct _VipsRegion; +typedef struct _VipsRegion VipsRegion; + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index a7b0cccc..5d26a69b 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -133,9 +133,6 @@ typedef enum { VIPS_ACCESS_LAST } VipsAccess; -struct _VipsImage; -struct _VipsRegion; - typedef void *(*VipsStartFn)( struct _VipsImage *out, void *a, void *b ); typedef int (*VipsGenerateFn)( struct _VipsRegion *out, void *seq, void *a, void *b, gboolean *stop ); diff --git a/libvips/include/vips/stream.h b/libvips/include/vips/stream.h index 53281546..64790c3f 100644 --- a/libvips/include/vips/stream.h +++ b/libvips/include/vips/stream.h @@ -68,7 +68,7 @@ typedef struct _VipsStream { */ int tracked_descriptor; - /* A descriptor we close close(). + /* A descriptor we close with close(). */ int close_descriptor; @@ -86,8 +86,6 @@ typedef struct _VipsStreamClass { GType vips_stream_get_type( void ); -void vips_stream_attach( VipsStream *stream ); - #define VIPS_TYPE_STREAM_INPUT (vips_stream_input_get_type()) #define VIPS_STREAM_INPUT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ @@ -162,6 +160,15 @@ typedef struct _VipsStreamInputClass { ssize_t (*read)( VipsStreamInput *, unsigned char *, size_t ); int (*rewind)( VipsStreamInput * ); + /* Shut down anything that can safely restarted. For example, if + * there's a fd that supports lseek(), it can be closed, since later + * (if neccessary) it can be reopened and lseek()ed back to the + * correct point. + * + * Non-restartable shutdown shuld be in _finalize(). + */ + void (*minimise)( VipsStreamInput * ); + } VipsStreamInputClass; GType vips_stream_input_get_type( void ); @@ -176,6 +183,8 @@ VipsStreamInput *vips_stream_input_new_from_options( const char *options ); ssize_t vips_stream_input_read( VipsStreamInput *input, unsigned char *data, size_t length ); int vips_stream_input_rewind( VipsStreamInput *input ); +void vips_stream_minimise( VipsStreamInput *input ); +void vips_stream_set_image( VipsStreamInput *input, VipsImage *image ); void vips_stream_input_decode( VipsStreamInput *input ); gboolean vips_stream_input_eof( VipsStreamInput *input ); unsigned char *vips_stream_input_sniff( VipsStreamInput *input, size_t length ); @@ -219,6 +228,11 @@ typedef struct _VipsStreamOutputClass { */ ssize_t (*write)( VipsStreamOutput *, const unsigned char *, size_t ); + /* A complete output image has been generated, so do any clearing up, + * eg. copy the bytes we saved in memory to the output blob. + */ + void (*finish)( VipsStreamOutput * ); + } VipsStreamOutputClass; GType vips_stream_output_get_type( void ); @@ -226,7 +240,7 @@ GType vips_stream_output_get_type( void ); VipsStreamOutput *vips_stream_output_new_from_descriptor( int descriptor ); VipsStreamOutput *vips_stream_output_new_from_filename( const char *filename ); VipsStreamOutput *vips_stream_output_new_memory( void ); -int vips_stream_output_write( VipsStreamOutput *stream, +int vips_stream_output_write( VipsStreamOutput *output, const unsigned char *data, size_t length ); void vips_stream_output_finish( VipsStreamOutput *output ); diff --git a/libvips/iofuncs/stream.c b/libvips/iofuncs/stream.c index ce8363bb..5dc96241 100644 --- a/libvips/iofuncs/stream.c +++ b/libvips/iofuncs/stream.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -114,19 +115,10 @@ G_DEFINE_ABSTRACT_TYPE( VipsStream, vips_stream, VIPS_TYPE_OBJECT ); -static void -vips_stream_close( VipsStream *stream ) -{ - if( stream->close_descriptor >= 0 ) { - close( stream->close_descriptor ); - stream->close_descriptor = -1; - } - - if( stream->tracked_descriptor >= 0 ) { - vips_tracked_close( stream->tracked_descriptor ); - stream->tracked_descriptor = -1; - } -} +#define STREAM_NAME( STREAM ) \ + (VIPS_STREAM( STREAM )->filename ? \ + VIPS_STREAM( STREAM )->filename : \ + VIPS_OBJECT( STREAM )->nickname) static void vips_stream_finalize( GObject *gobject ) @@ -139,7 +131,16 @@ vips_stream_finalize( GObject *gobject ) VIPS_DEBUG_MSG( "\n" ); #endif /*VIPS_DEBUG*/ - vips_stream_close( stream ); + if( stream->close_descriptor >= 0 ) { + close( stream->close_descriptor ); + stream->close_descriptor = -1; + } + + if( stream->tracked_descriptor >= 0 ) { + vips_tracked_close( stream->tracked_descriptor ); + stream->tracked_descriptor = -1; + } + VIPS_FREE( stream->filename ); G_OBJECT_CLASS( vips_stream_parent_class )->finalize( gobject ); @@ -178,11 +179,6 @@ vips_stream_init( VipsStream *stream ) stream->close_descriptor = -1; } -#define STREAM_NAME( STREAM ) \ - (VIPS_STREAM( STREAM )->filename ? \ - VIPS_STREAM( STREAM )->filename : \ - VIPS_OBJECT( STREAM )->nickname) - G_DEFINE_TYPE( VipsStreamInput, vips_stream_input, VIPS_TYPE_STREAM ); static void @@ -313,6 +309,12 @@ vips_stream_input_rewind_real( VipsStreamInput *input ) return( 0 ); } +static void +vips_stream_input_minimise_real( VipsStreamInput *input ) +{ + VIPS_DEBUG_MSG( "vips_stream_minimise_real:\n" ); +} + static void vips_stream_input_class_init( VipsStreamInputClass *class ) { @@ -330,6 +332,7 @@ vips_stream_input_class_init( VipsStreamInputClass *class ) class->read = vips_stream_input_read_real; class->rewind = vips_stream_input_rewind_real; + class->minimise = vips_stream_input_minimise_real; VIPS_ARG_BOXED( class, "blob", 3, _( "Blob" ), @@ -572,6 +575,14 @@ vips_stream_input_rewind( VipsStreamInput *input ) return( class->rewind( input ) ); } +void +vips_stream_input_minimise( VipsStreamInput *input ) +{ + VipsStreamInputClass *class = VIPS_STREAM_INPUT_GET_CLASS( input ); + + class->minimise( input ); +} + gboolean vips_stream_input_eof( VipsStreamInput *input ) { @@ -592,6 +603,19 @@ vips_stream_input_decode( VipsStreamInput *input ) } } +static void +vips_stream_input_minimise_cb( VipsImage *image, VipsStreamInput *input ) +{ + vips_stream_input_minimise( input ); +} + +void +vips_stream_input_set_image( VipsStreamInput *input, VipsImage *image ) +{ + g_signal_connect( image, "minimise", + G_CALLBACK( vips_stream_input_minimise_cb ), input ); +} + /** * vips_stream_input_sniff: * @bytes: number of bytes to sniff @@ -704,6 +728,25 @@ vips_stream_output_write_real( VipsStreamOutput *output, return( len ); } +static void +vips_stream_output_finish_real( VipsStreamOutput *output ) +{ + VIPS_DEBUG_MSG( "vips_stream_output_finish_real:\n" ); + + /* Move the output buffer into the blob so it can be read out. + */ + if( output->memory ) { + unsigned char *data; + size_t length; + + length = output->memory->len; + data = g_byte_array_free( output->memory, FALSE ); + output->memory = NULL; + vips_blob_set( output->blob, + (VipsCallbackFn) g_free, data, length ); + } +} + static void vips_stream_output_class_init( VipsStreamOutputClass *class ) { @@ -720,6 +763,7 @@ vips_stream_output_class_init( VipsStreamOutputClass *class ) object_class->build = vips_stream_output_build; class->write = vips_stream_output_write_real; + class->finish = vips_stream_output_finish_real; /* SET_ALWAYS means that blob is set by C and the obj system is not * involved in creation or destruction. It can be read at any time. @@ -866,20 +910,11 @@ vips_stream_output_write( VipsStreamOutput *output, } void -vips_stream_output_finish( VipsStreamOutput *output ) +vips_stream_output_finish( VipsStreamOutput *output ) { + VipsStreamOutputClass *class = VIPS_STREAM_OUTPUT_GET_CLASS( output ); + VIPS_DEBUG_MSG( "vips_stream_output_finish:\n" ); - if( output->memory ) { - unsigned char *data; - size_t length; - - length = output->memory->len; - data = g_byte_array_free( output->memory, FALSE ); - output->memory = NULL; - vips_blob_set( output->blob, - (VipsCallbackFn) g_free, data, length ); - } - - vips_stream_close( VIPS_STREAM( output ) ); + class->finish( output ); }