1 /*****************************************************************************
2 * png.c: png decoder module making use of libpng.
3 *****************************************************************************
4 * Copyright (C) 1999-2001 the VideoLAN team
7 * Authors: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
36 /*****************************************************************************
37 * decoder_sys_t : png decoder descriptor
38 *****************************************************************************/
44 /*****************************************************************************
46 *****************************************************************************/
47 static int OpenDecoder ( vlc_object_t
* );
48 static void CloseDecoder ( vlc_object_t
* );
50 static picture_t
*DecodeBlock ( decoder_t
*, block_t
** );
52 /*****************************************************************************
54 *****************************************************************************/
56 set_category( CAT_INPUT
)
57 set_subcategory( SUBCAT_INPUT_VCODEC
)
58 set_description( N_("PNG video decoder") )
59 set_capability( "decoder", 1000 )
60 set_callbacks( OpenDecoder
, CloseDecoder
)
64 /*****************************************************************************
65 * OpenDecoder: probe the decoder and return score
66 *****************************************************************************/
67 static int OpenDecoder( vlc_object_t
*p_this
)
69 decoder_t
*p_dec
= (decoder_t
*)p_this
;
71 if( p_dec
->fmt_in
.i_codec
!= VLC_CODEC_PNG
&&
72 p_dec
->fmt_in
.i_codec
!= VLC_FOURCC('M','P','N','G') )
77 /* Allocate the memory needed to store the decoder's structure */
78 if( ( p_dec
->p_sys
= malloc(sizeof(decoder_sys_t
)) ) == NULL
)
81 /* Set output properties */
82 p_dec
->fmt_out
.i_cat
= VIDEO_ES
;
83 p_dec
->fmt_out
.i_codec
= VLC_CODEC_RGBA
;
86 p_dec
->pf_decode_video
= DecodeBlock
;
91 static void user_read( png_structp p_png
, png_bytep data
, png_size_t i_length
)
93 block_t
*p_block
= (block_t
*)png_get_io_ptr( p_png
);
94 png_size_t i_read
= __MIN( p_block
->i_buffer
, i_length
);
95 memcpy( data
, p_block
->p_buffer
, i_length
);
96 p_block
->p_buffer
+= i_length
;
97 p_block
->i_buffer
-= i_length
;
99 if( i_length
!= i_read
) png_error( p_png
, "not enough data" );
102 static void user_error( png_structp p_png
, png_const_charp error_msg
)
104 decoder_t
*p_dec
= (decoder_t
*)png_get_error_ptr( p_png
);
105 p_dec
->p_sys
->b_error
= true;
106 msg_Err( p_dec
, "%s", error_msg
);
109 static void user_warning( png_structp p_png
, png_const_charp warning_msg
)
111 decoder_t
*p_dec
= (decoder_t
*)png_get_error_ptr( p_png
);
112 msg_Warn( p_dec
, "%s", warning_msg
);
115 /****************************************************************************
116 * DecodeBlock: the whole thing
117 ****************************************************************************
118 * This function must be fed with a complete compressed frame.
119 ****************************************************************************/
120 static picture_t
*DecodeBlock( decoder_t
*p_dec
, block_t
**pp_block
)
122 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
124 picture_t
*p_pic
= 0;
126 png_uint_32 i_width
, i_height
;
127 int i_color_type
, i_interlace_type
, i_compression_type
, i_filter_type
;
131 png_infop p_info
, p_end_info
;
132 png_bytep
*p_row_pointers
= NULL
;
134 if( !pp_block
|| !*pp_block
) return NULL
;
137 p_sys
->b_error
= false;
139 if( p_block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
141 block_Release( p_block
); *pp_block
= NULL
;
145 p_png
= png_create_read_struct( PNG_LIBPNG_VER_STRING
, 0, 0, 0 );
148 block_Release( p_block
); *pp_block
= NULL
;
152 p_info
= png_create_info_struct( p_png
);
155 png_destroy_read_struct( &p_png
, NULL
, NULL
);
156 block_Release( p_block
); *pp_block
= NULL
;
160 p_end_info
= png_create_info_struct( p_png
);
161 if( p_end_info
== NULL
)
163 png_destroy_read_struct( &p_png
, &p_info
, NULL
);
164 block_Release( p_block
); *pp_block
= NULL
;
168 /* libpng longjmp's there in case of error */
169 if( setjmp( png_jmpbuf( p_png
) ) )
172 png_set_read_fn( p_png
, (void *)p_block
, user_read
);
173 png_set_error_fn( p_png
, (void *)p_dec
, user_error
, user_warning
);
175 png_read_info( p_png
, p_info
);
176 if( p_sys
->b_error
) goto error
;
178 png_get_IHDR( p_png
, p_info
, &i_width
, &i_height
,
179 &i_bit_depth
, &i_color_type
, &i_interlace_type
,
180 &i_compression_type
, &i_filter_type
);
181 if( p_sys
->b_error
) goto error
;
183 /* Set output properties */
184 p_dec
->fmt_out
.i_codec
= VLC_CODEC_RGBA
;
185 p_dec
->fmt_out
.video
.i_width
= i_width
;
186 p_dec
->fmt_out
.video
.i_height
= i_height
;
187 p_dec
->fmt_out
.video
.i_sar_num
= 1;
188 p_dec
->fmt_out
.video
.i_sar_den
= 1;
189 p_dec
->fmt_out
.video
.i_rmask
= 0x000000ff;
190 p_dec
->fmt_out
.video
.i_gmask
= 0x0000ff00;
191 p_dec
->fmt_out
.video
.i_bmask
= 0x00ff0000;
193 if( i_color_type
== PNG_COLOR_TYPE_PALETTE
)
194 png_set_palette_to_rgb( p_png
);
196 if( i_color_type
== PNG_COLOR_TYPE_GRAY
||
197 i_color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
)
198 png_set_gray_to_rgb( p_png
);
200 /* Strip to 8 bits per channel */
201 if( i_bit_depth
== 16 ) png_set_strip_16( p_png
);
203 if( png_get_valid( p_png
, p_info
, PNG_INFO_tRNS
) )
205 png_set_tRNS_to_alpha( p_png
);
207 else if( !(i_color_type
& PNG_COLOR_MASK_ALPHA
) )
209 p_dec
->fmt_out
.i_codec
= VLC_CODEC_RGB24
;
212 /* Get a new picture */
213 p_pic
= decoder_NewPicture( p_dec
);
214 if( !p_pic
) goto error
;
217 p_row_pointers
= malloc( sizeof(png_bytep
) * i_height
);
218 if( !p_row_pointers
)
220 for( i
= 0; i
< (int)i_height
; i
++ )
221 p_row_pointers
[i
] = p_pic
->p
->p_pixels
+ p_pic
->p
->i_pitch
* i
;
223 png_read_image( p_png
, p_row_pointers
);
224 if( p_sys
->b_error
) goto error
;
225 png_read_end( p_png
, p_end_info
);
226 if( p_sys
->b_error
) goto error
;
228 png_destroy_read_struct( &p_png
, &p_info
, &p_end_info
);
229 free( p_row_pointers
);
231 p_pic
->date
= p_block
->i_pts
> VLC_TS_INVALID
? p_block
->i_pts
: p_block
->i_dts
;
233 block_Release( p_block
); *pp_block
= NULL
;
238 free( p_row_pointers
);
239 png_destroy_read_struct( &p_png
, &p_info
, &p_end_info
);
240 block_Release( p_block
); *pp_block
= NULL
;
244 /*****************************************************************************
245 * CloseDecoder: png decoder destruction
246 *****************************************************************************/
247 static void CloseDecoder( vlc_object_t
*p_this
)
249 decoder_t
*p_dec
= (decoder_t
*)p_this
;
250 decoder_sys_t
*p_sys
= p_dec
->p_sys
;