vlc | branch: master | Tristan Matthews <le.business...@gmail.com> | Fri Feb 14 02:16:37 2014 -0500| [858f38cf3d59c18724657339ad762c6c87e8889c] | committer: Tristan Matthews
png: add encoder > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=858f38cf3d59c18724657339ad762c6c87e8889c --- modules/codec/png.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 194 insertions(+), 6 deletions(-) diff --git a/modules/codec/png.c b/modules/codec/png.c index b4d6ef4..6a20b82 100644 --- a/modules/codec/png.c +++ b/modules/codec/png.c @@ -33,12 +33,31 @@ #include <vlc_codec.h> #include <png.h> +/* PNG_SYS_COMMON_MEMBERS: + * members common to encoder and decoder descriptors + */ +#define PNG_SYS_COMMON_MEMBERS \ +/**@{*/ \ + bool b_error; \ + vlc_object_t *p_obj; \ +/**@}*/ \ + +/* + * png common descriptor + */ +struct png_sys_t +{ + PNG_SYS_COMMON_MEMBERS +}; + +typedef struct png_sys_t png_sys_t; + /***************************************************************************** * decoder_sys_t : png decoder descriptor *****************************************************************************/ struct decoder_sys_t { - bool b_error; + PNG_SYS_COMMON_MEMBERS }; /***************************************************************************** @@ -49,6 +68,20 @@ static void CloseDecoder ( vlc_object_t * ); static picture_t *DecodeBlock ( decoder_t *, block_t ** ); +/* + * png encoder descriptor + */ +struct encoder_sys_t +{ + PNG_SYS_COMMON_MEMBERS + int i_blocksize; +}; + +static int OpenEncoder(vlc_object_t *); +static void CloseEncoder(vlc_object_t *); + +static block_t *EncodeBlock(encoder_t *, picture_t *); + /***************************************************************************** * Module descriptor *****************************************************************************/ @@ -59,6 +92,14 @@ vlc_module_begin () set_capability( "decoder", 1000 ) set_callbacks( OpenDecoder, CloseDecoder ) add_shortcut( "png" ) + + /* encoder submodule */ + add_submodule() + add_shortcut("png") + set_section(N_("Encoding"), NULL) + set_description(N_("PNG video encoder")) + set_capability("encoder", 1000) + set_callbacks(OpenEncoder, CloseEncoder) vlc_module_end () /***************************************************************************** @@ -78,6 +119,8 @@ static int OpenDecoder( vlc_object_t *p_this ) if( ( p_dec->p_sys = malloc(sizeof(decoder_sys_t)) ) == NULL ) return VLC_ENOMEM; + p_dec->p_sys->p_obj = p_this; + /* Set output properties */ p_dec->fmt_out.i_cat = VIDEO_ES; p_dec->fmt_out.i_codec = VLC_CODEC_RGBA; @@ -101,17 +144,40 @@ static void user_read( png_structp p_png, png_bytep data, png_size_t i_length ) p_block->i_buffer -= i_length; } +static void user_flush( png_structp p_png ) +{ + /* noop */ + (void) p_png; +} + +static void user_write( png_structp p_png, png_bytep data, png_size_t i_length ) +{ + block_t *p_block = (block_t *)png_get_io_ptr( p_png ); + if( i_length > p_block->i_buffer ) { + char err_str[64]; + snprintf( err_str, sizeof(err_str), + "block size %zu too small for %zu encoded bytes", + p_block->i_buffer, i_length ); + png_error( p_png, err_str ); + return; + } + + memcpy( p_block->p_buffer, data, i_length ); + p_block->p_buffer += i_length; + p_block->i_buffer -= i_length; +} + static void user_error( png_structp p_png, png_const_charp error_msg ) { - decoder_t *p_dec = (decoder_t *)png_get_error_ptr( p_png ); - p_dec->p_sys->b_error = true; - msg_Err( p_dec, "%s", error_msg ); + png_sys_t *p_sys = (png_sys_t *)png_get_error_ptr( p_png ); + p_sys->b_error = true; + msg_Err( p_sys->p_obj, "%s", error_msg ); } static void user_warning( png_structp p_png, png_const_charp warning_msg ) { - decoder_t *p_dec = (decoder_t *)png_get_error_ptr( p_png ); - msg_Warn( p_dec, "%s", warning_msg ); + png_sys_t *p_sys = (png_sys_t *)png_get_error_ptr( p_png ); + msg_Warn( p_sys->p_obj, "%s", warning_msg ); } /**************************************************************************** @@ -253,3 +319,125 @@ static void CloseDecoder( vlc_object_t *p_this ) free( p_sys ); } + +static int OpenEncoder(vlc_object_t *p_this) +{ + encoder_t *p_enc = (encoder_t *) p_this; + + if( p_enc->fmt_out.i_codec != VLC_CODEC_PNG ) + return VLC_EGENERIC; + + /* Allocate the memory needed to store the encoder's structure */ + p_enc->p_sys = malloc( sizeof(encoder_sys_t) ); + if( p_enc->p_sys == NULL ) + return VLC_ENOMEM; + + p_enc->p_sys->p_obj = p_this; + + p_enc->p_sys->i_blocksize = 3 * p_enc->fmt_in.video.i_visible_width * + p_enc->fmt_in.video.i_visible_height; + + p_enc->fmt_in.i_codec = VLC_CODEC_RGB24; + p_enc->fmt_in.video.i_rmask = 0x000000ff; + p_enc->fmt_in.video.i_gmask = 0x0000ff00; + p_enc->fmt_in.video.i_bmask = 0x00ff0000; + p_enc->pf_encode_video = EncodeBlock; + + return VLC_SUCCESS; +} + +/* + * EncodeBlock + */ +static block_t *EncodeBlock(encoder_t *p_enc, picture_t *p_pic) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + + if( unlikely( !p_pic ) ) + { + return NULL; + } + + block_t *p_block = block_Alloc( p_sys->i_blocksize ); + if( p_block == NULL ) + { + return NULL; + } + + png_structp p_png = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + if( p_png == NULL ) + { + block_Release( p_block ); + return NULL; + } + + /* save buffer start */ + uint8_t *p_start = p_block->p_buffer; + size_t i_start = p_block->i_buffer; + + p_sys->b_error = false; + png_infop p_info = NULL; + + /* libpng longjmp's there in case of error */ + if( setjmp( png_jmpbuf( p_png ) ) ) + goto error; + + png_set_write_fn( p_png, p_block, user_write, user_flush ); + png_set_error_fn( p_png, p_enc, user_error, user_warning ); + + p_info = png_create_info_struct( p_png ); + if( p_info == NULL ) + goto error; + + png_infop p_end_info = png_create_info_struct( p_png ); + if( p_end_info == NULL ) goto error; + + const unsigned i_width = p_enc->fmt_in.video.i_visible_width; + const unsigned i_height = p_enc->fmt_in.video.i_visible_height; + + png_set_IHDR( p_png, p_info, + i_width, + i_height, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); + if( p_sys->b_error ) goto error; + + png_write_info( p_png, p_info ); + if( p_sys->b_error ) goto error; + + /* Encode picture */ + + for( unsigned i = 0; i < i_height; i++ ) + { + png_write_row( p_png, p_pic->p->p_pixels + (i_width * i * 3)); + if( p_sys->b_error ) goto error; + } + + png_write_end( p_png, p_end_info ); + if( p_sys->b_error ) goto error; + + png_destroy_write_struct( &p_png, &p_info ); + + /* restore original buffer position */ + p_block->p_buffer = p_start; + p_block->i_buffer = i_start; + return p_block; + + error: + + png_destroy_write_struct( &p_png, p_info ? &p_info : NULL ); + + block_Release(p_block); + return NULL; +} + +/***************************************************************************** + * CloseEncoder: png encoder destruction + *****************************************************************************/ +static void CloseEncoder( vlc_object_t *p_this ) +{ + encoder_t *p_enc = (encoder_t *)p_this; + encoder_sys_t *p_sys = p_enc->p_sys; + + free( p_sys ); +} _______________________________________________ vlc-commits mailing list vlc-commits@videolan.org https://mailman.videolan.org/listinfo/vlc-commits