X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fpng.c;h=46d31af689d2e6a2ebc9557d53184b3b7e77663b;hb=e0e1f0fce33f18dd288151fb8a3ffa05e971d5c8;hp=3d8a6ff9fd075a5cf02ccff1196f7bc0c00b484d;hpb=9278fb81ed9603b92072e31a5915a8815a4c7c6a;p=vlc diff --git a/modules/codec/png.c b/modules/codec/png.c index 3d8a6ff9fd..46d31af689 100644 --- a/modules/codec/png.c +++ b/modules/codec/png.c @@ -1,24 +1,24 @@ /***************************************************************************** * png.c: png decoder module making use of libpng. ***************************************************************************** - * Copyright (C) 1999-2001 the VideoLAN team + * Copyright (C) 1999-2001 VLC authors and VideoLAN * $Id$ * * Authors: Gildas Bazin * - * 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 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -33,12 +33,31 @@ #include #include +/* 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 () /***************************************************************************** @@ -67,7 +108,6 @@ vlc_module_end () static int OpenDecoder( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; - decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_CODEC_PNG && p_dec->fmt_in.i_codec != VLC_FOURCC('M','P','N','G') ) @@ -76,10 +116,12 @@ static int OpenDecoder( vlc_object_t *p_this ) } /* Allocate the memory needed to store the decoder's structure */ - if( ( p_dec->p_sys = p_sys = - (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL ) + p_dec->p_sys = malloc( sizeof(decoder_sys_t) ); + if( p_dec->p_sys == 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; @@ -93,25 +135,50 @@ static int OpenDecoder( vlc_object_t *p_this ) static void user_read( png_structp p_png, png_bytep data, png_size_t i_length ) { block_t *p_block = (block_t *)png_get_io_ptr( p_png ); - png_size_t i_read = __MIN( p_block->i_buffer, i_length ); + if( i_length > p_block->i_buffer ) { + png_error( p_png, "not enough data" ); + return; + } + memcpy( data, p_block->p_buffer, i_length ); p_block->p_buffer += i_length; p_block->i_buffer -= i_length; +} + +static void user_flush( png_structp p_png ) +{ + /* noop */ + (void) p_png; +} - if( i_length != i_read ) png_error( p_png, "not enough data" ); +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 ); } /**************************************************************************** @@ -150,11 +217,11 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) block_Release( p_block ); *pp_block = NULL; return NULL; } - + p_info = png_create_info_struct( p_png ); if( p_info == NULL ) { - png_destroy_read_struct( &p_png, png_infopp_NULL, png_infopp_NULL ); + png_destroy_read_struct( &p_png, NULL, NULL ); block_Release( p_block ); *pp_block = NULL; return NULL; } @@ -162,11 +229,11 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) p_end_info = png_create_info_struct( p_png ); if( p_end_info == NULL ) { - png_destroy_read_struct( &p_png, &p_info, png_infopp_NULL ); + png_destroy_read_struct( &p_png, &p_info, NULL ); block_Release( p_block ); *pp_block = NULL; return NULL; } - + /* libpng longjmp's there in case of error */ if( setjmp( png_jmpbuf( p_png ) ) ) goto error; @@ -184,9 +251,10 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) /* Set output properties */ p_dec->fmt_out.i_codec = VLC_CODEC_RGBA; - p_dec->fmt_out.video.i_width = i_width; - p_dec->fmt_out.video.i_height = i_height; - p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height; + p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width = i_width; + p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height = i_height; + p_dec->fmt_out.video.i_sar_num = 1; + p_dec->fmt_out.video.i_sar_den = 1; p_dec->fmt_out.video.i_rmask = 0x000000ff; p_dec->fmt_out.video.i_gmask = 0x0000ff00; p_dec->fmt_out.video.i_bmask = 0x00ff0000; @@ -229,7 +297,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) png_destroy_read_struct( &p_png, &p_info, &p_end_info ); free( p_row_pointers ); - p_pic->date = p_block->i_pts > 0 ? p_block->i_pts : p_block->i_dts; + p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts; block_Release( p_block ); *pp_block = NULL; return p_pic; @@ -252,3 +320,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; + + png_set_IHDR( p_png, p_info, + p_enc->fmt_in.video.i_visible_width, + p_enc->fmt_in.video.i_visible_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( int i = 0; i < p_pic->p->i_lines; i++ ) + { + png_write_row( p_png, p_pic->p->p_pixels + (i * p_pic->p->i_pitch) ); + 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 - p_block->i_buffer; + + p_block->i_dts = p_block->i_pts = p_pic->date; + + 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 ); +}