1 /*****************************************************************************
2 * png.c: png decoder module making use of libpng.
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VLC authors and VideoLAN
7 * Authors: Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * 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 /* PNG_SYS_COMMON_MEMBERS:
37 * members common to encoder and decoder descriptors
39 #define PNG_SYS_COMMON_MEMBERS \
42 vlc_object_t *p_obj; \
46 * png common descriptor
50 PNG_SYS_COMMON_MEMBERS
53 typedef struct png_sys_t png_sys_t
;
55 /*****************************************************************************
56 * decoder_sys_t : png decoder descriptor
57 *****************************************************************************/
60 PNG_SYS_COMMON_MEMBERS
63 /*****************************************************************************
65 *****************************************************************************/
66 static int OpenDecoder ( vlc_object_t
* );
67 static void CloseDecoder ( vlc_object_t
* );
69 static int DecodeBlock ( decoder_t
*, block_t
* );
72 * png encoder descriptor
76 PNG_SYS_COMMON_MEMBERS
80 static int OpenEncoder(vlc_object_t
*);
81 static void CloseEncoder(vlc_object_t
*);
83 static block_t
*EncodeBlock(encoder_t
*, picture_t
*);
85 /*****************************************************************************
87 *****************************************************************************/
89 set_category( CAT_INPUT
)
90 set_subcategory( SUBCAT_INPUT_VCODEC
)
91 set_description( N_("PNG video decoder") )
92 set_capability( "video decoder", 1000 )
93 set_callbacks( OpenDecoder
, CloseDecoder
)
96 /* encoder submodule */
99 set_section(N_("Encoding"), NULL
)
100 set_description(N_("PNG video encoder"))
101 set_capability("encoder", 1000)
102 set_callbacks(OpenEncoder
, CloseEncoder
)
105 /*****************************************************************************
106 * OpenDecoder: probe the decoder and return score
107 *****************************************************************************/
108 static int OpenDecoder( vlc_object_t
*p_this
)
110 decoder_t
*p_dec
= (decoder_t
*)p_this
;
112 if( p_dec
->fmt_in
.i_codec
!= VLC_CODEC_PNG
&&
113 p_dec
->fmt_in
.i_codec
!= VLC_FOURCC('M','P','N','G') )
118 /* Allocate the memory needed to store the decoder's structure */
119 decoder_sys_t
*p_sys
= malloc( sizeof(decoder_sys_t
) );
122 p_dec
->p_sys
= p_sys
;
124 p_sys
->p_obj
= p_this
;
126 /* Set output properties */
127 p_dec
->fmt_out
.i_codec
= VLC_CODEC_RGBA
;
128 p_dec
->fmt_out
.video
.transfer
= TRANSFER_FUNC_SRGB
;
129 p_dec
->fmt_out
.video
.b_color_range_full
= true;
132 p_dec
->pf_decode
= DecodeBlock
;
137 static void user_read( png_structp p_png
, png_bytep data
, png_size_t i_length
)
139 block_t
*p_block
= (block_t
*)png_get_io_ptr( p_png
);
140 if( i_length
> p_block
->i_buffer
) {
141 png_error( p_png
, "not enough data" );
145 memcpy( data
, p_block
->p_buffer
, i_length
);
146 p_block
->p_buffer
+= i_length
;
147 p_block
->i_buffer
-= i_length
;
150 static void user_flush( png_structp p_png
)
156 static void user_write( png_structp p_png
, png_bytep data
, png_size_t i_length
)
158 block_t
*p_block
= (block_t
*)png_get_io_ptr( p_png
);
159 if( i_length
> p_block
->i_buffer
) {
161 snprintf( err_str
, sizeof(err_str
),
162 "block size %zu too small for %zu encoded bytes",
163 p_block
->i_buffer
, i_length
);
164 png_error( p_png
, err_str
);
168 memcpy( p_block
->p_buffer
, data
, i_length
);
169 p_block
->p_buffer
+= i_length
;
170 p_block
->i_buffer
-= i_length
;
173 static void user_error( png_structp p_png
, png_const_charp error_msg
)
175 png_sys_t
*p_sys
= (png_sys_t
*)png_get_error_ptr( p_png
);
176 p_sys
->b_error
= true;
177 msg_Err( p_sys
->p_obj
, "%s", error_msg
);
180 static void user_warning( png_structp p_png
, png_const_charp warning_msg
)
182 png_sys_t
*p_sys
= (png_sys_t
*)png_get_error_ptr( p_png
);
183 msg_Warn( p_sys
->p_obj
, "%s", warning_msg
);
186 /****************************************************************************
187 * DecodeBlock: the whole thing
188 ****************************************************************************
189 * This function must be fed with a complete compressed frame.
190 ****************************************************************************/
191 static int DecodeBlock( decoder_t
*p_dec
, block_t
*p_block
)
193 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
194 picture_t
*p_pic
= 0;
196 png_uint_32 i_width
, i_height
;
197 int i_color_type
, i_interlace_type
, i_compression_type
, i_filter_type
;
201 png_infop p_info
, p_end_info
;
202 png_bytep
*volatile p_row_pointers
= NULL
;
204 if( !p_block
) /* No Drain */
205 return VLCDEC_SUCCESS
;
207 p_sys
->b_error
= false;
209 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
211 block_Release( p_block
);
212 return VLCDEC_SUCCESS
;
215 p_png
= png_create_read_struct( PNG_LIBPNG_VER_STRING
, 0, 0, 0 );
218 block_Release( p_block
);
219 return VLCDEC_SUCCESS
;
222 p_info
= png_create_info_struct( p_png
);
225 png_destroy_read_struct( &p_png
, NULL
, NULL
);
226 block_Release( p_block
);
227 return VLCDEC_SUCCESS
;
230 p_end_info
= png_create_info_struct( p_png
);
231 if( p_end_info
== NULL
)
233 png_destroy_read_struct( &p_png
, &p_info
, NULL
);
234 block_Release( p_block
);
235 return VLCDEC_SUCCESS
;
238 /* libpng longjmp's there in case of error */
239 if( setjmp( png_jmpbuf( p_png
) ) )
242 png_set_read_fn( p_png
, (void *)p_block
, user_read
);
243 png_set_error_fn( p_png
, (void *)p_dec
, user_error
, user_warning
);
245 png_read_info( p_png
, p_info
);
246 if( p_sys
->b_error
) goto error
;
248 png_get_IHDR( p_png
, p_info
, &i_width
, &i_height
,
249 &i_bit_depth
, &i_color_type
, &i_interlace_type
,
250 &i_compression_type
, &i_filter_type
);
251 if( p_sys
->b_error
) goto error
;
253 /* Set output properties */
254 p_dec
->fmt_out
.i_codec
= VLC_CODEC_RGBA
;
255 p_dec
->fmt_out
.video
.i_visible_width
= p_dec
->fmt_out
.video
.i_width
= i_width
;
256 p_dec
->fmt_out
.video
.i_visible_height
= p_dec
->fmt_out
.video
.i_height
= i_height
;
257 p_dec
->fmt_out
.video
.i_sar_num
= 1;
258 p_dec
->fmt_out
.video
.i_sar_den
= 1;
260 if( i_color_type
== PNG_COLOR_TYPE_PALETTE
)
261 png_set_palette_to_rgb( p_png
);
263 if( i_color_type
== PNG_COLOR_TYPE_GRAY
||
264 i_color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
)
265 png_set_gray_to_rgb( p_png
);
266 if( i_color_type
& PNG_COLOR_MASK_ALPHA
)
267 png_set_alpha_mode( p_png
, PNG_ALPHA_OPTIMIZED
, PNG_DEFAULT_sRGB
);
269 /* Strip to 8 bits per channel */
270 if( i_bit_depth
== 16 )
272 #if PNG_LIBPNG_VER >= 10504
273 png_set_scale_16( p_png
);
275 png_set_strip_16( p_png
);
279 if( png_get_valid( p_png
, p_info
, PNG_INFO_tRNS
) )
281 png_set_tRNS_to_alpha( p_png
);
283 else if( !(i_color_type
& PNG_COLOR_MASK_ALPHA
) )
285 p_dec
->fmt_out
.i_codec
= VLC_CODEC_RGB24
;
288 /* Get a new picture */
289 if( decoder_UpdateVideoFormat( p_dec
) )
291 p_pic
= decoder_NewPicture( p_dec
);
292 if( !p_pic
) goto error
;
295 p_row_pointers
= vlc_alloc( i_height
, sizeof(png_bytep
) );
296 if( !p_row_pointers
)
298 for( i
= 0; i
< (int)i_height
; i
++ )
299 p_row_pointers
[i
] = p_pic
->p
->p_pixels
+ p_pic
->p
->i_pitch
* i
;
301 png_read_image( p_png
, p_row_pointers
);
302 if( p_sys
->b_error
) goto error
;
303 png_read_end( p_png
, p_end_info
);
304 if( p_sys
->b_error
) goto error
;
306 png_destroy_read_struct( &p_png
, &p_info
, &p_end_info
);
307 free( p_row_pointers
);
309 p_pic
->date
= p_block
->i_pts
!= VLC_TICK_INVALID
? p_block
->i_pts
: p_block
->i_dts
;
311 block_Release( p_block
);
312 decoder_QueueVideo( p_dec
, p_pic
);
313 return VLCDEC_SUCCESS
;
317 free( p_row_pointers
);
318 png_destroy_read_struct( &p_png
, &p_info
, &p_end_info
);
319 block_Release( p_block
);
320 return VLCDEC_SUCCESS
;
323 /*****************************************************************************
324 * CloseDecoder: png decoder destruction
325 *****************************************************************************/
326 static void CloseDecoder( vlc_object_t
*p_this
)
328 decoder_t
*p_dec
= (decoder_t
*)p_this
;
329 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
334 static int OpenEncoder(vlc_object_t
*p_this
)
336 encoder_t
*p_enc
= (encoder_t
*) p_this
;
338 if( p_enc
->fmt_out
.i_codec
!= VLC_CODEC_PNG
)
341 /* Allocate the memory needed to store the encoder's structure */
342 encoder_sys_t
*p_sys
= malloc( sizeof(encoder_sys_t
) );
345 p_enc
->p_sys
= p_sys
;
347 p_sys
->p_obj
= p_this
;
349 p_sys
->i_blocksize
= 3 * p_enc
->fmt_in
.video
.i_visible_width
*
350 p_enc
->fmt_in
.video
.i_visible_height
;
352 p_enc
->fmt_in
.i_codec
= VLC_CODEC_RGB24
;
353 p_enc
->fmt_in
.video
.i_bmask
= 0;
354 video_format_FixRgb( &p_enc
->fmt_in
.video
);
356 p_enc
->pf_encode_video
= EncodeBlock
;
364 static block_t
*EncodeBlock(encoder_t
*p_enc
, picture_t
*p_pic
)
366 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
368 if( unlikely( !p_pic
) )
373 block_t
*p_block
= block_Alloc( p_sys
->i_blocksize
);
374 if( p_block
== NULL
)
379 png_structp p_png
= png_create_write_struct( PNG_LIBPNG_VER_STRING
, 0, 0, 0 );
382 block_Release( p_block
);
386 /* Disable filtering to speed-up encoding */
387 png_set_filter( p_png
, 0, PNG_NO_FILTERS
);
388 /* 1 == best speed */
389 png_set_compression_level( p_png
, 1 );
391 /* save buffer start */
392 uint8_t *p_start
= p_block
->p_buffer
;
393 size_t i_start
= p_block
->i_buffer
;
395 p_sys
->b_error
= false;
396 png_infop p_info
= NULL
;
398 /* libpng longjmp's there in case of error */
399 if( setjmp( png_jmpbuf( p_png
) ) )
402 png_set_write_fn( p_png
, p_block
, user_write
, user_flush
);
403 png_set_error_fn( p_png
, p_enc
, user_error
, user_warning
);
405 p_info
= png_create_info_struct( p_png
);
409 png_set_IHDR( p_png
, p_info
,
410 p_enc
->fmt_in
.video
.i_visible_width
,
411 p_enc
->fmt_in
.video
.i_visible_height
,
412 8, PNG_COLOR_TYPE_RGB
, PNG_INTERLACE_NONE
,
413 PNG_COMPRESSION_TYPE_DEFAULT
, PNG_FILTER_TYPE_DEFAULT
);
414 if( p_sys
->b_error
) goto error
;
416 png_write_info( p_png
, p_info
);
417 if( p_sys
->b_error
) goto error
;
421 for( int i
= 0; i
< p_pic
->p
->i_visible_lines
; i
++ )
423 png_write_row( p_png
, p_pic
->p
->p_pixels
+ (i
* p_pic
->p
->i_pitch
) );
424 if( p_sys
->b_error
) goto error
;
427 png_write_end( p_png
, p_info
);
428 if( p_sys
->b_error
) goto error
;
430 png_destroy_write_struct( &p_png
, &p_info
);
432 /* restore original buffer position */
433 p_block
->p_buffer
= p_start
;
434 p_block
->i_buffer
= i_start
- p_block
->i_buffer
;
436 p_block
->i_dts
= p_block
->i_pts
= p_pic
->date
;
442 png_destroy_write_struct( &p_png
, p_info
? &p_info
: NULL
);
444 block_Release(p_block
);
448 /*****************************************************************************
449 * CloseEncoder: png encoder destruction
450 *****************************************************************************/
451 static void CloseEncoder( vlc_object_t
*p_this
)
453 encoder_t
*p_enc
= (encoder_t
*)p_this
;
454 encoder_sys_t
*p_sys
= p_enc
->p_sys
;