2 * Portable Network Graphics renderer
4 * Copyright 2001 by Felix Buenemann <atmosfear@users.sourceforge.net>
6 * Uses libpng (which uses zlib), so see according licenses.
8 * This file is part of MPlayer.
10 * MPlayer is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * MPlayer is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <sys/types.h>
39 #include "video_out.h"
40 #include "video_out_internal.h"
41 #include "subopt-helper.h"
46 static const vo_info_t info
=
50 "Felix Buenemann <atmosfear@users.sourceforge.net>",
54 const LIBVO_EXTERN (png
)
56 static int z_compression
= Z_NO_COMPRESSION
;
57 static char *png_outdir
= NULL
;
58 static int framenum
= 0;
65 enum {OK
,ERROR
} status
;
68 static void png_mkdir(char *buf
, int verbose
) {
72 if ( mkdir(buf
, 0755) < 0 ) {
74 if ( mkdir(buf
) < 0 ) {
76 switch (errno
) { /* use switch in case other errors need to be caught
77 and handled in the future */
79 if ( stat(buf
, &stat_p
) < 0 ) {
80 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s: %s\n", info
.short_name
,
81 MSGTR_VO_GenericError
, strerror(errno
) );
82 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s %s\n", info
.short_name
,
83 MSGTR_VO_UnableToAccess
,buf
);
84 exit_player(MSGTR_Exit_error
);
86 if ( !S_ISDIR(stat_p
.st_mode
) ) {
87 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s %s\n", info
.short_name
,
88 buf
, MSGTR_VO_ExistsButNoDirectory
);
89 exit_player(MSGTR_Exit_error
);
91 if ( !(stat_p
.st_mode
& S_IWUSR
) ) {
92 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s - %s\n", info
.short_name
,
93 buf
, MSGTR_VO_DirExistsButNotWritable
);
94 exit_player(MSGTR_Exit_error
);
97 mp_msg(MSGT_VO
, MSGL_INFO
, "%s: %s - %s\n", info
.short_name
,
98 buf
, MSGTR_VO_DirExistsAndIsWritable
);
102 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s: %s\n", info
.short_name
,
103 MSGTR_VO_GenericError
, strerror(errno
) );
104 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s - %s\n", info
.short_name
,
105 buf
, MSGTR_VO_CantCreateDirectory
);
106 exit_player(MSGTR_Exit_error
);
108 } else if ( verbose
) {
109 mp_msg(MSGT_VO
, MSGL_INFO
, "%s: %s - %s\n", info
.short_name
,
110 buf
, MSGTR_VO_DirectoryCreateSuccess
);
115 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
119 if(z_compression
== 0) {
120 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_PNG_Warning1
);
121 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_PNG_Warning2
);
122 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_PNG_Warning3
);
125 snprintf(buf
, BUFLENGTH
, "%s", png_outdir
);
127 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Compression level %i\n", z_compression
);
133 static struct pngdata
create_png (char * fname
, int image_width
, int image_height
, int swapped
)
137 /*png_structp png_ptr = png_create_write_struct
138 (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
139 user_error_fn, user_warning_fn);*/
140 //png_byte *row_pointers[image_height];
141 png
.png_ptr
= png_create_write_struct
142 (PNG_LIBPNG_VER_STRING
, NULL
,
144 png
.info_ptr
= png_create_info_struct(png
.png_ptr
);
147 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Failed to init png pointer\n");
153 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Failed to init png infopointer\n");
154 png_destroy_write_struct(&png
.png_ptr
,
160 if (setjmp(png
.png_ptr
->jmpbuf
)) {
161 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Internal error!\n");
162 png_destroy_write_struct(&png
.png_ptr
, &png
.info_ptr
);
168 png
.fp
= fopen (fname
, "wb");
169 if (png
.fp
== NULL
) {
170 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_PNG_ErrorOpeningForWriting
, strerror(errno
));
175 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Init IO\n");
176 png_init_io(png
.png_ptr
, png
.fp
);
178 /* set the zlib compression level */
179 png_set_compression_level(png
.png_ptr
, z_compression
);
182 /*png_set_IHDR(png_ptr, info_ptr, width, height,
183 bit_depth, color_type, interlace_type,
184 compression_type, filter_type)*/
185 png_set_IHDR(png
.png_ptr
, png
.info_ptr
, image_width
, image_height
,
186 8, use_alpha
? PNG_COLOR_TYPE_RGBA
: PNG_COLOR_TYPE_RGB
, PNG_INTERLACE_NONE
,
187 PNG_COMPRESSION_TYPE_DEFAULT
, PNG_FILTER_TYPE_DEFAULT
);
189 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Write Info\n");
190 png_write_info(png
.png_ptr
, png
.info_ptr
);
193 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Set BGR Conversion\n");
194 png_set_bgr(png
.png_ptr
);
201 static uint8_t destroy_png(struct pngdata png
) {
203 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Write End\n");
204 png_write_end(png
.png_ptr
, png
.info_ptr
);
206 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Destroy Write Struct\n");
207 png_destroy_write_struct(&png
.png_ptr
, &png
.info_ptr
);
214 static uint32_t draw_image(mp_image_t
* mpi
){
218 png_byte
*row_pointers
[mpi
->h
];
220 // if -dr or -slices then do nothing:
221 if(mpi
->flags
&(MP_IMGFLAG_DIRECT
|MP_IMGFLAG_DRAW_CALLBACK
)) return VO_TRUE
;
223 snprintf (buf
, 100, "%s/%08d.png", png_outdir
, ++framenum
);
225 png
= create_png(buf
, mpi
->w
, mpi
->h
, IMGFMT_IS_BGR(mpi
->imgfmt
));
228 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_PNG_ErrorInCreatePng
);
232 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Creating Row Pointers\n");
233 for ( k
= 0; k
< mpi
->h
; k
++ )
234 row_pointers
[k
] = mpi
->planes
[0]+mpi
->stride
[0]*k
;
236 //png_write_flush(png.png_ptr);
237 //png_set_flush(png.png_ptr, nrows);
239 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) {
240 mp_msg(MSGT_VO
,MSGL_DBG2
, "PNG Writing Image Data\n"); }
241 png_write_image(png
.png_ptr
, row_pointers
);
248 static void draw_osd(void){}
250 static void flip_page (void){}
252 static int draw_frame(uint8_t * src
[])
257 static int draw_slice( uint8_t *src
[],int stride
[],int w
,int h
,int x
,int y
)
263 query_format(uint32_t format
)
265 const int supported_flags
= VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
|VFCAP_ACCEPT_STRIDE
;
269 return use_alpha
? 0 : supported_flags
;
272 return use_alpha
? supported_flags
: 0;
277 static void uninit(void){
284 static void check_events(void){}
286 static int int_zero_to_nine(int *sh
)
288 if ( (*sh
< 0) || (*sh
> 9) )
293 static opt_t subopts
[] = {
294 {"alpha", OPT_ARG_BOOL
, &use_alpha
, NULL
, 0},
295 {"z", OPT_ARG_INT
, &z_compression
, (opt_test_f
)int_zero_to_nine
},
296 {"outdir", OPT_ARG_MSTRZ
, &png_outdir
, NULL
, 0},
300 static int preinit(const char *arg
)
303 png_outdir
= strdup(".");
305 if (subopt_parse(arg
, subopts
) != 0) {
311 static int control(uint32_t request
, void *data
, ...)
314 case VOCTRL_DRAW_IMAGE
:
315 return draw_image(data
);
316 case VOCTRL_QUERY_FORMAT
:
317 return query_format(*((uint32_t*)data
));