2 * JPEG Renderer for MPlayer
4 * Copyright (C) 2002 by Pontscho <pontscho@makacs.poliod.hu>
5 * Copyright (C) 2003 by Alex
6 * Copyright (C) 2004, 2005 by Ivo van Poorten <ivop@euronet.nl>
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.
25 /* ------------------------------------------------------------------------- */
35 #include <sys/types.h>
38 /* ------------------------------------------------------------------------- */
43 #include "subopt-helper.h"
45 #include "video_out.h"
46 #include "video_out_internal.h"
47 #include "mplayer.h" /* for exit_player_bad() */
50 /* ------------------------------------------------------------------------- */
54 /* Used for temporary buffers to store file- and pathnames */
57 /* ------------------------------------------------------------------------- */
61 static const vo_info_t info
=
65 "Zoltan Ponekker (pontscho@makacs.poliod.hu)",
69 const LIBVO_EXTERN (jpeg
)
71 /* ------------------------------------------------------------------------- */
73 /* Global Variables */
75 static int image_width
;
76 static int image_height
;
77 static int image_d_width
;
78 static int image_d_height
;
80 int jpeg_baseline
= 1;
81 int jpeg_progressive_mode
= 0;
82 int jpeg_optimize
= 100;
84 int jpeg_quality
= 75;
85 int jpeg_dpi
= 72; /** Screen resolution = 72 dpi */
86 char *jpeg_outdir
= NULL
;
87 char *jpeg_subdirs
= NULL
;
88 int jpeg_maxfiles
= 1000;
90 static int framenum
= 0;
92 /* ------------------------------------------------------------------------- */
94 /** \brief Create a directory.
96 * This function creates a directory. If it already exists, it tests if
97 * it's a directory and not something else, and if it is, it tests whether
98 * the directory is writable or not.
100 * \param buf Pointer to directory name.
101 * \param verbose Verbose on success. If verbose is non-zero, it will print
102 * a message if it was successful in creating the directory.
104 * \return nothing In case anything fails, the player will exit. If it
105 * returns, everything went well.
108 static void jpeg_mkdir(const char *buf
, int verbose
) {
111 if ( mkdir(buf
, 0755) < 0 ) {
112 switch (errno
) { /* use switch in case other errors need to be caught
113 and handled in the future */
115 if ( mp_stat(buf
, &stat_p
) < 0 ) {
116 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s: %s\n", info
.short_name
,
117 _("This error has occurred"), strerror(errno
) );
118 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s %s\n", info
.short_name
,
119 _("Unable to access"), buf
);
120 exit_player_bad(_("Fatal error"));
122 if ( !S_ISDIR(stat_p
.st_mode
) ) {
123 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s %s\n", info
.short_name
,
124 buf
, _("already exists, but is not a directory."));
125 exit_player_bad(_("Fatal error"));
127 if ( !(stat_p
.st_mode
& S_IWUSR
) ) {
128 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s - %s\n", info
.short_name
,
129 buf
, _("Output directory already exists, but is not writable."));
130 exit_player_bad(_("Fatal error"));
133 mp_msg(MSGT_VO
, MSGL_INFO
, "%s: %s - %s\n", info
.short_name
,
134 buf
, _("Output directory already exists and is writable."));
138 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s: %s\n", info
.short_name
,
139 _("This error has occurred"), strerror(errno
) );
140 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s - %s\n", info
.short_name
,
141 buf
, _("Unable to create output directory."));
142 exit_player_bad(_("Fatal error"));
144 } else if ( verbose
) {
145 mp_msg(MSGT_VO
, MSGL_INFO
, "%s: %s - %s\n", info
.short_name
,
146 buf
, _("Output directory successfully created."));
150 /* ------------------------------------------------------------------------- */
152 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
153 uint32_t d_height
, uint32_t flags
, char *title
,
160 snprintf(buf
, BUFLENGTH
, "%s", jpeg_outdir
);
162 jpeg_mkdir(buf
, 1); /* This function only returns if creation was
163 successful. If not, the player will exit. */
165 image_height
= height
;
167 /* Save for JFIF-Header PAR */
168 image_d_width
= d_width
;
169 image_d_height
= d_height
;
174 /* ------------------------------------------------------------------------- */
176 static uint32_t jpeg_write(const char * name
, uint8_t * buffer
)
179 struct jpeg_compress_struct cinfo
;
180 struct jpeg_error_mgr jerr
;
181 JSAMPROW row_pointer
[1];
184 if ( !buffer
) return 1;
185 if ( (outfile
= fopen(name
, "wb") ) == NULL
) {
186 mp_msg(MSGT_VO
, MSGL_ERR
, "\n%s: %s\n", info
.short_name
,
187 _("Unable to create output file."));
188 mp_msg(MSGT_VO
, MSGL_ERR
, "%s: %s: %s\n",
189 info
.short_name
, _("This error has occurred"),
191 exit_player_bad(_("Fatal error"));
194 cinfo
.err
= jpeg_std_error(&jerr
);
195 jpeg_create_compress(&cinfo
);
196 jpeg_stdio_dest(&cinfo
, outfile
);
198 cinfo
.image_width
= image_width
;
199 cinfo
.image_height
= image_height
;
200 cinfo
.input_components
= 3;
201 cinfo
.in_color_space
= JCS_RGB
;
203 jpeg_set_defaults(&cinfo
);
204 /* Important: Header info must be set AFTER jpeg_set_defaults() */
205 cinfo
.write_JFIF_header
= TRUE
;
206 cinfo
.JFIF_major_version
= 1;
207 cinfo
.JFIF_minor_version
= 2;
208 cinfo
.density_unit
= 1; /* 0=unknown, 1=dpi, 2=dpcm */
209 /* Image DPI is determined by Y_density, so we leave that at
210 jpeg_dpi if possible and crunch X_density instead (PAR > 1) */
211 cinfo
.X_density
= jpeg_dpi
*image_width
/image_d_width
;
212 cinfo
.Y_density
= jpeg_dpi
*image_height
/image_d_height
;
213 cinfo
.write_Adobe_marker
= TRUE
;
215 jpeg_set_quality(&cinfo
,jpeg_quality
, jpeg_baseline
);
216 cinfo
.optimize_coding
= jpeg_optimize
;
217 cinfo
.smoothing_factor
= jpeg_smooth
;
219 if ( jpeg_progressive_mode
) {
220 jpeg_simple_progression(&cinfo
);
223 jpeg_start_compress(&cinfo
, TRUE
);
225 row_stride
= image_width
* 3;
226 while (cinfo
.next_scanline
< cinfo
.image_height
) {
227 row_pointer
[0] = &buffer
[cinfo
.next_scanline
* row_stride
];
228 (void)jpeg_write_scanlines(&cinfo
, row_pointer
,1);
231 jpeg_finish_compress(&cinfo
);
233 jpeg_destroy_compress(&cinfo
);
238 /* ------------------------------------------------------------------------- */
240 static int draw_frame(uint8_t *src
[])
242 static int framecounter
= 0, subdircounter
= 0;
244 static char subdirname
[BUFLENGTH
] = "";
246 /* Start writing to new subdirectory after a certain amount of frames */
247 if ( framecounter
== jpeg_maxfiles
) {
251 /* If framecounter is zero (or reset to zero), increment subdirectory
252 * number and create the subdirectory.
253 * If jpeg_subdirs is not set, do nothing and resort to old behaviour. */
254 if ( !framecounter
&& jpeg_subdirs
) {
256 snprintf(subdirname
, BUFLENGTH
, "%s%08d", jpeg_subdirs
, subdircounter
);
257 snprintf(buf
, BUFLENGTH
, "%s/%s", jpeg_outdir
, subdirname
);
258 jpeg_mkdir(buf
, 0); /* This function only returns if creation was
259 successful. If not, the player will exit. */
264 /* snprintf the full pathname of the outputfile */
265 snprintf(buf
, BUFLENGTH
, "%s/%s/%08d.jpg", jpeg_outdir
, subdirname
,
270 return jpeg_write(buf
, src
[0]);
273 /* ------------------------------------------------------------------------- */
275 static void draw_osd(void)
279 /* ------------------------------------------------------------------------- */
281 static void flip_page (void)
285 /* ------------------------------------------------------------------------- */
287 static int draw_slice(uint8_t *src
[], int stride
[], int w
, int h
,
293 /* ------------------------------------------------------------------------- */
295 static int query_format(uint32_t format
)
297 if (format
== IMGFMT_RGB24
) {
298 return VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
;
304 /* ------------------------------------------------------------------------- */
306 static void uninit(void)
314 /* ------------------------------------------------------------------------- */
316 static void check_events(void)
320 /* ------------------------------------------------------------------------- */
322 /** \brief Validation function for values [0-100]
325 static int int_zero_hundred(void *valp
)
328 return *val
>= 0 && *val
<= 100;
331 static int preinit(const char *arg
)
333 const opt_t subopts
[] = {
334 {"progressive", OPT_ARG_BOOL
, &jpeg_progressive_mode
, NULL
},
335 {"baseline", OPT_ARG_BOOL
, &jpeg_baseline
, NULL
},
336 {"optimize", OPT_ARG_INT
, &jpeg_optimize
,
338 {"smooth", OPT_ARG_INT
, &jpeg_smooth
,
340 {"quality", OPT_ARG_INT
, &jpeg_quality
,
342 {"dpi", OPT_ARG_INT
, &jpeg_dpi
, NULL
},
343 {"outdir", OPT_ARG_MSTRZ
, &jpeg_outdir
, NULL
},
344 {"subdirs", OPT_ARG_MSTRZ
, &jpeg_subdirs
, NULL
},
345 {"maxfiles", OPT_ARG_INT
, &jpeg_maxfiles
, int_pos
},
346 {NULL
, 0, NULL
, NULL
}
348 const char *info_message
= NULL
;
350 mp_msg(MSGT_VO
, MSGL_V
, "%s: %s\n", info
.short_name
,
351 "Parsing suboptions.");
353 jpeg_progressive_mode
= 0;
358 jpeg_maxfiles
= 1000;
359 jpeg_outdir
= strdup(".");
362 if (subopt_parse(arg
, subopts
) != 0) {
366 if (jpeg_progressive_mode
) info_message
= _("Progressive JPEG enabled.");
367 else info_message
= _("Progressive JPEG disabled.");
368 mp_msg(MSGT_VO
, MSGL_INFO
, "%s: %s\n", info
.short_name
, info_message
);
370 if (jpeg_baseline
) info_message
= _("Baseline JPEG enabled.");
371 else info_message
= _("Baseline JPEG disabled.");
372 mp_msg(MSGT_VO
, MSGL_INFO
, "%s: %s\n", info
.short_name
, info_message
);
374 mp_msg(MSGT_VO
, MSGL_V
, "%s: optimize --> %d\n", info
.short_name
,
376 mp_msg(MSGT_VO
, MSGL_V
, "%s: smooth --> %d\n", info
.short_name
,
378 mp_msg(MSGT_VO
, MSGL_V
, "%s: quality --> %d\n", info
.short_name
,
380 mp_msg(MSGT_VO
, MSGL_V
, "%s: dpi --> %d\n", info
.short_name
,
382 mp_msg(MSGT_VO
, MSGL_V
, "%s: outdir --> %s\n", info
.short_name
,
385 mp_msg(MSGT_VO
, MSGL_V
, "%s: subdirs --> %s\n", info
.short_name
,
387 mp_msg(MSGT_VO
, MSGL_V
, "%s: maxfiles --> %d\n", info
.short_name
,
391 mp_msg(MSGT_VO
, MSGL_V
, "%s: %s\n", info
.short_name
,
392 "Suboptions parsed OK.");
396 /* ------------------------------------------------------------------------- */
398 static int control(uint32_t request
, void *data
)
401 case VOCTRL_QUERY_FORMAT
:
402 return query_format(*((uint32_t*)data
));
407 /* ------------------------------------------------------------------------- */
411 /* ------------------------------------------------------------------------- */